Skip to content

docs(plugin-hono-server): re-anchor the dead tracker citations in packages/plugins/plugin-hono-server/src to the commits that decided them - #20741

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-20594-hono-server-citations
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-20594-hono-server-citations

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #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 #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 #20533 is the method, and stages 1 to 9 of this card (PR #20624, PR #20632, PR #20656, PR #20673, PR #20689, PR #20703, PR #20713, PR #20723, PR #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 (#16599 x2, #9864, #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 #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 #20703, PR #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 #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 #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
#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 #17412) and the fourth to 5f7fa1de0; both wrote them citing this ruling. PR #13475 (200) names #13279. Stages 1, 2, 4 and 9 gave the number this anchor.
#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 #9992) answers 404 too. Stages 1, 2, 4 and 6 gave the number this anchor.
#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 #7396), which says it follows that direction. Stages 2 and 8 gave the number this anchor.
#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.
#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: #16599, #9864, #16334, #16363, #16049, #6878, #3867, #8086, #16545, #15999, #5090. packages/plugins/plugin-hono-server/src has no slash-joined #A/#B without spaces; the spaced pairs (#3867 / #8086, #2408 / #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 #9934 1 and commit 79c46da90 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 (#9934) at base and refusal text (commit 79c46da90) 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 #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):

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 chore: version packages #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: #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 (#11332) and :26 (#10724), tsconfig.test.json:3 and :61 (#13176), tsconfig.typecheck.json:12 (#11332 and #10724; #4914 in the same group answers 200). The other citations in the package outside src/** (CHANGELOG.md excluded) answer 200: tsconfig.test.json (#14062, #5286, #5449, #12542), tsconfig.typecheck.json (#13284, #5475, #10756), vitest.config.ts (#10374, #9457, #7378; #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

hotlong and others added 3 commits September 30, 2026 07:54
…kages/plugins/plugin-hono-server/src to the commits that decided them

Ruling C+D, form C: every comment site in packages/plugins/plugin-hono-server/src
that cited a tracker number now answering 404 cites the commit in main's history
that decided what the line describes, and says in its own words what was
decided. 24 comment lines in 5 files (the census's 5 in adapter.ts and
current-user-endpoints.ts, plus 19 in three test files), line for line, so every
file keeps its line count and no code token, string literal or identifier moves.

Anchors: 6a180e4 (a permission-store read that throws fails loud, and an
unreadable authz store licenses no verdict), 79c46da (the producer-side
userMessage refusal channel), 2934761 (refuse a repeated query value rather
than pick one: readSingleQueryValue), f586f1a (one ExecutionContext assembler,
two named anonymous entries, the fail-closed one the default) and 51ae731
(LiteKernel.use() runs the same plugin contract as ObjectKernel, the kernels
converge).

Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289
Co-authored-by: Claude <noreply@anthropic.com>
The rewritten comment at adapter.ts's declared-envelope return survives the
bundler: dist/index.js and dist/index.mjs differ between base and head in that
one comment line each (parser tokens identical), so the package's published
bytes move and a patch changeset is owed.

Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 7 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json fbec216e2d184afc03b456b0bd8013ad5d47bc6f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8ab123c0ed42b3678cc2c88bb80fef381674019d — the merge of head 03e5f4c0fd6f8bb63ce037d6d39141240bdccf51 into base fbec216e2d184afc03b456b0bd8013ad5d47bc6f, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8ab123c0ed42b3678cc2c88bb80fef381674019d && git checkout 8ab123c0ed42b3678cc2c88bb80fef381674019d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin fbec216e2d184afc03b456b0bd8013ad5d47bc6f 03e5f4c0fd6f8bb63ce037d6d39141240bdccf51 && git checkout -B drift-repro fbec216e2d184afc03b456b0bd8013ad5d47bc6f && git merge --no-ff 03e5f4c0fd6f8bb63ce037d6d39141240bdccf51

node scripts/docs-audit/affected-docs.mjs --json fbec216e2d184afc03b456b0bd8013ad5d47bc6f

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests tooling labels Sep 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 03e5f4c0fd6f8bb63ce037d6d39141240bdccf51
Local-runs: none

① Derived judgments

Inputs read. Card #20594's body and all 39 comments (the stage-1 to stage-10 claims, os-dev-reports, ACCEPT and Landed records; the stage-5 ruling 5895600995 that a changeset follows from a dist measurement; the domain:services pointer 5888293145 and its answer 5890033713). PR #20741's body; its file list (pulls/20741/files?per_page=100: page 1 holds 6 entries, page 2 is empty); its full diff (Accept: application/vnd.github.diff, 222 lines, 6 diff --git blocks; compare/main...03e5f4c0fd reads the same 6 files at merge base fbec216e2d). The check-runs on the head.

Sampled. The whole population: all 24 rewritten sites in all 5 code files (adapter.ts 4; current-user-endpoints.ts 1; current-user-endpoints-localization.test.ts 1; handler-throw-declared-envelope.test.ts 2; ui-plugin-auto-discovery.pin.test.ts 16), each read against its anchor's message and patch via commits/SHA. The brief's floor of 12 sites in 6 files exceeds the population's file count: the sixth file is the changeset, which carries no site. Every hunk of the diff was read, adapter.ts's four hunks in full.

(1) Comment-only: RIGHT. An awk pass over the diff (changeset excluded) finds 24 removed and 24 added lines and 0 changed lines whose first non-blank characters are not * or //. No code token, string literal, error message, identifier or test assertion moved. adapter.ts's four pairs are docblock lines :225 and :227, the // line :308 inside declaredEnvelopeForThrow's returned object literal (the code beside it — code, message, the details and userMessage spreads — is unchanged context, read on the head blob), and docblock line :349. The describe('UI plugin auto-discovery (#16050)' titles in the pin file's hunk headers are context, not changes. Every hunk header has equal old and new spans.

(2) Anchors: RIGHT, none wrong or unsupported. All 5 shas exist (commits/SHA answers each with one parent) and all 5 read ahead, behind_by 0 against main (ahead_by 3307 / 4838 / 6228 / 6053 / 1914).

No ADR or ruling record holds these decisions: a grep for the 5 numbers in docs/adr and scripts/adr-anchors of the worktree (at f11b5f20a2) reads 0, control #7329 reads 2. Commit anchors are the right form C.

(3) Numbers: RIGHT. Multiset over removed lines: #13279 x4, #9934 x2, #6307 x1, #6216 x1, #16721 x16 (the 24 dropped) plus #16599 x2, #9864 x1, #16334 x1; over added lines: #16599 x2, #9864 x1, #16334 x1. The kept numbers stand on the same lines they stood on, and no number is added. REST probe at my read: the 5 dropped answer 404; #16599, #9864, #16334 and the context-line #6878, #16363, #16049, #16050 answer 200 (#16363 is a pull request, kept as it stood). No 200 number was removed or rewritten. Shas on added lines: 6a180e4 x4, 79c46da x2, 2934761 x1, f586f1a x1, 51ae731 x16 (one sentence-initial "Commit" at :608); shas on removed lines: none.

(4) Line counts: RIGHT. Additions equal deletions in every modified file (4/4, 1/1, 1/1, 2/2, 16/16), every hunk's old and new spans are equal, and the head blobs read 1,660 / 335 / 1,020 / 403 / 697 lines, the dev's figures. The changeset is a new 11-line file.

(5) Judged in ②.

(6) Part of #20594: RIGHT. The card stays open for create-objectstack 3, plugin-dev 3, observability 1, verify 1, the form-D string stage and each package's files outside src/** (landing record 5900344766, claim 5901153104). The body's first line is Part of #20594 with no closing keyword; Part-of PR must not also close its card is success. Nothing left behind: I fetched all 33 src/*.ts blobs of the package at the head tree (truncated: false), extracted every #NNN token (304 tokens, 82 distinct numbers) and probed each by REST: 80 answer 200, 2 answer 404 — #16721 in the group-F describe title string at ui-plugin-auto-discovery.pin.test.ts:635 (a string literal, the form-D stage, as the dev declares) and #123456 at :111, a CSS hex colour in a fixture, not a citation. Zero comment sites remain. The brief's "52 to 0" is not this stage's figure: the dev reports the census 5 to 0 (24 sites including 19 test-comment sites), and both readings hold on the head.

