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.

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