Repository navigation
docs(rest): re-anchor the dead tracker citations in packages/rest/src to the commits that decided them - #20632
Conversation
…ew pending) Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
…t review fixes Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289 Co-authored-by: Claude <noreply@anthropic.com>
…st-dead-citations
📓 Docs Drift CheckThis PR changes 1 package(s): 11 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 15 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 ac055adb44b962e15291d7abcb5366a05d869ce9 && git checkout ac055adb44b962e15291d7abcb5366a05d869ce9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 542670da6dfc17d3a2ec919139afb7caae018d02 93e4d69ba6258a0c873d541b56184fc40517a04e && git checkout -B drift-repro 542670da6dfc17d3a2ec919139afb7caae018d02 && git merge --no-ff 93e4d69ba6258a0c873d541b56184fc40517a04e
node scripts/docs-audit/affected-docs.mjs --json 542670da6dfc17d3a2ec919139afb7caae018d02
|
Contract reviewServed-tier: Inputs, and nothing else: card #20594's body and all 7 comments (claim ① Derived judgments(1) Comment-only — right. The diff is 462 removed/added pairs: 11 are the new changeset, the other 451 are in the 85 files under (2) Anchors — right; no wrong or unsupported anchor found. 70 distinct shas stand on added lines; one of them,
(3) Tracker numbers — right. 98 distinct numbers stand on removed lines and 24 on added lines. 74 are dropped (on a removed line, on no added line), and every one of the 74 answers 404 on (4) Line counts — right. From the file list: 85 The three sites left — right. At the head, Check-runs on the head. First read 2026-09-29T11:42:55Z: 31 check-runs, 18 success, 3 skipped, 10 in progress, 0 failure. Second read at 12:05:15Z, at the write: 34 check-runs, newest per name, all completed — 31 success, 3 skipped ( ② Semver level
Clause-②: no — right. No accept-set widening, no public-surface change, no behaviour change; the PR body's line-initial ③ Boundary flags
Implemented-by: VERDICT: PASS |
…o the commits that decided them, and the source-hashes header at its producer (objectstack-ai#20656) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 3 of the `domain:cli` lane of the dead-citation sweep: `packages/cli/src/**`, plus the generated-header producer the `domain:services` pointer 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 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 (stage 1, `packages/runtime`) and PR objectstack-ai#20632 (stage 2, `packages/rest`) are the precedents this follows. Later stages cover `types` and the rest of the lane, so this PR says `Part of` and 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`, `objectstack-ai#10943/objectstack-ai#11157`). Each rewritten line cites one of **62 distinct commits**, except the six `objectstack-ai#15041` sites, 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:1435` and `i18n-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:9` read 「PR objectstack-ai#12463 (objectstack-ai#12151) single-sourced」 and now reads 「Commit 27b6902 (PR objectstack-ai#12463) single-sourced」, keeping the live PR as a convenience link beside the commit, as the ruling allows (objectstack-ai#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`: a `patch` changeset for `@objectstack/cli`, and the shrink-only `check:doc-authoring` prose-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. - **The producer.** `packages/cli/src/utils/i18n-extract.ts:2294` is the string literal `renderSourceHashModule` writes as line 8 of every `LOCALE.source-hashes.generated.ts`. It read 「bundles (objectstack-ai#11671, maintainer ruling objectstack-ai#12069 Option A, extending objectstack-ai#8765 Option B).」 and now reads 「bundles (commit 09b4f4e, maintainer ruling objectstack-ai#12069 Option A, extending objectstack-ai#8765 Option B).」. `09b4f4e4e` is the commit that extended the objectstack-ai#8765 Option B source-hash mechanism to the generated bundles per maintainer ruling objectstack-ai#12069 Option A; its message says exactly that, and it is the anchor stages 1 and 2 of objectstack-ai#20596 gave `objectstack-ai#11671`. objectstack-ai#12069 and objectstack-ai#8765 answer 200 (REST and web) and stay. The comment at `:249` beside `previousSourceHashes` cites the same commit. - **The flag's help text** (`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 (objectstack-ai#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. - **The regeneration.** `node scripts/check-i18n-bundles.mjs --write`, which runs each package's documented `os i18n extract` command from its `i18n-extract.config.ts` (every one of the nine carries the source-hashes flag), on a CLI built from `47241dd80e`. Before it, the bundle check reported the nine packages DRIFTED, 3 bundles each, against the new producer. After it: - exactly 27 files changed, `+27 −27`: 3 locales in `packages/platform-objects/src/apps/translations`, `plugins/plugin-{approvals,audit,security,sharing,webhooks}` and `services/service-{messaging,realtime,storage}`; - every hunk is `@@ -8 +8 @@`, and the one removed and one added line are the same in all 27 files; - each file with line 8 deleted hashes identically at base and head (27 of 27), so every hash entry is byte-identical; - `git status` shows nothing else in the nine packages, tracked or untracked; - `node scripts/check-i18n-bundles.mjs` then reads all nine packages in sync (7 bundles each), and `check:i18n-stale-fill` serves 27 of 27 companions with 0 stale fills. - **H3 holds.** `git grep -n "objectstack-ai#11671" -- '*.source-hashes.generated.ts'` answers 0 hits at head; the same grep at `04b202e5cb` answers 27 (the positive control). - **Not published by the nine.** The header is a comment their bundlers strip: after the build, none of the nine packages' `dist` holds `09b4f4e4e` or the header's own phrase 「Each entry is the digest of the SOURCE REVISION」, while the export name `…GeneratedSourceHashes` (the positive control) is in each `dist`. 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.ts` and `sdui-manifest.test.ts` stay at their base blobs (`41c4549ffe` and `3a242b54e0`, equal at base and head), because PR objectstack-ai#20589 edits them. They carry four citations (`objectstack-ai#4409` once, `objectstack-ai#20113` three 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 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/cli/`. Every run enumerated the whole board (185 pages), so none read a truncated board. | reading | tree | board | whole-repo `allocated-but-absent` | cli sites | lines | files | numbers | |---|---|---|---|---|---|---|---| | before | base `04b202e5cb`, run 2026-09-29T12:35:39Z to 12:43:03Z | enumerated, 185 pages, frontier objectstack-ai#20642, 18,469 numbers | 1,707 | **174** | 167 | 30 | 50 | | after | head `6bb4d3b531`, run 13:46:09Z to 13:54:25Z | enumerated, 185 pages, frontier objectstack-ai#20652, 18,479 numbers | 1,510 | **4** | 4 | 3 | 2 | The 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 of `origin/main` moved no count. An earlier after-run at `d1e09a7eed` (13:19:18Z to 13:29:41Z, frontier objectstack-ai#20649) read the same 4 and 1,510; `packages/cli` and the 27 companions are byte-identical between the two heads. One more attempt at `6bb4d3b531` (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) and `classifyCitation` over every `.ts`/`.tsx` file under `packages/cli/src` (298 files), against a board enumerated through the gate's own `enumerateBoard`. The lit controls objectstack-ai#20594, objectstack-ai#19123 and objectstack-ai#20632 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, 12:43Z | `04b202e5cb` | 185 pages, frontier objectstack-ai#20642 | 3,029 | **368** | 174 | 142 | 4 | 48 | | after, 13:39Z | `6bb4d3b531` | 185 pages, frontier objectstack-ai#20650 | 2,715 | **54** | 4 | 0 | 2 | 48 | Its 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 `objectstack-ai#11671` strings). The one slash-joined dead number the grammar never reads (`objectstack-ai#11157` in `objectstack-ai#10943/objectstack-ai#11157`) is gone too: a separate scan for dead `#N` tokens 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. `left` is a site with no deciding commit (see below). `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 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. | number | comment sites / files | rewritten | left | strings kept | anchor | |---|---|---|---|---|---| | `objectstack-ai#6217` | 12/8 (1 test) | 12 | 0 | 0 | `2b641ddd4` | | `objectstack-ai#6238` | 2/1 (2 test) | 2 | 0 | 2 | `c8d6f6e08` | | `objectstack-ai#6265` | 1/1 (1 test) | 1 | 0 | 0 | `cfb549db8` | | `objectstack-ai#6268` | 6/2 (2 test) | 6 | 0 | 1 | `68f5eccb1` | | `objectstack-ai#6293` | 2/2 (1 test) | 2 | 0 | 0 | `c39a911ae` | | `objectstack-ai#6344` | 2/2 (1 test) | 2 | 0 | 0 | `cfb549db8` | | `objectstack-ai#6345` | 21/6 (11 test) | 21 | 0 | 4 | `e2798fab7` | | `objectstack-ai#6535` | 1/1 | 1 | 0 | 0 | `a92b1793c` | | `objectstack-ai#8692` | 5/2 (3 test) | 5 | 0 | 3 | `712e185db` | | `objectstack-ai#10326` | 1/1 | 1 | 0 | 0 | `675ab574e` | | `objectstack-ai#10359` | 2/2 | 2 | 0 | 0 | `15b63e85a` | | `objectstack-ai#10398` | 1/1 (1 test) | 1 | 0 | 0 | `0681a76b8` | | `objectstack-ai#10485` | 1/1 | 1 | 0 | 0 | `35ad101bc` | | `objectstack-ai#10499` | 1/1 | 1 | 0 | 0 | `6d441e41f` | | `objectstack-ai#10504` | 8/1 | 8 | 0 | 0 | `ff5733e03`, `0d4bd93e7` | | `objectstack-ai#10514` | 16/2 (16 test) | 16 | 0 | 2 | `5359a9b4c` | | `objectstack-ai#10763` | 1/1 (1 test) | 1 | 0 | 0 | `c2b97c2a1` | | `objectstack-ai#10769` | 9/2 (6 test) | 9 | 0 | 0 | `3d7deb700` | | `objectstack-ai#10908` | 10/3 (6 test) | 10 | 0 | 5 | `9cc6777d3` | | `objectstack-ai#10909` | 2/1 | 2 | 0 | 0 | `5a90c56d1` | | `objectstack-ai#10917` | 1/1 | 1 | 0 | 0 | `7940de5e0` | | `objectstack-ai#10926` | 1/1 | 1 | 0 | 0 | `d173125fb` | | `objectstack-ai#10943` | 5/3 (2 test) | 5 | 0 | 0 | `46d34ab7c` | | `objectstack-ai#10944` | 9/3 (6 test) | 9 | 0 | 3 | `e598b1cbc` | | `objectstack-ai#10952` | 5/1 | 5 | 0 | 0 | `0d4bd93e7`, `ff5733e03` | | `objectstack-ai#10953` | 1/1 (1 test) | 1 | 0 | 0 | `be7262e72` | | `objectstack-ai#10967` | 6/2 (6 test) | 6 | 0 | 1 | `e4a71d418` | | `objectstack-ai#11022` | 1/1 (1 test) | 1 | 0 | 0 | `21756b325` | | `objectstack-ai#11025` | 3/2 | 3 | 0 | 0 | `1c3a46f87` | | `objectstack-ai#11048` | 1/1 | 0 | 1 | 0 | — | | `objectstack-ai#11071` | 3/2 | 3 | 0 | 0 | `50fb191dc` | | `objectstack-ai#11157` | 15/4 (10 test) (1 slash-joined) | 15 | 0 | 2 | `a4cb7817f` | | `objectstack-ai#11172` | 5/1 | 5 | 0 | 0 | `05181e8cc` | | `objectstack-ai#11174` | 2/1 (2 test) | 2 | 0 | 1 | `ab23c67ab` | | `objectstack-ai#11221` | 3/1 (3 test) | 3 | 0 | 1 | `e278a2970` | | `objectstack-ai#11331` | 3/2 | 0 | 3 | 0 | — | | `objectstack-ai#11671` | 1/1 | 1 | 0 | 0 (2 moved) | `09b4f4e4e` | | `objectstack-ai#12125` | 11/3 | 11 | 0 | 0 | `79cf692b0` | | `objectstack-ai#12151` | 3/2 (3 test) | 3 | 0 | 3 | `27b690272` | | `objectstack-ai#12162` | 2/1 (2 test) | 2 | 0 | 0 | `c0f5e8f21` | | `objectstack-ai#12181` | 4/2 (3 test) | 4 | 0 | 0 | `cf71d73f8` | | `objectstack-ai#12297` | 3/1 | 3 | 0 | 0 | `9fd45a952` | | `objectstack-ai#12943` | 2/1 (2 test) | 2 | 0 | 0 | `090f2302e` | | `objectstack-ai#12961` | 1/1 | 1 | 0 | 0 | `901355c3b` | | `objectstack-ai#13109` | 2/1 | 2 | 0 | 0 | `8b236c826` | | `objectstack-ai#13193` | 6/2 (3 test) | 6 | 0 | 0 | `faff497fd` | | `objectstack-ai#13218` | 1/1 | 1 | 0 | 0 | `c45d8e6b4` | | `objectstack-ai#13347` | 3/3 (2 test) | 3 | 0 | 3 | `098a08ffa` | | `objectstack-ai#13651` | 12/7 (4 test) | 12 | 0 | 0 | `ada3834ad` | | `objectstack-ai#14192` | 2/2 | 2 | 0 | 0 | `4d0d9445a` | | `objectstack-ai#14336` | 4/1 | 4 | 0 | 0 | `79c71d29d` | | `objectstack-ai#14397` | 1/1 | 1 | 0 | 1 | `957f7bb45` | | `objectstack-ai#14657` | 20/2 (7 test) | 20 | 0 | 1 | `431979e67` | | `objectstack-ai#14667` | 1/1 | 1 | 0 | 0 | `dc7c226b9` | | `objectstack-ai#14824` | 3/1 | 3 | 0 | 0 | `cf6b67164` | | `objectstack-ai#14828` | 22/3 (7 test) | 22 | 0 | 3 | `08706f0e0` | | `objectstack-ai#14829` | 9/3 (6 test) | 9 | 0 | 3 | `ee370d318` | | `objectstack-ai#14902` | 1/1 | 1 | 0 | 0 | `61821e54c` | | `objectstack-ai#15040` | 6/3 (3 test) | 6 | 0 | 2 | `8644d1d33` | | `objectstack-ai#15041` | 6/5 (4 test) | 6 | 0 | 2 | ADR-0104 (2026-09-05 addendum, landed as 932acc3) | | `objectstack-ai#15045` | 2/2 (1 test) | 2 | 0 | 0 | `288fe9c34` | | `objectstack-ai#16887` | 2/1 (2 test) | 2 | 0 | 0 | `9cdffbe36` | | `objectstack-ai#17080` | 1/1 (1 test) | 1 | 0 | 0 | `8b4890343` | | `objectstack-ai#17081` | 8/3 (4 test) | 8 | 0 | 3 | `f721ef0ff`, `24d622b94` | | `objectstack-ai#17883` | 10/3 (5 test) | 10 | 0 | 3 | `b06b2db5c` | | **total** | **317** | **313** | **4** | **49** | **62 distinct commits + ADR-0104** | Every 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-repository` false); the control leg `13a6cb4ad` exits 0 and the negative control (this branch's own `47241dd80e`, not on `main`) exits 1. ADR-0104's 2026-09-05 addendum landed as `932acc3df`, 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, objectstack-ai#17081 for its application half only; for example `e2798fab7` for objectstack-ai#6345, `68f5eccb1` for objectstack-ai#6268, `35ad101bc` for objectstack-ai#10485, `09b4f4e4e` for objectstack-ai#11671 and `61821e54c` for objectstack-ai#14902), so each number carries one anchor across the tree. Several numbers are the PR number of their own anchor commit (objectstack-ai#6344, objectstack-ai#10398, objectstack-ai#14667, objectstack-ai#16887), so the sha is the same object the number named. **Numbers with more than one anchor, by site:** - `objectstack-ai#10504` / `objectstack-ai#10952` (`format.ts`): `ff5733e03` added the opt-in zero row for `UI:` alone and `0d4bd93e7` made it required for every section, so lines naming both now name both commits. `format.ts:1573` read 「(objectstack-ai#10504, objectstack-ai#10952, objectstack-ai#11172)」 and now reads 「(commits ff5733e, 0d4bd93, 05181e8)」. - `objectstack-ai#10943` / `objectstack-ai#11157` (`serve.ts`): `46d34ab7c` made the host importer's fallback base a caller-supplied parameter, and `a4cb7817f` made `serve` pass its own base and collapsed `importConfigPlugin` from three branches to two. The slash-joined `serve.ts:1173` 「(objectstack-ai#10943/objectstack-ai#11157)」 now reads 「(commits 46d34ab and a4cb781)」; `serve.ts:1459` 「(objectstack-ai#10908 → objectstack-ai#11157)」 reads 「(commits 9cc6777 → a4cb781)」. - `objectstack-ai#17081` (8 sites): one card with two halves. `f721ef0ff` took the platform's half (the `Dev admin` banner line says what the account sees) for 7 sites; `format.ts:1132` describes the application half and now reads 「[objectstack-ai#17556 — commit 24d622b]」, the spelling the spec stage used at `dev-login.zod.ts:10`, with `format.ts:1133` naming objectstack-ai#17081 in words (「its parent card」). - `objectstack-ai#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:** - A commit does not rule. Where a line said a number ruled, it now says what the commit did with the ruling: 「semantics by the ruling commit 68f5ecc landed」, 「Ruled at triage, landed as commit e598b1c」, 「the triage commit 9cc6777 landed requires this text be CHOSEN」, 「Rulings objectstack-ai#5728 and objectstack-ai#14412, and the ruling commit d173125 landed,」, and `resync.ts:96` keeps the ruling's date from `712e185db`'s message: 「commit 712e185 (the 2026-08-15 ruling)」. - A line that named a DEFECT by its number now says so: 「the defect commit 79cf692 fixed」, 「the defect commit 9cc6777 fixed」, 「the exact defect commit 08706f0 closed」, 「the hard-failure class of the `22P02` commit 8644d1d fixed」, 「Before commit 5359a9b (raw)」 / 「Since commit 5359a9b (masked)」. - **A stale claim, corrected by its anchor.** `validate.ts:813-815` said 「`ManifestSchema` is not `.strict()` and drops unknown keys with nothing said (objectstack-ai#14192)」, but `ManifestSchema` has been `strictObject` since `4d0d9445a`, 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」. - **Anchors found by diff, not by subject.** `objectstack-ai#10326` has no commit message naming it; `675ab574e` took the 1.7.1 measurement the line cites, and its own changeset and test name objectstack-ai#10326. `objectstack-ai#12162` is named by no message either; `c0f5e8f21` is the only commit that ever added the number, and its message states the point the lines make. `objectstack-ai#14397`'s citation was added by `957f7bb45`'s own diff, which is the change the heading describes. `objectstack-ai#10763` is added three times by `c2b97c2a1`'s diff. - `objectstack-ai#10499` (`init.ts:978`): the line uses the earlier drift between the two scaffold paths as precedent; that drift was about pnpm build approvals, and `6d441e41f` gated the two paths against each other, so the line reads 「already drifted once (closed by commit 6d441e4)」. - `objectstack-ai#6293`: `c39a911ae` is the commit that found the 「headless husk」 `JSON.stringify(stack)` leaves where a declaration was; `bf4ebe2f3`, which wrote the cli lines, only cites it. - Quoted text: `generate-field-type-vocabulary.pin.test.ts:92` sits 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 objectstack-ai#20624 did. - Headings with a dash rule (`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:893` is 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` (objectstack-ai#11048): 「whether to admit that band at all is objectstack-ai#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.15` at the base. - `plugin/publish.ts:118`, `osplugin.ts:21`, `osplugin.ts:49` (objectstack-ai#11331): the parenthetical points at the unpack-time integrity re-verification leg, which was never built (`b60f48b52`: 「The enforce leg points at objectstack-ai#11331」). No commit decides it; the ownership clause on the same lines comes from `f89812e4d`, 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 resync` skip explanation at `commands/meta/resync.ts:71`, 「on installs from before objectstack-ai#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 `04b202e5cb` against the working tree, over all 65 touched files in `packages/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. - Real run: 156,633 base tokens, token counts equal in every file, **exactly 2 differing tokens**, both `StringLiteral`: `commands/i18n/extract.ts:227` (the help text) and `utils/i18n-extract.ts:2294` (the header line). No other token in any file differs. - Comment-insertion control (`serve.ts`): still exactly those 2 (exit 1, no new difference). - Code-insertion positive control (a declaration in `serve.ts`): the count differs (17,815 to 17,820) and a third difference appears at token 0. - String positive control (one character added inside the first string literal past offset 2000 of `serve.ts`): a third difference appears, a `StringLiteral` at token 145. - The 27 generated companions: 2,940 base tokens, 0 differing tokens (their only change is a JSDoc line). 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 `patch` changeset for `@objectstack/cli` is included, in PR objectstack-ai#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[]` is `dist`, `README.md` and `CHANGELOG.md`. After the build, the rewritten docblocks reach `dist`: 142 `commit SHA` citations in 39 of its `.js` / `.d.ts` files. For example `storage-driver.ts:91`'s rewritten line 「(commit 68f5ecc). These are the」 is in both `dist/utils/storage-driver.d.ts` and `.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 in `dist/commands/i18n/extract.js`, the header literal with `09b4f4e4e` is in `dist/utils/i18n-extract.js`, and `objectstack-ai#11671` appears nowhere in the package's `dist`. ## Gates (head `6bb4d3b531`) 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 110s (1m50s) · declare it in the PR body · pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=4 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 12s · declare it in the PR body · pnpm --filter @objectstack/cli typecheck os-verify-lock: VERDICT command-exit 1 · UNLOCKED (declared) · no usable `flock` on this host, so the shared verify lock was NEVER taken and NOTHING was serialized · ran 150s (2m30s) · declare it in the PR body · pnpm --filter @objectstack/cli exec vitest run --project unit --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/cli exec vitest run --project unit --maxWorkers=2 test/published-subpath-console.pin.test.ts test/published-subpath-hook-body.pin.test.ts 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 9s · declare it in the PR body · pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 src/commands/generate-declared-column-default.pin.test.ts src/commands/generate-string-family-width.pin.test.ts src/commands/meta/delete-reset-carriers.test.ts 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 30s · declare it in the PR body · pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 src/commands/validate-json-strict-exit.e2e.test.ts ``` The regeneration ran earlier against the same unlocked lock, on a closure build at `47241dd80e`: ```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 102s (1m42s) · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/cli...' --filter '@objectstack/platform-objects...' --filter '@objectstack/plugin-approvals...' --filter '@objectstack/plugin-audit...' --filter '@objectstack/plugin-security...' --filter '@objectstack/plugin-sharing...' --filter '@objectstack/plugin-webhooks...' --filter '@objectstack/service-messaging...' --filter '@objectstack/service-realtime...' --filter '@objectstack/service-storage...' build ``` The branch merged `origin/main` twice, as the dispatch orders (`d1e09a7eed` merging `cd901d7a5f`, and `6bb4d3b531` merging `0cb72cfc72`); neither touched `packages/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). - **Tests** (unit tier, then every touched file outside it): - `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.ts` and `test/published-subpath-hook-body.pin.test.ts` compare a path under `os.tmpdir()` with the realpath the resolver answers, and on macOS `/var` is a symlink to `/private/var`. With `TMPDIR` set 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. - The unit tier holds 32 of the 36 touched test files. The other four ran by name: the three integration-tier files (`--project integration`: 3 files, 60 tests pass) and the nightly-tier `validate-json-strict-exit.e2e.test.ts` (`OS_TEST_TIERS=nightly`: 1 file, 7 tests pass). So every touched test file ran. - The producer's own tests and the companions' readers: `test/i18n-extract-source-hashes.test.ts`, `test/i18n-extract-companion-orphan.test.ts` and `test/i18n-extract-generated-apps-leaf-provenance.test.ts` (3 files, 25 tests); `@objectstack/platform-objects`'s `src/apps/translations` (24 files, 430 tests); `@objectstack/plugin-sharing`'s `src/translations` (3 files, 13 tests). All pass, at `d71ab0e27e`, whose `packages/cli` and companions are byte-identical to this head. - **Typecheck:** `pnpm --filter @objectstack/cli typecheck` exits 0. `tsc --listFiles` counts 298 `src` files under `tsconfig.json`, all 158 `src` test files among them, so every touched test file is type-checked; `check:test-typecheck` holds its ledger (3 files, 28 errors, 6 pinned signatures). - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at `6bb4d3b531` (2026-09-29T13:44:40Z to 13:45:11Z). Not narrowed. - **Citation judging:** `node scripts/check-issue-citations.mjs --base origin/main` exits 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 objectstack-ai#12069 and objectstack-ai#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. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at `6bb4d3b531` derived 76 families (68 before the prose-id ledger commit put a `scripts/` path in the change set). All 76 ran, and `--ran` over a record carrying each exit code reads 「76 derived, 76 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero). - 75 exit 0. One exits 1 for this host, not for this diff: `pnpm check:bash32-floor` runs 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/bash` 3.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. - Among them: `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-ids` and `check:issue-citations` (self-test). - **Artifact rosters:** 35 of the 38 non-self-test roster rows exit 0 at `6bb4d3b531`, `check-changeset-fixed` (its roster sits under `.changeset/`), `check:error-code-casing`, `check:filter-alias-parity` and `check:authz-resolver` (the four whose rosters share a directory with this diff) among them. 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 17 checker-health-only rows were not run. ## Hypotheses (measured first) - **H0 holds.** The filtered census answers 174 dead sites at `04b202e5cb` (167 lines, 30 files, 50 numbers), equal to the card's count at `f11b5f20a2`: no drift. - **H1 holds, with the listed exceptions.** After the rewrite the filtered census answers 4, all for an unfound anchor: `objectstack-ai#11048` (an open support decision) and `objectstack-ai#11331` three 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 objectstack-ai#20589 in `packages/cli/src` and none touching a companion or the prose-id ledger. PR objectstack-ai#20652, opened after the claim, edits `packages/platform-objects`'s three `LOCALE.objects.generated.ts` bundles beside the companions: no file overlap. - **H2 holds, by the token guard.** A comment-stripped comparison of every touched file (the parser's leaf tokens, JSDoc excluded, every difference listed) finds exactly the two declared `StringLiteral` tokens and nothing else, and its code and string controls each add a difference. The emitted `dist` is not byte-identical, because docblocks and the two strings ship, which is why the changeset is `patch`. - **H3 holds.** `git grep -n "objectstack-ai#11671" -- '*.source-hashes.generated.ts'`: 0 hits at head, 27 at `04b202e5cb`. ## Acceptance notes - **Form D, not touched here.** 49 dead numbers stand inside string literals: 48 in test titles and test-code strings (22 files, 21 numbers), and one an operator reads: the `os meta resync` skip explanation at `commands/meta/resync.ts:71`, 「on installs from before objectstack-ai#8692, the platform's own seeded defaults carry that same stamp」. The comments beside it (`resync.ts:55` and `:96`) now cite `712e185db`. 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. - **`objectstack-ai#11671` outside this stage's surface.** The number still stands in other lanes' files: the nine `scripts/i18n-extract.config.ts` docstrings (outside the census surface), six `src/translations/index.ts` files (`plugin-approvals`, `plugin-audit`, `plugin-security`, `plugin-webhooks`, `service-realtime`, `service-storage`), six sites in `packages/platform-objects/src` (`source-hash.ts` three times, `setup.translation.ts`, `metadata-translations/index.ts`, `source-hash.test.ts`), `packages/cli/test/i18n-extract-source-hashes.test.ts:3`, and 13 in `scripts/**` and `.github/workflows/lint.yml`. The anchor for all of them is `09b4f4e4e`. Noted for those lanes' stages, not touched. - **Outside the scope and the census surface.** `packages/cli` outside `src/**` holds 242 dead citations: `test/` 185, `scripts/` 27, `bin/` 10, `vitest.config.ts` 15, `vitest-tiers.ts` 2, `vitest-tiers.fixtures.ts`, `tsconfig.test.json` and `test-typecheck-debt.json` 1 each (whole-file projection, the before board). They stay for a later stage of this card. - **A host-dependent pin.** `test/published-subpath-console.pin.test.ts` and `test/published-subpath-hook-body.pin.test.ts` fail 5 tests on macOS, where `os.tmpdir()` is a symlink, and pass with a realpath `TMPDIR`. CI's Linux runners do not see it. Noted, not filed. - **A hex colour in the whole-file reading.** `serve.ts:5621` holds the CSS colour `#141417` in 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 two `src string` sites left in the supplementary table, beside `objectstack-ai#8692`. - **The slash-joined grammar gap, again.** `CITATION_RE` refuses a `#` preceded by `/`, so the second number of `#A/#B` is never judged. In `packages/cli/src` one such dead number stood (`serve.ts:1173`, rewritten here). The same shape PR objectstack-ai#20624 and PR objectstack-ai#20632 reported, for the grammar family PR objectstack-ai#20533 names. ## Deviations - **One file outside the claim's surface.** `scripts/doc-authoring-prose-id.baseline.json`, the shrink-only ledger of `check:doc-authoring`'s sibling-package prose-id leg, pinned the two `objectstack-ai#11671` string 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 `objectstack-ai#11671` pairs 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. - One site beyond the census's read grammar (the slash-joined `objectstack-ai#11157`) is rewritten, and thirteen more lines are the other half of a rewritten sentence (listed under What changed). - `validate.ts:813-815` moved to the past tense, because the claim they carried was false before this change (see Wordings to check). - Anchor research for 64 of the 65 numbers ran in four read-only research subagents; every proposal was checked here against the commit's message or diff and every changed line was reviewed, and eight were reworded by hand (the four lines two subagents shared, 「that commit's to」, the kept PR link, and two companions). - 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, which AGENTS.md overrides. The two merge commits carry git's default message. --- _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>
…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>
…/src to the commits that decided them (objectstack-ai#20703) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 6 of the `domain:cli` lane of the dead-citation sweep: `packages/client/src`. Every comment site there 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 keeps saying in its own words what that commit decided. PR objectstack-ai#20533 is the method and stages 1 to 5 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **43 sites on 43 lines in 7 files, covering 13 numbers**, rewritten to **12 distinct commits**: - the census's **19 sites**, all in `src/index.ts` (8 numbers); - **24 test-file comment sites** in 6 test files (the census defers `*.test.ts`; stages 1 to 5 took test comments too). One more line changed: `client.test.ts:2198`, the second half of the `:2197` sentence ("byte-identical to the pre-(number) behavior" now reads "byte-identical to the behavior before commit cf74a11"). Only comments changed: **44 lines out, 44 in**, and every touched file keeps its line count, so no line citation into these files moves. **No citation number is added**: over the 44 line pairs, added-minus-removed numbers is empty, and no PR number stands on an added line. No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records any of these 13 decisions, so every anchor is a commit. A **`patch` changeset** for `@objectstack/client` rides along, because the rewritten docblocks reach `dist` (measured below). ## Census: `packages/client`, 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. The count is its `allocated-but-absent` findings under `packages/client/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | `packages/client` sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `3b47a693c7`, run 2026-09-29T18:31:09Z to 18:35:42Z | enumerated, 186 pages, frontier objectstack-ai#20701, 18,528 numbers | 1,298 | **19** | 19 | 8 | 1 (`src/index.ts`) | | after | `221a3f5e63`, run 18:39:47Z to 18:44:31Z | enumerated, 186 pages, frontier objectstack-ai#20702, 18,529 numbers | 1,279 | **0** | 0 | 0 | 0 | The whole-repo drop of 19 is exactly these sites: a site-by-site diff of the two JSON outputs has 19 findings gone, all in `packages/client/src/index.ts`, and none added. `packages/client/src` is byte-identical at `221a3f5e63` and at the head. **Supplementary scan (test files included).** The gate's exported `extractCitations` and `classifyCitation` over all 53 `.ts` files under `src/`, with the board from the gate's own `probeBoard`: 963 citations and 61 dead before (src comments 19, test comments 24, src strings 0, test strings 18), 920 and 18 after (0, 0, 0, 18). Its before list of src comment sites is identical to the census's. The 18 left are test titles, the form-D stage (see Acceptance notes). ## Per-site table `git blame` at the base ties each line to the commit that wrote it, and each anchor was read in its message, changeset or diff, not only its subject. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#12195` | `index.ts:684`, `:728`, `:1834`, `:2021`; `client.test.ts:2869`; `meta-automation-descriptors.test.ts:29` | `7986d973f`, stage 3 of the compound-name retirement: un-mounts the three `:section` arities and unifies the SDK's URL spelling on `encodeURIComponent`. All six lines blame to it. | | `objectstack-ai#12176` | `client.test.ts:357`; `meta-automation-descriptors.test.ts:31` | `7986d973f` as well: the lines say the card "retired compound-name addressing", and that commit completes the retirement. Both lines blame to it, and the landed stages give this number the same anchor. | | `objectstack-ai#12194` | `index.ts:738`, `:1838`, `:2026`; `client.test.ts:360`; `meta-automation-descriptors.test.ts:43` | `311433f6b`, stage 1: the item-name grammar, refused at the publish door. | | `objectstack-ai#12181` | `index.ts:799`, `:820`, `:911`, `:1866`; `meta-delete-item-carriers.test.ts:4`, `:265` | `cf71d73f8`: `meta.deleteItem` sends the reset door's `If-Match` pin and `?state=draft` on both declarations. Its changeset also records the withholding of `?dropStorage` that `:820` and the test's `:265` describe. All six lines blame to it; stage 3 gave the number the same anchor. | | `objectstack-ai#14879` | `index.ts:3479`, `:3552`, `:3635`, `:7536`; `client.data-prefix.test.ts:4`; `client.metadata-prefix.test.ts:7`; `client.test.ts:2165`, `:2197` | `cf74a1128`: the SDK reads the CRUD data prefix from discovery instead of restating `/data` (`_dataPrefix()`). Six lines blame to it; `index.ts:3552` and `client.metadata-prefix.test.ts:7` blame to `032452a54`, the metadata-prefix sibling, and name the data-prefix change as their precedent. | | `objectstack-ai#14313` | `index.ts:4911`; `return-type-precision.test.ts:1031` | `b1b978c8d`: binds the `auth.*` family to the wire shapes better-auth sends, and deliberately leaves `auth.deleteUser` unbound (the member `:4911` describes). Both lines blame to it. | | `objectstack-ai#14312` | `return-type-precision.test.ts:891`, `:973`, `:981`, `:1130` | `e944fdb24`: binds four `oauth.*` methods and deliberately leaves `oauth.applications.delete` unbound, the "open decision" `:973` and `:981` name. `:891` blames to it; `:973` and `:981` blame to the later delete binding (`7beaaa32c`) and `:1130` to `b1b978c8d`, and each refers back to what the `oauth.*` card did. | | `objectstack-ai#14314` | `return-type-precision.test.ts:1138` | `7092d63e4`: binds the `organizations.*` family. The line blames to it. | | `objectstack-ai#6361` | `index.ts:6379`; `client.test.ts:878`, `:1390` | `90bbf2510`: retires the notification-list `cursor` on both halves. `:1390` blames to `0b4022b41`, which applies the same retirement one door over and names this one as its precedent. Stages 1 and 2 and the spec lane gave the number this anchor. | | `objectstack-ai#9934` | `index.ts:7406`; `client.test.ts:27` | `79c46da90`: the producer-side `userMessage` marking. Both lines blame to it; the anchor the landed stages give this number. | | `objectstack-ai#6239` | `index.ts:8122` | `f549a0d4a`: the ADR-0049 retirement sweep that deleted `ViewProtocol` and its schemas. The line blames to it; the spec lane's stage 2 gave the number this anchor. | | `objectstack-ai#8480` | `client.test.ts:512` | `caaae2cca`: the typed `security.explain()` request gains the `recordIds` batch spelling. The line blames to it, and its changeset names the card. | | `objectstack-ai#13208` | `return-type-precision.test.ts:1394`, `:1415` | `74049254d`: `DeleteMetaItemResponseSchema` declares `seq` and `projectionApplied`. `objectstack-ai#13208` was the pull request that landed as this commit (its subject carries the number), and it answers 404 too. `objectstack-ai#13155`, the issue beside it, answers 200 and stays. | **Anchor checks.** 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 `main` (`merge-base --is-ancestor` against `31ed067639`, exit 0 for all 12). The checkout is not shallow. The control leg `6f657f4f5` (2026-08-07, the parent of the oldest anchor `f549a0d4a` of 2026-08-08) exits 0, and the negative control, this branch's own `221a3f5e63`, exits 1. Six anchors reuse the landed stages' (`7986d973f`, `311433f6b`, `cf71d73f8`, `90bbf2510`, `79c46da90`, `f549a0d4a`), so each number carries one anchor across the tree; six are new (`cf74a1128`, `b1b978c8d`, `e944fdb24`, `7092d63e4`, `caaae2cca`, `74049254d`). **Numbers.** All 13 dropped numbers answer 404 by REST (re-probed 2026-09-29T18:59Z). The three numbers kept on changed lines (`objectstack-ai#8326`, `objectstack-ai#12104`, `objectstack-ai#13155`) answer 200. Five slash-joined numbers stand in `packages/client/src`, which the citation grammar does not read (`objectstack-ai#11925/objectstack-ai#12036`, `objectstack-ai#3431/objectstack-ai#3455`, `objectstack-ai#2567/objectstack-ai#3963`, `objectstack-ai#5449/objectstack-ai#5546`, `objectstack-ai#5674/objectstack-ai#5787`); their second halves all answer 200, so none is dead. **Wordings to check, each true of its commit:** - `index.ts:820` "Maintainer-seat ruling, landed by commit cf71d73": that commit's changeset states the withholding in the same terms ("no caller was measured needing it from this client"). - `index.ts:3552` now reads "The defect commit cf74a11 fixed, one key over"; `client.metadata-prefix.test.ts:7` reads "the `crud.dataPrefix` defect commit cf74a11 fixed". - `index.ts:738` keeps "Stage 1" beside the commit, and its "this stage" is the docblock's own commit, tagged `7986d973f` at `:728`. - `return-type-precision.test.ts:891`, `:1031`, `:1138` keep "card N of 3 of objectstack-ai#12104" (that number answers 200). ## Mechanical guard: no code token moves **H2 holds on the comment-stripped reading; the emitted `dist` is NOT byte-identical, because the docblocks ship.** **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, JSDoc nodes excluded) of the 7 touched files at base `3b47a693c7` and at `221a3f5e63`. Controls mutate the head text in memory only. - Real run: 68,102 base tokens, 0 differing (exit 0). - Comment-insertion control: 0 differing (exit 0). - Code-insertion control: all 7 files differ at token 0 (exit 1). - String control (`'token'` to `'tokeN'` in the code literal at `index.ts:4895`): exactly 1 differing `StringLiteral`, at token 14,882 of `index.ts` (exit 1). **Emitted `dist`.** `pnpm --filter @objectstack/client build` at base (the base tree of `packages/client/src` restored in place with a trap-armed restore; blob-equal to HEAD and `git diff HEAD` empty afterwards) and at the head, with the same dependency builds: - `index.d.ts`, `index.d.mts`, `index.js` and `index.mjs` differ; `index.js.map` and `index.mjs.map` are equal. - The same parser comparison over the four differing `dist` files reads 0 differing tokens (12,637 / 12,637 / 25,487 / 25,184), so the whole `dist` delta is comment text. Its code control (a code line appended to `index.mjs`) reads COUNT DIFFERS. A first try at that control appended the line onto the file's last line, which is the `sourceMappingURL` comment with no trailing newline, so it landed inside a comment, read 0, and was void; it was redone after a newline. - The new wording is in `dist`: for example "commit cf74a11" appears 4 times in `index.d.ts` and `index.js`. - Code-mutation control (`scripts/ablation-replace.mjs`, anchor `searchParams.set('token'` hit 1 to 0, blob restored to HEAD `19305adddb`, `git diff HEAD` empty): changes `index.js` and `index.mjs`. `dist` was rebuilt to the head bytes and `scripts/ablation-dist-preflight.mjs` reads the marker absent from all 6 files with a clean tree. A raw scan of the 8 changed files for control bytes finds none (a positive probe on a scratch file matched). ## Changeset **`patch` for `@objectstack/client`** (`.changeset/client-provenance-anchors.md`), in PR objectstack-ai#20632's form. `@objectstack/client`'s `files[]` is `dist`, `README.md` and `CHANGELOG.md`, and the build above emits different `index.d.ts` / `index.d.mts` / `index.js` / `index.mjs` at base and head, so this diff publishes. `check-changeset-no-major`, `check-empty-changeset`, `check-adr-0087-registration` and `check-changeset-fixed` all exit 0. ## Gates (head `afa654081f`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its disclosure, verbatim, from each run at this head and from the two `dist` builds: ```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 59s · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/client...' 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 121s (2m01s) · declare it in the PR body · pnpm turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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 21s · declare it in the PR body · pnpm --filter @objectstack/client exec vitest run --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 8s · declare it in the PR body · pnpm --filter @objectstack/client 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 2s · declare it in the PR body · pnpm --filter @objectstack/client build ``` - **Build:** `@objectstack/client`'s closure (35 of 81 workspace projects), then the whole workspace, `turbo run build --filter='./packages/*' --filter='./packages/*/*'`, 71 of 71 tasks, after the merge. - **Tests:** `vitest run`: 50 files, 641 tests passed (every `*.test.ts` under `src/`; `tests/integration/**` needs a running server and is excluded by the package's own config). - **Typecheck:** `pnpm --filter @objectstack/client typecheck` exits 0. `tsc --listFiles`: `tsconfig.json` compiles the 3 non-test `src` files, `tsconfig.test.json` all 53 including the 50 test files. `check:test-typecheck`: 0 files, 0 errors, 0 pinned signatures. - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 (2026-09-29T18:57:45Z to 18:58:13Z). - **Citation judging:** after merging `origin/main` (`31ed067639`), `node scripts/check-issue-citations.mjs --base origin/main` reports "no issue citations added against 31ed067 (1 file(s) read)" (exit 0); pinned `--base 31ed067` reads the same. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 61 families. All 61 exit 0, and `--ran` with the exit-coded record reads "61 derived, 61 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: `check:issue-citations`, `check:doc-authoring` (808 pinned sites, no growth), `check:nul-bytes` (9,315 files, no raw control bytes), `check:published-files`, `check:type-check-debt`. - **Artifact rosters:** 36 of the 39 non-self-test roster rows exit 0, including the four the derivation marks as keeping their roster under one of this diff's paths (`check-changeset-fixed`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `3b47a693c7` the filtered census answers 19 sites on 19 lines, 8 numbers, all in `src/index.ts`. The whole-repo count is 1,298, as on `0be898499f`. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/client`. No site was left for an open PR (the file lists of all open PRs were read at 18:36:50Z, 11 PRs, and at 19:01:46Z, 8 PRs: only the Version Packages PR objectstack-ai#20639 touches `packages/client`, in `CHANGELOG.md` and `package.json`) or for an unfound anchor. - **H2 holds on the token reading, not on the `dist` reading.** The parser leaf-token diff is empty with its controls firing. The emitted `dist` differs, and the difference is comment text only (token-identical `dist` with a code control). That is why the changeset ships. ## Acceptance notes - **Test titles, the form-D stage.** 18 dead numbers remain in test string literals in `packages/client/src` (`describe` and `it` titles, no assertion text): `objectstack-ai#12195` 6, `objectstack-ai#12181` 5, `objectstack-ai#14879` 4, `objectstack-ai#9934` 1, `objectstack-ai#8480` 1, `objectstack-ai#6361` 1. They stay on the card for its form-D stage; no string moved here. - **Outside `src/**`, a later stage of the card:** `packages/client/tsconfig.json:8` and `packages/client/vitest.config.ts:33` cite `objectstack-ai#12181` (404), and `packages/client/test-typecheck-debt.json:3` cites `objectstack-ai#6083` (404). The other citations in `packages/client` outside `src/**` (`CHANGELOG.md` excluded) answer 200. - **The moving `origin/main`.** The branch merged `origin/main` once (`afa654081f`, merging `31ed067639`: `lint`, `metadata-protocol` and `service-datasource`). A later fetch advanced the shared ref to `a8acee28dd`, two commits in `packages/spec` and a generated reference page, none touching `packages/client`. There was no second merge; CI judges the merge ref. ## Deviations - **One companion line (`client.test.ts:2198`)** beyond the 43 sites, the second half of the `:2197` sentence. - **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, and AGENTS.md overrides it. The merge commit carries git's default message. --- _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>
…o the commits that decided them (objectstack-ai#20713) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 7 of the `domain:cli` lane of the dead-citation sweep: `packages/mcp/src`. Every comment site there 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 keeps saying in its own words what that commit decided. PR objectstack-ai#20533 is the method, and stages 1 to 6 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689, PR objectstack-ai#20703) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **17 sites on 17 lines in 9 files, covering 9 numbers**, rewritten to **9 distinct commits**: - the census's **10 sites**, in `mcp-server-runtime.ts` (5), `plugin.ts` (3) and `stdio-data-bridge.ts` (2), 7 numbers; - **7 test-file comment sites** in 6 test files (the census defers `*.test.ts`; stages 1 to 6 took test comments too). One more line changed: `__tests__/plugin-execution-context.test.ts:7`, the second half of the `:6` sentence ("this face was not in that card's inventory" now reads "not in that commit's inventory", since the card it pointed back to is now named as a commit). Only comments changed: **18 lines out, 18 in**, and every touched file keeps its line count, so no line citation into these files moves. **No citation number is added**: over the 18 line pairs, added-minus-removed numbers is empty, and no PR number stands newly on any line. No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records any of these 9 decisions (a grep for the 9 numbers there reads 0 hits, with a control number from the same tree reading 2), so every anchor is a commit. **No changeset, and `skip-changeset`:** none of the rewritten comments reaches `dist` (measured below: base and head emit six byte-identical files, and a code-mutation control changes four of them). That is stage 5's case (PR objectstack-ai#20689), not stage 6's. ## Census: `packages/mcp`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run under `with-fleet.sh --read` for the token. The count is its `allocated-but-absent` findings under `packages/mcp/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | `packages/mcp` sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `e4e5222b7b`, run 2026-09-29T19:45:33Z to 19:50:37Z | enumerated, 186 pages, frontier objectstack-ai#20708, 18,535 numbers | 1,222 | **10** | 10 | 7 | 3 | | after | `459ff81088`, run 19:58:39Z to 20:02:47Z | enumerated, 186 pages, frontier objectstack-ai#20709, 18,536 numbers | 1,212 | **0** | 0 | 0 | 0 | The whole-repo drop of 10 is exactly these sites: a site-by-site diff of the two JSON outputs has 10 findings gone, all under `packages/mcp/src`, and none added. The other three tallies (`resolves` 32,968, `resolves-as-pull-request` 1,984, `cross-repo-unjudged` 994) are equal in both runs. `packages/mcp/src` is byte-identical at `459ff81088` and at the head. **Supplementary scan (test files included).** The gate's exported `extractCitations` and `classifyCitation` over all 43 `.ts` files under `src/`, with the board from the gate's own `probeBoard`: 365 citations and 21 dead before (src comments 10, test comments 7, src strings 0, test strings 4), 348 and 4 after (0, 0, 0, 4). Its before list of src comment sites is identical to the census's. The 4 left are test titles, the form-D stage (see Acceptance notes). ## Per-site table `git blame` at the base ties each line to the commit that wrote it, and each anchor was read in its message, changeset or diff, not only its subject. Where the pull request that landed an anchor still answers, its body's first line names the dead number, which is noted. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#13318` | `mcp-server-runtime.ts:272` | `3ec8646f1`: the bridged tools' `readOnlyHint` / `destructiveHint` come from what the definition declares, and a tool that declares nothing is served neither hint (omit-when-unsourced). The line blames to `c39369d12`, the `openWorldHint` sibling, whose changeset calls this the repair "that preceded it". The PR that landed `3ec8646f1` answers 404 too. | | `objectstack-ai#6724` | `mcp-server-runtime.ts:625`; `mcp-server-runtime.metadata-outage.test.ts:289` | `4f3d2322e`: corrects `diagnoseEmptyRead`'s falsified claim that `MetadataFacade.getObject` differs from `get('object', n)`, in the TSDoc and in the outage test's restatement of it. Both lines blame to it; PR objectstack-ai#6948, which landed it, names objectstack-ai#6724. | | `objectstack-ai#6745` | `mcp-server-runtime.ts:636` | `7a5ef0008`: adds `metadata-service-getobject-equivalence.test.ts`, pinning `getObject(n)` equal to `get('object', n)` across all three implementations. The line's "PR objectstack-ai#6839 for objectstack-ai#6745" named this commit's PR (answers 200), which stays beside the sha as a convenience link. The spec lane gave the number this anchor. | | `objectstack-ai#6723` | `mcp-server-runtime.ts:637`, `:652`; `mcp-server-runtime.metadata-outage.test.ts:293` | `8ad609c69`: declares on `IMetadataService.getObject` that it answers the same as `get('object', name)`. `objectstack-ai#6723` was the pull request that landed as this commit (its subject carries the number); `objectstack-ai#6505`, the issue beside it on `:637`, answers 200 and stays. The spec lane gave the number this anchor. | | `objectstack-ai#17114` | `plugin.ts:8`, `:67`; `stdio-tenancy-posture-api-key-matrix.test.ts:569` | `4af758d47`: the last two admission doors, this one included, classify the tenancy rejection through the shared `classifyAdmissionTenancyPosture`. All three lines blame to it; PR objectstack-ai#17683 names objectstack-ai#17114, and stage 1 gave the number this anchor. | | `objectstack-ai#6216` | `plugin.ts:126`; `__tests__/plugin-execution-context.test.ts:6` | `f586f1a89`: one `ExecutionContext` assembler for the dispatcher, REST and share-link sites. Both lines blame to `502dc6fe7`, which converged this stdio face afterwards and names that convergence as its precedent. Its file list touches no `packages/mcp` file, which is what `:7` ("not in that commit's inventory") says. Stages 1 and 2 and the spec lane gave the number this anchor. | | `objectstack-ai#8422` | `stdio-data-bridge.ts:85`, `:394`; `stdio-data-bridge.not-found.test.ts:4` | `4810dd628`: the stdio bridge's by-id write seams throw the shared `recordNotFoundError` envelope instead of a bare `Error`. All three lines blame to it; PR objectstack-ai#8507 names objectstack-ai#8422. | | `objectstack-ai#17568` | `mcp-record-id-key-mistake-refusal.test.ts:4` | `9c9e6d08f`: pins that a missing-`recordId` refusal also names the `id` the caller sent (test-only). The line blames to it; PR objectstack-ai#17650 names objectstack-ai#17568. | | `objectstack-ai#13486` | `mcp-tool-bridge-safety-annotations.test.ts:423` | `6193e576d`: pins the bridge's two hand-copied safety name sets in the direction the old pin could not see (the docblock's heading is that commit's subject). The line blames to it; PR objectstack-ai#13888 names objectstack-ai#13486. | **Anchor checks.** Every cited sha matches exactly one object (`git rev-parse --disambiguate`, count 1 for each of the 9), is a commit, has one parent, and is an ancestor of `main` (`merge-base --is-ancestor` against `5757463712`, exit 0 for all 9). The checkout is not shallow. The control leg `979ad9575` (2026-08-08, the parent of the oldest anchor `8ad609c69` of 2026-08-08) exits 0, and the negative control, this branch's own `459ff81088`, exits 1. Four anchors reuse the landed stages' (`f586f1a89`, `4af758d47`, `7a5ef0008`, `8ad609c69`), so each number carries one anchor across the tree; five are new (`3ec8646f1`, `4f3d2322e`, `4810dd628`, `9c9e6d08f`, `6193e576d`). **Numbers.** All 9 dropped numbers answer 404 by REST (re-probed 2026-09-29T19:54Z). The numbers kept on changed lines (`objectstack-ai#6839`, a pull request; `objectstack-ai#6505`, `objectstack-ai#15348`, `objectstack-ai#16013`, `objectstack-ai#4435`, `objectstack-ai#5138`, `objectstack-ai#7867`) answer 200. Four slash-joined groups stand in `packages/mcp/src`, whose later halves the citation grammar does not read (`objectstack-ai#4435/objectstack-ai#5138/objectstack-ai#7867` twice, `objectstack-ai#5138/objectstack-ai#5581`, `objectstack-ai#7728/objectstack-ai#7823`); every half answers 200, so none is dead. ## Mechanical guard: no code token moves **H2 holds on both readings: the parser leaf-token diff is empty, and the emitted `dist` is byte-identical.** **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, JSDoc nodes excluded) of the 9 touched files at base `e4e5222b7b` and at `459ff81088`. Controls mutate the head text in memory only. - Real run: 21,192 base tokens, 0 differing (exit 0). - Comment-insertion control: 0 differing (exit 0). - Code-insertion control: all 9 files differ at token 0 (exit 1). - String control (the first character of the `'vitest'` import specifier in `plugin-execution-context.test.ts` flipped): exactly 1 differing `StringLiteral`, at token 15 of that file (exit 1). **Emitted `dist`.** `pnpm --filter @objectstack/mcp build` at the head, then at base (the base tree of `packages/mcp/src` restored in place under a trap-armed restore; an on-disk probe read `objectstack-ai#13318` 1 and `commit 3ec8646` 0 before that build; afterwards every touched blob equals its HEAD blob and `git diff HEAD` is empty), with the same dependency builds: - all six files (`index.cjs`, `index.cjs.map`, `index.d.cts`, `index.d.ts`, `index.js`, `index.js.map`) are **byte-identical** by sha256. The built files do carry docblocks (14 in `index.js`, 78 in `index.d.ts`); none of the rewritten ones is on an emitted declaration. - Code-mutation control (`scripts/ablation-replace.mjs`, anchor: the sync leg's typed `ctx.getService` call on `'tenancy'` in `plugin.ts`, hit 1 to 0, its argument renamed to a marker; blob restored to HEAD `0a1aaa7955`, `git diff HEAD` empty): `scripts/ablation-dist-preflight.mjs` found the marker in `index.cjs` and `index.js`, and `index.cjs`, `index.js` and both `.map` files differ from the head build. `dist` was then rebuilt, its six sha256 values equal the first head build, and the preflight in `--absent` mode reads the marker absent from all 6 files with a clean tree. A raw scan of the 9 changed files for control bytes finds none (a positive probe on a scratch file matched). ## Changeset **None, and `skip-changeset`.** `@objectstack/mcp`'s `files[]` is `dist`, `README.md` and `CHANGELOG.md`, and the build above emits byte-identical `dist` at base and head, so this diff publishes nothing from any released package. Stage 5 (PR objectstack-ai#20689) measured the same and shipped the same; stage 6 (PR objectstack-ai#20703) measured the opposite and carried a `patch`. ## Gates (head `7a0f15de62`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its disclosure, verbatim, from each run at this head and from the four `dist` builds (at `459ff81088`, `packages/mcp/src` byte-identical to 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 25s · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/mcp...' 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 116s (1m56s) · declare it in the PR body · pnpm turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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 10s · declare it in the PR body · pnpm --filter @objectstack/mcp exec vitest run --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 4s · declare it in the PR body · pnpm --filter @objectstack/mcp 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 3s · declare it in the PR body · pnpm --filter @objectstack/mcp 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 3s · declare it in the PR body · pnpm --filter @objectstack/mcp 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 3s · declare it in the PR body · pnpm --filter @objectstack/mcp 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 2s · declare it in the PR body · pnpm --filter @objectstack/mcp build ``` - **Build:** `@objectstack/mcp` with its closure (9 of 81 workspace projects), then the whole workspace, `turbo run build --filter='./packages/*' --filter='./packages/*/*'`, 71 of 71 tasks, after the merge. The tree was clean after both. - **Tests:** `vitest run`: 32 files, 344 tests passed (every `*.test.ts` under `src/`), at the head and before the merge. - **Typecheck:** `pnpm --filter @objectstack/mcp typecheck` exits 0. `tsc --listFiles`: `tsconfig.json` compiles the 11 non-test `src` files, `tsconfig.test.json` all 43 including the 32 test files. `check:test-typecheck`: 6 files, 53 errors, 8 pinned signatures, held. - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at this head (2026-09-29T20:18:54Z to 20:19:23Z), and at `459ff81088` before the merge. - **Citation judging:** after merging `origin/main` (`9b384f63ae`), `node scripts/check-issue-citations.mjs --base 9b384f6` judges 5 citations on the changed lines of 3 files (the kept numbers `objectstack-ai#15348`, `objectstack-ai#16013`, `objectstack-ai#4435`, `objectstack-ai#6505`, and `objectstack-ai#6839` as a pull request) and exits 0: every one resolves. Against `origin/main` after it moved to `5757463712`, the same 5 citations, exit 0. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 53 families. All 53 exit 0, and `--ran` with the exit-coded record reads "53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: `check:issue-citations`, `check:doc-authoring` (808 pinned sites, no growth), `check:nul-bytes` (9,331 files, no raw control bytes), `check:published-files`, `check:type-check-debt`. - **Artifact rosters:** 36 of the 39 non-self-test roster rows exit 0, including the three the derivation marks as keeping their roster under one of this diff's paths (`check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `e4e5222b7b` the filtered census answers 10 sites on 10 lines, 7 numbers, in 3 files, as on the seat's `0be898499f`. The whole-repo count is 1,222. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/mcp`. No site was left for an open PR (the file lists of all 8 open PRs were read at 20:08:05Z: only the Version Packages PR objectstack-ai#20639 touches `packages/mcp`, in `CHANGELOG.md` and `package.json`) or for an unfound anchor. - **H2 holds, on both readings.** The comment-stripped (parser-token) diff of all 9 touched files is empty with its controls firing, and the emitted `dist` is byte-identical at base and head with a code control that changes it. ## Acceptance notes - **Test titles, the form-D stage.** 4 dead numbers remain in test string literals in `packages/mcp/src` (`describe` titles, no assertion text): `objectstack-ai#17568` twice in `mcp-record-id-key-mistake-refusal.test.ts` (`:151`, `:315`), `objectstack-ai#8422` in `stdio-data-bridge.not-found.test.ts:99`, `objectstack-ai#17114` in `stdio-tenancy-posture-api-key-matrix.test.ts:592`. They stay on the card for its form-D stage; no string moved here. - **Outside `src/**`, a later stage of the card:** `packages/mcp/vitest.config.ts:18` cites `objectstack-ai#8651` (404). `packages/mcp/test-typecheck-debt.json:2` cites `objectstack-ai#13470` (404) inside its `_comment` field, which the file itself says is generated by `scripts/check-test-typecheck.mts`, so a fix there is at that producer, in the `scripts/**` lane, not a hand edit. The other citations in `packages/mcp` outside `src/**` (`CHANGELOG.md` excluded) answer 200. - **Card-word residue, cited nowhere.** A few docblocks still say "this card" or "the card" a paragraph away from the rewritten line (for example `stdio-data-bridge.not-found.test.ts:19`, `mcp-record-id-key-mistake-refusal.test.ts:19`, `stdio-tenancy-posture-api-key-matrix.test.ts:580`, `:584`). They cite no number, so they were left, as the landed stages left theirs; only the one same-sentence companion (`plugin-execution-context.test.ts:7`) was changed. - **The moving `origin/main`.** The branch merged `origin/main` once (`7a0f15de62`, merging `9b384f63ae`: `service-storage`, `platform-objects` and `plugin-audit`, nothing in `packages/mcp`). A later fetch advanced the shared ref to `5757463712`, one commit in `platform-objects` translations. There was no second merge; CI judges the merge ref. ## Deviations - **One companion line (`plugin-execution-context.test.ts:7`)** beyond the 17 sites, the second half of the `:6` sentence. - **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, and AGENTS.md overrides it. The merge commit carries git's default message. --- _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>
…commits that decided them (objectstack-ai#20723) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 8 of the `domain:cli` lane of the dead-citation sweep: `packages/qa`. `packages/qa` is a directory of five private workspace packages, not one package, so the surface is `packages/qa/*/src/**`. Every comment site there 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. Each line still says in its own words what that commit decided. PR objectstack-ai#20533 is the method, and stages 1 to 7 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689, PR objectstack-ai#20703, PR objectstack-ai#20713) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **12 sites on 12 lines in 5 files, covering 6 numbers**, rewritten to **6 distinct commits**: - the census's **8 sites**: `downstream-contract/src/additional-domains.fixtures.ts` (2), `http-conformance/src/adapter.ts` (4) and `vitest-filter-preflight/src/index.ts` (2), 5 numbers; - **4 test-file comment sites** in 2 test files under `http-conformance/src/` (the census leaves `*.test.ts` out; stages 1 to 7 took test comments too). Only comments changed: **12 lines out, 12 in**, and every touched file keeps its line count, so no line citation into these files moves. **No citation number is added.** Over the 12 line pairs, added-minus-removed numbers is empty, and no PR number stands newly on any line. The two numbers still on changed lines (`objectstack-ai#17978`, `objectstack-ai#14554`) were already on them, and both answer 200. **Two numbers have an ADR beside them, and both ADRs stay.** - `objectstack-ai#6083`'s line already cited ADR-0122 phase 2. The ADR's own amendment records phase 2, so the line now reads "ADR-0122 phase 2, commit 53068c1", the same pair spec stage 1 wrote in `contracts/data-engine.ts`. - `objectstack-ai#10485`'s line cites ADR-0049, the enforce-or-remove principle it was retired under. No ADR records the theme retirement itself, so the commit is the anchor, and the ADR stays beside it, as in the landed stages. None of the other four numbers appears in `docs/adr/` or `scripts/adr-anchors/`. The grep reads 0 hits for them. The control, `objectstack-ai#5551`, reads 1 hit in ADR-0122. **No changeset, and `skip-changeset`.** None of the three touched packages publishes anything (see Changeset below). ## Census: `packages/qa`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run under `with-fleet.sh --read` for the token. The count is its `allocated-but-absent` findings under `packages/qa/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | `packages/qa` sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `679f95ec5c`, run 2026-09-29T21:05:44Z to 21:09:44Z | enumerated, 186 pages, frontier objectstack-ai#20718, 18,545 numbers | 1,185 | **8** | 8 | 5 | 3 | | after | `30aae6a3e6`, run 21:18:38Z to 21:22:42Z | enumerated, 186 pages, frontier objectstack-ai#20720, 18,547 numbers | 1,177 | **0** | 0 | 0 | 0 | The whole-repo drop of 8 is exactly these sites. A site-by-site diff of the two JSON outputs has 8 findings gone, all under `packages/qa/*/src`, and none added. The other three tallies are equal in both runs: `resolves` 32,982, `resolves-as-pull-request` 1,984 and `cross-repo-unjudged` 995. `packages/qa/*/src` is byte-identical at `30aae6a3e6` and at the head; the two later commits are merges of `origin/main` that touch nothing in `packages/qa`. **Supplementary scan (test files and everything outside `src/` included).** The gate's exported `extractCitations` and `classifyCitation` ran over all 221 tracked files under `packages/qa` (`CHANGELOG.md` excluded), with the board from the gate's own `probeBoard`. The totals are 1,678 citations and 139 dead before, and 1,666 and 127 after. - Under `src/`, before: src comments 40 / 8 dead, test comments 42 / 4, src strings 1 / 0, test strings 9 / 0. - Under `src/`, after: src comments 32 / 0, test comments 38 / 0, strings unchanged. Nothing dead is left under any `src/`, strings included, so there is no form-D residue in this stage's surface. - Its before list of src comment sites is identical to the census's. - The 127 left are all outside `src/**` (see Acceptance notes). ## Per-site table `git blame` at the base ties each line to the commit that wrote it. Each anchor was read in its message, changeset or diff, not only its subject. Where the pull request that landed an anchor still answers, its body's first line names the dead number, and that is noted. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#6083` | `downstream-contract/src/additional-domains.fixtures.ts:11` | `53068c130`, ADR-0122 phase 2: the bare type name becomes the AUTHOR state (`z.input`) and the `XInput` synonyms retire. The same commit moved these frozen fixtures' annotations onto the bare names without touching a literal, which is what the paragraph says. The line blames to it, and its subject carries the number. The PR that landed it answers 404, and spec stage 1 gave the number this anchor. | | `objectstack-ai#10485` | `downstream-contract/src/additional-domains.fixtures.ts:133` | `35ad101bc`: retires the `themes` carrier key and `ThemeSchema` whole, under ADR-0049, and drops `DcTheme` from these fixtures. The line blames to it, and its subject carries the number. The spec, rest, runtime and cli stages gave the number this anchor. | | `objectstack-ai#6143` | `http-conformance/src/adapter.ts:32`, `:189`, `:257`, `:346`; `http-conformance/src/fallback-seam.conformance.test.ts:4`, `:27` | `12298c7d6`, which does two things: `NodeHttpServer` implements the optional `setFallbackHandler` out of its own router, as a field consulted in the route-miss branch, with the 405 answer extracted for its second call site; and the cross-adapter suite asserts the contract's four guarantees on both adapters. All six lines blame to it. PR objectstack-ai#6851, which landed it, names objectstack-ai#6143 on its first line. | | `objectstack-ai#6307` | `http-conformance/src/query-multiplicity.conformance.test.ts:76`, `:296` | `293476148`: refuses a repeated `?version=` on `GET` / `DELETE /packages/:id`, and adds `package-routes-query-multiplicity.test.ts`. Its changeset records the measured read: on `DELETE`, a repeated value skipped the full-uninstall branch, and the call still reported success. The lines blame to the later `68feaadd6` and `7cdbcbb30`, which cite this earlier work by number. PR objectstack-ai#6895, which landed the anchor, names objectstack-ai#6307 on its first line. The rest stage gave the number this anchor. | | `objectstack-ai#17853` | `vitest-filter-preflight/src/index.ts:5` | `08f5f0e5a`: a vitest file filter that selects nothing says so, even when the rest of the run selects something. This is the first implementation, in `packages/cli`. The line blames to `c667d8c80`, the shared port for all eight project-declaring packages; its number is `objectstack-ai#17978`, which answers 200 and stays. PR objectstack-ai#17965, which landed the anchor, names objectstack-ai#17853 on its first line. | | `objectstack-ai#13504` | `vitest-filter-preflight/src/index.ts:273` | `44813ba57`: splits `packages/cli`'s suite into the named `unit` and `integration` tiers, decided on behaviour, with the partition pin. That is half of the "tier walk" this sentence names, and its diff heads the new section with this number. `objectstack-ai#14554`, the derived-population half, answers 200 and stays. The only commit whose subject carries `objectstack-ai#13504` is `55519d503`, the comment-only measurement half: PR objectstack-ai#13872 says it lands only that half. So that commit is not the anchor for this sentence. The PR that landed `44813ba57` answers 404. | **Anchor checks.** Every cited sha matches exactly one object (`git rev-parse --disambiguate`, count 1 for each of the 6). Each is a commit with one parent, and each is an ancestor of `main` (`merge-base --is-ancestor` against `cbaf04c1fd`, exit 0 for all 6). The checkout is not shallow. The control leg `3cc8676e1` (2026-08-08, the parent of the oldest anchor `53068c130` of 2026-08-08) exits 0, and the negative control, this branch's own `06b8fbc2d3`, exits 1. Three anchors reuse the landed stages' (`53068c130`, `35ad101bc`, `293476148`), so each number carries one anchor across the tree. Three are new (`12298c7d6`, `08f5f0e5a`, `44813ba57`). **Numbers.** All 6 dropped numbers answer 404 by REST (probed 2026-09-29T21:16:49Z). The numbers kept on changed lines (`objectstack-ai#17978`, `objectstack-ai#14554`) answer 200. No slash-joined citation group stands in `packages/qa/*/src`. ## Mechanical guard: no code token moves **H2 holds on the parser-token reading.** The emitted-`dist` reading does not apply, because none of these packages has a build (see Changeset below). **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, `getChildren` walked to the leaves, JSDoc nodes excluded) of the 5 touched files at base `679f95ec5c` and at `30aae6a3e6`. Controls mutate the head text in memory only. - Real run: 7,917 base tokens, 0 differing (exit 0). - Comment-insertion control: 0 differing (exit 0). - Code-insertion control: all 5 files differ at token 0 (exit 1). - String control (the first character of the `'vitest'` import specifier in `fallback-seam.conformance.test.ts` flipped): exactly 1 differing `StringLiteral`, at token 11 of that file (exit 1). Every one of the 24 changed lines is a `//` or `*` comment line. A raw scan of the 5 changed files for control bytes finds none (a positive probe on a scratch file matched). ## Changeset **None, and `skip-changeset`.** There is no `@objectstack/qa` package. The three touched packages are `@objectstack/downstream-contract`, `@objectstack/http-conformance` and `@objectstack/vitest-filter-preflight`. Each is `"private": true`, has no `build` script, no `files[]` and no `dist/`. `.changeset/config.json` versions private packages but never tags or publishes them. This diff therefore publishes nothing from any released package, so there is no `dist` to compare and no code-mutation control to run. The measurement is the packages' own manifests. ## Gates (head `06b8fbc2d3`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its disclosure, verbatim, from each run at this head, and from the closure build at `527d5dca06` (the first merge; `packages/qa` is byte-identical between the two): ```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 77s (1m17s) · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/downstream-contract^...' --filter '@objectstack/http-conformance^...' --filter '@objectstack/vitest-filter-preflight^...' 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 11s · declare it in the PR body · pnpm turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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/downstream-contract exec vitest run --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 3s · declare it in the PR body · pnpm --filter @objectstack/downstream-contract 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 8s · declare it in the PR body · pnpm --filter @objectstack/http-conformance exec vitest run --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 4s · declare it in the PR body · pnpm --filter @objectstack/http-conformance 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 4s · declare it in the PR body · pnpm --filter @objectstack/vitest-filter-preflight exec vitest run --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 1s · declare it in the PR body · pnpm --filter @objectstack/vitest-filter-preflight typecheck ``` - **Build.** The three packages' dependency closure was built: 61 of 81 workspace projects, at `30aae6a3e6` and again at `527d5dca06`. Then the whole workspace was built with `turbo run build --filter='./packages/*' --filter='./packages/*/*'`: 71 of 71 tasks at this head, 66 of them cache hits. The tree was clean after each build. - **Tests (`vitest run`), at this head and at both earlier commits:** - `downstream-contract`: 3 files, 31 tests passed; - `http-conformance`: 8 files, 102 tests passed; - `vitest-filter-preflight`: 3 files, 111 tests passed. - These are every test file each package has. - **Typecheck.** All three `typecheck` scripts exit 0; `downstream-contract`'s is also one of CI's consumer-gate type-check lanes. `http-conformance`'s `check:test-typecheck` holds: 3 files, 27 errors, 10 pinned signatures. `tsc --listFiles` shows every touched file compiled: - `downstream-contract/tsconfig.json`: 11 files, 3 of them tests; - `http-conformance/tsconfig.test.json`: 11 files, all 8 tests, including both touched test files and `adapter.ts`; - `vitest-filter-preflight/tsconfig.json`: 6 files, 3 of them tests. - **Lint.** The repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at this head (2026-09-29T21:48:59Z to 21:49:26Z), and at `527d5dca06` before the second merge. - **Citation judging.** `node scripts/check-issue-citations.mjs --base origin/main`, with `origin/main` at `cbaf04c1fd` and merged, judges 2 citations on the changed lines of 3 files (the kept `objectstack-ai#17978` and `objectstack-ai#14554`). Both resolve, and the run exits 0. The pinned merged base of the first merge (`--base 1ab9892`, at `527d5dca06`) gives the same 2 citations and also exits 0. - **Derived gates.** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 53 families, identical at `527d5dca06` and at this head. All 53 exit 0 at this head. `--ran` with the exit-coded record reads "53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: - `check:issue-citations`; - `check:doc-authoring` (808 pinned sites, no growth); - `check:nul-bytes` (9,342 text files, no raw control bytes); - `check:published-files`, `check:type-check-coverage` and `check:type-check-debt`. - **Artifact rosters.** 36 of the 39 non-self-test roster rows exit 0. These include the three the derivation marks as keeping their roster under one of this diff's paths (`check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists, and the results are reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `679f95ec5c` the filtered census answers 8 sites on 8 lines, 5 numbers, in 3 files, as on the seat's `0be898499f`. The whole-repo count is 1,185. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/qa`. No site was left for an open PR or for an unfound anchor. The file lists of all 12 open PRs were read at 2026-09-29T21:13:53Z: only the Version Packages PR objectstack-ai#20639 touches `packages/qa`, in `CHANGELOG.md` and `package.json`. - **H2 holds on the parser-token reading.** The comment-stripped (parser-token) diff of all 5 touched files is empty, and its controls fire. The `dist` reading is not available, because none of the packages has a build. ## Acceptance notes - **`packages/qa` outside `src/**`, a later stage of the card.** The census surface is `packages/**/src/**`, and `packages/qa/dogfood` has no `src/` at all. The supplementary scan counts 127 dead sites left in `packages/qa` outside `src/**`: - `dogfood/test/**` and `dogfood/vitest.config.ts`: 122 sites, 27 numbers, 28 files (94 comments, 28 strings); - `downstream-contract/test/contract.test.ts:46` (`objectstack-ai#10485`, a comment); - `vitest-filter-preflight/test/config-wiring-sweep.test.ts:6` and `test/filter-preflight.test.ts:5` (`objectstack-ai#17853`, comments); - `vitest-filter-preflight/package.json:6` (`objectstack-ai#17853`, in the package `description`); - `http-conformance/test-typecheck-debt.json:2` (`objectstack-ai#13470`, in the generated `_comment`, whose producer is `scripts/check-test-typecheck.mts`; that producer is objectstack-ai#20715's, and it is never fixed by hand). None of them is in this stage's surface, and none moved. - **ADR-0122's own status line and amendment heading** cite `objectstack-ai#6083` (404). `docs/adr/**` is a governed surface and one of the gate's deferred surfaces, so it is noted here, not touched. - **Card-word residue, cited nowhere.** `vitest-filter-preflight/src/index.ts:117` says "this card" about 150 lines from either rewritten line. It cites no number, so it was left, as the landed stages left theirs. - **The moving `origin/main`.** The branch merged `origin/main` twice. The first merge (`527d5dca06`) took `1ab98926b0` (a spec retirement, nothing in `packages/qa`). After it, the shared ref advanced to `cbaf04c1fd`, the plugin-approvals re-anchor (PR objectstack-ai#20717). Against that moved ref, `--base origin/main` then read the old plugin-approvals lines as this branch's additions: it judged 31 citations and exited 2, because the diff was two-dot. That run is not a measurement of this change. The pinned base answered exit 0. The second merge (`06b8fbc2d3`) took `cbaf04c1fd`, and every gate above was re-run on it. CI judges the merge ref. ## Deviations - **The dispatch's `packages/qa/src/**` and `@objectstack/qa`** do not exist as spelled. The surface was read as `packages/qa/*/src/**`, the census's own reading of `packages/**/src/**`. The changeset measurement was taken per touched package. - **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, and AGENTS.md overrides it. The two merge commits carry git's default message. --- _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>
…ges/cloud-connection/src to the commits that decided them (objectstack-ai#20735) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 9 of the `domain:cli` lane of the dead-citation sweep: `packages/cloud-connection/src`. Every comment site there 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 keeps saying in its own words what that commit decided. PR objectstack-ai#20533 is the method, and stages 1 to 8 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689, PR objectstack-ai#20703, PR objectstack-ai#20713, PR objectstack-ai#20723) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **10 sites on 10 lines in 3 files, covering 3 numbers**, rewritten to **3 distinct commits**: - the census's **5 sites**, all in `src/marketplace-install-local-plugin.ts` (3 numbers); - **5 test-file comment sites** in 2 test files (the census defers `*.test.ts`; stages 1 to 8 took test comments too). Only comments changed: **10 lines out, 10 in**, and every touched file keeps its line count (1,969 / 377 / 308), so no line citation into these files moves. **No citation number is added**: over the 10 line pairs, added-minus-removed numbers is empty, and no PR number stands on an added line. No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records any of these 3 decisions (a grep for the 3 numbers there reads 0 hits, with a control number from the same tree, `objectstack-ai#7329`, reading 1), so every anchor is a commit. A **`patch` changeset** for `@objectstack/cloud-connection` rides along, because the rewritten docblocks reach `dist` (measured below). That is stage 6's case (PR objectstack-ai#20703), not stages 5 and 7's. ## Census: `packages/cloud-connection`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run under `with-fleet.sh --read` for the token. The count is its `allocated-but-absent` findings under `packages/cloud-connection/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | `packages/cloud-connection` sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `b291fcdae9`, run 2026-09-29T22:34:12Z to 22:38:18Z | enumerated, 186 pages, frontier objectstack-ai#20731, 18,558 numbers | 1,153 | **5** | 5 | 3 | 1 | | after | `4a1f38a4e6`, run 22:44:08Z to 22:47:58Z | enumerated, 186 pages, frontier objectstack-ai#20731, 18,558 numbers | 1,148 | **0** | 0 | 0 | 0 | The whole-repo drop of 5 is exactly these sites: a site-by-site diff of the two JSON outputs has 5 findings gone, all in `packages/cloud-connection/src/marketplace-install-local-plugin.ts`, and none added. The other three tallies (`resolves` 32,994, `resolves-as-pull-request` 1,984, `cross-repo-unjudged` 995) are equal in both runs. `packages/cloud-connection/src` is byte-identical at `4a1f38a4e6` and at the head. **Supplementary scan (test files included).** The gate's exported `extractCitations` and `classifyCitation` over all 44 `.ts` files under `src/`, with the board from the gate's own `probeBoard`: 301 citations and 14 dead before (src comments 5, test comments 5, src strings 1, test strings 3), 291 and 4 after (0, 0, 1, 3). Its before list of src comment sites is identical to the census's. The 4 left are strings, the form-D stage (see Acceptance notes). ## Per-site table `git blame` at the base ties each line to the commit that wrote it, and each anchor was read in its message, changeset or diff, not only its subject. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#9011` | `marketplace-install-local-plugin.ts:35`, `:1001`, `:1821`; `marketplace-install-local-capability-enumeration.test.ts:50`, `:303`; `marketplace-install-local-list-posture.test.ts:4`, `:302` | `01074e551`: the install-local listing requires an authenticated principal (anonymous gets 401) and serves `installedBy` / `storageDir` only to a `manage_metadata` holder, the maintainer's 2026-08-16 "Option 3" that `:1008` still names; it also extracts the one `refuseUnauthenticated` 401 envelope that `:1821` describes. All seven lines blame to it. The PR that landed it (PR objectstack-ai#9256, which answers 200) names objectstack-ai#9011 on its first line. `list-posture.test.ts:302` now reads "The wire shape before commit 01074e5" for "The pre-(number) wire shape". | | `objectstack-ai#8919` | `marketplace-install-local-plugin.ts:98`; `marketplace-install-local-capability-enumeration.test.ts:40` | `b5378550e`: gates the `/meta` publish and rollback promotion verbs on `manage_metadata` and adds `meta-write-door-capability-enumeration.test.ts`, the enumeration pin `:40` names as its precedent. Both lines blame to `e0695b582`, the commit that gated the four mutating install-local doors for objectstack-ai#8976 (which answers 200), whose message cites this gate as the precedent. Stages 2 and 5 gave the number this anchor. The PR that landed `b5378550e` answers 404 too. | | `objectstack-ai#13279` | `marketplace-install-local-plugin.ts:1813` | `6a180e42d`: a failed permission-store read raises `AuthzStoreUnavailableError` instead of resolving as an unauthenticated or capability-less principal, and each fail-closed transport `catch` re-raises it. The line blames to it; PR objectstack-ai#13475 names objectstack-ai#13279. Stages 1, 2 and 4 gave the number this anchor. | **Anchor checks.** Every cited sha matches exactly one object (`git rev-parse --disambiguate`, count 1 for each of the 3), is a commit, has one parent, and is an ancestor of `main` (`merge-base --is-ancestor` against `36d043be17`, exit 0 for all 3). The checkout is not shallow. The control leg `818fcafda` (2026-08-16, the parent of the oldest anchor `b5378550e` of 2026-08-16) exits 0, and the negative control, this branch's own `16a88d69b2`, exits 1. Two anchors reuse the landed stages' (`b5378550e`, `6a180e42d`), so each number carries one anchor across the tree; one is new (`01074e551`). **Numbers.** All 3 dropped numbers answer 404 by REST (probed 2026-09-29T22:40:35Z). The numbers kept near the changed lines (`objectstack-ai#8976`, `objectstack-ai#15353`) answer 200. Three slash-joined groups stand in `packages/cloud-connection/src`, whose later halves the citation grammar does not read (`objectstack-ai#6603/objectstack-ai#7020`, `objectstack-ai#4127/objectstack-ai#4251` twice); every half answers 200, so none is dead. ## Mechanical guard: no code token moves **H2 holds on the comment-stripped reading; the emitted `dist` is NOT byte-identical, because the docblocks ship.** **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, JSDoc nodes excluded) of the 3 touched files at base `b291fcdae9` and at `4a1f38a4e6`. Controls mutate the head text in memory only. - Real run: 12,349 base tokens (8,351 / 2,246 / 1,752), 0 differing (exit 0 for each file). - Comment-insertion control: 0 differing (exit 0). - Code-insertion control: all 3 files differ (exit 1). - String control (`'Authentication required.'` to `'Authentication requireD.'` in `refuseUnauthenticated`): exactly 1 differing `StringLiteral`, at token 7,973 of `marketplace-install-local-plugin.ts` (exit 1). **Emitted `dist`.** `pnpm --filter @objectstack/cloud-connection build` at the head, then at base (the base tree of `packages/cloud-connection/src` restored in place under a trap-armed restore; an on-disk probe read `[objectstack-ai#13279]` 1 and `commit 6a180e4` 0 before that build; afterwards every touched blob equals its HEAD blob and `git diff HEAD` is empty), with the same dependency builds: - `index.cjs`, `index.js`, `index.d.ts` and `index.d.cts` differ; `index.cjs.map` and `index.js.map` are equal. - The same parser comparison over the four differing `dist` files reads 0 differing tokens (19,465 / 18,741 / 16,868 / 16,868), so the whole `dist` delta is comment text. Its code control (a code line appended after a newline) reads COUNT DIFFERS in each. - The new wording is in `dist`: "commit 01074e5" appears 2 times in `index.js` and `index.cjs` and 3 times in each declaration file, where the base build carries `objectstack-ai#9011` in the same places. - Code-mutation control (`scripts/ablation-replace.mjs`, anchor `'Authentication required.'` hit 1 to 0, planted marker 0 to 1, blob `2ef0f0ae8bac` to `77c3cef6324b`; `scripts/ablation-dist-preflight.mjs` found the marker in `dist`): `index.cjs`, `index.js` and both `.map` files differ from the head build. The blob was restored to HEAD `2ef0f0ae8bac` with `git diff HEAD` empty, `dist` was rebuilt, its six sha256 values equal the first head build, and the preflight in `--absent` mode reads the marker absent from all 6 files with a clean tree. A raw scan of the 4 changed files for control bytes finds none (a positive probe on a scratch file matched). ## Changeset **`patch` for `@objectstack/cloud-connection`** (`.changeset/cloud-connection-provenance-anchors.md`), in PR objectstack-ai#20632's form. `@objectstack/cloud-connection`'s `files[]` is `dist`, `README.md` and `CHANGELOG.md`, and the build above emits different `index.js` / `index.cjs` / `index.d.ts` / `index.d.cts` at base and head, so this diff publishes. `check-changeset-no-major`, `check-empty-changeset`, `check-adr-0087-registration` and `check-changeset-fixed` all exit 0. ## Gates (head `16a88d69b2`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its disclosure, verbatim, from each run (the closure build at `4a1f38a4e6`, whose `packages/cloud-connection` and dependency closure are byte-identical to this head; the whole-workspace build, the tests and the typecheck at this head; the three `dist` builds at `4a1f38a4e6`, whose `packages/cloud-connection/src` is byte-identical to 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 59s · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/cloud-connection...' 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 118s (1m58s) · declare it in the PR body · pnpm turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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 11s · declare it in the PR body · pnpm --filter @objectstack/cloud-connection exec vitest run --maxWorkers=2 os-verify-lock: VERDICT command-exit 2 · 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 exec tsc --noEmit -p tsconfig.json --listFiles 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 3s · declare it in the PR body · pnpm --filter @objectstack/cloud-connection 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 3s · declare it in the PR body · pnpm --filter @objectstack/cloud-connection 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 3s · declare it in the PR body · pnpm --filter @objectstack/cloud-connection build ``` - **Build:** `@objectstack/cloud-connection` with its closure (33 of 81 workspace projects), then the whole workspace, `turbo run build --filter='./packages/*' --filter='./packages/*/*'`, 71 of 71 tasks, after the merge. The tree was clean after both, and the package's six `dist` files after the whole build equal the first head build by sha256. - **Tests:** `vitest run`: 30 files, 397 tests passed (every `*.test.ts` under `src/`), at this head and before the merge. - **Typecheck:** `@objectstack/cloud-connection` has no `typecheck` script; it is a `DEBT` entry in `scripts/check-type-check-coverage.mjs` (13 errors: 11 TS2493, 2 config-tier). `tsc --noEmit -p tsconfig.json` exits 2 with exactly those 13 (11 TS2493, 2 TS2550), all in three test files this PR does not touch (`cloud-connection-plugin.test.ts` 4, `connection-credential-store.test.ts` 7, `marketplace-install-local-bundle.test.ts` 2). `--listFiles` compiles all three touched files and all 30 test files. `check:type-check-debt` and `check:type-check-coverage` exit 0, and the `dist` build's DTS step, this package's type gate, succeeds. - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at this head (2026-09-29T23:01:12Z to 23:01:39Z). - **Citation judging:** after merging `origin/main` (`36d043be17`), `node scripts/check-issue-citations.mjs --base origin/main` reports "no issue citations added against 36d043b (1 file(s) read)" (exit 0); pinned `--base 36d043b` reads the same. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 61 families. All 61 exit 0, and `--ran` with the exit-coded record reads "61 derived, 61 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: `check:issue-citations`, `check:doc-authoring`, `check:nul-bytes`, `check:published-files`, `check:type-check-debt`, `check-adr-0087-registration`, `check-empty-changeset`. - **Artifact rosters:** 36 of the 39 non-self-test roster rows exit 0, including the four the derivation marks as keeping their roster under one of this diff's paths (`check-changeset-fixed`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `b291fcdae9` the filtered census answers 5 sites on 5 lines, 3 numbers, all in `src/marketplace-install-local-plugin.ts`, as on the seat's `0be898499f`. The whole-repo count is 1,153. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/cloud-connection`. No site was left for an open PR (the file lists of all 10 open PRs were read at 2026-09-29T22:41:18Z: only the Version Packages PR objectstack-ai#20639 touches `packages/cloud-connection`, in `CHANGELOG.md` and `package.json`) or for an unfound anchor. - **H2 holds on the token reading, not on the `dist` reading.** The parser leaf-token diff of all 3 touched files is empty with its controls firing. The emitted `dist` differs, and the difference is comment text only (token-identical `dist` with a code control). That is why the changeset ships. ## Acceptance notes - **Strings, the form-D stage.** 4 dead numbers remain in string literals in `packages/cloud-connection/src`: `objectstack-ai#9011` in the three `describe` titles of `marketplace-install-local-list-posture.test.ts` (`:206`, `:247`, `:287`, no assertion text), and `objectstack-ai#9011` in the `note` string of the `GET /api/v1/marketplace/install-local` row of `cloud-connection-route-ledger.ts` (`:215`), a runtime string already recorded in `scripts/doc-authoring-prose-id.baseline.json`. They stay on the card for its form-D stage; no string moved here. - **Outside `src/**`, a later stage of the card:** `packages/cloud-connection/vitest.config.ts:64` cites `objectstack-ai#16917` (404). The other citations in `packages/cloud-connection` outside `src/**` (`CHANGELOG.md` excluded) answer 200: `README.md:108` (`objectstack-ai#10805`, `objectstack-ai#12681`) and `vitest.config.ts` (`objectstack-ai#10374`, `objectstack-ai#11480`, `objectstack-ai#7668/objectstack-ai#7778`, `objectstack-ai#7955`, `objectstack-ai#10374/objectstack-ai#13522`). - **Card-word residue, cited nowhere.** A few docblocks still say "this card's ruling" or "That ruling has since landed" a paragraph away from a rewritten line (`marketplace-install-local-capability-enumeration.test.ts:48`, `marketplace-install-local-list-posture.test.ts:12`). They cite no number, so they were left, as the landed stages left theirs. - **The moving `origin/main`.** The branch merged `origin/main` once (`16a88d69b2`, merging `36d043be17`: `service-automation` and two changesets, nothing in `packages/cloud-connection` or its dependency closure). ## Deviations - **The first token-guard run was void.** It looped over the touched files in a zsh shell, which does not word-split an unquoted variable, so each invocation received all three paths as one argument and read nothing; it was rerun under bash before any reading was used. - **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, and AGENTS.md overrides it. The merge commit carries git's default message. --- _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>
…kages/plugins/plugin-hono-server/src to the commits that decided them (objectstack-ai#20741) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 10 of the `domain:cli` lane of the dead-citation sweep: `packages/plugins/plugin-hono-server/src`. Every comment site there 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 keeps saying in its own words what that commit decided. PR objectstack-ai#20533 is the method, and stages 1 to 9 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689, PR objectstack-ai#20703, PR objectstack-ai#20713, PR objectstack-ai#20723, PR objectstack-ai#20735) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **24 sites on 24 lines in 5 files, covering 5 numbers**, rewritten to **5 distinct commits**: - the census's **5 sites**: `src/adapter.ts` 4, `src/current-user-endpoints.ts` 1 (4 numbers); - **19 test-file comment sites** in 3 test files (the census defers `*.test.ts`; stages 1 to 9 took test comments too): `ui-plugin-auto-discovery.pin.test.ts` 16, `handler-throw-declared-envelope.test.ts` 2, `current-user-endpoints-localization.test.ts` 1. Only comments changed: **24 lines out, 24 in**, every one of them a site (no companion line), and every touched file keeps its line count (1,660 / 1,020 / 335 / 403 / 697), so no line citation into these files moves. **No citation number is added**: over the 24 line pairs, the added numbers are a subset of the removed ones (`objectstack-ai#16599` x2, `objectstack-ai#9864`, `objectstack-ai#16334`, all answering 200, stay where they stood), and no PR number stands on an added line. No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records any of these 5 decisions (a grep for the 5 numbers there reads 0 hits; the control number `objectstack-ai#7329` reads 1 in the same tree), so every anchor is a commit. A **`patch` changeset** for `@objectstack/plugin-hono-server` rides along, because one rewritten comment reaches `dist` (measured below). That is stage 6's and stage 9's case (PR objectstack-ai#20703, PR objectstack-ai#20735), not stages 5 and 7's. ## Census: `packages/plugins/plugin-hono-server`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run under `with-fleet.sh --read` for the token. The count is its `allocated-but-absent` findings under `packages/plugins/plugin-hono-server/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | package sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `f927864ea0`, run 2026-09-29T23:42:29Z to 23:46:56Z | enumerated, 186 pages, frontier objectstack-ai#20735, 18,562 numbers | 1,105 | **5** | 5 | 4 | 2 | | after | `91ce7e5e8f`, run 23:58:22Z to 2026-09-30T00:02:19Z | enumerated, 186 pages, frontier objectstack-ai#20737, 18,564 numbers | 1,100 | **0** | 0 | 0 | 0 | The whole-repo drop of 5 is exactly these sites: a site-by-site diff of the two JSON outputs has 5 findings gone (`adapter.ts:225`, `:227`, `:308`, `:349`; `current-user-endpoints.ts:448`) and none added. The other three tallies (`resolves` 33,003, `resolves-as-pull-request` 1,984, `cross-repo-unjudged` 995) are equal in both runs. `packages/plugins/plugin-hono-server` is byte-identical at `91ce7e5e8f` and at the head. **Supplementary scan (test files, strings and files outside `src/` included).** The gate's exported `extractCitations` and `classifyCitation` over all 41 tracked files of the package (`CHANGELOG.md` excluded), comment-prose and whole-file projections, with the board from the gate's own `probeBoard`: 347 citations and 32 dead before, 323 and 8 after. Under `src/`: comments 5 dead to 0, test comments 19 to 0, strings 0 and test strings 2 unchanged. Its before list of `src/` comment sites equals the census's. The 8 left are 2 test strings and 6 sites outside `src/` (see Acceptance notes). ## Per-site table `git blame` at the base ties each line to the commit that wrote it, and each anchor was read in its message, changeset or diff, not only its subject. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#13279` | `adapter.ts:225`, `:227`; `handler-throw-declared-envelope.test.ts:84`; `current-user-endpoints-localization.test.ts:90` | `6a180e42d`: `tryFind` in `resolveAuthzContext` raises `AuthzStoreUnavailableError` (503 `SERVICE_UNAVAILABLE`) when a permission-store read is issued and throws, instead of answering it as an empty read, and each fail-closed transport `catch` (`requireDatasourceAdmin` in `service-datasource` among them) re-raises it: an unreadable store licenses no verdict, the maintainer's 2026-08-30 ruling recorded in its message. The first three lines blame to `cefe068702` (the declared-envelope rendering, PR objectstack-ai#17412) and the fourth to `5f7fa1de0`; both wrote them citing this ruling. PR objectstack-ai#13475 (200) names objectstack-ai#13279. Stages 1, 2, 4 and 9 gave the number this anchor. | | `objectstack-ai#9934` | `adapter.ts:308`; `handler-throw-declared-envelope.test.ts:152` | `79c46da90`: the producer-side user-facing marking for hook refusals, the `userMessage` channel, a text field a producer sets at throw time and every classified envelope carries. Both lines blame to `cefe068702`. The PR that landed it (PR objectstack-ai#9992) answers 404 too. Stages 1, 2, 4 and 6 gave the number this anchor. | | `objectstack-ai#6307` | `adapter.ts:349` | `293476148`: refuse a repeated `?version=` on `GET`/`DELETE /packages/:id` rather than pick one value, through `readSingleQueryValue`, which it introduces. The line blames to `7cdbcbb306` (surface repeated query parameters as arrays, PR objectstack-ai#7396), which says it follows that direction. Stages 2 and 8 gave the number this anchor. | | `objectstack-ai#6216` | `current-user-endpoints.ts:448` | `f586f1a89`: one `ExecutionContext` assembler with two named anonymous entries, `assembleExecutionContext` the default, fail-closed one and `assembleExecutionContextOrGuest` the explicit guest one, the maintainer's 2026-08-08 Option A recorded in its docblock. The line blames to `6615a024c3` (the current-user faces adopt the shared assembler). Stages 1, 2 and 7 gave the number this anchor. | | `objectstack-ai#16721` | `ui-plugin-auto-discovery.pin.test.ts:27`, `:37`, `:42`, `:180`, `:211`, `:217`, `:360`, `:363`, `:495`, `:498`, `:594`, `:596`, `:604`, `:608`, `:631`, `:646` | `51ae73123`: `LiteKernel.use()` runs the same `assertPluginContract` as `ObjectKernel.use()` and refuses the same plugin objects with the same envelope, the maintainer's 2026-09-08 option A (the kernels converge) recorded in its changeset. 15 lines blame to it; `:180` blames to `3c48234b3`, which re-wrapped that sentence and keeps its fact. Its `lite-kernel.ts` docblock records the measurement taken before converging, which `:604` describes ("before commit 51ae731"). `:363`, `:498` and `:631` said the `hono-plugin.ts` question was "noted on" the dead number; that note is the text this commit wrote into this file, so they now say "raised with" / "recorded with" it. New anchor; no other package has re-anchored this number yet. | **Anchor checks.** Every cited sha matches exactly one object (`git rev-parse --disambiguate`, count 1 for each of the 5), is a commit, has one parent, and is an ancestor of `main` (`merge-base --is-ancestor` against `f927864ea0`, exit 0 for all 5). The checkout is not shallow. The control leg `2672f855fa` (2026-08-09, the parent of the oldest anchor `293476148`) exits 0 against `origin/main`, and the negative control, this branch's own head, exits 1. Four anchors reuse the landed stages' (`6a180e42d`, `79c46da90`, `293476148`, `f586f1a89`), so each number carries one anchor across the tree; one is new (`51ae73123`). **Numbers.** All 5 dropped numbers answer 404 by REST (probed 2026-09-30T00:14:17Z). The numbers kept on or beside the changed lines answer 200: `objectstack-ai#16599`, `objectstack-ai#9864`, `objectstack-ai#16334`, `objectstack-ai#16363`, `objectstack-ai#16049`, `objectstack-ai#6878`, `objectstack-ai#3867`, `objectstack-ai#8086`, `objectstack-ai#16545`, `objectstack-ai#15999`, `objectstack-ai#5090`. `packages/plugins/plugin-hono-server/src` has no slash-joined `#A/#B` without spaces; the spaced pairs (`objectstack-ai#3867 / objectstack-ai#8086`, `objectstack-ai#2408 / objectstack-ai#3361`) are read by the grammar and every half answers 200. ## Mechanical guard: no code token moves **H2 holds on the parser-token reading; the emitted `dist` is NOT byte-identical, because one rewritten `//` comment sits inside a returned object literal and the bundler keeps it.** **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, `getChildren` walk, JSDoc nodes excluded) of the 5 touched files at base `f927864ea0` and at the head. Controls mutate the head text in memory only. - Real run: 15,054 base tokens (4,831 / 2,134 / 3,559 / 2,363 / 2,167), 0 differing, exit 0. - Comment-insertion control: 0 differing, exit 0. - Code-insertion control: all 5 files differ, exit 1. - String control (the first character of the first import specifier flipped in each file): exactly 1 differing `StringLiteral` per file, exit 1. All 48 changed lines (24 out, 24 in) are `//` or `*` comment lines. **Emitted `dist`.** `pnpm --filter @objectstack/plugin-hono-server build` at the head, then at base (the base blobs of the 5 touched files restored in place under a trap-armed restore; an on-disk probe read `objectstack-ai#9934` 1 and `commit 79c46da` 0 in `adapter.ts` before that build; afterwards every touched blob equals its HEAD blob, `git diff HEAD` is empty and the status is clean), with the same dependency builds: - `index.js` and `index.mjs` differ, in one line each: the `adapter.ts:308` comment, `refusal text (objectstack-ai#9934)` at base and `refusal text (commit 79c46da)` at head. `index.d.ts`, `index.d.mts` and both `.map` files are equal. No docblock of this diff reaches the declaration files. - The same parser comparison over the two differing files reads identical tokens (10,818 in `index.js`, 10,521 in `index.mjs`), so the whole `dist` delta is comment text. Its code control (a code line appended) reads COUNT/TOKENS DIFFER in each. - Code-mutation control (`scripts/ablation-replace.mjs`, wrap mode, anchor `message: 'No response from handler' }` hit 1 to 0, planted marker 0 to 1, blob `6a0c10f76282` to `d5223196afeb`; `scripts/ablation-dist-preflight.mjs` found the marker in `index.js` and `index.mjs`): `index.js`, `index.mjs` and both `.map` files differ from the head build. The blob was restored to HEAD `6a0c10f76282` with `git diff HEAD` empty, `dist` was rebuilt, its six sha256 values equal the first head build, and the preflight in `--absent` mode reads the marker absent from all 6 files with a clean tree. A raw scan of the 6 changed files for ASCII control bytes finds none, and `check:nul-bytes` exits 0. ## Changeset **`patch` for `@objectstack/plugin-hono-server`** (`.changeset/plugin-hono-server-provenance-anchors.md`), in PR objectstack-ai#20632's form. The package's `files[]` is `dist`, `README.md` and `CHANGELOG.md`, and the build above emits different `index.js` / `index.mjs` at base and head, so this diff publishes. `check-changeset-no-major`, `check-empty-changeset`, `check-adr-0087-registration` and `check-changeset-fixed` all exit 0. ## Gates (head `03e5f4c0fd`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its official wording, verbatim (printed by every run; the command line differs per run and is listed in the verdicts below): > **Declared narrowing — verification ran UNLOCKED.** `scripts/pm/os-verify-lock.sh` > could not take the shared verify lock on this host: no usable `flock`. The shared > verify lock is declared Linux-only (`flock` is util-linux, and a stock macOS does > not ship it), so the command below was run directly, without the lock — > a declared narrowing, not a silent one. No serialization guarantee held for this > run, nor for any sibling agent in this container while it ran. Its verdict line from each run (the closure build and the three `dist` builds at `feaf0c9b73`, whose `packages/plugins/plugin-hono-server` is byte-identical to this head; the first whole-workspace build, tests and typecheck at `91ce7e5e8f`; the second whole-workspace build, tests and typecheck at this head after the merge; the scratch-script paths shortened to `SCRATCH`): ```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 27s · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/plugin-hono-server...' 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 3s · declare it in the PR body · bash SCRATCH/base-build.sh SCRATCH 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 3s · declare it in the PR body · node scripts/ablation-replace.mjs --file packages/plugins/plugin-hono-server/src/adapter.ts --anchor "message: 'No response from handler' }" --replacement "message: 'No response from handler ABLMARK20594S10' }" -- bash SCRATCH/mut-inner.sh SCRATCH 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 3s · declare it in the PR body · pnpm --filter @objectstack/plugin-hono-server 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 12s · declare it in the PR body · pnpm --filter @objectstack/plugin-hono-server exec vitest run --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 17s · declare it in the PR body · pnpm --filter @objectstack/plugin-hono-server 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 118s (1m58s) · declare it in the PR body · pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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 118s (1m58s) · declare it in the PR body · pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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 11s · declare it in the PR body · pnpm --filter @objectstack/plugin-hono-server exec vitest run --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 16s · declare it in the PR body · pnpm --filter @objectstack/plugin-hono-server typecheck ``` - **Build:** `@objectstack/plugin-hono-server` with its closure (7 of 81 workspace projects), then the whole workspace, `turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2`, 71 of 71 tasks, before and again after the merge. The tree was clean after each, and the package's six `dist` files after each whole build equal the first head build by sha256. - **Tests:** `vitest run --maxWorkers=2`: 27 files, 324 tests passed (every `*.test.ts` under `src/`), at this head and at `91ce7e5e8f`. - **Typecheck:** `pnpm --filter @objectstack/plugin-hono-server typecheck` exits 0 at this head and at `91ce7e5e8f` (`tsc --noEmit`, `tsc --noEmit -p tsconfig.typecheck.json`, and `check:test-typecheck` OK with 0 files / 0 errors / 0 pinned signatures). `--listFiles`: `tsconfig.json` and `tsconfig.test.json` each compile 33 `src/` files including all 27 tests and all 5 touched files. - **Spec artifacts:** `origin/main` brought a `packages/spec` change, so `pnpm --filter @objectstack/spec check:generated` ran after the rebuild: "All 15 generated artifacts are up to date" (exit 0). - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at this head (2026-09-30T00:25:09Z to 00:25:36Z), and at `91ce7e5e8f`. - **Citation judging:** after merging `origin/main` (`fbec216e2d`), `node scripts/check-issue-citations.mjs --base origin/main` reports "no issue citations added against fbec216 (2 file(s) read)" (exit 0). - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 63 families, the same list at `91ce7e5e8f` and at this head. All 63 exit 0 at this head in one pass, and `--ran` with the exit-coded record reads "63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: `check:issue-citations`, `check:doc-authoring`, `check:nul-bytes`, `check:published-files`, `check:dts-closure`, `check:dual-build-cjs-loads`, `check:type-check-debt`, `check-adr-0087-registration`, `check-empty-changeset`. - **Artifact rosters:** 36 of the 39 non-self-test roster rows exit 0 at this head, including the four the derivation marks as keeping their roster under one of this diff's paths (`check-changeset-fixed`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `f927864ea0` the filtered census answers 5 sites on 5 lines, 4 numbers, 2 files, as on the seat's `0be898499f`. The whole-repo count is 1,105. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/plugins/plugin-hono-server`. No site was left for an open PR (the file lists of all open PRs were read at 2026-09-29T23:48:36Z, 6 PRs, and again at 2026-09-30T00:15:14Z, 9 PRs: only the Version Packages PR objectstack-ai#20639 touches the package, in `CHANGELOG.md` and `package.json`) or for an unfound anchor. - **H2 holds on the token reading, not on the `dist` reading.** The parser leaf-token diff of all 5 touched files is empty with its controls firing. The emitted `dist` differs in one comment line of `index.js` and of `index.mjs`, token-identical with a code control. That is why the changeset ships. ## Acceptance notes - **Strings, the form-D stage.** One dead number remains in a string literal in `packages/plugins/plugin-hono-server/src`: `objectstack-ai#16721` at the end of the group-F `describe` title of `ui-plugin-auto-discovery.pin.test.ts` (`:635`, a test title, no assertion text). It stays on the card for its form-D stage; no string moved here. The supplementary scan's second test-string hit, `:111` (`'.os-pin{color:#123456}'`), is a CSS hex colour in a fixture, not a citation: the whole-file projection reads it as a six-digit number, while the census blanks strings and defers test files. - **Outside `src/**`, a later stage of the card:** `objectstack.config.ts:19` (`objectstack-ai#11332`) and `:26` (`objectstack-ai#10724`), `tsconfig.test.json:3` and `:61` (`objectstack-ai#13176`), `tsconfig.typecheck.json:12` (`objectstack-ai#11332` and `objectstack-ai#10724`; `objectstack-ai#4914` in the same group answers 200). The other citations in the package outside `src/**` (`CHANGELOG.md` excluded) answer 200: `tsconfig.test.json` (`objectstack-ai#14062`, `objectstack-ai#5286`, `objectstack-ai#5449`, `objectstack-ai#12542`), `tsconfig.typecheck.json` (`objectstack-ai#13284`, `objectstack-ai#5475`, `objectstack-ai#10756`), `vitest.config.ts` (`objectstack-ai#10374`, `objectstack-ai#9457`, `objectstack-ai#7378`; `objectstack-ai#8129` resolves as a pull request). `README.md` carries none. - **An open question now lives only in this file.** `hono-plugin.ts:521` and `:523` still carry the `&& plugin.staticPath` conjunct and the `plugin.slug || plugin.name.split('/').pop()` derivation that, since `51ae73123`, neither published kernel's `use()` lets an input reach. The pin file says so and leaves the call to `hono-plugin.ts`; the tracker note it pointed at is gone, so this file's text (and commit `3c48234b3`'s message) are the record. Unreachable defensive code, not a defect: noted, not filed. - **Card-word residue, cited nowhere.** `handler-throw-declared-envelope.test.ts` still says "before this card" (`:85`) and "the card" (`:19`, `:32`) around its rewritten lines. They cite no dead number, so they were left, as the landed stages left theirs. - **The moving `origin/main`.** The branch merged `origin/main` once (`03e5f4c0fd`, merging `fbec216e2d`: the ADR-0087 migration chain moves to `@objectstack/spec/migrations`). `packages/spec` is in this package's dependency closure, so the workspace was rebuilt and the package's tests, typecheck and every gate above were rerun at the merge head; nothing in `packages/plugins/plugin-hono-server` changed. ## Deviations - **Three derived gates first read NOT MEASURED.** `check:dual-build-cjs-loads`, `check:lean-entry-closure` and `check:type-check-debt` exited 3 (PREREQUISITE NOT MET: built output absent) in the first pass, before the whole-workspace build. Rerun after it, each exits 0, and all 63 exit 0 in the single pass at this head. - **The first `check:generated` run was void.** This host's global `pnpm` is a v11 front end that rejects the `-s` each sub-gate passes, so all 15 rows read "unexpected argument '-s'" (exit 1, nothing measured). Rerun with the real pnpm 10.31 binary first on `PATH`, it reads all 15 up to date (exit 0). - **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, and AGENTS.md overrides it. The merge commit carries git's default message. --- _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>
…kages/create-objectstack/src to the commits that decided them (objectstack-ai#20748) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 11 of the `domain:cli` lane of the dead-citation sweep: `packages/create-objectstack/src`. Every comment site there 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 keeps saying in its own words what that commit decided. PR objectstack-ai#20533 is the method, and stages 1 to 10 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689, PR objectstack-ai#20703, PR objectstack-ai#20713, PR objectstack-ai#20723, PR objectstack-ai#20735, PR objectstack-ai#20741) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **25 sites on 25 lines in 10 files, covering 9 numbers**, rewritten to **8 distinct commits**: - the census's **3 sites**: `src/banner.ts` 2, `src/index.ts` 1 (2 numbers); - **22 test-file comment sites** in 8 test files (the census defers `*.test.ts`; stages 1 to 10 took test comments too): `starter-comments-self-contained.test.ts` 9, `scaffold-e2e-boot-probe.test.ts` 3, `banner-version.test.ts` 2, `blank-readme-validate-disclosure.test.ts` 2, `scaffold-next-steps-pm.test.ts` 2, `template-consistency.test.ts` 2, `scaffold-skills-single-copy.test.ts` 1, `template-ci-workflow.test.ts` 1. Only comments changed: **25 lines out, 25 in**, every one of them a site (no companion line), and every touched file keeps its line count (147 / 67 / 58 / 617 / 910 / 261 / 357 / 328 / 221 / 745), so no line citation into these files moves. **No citation number is added**: the added lines carry no tracker number at all, and no PR number stands on an added line. No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records any of these 9 decisions (a grep for the 9 numbers there reads 0 hits; the control number `objectstack-ai#7329` reads 2 in the same tree), so every anchor is a commit. **No changeset; `skip-changeset`.** The rewritten comments do not reach the published `dist` (measured below), as in stages 5 and 7 (PR objectstack-ai#20689, PR objectstack-ai#20713). **Scaffold output is untouched.** No site sits inside a template literal or in a file the scaffolder copies: `src/templates/**` carries zero tracker citations in either projection, and all 25 sites are `//` or JSDoc comment prose outside any string. A real scaffold run at base and at head emits a byte-identical project (below). ## Census: `packages/create-objectstack`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run under `with-fleet.sh --read` for the token. The count is its `allocated-but-absent` findings under `packages/create-objectstack/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | package sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `01e78dceef`, run 2026-09-30T01:14:08Z to 01:19:48Z | enumerated, 186 pages, frontier objectstack-ai#20742, 18,569 numbers | 1,077 | **3** | 3 | 2 | 2 | | after | `4ed638093d`, run 01:30:22Z to 01:35:31Z | enumerated, 186 pages, frontier objectstack-ai#20745, 18,572 numbers | 1,074 | **0** | 0 | 0 | 0 | The whole-repo drop of 3 is exactly these sites: a site-by-site diff of the two JSON outputs has 3 findings gone (`banner.ts:10`, `banner.ts:17`, `index.ts:441`) and none added. The other three tallies (`resolves` 33,014, `resolves-as-pull-request` 1,984, `cross-repo-unjudged` 995) are equal in both runs. `packages/create-objectstack` is byte-identical at `4ed638093d` and at the head (the one merge brought no file under it). **Supplementary scan (test files, strings and files outside `src/` included).** The gate's exported `extractCitations` and `classifyCitation` over all 53 tracked files of the package (`CHANGELOG.md` excluded), comment-prose and whole-file projections, with the board from the gate's own `probeBoard`: 77 citations and 33 dead before, 52 and 8 after. Under `src/`: comments 3 dead to 0, test comments 23 to 1, test strings 7 unchanged; `src/templates/**` 0 citations of any kind. Outside `src/`, one citation (`vitest.config.ts:24`, `objectstack-ai#10374`) answers 200. Its before list of `src/` comment sites equals the census's. The 8 left are 7 test strings and 1 test comment with no deciding commit (see "The site left" and Acceptance notes). ## Per-number table `git blame` at the base ties each line to the commit that wrote it, and each anchor was read in its message, changeset or diff, not only its subject. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#10325` | `banner.ts:10`; `banner-version.test.ts:3` | `cec9d239d`: the startup banner reads the real version from `package.json` through the new `renderVersionBanner()`, and sizes the box from the version's plain length, widening and never truncating, instead of the hardcoded `v6.x`. Both lines blame to it; its message carries the closing trailer for this number. New anchor. | | `objectstack-ai#10322` | `banner.ts:17`; `index.ts:441`; `banner-version.test.ts:17`; `blank-readme-validate-disclosure.test.ts:3`, `:50`; `scaffold-next-steps-pm.test.ts:3`, `:7` | `8d21f7a76`: detect the package manager once, up front, and name it in the install line, the install-failure remedy and every "Next steps" line (labels padded to the longer of the two instead of hand-kerned for `npm`), and name `validate` in the blank README's "Getting started". Its message carries the closing trailer for this number. `index.ts:441` and the two test headers blame to it; `banner.ts:17` and `banner-version.test.ts:17` blame to `cec9d239d`, whose message calls this "the sibling bug fixed one function away in the same file"; `scaffold-next-steps-pm.test.ts:7` blames to `c6c7feccd`, a re-wrap that keeps the sentence. New anchor. | | `objectstack-ai#19424` | `scaffold-e2e-boot-probe.test.ts:397`, `:679`, `:816` | `c27e16059`: the boot-probe neighbour announces its own listener (or its bind error), asks the kernel for its port with `listen(0)`, and the harness names five distinct outcomes instead of one "never came up"; the controls block pins each. All three lines blame to it; its message carries the closing trailer for this number. New anchor. | | `objectstack-ai#16331` | `scaffold-skills-single-copy.test.ts:3` | `fd75728bc`: install the skills bundle for one agent (`--skill '*' --agent claude-code -y`) so a scaffolded project's first commit stages it once, with no symlinks. The line blames to it, and its diff is what added the number; its message names none. New anchor. | | `objectstack-ai#10990` | `starter-comments-self-contained.test.ts:41`, `:283` | `21756b325`: converge the shipped template files on the ruled canonical docs origin and pin that convergence as assertion 4 over `shippedFiles()`. Both lines blame to it; its message carries the closing trailer for this number. New anchor for this number. | | `objectstack-ai#11022` | `starter-comments-self-contained.test.ts:50`, `:91`, `:122`, `:221` | `21756b325`: rewrite the blank README's two monorepo-only references, add the fifth `MONOREPO_ONLY` pattern (the framework's own name next to a "repo" word), retire the self-retiring `EXCLUDED` entry and add the README's two RATIONALE facts. All four lines blame to it. Stage 3 (PR objectstack-ai#20656) gave this number the same anchor. | | `objectstack-ai#15150` | `starter-comments-self-contained.test.ts:72`, `:133`, `:141` | `cc986c913`: the sixth `MONOREPO_ONLY` pattern, for a reference written as a relative path that climbs out of the project, anchored on bare `../` rather than on a depth judgement. All three lines blame to it; its diff is what added the number (8 times, across both scaffolders' pins), its message names none. New anchor. | | `objectstack-ai#16330` | `template-ci-workflow.test.ts:3`; `template-consistency.test.ts:376` | `4998efa71`: ship `.github/workflows/ci.yml` in the blank template (the template's first dot-directory) so a scaffolded project has gates from its first push. Both lines blame to it; its diff added the number, its message names none. New anchor. | | `objectstack-ai#10326` | `template-consistency.test.ts:498` | `675ab574e`: declare the two benign peer skews a clean first install reported as scoped pnpm `allowedVersions` inside the scaffold. The line blames to it. Stage 3 (PR objectstack-ai#20656) gave this number the same anchor. | **Anchor checks.** Every cited sha matches exactly one object (`git rev-parse --disambiguate`, count 1 for each of the 8), is a commit, has one parent, and is an ancestor of `main` (`merge-base --is-ancestor` against `01e78dceef`, exit 0 for all 8). The checkout is not shallow. The control leg `2aca1bc4c0` (the parent of the oldest anchor `675ab574e`, 2026-08-20) exits 0 against the base, and the negative control (the base as an ancestor of `675ab574e`) exits 1. Two anchors reuse the landed stages' (`21756b325`, `675ab574e`); six are new. **Numbers.** All 9 dropped numbers answer 404 by REST (probed 2026-09-30T01:11:14Z and again at 01:50:21Z). The one number kept on a line beside the changed ones, `objectstack-ai#9779` (`scaffold-e2e-boot-probe.test.ts:673`), answers 200. The anchor commits' own PR numbers are not cited: three of them (objectstack-ai#11030, objectstack-ai#11013, objectstack-ai#11191) answer 404 as well, which is the reason the ruling cites commits. ## The site left **No deciding commit (1 site, a test comment, so not in the census):** `template-consistency.test.ts:153` (`objectstack-ai#11048`): "admitting them is a support decision (objectstack-ai#11048), not a value to drift here". The number names an open support decision (whether to admit 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 pnpm 10.15 or later at the base. Stage 3 (PR objectstack-ai#20656) left the sibling site `packages/cli/src/commands/init.ts:267` for the same reason. ## Mechanical guard: no code token moves, and nothing emitted moves **H2 holds on both readings: the parser-token diff is empty, and the emitted `dist` and the scaffolded project are byte-identical.** **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, `getChildren` walk, JSDoc nodes excluded) of the 10 touched files at base `01e78dceef` and at `4ed638093d`. Controls mutate the head text in memory only. - Real run: 16,198 base tokens, 0 files differing, exit 0. - Comment-insertion control: 0 differing, exit 0. - Code-insertion control: all 10 files differ, exit 1. - String control (the first character of the first import specifier flipped in each file): all 10 files differ, first differing kind `StringLiteral`, exit 1. All 50 changed lines (25 out, 25 in) are `//` or `*` comment lines. **Emitted `dist`.** `pnpm --filter create-objectstack build` at base (before any edit) and at `4ed638093d`, after the same dependency build. All 24 `dist` files (`index.js`, `chunk-ZIUW7UEA.js`, `created-summary.js`, `created-summary.d.ts` and the 20 copied template files) have equal sha256 at base and head, and `diff -r` is empty. None of the dead numbers appears in the base `dist` at all: tsup drops these comments. - Code-mutation control (`scripts/ablation-replace.mjs`, wrap mode, anchor `Dependency installation failed.` hit 1 to 0, planted marker 0 to 1, blob `b68538942c96` to `860de8778f10`; `scripts/ablation-dist-preflight.mjs` found the marker in `dist/index.js`): `index.js` differs from the head build. The blob was restored to HEAD `b68538942c96` with `git diff HEAD` empty, `dist` was rebuilt, the preflight in `--absent` mode reads the marker absent from all 24 files with a clean tree, and the 24 sha256 values equal the first head build. - The whole-workspace builds (below) left `create-objectstack`'s `dist` equal to the same 24 values. **Scaffold output.** `node packages/create-objectstack/bin/create-objectstack.js demo-app --skip-install --skip-skills`, run in an empty directory from the base build and again from the head build: both emit the same 21 files with equal sha256, `diff -r` is empty, and the printed output differs only in the absolute target directory line. A raw scan of the 10 changed files for ASCII control bytes finds none (a positive probe on a scratch file with one such byte reads 1), and `check:nul-bytes` exits 0. ## Changeset **None; `skip-changeset`.** The package's `files[]` is `dist`, `README.md` and `CHANGELOG.md`; the build above emits a byte-identical `dist` at base and head, and the code-mutation control proves that build does move when code moves. The two other shipped files are untouched, so this diff publishes nothing. ## Gates (head `a84b73af13`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its official wording, verbatim (printed by every run; the command line differs per run and is listed in the verdicts below): > **Declared narrowing — verification ran UNLOCKED.** `scripts/pm/os-verify-lock.sh` > could not take the shared verify lock on this host: no usable `flock`. The shared > verify lock is declared Linux-only (`flock` is util-linux, and a stock macOS does > not ship it), so the command below was run directly, without the lock — > a declared narrowing, not a silent one. No serialization guarantee held for this > run, nor for any sibling agent in this container while it ran. Its verdict line from each run (the closure build and the base build at `01e78dceef`; the head build, the first whole-workspace build, the tests, the boot-probe file and the typecheck at `4ed638093d`; the second whole-workspace build, tests and typecheck at this head after the merge): ```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 22s · declare it in the PR body · pnpm --workspace-concurrency=2 --filter 'create-objectstack^...' 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 2s · declare it in the PR body · pnpm --filter create-objectstack 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 1s · declare it in the PR body · pnpm --filter create-objectstack 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 134s (2m14s) · declare it in the PR body · pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=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 8s · declare it in the PR body · pnpm --filter create-objectstack exec vitest run --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 create-objectstack exec vitest run --maxWorkers=2 src/scaffold-e2e-boot-probe.test.ts 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 create-objectstack 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 35s · declare it in the PR body · pnpm exec turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=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 7s · declare it in the PR body · pnpm --filter create-objectstack exec vitest run --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 create-objectstack typecheck ``` - **Build:** `create-objectstack`'s dependency closure (`@objectstack/spec`, its only workspace dependency), then the package, then the whole workspace, `turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=2`, 71 of 71 tasks, before and again after the merge. The tree was clean after each. - **Tests:** `vitest run --maxWorkers=2`: 16 files, 247 tests: 233 passed and 14 skipped, at this head and at `4ed638093d`. The 14 skipped are the whole of `scaffold-e2e-boot-probe.test.ts` (run alone: 1 file skipped, 14 tests skipped), which its own `RUNNABLE` gate (`process.platform === 'linux'`, plus `bash`, `curl`, `openssl`) skips on this macOS host. **NOT MEASURED locally: `scaffold-e2e-boot-probe.test.ts`, reason: Linux-only by its own gate; CI runs it.** Its diff is 3 comment lines with identical parser tokens. - **Typecheck:** `pnpm --filter create-objectstack typecheck` (`tsc --noEmit`) exits 0 at this head and at `4ed638093d`. `--listFiles` reaches 26 `src/` files outside `src/templates/`, including all 16 tests and all 10 touched files. - **Spec artifacts:** not run. Neither `origin/main`'s one incoming commit nor this diff touches `packages/spec`. - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at this head (2026-09-30T02:00:09Z to 02:00:43Z), and at `4ed638093d` (01:49:31Z to 01:50:04Z). - **Citation judging:** after merging `origin/main` (`697845d19f`), `node scripts/check-issue-citations.mjs --base origin/main` reports "no issue citations added against 697845d (2 file(s) read)" (exit 0). - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 52 families, the same list at `4ed638093d` and at this head. All 52 exit 0 at this head in one pass, and `--ran` with the exit-coded record reads "52 derived, 52 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: `check:issue-citations`, `check:doc-authoring`, `check:nul-bytes`, `check:published-files`, `check:cross-package-test-inputs`, `check:dts-closure`, `check:dual-build-cjs-loads`, `check:type-check-debt`, `check-changeset-no-major`. - **Artifact rosters:** 36 of the 39 non-self-test roster rows exit 0 at this head, among them `check:scaffold-emission-policy` and the three the derivation marks as keeping their roster under one of this diff's paths (`check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `01e78dceef` the filtered census answers 3 sites on 3 lines, 2 numbers, 2 files, as on the seat's `0be898499f`. The whole-repo count is 1,077. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/create-objectstack`. No census site was left for an open PR (the file lists of all open PRs were read at 2026-09-30T01:21:44Z and again at 01:52:53Z, 8 PRs each time: only the Version Packages PR objectstack-ai#20639 touches the package, in `CHANGELOG.md` and `package.json`) or for an unfound anchor. The one site left for an unfound anchor is a test comment, outside the census. - **H2 holds.** The parser leaf-token diff of all 10 touched files is empty with its controls firing, and, independently, the emitted `dist` and the scaffolded project are byte-identical at base and head, with a code-mutation control that changes `dist`. ## Acceptance notes - **Strings, the form-D stage.** Seven dead numbers remain in string literals, all test titles in `src/`: `banner-version.test.ts:66` and `:96` (`objectstack-ai#10325`), `blank-readme-validate-disclosure.test.ts:25` (`objectstack-ai#10322`), `scaffold-e2e-boot-probe.test.ts:829` (`objectstack-ai#19424`), `scaffold-next-steps-pm.test.ts:173` and `:197` (`objectstack-ai#10322`), `template-consistency.test.ts:503` (`objectstack-ai#10326`). They stay on the card for its form-D stage; no string moved here. None is an assertion text or scaffold output. - **Outside `src/**`:** nothing dead. The one citation there, `vitest.config.ts:24` (`objectstack-ai#10374`), answers 200; `README.md` and `bin/` carry none. - **Live but misdirected numbers, a different class.** Two numbers in this package answer 200, but as unrelated pull requests. `objectstack-ai#4902` (`index.ts:165`, `:239`; `rewrite-identity.ts:36`; `runtime-image.ts:140`; `rewrite-identity.test.ts:3`, and the test title at `:123`) was written by `8d41998b0`, whose own message names `objectstack-ai#4926` (the remote-template object-name rewrite being silently skipped), and `f2f09e4e3` repeated it at `runtime-image.ts:140`; `objectstack-ai#4902` itself is an unrelated `init-service` guard PR. `objectstack-ai#3120` (`template-copy.ts:20`; `template-consistency.test.ts:259`) was written by `3b6ef8a32` (the scaffolded `.gitignore`), and `objectstack-ai#3120` is an unrelated approvals-docs PR. The census reads both as `resolves-as-pull-request`, a reading and not a finding, and this card is about 404s, so neither moved here. Noted, not filed. - **Card-word residue, cited nowhere.** Some rewritten test headers still say "the card" or "per triage" nearby (`banner-version.test.ts:13`, `blank-readme-validate-disclosure.test.ts:3`). They cite no dead number, so they were left, as the landed stages left theirs. - **The moving `origin/main`.** The branch merged `origin/main` once (`a84b73af13`, merging `697845d19f`: PR objectstack-ai#20742, the `service-package` citation re-anchoring). Nothing under `packages/create-objectstack` or `packages/spec` changed, so the package's tests, typecheck, every derived gate, the roster rows and lint were rerun at the merge head and all read as before. ## Deviations - **Three derived gates first read NOT MEASURED.** `check:dual-build-cjs-loads`, `check:lean-entry-closure` and `check:type-check-debt` exited 3 (PREREQUISITE NOT MET: built output absent) in the first pass, before the whole-workspace build. Rerun after it, each exits 0, and all 52 exit 0 in the single pass at this head. - **The first code-mutation attempt was void.** Its replacement text contained the anchor, so the anchor count could not fall; `ablation-replace.mjs` refused it (anchor 1 to 1, exit 1) and restored the blob to HEAD before anything was built. The second attempt, with a replacement that does not contain the anchor, is the one reported above. - **The two builds inside the code-mutation control** (the mutate leg and the restore leg) ran directly, not through `os-verify-lock.sh`. On this host that wrapper runs unlocked anyway, so nothing was serialized either way. - **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, and AGENTS.md overrides it. The merge commit carries git's default message. --- _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>
…ugins/plugin-dev/src to the commits that decided them (objectstack-ai#20767) Part of objectstack-ai#20594 Clause-②: no ## What changed This is stage 12 of the `domain:cli` lane of the dead-citation sweep: `packages/plugins/plugin-dev/src`. Every comment site there 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 keeps saying in its own words what that commit decided. PR objectstack-ai#20533 is the method, and stages 1 to 11 of this card (PR objectstack-ai#20624, PR objectstack-ai#20632, PR objectstack-ai#20656, PR objectstack-ai#20673, PR objectstack-ai#20689, PR objectstack-ai#20703, PR objectstack-ai#20713, PR objectstack-ai#20723, PR objectstack-ai#20735, PR objectstack-ai#20741, PR objectstack-ai#20748) are the precedents. The card stays open for the lane's remaining packages, so this PR says `Part of`. That is **6 sites on 6 lines in 3 files, covering 2 numbers**, rewritten to **2 distinct commits**: - the census's **3 sites**, all in `src/dev-plugin.ts` (`:1063`, `:1078`, `:1097`); - **3 test-file comment sites** (the census defers `*.test.ts`; stages 1 to 11 took test comments too): `dev-plugin.test.ts:90` and `:127`, `dev-plugin-security-enforcement-warning.test.ts:53`. Only comments changed: **6 lines out, 6 in**, every one of them a site (no companion line), and every touched file keeps its line count (1159 / 317 / 199), so no line citation into these files moves. **No citation number is added**: the only tracker number on an added line is `objectstack-ai#3900` at `dev-plugin.ts:1063`, which the removed line already carried and which answers 200; no PR number stands on an added line. No ADR or ruling-record file in `docs/adr/` or `scripts/adr-anchors/` records either decision (a grep there for the 2 numbers, their PR number objectstack-ai#10092 and the 2 shas reads 0 hits; the control number `7329` reads 1 file in the same tree), so both anchors are commits. ADR-0115 records the older decision the warning comes from (an empty security slot gets one loud boot-log line), not the move these lines describe. **A `patch` changeset** for `@objectstack/plugin-dev` rides along (`.changeset/plugin-dev-provenance-anchors.md`, in PR objectstack-ai#20632's form), because the two rewritten docblock lines reach the published `dist` (measured below), as stage 6 (PR objectstack-ai#20703) measured for its package. ## Census: `packages/plugins/plugin-dev`, before and after **Instrument.** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged, run under `with-fleet.sh --read` for the token. The count is its `allocated-but-absent` findings under `packages/plugins/plugin-dev/`. Both runs enumerated the whole board. | reading | tree | board | whole-repo `allocated-but-absent` | package sites | lines | numbers | files | |---|---|---|---|---|---|---|---| | before | base `33e4a5609c`, run 2026-09-30T02:45:30Z to 02:51:51Z | enumerated, 186 pages, frontier objectstack-ai#20757, 18,584 numbers | 1,061 | **3** | 3 | 2 | 1 | | after | head `a237b10ee7`, run 03:07:39Z to 03:14:14Z | enumerated, 186 pages, frontier objectstack-ai#20765, 18,592 numbers | 1,058 | **0** | 0 | 0 | 0 | The whole-repo drop of 3 is exactly these sites: a site-by-site diff of the two JSON outputs has 3 findings gone (`dev-plugin.ts:1063`, `:1078`, `:1097`) and none added. The other three tallies (`resolves` 33,038, `resolves-as-pull-request` 1,984, `cross-repo-unjudged` 995) are equal in both runs. **Supplementary scan (test files, strings and files outside `src/` included).** Every `#N` token (two to six digits) in the package's 19 tracked files, `CHANGELOG.md` excluded, was probed by REST: 39 distinct numbers at base, of which 2 answer 404 in `src/` (`objectstack-ai#10035`, `objectstack-ai#10036`) and 1 outside it (`objectstack-ai#13176`, in `tsconfig.test.json`); `objectstack-ai#1020` is `cloud#1020`, cross-repo. Dead occurrences at base: 6 in `src/` comments (3 source, 3 test), 1 in a test string, 2 in `tsconfig.test.json`. After: 0 in comments, the test string and the two `tsconfig.test.json` lines unchanged (see Acceptance notes). A grep for the two numbers with no word-boundary operator, beside a control of the same shape (`objectstack-ai#3900` reads 6 lines of `dev-plugin.ts`), finds only those three lines left. ## Per-number table `git blame` at the base ties every one of the 6 lines to `7552e0337`, the commit that wrote them, and each anchor was read in its message and its diff, not only its subject. | number | sites (base line) | anchor: what it decided | |---|---|---| | `objectstack-ai#10036` | `dev-plugin.ts:1063`, `:1078`; `dev-plugin.test.ts:90`, `:127`; `dev-plugin-security-enforcement-warning.test.ts:53` | `7552e0337`: the "RBAC/RLS/masking are NOT enforced" warning stops probing the three `SecurityPlugin.init()` internals (`security.permissions`, `security.rls`, `security.fieldMasker`, which the spec contract names implementation internals) and asks the published `security` service instead, and asks it from `DevPlugin.start()`, after the child-start loop and beside the boot banner, since asking from `init()` would find it absent on every stack; the internal handles keep one use, telling "never loaded" apart from "loaded, then failed to start". Both halves of its squash message carry this number. Its own PR number (objectstack-ai#10092) answers 404 as well. | | `objectstack-ai#10035` | `dev-plugin.ts:1097` | `c1731d023`: `plugin-hono-server`'s `/auth/me/permissions` and `/me/apps` delegate permission-set resolution to the `security` service, and their degraded branches key on the published `security` service instead of `security.permissions` (its docblock "What absent now means, precisely"). The site's sentence says the same presence signal misled that endpoint and was cured "by this same move"; `objectstack-ai#10035` is that commit's own PR number, carried in its subject. | **How the lines read now.** `:1063` keeps `objectstack-ai#3900` and says `commit 7552e03 moved this check here from init()`; the `:1078` heading and the test-comment brackets name `commit 7552e03` where the number stood, with the decision spelled out in the surrounding prose they already carried; `:127` reads `(the two told apart since commit 7552e03)`; `:1097` reads `commit c1731d0 by this same move`. **Anchor checks.** Both cited shas match exactly one object (`git rev-parse --disambiguate`, count 1 each), are commits, have one parent, and are ancestors of `main` (`merge-base --is-ancestor` against `33e4a5609c`, exit 0 for both). The checkout is not shallow. Control legs: `44738f7af6` (the parent of `c1731d023`) exits 0 against the base; the negative control (the base as an ancestor of `7552e0337`) exits 1. **Numbers.** `objectstack-ai#10035`, `objectstack-ai#10036` and `objectstack-ai#10092` answer 404 by REST (probed 2026-09-30T02:43:04Z and again at 03:14:40Z). `objectstack-ai#3900`, kept on `:1063`, answers 200. ## Mechanical guard: no code token moves **H2 holds on the token reading; the emitted `dist` is NOT byte-identical, and the difference is exactly the two docblock lines.** **Token guard.** It compares the TypeScript parser's leaf tokens (TypeScript 6.0.3, `getChildren` walk, JSDoc nodes excluded) of the 3 touched files at base `33e4a5609c` and at `37eaf1647f` (the comment commit). Controls mutate the head text in memory only. - Real run: 6,653 base tokens, 0 files differing. - Comment-insertion control: 0 differing. - Code-insertion control: all 3 files differ. - String control (the first character of the first import specifier flipped in each file): all 3 files differ, first differing kind `StringLiteral`. - The script's own verdict: exit 0 (real 0 and every control as expected). All 12 changed lines in `src/` (6 out, 6 in) are `//` or `*` comment lines. **Emitted `dist`.** `pnpm --filter @objectstack/plugin-dev build` at base (before any edit, after its dependency closure) and at `37eaf1647f`. Of the 6 `dist` files, `index.js.map` and `index.mjs.map` have equal sha256; `index.js`, `index.mjs`, `index.d.ts` and `index.d.mts` differ, and `diff -r` shows exactly two changed lines in each: the `:1078` heading and the `:1097` line of the `warnIfNothingIsEnforcingSecurity` docblock. The `//` comment at `:1063` does not ship. So the published tarball carried both dead numbers, and now carries the commits. - Code-mutation control (`scripts/ablation-replace.mjs`, wrap mode, anchor `ctx.logger.info(' Discovery: /.well-known/objectstack');` hit 1 to 0, planted marker 0 to 1, blob `708af69f9b2a` to `b0b387f53d6a`; `scripts/ablation-dist-preflight.mjs` found the marker in `dist/index.js` and `dist/index.mjs`): `index.js`, `index.mjs` and both source maps differ from the head build. The blob was restored to HEAD `708af69f9b2a` with `git diff HEAD` empty, `dist` was rebuilt, the preflight in `--absent` mode reads the marker absent from all 6 files with a clean tree, and the 6 sha256 values equal the head build. - The whole-workspace build (below) left `plugin-dev`'s `dist` equal to the same 6 values. A raw scan of the 4 changed files for ASCII control bytes finds none (a positive probe on a scratch file with one such byte reads 1), and `check:nul-bytes` exits 0. ## Changeset **`patch` for `@objectstack/plugin-dev`.** The package publishes (`files` is `dist`, `README.md`, `CHANGELOG.md`), and the measurement above shows the rewritten docblock reaching four `dist` files. The changeset states comments only, with no behaviour change. `check-empty-changeset`, `check-changeset-no-major`, `check-adr-0087-registration` (1 non-breaking changeset seen) and `check-changeset-fixed` all exit 0. ## Gates (head `a237b10ee7`) This host has no `flock`, so `os-verify-lock.sh` ran in its declared unlocked mode. Its official wording, verbatim (printed by every run; the command line differs per run and is listed in the verdicts below): > **Declared narrowing — verification ran UNLOCKED.** `scripts/pm/os-verify-lock.sh` > could not take the shared verify lock on this host: no usable `flock`. The shared > verify lock is declared Linux-only (`flock` is util-linux, and a stock macOS does > not ship it), so the command below was run directly, without the lock — > a declared narrowing, not a silent one. No serialization guarantee held for this > run, nor for any sibling agent in this container while it ran. Its verdict line from each run (the closure build at base `33e4a5609c`; the head build at `37eaf1647f`; the whole-workspace build, the tests and the typecheck 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 65s (1m05s) · declare it in the PR body · pnpm --workspace-concurrency=2 --filter '@objectstack/plugin-dev...' 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 3s · declare it in the PR body · pnpm --filter @objectstack/plugin-dev 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 97s (1m37s) · declare it in the PR body · pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=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 7s · declare it in the PR body · pnpm --filter @objectstack/plugin-dev exec vitest run --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 6s · declare it in the PR body · pnpm --filter @objectstack/plugin-dev typecheck ``` - **Build:** `plugin-dev` with its dependency closure (36 packages, the filter spelled with the package included), then the package, then the whole workspace, `turbo run build --filter=./packages/* --filter=./packages/*/* --concurrency=2`, 71 of 71 tasks. The tree was clean after each. - **Tests:** `vitest run --maxWorkers=2`: 9 files, 86 tests, all passed. - **Typecheck:** `pnpm --filter @objectstack/plugin-dev typecheck` (`tsc --noEmit`, then `check:test-typecheck` over `tsconfig.test.json`) exits 0. `--listFiles` under both configs reaches all 12 `src/` files, including the 9 tests and the 3 touched files. - **Spec artifacts:** not run. `origin/main` did not move while this branch was open (still `33e4a5609c`; the merge was a no-op), and this diff does not touch `packages/spec`. - **Lint:** the repo-wide `pnpm lint` (`eslint . --no-inline-config`) exits 0 at this head (2026-09-30T03:07:02Z to 03:07:32Z). - **Citation judging:** after merging `origin/main` (already up to date at `33e4a5609c`), `node scripts/check-issue-citations.mjs --base origin/main` judges 1 added citation (`objectstack-ai#3900`), which resolves (exit 0). - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 62 families from the 4 changed paths. All 62 exit 0 in one pass at this head, and `--ran` with the exit-coded record reads "62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero). Among them: `check:issue-citations`, `check:doc-authoring`, `check:nul-bytes`, `check:published-files`, `check:cross-package-test-inputs`, `check:dts-closure`, `check:dual-build-cjs-loads`, `check:type-check-debt`, `check-empty-changeset`, `check-adr-0087-registration`. - **Artifact rosters:** 36 of the 39 non-self-test roster rows exit 0 at this head, among them `check-changeset-fixed` and the three others the derivation marks as keeping their roster under one of this diff's paths (`check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`). The other three need a pull request's context; they are run against this PR once it exists and reported on the card. The 18 self-test-only rows grade their checkers' fixtures and cannot judge this diff. ## Hypotheses (measured first) - **H0 holds.** At base `33e4a5609c` the filtered census answers 3 sites on 3 lines, 2 numbers, 1 file, as on the seat's `0be898499f`. The whole-repo count is 1,061. - **H1 holds.** After the rewrite, the filtered census answers 0 for `packages/plugins/plugin-dev`. No site was left for an open PR (the file lists of all 8 open PRs were read at 2026-09-30T02:45:10Z: only the Version Packages PR objectstack-ai#20639 touches the package, in `CHANGELOG.md` and `package.json`) or for an unfound anchor. - **H2 holds, by the token reading, not the `dist` reading.** The parser leaf-token diff of all 3 touched files is empty with its controls firing. The emitted `dist` is not byte-identical, and it is not meant to be: its only difference is the two docblock lines, which is why the changeset ships. ## Acceptance notes - **Strings, the form-D stage.** One dead number remains in a string literal: the `describe` title at `dev-plugin-security-enforcement-warning.test.ts:121` (`objectstack-ai#10036`). It stays on the card for its form-D stage; no string moved here. It is not assertion text. The same title is quoted in three recorded CI-log fixtures under `scripts/fixtures/merge-queue-triage/`; those are captured logs read by `check-merge-queue-triage-outcome.mjs`, so a later rename of the title does not need them edited. - **Outside `src/**`:** `tsconfig.test.json:3` and `:56` cite `objectstack-ai#13176`, which answers 404. The same number sits in the `tsconfig.test.json` of 13 `packages/plugins/*` packages (17 `tsconfig*.json` files under `packages/` in all), outside the census's declared surface; stage 10 (PR objectstack-ai#20741) recorded its own copy for a later stage of this card. Every other citation in the package outside `src/` answers 200 (`vitest.config.ts`, `README.md`, `tsconfig.json`, `package.json`); `CHANGELOG.md` is release-owned and was not read as a site. - **`origin/main` did not move.** It read `33e4a5609c` at worktree creation and at every later fetch, so every run above is against the same base and nothing needed rerunning after the merge. ## Deviations - **The two builds inside the code-mutation control** (the mutate leg and the restore leg) ran directly, not through `os-verify-lock.sh`. On this host that wrapper runs unlocked anyway, so nothing was serialized either way. - **The dependency-closure build** used the filter `'@objectstack/plugin-dev...'` (package plus its dependencies) rather than the closure-only `^...` spelling; it built the same closure and the package in one run. - **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, and AGENTS.md overrides it. --- _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 2 of the
domain:clilane of the dead-citation sweep:packages/rest/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 #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 and PR #20624 (stage 1,packages/runtime) the precedent this follows line for line. Later stages covercli,typesand the rest of the lane, so this PR saysPart ofand the card stays open.That is 457 comment sites on 445 lines in 85 files, covering 74 numbers: the census's 191 sites, 256 more in test comments (which the census defers), and 10 sites whose dead number is the second half of a slash-joined pair the citation grammar does not read (
#3984/#6241,#9901/#10255four times,#10993/#11235/#11292,#11235/#11242twice,#10993/#11242,#7543/#15071). Each rewritten line cites one of 70 distinct commits.ADR-0076 D11 is the only ADR that records any of these numbers, and it records #8850 only as the extraction it names as landed in
8664a2c99, so that commit is the anchor there. No other ADR or ruling-record file indocs/adr/orscripts/adr-anchors/records the decision behind any of these numbers, so every anchor is a commit. The anchors the landed stages already gave the same numbers are reused where the rest sites describe the same decision (30 numbers, for example79c46da90for #9934,7986d973f/311433f6bfor the compound-name retirement,6a180e42dfor #13279 andcf6e0a193for #15071), so each number carries one anchor across the tree.Only comments changed. Every touched file keeps its line count (451 lines out, 451 in, over 85 files), so no line citation into these files moves. Six of the 451 lines held no dead site; each is the other half of a sentence that had to change:
discovery-schema-conformance.test.ts:343(「(reaffirmed by」 to 「(which commits」, because line 344 now names the two commits that landed the ruling),package-door-16019-raw-statement-fault-code.test.ts:51anderror-response.ts:1485(a trailing 「PR」 whose number wrapped onto the next line),error-response-structured-arm-door-parity.test.ts:463(「That card added the limb」 to 「That commit」, because line 459's tag now names the commit),rest-hook-script-fault-envelope.test.ts:331(「both sides of that card」 to 「that fix」),rest-server.ts:908(「(test(driver-sql): measure what each dialect materialises for a datetime JS cannot hold (#14078) #14409, landed」 to 「(landed as commit」, the sha3ecb7dc1aalready standing on line 909).No citation number is added. Every tracker number on an added line was already on the line it replaces. No PR number stands on an added line. One of the 70 shas is on a removed line, and it was there before:
rest-14078-invalid-date-total-arm.test.ts:19read 「PR #14409 (landed3ecb7dc1a)」 and now reads 「Commit 3ecb7dc drove」. No code token moves (see the guard below).Three dead comment sites are left on purpose, listed under "The sites left". One more file: a
patchchangeset for@objectstack/rest, because the rewritten docblocks ship (see Changeset below).Census:
packages/rest, 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/rest/. Both runs enumerated the whole board (185 pages), so neither read a truncated board.allocated-but-absenta186aea996, run 2026-09-29T10:28:18Z to 10:36:06Z93e4d69ba6, run 11:11:30Z to 11:17:37ZThe before count equals the card's 191 at
f11b5f20a2. The whole-repo drop is 251: this diff's 191, plus the 60 of PR #20626 (packages/plugins/plugin-sharing, 63 to 3), which landed onmainin between and came in with the merge. No other package moved.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.tsfile underpackages/rest/src(256 files), against the board enumerated through the gate's ownenumerateBoard. The lit controls #20594, #19123 and #20624 answered 200 and are on both boards; the dead controls #13214, #14541 and #15071 answered 404 and are on neither.a186aea99693e4d69ba6Its src-comment column equals the census's 191 and 0, which is the control on the second instrument, and a site-by-site comparison of the two before-readings is identical. Resolving comment citations move by one (1,364 to 1,365 in src):
(#10993/#11235/#11292)became(#10993, commit 376c70f98, #11292), so the grammar now reads the live#11292that the slash hid. The drop is 447 grammar-read sites; the other 10 rewritten sites are the slash-joined ones the grammar never read.Separately, every one of the 77 numbers was probed on its web endpoint: 76 answer 404 (deleted) and one, #14026, answers 302 to objectstack-ai/objectui#10102 (transferred), which is why it is left (see below).
Per-number table
Sites and files are the dead comment sites in scope at the base, tests and slash-joined halves included.
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.#603718189983d#612264cd01082#62068e13ca876#6216f586f1a89#624183a3b1f2e#62596968885ef#6303465c5fc14#6306fec784863#6307293476148#63492443bb4c4#647418189983d#6535a92b1793c#66402ab1257c9#6704c3f491626#8641#88508664a2c99#888530b1c636a#8919b5378550e#97412a29caa53#980545862a53d#993479c46da90#99678f266f1cd#100639e04c3e35#1017838cf397ea#10179#102556ce58a735#1034026f3588fb#10345cad8b42f0#10350490879ad0#1048535ad101bc#10537e634ecf6a#10888d806081dd#11006cccbe51bf#11130851909530#11235376c70f98#1124298ea3443f#121443a04b0125#121767986d973f#12194311433f6b#121957986d973f#131825b3ff63cc#1319756c093c4d#132134801296e7#13214cc837dbfe,889ec5b42,3d10755f0#13244889ec5b42#1325543028a8f8#132583d10755f0#132796a180e42d#13280add6a1b1c#1328243028a8f8#13377e10cf3444#1337882faea03f#134547ad57e17a#14026#14365#1436653cbad9f7#14369a3d5724c8,53cbad9f7#1438910220a7bf#143909d7f7259f#144093ecb7dc1a#145416d178a408#1461381208086a#14677a4e4d2d78#1468396326040f#14691b3a63d32c#147041c7adc73d#1472365846bc46#14725f5cc78b63#14849226e72443#14907e1d4f9e3f#14908d5cbb44f3#15021cc238db8b#15034abf9101f1#150651c7adc73d#15071cf6e0a193#16650001a83b04#1705894c930248#1854658f60e37eEvery cited sha matches exactly one object (
git rev-parse --disambiguate, count 1 for each of the 70), is a commit, has one parent, and is an ancestor of the base (merge-base --is-ancestor, exit 0 for all 70). The checkout is not shallow (--is-shallow-repositoryfalse); the control leg13a6cb4adexits 0 and the negative control (this branch's first WIP commit, not onmain) exits 1. Several numbers are the PR number of their own anchor commit (#6122, #6303, #6474, #11242, #13213, #13244, #13258, #13282, #14409, #14677, #14908, #15065, #16650), so the sha is the same object the number named.Numbers with more than one anchor, by site:
#13214(18 sites) was one card with three commits.cc837dbfe(the ownership gate, the 2026-08-30 ruling) for the 11 sites that describe the gate;889ec5b42for the 5 inui-view-route-identity.measurement.test.ts, the identity measurement it created;3d10755f0for the tenancy file's header, the measurement it created; andrest-server.ts:2247, 「Driven and reported on [finding]GET /api/v1/ui/view/:object/:typeresolves a UI view with no identity resolution and no anonymous-deny at the REST seam #13214 (PRs test(rest): measure identity resolution at GET /ui/view/:object/:type — seam, downstream producer, and the ratchet blind spot behind it #13244, test(rest): drive the tenancy axis of GET /ui/view/:object/:type — an anonymous caller can name another environment and receive its UI view #13258)」, now reads 「Measured in commits 889ec5b (identity) and 3d10755 (tenancy)」: those PRs are exactly those two commits.#14369(3 sites):a3d5724c8(the liveness census it recorded) forrest-server.ts:1172andrest-sub-config-parse-not-cast.test.ts:48.rest-server.ts:4092said the zero read sites ofapi.documentation/api.responseFormatcame from 「the [finding] Ten declaredRestServerConfigkeys are normalized byRestServerand read by nothing —routes.*entirely,crud.patterns/objectParamStyle,metadata.cacheTtl/endpoints.schema,batch.defaultAtomic/operations.upsertMany(ADR-0049 enforce-or-remove candidates) #14369 census」, buta3d5724c8explicitly leftapiout of that census; the zero was measured by53cbad9f7(its changeset: no other read site for either key), which is the anchor there.#11235/#11242/#10993:376c70f98derives the discoveryversionin metadata-protocol ([finding] a THIRD hardcoded discoveryversionliteral —getDiscovery()inpackages/metadata-protocol/src/protocol.ts, identical defect to #10993, different producer/package #11235), and98ea3443fis fix(runtime): derive /health and discoveryversioninstead of a hardcoded '1.0.0' literal #11242's own squash, which landed the [finding] /api/v1/health reports a hardcoded version: '1.0.0' — a field that exists and lies, so no consumer can use it for artifact identity #10993 ruling on/healthand the dispatcher's/discovery. So 「the [finding] /api/v1/health reports a hardcoded version: '1.0.0' — a field that exists and lies, so no consumer can use it for artifact identity #10993 ruling … reaffirmed by [finding] a THIRD hardcoded discoveryversionliteral —getDiscovery()inpackages/metadata-protocol/src/protocol.ts, identical defect to #10993, different producer/package #11235/fix(runtime): derive /health and discoveryversioninstead of a hardcoded '1.0.0' literal #11242」 now reads 「the [finding] /api/v1/health reports a hardcoded version: '1.0.0' — a field that exists and lies, so no consumer can use it for artifact identity #10993 ruling, landed by commits 98ea344 and 376c70f」 (rest-server.ts:4528,discovery-schema-conformance.test.ts:343-344).#10993,#11292and#11297answer 200 and stay.#6037/#6474: one commit,18189983d(feat(spec,objectql,metadata-protocol): validate-only data operation — DataProtocol.validateData #6474 is its PR number), so 「([spec] DataProtocol 新增 validate-only 数据校验操作 —— #4633 裁 D 的契约半边(spec 先行) #6037 / PR feat(spec,objectql,metadata-protocol): validate-only data operation — DataProtocol.validateData #6474)」 became 「(commit 1818998)」.Wordings to check, each true of its commit:
#14541's contract review: 「the Routes exiting throughhandleRouteErroranswer the engine'sDUPLICATE_RECORDenvelope fromresolveErrorResponse's.statuspassthrough —fieldandobjectdropped,mapDataError's structured 409 arms never consulted #14541 contract review (condition N)」 now reads 「the contract review of commit 6d178a4 (condition N)」; that commit's message lists the conditions it carries. 「Routes exiting throughhandleRouteErroranswer the engine'sDUPLICATE_RECORDenvelope fromresolveErrorResponse's.statuspassthrough —fieldandobjectdropped,mapDataError's structured 409 arms never consulted #14541's §4」 and 「Routes exiting throughhandleRouteErroranswer the engine'sDUPLICATE_RECORDenvelope fromresolveErrorResponse's.statuspassthrough —fieldandobjectdropped,mapDataError's structured 409 arms never consulted #14541 §5」 inerror-response-generic-passthrough-object-parity.test.tsare sections oferror-response-structured-arm-door-parity.test.ts(the file6d178a408created), so they now name that file. 「measured on the Routes exiting throughhandleRouteErroranswer the engine'sDUPLICATE_RECORDenvelope fromresolveErrorResponse's.statuspassthrough —fieldandobjectdropped,mapDataError's structured 409 arms never consulted #14541 branch」 reads 「on the branch that landed as commit 6d178a4」./metadoors decided ORGANIZATION SCOPE from the RAW url」, 「the defect commit 2443bb4 fixed」 and 「would be the defect commit 26f3588 fixed」.#13255: 「As written for [finding] resolveExecCtx 的.catch(() => undefined)把执行上下文解析失败静默降级为「无上下文」— 该行为在包管理门上可达什么错误状态,未测 #13255 this file repaired nothing」 reads 「As first written (commit 43028a8)」, the commit that created the file and answered the measurement; 「CONTEXT-LOST family ([finding] resolveExecCtx 的.catch(() => undefined)把执行上下文解析失败静默降级为「无上下文」— 该行为在包管理门上可达什么错误状态,未测 #13255), still unruled」 reads 「first measured by commit 43028a8」 (the ruling on that family never landed, which the line still says).#13214in the identity file: 「the half [finding]GET /api/v1/ui/view/:object/:typeresolves a UI view with no identity resolution and no anonymous-deny at the REST seam #13214 marks UNMEASURED」 reads 「the half left UNMEASURED until commit 889ec5b」, and 「[finding]GET /api/v1/ui/view/:object/:typeresolves a UI view with no identity resolution and no anonymous-deny at the REST seam #13214 asks for an INDEPENDENT reproduction」 reads 「commit 889ec5b is an INDEPENDENT reproduction」.handleApprovalError's 9 wire-code rows have no live-emission pin — counted, not fixed #14849 predicted」 reads 「The card behind commit 226e724 predicted」; 「the hazard A typed IHttpRequest test builder — 4 ledgered TS2345 in packages/rest are hand-built request literals, and the only in-repo alternative isas any#13377 names」 reads 「the hazard commit e10cf34 was written to remove」; 「The concrete harm [finding]ImportRequest.runAutomationsdeclares.default(false)and documents "off by default for bulk", butPOST /data/:object/importdefaults it ON #6704 names」 reads 「removed」.error-response-sandbox-arm-message.test.ts:340sits inside a verbatim ruling quote, so the commit stands in an editorial bracket (「not from [commit 1c7adc7]'s list」), as PR docs(runtime): re-anchor the dead tracker citations in packages/runtime/src to the commits that decided them #20624 did.meta-state-route-engine-outage.test.ts:76,objectql-slot-consumer-census.test.ts:43): the rewritten cell is wider than its column, and its padding is reduced rather than widening the four sibling rows.The sites left
No deciding commit (3 sites, all in test files, so the census does not see them):
meta-object-owd-gate.test.ts:516([Decision]sys_*objects silently default to PUBLIC row visibility — should the platform's own objects keep an unstated default at all, and isisSystemeven the right predicate? #8641): 「whether it should stay is [Decision]sys_*objects silently default to PUBLIC row visibility — should the platform's own objects keep an unstated default at all, and isisSystemeven the right predicate? #8641's question」, an open decision. The commit that added the citation calls it a pointer to the open decision card, and no commit decides it.rest-sub-config-parse-not-cast.test.ts:321(CrudEndpointsConfigSchema.patternsis an exhaustive enum-keyedz.record— the input type demands all five operations and a partial parses to explicitundefinedentries (wantsz.partialRecord) #14365): thez.partialRecordquestion 「deferred toCrudEndpointsConfigSchema.patternsis an exhaustive enum-keyedz.record— the input type demands all five operations and a partial parses to explicitundefinedentries (wantsz.partialRecord) #14365」 was never taken (git log -S partialRecord);b3a63d32cmade it moot by retiring the record, which the other half of the same line now cites.import-integration.test.ts:1043(#14026): not deleted, TRANSFERRED. The web endpoint answers 302 to Re-raise of #4375 with the downstream confirmation it asked for: the console import wizard never sendsmappingNameand hardcodeswriteMode:"insert", so a named mapping'supsertcan never reach a user objectui#10102, the REST read follows the redirect, and the board enumeration does not list it, so the census and the supplementary reading both class itallocated-but-absent. The line says how an issue was raised; no commit decides that, so form C has nothing to cite.String sites kept as tokens (127). 126 are test titles and test-code strings in 41 files. One is a non-test string: the
notefield of the REST route ledger'sGET /api/v1/meta/object/:name/state/:fieldrow atrest-route-ledger.ts:290, which ends 「(#10179)」 (see Acceptance notes).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
a186aea996against the working tree at93e4d69ba6, over all 85 touched.tsfiles. Controls mutate the head text in memory only, so nothing on disk moved for them.error-response.ts): 0 files changed (exit 0).Line balance: every touched file is +N/−N (451/451), and every line count is equal at base and head. A raw scan of the 86 changed files for control bytes finds none (its positive control on a scratch file with a U+0001 byte matches).
Changeset
This change ships bytes, so a
patchchangeset for@objectstack/restis included, in PR #20624's form and level. It says only that the provenance comments were re-anchored.Measured on the built package:
files[]isdist,README.mdandCHANGELOG.md. Afterpnpm --filter @objectstack/rest build, the rewritten docblocks reachdist: for example53cbad9f7appears 4 times indist/index.d.ts, and26f3588fb8 times andb3a63d32c5 times indist/index.js. The positive control, the unchanged sentence 「It was VALIDATE-ONLY from #11637」 of the samerest-server.tsdocblock whose first line now reads 「[commit 53cbad9] The parsed output is CONSUMED」, is indist/index.d.tsbeside it; a negative control phrase appears nowhere.Gates (head
93e4d69ba6)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 branch merged
origin/mainonce (93e4d69ba6, merging542670da6d) before these runs, as the dispatch orders;origin/mainhas not moved since (read at 11:19Z). The merge brought PR #20626 and PR #20587 and touched none of this diff's files. The dependency closure was built first (pnpm --filter '@objectstack/rest...' build, 26 packages), then the whole workspace (turbo run build --filter='./packages/*' --filter='./packages/*/*', 71 tasks, 71 successful).vitest run --project local: 227 files, 4,382 tests passed, 50 skipped.--project repo(which holds the touchedmeta-state-route-doc-spelling.test.ts): 1 file, 8 tests passed. Together they are all 228 test files of the package, so every touched test file ran.pnpm --filter @objectstack/rest typecheckexits 0.tsc --listFilescounts 28srcfiles (no tests) undertsconfig.jsonand all 228 test files undertsconfig.test.json, whichcheck:test-typecheckjudges: 0 files, 0 errors, 0 pinned signatures in the ledger.pnpm lint(eslint . --no-inline-config) exits 0 at93e4d69ba6(2026-09-29T11:19:30Z to 11:20:00Z). Not narrowed.node scripts/check-issue-citations.mjs --base origin/mainexits 0: 19 citations judged across 14 files (18 resolve, 1 resolves as a pull request). These are the live numbers that stay on rewritten lines. 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 --commandsat93e4d69ba6derived 68 families. All 68 exit 0, and--ranover a record carrying each exit code reads 「68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN」 (a derived zero).check:dual-build-cjs-loadsandcheck:type-check-debtfirst exited 3 (PREREQUISITE NOT MET, nothing measured) on the closure-only build; after the whole-workspace build both exited 0.check:doc-authoring,check:nul-bytes,check:rest-log-declared,check:route-envelope,check:system-context-census(106 elevation read sites, the page's 102 symbols held) andcheck:issue-citations(self-test).93e4d69ba6,check-changeset-fixed(the one whose roster sits under.changeset/) andcheck:route-ledger-censusamong them. The other three,check-closing-target-claim,check-partof-closing-keywordandcheck-single-claim-paths, answer 「NOT WIRED」 (exit 2) without a pull request's context; they are run against this PR once it exists and reported on the card.Hypotheses (measured first)
a186aea996(186 lines, 14 files, 51 numbers), equal to the card's count atf11b5f20a2: no net drift, although PR fix(rest)!: /import reads a date, datetime or time cell only in ISO 8601, the export shape or a year-first date, on a real day, with a four-digit year (#20534) #20601 (merged aseb4b17c346, before this base) touches four files inpackages/rest.packages/rest.distis not byte-identical, because the docblocks ship, which is why the changeset ispatch.Acceptance notes
noteof the REST route ledger's legal-next-state row (rest-route-ledger.ts:290, 「([finding] The legacy dispatcher/metabranch still matches the pluralobjectsliteral after step ② retires the REST registration #10179)」), which is ledger data, not an author-shown refusal. Ruling D (no number, the lesson in words) is a string change outside this comment-only scope; the card already carries a form-D stage for the lane.mappingNameand hardcodeswriteMode:"insert", so a named mapping'supsertcan never reach a user objectui#10102 on its web endpoint. The census classes itallocated-but-absent(deleted and transferred are only told apart under--probe-cause), andscripts/check-issue-citations.mjs's header says thetransferredarm has no positive specimen on this tree; this is one. Noted, not filed.CITATION_RErefuses a#preceded by/, so the second number of#A/#Bis never judged. Inpackages/rest/srcsix such dead numbers stood at 10 comment sites, all rewritten here; one more,#14389in#14095/#14389, stands inside a string (error-response-structured-arm-door-parity.test.ts:187) and is kept. 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(lint): re-anchor the dead tracker citations in packages/lint/src to the commits that decided them #20612 reported. Noted, not filed.packages/rest/vitest.config.ts:21cites [finding] vitest 的 --project 过滤器落空即静默成功 —— 点名一个 integration 文件跑 --project unit,报它是通过的文件、执行零个用例,并把它从文件计数里减掉 #17853, which answers 404;packages/rest/test-typecheck-debt.json, written bygen:test-typecheck-debt, carries [finding] The test-typecheck EXACT ratchet is a per-file COUNT, so it stays green through a wholesale substitution of error identity — measured by ablation, not argued #13470, The 2 remaining ledgered TS2345 in packages/rest are hand-builtIHttpResponseliterals — they were masked by the request literals, not absent #13454, A typed IHttpRequest test builder — 4 ledgered TS2345 in packages/rest are hand-built request literals, and the only in-repo alternative isas any#13377 and exceljs 4.4.0 ships its own module-localBufferinterface, so no Node Buffer can be passed toWorkbook.xlsx.load— 6 sites pay it withas any, the 7th is a ledgered error #13378 in its prose, all 404. Neither is undersrc/**. The other numbers invitest.config.ts,tsconfig.jsonandtsconfig.test.jsonanswer 200.rest-server.ts'sapidocblock near:1115and the 「zero read sites」 sentence at:4092both overtaken by80153f5a4, whose own acceptance notes record it. This PR re-anchors their citations and leaves their claims alone.rest-server.ts:4092credited its zero-read-site count to 「the [finding] Ten declaredRestServerConfigkeys are normalized byRestServerand read by nothing —routes.*entirely,crud.patterns/objectParamStyle,metadata.cacheTtl/endpoints.schema,batch.defaultAtomic/operations.upsertMany(ADR-0049 enforce-or-remove candidates) #14369 census」, which (a3d5724c8) excludedapi; it now cites53cbad9f7, the commit that measured it.origin/main(93e4d69ba6) before the--base origin/mainrun, as the dispatch orders.Deviations
--concurrency=4, not 2, to stay inside the ten-minute foreground cap on this host; it took 1m42s.Claude-SessionplusCo-authored-by: Claude), and the pre-push trailer check passed on every push. The merge commit carries git's default message.Generated by Claude Code