Skip to content

check-cross-package-test-inputs' @objectstack/spec entry cites sync-template-versions.mjs as "named in a comment rather than read" — the same clause #9651 already retired, reintroduced in a second entry #9977

Closed

Description

@os-steve

Found while resolving the merge conflict on PR #9826 (issue #9763). Not fixed there — that PR is a reviewed conflict resolution and its ruling 4 forbids re-scoping. Recording only.

The stale clause

scripts/check-cross-package-test-inputs.mjs, in the @objectstack/spec entry, justifying the packages/cli/src/commands/serve.ts glob:

      // `serve.ts` is named in a comment rather than read, the same shape as
      // `check-nul-bytes.mjs` / `sync-template-versions.mjs` / the realtime
      // protocol page below, and settled the same way: the literal collector
      // takes quoted paths without parsing, so a mention forces a declaration,

sync-template-versions.mjs is not that shape any more. packages/create-objectstack/src/template-version-stamps.test.ts:47 really reads it:

const SYNC_SCRIPT = path.join(repoRoot, 'scripts', 'sync-template-versions.mjs');

and since #9763 the collector reconstructs split-segment join/resolve paths, so that read is what holds the radius. The create-objectstack entry in the same file now says so in as many words — "What FORCES the glob is now the read itself … The mentions are ordinary prose again — free to reword." Two entries in one file, disagreeing about the same path.

Why it is worth a card rather than a shrug

This is the second instance of the identical clause. #9651 retired it from the create-objectstack entry for exactly this reason ("still calls sync-template-versions.mjs 'named in a comment rather than read', which stopped being true"). It came back because #9782 wrote a fresh rationale in a different entry that reached for sync-template-versions.mjs as its canonical example of the mention shape — correct when written against main, false once #9763 landed.

The cost is not cosmetic: the clause tells the next author that rewording those mentions would unforce a live radius. That was true before #9763 and is the reason the clause exists; it is now advice against a hazard that has been fixed, attached to a path that no longer has it.

Bounded, and stated

