Skip to content

docs(cli): re-anchor the dead tracker citations in packages/cli's files outside src to the commits that decided them - #20883

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20594-outside-src-citations
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20594-outside-src-citations

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #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 #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 #20767 and PR #20842.

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:

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 #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

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

Not in this stage

  • The other lane packages, 116 dead comment sites in total: see the census table.
  • String sites (70, form D, runtime strings in the domain:cli packages carry tracker numbers (114 messages in 8 packages, 254 ledgered ids): this lane's share of the #20513 A/A burn-down #20752, not moved):
    • cli, 42 sites in 24 test files. Examples: describe('#12125 — ...') in build-json-failure-conversions.e2e.test.ts:300, :459 and :557, and describe('[#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:

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


Generated by Claude Code

…es outside src to the commits that decided them

Stage 14 of the domain:cli lane's dead-citation sweep: comment prose in
packages/cli's test/**, vitest.config.ts and tsconfig.test.json. Every
comment site that cited a tracker number answering 404 now cites, in
ruling C+D's form C, the commit in this repository's history that decided
what the line describes. 154 sites on 149 lines in 56 files, 51 numbers,
50 distinct commits; one companion line moves a stale present tense into
the past (generate-skill.e2e.test.ts:35). Five sites have no deciding
commit and are left as they were (#10149, #11048, #14874 x3).

Comments only: 150 lines out, 150 in, every file keeps its line count.

Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/cli/vitest.config.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/cli/vitest.config.ts) — pages documenting those are invisible to this run
  • 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 — 25 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 9905e61ca2fddb43d266c23cdb12ced5019c1a74 → packageMentionDocs.

@github-actions github-actions Bot added the tests label Sep 30, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 30, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 15:23
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 4edb614 Sep 30, 2026
40 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20594-outside-src-citations branch September 30, 2026 15:40
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…gfood's files outside src to the commits and ADR that decided them (objectstack-ai#20898)

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

## What changed

This is stage 15 of the `domain:cli` lane's dead-citation sweep:
**`packages/qa/dogfood`'s dead citations in files outside `src/**`**,
the largest package left after stage 14 (claim `5914651671`). The
package has no `src/` at all, so the surface is its `test/**`,
`README.md`, `tsconfig.json` and `vitest.config.ts`.

Every comment site on that surface whose tracker number answers 404 now
cites the object that decided what the line describes, in ruling C+D's
form C (comment `5749154545` on objectstack-ai#19123): the ADR clause when one records
the ruling, otherwise the commit in this repository's history. Stages 1
to 14 of this card are the precedents; the latest is PR objectstack-ai#20883.

- **94 sites on 93 lines in 27 files**, covering **24 numbers**, now
cite **24 distinct commits and one ADR clause** (ADR-0029 D9.2a).
- The 27 files are `vitest.config.ts` and 26 under `test/**`: 21 test
files, 4 helper modules and 1 fixture.
- **Comments only.** 93 lines out and 93 in, and every file keeps its
line count. A token guard (below) shows zero non-comment tokens changed.
- **String literals, `describe` / `it` titles and messages are
untouched.** They belong to objectstack-ai#20752 (form D, fold `5911936313`); 28 such
sites stay on this file list, listed in the acceptance notes.
- **No tracker number is added.** The live numbers that share a changed
line stay as they were: objectstack-ai#4757, objectstack-ai#6915, objectstack-ai#7987, objectstack-ai#8074, objectstack-ai#8284, objectstack-ai#8408, objectstack-ai#9719,
objectstack-ai#11373 and objectstack-ai#17978 all answer 200.
- **Sites left without a deciding commit: none.** Every one of the 24
numbers has one.
- Where an earlier stage anchored a number and the line here describes
the same decision, the same anchor is reused: 16 of the 24 numbers. The
other 8 anchors are new (marked below).
- A trailing box rule (`── … ─────`) is shortened by the characters its
heading gained, never below one dash. Three of the five section headers
keep their width; `admin-route-nonadmin-refusal:339` grows by 2
characters and `two-doors-permission:81`, which already ended in one
dash, by 11.

## Census

**Instrument.** The card's gate does not read these files: its declared
surface is `packages/**/src/**`, and `surfaceFor` answers null for all
27 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, as stage 14 took it:

- **Files:** every tracked file of `packages/qa/dogfood` outside
`src/**`, with `CHANGELOG.md` (claim) and `package.json` (not on the
claim's list) left out. That is 178 files.
- **Extraction:** `extractCitations` from
`scripts/check-issue-citations.mjs`, with its comment-prose projection
for code and JSONC files and the whole file for `README.md`. The
whole-file extraction minus the comment projection gives the string
sites.
- **Numbers kept:** only those naming this repository
(`namesThisRepository`).
- **Probe:** each distinct number, `GET
/repos/objectstack-ai/objectstack/issues/N`; 404 means dead.

| | tree | probe window (UTC) | numbers | answer 200 | answer 404 | dead
comment sites | comment sites | dead string sites |
|---|---|---|---|---|---|---|---|---|
| before | base `4edb61449b` | 2026-09-30 15:46:43 to 15:49:29 | 386 |
359 | 27 | **94** (24 numbers, 27 files) | 1,145 | 28 (13 files) |
| after | head `57ffb83b00` | 2026-09-30 15:59:37 to 16:02:15 | 375 |
359 | 16 | **0** | 1,051 | 28 (13 files) |

- The before count matches stage 14's census at `660a9b247`: 94 comment
sites and 28 string sites in 13 files.
- No number present in both probes changed its answer. The 11 numbers
that left the census were only on the rewritten lines.
- Comment sites fell by exactly 94, the rewritten sites. String sites
did not move.
- `README.md` cites objectstack-ai#2018 and objectstack-ai#1994, and `package.json`'s description
cites objectstack-ai#2018, objectstack-ai#1994 and objectstack-ai#2004. All answer 200.

## Per-number anchors

Each anchor was checked by blame on the site, and in the anchor's own
message or diff. "Reused" names an earlier stage that gave the number
the same anchor.

| number | sites | anchor | what it decided | |
|---|---|---|---|---|
| `objectstack-ai#6293` | 9 | `c39a911ae` | the build stand-in:
`build-shaped-artifact.ts` runs the real lowering, and no published
surface grows (its subject names the card) | reused (cli `src`) |
| `objectstack-ai#6483` | 15 | `ee58392e1` | the ADR-0005 rollback of `permission`
(and eight more types) to `allowOrgOverride: false`;
`allowRuntimeCreate` stays open | reused (spec, plugin-security,
runtime) |
| `objectstack-ai#8460` | 4 | ADR-0029 D9.2a | the ruling itself, 2026-08-13, option A
"tenant wins"; implemented in `01a7337fc`, which amends the ADR | reused
(spec stage 6) |
| `objectstack-ai#8676` | 9 | `d6e80b28b` | flags `sys_account.password` and
`previous_password_hashes` `internal` | reused (plugin-auth) |
| `objectstack-ai#8711` | 3 | `2ce1eb41b` | half (2): the ruled narrowing of the
matrix's completeness claim to routes (its message records the
maintainer ruling) | **new** |
| `objectstack-ai#8711` | 1 | `60ade586e` | half (1): the two `active` rows with no
`covers`, and why (`matrix.ts:393`) | **new** |
| `objectstack-ai#8811` | 1 | `d6e793507` | adds the `grant-validity-window` matrix
row (its subject names the card) | **new** |
| `objectstack-ai#8839` | 7 | `c25b2d52a` | comment moderation stops being dead behind
the delete floor; ruling of 2026-08-15, reading 1 | reused
(plugin-security) |
| `objectstack-ai#8919` | 1 | `b5378550e` | gates `/meta` publish and rollback on
`manage_metadata`, with the enumeration pin | reused (rest, runtime,
cloud-connection) |
| `objectstack-ai#9797` | 7 | `1258dcaee` | the PR itself: the opt-in whole-operation
dispatch that restores the unscoped multi-delete refusal | **new** |
| `objectstack-ai#9934` | 2 | `79c46da90` | the producer-side `userMessage` marking,
including the QuickJS side-channel | reused (types, rest, client,
runtime, plugin-hono-server, spec) |
| `objectstack-ai#10243` | 1 | `266436a7f` | the toggle ruling: `POST
/automation/:name/toggle` joins the `manage_metadata` write set
(`automation-toggle-tenant-scope:4`) | reused (runtime,
service-automation) |
| `objectstack-ai#10243` | 1 | `02b41232d` | the measured cross-organization toggle
leak ADR-0126 §7.2 retires (`packaged-activation-ledger-reach:291`) |
reused (runtime, service-automation) |
| `objectstack-ai#10943` | 1 | `46d34ab7c` | `fallbackImport` becomes a
caller-supplied parameter | reused (types, cli, verify) |
| `objectstack-ai#10996` | 1 | `02b41232d` | the PR itself, the first landing of this
file as a measurement | **new** |
| `objectstack-ai#11477` | 7 | `6dd3e6968` | `/admin/remove-user` authorizes before
the break-glass guard (its message records "Ruled option A on" the card)
| reused (plugin-auth, verify) |
| `objectstack-ai#11530` | 1 | `033a34c7c` | the PR itself: retires the
`set_user_role` console action | **new** |
| `objectstack-ai#11686` | 1 | `7131f12bf` | the PR itself: `hasPlatformAdminStanding`
as the one authority | **new** |
| `objectstack-ai#12176` | 3 | `7986d973f` | stage 3 of the ruled retirement:
un-mounts the compound arities, `PUT /meta/:type/:section/:name` among
them. The ruling's `D3` ordinal is kept beside it | reused (rest,
client, runtime, spec) |
| `objectstack-ai#12194` | 1 | `311433f6b` | declares the metadata item-name grammar |
reused (rest, client, runtime, spec) |
| `objectstack-ai#13214` | 4 | `cc837dbfe` | the ruled ownership gate at `GET
/ui/view/:object/:type`; its diff writes these census lines and its
message the 2026-08-30 ruling | reused (rest) |
| `objectstack-ai#16589` | 4 | `555a89cbd` | `driver-memory` refuses a tenant-scoped
call; its diff names the card at every seam | reused (trigger-schedule)
|
| `objectstack-ai#16659` | 6 | `ecdfc9411` | a time-triggered flow declares its acting
organization; its diff adds these pins and the fixture. The `F2` ordinal
is kept, as the trigger-schedule stage kept it | reused
(trigger-schedule, service-automation, spec, lint) |
| `objectstack-ai#16687` | 1 | `779710213` | the PR itself; its squash carries the
contract-review patch round the line describes | **new** |
| `objectstack-ai#17853` | 1 | `08f5f0e5a` | a vitest filter that selects nothing says
so (the same sentence stage 14 rewrote in cli's config) | reused (qa,
cli) |
| `objectstack-ai#19306` | 2 | `f9e16d856` | a packaged permission set's DELETE stops
reporting a deletion; its diff adds both pins | **new** |

**ADR and ruling records.** A grep of `docs/adr` and
`scripts/adr-anchors` for the 24 numbers finds three: objectstack-ai#8460, objectstack-ai#6483 and
objectstack-ai#10243. ADR-0029 D9.2a is the ruling for objectstack-ai#8460 (it carries the number in
its heading), so it is cited. The objectstack-ai#6483 hits (ADR-0086, ADR-0094,
ADR-0126 and two adr-anchors entries) and the objectstack-ai#10243 hits (ADR-0126,
ADR-0131) mention those landings as history; none records the ruling
itself, so those two stay on the commit every earlier stage anchored
them to. The control number `7329` finds 1 file in the same tree.

**Anchor checks:**
- **Each sha is unambiguous:** `git rev-parse --disambiguate` gives
count 1 for each of the 24.
- **Each is a plain commit** with one parent.
- **Each is on the base:** `merge-base --is-ancestor` against
`4edb61449b` exits 0 for all 24.
- **The history is complete:** the checkout is not shallow. Control leg:
`255588bd36`, the parent of the oldest anchor `ee58392e1` (2026-08-09),
exits 0. Negative control: the base as an ancestor of `ee58392e1` exits
1.

## Verification

All at head `57ffb83b00`. Heavy runs went through
`scripts/pm/os-verify-lock.sh` with
`OS_VERIFY_LOCK_SLOT=issue-20594-dogfood`.

- **Build (dependency closure):** `pnpm exec turbo run build
--filter='@objectstack/dogfood^...' --concurrency=2` → 63 successful, 63
total (32 cached), lock verdict exit 0.
- **Every touched test file ran, by name.** Dogfood has two vitest
projects (`shared-showcase` and `isolated`) and no tier split, so one
run named all 21 touched test files plus the unit tests of the two
touched helpers no touched test imports
(`authz-probe-blind-spot.test.ts`, the census module's only importer,
and `enterprise-organizations.test.ts`): `pnpm --filter
@objectstack/dogfood exec vitest run --maxWorkers=2 FILES` → **Test
Files 23 passed (23), Tests 317 passed (317)**, lock verdict
command-exit 0. `vitest.config.ts` is loaded by that run.
- **Typecheck:** `pnpm --filter @objectstack/dogfood typecheck` (`tsc
--noEmit`) → lock verdict command-exit 0. `--listFilesOnly` shows 26 of
the 27 touched files in the program; the 27th is `vitest.config.ts`.
- **Token guard** (TypeScript leaf tokens via `getChildren`, JSDoc nodes
skipped), base `4edb61449b` against head, 27 files, 52,502 base tokens:
**0 files differ**. Controls, in memory only: a comment inserted into
each file, 0 of 27 differ; a statement appended, 27 of 27; one character
flipped inside each file's first `StringLiteral`, 27 of 27.
- **Control bytes:** a scan of the 27 files finds 0 (positive control, a
scratch file holding U+0001: 1). `pnpm check:nul-bytes` exits 0.
- **Derived gates and lint:** listed under "Gates".

## Gates

All at head `57ffb83b00`, exit codes captured before any pipe.

- **Derivation:** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands`, no paths, derives **53
commands** for this change set (27 paths against merge base
`4edb61449b`). Re-derived after two fetches of `origin/main` (to
`00a92e18da`, then `33b6e8bece`): the same 53, and none of the upstream
commits touches a derivation input or a file here.
- **All 53 exit 0.** One needed a second run for a reason outside the
diff: `pnpm check:dual-build-cjs-loads` first exited 3 (`PREREQUISITE
NOT MET`, no `dist/` for 8 packages outside dogfood's build closure);
after `pnpm exec turbo run build --filter='./packages/*'
--filter='./packages/*/*' --concurrency=2` (71 of 71, all cached) it
exits 0.
- **Reconciliation:** `dispatch-gates --ran` over the recorded `COMMAND
:: exit CODE` list → "53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN", exit
0.
- **`pnpm lint`** (repo-wide `eslint . --no-inline-config`, the family
the derivation does not name) → exit 0, 2026-09-30T16:13:49Z to
16:18:00Z.
- `node scripts/check-issue-citations.mjs` (diff mode, in the 53) reads
0 files, because none of these paths is on its declared surface; the
hand census above is the measurement for this surface.
- A local `git merge-tree --write-tree` of this head against
`origin/main` `33b6e8bece` is clean.

**The 53 derived commands:**

- `node scripts/check-ci-filter-parity.mjs`
- `node scripts/check-closing-keyword-parity.mjs`
- `node scripts/check-closing-keyword-parity.mjs --self-test`
- `node scripts/check-comment-mask-adoption.mjs`
- `node scripts/check-comment-mask-adoption.mjs --self-test`
- `node scripts/check-comment-mask-corpus.mjs`
- `node scripts/check-issue-citations.mjs`
- `node scripts/check-keyed-text-bounds.mjs`
- `node scripts/check-keyed-text-bounds.mjs --self-test`
- `node scripts/check-platform-object-tenancy-census.mjs`
- `node scripts/check-platform-object-tenancy-census.mjs --self-test`
- `node scripts/check-plugin-teardown-shape.mjs`
- `node scripts/check-plugin-teardown-shape.mjs --self-test`
- `node scripts/check-registry-log-declared.mjs`
- `node scripts/check-registry-log-declared.mjs --self-test`
- `node scripts/check-rest-log-spy-declared.mjs`
- `node scripts/check-rest-log-spy-declared.mjs --self-test`
- `node scripts/check-system-context-census.mjs`
- `node scripts/check-system-context-census.mjs --self-test`
- `node scripts/check-undeclared-dep-imports.mjs`
- `node scripts/check-undeclared-dep-imports.mjs --self-test`
- `node scripts/docs-audit/check-affected-docs.mjs`
- `node scripts/docs-audit/check-drift-comment.mjs`
- `pnpm --filter @objectstack/spec run check:empty-state`
- `pnpm --filter @objectstack/spec run check:liveness`
- `pnpm --filter @objectstack/spec run check:strictness-ledger`
- `pnpm --filter @objectstack/spec run check:variant-docs`
- `pnpm check:cross-package-test-inputs`
- `pnpm check:dispatcher-error-vocabulary`
- `pnpm check:doc-authoring`
- `pnpm check:driver-memory-census`
- `pnpm check:dts-closure`
- `pnpm check:dual-build-cjs-loads`
- `pnpm check:engine-double-contract`
- `pnpm check:gitlink-declared`
- `pnpm check:issue-citations`
- `pnpm check:lean-entry-closure`
- `pnpm check:logger-receiver-detach`
- `pnpm check:nul-bytes`
- `pnpm check:objectql-double-limit`
- `pnpm check:org-identifier`
- `pnpm check:page-declaration-shape`
- `pnpm check:published-files`
- `pnpm check:query-options-erasure`
- `pnpm check:refd-timer-probe`
- `pnpm check:slot-lookup`
- `pnpm check:sourcemap-no-sources-content`
- `pnpm check:test-source-alias`
- `pnpm check:tier-file-adoption`
- `pnpm check:type-check-coverage`
- `pnpm check:type-check-debt`
- `pnpm check:watch-hint-literal`
- `pnpm check:where-matcher`

## Acceptance notes

- **Changeset:** none. `@objectstack/dogfood` is `private: true`, so
nothing here publishes; the PR carries `skip-changeset`.
- **28 dead string sites stay on this file list** (16 numbers in 13
files: objectstack-ai#6293, objectstack-ai#6483, objectstack-ai#8676, objectstack-ai#8710, objectstack-ai#8711, objectstack-ai#8811, objectstack-ai#9934, objectstack-ai#10243, objectstack-ai#11477,
objectstack-ai#11530, objectstack-ai#11686, objectstack-ai#11757, objectstack-ai#12176, objectstack-ai#13260, objectstack-ai#16589, objectstack-ai#16659). They are
`describe` / `it` titles and string values such as the matrix rows'
`note:` text. They belong to objectstack-ai#20752 (form D).
- **What remains on this card after this stage** (stage 14's census at
`660a9b247`, report `5914100460`): 17 comment sites in the other lane
packages outside `src/**` (`plugin-hono-server` 4; `plugin-dev`,
`client` and `qa/vitest-filter-preflight` 2 each; `cloud-connection`,
`mcp`, `qa/downstream-contract`, `rest`, `runtime`, `types` and `verify`
1 each), the five `cli` sites with no deciding commit, and the 55
off-list sites stage 14 listed. None of them is touched here.
- **No open PR touches `packages/qa/dogfood`** (all 10 open PRs' file
lists read at 2026-09-30T15:56:00Z). The in-flight branch for objectstack-ai#20862
adds one new file there,
`automation-authoring-doors-durable.dogfood.test.ts`, which is not among
these 27.

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

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…es' files outside src to the commits that decided them (objectstack-ai#20923)

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

## What changed

This is stage 16 of the `domain:cli` lane's dead-citation sweep: **the
17 comment sites left in eleven lane packages' files outside `src/**`**
(claim `5917064266`; the list on stage 15's landing `5916232164`). The
file surface is the one stage 14 set: `README.md`, `tsconfig*.json`,
`vitest.config.*`, `tsup.config.*` and `test/**`.

Every comment site on that surface whose tracker number answers 404 now
cites the commit that decided what the line describes, in ruling C+D's
form C (comment `5749154545` on objectstack-ai#19123). Stages 1 to 15 of this card are
the precedents; the latest are PR objectstack-ai#20883 and PR objectstack-ai#20898.

- **17 sites on 16 lines in 14 files**, covering **9 numbers**, now cite
**9 distinct commits**.
- The 14 files: 5 JSONC configs (`tsconfig.test.json` in
plugin-hono-server, plugin-dev and verify; plugin-hono-server's
`tsconfig.typecheck.json`; client's `tsconfig.json`), 6
`vitest.config.ts` (client, cloud-connection, mcp, rest, runtime, types)
and 3 test files (`qa/vitest-filter-preflight` 2,
`qa/downstream-contract` 1).
- **Comments only.** 16 lines out and 16 in, and every file keeps its
line count. A token guard (below) shows zero non-comment tokens changed.
- **String literals, `describe` / `it` titles and messages are
untouched** (they belong to objectstack-ai#20752, fold `5911936313`).
- **No tracker number is added.** The live numbers that share a changed
line stay as they were: objectstack-ai#4914, objectstack-ai#12542 and objectstack-ai#17978 all answer 200.
- **Sites left without a deciding commit: none.**
- Where an earlier stage anchored a number and the line here describes
the same decision, the same anchor is reused: 6 of the 9 numbers. The
other 3 anchors are new (marked below).

## Census

**Instrument.** The card's gate does not read these files (its declared
surface is `packages/**/src/**`), so the census is taken by hand with
the gate's own grammar, as stages 14 and 15 took it:

- **Files:** every tracked file of the eleven packages outside `src/**`,
with `CHANGELOG.md` left out: 81 files. Each is classed ON stage 14's
file list (48 files) or OFF it (33: `package.json`, `LICENSE`, ledgers,
`objectstack.config.ts` and the like). Only ON-list comment sites are
this stage's.
- **Extraction:** `extractCitations` from
`scripts/check-issue-citations.mjs`, with its comment-prose projection
for code and JSONC files and the whole file for `*.md`. The whole-file
extraction minus the comment projection gives the string sites.
- **Numbers kept:** only those naming this repository
(`namesThisRepository`).
- **Probe:** each distinct number, `GET
/repos/objectstack-ai/objectstack/issues/N`; 404 means dead.

| | tree | probe window (UTC) | numbers | answer 200 | answer 404 | dead
comment sites, on-list | comment sites | dead comment sites, off-list |
dead string sites |
|---|---|---|---|---|---|---|---|---|---|
| before | base `cb4c31dd52` | 2026-09-30 18:18:37 to 18:19:15 | 94 | 80
| 14 | **17** (9 numbers, 14 files) | 212 | 2 | 11 |
| after | head `1e3782200f` | 2026-09-30 18:23:26 to 18:24:03 | 88 | 80
| 8 | **0** | 195 | 2 | 11 |

- The before count matches the list on stage 15's landing, package by
package.
- No number present in both probes changed its answer. The 6 numbers
that left the census (objectstack-ai#8651, objectstack-ai#10485, objectstack-ai#12181, objectstack-ai#13176, objectstack-ai#15145, objectstack-ai#16917)
were only on the rewritten lines.
- Comment sites fell by exactly 17. The off-list and string counts did
not move.

**Per package, dead on-list comment sites, before to after:**

| package | before | after |
|---|---|---|
| `packages/plugins/plugin-hono-server` | 4 | 0 |
| `packages/plugins/plugin-dev` | 2 | 0 |
| `packages/client` | 2 | 0 |
| `packages/qa/vitest-filter-preflight` | 2 | 0 |
| `packages/cloud-connection` | 1 | 0 |
| `packages/mcp` | 1 | 0 |
| `packages/qa/downstream-contract` | 1 | 0 |
| `packages/rest` | 1 | 0 |
| `packages/runtime` | 1 | 0 |
| `packages/types` | 1 | 0 |
| `packages/verify` | 1 | 0 |
| **total** | **17** | **0** |

## Per-number anchors

Each anchor was checked by blame on the site and in the anchor's own
message or diff. "Reused" names earlier stages that gave the number the
same anchor.

| number | sites | anchor | what it decided | |
|---|---|---|---|---|
| `objectstack-ai#13176` | 4: plugin-hono-server and plugin-dev `tsconfig.test.json`
(:3 and :61 / :56) | `a68c61267` | plugin-security's test layer enters
tsc under a sibling `tsconfig.test.json` at zero residue, with no
`test-typecheck-debt.json`; its diff writes the number into that
config's header and into the TEST_DEBT graduation | reused
(plugin-security) |
| `objectstack-ai#11332` | 1: plugin-hono-server `tsconfig.typecheck.json:12` |
`dce5cd4f0` | retires the manifest's `capabilities` / `configuration` /
`extensions` containers as `retiredKey()` tombstones (ADR-0049); its
changeset names the number | reused (spec) |
| `objectstack-ai#10724` | 1: the same line | `be21955ba` | retires the nine dead
`contributes` members as `retiredKey()` tombstones (ADR-0049); its
subject names the number | reused (spec) |
| `objectstack-ai#12181` | 2: client `tsconfig.json:8`, `vitest.config.ts:33` |
`cf71d73f8` | `meta.deleteItem`'s reset carriers; this same commit wrote
both blocks (the `paths` rules and the alias for the real-door test),
and its changeset names the number | reused (client, cli) |
| `objectstack-ai#17853` | 5: vitest-filter-preflight's two test headers, rest /
runtime / types `vitest.config.ts` | `08f5f0e5a` | a vitest filter that
selects no test file says so; its message names the card it lands. The
sentence in the three configs is the one stage 14 and stage 15 rewrote
in cli's and dogfood's | reused (qa, cli, dogfood) |
| `objectstack-ai#16917` | 1: cloud-connection `vitest.config.ts:64` | `7ce3154e6` |
the comment-only repair of this file, which wrote the "paraphrased
rather than quoted" sentence; its message names the card it lands |
**new** |
| `objectstack-ai#8651` | 1: mcp `vitest.config.ts:18` | `8c65046e4` | pins mcp's
three engine doubles to metadata-core's dispatch predicates, adds that
devDependency and creates this config for the alias; its message names
the card it lands | **new** |
| `objectstack-ai#10485` | 1: downstream-contract `test/contract.test.ts:46` |
`35ad101bc` | retires `ThemeSchema` and the `themes` carrier key
(ADR-0049, kept beside it); its subject names the number, and it wrote
this line | reused (spec, qa, cli) |
| `objectstack-ai#15145` | 1: verify `tsconfig.test.json:1` | `45a72b0cc` | wires
verify's test layer into `typecheck` through this file; its diff writes
the number into this line and into the coverage-ledger graduation |
**new** |

**ADR and ruling records.** A grep of `docs/adr` and
`scripts/adr-anchors` for the 9 numbers finds one hit: ADR-0088 names
objectstack-ai#10724 in a correction note (history, not the ruling), so that number
stays on the commit every earlier stage anchored it to. The sentence it
sits in already names ADR-0049. The control number `7329` finds 1 file
in the same tree.

**Anchor checks:**
- **Each sha is unambiguous:** `git rev-parse --disambiguate` gives
count 1 for each of the 9.
- **Each is a plain commit** with one parent.
- **Each is on the base:** `merge-base --is-ancestor` against
`cb4c31dd52` exits 0 for all 9.
- **The history is complete:** the checkout is not shallow. Control leg:
`01218124ae`, the parent of the oldest anchor `8c65046e4` (2026-08-16),
exits 0. Negative control: the base as an ancestor of `8c65046e4` exits
1.

## Verification

All at head `1e3782200f`. Heavy runs went through
`scripts/pm/os-verify-lock.sh` with
`OS_VERIFY_LOCK_SLOT=issue-20594-outside`.

- **Build (whole workspace):** `pnpm exec turbo run build
--filter='./packages/*' --filter='./packages/*/*' --concurrency=2` → 71
successful, 71 total (9 cached), lock verdict command-exit 0.
- **Typecheck, ten packages** (cloud-connection declares no `typecheck`
script): `pnpm --workspace-concurrency=2 --filter` plugin-hono-server,
plugin-dev, client, vitest-filter-preflight, mcp, downstream-contract,
rest, runtime, types, verify `run typecheck` → 10 of 10 `Done`, 0 `error
TS`, lock verdict command-exit 0. That reads every touched JSONC config
(plugin-hono-server's runs `tsconfig.typecheck.json` by name; the
`tsconfig.test.json` files are read by `check:test-typecheck`, all at
their recorded ledgers). `--listFilesOnly` holds all 3 touched test
files in their packages' programs.
- **Tests, by name** (one lock call, verdict command-exit 0). Each
touched test file ran, and each touched `vitest.config.ts` was loaded by
a run of its own package:
- vitest-filter-preflight: `test/config-wiring-sweep.test.ts`,
`test/filter-preflight.test.ts` → 2 files, 97 tests passed.
- downstream-contract: `test/contract.test.ts` → 1 file, 13 tests
passed.
- client: `src/meta-delete-item-carriers.test.ts` (the suite the edited
alias block serves) → 20 passed.
- cloud-connection: `src/canonical-expression-envelopes.test.ts` (the
suite the alias exists for) → 16 passed.
- mcp: `src/mcp-stdio-tools.test.ts` (the engine doubles the edited
block describes) → 12 passed.
- rest, runtime, types (`--project local`):
`src/rest-exec-ctx-memo.test.ts` 4 passed,
`src/app-plugin.ordering.test.ts` 3 passed, `src/email-verified.test.ts`
2 passed.
- **Token guard**, base `cb4c31dd52` against head, 14 files, 5,764 base
tokens: **0 files differ**. TypeScript files are compared as leaf tokens
(`getChildren`, JSDoc nodes skipped), JSONC files as the scanner's
non-trivia token stream plus their parsed value (0 of 5 values differ).
Controls, in memory only: a comment inserted into each file, 0 of 14
differ; a statement appended, 14 of 14; one character flipped inside
each file's first string token, 14 of 14 (9 `StringLiteral`, 5 JSON
strings).
- **Control bytes:** a scan of the 14 files finds 0 (positive control, a
scratch file holding U+0001: 1). `pnpm check:nul-bytes` exits 0.
- **Nothing publishes.** `npm pack --dry-run` in each of the 9 public
packages packs only `dist/**`, `README.md`, `CHANGELOG.md`, `LICENSE`
and `package.json`: 0 of the 11 touched files in those packages is
packed. After the build, the first 48 characters of each of the 16 added
comment lines occur in 0 files of any package's `dist/`; control: a
`src` docblock phrase an earlier stage wrote ("Maintainer-seat ruling,
landed by commit cf71d73") occurs in
`packages/client/dist/index.d.ts`. The other two packages are private.

## Gates

All at head `1e3782200f`, exit codes captured before any pipe.

- **Derivation:** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands`, no paths, derives **52
commands** (14 paths against merge base `cb4c31dd52`). Re-derived after
fetching `origin/main` to `4d0b9cd542`: the same 52, and none of the 4
upstream commits touches a derivation input or a file here.
- **All 52 exit 0**, each on its first run.
- **Reconciliation:** `dispatch-gates --ran` over the recorded `COMMAND
:: exit CODE` list → "52 derived, 52 run, 0 NOT-MEASURED, 0 UNRUN", exit
0.
- **Roster gates the derivation marks as keeping a roster under
`packages/`:** `pnpm check:authz-resolver`, `pnpm
check:error-code-casing` and `pnpm check:filter-alias-parity` → exit 0
each.
- **`pnpm lint`** (repo-wide `eslint . --no-inline-config`, the family
the derivation does not name) → exit 0, 2026-09-30T18:26:35Z to
18:30:31Z.
- `node scripts/check-issue-citations.mjs` (diff mode, in the 52) reads
0 files, because none of these paths is on its declared surface; the
hand census above is the measurement for this surface.
- A local `git merge-tree --write-tree` of this head against
`origin/main` `4d0b9cd542` is clean.

**The 52 derived commands:** stage 15's list with `pnpm --filter
@objectstack/spec run check:skill-examples` and `node
scripts/check-tenant-audit-census.mjs` (with its `--self-test`) in, and
`check:empty-state`, `check:liveness`, `check:strictness-ledger` and
`check:variant-docs` (spec) out:

- `node scripts/check-ci-filter-parity.mjs`
- `node scripts/check-closing-keyword-parity.mjs` and `--self-test`
- `node scripts/check-comment-mask-adoption.mjs` and `--self-test`
- `node scripts/check-comment-mask-corpus.mjs`
- `node scripts/check-issue-citations.mjs`
- `node scripts/check-keyed-text-bounds.mjs` and `--self-test`
- `node scripts/check-platform-object-tenancy-census.mjs` and
`--self-test`
- `node scripts/check-plugin-teardown-shape.mjs` and `--self-test`
- `node scripts/check-registry-log-declared.mjs` and `--self-test`
- `node scripts/check-rest-log-spy-declared.mjs` and `--self-test`
- `node scripts/check-system-context-census.mjs` and `--self-test`
- `node scripts/check-tenant-audit-census.mjs` and `--self-test`
- `node scripts/check-undeclared-dep-imports.mjs` and `--self-test`
- `node scripts/docs-audit/check-affected-docs.mjs`
- `node scripts/docs-audit/check-drift-comment.mjs`
- `pnpm --filter @objectstack/spec run check:skill-examples`
- `pnpm check:cross-package-test-inputs`,
`check:dispatcher-error-vocabulary`, `check:doc-authoring`,
`check:driver-memory-census`, `check:dts-closure`,
`check:dual-build-cjs-loads`, `check:engine-double-contract`,
`check:gitlink-declared`, `check:issue-citations`,
`check:lean-entry-closure`, `check:logger-receiver-detach`,
`check:nul-bytes`, `check:objectql-double-limit`,
`check:org-identifier`, `check:page-declaration-shape`,
`check:published-files`, `check:query-options-erasure`,
`check:refd-timer-probe`, `check:slot-lookup`,
`check:sourcemap-no-sources-content`, `check:test-source-alias`,
`check:tier-file-adoption`, `check:type-check-coverage`,
`check:type-check-debt`, `check:watch-hint-literal`,
`check:where-matcher`

## Acceptance notes

- **Changeset:** none. Nine of the eleven packages publish, but no
touched file is in any package's `files` (measured above), and
`qa/vitest-filter-preflight` and `qa/downstream-contract` are private.
The PR carries `skip-changeset`.
- **Left in these eleven packages, not this stage's:** 2 dead comment
sites off stage 14's file list, in plugin-hono-server's
`objectstack.config.ts` (:19 objectstack-ai#11332, :26 objectstack-ai#10724), and 11 dead string
sites: the `test-typecheck-debt.json` notes in client (1), mcp (1), rest
(7) and runtime (1), and vitest-filter-preflight's `package.json`
description (1). All 13 are among the 55 off-list sites stage 14 listed.
- **What remains on this card after this stage:** the 55 off-list sites
stage 14 listed, and the five `cli` sites with no deciding commit
(objectstack-ai#10149, objectstack-ai#11048, objectstack-ai#14874 x3). None of them is touched here.
- **Grammar reach, measured on this surface:** the gate's grammar does
not extract the second number of a slash-joined pair such as
`objectstack-ai#10374/objectstack-ai#13522`. On these 81 files that shape holds 4 such numbers
(objectstack-ai#3060, objectstack-ai#7778, objectstack-ai#13522, objectstack-ai#14016), and all 4 answer 200
(2026-09-30T19:04Z), so the census above misses no dead site.
- **No open PR touches these files.** The claim's serial check read all
11 open PRs' file lists at `cb4c31dd52`; objectstack-ai#20602 and objectstack-ai#20583 on this seat
stay in `packages/rest/src` and `packages/cli/src`.

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

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
… stage 14's list to the commits that decided them (objectstack-ai#20947)

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

## What changed

This is stage 17 of the `domain:cli` lane's dead-citation sweep: **the
comment sites in lane files outside stage 14's file list** (claim
`5918748154`; the list on stage 16's landing `5918606717` and stage 14's
report `5914100460`). The claim names six files:

- `packages/cli/bin/run.js` and `packages/cli/bin/run-dev.js`;
- `packages/cli/scripts/check-app-nav-i18n.mjs`;
- `packages/cli/vitest-tiers.ts` and
`packages/cli/vitest-tiers.fixtures.ts`;
- `packages/plugins/plugin-hono-server/objectstack.config.ts`.

Every comment site in those files whose tracker number answers 404 now
cites the commit that decided what the line describes, in ruling C+D's
form C (comment `5749154545` on objectstack-ai#19123), except one site with no
deciding commit. Stages 1 to 16 of this card are the precedents; the
latest are PR objectstack-ai#20883, PR objectstack-ai#20898 and PR objectstack-ai#20923.

- **27 sites on 27 lines in 6 files**, covering **8 numbers**, now cite
**8 distinct commits**. 6 of the 8 anchors are reused from earlier
stages for the same decision; 2 are new (marked below).
- **Comments only.** 27 lines out and 27 in, and every file keeps its
line count. A token guard (below) shows zero non-comment tokens changed.
- **String literals, `describe` / `it` titles and messages are
untouched.** They belong to objectstack-ai#20752 (fold `5911936313`). That includes
the 14 dead numbers inside strings in `check-app-nav-i18n.mjs`.
- **No tracker number is added.** The live numbers that share a changed
line stay as they were: objectstack-ai#14554, objectstack-ai#15564 and objectstack-ai#16746 all answer 200.
- **One site is kept without a deciding commit:** `bin/run.js:225`
(objectstack-ai#14874). See "Kept" below.
- **A `patch` changeset for `@objectstack/cli`**, because `bin/run.js`
is packed (see "Publish check").

## Census

**Instrument.** The card's gate does not read these files (its declared
surface is `packages/**/src/**`), so the census is taken by hand with
the gate's own grammar, as stages 14 to 16 took it:

- **Files:** every tracked file of the 19 lane packages outside
`src/**`, with `CHANGELOG.md` left out: 538 files. Each is classed as
one of the claim's six files, as ON stage 14's file list (`README.md`,
`tsconfig*.json`, `vitest.config.*`, `tsup.config.*`, `test/**`), or as
neither.
- **Extraction:** `extractCitations` from
`scripts/check-issue-citations.mjs`, with its comment-prose projection
for code and JSON files and the whole file for prose files. The
whole-file extraction minus the comment projection gives the string
sites.
- **Numbers kept:** only those naming this repository
(`namesThisRepository`).
- **Probe:** each distinct number, `GET
/repos/objectstack-ai/objectstack/issues/N`; 404 means dead.

| | tree | probe window (UTC) | numbers | 200 | 404 | dead comment
sites, the six files | dead comment sites, whole lane surface | dead
string sites, whole lane surface |
|---|---|---|---|---|---|---|---|---|
| before | base `aaad682dbc` | 2026-09-30 20:09:40 to 20:15:09 | 852 |
798 | 54 | **28** (9 numbers) | 33 | 97 |
| after | head `89264b0c1e` | 2026-09-30 20:23:18 to 20:28:44 | 848 |
798 | 50 | **1** | 6 | 97 |

- The before count matches stage 14's per-file counts for comments:
`bin/` 10, `check-app-nav-i18n.mjs` 13 (plus 14 string sites, 27 in
all), `vitest-tiers*.ts` 3, `objectstack.config.ts` 2.
- No number present in both probes changed its answer. The 4 numbers
that left the census (objectstack-ai#10724, objectstack-ai#11332, objectstack-ai#12964, objectstack-ai#14715) were only on the
rewritten lines.
- Comment sites across the whole surface fell by exactly 27 (2,452 to
2,425). The string count did not move.

**Per file, dead comment sites, before to after:**

| file | before | after |
|---|---|---|
| `packages/cli/bin/run-dev.js` | 6 | 0 |
| `packages/cli/bin/run.js` | 4 | 1 |
| `packages/cli/scripts/check-app-nav-i18n.mjs` | 13 | 0 |
| `packages/cli/vitest-tiers.ts` | 2 | 0 |
| `packages/cli/vitest-tiers.fixtures.ts` | 1 | 0 |
| `packages/plugins/plugin-hono-server/objectstack.config.ts` | 2 | 0 |
| **total** | **28** | **1** |

**What the lane surface outside `src/**` still holds after this stage:**
6 dead comment sites, all without a deciding commit (`bin/run.js:225`
and the five stage 14 kept), and 97 dead string sites (objectstack-ai#20752's form D).

## Per-number anchors

Each anchor was checked by blame on the site and in the anchor's own
message or diff. "Reused" names the earlier stage that gave the number
the same anchor.

| number | sites | anchor | what it decided | |
|---|---|---|---|---|
| `objectstack-ai#12964` | 3: `run-dev.js:71`, `:152`, `:466` | `e6fd1caf7` |
`bin/run-dev.js` collects oclif's module-load warnings and names the
missing build output instead of "command not found"; its changeset names
the number, and it wrote `:152` and `:466` itself | reused (stage 14,
cli tests) |
| `objectstack-ai#14715` | 2: `run-dev.js:362`, `:400` | `accb9231c` | the squash of
that number's PR (its subject names it): the never-read reader's case
keeps its product assertions, "the child exits on its own, with code 2"
| reused (stage 14) |
| `objectstack-ai#14858` | 4: `run-dev.js:377`; `run.js:163`, `:168`, `:220` |
`0c5e97368` | a closed stderr read end exits 2 instead of dying of an
uncaught EPIPE; its subject names the number, and it added the
`run-dev.js` listener and docblock that `:377` heads | reused (stage 14,
cli tests) |
| `objectstack-ai#17891` | 9 in `check-app-nav-i18n.mjs` (`:112`, `:221`, `:237`,
`:261`, `:289`, `:302`, `:502`, `:552`, `:706`) | `ca9d9d361` | widens
`check:app-nav-i18n` from one app to the declared platform-app
population (the Account shell in the roster, one build probe per shell,
per-app counts in the pass line); its message names the card it lands |
**new** |
| `objectstack-ai#17759` | 4 in `check-app-nav-i18n.mjs` (`:148`, `:238`, `:259`,
`:537`) | `c744c0af3` | translates the Account app's contributed
`nav_connect_agent` in all four locales, one namespace per app; its
message names the card it lands | **new** |
| `objectstack-ai#13504` | 3: `vitest-tiers.ts:5`, `:67`;
`vitest-tiers.fixtures.ts:194` | `44813ba57` | the tier half of that
card: the named `unit` / `integration` tiers and the behavioural
predicate that replaced the text-match census | reused (stage 14,
`vitest.config.ts`) |
| `objectstack-ai#11332` | 1: `objectstack.config.ts:19` | `dce5cd4f0` | retires the
manifest's `capabilities` / `configuration` / `extensions` containers
(ADR-0049); it wrote this comment | reused (stage 16) |
| `objectstack-ai#10724` | 1: `objectstack.config.ts:26` | `be21955ba` | retires the
nine dead `contributes` members (ADR-0049); its subject names the
number, and it wrote this comment | reused (stage 16) |


**ADR and ruling records.** A grep of `docs/adr` and
`scripts/adr-anchors` for the 8 numbers (and objectstack-ai#14874) finds one hit:
ADR-0088 names objectstack-ai#10724 in a correction note (history, not the ruling), so
that number stays on the commit stage 16 anchored it to. The sentence it
sits in already names ADR-0049. The control number `7329` finds 1 file
in the same tree.

**Anchor checks:**
- **Each sha is unambiguous:** `git rev-parse --disambiguate` gives
count 1 for each of the 8.
- **Each is a plain commit** with one parent.
- **Each is on the base:** `merge-base --is-ancestor` against
`aaad682dbc` exits 0 for all 8.
- **The history is complete:** the checkout is not shallow, and an exit
0 from `--is-ancestor` proves itself. Negative control: the base as an
ancestor of the oldest anchor `be21955ba` (2026-08-25) exits 1.

## Kept: no deciding commit found

`bin/run.js:225` keeps objectstack-ai#14874 ("npm packs a `bin` target regardless" of
`files`). The history search this stage ran:
- `git log --grep` for the number finds only this card's re-anchoring
commits.
- `git log -S` finds the earliest mention in `95d5cbb316`, which cites
objectstack-ai#14874 as the measurement ("objectstack-ai#14874 measured the other half of the same
lesson"). It does not decide it.
- `5023630b1` records the same measurement in its changeset, but neither
its message nor its diff names the number. Stage 14 named it as a
candidate, and the ACCEPT `5914299201` ruled that a commit which only
restates or applies a decision is not the anchor.

The five `cli` sites stage 14 kept (objectstack-ai#10149, objectstack-ai#11048, objectstack-ai#14874 ×2 in
`test/published-entry-stderr-error-listener.test.ts` and 1 in
`test/published-subpath-hook-body.pin.test.ts`) were searched again the
same way. For objectstack-ai#10149, `cc21aad8ed` is "Part of" it and leaves the
decision to the maintainer, and `d18bc32770` applies its reasoning. For
objectstack-ai#11048, `568de194ec` files it unassigned as an open support decision. So
no deciding commit was found, and they stay as they are.

## Verification

All at head `89264b0c1e`. Heavy runs went through
`scripts/pm/os-verify-lock.sh` with
`OS_VERIFY_LOCK_SLOT=issue-20594-offlist`.

- **Build (whole workspace):** `pnpm exec turbo run build
--filter='./packages/*' --filter='./packages/*/*' --concurrency=2` → 71
successful, 71 total (7 cached), lock verdict command-exit 0.
- **Typecheck:** `pnpm --workspace-concurrency=2 --filter
@objectstack/cli --filter @objectstack/plugin-hono-server run typecheck`
→ both `Done`, 0 `error TS`, lock verdict command-exit 0.
`check:test-typecheck` holds both ledgers where they were: cli 3 files /
28 errors / 6 pinned signatures, plugin-hono-server 0. `--listFilesOnly`
shows cli's `tsconfig.test.json` program holds `vitest-tiers.ts` and
`vitest-tiers.fixtures.ts`, and plugin-hono-server's
`tsconfig.typecheck.json` holds `objectstack.config.ts`.
- **cli `unit` tier:** `pnpm --filter @objectstack/cli exec vitest run
--project unit --maxWorkers=2` → 239 files, 3391 tests passed, lock
verdict command-exit 0. It holds `test/vitest-tiers-partition.test.ts`,
which imports both `vitest-tiers*.ts` files, and every run loads
`vitest.config.ts`, which imports `vitest-tiers.ts`.
- **cli `integration` tier**, run locally because the diff touches
`bin/` (the spawn entries): `--project integration --maxWorkers=2` → 67
files, 572 passed and 1 skipped (a data-conditional `skipIf` in
`test/migrate-meta-default-range.test.ts`), lock verdict command-exit 0.
It holds `test/published-entry-stderr-error-listener.test.ts`, which
spawns `bin/run.js`.
- **Nightly-tier files that spawn the two entries**, by name under
`OS_TEST_TIERS=nightly`: `test/run-dev-unbuilt-workspace.e2e.test.ts`,
`test/published-entry-stderr-nonblocking.e2e.test.ts` and
`test/run-dev-stderr-nonblocking.e2e.test.ts` → 3 files, 21 tests
passed, lock verdict command-exit 0.
- **The script, the way CI calls it:** `pnpm check:app-nav-i18n`
(`--self-test`, then the real run; `lint.yml` runs this) → exit 0. The
self-test passes, and the pass line reads `OK (11 contributor(s), 4
locale(s), 2 app(s) — setup: 55 merged nav id(s), account: 12 merged nav
id(s) — every id labelled in every locale)`.
- **The entries, smoke:** `node packages/cli/bin/run.js --help` exit 0
(66 lines); `node packages/cli/bin/run-dev.js --help` exit 0 (66 lines);
`node packages/cli/bin/run.js --version` exit 0; `node
packages/cli/bin/run.js no-such-command-xyz` exit 2 with oclif's
`command … not found`.
- **Token guard**, base `aaad682dbc` against head, 6 files, 6,224 base
tokens: **0 files differ**. Leaf tokens come from the TypeScript parser
(`getChildren`, JSDoc nodes skipped; `.js` / `.mjs` parsed as JS).
Controls, in memory only: a comment inserted into each file, 0 of 6
differ; a statement appended, 6 of 6; one character flipped inside each
file's first `StringLiteral`, 6 of 6. The comment control's first form
put its comment above the shebang in the three `#!` files and moved
tokens in 3 of 6. It was corrected to insert below the shebang before it
was used as a reading.
- **Control bytes:** a scan of the 6 files and the changeset finds 0
(positive control, a scratch file holding U+0001: 1). `pnpm
check:nul-bytes` exits 0.
- **Publish check:** `npm pack --dry-run` in `packages/cli` packs
`bin/run.js` (a `bin` target, packed regardless of `files`) beside
`dist/**`, `README.md`, `CHANGELOG.md`, `LICENSE` and `package.json`. It
packs none of `bin/run-dev.js`, `scripts/` or `vitest-tiers*.ts`, so the
`patch` changeset covers `bin/run.js` alone. `plugin-hono-server` packs
no `objectstack.config.ts`, and its `src/` never imports that file.
After the build, the first 48 characters of each of the 27 added comment
lines occur in 0 files of any package's `dist/`. Control: the `src`
docblock phrase `document" (commit 2b641dd). Both device-flow` occurs
in 1 file of `packages/cli/dist`. (plugin-hono-server's bundler keeps no
comments, so its `dist` gives no reading either way: its own control
phrase occurs in 0 files.)

## Gates

All at head `89264b0c1e`, exit codes captured before any pipe.

- **Derivation:** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands`, no paths, derives **57
commands** (7 paths against merge base `aaad682db`). Re-derived after
fetching `origin/main` to `31c39964fc`: the same 57. None of the 5
upstream commits touches a derivation input or a file here.
- **All 57 exit 0**, each on its first run.
- **Reconciliation:** `dispatch-gates --ran` over the recorded `COMMAND
:: exit CODE` list → "57 derived, 57 run, 0 NOT-MEASURED, 0 UNRUN", exit
0.
- **Roster gates the derivation marks as keeping a roster under a
touched directory:** `node scripts/check-changeset-fixed.mjs`, `pnpm
check:authz-resolver`, `pnpm check:error-code-casing`, `pnpm
check:filter-alias-parity` and `node scripts/release-pending-publish.mjs
--self-test` → exit 0 each.
- **`pnpm lint`** (repo-wide `eslint . --no-inline-config`, the family
the derivation does not name) → exit 0, 2026-09-30T21:33:42Z to
21:36:25Z.
- `node scripts/check-issue-citations.mjs` (diff mode, in the 57) reads
0 files, because none of these paths is on its declared surface. The
hand census above is the measurement for this surface.
- The changeset gates in the 57: `check-empty-changeset` ("1 declaring
changeset(s) added"), `check-changeset-no-major` ("no `major` bump"),
`check-adr-0087-registration` ("no declared-breaking changeset").
- A local `git merge-tree --write-tree` of this head against
`origin/main` `3fbf3ca617` is clean.

**The 57 derived commands:** stage 16's 52, minus `pnpm --filter
@objectstack/spec run check:skill-examples`, `pnpm
check:dispatcher-error-vocabulary`, `pnpm check:engine-double-contract`,
`pnpm check:objectql-double-limit`, `pnpm check:query-options-erasure`,
`pnpm check:type-check-coverage`, `pnpm check:type-check-debt` and `pnpm
check:where-matcher`, plus the changeset family
(`check-adr-0087-registration`, `check-changeset-no-major`,
`check-empty-changeset`, each with its `--self-test`; `pnpm
check:changeset-gate-self-tests`, `pnpm check:objectui-changeset`, `pnpm
check:pm-changeset-deadline-census`), `pnpm check:i18n`, `pnpm
check:i18n-coverage`, `pnpm check:i18n-walk-parity` and `node
scripts/pm/release-rehearsal-clone.mjs --self-test`.

## Acceptance notes

- **Not this card's: dead numbers in strings.** `check-app-nav-i18n.mjs`
holds 14 (objectstack-ai#17891 ×13, objectstack-ai#17759 ×1: the self-test's `expect` titles and
messages, and the `--self-test` pass line, which prints `(objectstack-ai#17891)` at
runtime). The lane surface holds 97 dead string sites in all. They
belong to objectstack-ai#20752's form D (fold `5911936313`).
- **What this card has left:** the 6 comment sites without a deciding
commit, listed above.

---
_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

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants