Skip to content

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

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20594-plugin-dev-citations
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20594-plugin-dev-citations

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #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 #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 11 of this card (PR #20624, PR #20632, PR #20656, PR #20673, PR #20689, PR #20703, PR #20713, PR #20723, PR #20735, PR #20741, PR #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 #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 #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 #20632's form), because the two rewritten docblock lines reach the published dist (measured below), as stage 6 (PR #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 #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 #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/ (#10035, #10036) and 1 outside it (#13176, in tsconfig.test.json); #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 (#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
#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 (#10092) answers 404 as well.
#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"; #10035 is that commit's own PR number, carried in its subject.

How the lines read now. :1063 keeps #3900 and says commit 7552e0337 moved this check here from init(); the :1078 heading and the test-comment brackets name commit 7552e0337 where the number stood, with the decision spelled out in the surrounding prose they already carried; :127 reads (the two told apart since commit 7552e0337); :1097 reads commit c1731d023 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. #10035, #10036 and #10092 answer 404 by REST (probed 2026-09-30T02:43:04Z and again at 03:14:40Z). #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):

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 (#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 chore: version packages #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 (#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 #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 docs(plugin-hono-server): re-anchor the dead tracker citations in packages/plugins/plugin-hono-server/src to the commits that decided them #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

hotlong and others added 2 commits September 30, 2026 10:55
…ugins/plugin-dev/src to the commits that decided them

Six comment lines in three files cited two tracker numbers that no longer
resolve. Each now cites the commit in this repository's history that
decided what the line describes (ruling C+D, form C):

- the security-enforcement warning asks the published `security` service,
  and asks it in start(): commit 7552e03 (dev-plugin.ts x2, and three
  test-file comments);
- plugin-hono-server's current-user endpoints key on the same published
  service instead of the init()-registered internals: commit c1731d0
  (dev-plugin.ts x1).

Comments only; every touched file keeps its line count.

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

The two rewritten docblock lines reach dist (index.js, index.mjs,
index.d.ts, index.d.mts), so the package ships different bytes and takes a
patch changeset, in the form the earlier stages of this sweep used.

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

This PR changes 1 package(s): @objectstack/plugin-dev, touching 1 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/kernel/services-checklist.mdx (via DevPlugin (symbol, a top-level class))
What this run could not see

Coarse fallback — 3 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 a51920f5fb1059ae6e8c7b1a96aa785f1da5d248 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8452a32c8a492e655d182c9e620969aa637efa1f — the merge of head a237b10ee73b097d836b08da5af92e1bae1872f1 into base a51920f5fb1059ae6e8c7b1a96aa785f1da5d248, 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 8452a32c8a492e655d182c9e620969aa637efa1f && git checkout 8452a32c8a492e655d182c9e620969aa637efa1f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a51920f5fb1059ae6e8c7b1a96aa785f1da5d248 a237b10ee73b097d836b08da5af92e1bae1872f1 && git checkout -B drift-repro a51920f5fb1059ae6e8c7b1a96aa785f1da5d248 && git merge --no-ff a237b10ee73b097d836b08da5af92e1bae1872f1

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

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs a51920f5fb1059ae6e8c7b1a96aa785f1da5d248 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a237b10ee73b097d836b08da5af92e1bae1872f1
Local-runs: none

Inputs read: card #20594 body and all 49 comments (the dev report 5903397162, the handover 5903477632 and the takeover claim 5903738364 included); PR #20767 body, file list and three-dot diff (the API diff is byte-equal to git diff 33e4a5609c..a237b10ee7; merge-base 33e4a5609c); the 34 check-runs on the head; ruling 5749154545 on #19123; and the two cited commits read in full with git show, with the REST commit and compare endpoints answering what a shallow clone cannot (ancestry). Nothing was built, run or re-run.

Seat correction on adoption: the reviewer wrote that main had moved by one commit since the merge-base. The seat's own reading is git log 33e4a5609c..origin/main = 6 commits (to c9c182ed), and git diff --name-only 33e4a5609c origin/main over packages/plugins/plugin-dev and this changeset path = 0 files. The verdict does not depend on the count: none of those commits touches these paths.

① Derived judgments

Diff: 4 files, +17/-6. Three files under packages/plugins/plugin-dev/src/, with 6 comment lines out and 6 in, and every touched file keeps its line count (1159 / 317 / 199 at base and head). One new file, .changeset/plugin-dev-provenance-anchors.md. No code token, string literal, export, type, assertion or message moves, so the accept set of @objectstack/plugin-dev does not move. The public-surface change is the two docblock lines of warnIfNothingIsEnforcingSecurity that reach dist (the .d.ts/.d.mts hover text and the .js/.mjs comment), plus the changeset sentence that becomes the published CHANGELOG entry. Not governed: no path is under the register, and Governed Surface Queue Guard is success.

Site by site, each judged against the cited commit's own message and diff:

  1. dev-plugin.ts:1063: (#10036, #3900) becomes (#3900; commit 7552e0337 moved this check here from init()). Right.
    • 7552e0337 deletes the init()-phase probe of security.permissions / security.rls / security.fieldMasker, and adds this.warnIfNothingIsEnforcingSecurity(ctx) beside the ready banner in start().
    • #3900 is kept, not added: it stood on the removed line and answers 200. No number is added anywhere in the diff.
  2. dev-plugin.ts:1078: the heading (#10036) becomes (commit 7552e0337). Right.
    • The docblock under it is that commit's own text, so the commit is the decision.
    • #10092, #10036 and #10035 answer 404 at review time.
  3. dev-plugin.ts:1097: fixed in #10035 by this same move becomes fixed in commit c1731d023 by this same move. Right. c1731d023 re-keys the degraded branches of /auth/me/permissions and /me/apps on the published security service.
  4. dev-plugin.test.ts:90: [#10036] becomes [commit 7552e0337]. Right.
  5. dev-plugin.test.ts:127: (#10036) becomes (the two told apart since commit 7552e0337). Right.
  6. dev-plugin-security-enforcement-warning.test.ts:53: [#10036] becomes [commit 7552e0337]. Right.

Anchor choice.

  • docs/adr/** and scripts/adr-anchors/** hold 0 hits for 10035, 10036, 10092, 7552e0337 and c1731d023 (control 7329: 1 file). So ruling C's order lands on the commit for both numbers.
  • Each commit is cited by sha alone.

Changeset ('@objectstack/plugin-dev': patch):

  • Accurate: comments only, and it says so.
  • It carries no tracker number, no PR number and no model identifier.
  • It matches what the diff publishes: the package is public and the rewritten docblock reaches the tarball.

Left in the package, and right to leave: #10036 in the describe title string at dev-plugin-security-enforcement-warning.test.ts:121 (a string literal, which is the card's form-D stage), and #13176 in tsconfig.test.json:3 and :56 (outside src/**).

Check-runs on the head:

  • 34 names, all completed: 31 success and 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke (opt-in)).
  • All seven required contexts are success.

② Semver level

  • patch for @objectstack/plugin-dev is right. The diff publishes changed bytes from a released package, while no accept set, export, type or behaviour moves.
  • Clause-②: no on the PR body is right.
  • The changeset is non-breaking, so no ADR-0087 marker is due.
  • PR shape: draft, base main, first line Part of #20594, and no closing keyword.

③ Boundary flags

  • The dev report 5903397162 has empty open_questions and premise_still_valid true.
  • Each of its eight deviations is answered, and none bears on the diff: the H2 dist branch is what the changeset stands on; the unlocked control builds and the superset closure spelling are local only; the self-refused first label-write wrote nothing; the skipped spec check:generated and self-test-only roster rows are covered by the head's TypeScript Type Check; the model-free trailers are right; the worktree cleanup came after the push.
  • Both out_of_scope_findings are carried by the card's own later stages, noted, not filed. That is right: neither is a reproducible defect, a contract violation or an authoring trap.
  • Nothing needs escalation.

Implemented-by: claude/issue-20594-plugin-dev-citations
Reviewed-by: session_01VvcEokUG1tvVxkceYfR5XB

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 04:07
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit f7c6d65 Sep 30, 2026
36 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20594-plugin-dev-citations branch September 30, 2026 04:44
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…es outside src to the commits that decided them (objectstack-ai#20883)

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

## What changed

This is stage 14 of the `domain:cli` lane's dead-citation sweep. It
covers the lane packages' tracked files outside `src/**`, the card's one
remaining stage (claim `5911994187`): `README.md`, `tsconfig*.json`,
`vitest.config.*`, `tsup.config.*` and each package's `test/**`.

The census at the stage's base `660a9b247e` counts **270 dead comment
sites** on that surface. That is over the claim's 40-site line, so this
stage takes the largest package, **`packages/cli`**. Every other package
is listed below with its count.

In `packages/cli`, every comment site on that surface that cited a
tracker number answering 404 now cites a commit instead. Following
ruling C+D's form C (comment `5749154545` on objectstack-ai#19123), it is the commit
in this repository's history that decided what the line describes.
Stages 1 to 13 of this card are the precedents; the latest are PR objectstack-ai#20767
and PR objectstack-ai#20842.

- **154 sites on 149 lines in 56 files**, covering **51 numbers**, now
cite **50 distinct commits**. The 56 files are `vitest.config.ts`,
`tsconfig.test.json` and 54 files under `test/**`: 50 test files,
`helpers/serve-process.ts` and 3 fixtures.
- **Comments only.** 150 lines out and 150 in, and every file keeps its
line count.
- One of the 150 is a companion line: `generate-skill.e2e.test.ts:35`,
"both pass" becomes "both passed".
- Its anchor, commit `3c418c498`, rewrote the two `@example` blocks the
sentence is about. A present tense beside that citation would contradict
it.
- **5 sites have no deciding commit** and are left as they were (see
"The sites left").
- **No tracker number is added.** The 12 numbers still on changed lines
were already on the removed lines, and all 12 answer 200: objectstack-ai#5286, objectstack-ai#5728,
objectstack-ai#10678, objectstack-ai#11391, objectstack-ai#11643, objectstack-ai#11772, objectstack-ai#12047, objectstack-ai#13158, objectstack-ai#14554, objectstack-ai#16483, objectstack-ai#16888
(kept as a convenience link beside its commit) and objectstack-ai#17978.
- **No ADR or ruling record carries any of these decisions.** A grep of
`docs/adr` and `scripts/adr-anchors` finds 0 hits for the 54 numbers and
0 for the 50 shas. The control `7329` finds 1 file in the same tree. So
every anchor is a commit.
- Where an earlier stage gave a number an anchor and the line here
describes the same decision, the same anchor is reused. That covers 33
of the 51 numbers (for `objectstack-ai#13504`, the tier half only), read by pairing
the landed stages' removed and added lines. The other 18 anchors are
new.

## Census, per package

**Instrument.** The card's gate does not read these files. Its declared
surface is `packages/**/src/**`, and `surfaceFor` answers null for all
56 touched paths; the control `packages/cli/src/commands/init.ts`
answers `package-docblocks`. So the census is taken by hand, with the
gate's own grammar:
- **Files:** every tracked file of the 19 lane packages outside
`src/**`, `CHANGELOG.md` excluded. That is 534 files.
- **Extraction:** `extractCitations` from
`scripts/check-issue-citations.mjs`, whole-file. Its comment-prose
projection decides comment versus string.
- **Numbers kept:** only those naming this repository.
- **Probe:** each distinct number is probed by REST, `GET
/repos/objectstack-ai/objectstack/issues/N`.

**Probes:**
- **Before**, at base `660a9b247e`, 2026-09-30T13:15:23Z to 13:16:12Z:
889 numbers. 794 answer 200 and 95 answer 404.
- **After**, at head `fda0702246`, 15:00:12Z to 15:01:16Z: 864 numbers.
794 answer 200, 69 answer 404, and one answered 502. That one was
objectstack-ai#11267; re-probed twice at 15:01:23Z, it answers 404.
- No number present in both probes changed its answer.
- Citation sites went from 3,634 to 3,480, a drop of exactly the 154
rewritten sites.

Dead sites per package. "Comment" is this stage's surface. "String"
means a string, a `describe`/`it` title or a message on the same file
list; those belong to objectstack-ai#20752 (form D) and are untouched. "Off-list"
means files outside the claim's file list; they are untouched and listed
below.

| package | comment, before → after | string (unchanged) | off-list
(unchanged) |
|---|---|---|---|
| `cli` | **159 → 5** | 42 | 41 |
| `qa/dogfood` | 94 → 94 | 28 | 0 |
| `plugin-hono-server` | 4 → 4 | 0 | 2 |
| `plugin-dev` | 2 → 2 | 0 | 0 |
| `client` | 2 → 2 | 0 | 1 |
| `qa/vitest-filter-preflight` | 2 → 2 | 0 | 1 |
| `cloud-connection` | 1 → 1 | 0 | 0 |
| `mcp` | 1 → 1 | 0 | 1 |
| `qa/downstream-contract` | 1 → 1 | 0 | 0 |
| `rest` | 1 → 1 | 0 | 7 |
| `runtime` | 1 → 1 | 0 | 1 |
| `types` | 1 → 1 | 0 | 0 |
| `verify` | 1 → 1 | 0 | 0 |
| `qa/http-conformance` | 0 → 0 | 0 | 1 |
| `observability`, `client-react`, `create-objectstack`,
`adapters/hono`, `qa/refd-timer-testkit` | 0 → 0 | 0 | 0 |
| **total** | **270 → 116** | 70 | 55 |

- **`tsconfig*.json` string values: none.** Every dead site in a
`tsconfig*.json` sits in a `//` comment, and these files are JSONC.
  - **Taken here:** cli's `tsconfig.test.json:1`.
- **Still dead:** `verify/tsconfig.test.json:1` (objectstack-ai#15145),
`plugin-dev/tsconfig.test.json:3` and `:56`, and
`plugin-hono-server/tsconfig.test.json:3` and `:61` (objectstack-ai#13176),
`plugin-hono-server/tsconfig.typecheck.json:12` (objectstack-ai#11332, objectstack-ai#10724), and
`client/tsconfig.json:8` (objectstack-ai#12181).
- **No `README.md`** in any lane package cites a dead number.

## Per-number anchors

`sites` counts the rewritten sites for each number. Each anchor was
checked by blame, and in its message or its diff. The "what it decided"
column is what the lines describe.

| number | sites | anchor | what it decided |
|---|---|---|---|
| `objectstack-ai#6217` | 4 | `2b641ddd4` | `--json` reserves stdout for the payload
across the `bootSchemaStack` family (its message closes the card) |
| `objectstack-ai#10152` | 1 | `ad492e7fd` | wrote the measured suite-cost section
this heading opens (a later commit's message pairs the card with this
PR) |
| `objectstack-ai#10323` | 1 | `5a616d558` | `create-objectstack` derives "Created
files" from the finished project |
| `objectstack-ai#10324` | 3 | `ecd06f613` | self-contained starter comments, and
creates `starter-comments-self-contained.test.ts` |
| `objectstack-ai#10326` | 1 | `675ab574e` | the two benign peer skews declared inside
the scaffold (stage 3's anchor) |
| `objectstack-ai#10359` | 4 | `15b63e85a` | retires `os g agent` (stage 3's anchor) |
| `objectstack-ai#10366` | 1 | `bbe643c08` | gates plugin-auth's localhost
trusted-origin substitution to non-production (the plugin-auth stage's
anchor) |
| `objectstack-ai#10498`, `objectstack-ai#10499` | 1, 4 | `6d441e41f` | its squash carries both: the
measured pnpm boundary, and the gate between the two scaffold paths |
| `objectstack-ai#10504` | 5 | `ff5733e03` | `UI: 0 Apps` instead of a dropped row;
records the triage ruling |
| `objectstack-ai#10557` | 2 | `818e02700` | init's "Created files" summary after
install, and the `create-objectstack` alias |
| `objectstack-ai#10763` | 1 | `c2b97c2a1` | `os package publish` prints the server's
reason (stage 3's anchor) |
| `objectstack-ai#10917` | 7 | `7940de5e0` | retires the `@capabilities` hook-body
directive |
| `objectstack-ai#10926` | 1 | `d173125fb` | the ruling commit stage 3 and the spec
stages used for this number |
| `objectstack-ai#10931` | 2 | `afe1c4e0a` | declares the four `@better-auth/utils`
peer skews |
| `objectstack-ai#10943` | 1 | `46d34ab7c` | `fallbackImport` becomes a
caller-supplied parameter |
| `objectstack-ai#10952` | 6 | `0d4bd93e7` | every summary section prints its zero
state |
| `objectstack-ai#10953` | 2 | `be7262e72` | the four structural advisories in `os
validate --json` |
| `objectstack-ai#11022` | 2 | `21756b325` | adds the fifth `MONOREPO_ONLY` pattern |
| `objectstack-ai#11025` | 3 | `1c3a46f87` | `os g skill` writes `NAME.skill.ts` |
| `objectstack-ai#11026` | 2 | `3c418c498` | rewrites `skill.zod.ts`'s two `@example`
blocks off `triggerPhrases`; its changeset names the number |
| `objectstack-ai#11071` | 7 | `50fb191dc` | derives every `os generate` filename from
the registry (its message closes the card, and measures the loader) |
| `objectstack-ai#11157` | 4 | `a4cb7817f` | `serve` hands the host importer its own
base |
| `objectstack-ai#11172` | 2 | `05181e8cc` | keeps the `Runtime:` row and stops
counting an unrendered metric |
| `objectstack-ai#11174` | 1 | `ab23c67ab` | `os validate --json --strict` exits 1 |
| `objectstack-ai#11267` | 19 | `1ddda1d00` | introduces `childEnv()`, the measurement
table and `serve-process-child-env.e2e.test.ts`; its message names the
card twice |
| `objectstack-ai#11268` | 4 | `918988ad3` | the PR itself; its squash changes
`turbo.json` to `@objectstack/cli#test` `dependsOn: ["build"]` |
| `objectstack-ai#11671` | 1 | `09b4f4e4e` | the source-hashes provenance companion
(every earlier stage's anchor) |
| `objectstack-ai#12125`, `objectstack-ai#12285` | 7, 1 | `79cf692b0` | carries `conversions` on
every failure exit. `objectstack-ai#12285` is this commit's own PR. Its message
withholds the fold question, which is what 3 of the lines say |
| `objectstack-ai#12297` | 3 | `9fd45a952` | `os lint` surfaces conversion notices
(stage 3's anchor) |
| `objectstack-ai#12964` | 4 | `e6fd1caf7` | names the missing build output; its
changeset names the number, and it holds both halves |
| `objectstack-ai#13109` | 2 | `8b236c826` | matches i18n-extract's walk to
`translatePage`'s |
| `objectstack-ai#13112` | 1 | `e7191ce71` | per-condition `types` targets in the
dual-build packages; its changeset names the number |
| `objectstack-ai#13193` | 1 | `faff497fd` | `os serve` writes the state file before
it announces the port |
| `objectstack-ai#13218` | 1 | `c45d8e6b4` | exports the addressed-component walk; its
changeset says "ruled 2026-08-30" |
| `objectstack-ai#13504` | 4 | `55519d503` | the measurement half: attributes the
`import` term per file (`vitest.config.ts:82`, `:261`, `:263`, `:359`) |
| `objectstack-ai#13504` | 5 | `44813ba57` | the tier half: the named `unit` /
`integration` split and the partition pin (`:496`, `:541`, `:677`,
`:831` and `vitest-tiers-partition.test.ts:5`; the qa stage's anchor) |
| `objectstack-ai#13651` | 1 | `ada3834ad` | the silent hook-body downgrade becomes a
lint verdict (stage 3's anchor) |
| `objectstack-ai#14336` | 2 | `79c71d29d` | object / view / action / app scaffolds
`os validate` accepts |
| `objectstack-ai#14710` | 2 | `95fdf627b` | wires the test layer into
`check:test-typecheck` |
| `objectstack-ai#14715` | 1 | `accb9231c` | the PR itself; keeps the exit-2 assertion
for the never-read reader |
| `objectstack-ai#14811` | 1 | `8ad872ba3` | sweeps every `os explain` catalog entry;
its diff adds this heading |
| `objectstack-ai#14817` | 2 | `5529a374e` | puts the three platform record pages
under an i18n gate; its message records the harm |
| `objectstack-ai#14824` | 6 | `cf6b67164` | `os create` emits a project that installs
outside the monorepo (stage 3's anchor) |
| `objectstack-ai#14858` | 5 | `0c5e97368` | a closed stderr read end exits 2 |
| `objectstack-ai#15150` | 5 | `cc986c913` | the sixth `MONOREPO_ONLY` pattern (the
create-objectstack stage's anchor) |
| `objectstack-ai#16330` | 2 | `4998efa71` | the blank template's CI workflow, with
`lint` (the create-objectstack stage's anchor) |
| `objectstack-ai#16350` | 2 | `68aee4c99` | `os init` writes a `lint` script; its
diff adds the pin that cites the number (PR objectstack-ai#16888 kept beside it) |
| `objectstack-ai#16721` | 1 | `51ae73123` | `LiteKernel.use()` enforces the plugin
contract (the plugin-hono-server stage's anchor) |
| `objectstack-ai#17080` | 1 | `8b4890343` | the per-release `spec-changes.json`
section (its message closes the card) |
| `objectstack-ai#17853` | 2 | `08f5f0e5a` | a vitest filter that selects nothing says
so (the qa stage's anchor) |

**Anchor checks:**
- **Each sha is unambiguous:** it matches exactly one object (`git
rev-parse --disambiguate`, count 1 for each of the 50).
- **Each is a plain commit** with one parent.
- **Each is on the base:** `merge-base --is-ancestor` against
`660a9b247e` exits 0 for all 50.
- **The history is complete:** the checkout is not shallow.
- **Control legs:** the parent of the oldest anchor, `8e13ca8764` (the
parent of `2b641ddd4`, 2026-08-08), exits 0. The negative control, the
base as an ancestor of `2b641ddd4`, exits 1.

**Wordings to check, each true of its commit:**
- **A defect named by its number now says so:** "The defect commit
79cf692 fixed — ...".
- **A card's words stay the card's.** Where a line quotes what a card
said or asked, it now says "commit X's card". That is
`vitest.config.ts:263`, `:359` and `:541`, and
`published-subpath-hook-body.pin.test.ts:28`.
- **The objectstack-ai#12125 fold question:** "the same question commit 79cf692 left
open", "commit 79cf692 explicitly withheld an answer". The commit's
message reads: "`warnings` and `conversions` are deliberately NOT
folded: whether they should become one field is a live question the
ruling did not address."
- **Ruling dates:** `platform-page-i18n-parity.test.ts:163` keeps its
ruling date as "(the 2026-08-30 ruling)".
- **Headings with a dash rule** keep their width by trimming the rule.
The exception is `commands.test.ts:181`, which keeps a 2-character rule
and grows by 6.

## The sites left

**No deciding commit (5 sites).** The claim says to list them, not
guess.
- **`vitest.config.ts:221` (objectstack-ai#10149):** "the outer fan-out ... is a
property of the shard, decided in `ci.yml`".
- Only two commits name the number. `cc21aad8ed` is a measurement that
says "Part of" and leaves the decision to the maintainer. `d18bc32770`
cites the card's recorded reasoning.
- Neither decides it, and the commit that wrote the line (`ad492e7fd`)
only cites it.
- **`test/init.test.ts:189` (objectstack-ai#11048):** "Admitting that band is a
support decision".
- It names an open decision (pnpm 10.0 to 10.4), and the floor is still
pnpm 10.15 or later at the base.
- Stage 3 and the create-objectstack stage left the sibling sites for
the same reason.
- **`published-entry-stderr-error-listener.test.ts:11` and `:150`, and
`published-subpath-hook-body.pin.test.ts:35` (objectstack-ai#14874):** "npm packs a
`bin` target regardless of `files`".
- No commit message names the number. The commits that add it
(`95d5cbb31`, `b3ef687c0`) only cite it.
- `5023630b1`'s changeset records the same measurement but names no
number, so the link is not proven.

## Not in this stage

- **The other lane packages**, 116 dead comment sites in total: see the
census table.
- **String sites (70, form D, objectstack-ai#20752, not moved):**
- **`cli`, 42 sites in 24 test files.** Examples: `describe('objectstack-ai#12125 —
...')` in `build-json-failure-conversions.e2e.test.ts:300`, `:459` and
`:557`, and `describe('[objectstack-ai#11025] ...')` in
`generate-skill.e2e.test.ts:203`.
- **`qa/dogfood`, 28 sites in 13 test files**, including
`authz-conformance.matrix.ts:429` (3 numbers in one string).
- **Off-list files (55 sites):**
- **`cli`:** `bin/run-dev.js` 6 and `bin/run.js` 4 (comments;
`bin/run.js` ships). `scripts/check-app-nav-i18n.mjs` has 13 comment and
14 string sites. `vitest-tiers.ts` has 2 and `vitest-tiers.fixtures.ts`
1 (comments). `test-typecheck-debt.json` has 1 (string).
  - **`plugin-hono-server`:** `objectstack.config.ts` 2.
- **`test-typecheck-debt.json` strings:** `rest` 7, and 1 each in
`runtime`, `mcp`, `client` and `qa/http-conformance`.
- **`qa/vitest-filter-preflight`:** `package.json` 1 (the description
string).

## Mechanical guard: no code token moves

The check compares the TypeScript parser's leaf tokens of the 56 changed
files at base `660a9b247e` against head `fda0702246`. It walks with
`getChildren`, excludes JSDoc nodes, and treats comments as trivia.
`tsconfig.test.json` is compared by its parsed JSONC value. Controls
mutate the head text in memory only.

| run | result | exit |
|---|---|---|
| real diff | 86,550 base tokens, **0 files differing** | 0 |
| comment-insertion control | 0 differing | 0 |
| code-insertion control | 56 of 56 differ | 1 |
| string control (one character flipped in each file's first real
`StringLiteral`) | 56 of 56 differ (55 first at a `StringLiteral`, plus
the JSON value) | 1 |

A raw scan of the 56 changed files for control bytes finds none. Its
positive control, a scratch file holding a U+0001 byte, matches 1.

## Changeset: none (`skip-changeset`)

`@objectstack/cli`'s published set is `files: ["dist", "README.md",
"CHANGELOG.md"]`, plus the `bin` target npm packs regardless of `files`.
No touched path is in it:
- `dist` is built from `tsconfig.build.json` (`rootDir: "src"`,
`include: ["src"]`).
- `bin/` is not touched.

Measured on the built package at head, 3 phrases the change adds occur
in 0 files of `dist`:
- "commit 55519d5's card"
- "the two templates commit cf6b671 repaired"
- "commit 1ddda1d"

The positive control, a `src` docblock phrase ("already drifted once
(closed by commit 6d441e4)"), occurs in `dist/commands/init.js`.

## Tests (head `fda0702246`, `os-verify-lock` with
`OS_VERIFY_LOCK_SLOT=issue-20594-outsidesrc`)

- **Closure build.** `pnpm --workspace-concurrency=2 --filter
'@objectstack/cli...' build` → VERDICT command-exit 0.
- **Unit tier.** `pnpm --filter @objectstack/cli exec vitest run
--project unit --maxWorkers=2` → VERDICT 0, Test Files 237 passed (237),
Tests 3370 passed (3370). The unit tier holds 23 of the 50 touched test
files.
- **Queue integration tier.** The one touched file ran by name:
`--project integration
test/published-entry-stderr-error-listener.test.ts` → 1 file, 6 tests
passed.
- **Nightly tier.** The other 26 touched test files ran by name under
`OS_TEST_TIERS=nightly`, in 4 runs: 9 files / 87 tests, 6 / 74, 6 / 22
and 5 / 22, each VERDICT 0 and all passed.
- **Coverage.** Every touched test file ran.
- **Typecheck.** `pnpm --filter @objectstack/cli typecheck` → VERDICT 0.
- It runs `tsc --noEmit` and then `check:test-typecheck`, which reports
"3 file(s) / 28 error(s) / 6 pinned signature(s) held in
test-typecheck-debt.json". That is the ledger as it stands at the base,
unchanged.
- **Whole workspace.** `pnpm exec turbo run build
--filter='./packages/*' --filter='./packages/*/*' --concurrency=2` →
VERDICT 0, 71/71 tasks. This was needed by the two gates that read built
output.
- **Reverse verification: none.** A comment-only change has no behaviour
to invert. The token guard's controls are the sensitivity proof.

## Gates (head `fda0702246`)

- **Derivation.** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` derives 49 families.
  - All 49 ran, and every recorded exit code is 0.
  - Three needed a second run, each for a reason outside the diff:
- `check:dual-build-cjs-loads` refused with exit 3 (PREREQUISITE NOT
MET, no `dist` for 9 packages). After the whole-workspace build it exits
0.
- `check:query-options-erasure` hit my 300 s cap on a contended box.
Rerun, it exits 0 in 363 s ("ratchet holds ... none new").
- `check:type-check-debt` refused with exit 3 (no built `objectql`).
After the build it exits 0 ("none above its recorded number").
- **Reconciliation.** `--ran`: 49 derived, 49 run, 0 NOT-MEASURED, 0
UNRUN.
- **Issue citations, diff mode.** `node
scripts/check-issue-citations.mjs` → 0 citations added.
- **Lint.** `pnpm lint` (`eslint . --no-inline-config`, repo-wide) →
exit 0, 2026-09-30T14:56:17Z to 15:00:01Z, at `fda0702246`.

## Acceptance notes

- **`origin/main` moved 14 commits past the base (to `9905e61ca2`), and
the branch was not merged forward.**
  - Of the files those commits touch, 0 are among this PR's 56.
- The derived family set on `9905e61ca2` with this diff applied (a
throwaway detached worktree, since removed) is the same 49 commands.
  - The merge-ref CI and the queue cover the joint tree.
- **Five nearby wordings still read as before, because they are not
sites:**
- `print-metadata-stats-zero-row.test.ts:101` says "That card" and
`:184` "that card's head". Both now follow a commit citation and mean
the card behind it.
- The `it` title at `generate-skill.e2e.test.ts:269` says both spec
`@example` blocks "still pass" `triggerPhrases`. That is stale since
`3c418c498`, but it is a test string and belongs to form D.
- **The objectstack-ai#14874 wording repeats in `bin/run.js:225` and three
`scripts/check-changeset-no-major.mjs` sites.** Both are outside this
surface; `scripts/**` is objectstack-ai#15809's lane.

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

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.

2 participants