No gate is wrong — serve.ts genuinely is mention-held, so the @objectstack/spec declaration it justifies is correct and load-bearing (ablated on the PR #9826 merge head: removing it fails the gate, naming packages/spec/scripts/publish-smoke-port-collision.test.ts). Only the cross-reference inside the rationale is stale. Same for the sibling clause in the create-objectstack entry, which PR #9826's conflict resolution had to author and therefore corrected in place — that one is already handled; this card is about the @objectstack/spec copy that git auto-merged untouched.

Shape of a fix

Delete the stale half of the cross-reference, keeping the example that is still true:

       // `serve.ts` is named in a comment rather than read, the same shape as
-      // `check-nul-bytes.mjs` / `sync-template-versions.mjs` / the realtime
-      // protocol page below, and settled the same way: the literal collector
+      // `check-nul-bytes.mjs` / the realtime protocol page below, and settled
+      // the same way: the literal collector

check-nul-bytes.mjs is still correct — the file's own @objectstack/cli rationale calls it "the one entry no test READS" — and so is the realtime-protocol.mdx reference, which #9651's dev deliberately left alone for the same reason.

Worth considering alongside the recurrence itself: a rationale that names another entry's path as an example goes stale whenever that path's status changes, and nothing mechanical notices. #9651 and this card are the same failure twice in eight days.

Generated by Claude Code

Activity

  1. claude commented on Aug 19, 2026

    @claude
    Contributor

    Claim: PM loop round 20
    Session: session_01XqDQYVU5smx29ts9pAErja
    Branch: claude/issue-9977-stale-named-not-read-clause
    Worktree: objectstack-issue-9977
    Domain: domain:devx
    File surface: scripts/check-cross-package-test-inputs.mjs (the @objectstack/spec entry's serve.ts rationale) (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus (node scripts/pm/dispatch-gates.mjs --tier scripts/check-cross-package-test-inputs.mjs run this round: "no path-derived mandate … This line is a FLOOR, never a clearance"; content limb no — comment prose, no invariant affected)
    Clause-②: no
    Serial constraints cleared: swept all open PRs for any touching check-cross-package-test-inputs — none. The PR that FILED this card, #9826 (#9763), is MERGED (12:11Z today), so the region is on main and free. ⚠️ PR #10014 (#9829) is armed and touches ci.yml only — no overlap.


    Generated by Claude Code

  2. os-steve commented on Aug 19, 2026

    @os-steve
    CollaboratorAuthor
    {
      "issue": 9977,
      "status": "done",
      "branch": "claude/issue-9977-stale-named-not-read-clause",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/10018",
      "premise_still_valid": true,
      "summary": "Premise verified against origin/main (merge base 73cfddfa9) and STILL TRUE, then fixed with 5 comment lines (+5/-5, one file). H1 per file: (a) sync-template-versions.mjs is genuinely READ, so the L141 citation was false and is now deleted -- packages/create-objectstack/src/template-version-stamps.test.ts:47 builds the path as path.join(repoRoot,'scripts','sync-template-versions.mjs') and :97 does fs.readFileSync(SYNC_SCRIPT,'utf8') to seed its fixture, on top of a by-URL import and execFileSync; (b) check-nul-bytes.mjs IS STILL A CORRECT EXAMPLE -- every reference in the tree is a comment, the forcing one being packages/cli/test/login-json-noninteractive.e2e.test.ts:143, and no test reads it; (c) realtime-protocol.mdx is still correct -- named in comments at packages/qa/dogfood/test/authz-conformance.test.ts:175 and :260, read by nothing; (d) the subject serve.ts is still mention-held -- packages/spec/scripts/publish-smoke-port-collision.test.ts:11 quotes the whole repo-relative path in a comment and the test's only repo read is scripts/publish-smoke.sh at :69 via execFileSync('bash',[harness]). The paragraph's remaining factual claims were re-checked and stand (serve.ts:861 still reads portAutoShiftAllowed = flags.dev || process.env.NODE_ENV === 'development'), so no newly-false half was left behind. Ruling 3: the card's proposed line was checked against the tree rather than copied -- it matched on substance, but its wrapping left a 43-column orphan line mid-paragraph, so the paragraph was reflowed instead of patched two lines. H2 sweep: the 'named rather than read' shape occurs at exactly 4 sites, ALL inside scripts/check-cross-package-test-inputs.mjs (L141 @objectstack/spec, L238 @objectstack/cli, L327 @objectstack/dogfood, L393 create-objectstack), plus one inverse statement at L386 ('is READ, not merely mentioned'); nowhere else in the repo. Totals: 4 total / 3 still-true / 1 stale before this PR; 4/4 true after. So yes -- this is a COPIED RATIONALE, not a one-off sentence. The sharper reading: 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. H4: pure rationale -- nothing mechanical keys on the named-vs-read distinction, so ruling 2's boundary holds and Clause-(2) stays 'no' (grep and measurement in `tests`). No separate card filed: the two candidate findings (H2's copied rationale, H3's silent-auto-merge blind spot) are both explicitly open questions you are holding on this card, and filing either would duplicate a decision already in flight.",
      "tests": "All gates re-run on the FINAL commit 44dfb28457 (git status --porcelain empty before the run). Union re-derived from the merge base by `node scripts/pm/dispatch-gates.mjs` with NO paths passed -- it named exactly two invocations, both this gate. Exit codes captured before any pipe (`cmd > file 2>&1; EXIT=$?`), and each result below quotes the gate's own verdict line. (1) node scripts/check-cross-package-test-inputs.mjs --self-test -> exit 0, 'All 52 self-test cases passed.' (2) node scripts/check-cross-package-test-inputs.mjs -> exit 0, 'OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.' (3) node scripts/check-nul-bytes.mjs -> exit 0, 'check-nul-bytes: OK (scanned 6345 text file(s) -- 6345 tracked, 0 untracked-not-ignored; skipped 5 binary; no raw ASCII control bytes).' plus a direct C0-range scan of the edited file (grep -naP) returning 1 = clean. (4) node scripts/pm/dispatch-gates.mjs --self-test -> exit 0, 'dispatch-gates self-test: 314 cases pass.' -- run because that self-test reads THIS file live as a fixture (dispatch-gates.mjs:2629 readFileSync of scripts/check-cross-package-test-inputs.mjs), not because the derivation named it. H4 evidence, grep + measurement: the only consumer that reads this gate's own source text is extractWatchHints (scripts/pm/dispatch-gates.mjs:650), which runs maskSelfTests(maskComments(scriptSource)) BEFORE extracting anything, and whose header at :503-512 states the reason outright -- 'naming a path is not reading it'; the gate's own literal collector runs over package test files and this script is not one. Measured: `node scripts/pm/dispatch-gates.mjs scripts/check-cross-package-test-inputs.mjs` produced byte-identical output before and after the edit (diff empty). No ablation: the change is comment prose, there is no assertion to falsify, and the gate's verdict/exit code/population are untouched by construction. DECLARED NARROWING: no `pnpm install` and no local eslint run in this worktree -- the diff is 5 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.mjs carries no line-length rule. CI runs the farm regardless. Baseline symmetry: gates (1) and (2) were also run BEFORE the edit and were green then too, so their green after is a no-regression reading, not a repair.",
      "open_questions": [
        {
          "question": "H3 -- you asked for my opinion in one or two sentences, and it is a question you are deciding rather than one I can settle: does 'regions git auto-merged with no conflict marker' deserve its own card as a merge-review blind spot? My opinion: I agree with the card's mechanism, and what is on main is consistent with it -- the create-objectstack twin at L393 is corrected while the @objectstack/spec copy at L141 was not, which is exactly the split you get when a resolver reviews the three-stage view and a silently merged region never enters it. What makes it worth a card is not this stale sentence but the second unmarked region you describe, the one that left the file unparseable: a blind spot that produces both a cosmetic defect and a fatal one is not a prose-hygiene problem. Stated for honesty: 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.",
          "options": [
            "A -- file it, but only with a mechanical narrowing named up front (e.g. a post-resolution step that diffs the resolved file against BOTH parents and lists regions no marker covered), so the card has an affordable remedy rather than 'read the whole merged file'.",
            "B -- file it as a plain observation with no remedy, accepting it becomes a card that documents a hazard nobody can act on cheaply.",
            "C -- do not file; treat these two instances as the cost of a rare event and let the cross-reference discipline below carry it."
          ],
          "recommendation": "A, because the generic remedy is unaffordable and a card without one will sit. If A's narrowing cannot be specified cheaply, C over B -- and in either case the cheaper, separately-actionable half is the H2 finding: the cross-reference is what rots, not the shape, so the durable discipline is '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)."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions