docs(cli): re-anchor the dead tracker citations in packages/cli/src to the commits that decided them, and the source-hashes header at its producer - #20656
Conversation
…cer, and state the flag's lesson in words The generated-header line in renderSourceHashModule and the comment beside previousSourceHashes cite commit 09b4f4e, which extended the source-hash mechanism to the generated bundles, in place of a tracker number that no longer resolves. The --source-hashes help text says what the companion records instead of citing a number. Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
…nchored header Regenerated with node scripts/check-i18n-bundles.mjs --write, which runs each package's documented os i18n extract command. Only line 8 of each file moves (the provenance header now cites commit 09b4f4e); every hash entry is byte-identical, and no other file in the nine packages changes. Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
…o the commits that decided them Every comment and docblock site in packages/cli/src (tests included) that cited a tracker number now answering 404 cites the commit in this repository's history that decided what the line describes, or ADR-0104's 2026-09-05 addendum where that record holds the decision, and says in its own words what was decided. Four sites with no deciding commit stay as they were. Comments only: 316 lines out, 316 in, over 64 files, and no code token moves. Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
…ce comments The rewritten docblocks and the two strings ship in dist, so the package publishes changed bytes. Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
…prose-id baseline The --source-hashes help text and the generated-header string no longer carry a tracker number, so check:doc-authoring's shrink-only ledger over-pinned the tree by those two pairs. Regenerated with its own command (node scripts/check-doc-authoring.mjs --census-ledger); nothing else moves. Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 10 package(s): 42 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 12 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 51 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1dadd2e55cfc8e9627ac318fd5b25330548daf1f && git checkout 1dadd2e55cfc8e9627ac318fd5b25330548daf1f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c6b37cd08d0eb622d4f59b79effdc954f86dad9f 6bb4d3b53169c395bce11b0faf5ffc6e346656bb && git checkout -B drift-repro c6b37cd08d0eb622d4f59b79effdc954f86dad9f && git merge --no-ff 6bb4d3b53169c395bce11b0faf5ffc6e346656bb
node scripts/docs-audit/affected-docs.mjs --json c6b37cd08d0eb622d4f59b79effdc954f86dad9f
|
Contract reviewServed-tier: Reviewed against card #20594 (body and all 11 comments, the stage-3 claim Check-runs on this head, final read 2026-09-29T14:43:58Z: 35 names, newest run per name: 32 ① Derived judgmentsAccept sets and public surface. No accept set moves: no schema, flag, exit code, error code, export, type or route changes anywhere in the diff. What reaches consumers is prose: the rewritten docblocks of (1) Comment-only apart from the two declared strings — YES. My own pairing of every removed line with its added line over the 92 changed source and generated files gives 346 pairs (the file list's 350 deletions less the 4 baseline-JSON lines; the 360 additions are those 346 plus the 14-line changeset). 343 pairs are lines that begin with (2) Anchors — all 62 shas plus the ADR addendum's
No wrong or unsupported anchor found. (3) Numbers. Over every removed and added line of the 92 source and generated files (the (4) Line counts. From the file list: all 92 modified files have additions equal to deletions (65 under (7) The declared step past comment-only. The two (8) The 27 companions. Every one of the 27 diffs is a single hunk (9) The prose-id baseline. The 4 removed lines are the whole ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
…rc to the commits that decided them (objectstack-ai#20673) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 4 of the `domain:cli` lane of the dead-citation sweep: `packages/types/src/**`. Every comment or docblock site in scope that cited a tracker number answering 404 now cites, in ruling C+D's form C (comment 5749154545 on objectstack-ai#19123), the commit in this repository's history that decided what the line describes, and says in its own words what that commit decided. PR objectstack-ai#20533 is the method; PR objectstack-ai#20624 (`runtime`), PR objectstack-ai#20632 (`rest`) and PR objectstack-ai#20656 (`cli`) are the landed stages this follows. The card stays open for the form-D stage and the rest of the lane, so this PR says `Part of`. That is **83 comment sites on 83 lines in 17 files, covering 12 numbers**: the census's 52 (all of them) and 31 more in test comments, which the census defers. Each rewritten line cites one of **12 distinct commits**. No ADR or ruling-record file records any of these twelve decisions, so every anchor is a commit. Only comments changed. Every touched file keeps its line count (94 lines out, 94 in, over 17 files), so no line citation into these files moves. Eleven of the 94 lines held no dead site; each is the other half of a sentence that had to change: `thrown-http-error.ts:316-319`, `node.ts:1103`, `:1429`, `:1447`, `:1452`, `:1476`, and `node.test.ts:449`, `:2420` (see "Wordings to check"). **No citation number is added.** Over the 94 line pairs, every tracker number on an added line was already on the line it replaces (per-pair check: 0 added), and no PR number stands on an added line. No code token moves (see the guard below). No site was left: no dead comment site in scope lacked a deciding commit, and no open PR touches `packages/types/src`. One file outside `packages/types/src`: a `patch` changeset for `@objectstack/types`, in PR objectstack-ai#20632's form and level. ## Census: `packages/types`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run with the fleet token. Its surface is comment prose in `packages/**/src/**/*.ts` with string literals blanked, and it defers `*.test.ts`. The count is its `allocated-but-absent` findings under `packages/types/`. Both runs enumerated the whole board (185 pages), so neither read a truncated board. | reading | tree | board | whole-repo `allocated-but-absent` | types sites | lines | files | numbers | |---|---|---|---|---|---|---|---| | before | base `6bff748bbd`, run 2026-09-29T15:31:59Z to 15:41:36Z | enumerated, 185 pages, frontier objectstack-ai#20663, 18,490 numbers | 1,510 | **52** | 52 | 7 | 11 | | after | head `686a4c60cb`, run 2026-09-29T16:04:17Z to 16:12:39Z | enumerated, 185 pages, frontier objectstack-ai#20671, 18,498 numbers | 1,458 | **0** | 0 | 0 | 0 | The before count equals the card's 52 at `f11b5f20a2`: no drift. The whole-repo drop is 52, exactly this diff's 52 sites, and the whole-repo resolving count rises by one (32,882 to 32,883): the live objectstack-ai#12751 that `index.ts:4` now spells so the grammar reads it. Both runs read this worktree, the base and then the base plus this one commit, so no other change entered either count. **Supplementary instrument, the whole scope.** The census does not read test files or strings, and this stage's scope includes test comments. So a second reading runs the gate's own exported `extractCitations` (whole-file and comment-prose projections) and `classifyCitation` over every `.ts` file under `packages/types/src` (42 files), against a board from the gate's own `probeBoard`. The lit controls objectstack-ai#20594, objectstack-ai#19123 and objectstack-ai#20656 answered 200 and are on both boards; the dead controls objectstack-ai#11671, objectstack-ai#10514 and objectstack-ai#14828 answered 404 and are on neither. | reading | tree | board | citations | dead | src comment | test comment | src string | test string | |---|---|---|---|---|---|---|---|---| | before, 15:34Z | `6bff748bbd` | probed, frontier objectstack-ai#20661 | 622 | **101** | 52 | 31 | 1 | 17 | | after, 16:04Z | `686a4c60cb` | probed, frontier objectstack-ai#20668 | 540 | **18** | 0 | 0 | 1 | 17 | Its src-comment column equals the census's 52, site for site (the two site lists are identical), which is the control on the second instrument. The drop of 82 citations is the 83 dead sites removed plus one live number the grammar now reads: `index.ts:4` spelled `[objectstack-ai#11343/objectstack-ai#12751]`, whose second half the grammar skips after a slash, and now reads `[commit c0714eb / objectstack-ai#12751]` like its module doc, so the live objectstack-ai#12751 is judged (resolving src comments 273 to 274). Resolving pull requests (20), cross-repo citations (14) and the other resolving counts are unchanged. A separate scan for slash-joined pairs in `packages/types/src` found six (`objectstack-ai#11343/objectstack-ai#12751`, `objectstack-ai#3878/objectstack-ai#3899`, `objectstack-ai#7525/objectstack-ai#8016`, `objectstack-ai#4728/objectstack-ai#4825`, `objectstack-ai#8621/objectstack-ai#8622`, `objectstack-ai#5352/objectstack-ai#5367`); every second half answers 200, so no dead number hid behind a slash here. ## Per-number table Sites and files are the dead comment sites in scope at the base, test sites counted in brackets. `strings kept` counts string-literal sites, which are tokens and stay as they were. Every anchor was read in its message or its diff, not only its subject: it is the commit that made the change the line describes. | number | comment sites / files | rewritten | strings kept | anchor | |---|---|---|---|---| | `objectstack-ai#8824` | 1/1 (1 test) | 1 | 0 | `8ac232306` | | `objectstack-ai#9934` | 5/4 (2 test) | 5 | 2 | `79c46da90` | | `objectstack-ai#10943` | 10/2 (4 test) | 10 | 2 | `46d34ab7c` | | `objectstack-ai#10944` | 1/1 | 1 | 0 | `e598b1cbc` | | `objectstack-ai#11343` | 3/3 (1 test) | 3 | 1 | `c0714eb5d` | | `objectstack-ai#12281` | 1/1 | 1 | 0 | `0783d7b80` | | `objectstack-ai#13197` | 5/2 (2 test) | 5 | 2 | `56c093c4d` | | `objectstack-ai#13279` | 8/5 (2 test) | 8 | 0 | `6a180e42d` | | `objectstack-ai#13324` | 15/3 (7 test) | 15 | 5 | `4cda78c9b` | | `objectstack-ai#15044` | 8/2 (3 test) | 8 | 1 | `088f761e5` | | `objectstack-ai#15045` | 21/2 (8 test) | 21 | 1 | `288fe9c34` | | `objectstack-ai#16657` | 5/2 (1 test) | 5 | 4 | `5a95b0e93` | | **total** | **83** | **83** | **18** | **12 distinct commits** | Every cited sha matches exactly one object (`git rev-parse --disambiguate`, count 1 for each of the 12), is a commit, has one parent, and is an ancestor of the base (`merge-base --is-ancestor`, exit 0 for all 12). The checkout is not shallow (`--is-shallow-repository` false); the control leg `f5a9bc2f3` (2026-08-10, older than the oldest anchor, `8ac232306` of 2026-08-15) exits 0 and the negative control (this branch's own `686a4c60cb`, not on `main`) exits 1. **Anchors reused from earlier stages**, so each number carries one anchor across the tree: `79c46da90` for objectstack-ai#9934 (stages 1 and 2, the spec lane), `46d34ab7c` for objectstack-ai#10943, `e598b1cbc` for objectstack-ai#10944 and `288fe9c34` for objectstack-ai#15045 (stage 3), `0783d7b80` for objectstack-ai#12281 (stage 1), `56c093c4d` for objectstack-ai#13197 (stage 2, the spec lane), `6a180e42d` for objectstack-ai#13279 (stages 1 and 2, `plugin-sharing`) and `c0714eb5d` for objectstack-ai#11343 (`plugin-auth`). **New anchors, and how each was found:** - `objectstack-ai#8824` → `8ac232306`: objectstack-ai#8824 is that commit's own PR number (its subject ends `(objectstack-ai#8824)`), so the sha is the object the number named. `error-leak.test.ts:180` read 「PR objectstack-ai#8824 corrected the」 and now reads 「Commit 8ac2323 corrected the」. - `objectstack-ai#13324` → `4cda78c9b`: its subject does not name the number, but its changeset heading does (「require a missing-table error to name the table that was READ (objectstack-ai#13324)」), and its diff adds `readObject` and every `[objectstack-ai#13324]` marker this module carries. It landed in `packages/metadata/src/utils/schema-sync-errors.ts`, the file `6a180e42d` then moved here (a rename at 86 percent similarity). - `objectstack-ai#15044` → `088f761e5`: 「Part of objectstack-ai#15044」, the only commit whose message names the number; it made the objectstack-ai#13330 succeeding leg recognise the package root by the name the declaration promises, and added the `BOUNDARY` pin at `node.test.ts:1863` that `:2175` and `:2419` point at. - `objectstack-ai#16657` → `5a95b0e93`: it added `operatorFacingErrorText`, `DECLARED_DATABASE_FAULT_CODE` and the raw-path fragment, and its message calls itself the fourth prose round on objectstack-ai#16657. ## Wordings to check - **A stale future tense, corrected by its anchor.** `thrown-http-error.ts:315-320` said objectstack-ai#12281 「is a separate card with its own measurement-first step, so nothing here applies it; this function is the shape it will read」. `a81aa9dd5` wrote that on 2026-08-29; `0783d7b80` landed the next day and its message says 「the door now reads `serverFaultProvenance`」. Citing the commit in the future tense would contradict itself, so the six lines now read 「Commit 0783d7b — the prose axis of the same 2026-08-27 ruling — reads the `'declared'` limb of this same function … It landed separately, after its own measurement-first step, so nothing here applies it; this function is the shape it reads rather than a second copy it would have had to grow.」 - **An open question named by a number that had already landed.** `node.ts:1447-1452` called where a relative specifier should resolve from 「an open policy question owned by objectstack-ai#10944」 and ended with 「Answering half of another card's undecided question」. `e598b1cbc` (objectstack-ai#10944's landing) had merged 40 minutes before `46d34ab7c` wrote those lines, and it refuses the relative spelling. The lines now read 「the policy question commit e598b1c settled for `serve` (it refuses a relative `plugins: [...]` entry rather than silently re-basing it)」 and 「Answering half of another change's question」. - **「the card」 once the antecedent became a commit.** `node.ts:1102-1103` 「objectstack-ai#15045 is the card about telling an operator which one was measured」 now reads 「commit 288fe9c is the change that tells an operator which one was measured」. `node.ts:1476` 「the second verification axis the card holds open」 now reads 「the second verification axis that commit left unbuilt」, which is what `288fe9c34`'s message says (「deliberately not built here」). `node.test.ts:449` 「The card's own 4-row matrix」 now reads 「The 4-row matrix behind that commit」. - **Headings that named a defect by its number now say so.** `node.test.ts:1566` reads 「Fixed by commit 088f761: the SUCCEEDING leg recognised the package by the DECLARATION KEY」 and `:1881` reads 「Reworded by commit 288fe9c: the location sub-case REFUSES correctly and EXPLAINED itself wrongly」 (`288fe9c34` changed the wording and kept the refusal). The dash-rule headings trim trailing dashes: `node.ts:1381`, `node.test.ts:1566`. - **A quoted triage.** `node.test.ts:2160` quoted 「objectstack-ai#15045's triage」; it now reads 「quoted from the triage commit 288fe9c landed」. That commit's changeset records the same decision in its own words: the key stays the expectation 「because widening it would accept any directory sitting at the key and trade a wrong REMEDY for a wrong LOAD」. `node.test.ts:2053` said objectstack-ai#15045 「asked for this sentence」; it now says `288fe9c34` 「wrote this sentence」, and that commit's own test comment says the card asked for it. - **A defect that proved a point.** `driver-error-classification.callers.test.ts:24-25` said the omission is the shape 「objectstack-ai#13324 existed to close」 and that prose 「is exactly what objectstack-ai#13324 proved insufficient」; it now reads 「the … shape commit 4cda78c closed」 and 「prose is exactly what that commit's defect proved insufficient」. - **「pre-#N」 spellings** (the card's control sites `driver-error-classification.ts:608` and `node.ts:1428`, plus `callers.test.ts:20` and `node.test.ts:594`) now say 「before commit X」. ## Mechanical guard: no code token moves The check compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, JSDoc nodes excluded, comments being trivia) of each touched file at base `6bff748bbd` against the working tree at `686a4c60cb`, over all 17 touched files, and lists EVERY differing token, not only the first. Controls mutate the head text in memory only, so nothing on disk moved for them. - Real run: 31,911 base tokens, token counts equal in every file, **0 differing tokens** (exit 0). - Comment-insertion control (a new line comment in `node.ts`): 0 differing tokens (exit 0). - Code-insertion positive control (a declaration prepended to `node.ts`): the count differs and a difference appears at token 0 (exit 1). - String positive control (one character changed inside the kept `undeclaredMessage` literal at `node.ts:383`): exactly 1 differing token, a `StringLiteral` at token 672 (exit 1). So H2 holds by the token guard. The emitted `dist` is not byte-identical, because the docblocks ship, which is why the changeset is `patch`. Line balance: every touched file is +N/−N and every line count is equal at base and head (17 files). A raw scan of the 18 changed files for control bytes finds none (its positive control, a scratch file holding a U+0001 byte, matches). ## Changeset This change ships bytes, so a `patch` changeset for `@objectstack/types` is included, in PR objectstack-ai#20632's form and level: 「Comments only: no error code, refusal text, type, export or runtime behaviour changes.」 Measured on the built package: `files[]` is `dist`, `README.md` and `CHANGELOG.md`. After the build, the rewritten docblocks reach `dist`: `0783d7b80`, `79c46da90`, `5a95b0e93` and `c0714eb5d` are in `dist/index.d.ts` and `index.d.mts`, `4cda78c9b` in all four `index` files, `6a180e42d` in `index.js` and `index.mjs`, and `46d34ab7c` and `288fe9c34` in `dist/node.d.ts` and `node.d.mts`. The positive control, the unchanged sentence 「sanitisation REGIME is the condition, not one of its two outcomes」 of the `0783d7b80` docblock, is in `dist/index.d.ts` beside it; a negative control phrase appears nowhere. Of the twelve dead numbers, only objectstack-ai#10943 remains in `dist`, twice, and both are the kept operator-facing string at `node.ts:383` (see Acceptance notes). ## Gates (head `686a4c60cb`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its disclosure, verbatim, from each locked run at this head: ```text os-verify-lock: VERDICT command-exit 0 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 2s · declare it in the PR body · pnpm --filter @objectstack/types exec vitest run --project repo --maxWorkers=2 os-verify-lock: VERDICT command-exit 0 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 5s · declare it in the PR body · pnpm --filter @objectstack/types exec vitest run --project local --maxWorkers=2 os-verify-lock: VERDICT command-exit 0 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 2s · declare it in the PR body · pnpm --filter @objectstack/types typecheck os-verify-lock: VERDICT command-exit 0 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 28s · declare it in the PR body · pnpm --filter '@objectstack/types...' build os-verify-lock: VERDICT command-exit 0 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 46s · declare it in the PR body · pnpm lint os-verify-lock: VERDICT command-exit 0 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 93s (1m33s) · declare it in the PR body · pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=4 ``` `origin/main` did not move after the branch was cut: `git merge origin/main` answered 「Already up to date」 at `6bff748bbd`, so the base is the merge base and nothing needed rebuilding. `origin/main` has since moved to `6c11ef9ecb` (PR objectstack-ai#20663: two pages under `content/docs/automation`, read 16:13Z). It touches nothing this diff or its gates read, so the branch was not merged again and every reading here stays at `686a4c60cb`. - **Build:** the dependency closure (`@objectstack/types...`: `spec` then `types`) and then the whole workspace (71 tasks, 71 successful). `check-dts-emitted` finds 2 of 2 declared declaration files. The build left the tree clean. - **Tests:** `--project local`: 22 files, 685 tests pass. `--project repo`: 1 file (`driver-error-classification.callers.test.ts`, touched here), 7 tests pass. 22 + 1 is all 23 test files in the package, so every touched test file ran. - **Typecheck:** `pnpm --filter @objectstack/types typecheck` exits 0. `tsc --listFiles` counts 42 `src` files under `tsconfig.json`, all 23 test files among them, so every touched test file is type-checked. - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at `686a4c60cb` (2026-09-29T16:01:23Z to 16:02:09Z). Not narrowed. - **Citation judging:** `node scripts/check-issue-citations.mjs --base origin/main` exits 0: 5 citations judged across 7 files (4 resolve, 1 cross-repo). These are the live numbers that stay on rewritten non-test lines. It defers `*.test.ts`, so the per-pair count over the whole diff covers the rest: 0 numbers added. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at `686a4c60cb` derived 61 families. All 61 ran and exit 0, and `--ran` over a record carrying each exit code reads 「61 derived, 61 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero). Among them: `check:doc-authoring`, `check:nul-bytes`, `check:issue-citations` (self-test), `check:published-files`, `check:dts-closure`, `check:dual-build-cjs-loads`, `check:type-check-coverage` and `check:type-check-debt`. - **Artifact rosters:** all 36 non-self-test roster rows that run without a pull request exit 0 at `686a4c60cb`, the four whose rosters share a directory with this diff among them (`check-changeset-fixed`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three, `check-closing-target-claim`, `check-partof-closing-keyword` and `check-single-claim-paths`, need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 checker-health-only rows were not run. ## Hypotheses (measured first) - **H0 holds.** The filtered census answers 52 dead sites at `6bff748bbd` (52 lines, 7 files, 11 numbers), equal to the card's count at `f11b5f20a2`: no drift. - **H1 holds, with no exceptions.** After the rewrite the filtered census answers 0 dead sites for `packages/types/`. No site is left for an open PR or an unfound anchor: the claim's read and this stage's read of the open PRs' file lists (15:40:08Z, 7 open PRs) found none touching `packages/types/src` (the Version Packages PR touches only `packages/types/CHANGELOG.md` and `package.json`). A second read before this PR was opened (16:13:18Z, 11 open PRs) found the same. - **H2 holds, by the token guard** above: 0 differing parser leaf tokens over the 17 touched files, with the comment control at 0 and the code and string controls each turning red. ## Acceptance notes - **Form D, not touched here.** 18 dead numbers stand inside string literals: 17 in test titles and test-code strings (8 files, 8 numbers), and one an operator reads. That one is the `undeclaredMessage` note at `node.ts:383`, 「a caller that needs its own resolution passes `{ fallbackImport: (s) => import(s) }`, objectstack-ai#10943)」, printed when the host importer's undeclared fallback fails without a caller base. It is also the only dead number left in `dist`. The comments around it (`node.ts:368`, `:1381`, `:1428`) now cite `46d34ab7c`. Ruling D (no number, the lesson in words) is a string change outside this comment-only stage; the card already carries a form-D stage for the lane (ACCEPT 5888034755), and this string is its author-shown first in `packages/types`. A second one is a remedy an author reads: the `REMEDY` text at `callers.test.ts:281`, which that gate test prints for any call site that omits `readObject` (「Without it the predicate returns the pre-objectstack-ai#13324 WIDE verdict」). - **Outside the scope and the census surface.** `packages/types` outside `src/**` holds one dead citation: `vitest.config.ts:25` cites objectstack-ai#17853 (404), the same number PR objectstack-ai#20624 and PR objectstack-ai#20632 reported in their packages' `vitest.config.ts`. The six other citations outside `src/**` (`CHANGELOG.md` excluded) resolve. It stays for a later stage of this card. ## Deviations - Eleven lines beyond the dead sites are the other half of a rewritten sentence (listed under What changed), and the six lines at `thrown-http-error.ts:315-320` move from the future tense to the present, because the claim they carried stopped being true when `0783d7b80` landed (see Wordings to check). - The anchors were researched in this session, not delegated; every one was checked against its commit's message or diff. - Commit trailers are AGENTS.md's model-free pair (`Claude-Session` plus `Co-authored-by: Claude`), and the pre-push trailer check passed on every push; the harness's attribution reminder asked for a model-named trailer and a different PR footer, which AGENTS.md overrides. --- _Generated by [Claude Code](https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289)_ Co-authored-by: Jack Zhuang <50353452+hotlong@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
Part of #20594
Clause-②: no
What changed
This is stage 3 of the
domain:clilane of the dead-citation sweep:packages/cli/src/**, plus the generated-header producer thedomain:servicespointer on the card hands this lane. Every comment or docblock site in scope that cited a tracker number answering 404 now cites, in ruling C+D's form C (comment 5749154545 on #19123), the commit in this repository's history that decided what the line describes, and says in its own words what that commit decided. PR #20533 is the method; PR #20624 (stage 1,packages/runtime) and PR #20632 (stage 2,packages/rest) are the precedents this follows. Later stages covertypesand the rest of the lane, so this PR saysPart ofand the card stays open.That is 313 comment sites on 304 lines in 64 files, covering 63 numbers: the census's 170 rewritable sites (of its 174), 142 more in test comments (which the census defers), and one site whose dead number is the second half of a slash-joined pair the citation grammar does not read (
serve.ts:1173,#10943/#11157). Each rewritten line cites one of 62 distinct commits, except the six#15041sites, which cite ADR-0104's 2026-09-05 addendum: that ADR records the maintainer ruling the lines describe, and the ruling allows the ADR to be cited instead of a commit.Only comments changed in
packages/cli/src, apart from the two string literals this stage declares (next section). Every touched file keeps its line count (319 lines out, 319 in, over 65 files), so no line citation into these files moves. Thirteen of the 319 lines held no dead site; each is the other half of a sentence that had to change:create.ts:326,doctor-organizations-message-spelling.test.ts:11,environments.test.ts:162,generate.ts:153,serve-cluster-host-resolution.test.ts:816,serve-host-fallback-base.test.ts:5,validate.ts:336,validate.ts:813,validate.ts:815,hook-body-lowering.test.ts:10,format.ts:1132,format.ts:1435andi18n-extract.ts:34(mostly 「that card」 to 「that commit」 once the antecedent became a commit).No citation number is added. Every tracker number on an added line was already on the line it replaces. One PR number stands on an added line, and it was there before:
doctor-organizations-message-spelling.test.ts:9read 「PR #12463 (#12151) single-sourced」 and now reads 「Commit 27b6902 (PR #12463) single-sourced」, keeping the live PR as a convenience link beside the commit, as the ruling allows (#12463 is that commit's own PR). No code token moves (see the guard below).Four dead comment sites are left on purpose, listed under "The sites left". Two more files outside
packages/cli: apatchchangeset for@objectstack/cli, and the shrink-onlycheck:doc-authoringprose-id ledger (see Deviations).The source-hashes producer and its 27 generated companions
The claim declares these as the only strings this stage moves, and the regeneration of the files they write.
packages/cli/src/utils/i18n-extract.ts:2294is the string literalrenderSourceHashModulewrites as line 8 of everyLOCALE.source-hashes.generated.ts. It read 「bundles ([finding]check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671, maintainer ruling [Decision] 把 #8765 的 source-hash sidecar 扩展到生成的 i18n bundle —— #9672 写明的升级条件已满足 #12069 Option A, extending i18n: a source-string edit still leaves zh-CN / ja-JP / es-ES silently stale — and pinningento the source makes the asymmetry sharper, not smaller (needs a maintainer decision) #8765 Option B).」 and now reads 「bundles (commit 09b4f4e, maintainer ruling [Decision] 把 #8765 的 source-hash sidecar 扩展到生成的 i18n bundle —— #9672 写明的升级条件已满足 #12069 Option A, extending i18n: a source-string edit still leaves zh-CN / ja-JP / es-ES silently stale — and pinningento the source makes the asymmetry sharper, not smaller (needs a maintainer decision) #8765 Option B).」.09b4f4e4eis the commit that extended the i18n: a source-string edit still leaves zh-CN / ja-JP / es-ES silently stale — and pinningento the source makes the asymmetry sharper, not smaller (needs a maintainer decision) #8765 Option B source-hash mechanism to the generated bundles per maintainer ruling [Decision] 把 #8765 的 source-hash sidecar 扩展到生成的 i18n bundle —— #9672 写明的升级条件已满足 #12069 Option A; its message says exactly that, and it is the anchor stages 1 and 2 of dead tracker citations in thedomain:servicespackages (629 sites, 112 numbers, 152 files): the ruling C+D stage for this lane (from #20556) #20596 gave#11671. [Decision] 把 #8765 的 source-hash sidecar 扩展到生成的 i18n bundle —— #9672 写明的升级条件已满足 #12069 and i18n: a source-string edit still leaves zh-CN / ja-JP / es-ES silently stale — and pinningento the source makes the asymmetry sharper, not smaller (needs a maintainer decision) #8765 answer 200 (REST and web) and stay. The comment at:249besidepreviousSourceHashescites the same commit.packages/cli/src/commands/i18n/extract.ts:227, author-shown CLI help), in form D: the lesson in words, no number. It read 「the provenance companion that lets a stale fill be told from a translation ([finding]check:i18nverifies key presence, not that an untranslated leaf still matches the source string it was filled from — and the drift is sticky #11671).」 and now reads 「the provenance companion that records which source revision each generated leaf is still a copy of, so a stale fill can be told from a translation.」. The rest of the description is unchanged.node scripts/check-i18n-bundles.mjs --write, which runs each package's documentedos i18n extractcommand from itsi18n-extract.config.ts(every one of the nine carries the source-hashes flag), on a CLI built from47241dd80e. Before it, the bundle check reported the nine packages DRIFTED, 3 bundles each, against the new producer. After it:+27 −27: 3 locales inpackages/platform-objects/src/apps/translations,plugins/plugin-{approvals,audit,security,sharing,webhooks}andservices/service-{messaging,realtime,storage};@@ -8 +8 @@, and the one removed and one added line are the same in all 27 files;git statusshows nothing else in the nine packages, tracked or untracked;node scripts/check-i18n-bundles.mjsthen reads all nine packages in sync (7 bundles each), andcheck:i18n-stale-fillserves 27 of 27 companions with 0 stale fills.git grep -n "#11671" -- '*.source-hashes.generated.ts'answers 0 hits at head; the same grep at04b202e5cbanswers 27 (the positive control).distholds09b4f4e4eor the header's own phrase 「Each entry is the digest of the SOURCE REVISION」, while the export name…GeneratedSourceHashes(the positive control) is in eachdist. So the regeneration changes no published byte of those packages, and no changeset is owed for them. The other lanes' stages can keep leaving their generated copies alone, as the pointer asked.Held files
packages/cli/src/utils/sdui-manifest.tsandsdui-manifest.test.tsstay at their base blobs (41c4549ffeand3a242b54e0, equal at base and head), because PR #20589 edits them. They carry four citations (#4409once,#20113three times), and all four answer 200, so no dead site is held and there is no anchor to list for a follow-up.Census:
packages/cli, before and afterInstrument. The gate's own
node scripts/check-issue-citations.mjs --census --json, read-only and unchanged, run with the fleet token. Its surface is comment prose inpackages/**/src/**/*.tswith string literals blanked, and it defers*.test.ts. The count is itsallocated-but-absentfindings underpackages/cli/. Every run enumerated the whole board (185 pages), so none read a truncated board.allocated-but-absent04b202e5cb, run 2026-09-29T12:35:39Z to 12:43:03Z6bb4d3b531, run 13:46:09Z to 13:54:25ZThe before count equals the card's 174 at
f11b5f20a2. The 4 left are the deliberate sites below. The whole-repo drop is 197: this diff's 170 cli sites plus the 27 generated headers (3 in each of the nine packages; nothing else moved in any of them). The two merges oforigin/mainmoved no count. An earlier after-run atd1e09a7eed(13:19:18Z to 13:29:41Z, frontier #20649) read the same 4 and 1,510;packages/cliand the 27 companions are byte-identical between the two heads. One more attempt at6bb4d3b531(13:35:15Z) exited 3, PREREQUISITE NOT MET, on a malformed board page, and measured nothing; the run in the table is its retry.Supplementary instrument, the whole scope. The census does not read test files or strings, and this stage's scope includes test comments. So a second reading runs the gate's own exported
extractCitations(whole-file and comment-prose projections) andclassifyCitationover every.ts/.tsxfile underpackages/cli/src(298 files), against a board enumerated through the gate's ownenumerateBoard. The lit controls #20594, #19123 and #20632 answered 200 and are on both boards; the dead controls #11671, #10514 and #14828 answered 404 and are on neither.04b202e5cb6bb4d3b531Its src-comment column equals the census's 174 and 4, which is the control on the second instrument. The resolving citations (1,468 and 755 in comments, 50 and 53 as pull requests, 32 cross-repo) are the same in both readings, so no live citation was lost; the drop of 314 is exactly the dead sites removed (312 grammar-read comment sites and the two
#11671strings). The one slash-joined dead number the grammar never reads (#11157in#10943/#11157) is gone too: a separate scan for dead#Ntokens the grammar skips answers 1 before and 0 after.Per-number table
Sites and files are the dead comment sites in scope at the base, test sites counted in brackets.
leftis a site with no deciding commit (see below).strings keptcounts string-literal sites, which are tokens and stay as they were. Every anchor was read in its message or its diff, not only in its subject: it is the commit that made the change the line describes, and its own message or diff names the number it replaces or adds the citation the line carries.#62172b641ddd4#6238c8d6f6e08#6265cfb549db8#626868f5eccb1#6293c39a911ae#6344cfb549db8#6345e2798fab7#6535a92b1793c#8692712e185db#10326675ab574e#1035915b63e85a#103980681a76b8#1048535ad101bc#104996d441e41f#10504ff5733e03,0d4bd93e7#105145359a9b4c#10763c2b97c2a1#107693d7deb700#109089cc6777d3#109095a90c56d1#109177940de5e0#10926d173125fb#1094346d34ab7c#10944e598b1cbc#109520d4bd93e7,ff5733e03#10953be7262e72#10967e4a71d418#1102221756b325#110251c3a46f87#11048#1107150fb191dc#11157a4cb7817f#1117205181e8cc#11174ab23c67ab#11221e278a2970#11331#1167109b4f4e4e#1212579cf692b0#1215127b690272#12162c0f5e8f21#12181cf71d73f8#122979fd45a952#12943090f2302e#12961901355c3b#131098b236c826#13193faff497fd#13218c45d8e6b4#13347098a08ffa#13651ada3834ad#141924d0d9445a#1433679c71d29d#14397957f7bb45#14657431979e67#14667dc7c226b9#14824cf6b67164#1482808706f0e0#14829ee370d318#1490261821e54c#150408644d1d33#15041#15045288fe9c34#168879cdffbe36#170808b4890343#17081f721ef0ff,24d622b94#17883b06b2db5cEvery cited sha matches exactly one object (
git rev-parse --disambiguate, count 1 for each of the 62), is a commit, has one parent, and is an ancestor of the base (merge-base --is-ancestor, exit 0 for all 62). The checkout is not shallow (--is-shallow-repositoryfalse); the control leg13a6cb4adexits 0 and the negative control (this branch's own47241dd80e, not onmain) exits 1. ADR-0104's 2026-09-05 addendum landed as932acc3df, which passes the same four checks. Where an earlier stage gave a number an anchor and the cli site describes the same decision, the same anchor is reused (17 numbers, #17081 for its application half only; for examplee2798fab7for #6345,68f5eccb1for #6268,35ad101bcfor #10485,09b4f4e4efor #11671 and61821e54cfor #14902), so each number carries one anchor across the tree. Several numbers are the PR number of their own anchor commit (#6344, #10398, #14667, #16887), so the sha is the same object the number named.Numbers with more than one anchor, by site:
#10504/#10952(format.ts):ff5733e03added the opt-in zero row forUI:alone and0d4bd93e7made it required for every section, so lines naming both now name both commits.format.ts:1573read 「([finding]os validatedrops the wholeUI:row at zero apps, so a project with no navigable UI reads identically to one that was never asked #10504, [finding]os validate's summary printer drops ANY zero-count section row, not justUI:—Logic:/Security:vanish the same way #10952, [finding]printMetadataStatshas two more rows that say nothing:Runtime:drops at zero plugins, andstats.translationsis collected but never rendered at all #11172)」 and now reads 「(commits ff5733e, 0d4bd93, 05181e8)」.#10943/#11157(serve.ts):46d34ab7cmade the host importer's fallback base a caller-supplied parameter, anda4cb7817fmadeservepass its own base and collapsedimportConfigPluginfrom three branches to two. The slash-joinedserve.ts:1173「(createHostImporter's undeclared fallback resolves from@objectstack/types, not from the calling package — its documented contract says otherwise #10943/serve.ts'simportFromHostdoes not pass its own resolution base tocreateHostImporter— measured harmless today, open by construction #11157)」 now reads 「(commits 46d34ab and a4cb781)」;serve.ts:1459「(serve.tsloads an app's ownplugins: [...]config entries with a bareimport(), so a plugin package the APP declares resolves from the CLI #10908 →serve.ts'simportFromHostdoes not pass its own resolution base tocreateHostImporter— measured harmless today, open by construction #11157)」 reads 「(commits 9cc6777 → a4cb781)」.#17081(8 sites): one card with two halves.f721ef0fftook the platform's half (theDev adminbanner line says what the account sees) for 7 sites;format.ts:1132describes the application half and now reads 「[Let an app contribute its own first-run credentials to the boot banner (devHint/devLogins[]) — the platform cannot know which of an app's audiences shows something, and only the app can #17556 — commit 24d622b]」, the spelling the spec stage used atdev-login.zod.ts:10, withformat.ts:1133naming The boot banner's "🔑 Dev admin" is the only credential a first-run operator is given, and in any audience-gated app it is the account that sees nothing #17081 in words (「its parent card」).#15041(6 sites): the decision is a maintainer ruling recorded verbatim in ADR-0104's 2026-09-05 addendum, whose Sequencing section names the three steps the lines cite. So the lines cite the addendum (「The ruling in ADR-0104's 2026-09-05 addendum decided it」, 「sequencing step 2 of ADR-0104's 2026-09-05 addendum」), not a commit.Wordings to check, each true of its commit:
PageTranslation.componentshas no key forelement:text'scontent— the one string that element renders cannot be addressed by a bundle #14412, and the ruling commit d173125 landed,」, andresync.ts:96keeps the ruling's date from712e185db's message: 「commit 712e185 (the 2026-08-15 ruling)」.22P02commit 8644d1d fixed」, 「Before commit 5359a9b (raw)」 / 「Since commit 5359a9b (masked)」.validate.ts:813-815said 「ManifestSchemais not.strict()and drops unknown keys with nothing said (ManifestSchemastrips unknown keys silently — anamespacetypo insidemanifest:parses green and the namespace comes outundefined#14192)」, butManifestSchemahas beenstrictObjectsince4d0d9445a, which landed before the commit that wrote the sentence. Citing that commit in a present-tense sentence would contradict itself, so the three lines move to the past tense: 「was not.strict()and dropped unknown keys with nothing said until commit 4d0d944, so acting on that inference produced a manifest that looked fine」.#10326has no commit message naming it;675ab574etook the 1.7.1 measurement the line cites, and its own changeset and test name [finding] A clean first install shows the newcomer two red ✕ unmet-peer warnings (better-sqlite3, better-call) #10326.#12162is named by no message either;c0f5e8f21is the only commit that ever added the number, and its message states the point the lines make.#14397's citation was added by957f7bb45's own diff, which is the change the heading describes.#10763is added three times byc2b97c2a1's diff.#10499(init.ts:978): the line uses the earlier drift between the two scaffold paths as precedent; that drift was about pnpm build approvals, and6d441e41fgated the two paths against each other, so the line reads 「already drifted once (closed by commit 6d441e4)」.#6293:c39a911aeis the commit that found the 「headless husk」JSON.stringify(stack)leaves where a declaration was;bf4ebe2f3, which wrote the cli lines, only cites it.generate-field-type-vocabulary.pin.test.ts:92sits inside a verbatim quotation of the file's former clause, so the commit stands in an editorial bracket (「([commit ee370d3]'s pin argues this in full)」), as PR docs(runtime): re-anchor the dead tracker citations in packages/runtime/src to the commits that decided them #20624 did.serve.ts:1125,:1459,:1521,:3276,serve-cluster-host-resolution.test.ts:831,generate-field-type-vocabulary.pin.test.ts:260,files-to-references.ts:274) trim their trailing dashes to hold the width;serve-cluster-host-resolution.test.ts:893is a trailing comment whose code part is byte-identical.The sites left
No deciding commit (4 sites, all visible to the census):
init.ts:267([Decision] Withpackages: []shipped, theengines.pnpm >=10.15floor is now what refuses pnpm 10.0–10.4 — measured: they install with a lower floor, but never read the scaffold's build allowlist #11048): 「whether to admit that band at all is [Decision] Withpackages: []shipped, theengines.pnpm >=10.15floor is now what refuses pnpm 10.0–10.4 — measured: they install with a lower floor, but never read the scaffold's build allowlist #11048」 names an open support decision (pnpm 10.0 to 10.4). The only commit naming it,568de194e, files it unassigned; no later commit decides it, and the floor is still>=10.15at the base.plugin/publish.ts:118,osplugin.ts:21,osplugin.ts:49(manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331): the parenthetical points at the unpack-time integrity re-verification leg, which was never built (b60f48b52: 「The enforce leg points atmanifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331」). No commit decides it; the ownership clause on the same lines comes fromf89812e4d, but the number is not about that clause.String sites kept as tokens (49). 48 are test titles and test-code strings in 22 files. One is a non-test string: the
os meta resyncskip explanation atcommands/meta/resync.ts:71, 「on installs from before #8692, the platform's own seeded defaults carry that same stamp」, which an operator reads (see Acceptance notes).Mechanical guard: no code token moves, and exactly two string literals do
The check compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, JSDoc nodes excluded, comments being trivia) of each touched file at base
04b202e5cbagainst the working tree, over all 65 touched files inpackages/cli/src, and lists EVERY differing token, not only the first. Controls mutate the head text in memory only, so nothing on disk moved for them.StringLiteral:commands/i18n/extract.ts:227(the help text) andutils/i18n-extract.ts:2294(the header line). No other token in any file differs.serve.ts): still exactly those 2 (exit 1, no new difference).serve.ts): the count differs (17,815 to 17,820) and a third difference appears at token 0.serve.ts): a third difference appears, aStringLiteralat token 145.Line balance: every touched file is +N/−N, and every line count is equal at base and head (94 files). A raw scan of the 92 changed source and generated files for control bytes finds none (its positive control, a scratch file holding a U+0001 byte, matches).
Changeset
This change ships bytes, so a
patchchangeset for@objectstack/cliis included, in PR #20632's form and level. Unlike stage 2's, it names the two strings, because 「Comments only」 would not be true here.Measured on the built package:
files[]isdist,README.mdandCHANGELOG.md. After the build, the rewritten docblocks reachdist: 142commit SHAcitations in 39 of its.js/.d.tsfiles. For examplestorage-driver.ts:91's rewritten line 「(commit 68f5ecc). These are the」 is in bothdist/utils/storage-driver.d.tsand.js, beside the unchanged next line of the same docblock 「runtime's declarations, not copies of them — in particular」 (the positive control); a negative control phrase appears nowhere. The new help text is indist/commands/i18n/extract.js, the header literal with09b4f4e4eis indist/utils/i18n-extract.js, and#11671appears nowhere in the package'sdist.Gates (head
6bb4d3b531)This host has no
flock, soos-verify-lock.shran in its declared unlocked mode. Its disclosure, verbatim, from each locked run at this head:The regeneration ran earlier against the same unlocked lock, on a closure build at
47241dd80e:The branch merged
origin/maintwice, as the dispatch orders (d1e09a7eedmergingcd901d7a5f, and6bb4d3b531merging0cb72cfc72); neither touchedpackages/cli, a translations directory or the prose-id ledger. After each merge:pnpm install --frozen-lockfile, then the whole workspace (turbo run build --filter='./packages/*' --filter='./packages/*/*', 71 tasks, 71 successful).vitest run --project unit: 234 files, 3,342 tests; 232 files and 3,337 tests pass, 5 tests in 2 untouched files fail on this host:test/published-subpath-console.pin.test.tsandtest/published-subpath-hook-body.pin.test.tscompare a path underos.tmpdir()with the realpath the resolver answers, and on macOS/varis a symlink to/private/var. WithTMPDIRset to its realpath the same two files pass, 29 of 29 (the fourth line above). Neither file is in this diff; the cli change is comments and two strings.--project integration: 3 files, 60 tests pass) and the nightly-tiervalidate-json-strict-exit.e2e.test.ts(OS_TEST_TIERS=nightly: 1 file, 7 tests pass). So every touched test file ran.test/i18n-extract-source-hashes.test.ts,test/i18n-extract-companion-orphan.test.tsandtest/i18n-extract-generated-apps-leaf-provenance.test.ts(3 files, 25 tests);@objectstack/platform-objects'ssrc/apps/translations(24 files, 430 tests);@objectstack/plugin-sharing'ssrc/translations(3 files, 13 tests). All pass, atd71ab0e27e, whosepackages/cliand companions are byte-identical to this head.pnpm --filter @objectstack/cli typecheckexits 0.tsc --listFilescounts 298srcfiles undertsconfig.json, all 158srctest files among them, so every touched test file is type-checked;check:test-typecheckholds its ledger (3 files, 28 errors, 6 pinned signatures).pnpm lint(eslint . --no-inline-config) exits 0 at6bb4d3b531(2026-09-29T13:44:40Z to 13:45:11Z). Not narrowed.node scripts/check-issue-citations.mjs --base origin/mainexits 0 after the second merge: 67 citations judged across 56 files (66 resolve, 1 cross-repo). These are the live numbers that stay on rewritten lines, 54 of them the [Decision] 把 #8765 的 source-hash sidecar 扩展到生成的 i18n bundle —— #9672 写明的升级条件已满足 #12069 and i18n: a source-string edit still leaves zh-CN / ja-JP / es-ES silently stale — and pinningento the source makes the asymmetry sharper, not smaller (needs a maintainer decision) #8765 pair in the 27 headers. It defers*.test.ts, so the added-minus-removed count over the whole diff covers the rest: 0 numbers added.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsat6bb4d3b531derived 76 families (68 before the prose-id ledger commit put ascripts/path in the change set). All 76 ran, and--ranover a record carrying each exit code reads 「76 derived, 76 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero).pnpm check:bash32-floorruns its self-test first, and 7 of its 179 cases assert that each bash-4 probe is shell THIS host can parse; the only bash here is/bin/bash3.2.57, which cannot. The gate's real-tree half, run alone (node scripts/check-bash32-floor.mjs), exits 0: 32 tracked shell files, 0 findings. The self-test half is NOT MEASURED here, reason: no bash 4+ on this host; CI's bash measures it. This diff touches no shell file.check:doc-authoring(809 pinned sibling prose-id sites, no growth, no unrecorded burn-down),check:i18n(9 packages in sync),check:i18n-coverage(13 configs, none new),check:i18n-stale-fill(27 of 27 companions served, 0 stale),check:i18n-walk-parity,check:nul-bytes(9,283 files, no raw control bytes),check:published-files,check:cli-command-idsandcheck:issue-citations(self-test).6bb4d3b531,check-changeset-fixed(its roster sits under.changeset/),check:error-code-casing,check:filter-alias-parityandcheck:authz-resolver(the four whose rosters share a directory with this diff) among them. The other three,check-closing-target-claim,check-partof-closing-keywordandcheck-single-claim-paths, need a pull request's context; they are run against this PR once it exists and reported on the card. The 17 checker-health-only rows were not run.Hypotheses (measured first)
04b202e5cb(167 lines, 30 files, 50 numbers), equal to the card's count atf11b5f20a2: no drift.#11048(an open support decision) and#11331three times (an enforce leg never built). No site is held for an open PR: the two held files carry no dead citation. The claim's read and this stage's two reads of the open PRs' file lists (12:38:15Z, 7 open PRs; 13:58:56Z, 9 open PRs) found only PR fix(cli)!: the JSX page gate's console manifest fallback resolves through @objectstack/console/package.json, so a project without its own manifest gets full component checking #20589 inpackages/cli/srcand none touching a companion or the prose-id ledger. PR fix(platform-objects): re-translate the object leaves that contradict their current en source #20652, opened after the claim, editspackages/platform-objects's threeLOCALE.objects.generated.tsbundles beside the companions: no file overlap.StringLiteraltokens and nothing else, and its code and string controls each add a difference. The emitteddistis not byte-identical, because docblocks and the two strings ship, which is why the changeset ispatch.git grep -n "#11671" -- '*.source-hashes.generated.ts': 0 hits at head, 27 at04b202e5cb.Acceptance notes
os meta resyncskip explanation atcommands/meta/resync.ts:71, 「on installs from before [finding]os meta resyncmay silently skip every platform default permission set — the seeder never writesmanaged_by, and the tests stub the field default away #8692, the platform's own seeded defaults carry that same stamp」. The comments beside it (resync.ts:55and:96) now cite712e185db. Ruling D (no number, the lesson in words) is a string change outside this stage's two declared strings; the card already carries a form-D stage for the lane (ACCEPT 5888034755), and this string is its author-shown first.#11671outside this stage's surface. The number still stands in other lanes' files: the ninescripts/i18n-extract.config.tsdocstrings (outside the census surface), sixsrc/translations/index.tsfiles (plugin-approvals,plugin-audit,plugin-security,plugin-webhooks,service-realtime,service-storage), six sites inpackages/platform-objects/src(source-hash.tsthree times,setup.translation.ts,metadata-translations/index.ts,source-hash.test.ts),packages/cli/test/i18n-extract-source-hashes.test.ts:3, and 13 inscripts/**and.github/workflows/lint.yml. The anchor for all of them is09b4f4e4e. Noted for those lanes' stages, not touched.packages/clioutsidesrc/**holds 242 dead citations:test/185,scripts/27,bin/10,vitest.config.ts15,vitest-tiers.ts2,vitest-tiers.fixtures.ts,tsconfig.test.jsonandtest-typecheck-debt.json1 each (whole-file projection, the before board). They stay for a later stage of this card.test/published-subpath-console.pin.test.tsandtest/published-subpath-hook-body.pin.test.tsfail 5 tests on macOS, whereos.tmpdir()is a symlink, and pass with a realpathTMPDIR. CI's Linux runners do not see it. Noted, not filed.serve.ts:5621holds the CSS colour#141417in a string. The census blanks strings, so it never sees it; the supplementary whole-file projection reads it as a citation beyond the frontier (never-issued). It is not a citation; it is the second of the twosrc stringsites left in the supplementary table, beside#8692.CITATION_RErefuses a#preceded by/, so the second number of#A/#Bis never judged. Inpackages/cli/srcone such dead number stood (serve.ts:1173, rewritten here). The same shape PR docs(runtime): re-anchor the dead tracker citations in packages/runtime/src to the commits that decided them #20624 and PR docs(rest): re-anchor the dead tracker citations in packages/rest/src to the commits that decided them #20632 reported, for the grammar family PR docs(spec): re-anchor the dead tracker citations in data/ to the commits that decided them (stage 3) #20533 names.Deviations
scripts/doc-authoring-prose-id.baseline.json, the shrink-only ledger ofcheck:doc-authoring's sibling-package prose-id leg, pinned the two#11671string sites this stage removes, so the gate went red (「the prose-id baseline is STALE — pinned entries exceed the tree」) and prescribed regenerating it in the same PR. It was regenerated with its own command (node scripts/check-doc-authoring.mjs --census-ledger, which refuses to grow the ledger): 4 lines removed, the two#11671pairs and nothing else. The claim's file surface did not name this file; it is the gate's own remedy for the two strings the claim does name.#11157) is rewritten, and thirteen more lines are the other half of a rewritten sentence (listed under What changed).validate.ts:813-815moved to the past tense, because the claim they carried was false before this change (see Wordings to check).Claude-SessionplusCo-authored-by: Claude), and the pre-push trailer check passed on every push; the harness's attribution reminder asked for a model-named trailer, which AGENTS.md overrides. The two merge commits carry git's default message.Generated by Claude Code