Merge head. 03e5f4c0fd merges fbec216e2d (26 files, none under packages/plugins/plugin-hono-server/), so the package at the head is the package at 91ce7e5e8f, where the dev's census and dist readings were taken.

Accept-set and public-surface changes implied by the diff: none. No runtime symbol, route, error code, envelope key, type or export moves; nothing in a // or * line can reach a declaration file.

Check-runs on the head at my read (2026-09-30T00:41:30Z): 34 runs, newest per name — 31 completed/success, 3 completed/skipped (Build Docs, Console Pin Gate, Packed-tarball smoke (opt-in): the expected skips), 0 in progress, 0 failed. Check Changeset, Lint & Repo Gates, the four Type Check runs, Test Core 1–6, Dogfood Regression Gate 1–3, Temporal Conformance and the four PR-shape guards are all success.

② Semver level

patch for @objectstack/plugin-hono-server: RIGHT. The package publishes (no private; files = dist, README.md, CHANGELOG.md; the build is the shared tsup.config.ts, esm and cjs, unminified). The dev's measurement — base and head builds with the same dependency builds; dist/index.js and dist/index.mjs differing in exactly the adapter.ts:308 comment line; index.d.ts, index.d.mts and both maps equal; parser tokens of the two differing files identical; and a code-mutation control (ablation-replace.mjs) that flips index.js, index.mjs and both maps — supports carrying a changeset under the lane's own rule (ACCEPT 5895600995: the changeset follows from the dist measurement; stages 6 and 9, PR #20703 and PR #20735, shipped patch on a comment-text-only dist delta, while stages 5 and 7 took skip-changeset on byte-identical dist). The one comment that ships is a // line inside a returned object literal, a position unminified esbuild output keeps while docblocks do not reach the bundle, so the measurement's shape is the expected one. A tarball whose bytes differ is a publish, and patch is its floor. The changeset prose ("Comments only: no route, error code, refusal text, type, export or runtime behaviour changes") is accurate to the diff, and Check Changeset is success.

Clause-②: Clause-②: no on the body's second line is RIGHT. No accept-set narrows or widens, no public surface moves, no metadata surface is touched, so no ADR-0087 disposition is owed.

③ Boundary flags

  • open_questions: empty in the dev's report (5901683329). Nothing to answer.
  • Dev deviations, each judged: three derived gates first NOT MEASURED before the whole-workspace build, then exit 0 — sequencing, and CI's Build Core and Type Check · debt ledger answer the same families green; the void first check:generated run under the pnpm v11 front end, rerun green — host noise, and CI answers; the os-verify-lock UNLOCKED disclosure copied into the body — declared as required; 18 self-test-only roster rows not run — they grade fixtures, not this diff; model-free trailers per AGENTS.md — the seat's concern, not a contract one. None changes the verdict.
  • Out-of-scope findings, both rightly left on the card: the #16721 describe-title string at :635 (form-D stage), and the five 404 sites outside src/** (objectstack.config.ts:19, :26; tsconfig.test.json:3, :61; tsconfig.typecheck.json:12), which the census does not sweep and no stage claims.
  • The dev's Acceptance notes: hono-plugin.ts:521/:523's unreachable defensive conjunct is now recorded only in the pin file's text — noted, not a defect of this change; the "before this card" / "the card" residue at handler-throw-declared-envelope.test.ts:19, :32, :85 cites no number and is left as the landed stages left theirs — right.
  • No escalation.

Implemented-by: claude/issue-20594-hono-server-citations
Reviewed-by: local_1d2a197c-c20e-4e90-9be8-413d4d432289

VERDICT: PASS

@github-actions

Copy link
Copy Markdown
Contributor

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

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

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

  • Console Pin Gate — 失败步骤: Build the Console SPA at the pinned objectui SHA

    ✗ Neither spec appears in the built console — no @objectstack/spec
    

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

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

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

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

历史信号:

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

分诊清单:

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

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

Merged via the queue into main with commit 01e78dc Sep 30, 2026
36 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20594-hono-server-citations branch September 30, 2026 01:07
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…mmits that decided them (objectstack-ai#20742)

Part of objectstack-ai#20596
Clause-②: no

## What changed

This is the tenth stage of the `domain:services` lane of the
dead-citation sweep. It covers
`packages/services/service-package/src/**` and nothing else. By the
seat's census at the claim (`5901757839`), it is the largest package in
the lane that no in-flight work holds. Later stages cover the other
packages, so this PR says `Part of` and the card stays open.

Every comment or docblock site in scope that cited a tracker number
answering 404 has been rewritten in ruling C+D's form C (comment
5749154545 on objectstack-ai#19123), by the method of stages 1 to 9 (PR objectstack-ai#20609 as
`422db788a`, PR objectstack-ai#20626 as `b80ab579d`, PR objectstack-ai#20634 as `4d04b6be3`, PR
objectstack-ai#20658 as `9a4b2bb38`, PR objectstack-ai#20693 as `0e9ad74fb`, PR objectstack-ai#20708 as
`9b384f63a`, PR objectstack-ai#20717 as `cbaf04c1f`, PR objectstack-ai#20729 as `d2820876f`, PR
objectstack-ai#20737 as `4dfff176b`). That is **18 sites on 17 lines in 5 files,
covering 5 numbers**:

- 13 census sites (every census site this package has);
- 5 sites in test comments, which the census defers;
- no site the gate's grammar cannot see (the package has none, see
Acceptance notes).

Each rewritten line now cites the commit in `origin/main` history that
decided what the line describes, and says in its own words what was
decided: **4 distinct shas**. No number in this package has an ADR or
ruling record of its own in the repository (a grep of `docs/adr/` and
`scripts/adr-anchors/` for all 5 finds none, and nothing else under
`docs/` names them), so every anchor is a commit, per ruling C's order.
No number was dropped.

Only comments changed. Every touched source file keeps its line count
(17 lines out, 17 in, over 5 files), so no line citation into these
files moves. Every one of the 17 changed lines carried a dead citation;
there is no reflow line. No code token moves (see the guard below).

**No citation number is added.** The one tracker number on an added
line, `objectstack-ai#10677`, was already on the line it replaces (`index.ts:234`) and
resolves. Over the whole diff, added minus removed is 0 for `objectstack-ai#10677` and
negative for the five dead numbers, and no number is new to the diff. No
PR number is the citation on an added line: the three `PR #N` spellings
in scope became their pull request's squash commit.

4 dead sites are left on purpose, all of them `describe` titles (see the
list below).

One more file: a `patch` changeset for `@objectstack/service-package`,
because one rewritten docblock ships (see Changeset below).

## Census: `service-package`, before and after

**Instrument (A1).** The gate's own `node
scripts/check-issue-citations.mjs --census --json`, read-only and
unchanged. The count below is its `allocated-but-absent` findings under
`packages/services/service-package/`. Each run counts as a reading only
because its board frontier equals the newest issue number, read by a
separate request just before and just after the run.

| reading | tree | board | whole-repo `allocated-but-absent` |
service-package sites | lines | files | numbers |
|---|---|---|---|---|---|---|---|
| before | base `4dfff176b`, run 2026-09-30T00:41:15Z to 00:44:24Z |
enumerated, 186 pages, frontier objectstack-ai#20741 (newest objectstack-ai#20741 before and after),
18,568 numbers | 1,082 | **13** | 12 | 1 | 4 |
| after | head `34ba921e6`, run 00:49:33Z to 00:52:49Z | enumerated, 186
pages, frontier objectstack-ai#20741 (newest objectstack-ai#20741 before and after), 18,568 numbers
| 1,069 | **0** | 0 | 0 | 0 |

The before count matches the seat's census and A1 (13 sites). The
whole-repo drop is 13, exactly this diff's census sites. The `resolves`
tally is 33,003 in both runs, and `resolves-as-pull-request` (1,984) and
`cross-repo-unjudged` (995) did not move either. The after run was taken
on `34ba921e6`; the head `ffd2f1ed2` adds only the changeset. No run was
truncated or discarded: both enumerations read 186 pages at the newest
frontier.

**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 `namesThisRepository`
over every `.ts` file under `service-package/src` (6 files). It takes
its verdicts from the before census's own board reading rather than from
a second enumeration: a number is dead when that census reported it
`allocated-but-absent`, and alive when that census judged it on this
board anywhere (its `--list` extraction, 37,065 rows) and did not report
it. The one number the census never saw, because it stands only in test
files here, was read on its own: `objectstack-ai#16650` answers 404 on the issues
endpoint and on the pulls endpoint.

| reading | citations | dead | src comment | test comment | src string |
test string |
|---|---|---|---|---|---|---|
| before, `4dfff176b` | 82 | **22** | 13 | 5 | 0 | 4 |
| after, `34ba921e6` | 64 | **4** | 0 | 0 | 0 | 4 |

Its src-comment column equals the census's 13, which is the control on
the second instrument. The 60 live citations are the same in both
readings (no cross-repo citation stands in this package), and the drop
of 18 citations is exactly the rewritten sites. A third, raw reading
(every `#` followed by 2 to 6 digits, whatever surrounds it) finds 82
occurrences and 22 dead before, 64 and 4 after: the same as the gate's
grammar, so nothing here sits beyond it, and it has no unjudged token.

## Per-number table

Sites and files count every dead occurrence in scope at the base
(comments and strings, tests included). `rewritten / left` counts the
sites rewritten and the sites left. Each anchor was read in its message
and diff, not only its subject, and `git blame` at the base puts every
rewritten line in its anchor commit or in a later commit that descends
from it (`merge-base --is-ancestor` exit 0 for all 17 line and anchor
pairs).

| number | sites / files | rewritten / left | anchor: what it decided |
|---|---|---|---|
| `objectstack-ai#10965` | 17/3 | 13/4 | `ab47f6974` (PR objectstack-ai#11064): `get()` and `list()`
refuse a storage seam that accepted the query and returned no result
set, with a declared ADR-0112 envelope (`SERVICE_UNAVAILABLE` / 503),
and the skipped boot rehydration is logged at warn; a seam that answers
with zero rows is unchanged. Its body says `Part of objectstack-ai#10965` three times,
and it is the only commit that wrote the seam guard (`git log -S
packageSeamUnreadableError`). The `runtime` stage's anchor for the same
number |
| `objectstack-ai#10788` | 1/1 | 1/0 | `3a7ec2d3b`: `os migrate duplicates` holds a
raw-SQL seam that cannot answer to be absent, not empty. The squash
commit of the pull request that was `objectstack-ai#10788` (404 on the pulls endpoint
too); `objectstack-ai#10677`, the card it answers, stays beside it. New to the sweep |
| `objectstack-ai#10789` | 1/1 | 1/0 | `38bc74ed1`: `backfillSeedTenancy`'s read
probes hold a seam that cannot answer to be absent, not empty. Its
subject names `objectstack-ai#10789`. The `runtime` stage's anchor for the same number
|
| `objectstack-ai#10964` | 1/1 | 1/0 | `38bc74ed1`: the same commit, the squash commit
of the pull request that was `objectstack-ai#10964` (404 on the pulls endpoint too),
so the pair `objectstack-ai#10789 / PR objectstack-ai#10964` became one sha |
| `objectstack-ai#16650` | 2/2 | 2/0 | `001a83b04`: `SqlDriver.execute()` declares a
backend refusal as `DATABASE_ERROR` / 500. The squash commit of the pull
request that was `objectstack-ai#16650`; its review round (「pin the package-door code
flip」) wrote the two `[objectstack-ai#16019]` blocks whose closing sentence these
lines are. The `rest` stage's anchor for the same sentence in
`package-door-16019-raw-statement-fault-code.test.ts` |

Every cited sha matches exactly one commit (`git rev-parse
--disambiguate`, count 1 for each of the 4), and every one is an
ancestor of the base (`merge-base --is-ancestor`, exit 0 for all 4;
control leg: stage 1's landing `422db788a` exit 0; the history is
complete, `--is-shallow-repository` false, 15,149 commits). Each of the
5 numbers answers 404 on the issues endpoint and on the pulls endpoint.

## Wordings to check

- **Bracket tags.** `[objectstack-ai#10965]` became `[commit ab47f69]` on 9 lines of
`index.ts` (`:208`, `:286`, `:304`, `:327`, `:451`, `:476`, `:502`,
`:517`, `:626`).
- **`index.ts:223`**, a section heading: 「(objectstack-ai#10965)」 became 「(commit
ab47f69)」, and its trailing rule was shortened from 11 characters to 2
so the line stays near its old width.
- **`index.ts:234-235`**, the two siblings of the seam guard: 「(objectstack-ai#10677 /
PR objectstack-ai#10788 for / `os migrate duplicates`, objectstack-ai#10789 / PR objectstack-ai#10964 for
`backfillSeedTenancy`)」 became 「(objectstack-ai#10677 / commit 3a7ec2d for / `os
migrate duplicates`, commit 38bc74e for `backfillSeedTenancy`)」. The
live `objectstack-ai#10677` stays beside its fix; the dead issue and its dead pull
request became their one squash commit.
- **`mysql2-tuple.test.ts:26` and `:196`.** 「objectstack-ai#10965's guard」 and
「(objectstack-ai#10965's leg」 became 「commit ab47f69's guard」 and 「(commit
ab47f69's leg」.
- **`null-seam.test.ts:4`**, the file's title line: 「objectstack-ai#10965 — `get()` /
`list()` answered over a driver they never queried.」 became 「The card
behind commit ab47f69 — …」, so line 8's 「The card established the
conflation by READING」 keeps its referent.
- **`delete-driver-fault.test.ts:319` and
`publish-driver-fault.test.ts:357`.** 「The reviewer of PR objectstack-ai#16650
required the flip」 became 「The reviewer of commit 001a83b required the
flip」, the `rest` stage's form for the same sentence.

## The 4 sites left

- **Test strings, 4 sites**, all `objectstack-ai#10965`, all `describe` titles in
`null-seam.test.ts` (`:140`, `:184`, `:229`, `:284`), left as stages 1
to 9 left theirs.
- No source string, operator log string, assertion message, quoted
maintainer ruling or generated file in this package carries a dead
number.

## Mechanical guard: no code token moves

The guard compares the TypeScript parser's leaf nodes (a `forEachChild`
walk, so comments are trivia and JSDoc nodes are never visited), base
`4dfff176b` against head. String and template literals are therefore
read in full. It ran over all 5 touched `.ts` files.

- Real run: 3,323 base leaf tokens, **0 files with a token change**
(exit 0).
- Comment control in `index.ts` (「Is this the seam refusal above?」 to 「…
named above?」): 0 files changed, as expected (exit 0).
- Positive control, a code token added in `index.ts`
(`isResultSet(result)` given `as any` in `get()`): DIFFER (exit 1).
- Positive control, one digit changed inside a kept test title
(`null-seam.test.ts:140`, `objectstack-ai#10965` to `objectstack-ai#10966`): DIFFER (exit 1).

Every mutation went through `scripts/ablation-replace.mjs`, and each
landed (anchor 1 to 0, blob changed). Each restore was proven
byte-identical to the HEAD blob (`2555410dd0a7`, `0c5bf5e7e190`), with
`git diff HEAD` empty and a clean tree afterwards.

## Changeset

This change ships bytes, so a `patch` changeset for
`@objectstack/service-package`
(`.changeset/20596-service-package-provenance-anchors.md`) is included.
Its body is stage 9's, word for word, with the package name changed.

Measured on the built package (A3): `files[]` is `dist`, `README.md` and
`CHANGELOG.md`. After the build, `ab47f6974` appears once in each of
`dist/index.d.ts` and `dist/index.d.cts`: the rewritten docblock sits on
the exported `PACKAGE_SEAM_UNREADABLE_MESSAGE`. The other rewritten
comments do not reach `dist` (0 for `3a7ec2d3b`, `38bc74ed1` and
`001a83b04`, and 0 for `ab47f6974` in `index.js` and `index.cjs`).
Positive control: the unchanged line 「Like {@link
PACKAGE_PUBLISH_DRIVER_FAULT_MESSAGE}, a CONSTANT that」, in the same
docblock, is found once in each declaration file. A never-written
negative phrase appears nowhere in `dist`. None of the 5 dead numbers is
left in `dist`.

## Gates (head `ffd2f1ed2`)

- **Citation judging, as CI runs it:** `pnpm check:issue-citations`
(self-test, 114 cases, 8 batteries) exits 0. `node
scripts/check-issue-citations.mjs` exits 0: the diff-scoped run judged 1
citation in 1 file and found it on the board: `objectstack-ai#10677`, which already
stood on its line.
- **Doc authoring:** `pnpm check:doc-authoring` exits 0; the
sibling-package prose-id baseline holds (808 pinned sites, no growth).
- **Derived gates:** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` at `ffd2f1ed2` derived 62 commands:
all 56 derived at dispatch, plus `check:engine-double-contract`,
`check:objectql-double-limit`, `check:query-options-erasure`,
`check:type-check-coverage`, `check:type-check-debt` and
`check:where-matcher`. Each ran with its exit code captured before any
pipe, and all 62 exit 0. `--ran`, fed each command with its exit code,
reports 62 run, 0 NOT MEASURED (a derived zero), 0 unrun, and exits 0. A
full `turbo run build` of `./packages/*` and `./packages/*/*` ran first
under the shared verify lock (71 of 71 tasks, exit 0), so no gate hit an
unbuilt workspace.
- **Roster families the derivation lists outside its commands** (their
rosters sit in directories this diff touches): `node
scripts/check-changeset-fixed.mjs`, `pnpm check:authz-resolver`, `pnpm
check:error-code-casing` and `pnpm check:filter-alias-parity`, each exit
0.
- **Tests and typecheck, under the verify lock:**
- `pnpm --filter @objectstack/service-package test`: 5 files pass and 79
tests pass. `vitest list --filesOnly` names 5 files, all the tracked
test files, the 4 touched ones included.
- `pnpm --filter @objectstack/service-package typecheck` exits 0. `tsc
--listFiles` holds all 6 files under `src/`, all 5 touched files
included.
- **Lint, as a proven narrowing:** `eslint --no-inline-config --format
json` over the 5 touched `.ts` files gives 5 files, 0 errors and 0
warnings. All 5 are in eslint's own population (`isPathIgnored` is false
for each; a `dist` file, as the control, is ignored).
`eslint.config.mjs` never enables type-aware linting (no
`parserOptions.project`, as its own lines 327-328 state), so a comment
edit here cannot move the verdict on any untouched file. The repo-wide
`pnpm lint` is CI's run.
- **Control bytes:** `pnpm check:nul-bytes` exits 0, and a raw scan of
the 6 changed files for control bytes finds none.

## Acceptance notes

- **The gate-invisible spellings, grepped as the claim asked.**
`CITATION_RE` refuses a hyphen after the digits and a `/` before the `#`
(objectstack-ai#20636), and `NON_CITATION_HEADS` excuses a number after the word
「option」. In this package: `#N-word` none, `#A/#B` none, `option #N`
none, at the base and at the head. The raw scan agrees: nothing sits
beyond the gate's grammar here.
- **「This card」 phrases are left.** 14 comment lines in 5 files of this
package speak of 「this card」, 「the card」 or 「The card」. They carry no
number and neither instrument sees them. One title line was worded so
that its neighbour keeps a referent (`null-seam.test.ts:4`, above); the
rest are unchanged, as in stages 8 and 9.
- **The census instrument did not truncate in this stage.** Both
enumerations read 186 pages at the newest frontier.
- **Anchors the next stages can reuse**, each checked here: `objectstack-ai#10788` →
`3a7ec2d3b`; `objectstack-ai#10964` → `38bc74ed1`. The other three reuse sibling
stages' anchors: `objectstack-ai#10965` → `ab47f6974` and `objectstack-ai#10789` → `38bc74ed1` (the
`runtime` stage), `objectstack-ai#16650` → `001a83b04` (the `rest` stage).
- **Base.** The branch is on `main` at `4dfff176b`. `main` has since
moved four commits (`03cdb9a5c`, `b785c3b11`, `5a23096ca`, `01e78dcee`).
Their 40 files touch nothing under `service-package`, nor
`scripts/check-issue-citations.mjs` or `.changeset/config.json`; the
`doc-authoring-prose-id` baseline they shrink has no `service-package`
row. So no merge was taken; the merge queue rebuilds on the merged
generation.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…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>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant