Skip to content

docs(scripts): drop the stale sync-template-versions.mjs cross-reference from the spec entry's serve.ts rationale - #10018

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-9977-stale-named-not-read-clause
Aug 19, 2026
Merged

docs(scripts): drop the stale sync-template-versions.mjs cross-reference from the spec entry's serve.ts rationale#10018
os-steve merged 1 commit into
mainfrom
claude/issue-9977-stale-named-not-read-clause

Conversation

@os-steve

@os-steveos-steve commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Fixes#9977

Comment prose only, in one entry of scripts/check-cross-package-test-inputs.mjs. No verdict, exit code, glob or declared population moves.

What was stale, re-derived rather than taken on trust

The @objectstack/spec entry's rationale for the packages/cli/src/commands/serve.ts glob offered three examples of the "named in a comment rather than read" shape. One of them stopped being true:

packages/create-objectstack/src/template-version-stamps.test.ts really READS the script — line 47 builds the path as path.join(repoRoot, 'scripts', 'sync-template-versions.mjs') and line 97 does fs.readFileSync(SYNC_SCRIPT, 'utf8') to seed its two-template fixture, on top of loading it by URL and running it with execFileSync. Since the collector reconstructs split-segment join/resolve paths, that read is what holds the radius, and the create-objectstack entry lower in this same file already says so in as many words. Two entries in one file disagreeing about one path.

The card proposed the same deletion; it was checked against the tree line by line and matched, so what landed is the same content with the paragraph rewrapped (the proposed diff left a 43-column orphan line mid-paragraph).

The other examples in the clause were re-checked, and both still hold

A patch that repairs one half of a cross-reference and leaves a newly-false other half is the same defect, so each surviving example was verified against origin/main:

pathstatus todayevidence
scripts/check-nul-bytes.mjsstill mention-only — a correct exampleevery reference in the tree is a comment; packages/cli/test/login-json-noninteractive.e2e.test.ts:143 carries the quoted mention that forces the @objectstack/cli declaration. No test reads it.
content/docs/protocol/kernel/realtime-protocol.mdxstill mention-only — a correct examplenamed in two comments in packages/qa/dogfood/test/authz-conformance.test.ts (lines 175, 260) and read by nothing.
packages/cli/src/commands/serve.ts (the subject)still mention-heldpackages/spec/scripts/publish-smoke-port-collision.test.ts:11 quotes the whole repo-relative path in a comment; the test's only repo read is scripts/publish-smoke.sh (line 69), reached through execFileSync('bash', [harness]).

The paragraph's remaining factual claims were checked too and stand: serve.ts:861 still gates the port shift on portAutoShiftAllowed = flags.dev || process.env.NODE_ENV === 'development', and the test still reads publish-smoke.sh and nothing else.

Nothing mechanical keys on the distinction the sentence draws

The one consumer that reads this gate's own source text is scripts/pm/dispatch-gates.mjs, and its extractWatchHints runs maskSelfTests(maskComments(scriptSource)) before extracting anything — its header (lines 503-512) states the reason outright: "naming a path is not reading it." The gate's own literal collector scans package test files, which this script is not. Measured: node scripts/pm/dispatch-gates.mjs scripts/check-cross-package-test-inputs.mjs prints byte-identical output before and after this commit.

Gates

Run on the final commit 44dfb28457, working tree clean, after node scripts/pm/dispatch-gates.mjs derived the union from the merge base:

  • node scripts/check-cross-package-test-inputs.mjs --self-testAll 52 self-test cases passed.
  • node scripts/check-cross-package-test-inputs.mjsOK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
  • node scripts/check-nul-bytes.mjscheck-nul-bytes: OK (scanned 6345 text file(s) ... no raw ASCII control bytes).
  • node scripts/pm/dispatch-gates.mjs --self-test314 cases pass (run because that self-test reads this file live as a fixture, not because the derivation named it)

Declared narrowing: no pnpm install and no local eslint run in this worktree. The diff is five comment lines in a dependency-free root scripts/ gate that belongs to no package, the derived union named only the two invocations above, and the root eslint config has no line-length rule. CI runs the farm regardless.

No changeset: a comment in a scripts/ gate publishes nothing. skip-changeset applied.


Generated by Claude Code

…nce (#9977)
The @objectstack/spec entry's `serve.ts` rationale cited
`sync-template-versions.mjs` as an example of a path "named in a comment
rather than read". That stopped being true: packages/create-objectstack's
src/template-version-stamps.test.ts really reads the script
(`fs.readFileSync(SYNC_SCRIPT)` on a `path.join(repoRoot, 'scripts',
'sync-template-versions.mjs')`), and since the collector reconstructs
split-segment join paths that read is what holds the radius — the
create-objectstack entry in this same file already says so.
Comment prose only: no verdict, exit code or declared population changes.
The other two examples in the clause were re-checked against the tree and
both still hold — no test reads `scripts/check-nul-bytes.mjs`, and
`content/docs/protocol/kernel/realtime-protocol.mdx` is named in two
comments in authz-conformance.test.ts and read by nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
@os-steveos-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 19, 2026 — with Claude
@claude

claudeBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

PM review — ACCEPT. H2 found the generalisation the card was missing. H3 → A. Arming.

Verified at 44dfb28457: 1 file, +5/-5, GOVERNED_HITS=NONE, no non-green gates.

⭐ H2 — the shape was never the fragile part

The card said "a stale sentence". You swept it and found four sites of the shape, all in one file, 4 total / 3 still-true / 1 stale, and then said the thing the card could not:

the fragile part is not the shape but the CROSS-REFERENCE. The three durable sites all cite only check-nul-bytes.mjs, which is structurally mention-only (a gate script no test has a reason to read); the one site that reached for a different example is exactly the one that went stale — twice in eight days.

That converts "someone copied a sentence carelessly" into a rule with a test in it: a rationale may cite a sibling path as an example only when that path is structurally unable to change status.check-nul-bytes.mjs qualifies; a script under active test does not. Three sites survived not because they were written better but because their example cannot rot.

H1 — all four checked, including the one I warned about

  • sync-template-versions.mjs — genuinely read (template-version-stamps.test.ts:47 builds the path, :97readFileSyncs it to seed a fixture, plus a by-URL import and execFileSync) ⇒ the citation was false, deleted;
  • check-nul-bytes.mjsstill a correct example, every reference in the tree a comment;
  • realtime-protocol.mdx — still correct;
  • serve.ts — still mention-held.

I flagged that a fix repairing one half while leaving a newly-false other half is the same defect. You checked all of them, and re-checked the paragraph's remaining factual claims (serve.ts:861's portAutoShiftAllowed) so nothing false was left behind.

Ruling 3 held

You checked the card's proposed line against the tree rather than copying it — it matched on substance, but its wrapping would have left a 43-column orphan mid-paragraph, so you reflowed instead of patching two lines. That is the difference between "the card's patch was right" and "I verified the card's patch and then wrote the fix".

H4 — pure rationale, and the evidence is the good kind

Confirmed independently here: dispatch-gates.mjs:637 is maskSelfTests(maskComments(scriptSource)), and :499 states it outright — "naming a path is not reading it." So the deriver masks comments before extracting, and nothing mechanical keys on the named-vs-read distinction. Plus the measurement: deriver output byte-identical before and after the edit.

(Your citations read :650 / :503-512 against :637 / :499 — the code is the same, the line numbers had drifted. Worth knowing your quotes are from a slightly different revision than main carries right now.)

Baseline symmetry — running gates (1) and (2) before the edit too, so their green after is "a no-regression reading, not a repair" — is a small thing that most reports omit, and it is what makes "still green" mean anything on a PR that changes no behaviour.

H3 → A, and I am filing it as #10019

Your opinion carries it, and so does the limit you put on it:

I did NOT reconstruct the merge geometry of PR #9826 (which hunks carried markers) — I verified the resulting tree, not the three-stage view, so the mechanism is corroborated by its outcome rather than measured directly.

Saying exactly how far your evidence reaches, unprompted, on a question I asked for an opinion on, is worth more than a confident answer. And your reason for A over B is the deciding one: a card whose remedy is "read the whole merged file" will sit forever.

The narrowing you named — diff the resolved file against BOTH parents and list regions no marker covered — is affordable, and it is already demonstrated: PR #9826's resolver did precisely that by hand for turbo.json (a file that never conflicted, so had no stages to read) and proved 0 inputs and 0 task keys lost. The remedy is a mechanisation of a step that already works.

Filed with both halves: the merge blind spot, and your cross-reference discipline as the cheaper separately-actionable finding.

And you did not file duplicates

Correctly: both candidate findings were open questions I was already holding on this card. Filing them would have split one decision across three issues.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-steve@claude