Skip to content

docs(qa): FOLLOW-UPS § 7a records the landed subpath repair, not a pending choice - #16909

Merged
os-musk merged 1 commit into
mainfrom
claude/issue-16208-phase2-security-subpath-prose
Sep 8, 2026
Merged

docs(qa): FOLLOW-UPS § 7a records the landed subpath repair, not a pending choice#16909
os-musk merged 1 commit into
mainfrom
claude/issue-16208-phase2-security-subpath-prose

Conversation

@os-musk

@os-musk os-musk commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Part of #16208 — this lands the QA-ledger half only. The second note the card names is
deliberately untouched; What is deliberately left below says why, and names the ruling.

Clause-②: no

1. The premise, verified first — by content on origin/main

The card rests on the words "which PR #16205 repaired". That was verified in the tree, never
from a merged flag or a commit subject, and with a firing control in the same run:

$ git grep -c -F "@objectstack/core/security" origin/main -- packages/core/PHASE2_IMPLEMENTATION.md
exit=1, 0 hits                    <- the subject of the stale claim is GONE

$ git grep -c -F "@objectstack/core" origin/main -- packages/core/PHASE2_IMPLEMENTATION.md
origin/main:packages/core/PHASE2_IMPLEMENTATION.md:7
exit=0, 7 hits                    <- FIRING CONTROL, same query shape, same file, same run

The instrument answers both ways on that one file, so the zero is a reading and not a
pathspec that silently matched nothing. Reading the sections themselves: section 4
(Permission Manager) at line 161 and section 5 (Sandbox Runtime) at line 219 both now say
from '@objectstack/core'. The landing commit, reached by walking origin/main's own history
for that path — so an ancestor by construction, no shallow-clone ancestry test needed:

$ git log --oneline -1 origin/main -- packages/core/PHASE2_IMPLEMENTATION.md
e270ebb791 fix(core): PHASE2_IMPLEMENTATION.md imports from the root barrel, not an
           undeclared subpath (#16205)

The repair landed. premise_still_valid: true.

2. Per-note verdicts — each judged on its own reading, not as a package

Note 1 — docs/qa/platform-checklist/FOLLOW-UPS.md § 7a: STALE. Rewritten here.
Two of its claims are false at head. "sections 4 and 5 still tell readers to import … from '@objectstack/core/security'" — measured above, 0 occurrences. "Deliberately left: the two
repairs … differ in whether they widen the published contract, which is not a lane's call"

the choice has since been made. Its remaining claims are true and are kept: the subpath is
still in no exports entry (re-measured: packages/core/package.json declares exactly .
and ./logger), and the "filed separately" half still holds, so it stays and now names its
filing, #15931.

Note 2 — packages/core/src/security/security-scanner-retirement.pin.test.ts:46: STALE too,
and deliberately NOT touched here.
Its parenthetical "(PHASE2_IMPLEMENTATION.md sections
4 and 5 still teach it; filed separately, since the two repairs differ …)"
is false by the
same measurement. Everything around it was re-measured and is exactly true, so nothing else in
that header is in question: packages/core/package.json declares exactly . and ./logger;
PluginSecurityScanner does still survive in that document's retired section (line 274) and
in the tombstone on ./index.ts (line 80), which is the stated reason the pin is an
export-list assertion rather than a grep.

3. What is deliberately left, and on whose ruling

The card does not grade note 2 — it hands that scope decision away in its own words:

whether a stale parenthetical in a tombstone comment is worth a commit at all is a triage
call, and the honest answer may be to fix site 1 and leave site 2.

The triage seat took that call on the card and ruled:

⇒ ⭐ 裁定:站点一单独修;站点二在该文件下次因别的原因被触碰时顺手改掉。

— site 1 on its own; site 2 corrected in passing the next time that file is touched for
another reason, its stated cost being that editing a test file's header for one parenthetical
pulls that whole suite into this change's verification surface for zero gain. This PR executes
that ruling rather than reopening it, which is why the first line reads Part of and not a
closing keyword: the card should stay open as the record for note 2 until someone touches
that pin test for an unrelated reason. If the maintainer or PM would rather bank it now, the
edit is one comment line and the card can be shut by hand.

Also on the triage seat's instruction — "顺带把做出的选择记下来,那正是这份账本该承载的信息"
the rewritten paragraph now records which repair was taken (repoint at the root barrel, the
one that does not widen the published contract), which is the fact a tracking ledger owes
its next reader. That is what stops the next person re-opening a settled trade-off.

4. The fossil, read before rewriting

The recorded reason note 1 said what it said is in the note itself, and it does not contradict
the card:

Deliberately left: the two repairs (declare the subpath, or repoint both sections at the
root barrel) differ in whether they widen the published contract, which is not a lane's call.

Both named repairs are still the only two, and the delivering PR took the second. So the fossil
is discharged, not overruled — the rewrite says which of its two options was taken.

5. Evidence

Ablation: INAPPLICABLE, not invented. This diff is one Markdown paragraph. It adds no
guard, no assertion and no gate, so there is nothing whose removal could be driven to red.

Per-note absence check, counted on whitespace-flattened text so re-wrapping can neither
mask nor manufacture a count, with a both-ways control in the same run:

pattern at HEAD in the branch
REMOVED still tell readers to `import … from '@objectstack/core/security'` 1 0
REMOVED Deliberately left: 1 0
REMOVED which is not a lane's call 1 0
CONTROL Filed separately (must survive — triage said keep it) 1 1
CONTROL PHASE2_IMPLEMENTATION.md 2 2
ADDED repaired in **PR #16205** 0 1
ADDED does **not** widen the published contract was taken 0 1

The two CONTROL rows are what make the zeros mean something: the same instrument, on the same
file, in the same run, still answers "present" — so a zero is an absence and not a broken query.

Gates. Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, all run, reconciled with --ran. The reconciliation line, verbatim
— and it is a statement about COVERAGE, not about verdicts:

✓ dispatch-gates --ran: 12 derived famil(ies) accounted for — 12 run, 0 NOT-MEASURED.

Verdicts, stated separately: 12/12 exit 0. One of them needed a second attempt and it is
disclosed rather than quietly re-run — pnpm --filter @objectstack/lint run check:doc-formula-expressions first came back exit 3, PREREQUISITE NOT MET, which is
NOT MEASURED and is not a pass. Its prerequisite build was run under the shared verify lock
(os-verify-lock: VERDICT command-exit 0), after which the gate itself printed
✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 434 files / 1373 TS blocks judged clean. No verdict here was read while a build was in flight: every gate ran
either before that build was started or after it had returned.

The path-matched gate that actually reads the edited file is pnpm check:platform-checklist,
green: check-platform-checklist: OK — 15 areas, 264 items (264 active).

Repo-wide pnpm lint is CI's run; the narrowing here is measured, not skipped. Three
readings: (1) the checked population comes from ESLint's own config resolution, not a guess —
isPathIgnored('docs/qa/platform-checklist/FOLLOW-UPS.md') returns true; (2) the count comes
from --format json — 1 result, 0 errors, 1 warning, and that warning is the notice
"File ignored because no matching configuration was supplied.", i.e. 0 linted files; (3) the
invariance for untouched files is stated by the config itself at eslint.config.mjs:326-329
"this repo runs one eslint.config.mjs, which never enables type-aware linting (no
parserOptions.project, no typed @typescript-eslint rules) for ANY file" — so a Markdown-only
diff cannot move any verdict on any file it did not edit.

Tests/typecheck: none owed. The one edited path belongs to no workspace package (the
nearest package.json above it is the private root @objectstack/spec-monorepo; the
pnpm-workspace.yaml globs cover only packages/**), so no package's suite is implicated.
All readings above were taken at 605abe4b on this branch.

6. Changeset route — decided on a measurement

Route 2, the skip-changeset label; no .changeset/*.md entry. The floor sentence, cited with
its tree — AGENTS.md:1036, identical on origin/main and in this branch's worktree, which is
checkable because this diff touches exactly one file and AGENTS.md is not it:

A bug fix in a released package takes a patch changeset — never none, and ⛔ never
skip-changeset: that label is for a diff that publishes nothing from any released package.

The measurement that puts this diff in the label's half: walking upward from
docs/qa/platform-checklist/FOLLOW-UPS.md, the first package.json is the repo root's, which
is "private": true, and pnpm-workspace.yaml enumerates only packages/* and its
subdirectories. The path ships from no released package, so a changeset would publish nothing.

7. 验收备注

  • Census, reported and NOT swept in (the card is not widened). Repo-wide, the stale
    description — sections 4 and 5 currently teaching the subpath — exists in exactly the two
    places the card names, and nowhere else. Two neighbours were read and are correct as
    written
    , so they are left alone: packages/spec/src/migrations/entries/semantic/18.plugin-security-scanner-retired.ts:55
    (and its generated mirror in registry.ts) says the subpath is one "the package has never
    declared in its exports and which therefore resolved for nobody" — a true statement about
    the subpath that makes no claim about the document; and packages/core/src/security/index.ts:10
    carries @module @objectstack/core/security, a module tag, not an import instruction. The
    CHANGELOG.md hits are historical release records.
  • Governed-surface check: the register printed today's set —
    docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md — and the single edited path is
    in none of them. content/docs/releases/** is untouched.
  • Collision fences respected: packages/metadata-protocol/src/protocol.ts and
    packages/spec/src/contracts/scoped-context.ts are not in this diff.
  • Worktree was checked for a predecessor's uncommitted work before any edit: a clean
    negative
    — no claude/issue-16208-* branch existed locally or on the remote, and
    git status --porcelain in the fresh worktree was empty.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ADLdAs2pVcH17h9tZKWMBg


Generated by Claude Code

…nding choice

`docs/qa/platform-checklist/FOLLOW-UPS.md` § 7a stated in the present tense that
`PHASE2_IMPLEMENTATION.md` sections 4 and 5 "still tell readers to `import … from
'@objectstack/core/security'`", and that the choice between the two available repairs
was "Deliberately left ... not a lane's call".

Measured on `origin/main`: that specifier occurs 0 times in
`packages/core/PHASE2_IMPLEMENTATION.md` (firing control in the same run:
`@objectstack/core` occurs 7 times in the same file), and both section 4 and section 5
now import from the root barrel. PR #16205 (commit e270ebb) repointed them.

So both halves were stale: the residue is gone, and the choice was made — the repair
taken is the one that does NOT widen the published contract, which is the fact a
tracking ledger owes its next reader. `packages/core/package.json` still declares
exactly `.` and `./logger`, re-measured here. The "filed separately" half stays and now
names its filing, #15931.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADLdAs2pVcH17h9tZKWMBg
@github-actions github-actions Bot added the size/s label Sep 8, 2026
@os-musk os-musk added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 8, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 8, 2026
@os-musk
os-musk marked this pull request as ready for review September 8, 2026 16:12
@os-musk
os-musk enabled auto-merge September 8, 2026 16:13
@os-musk
os-musk disabled auto-merge September 8, 2026 16:13
@os-musk
os-musk added this pull request to the merge queue Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 34250893042 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Dogfood Verify CLI — 失败步骤: Publish this leg's attestation(日志不可读,点进 job 看)

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

  • ⚠️ 本次没有可用的聚合签名(日志里没有能解析出测试文件名的 FAIL 行)—— 这不是「没有同签名的其他 PR」,是这一轮没测到。跨 PR 聚合本次不可用,请手工比对其他 PR 的同类评论。
  • ⚠️ 24h 评论账本没读完(超过 5 页仍未读到窗口尽头),所以上面的「不同 PR 数」是下界,不是全量。

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 2 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants