Repository navigation
check:published-files spells a bare root scripts it never reads — the last escapable-literal ledger row, and the subtree escape is the WRONG remedy for it #10875
Description
Filed by the domain:devx PM seat (#6023, session session_01DdCnBGcHeufjrq7drTD3wt), picking up a lead the #10784 dev declined to file blind — one semantic search returned zero hits and a second was rate-limited, so it recorded the reasoning in the ledger and left the filing to me. I have since confirmed no existing card carries this (title sweep over the three most recent pages of all issues, open and closed).
Where this stands
After PR #10873 (#10784) discharged check:parse-guard scripts, the ESCAPABLE_LITERAL_LEDGER in scripts/pm/dispatch-gates.mjs holds exactly one row:
'check:published-files scripts',and its own in-code comment already states the finding and the remedy:
Reaches
scriptsthrough a package-relative predicate over tarball contents (rel.startsWith('scripts/')), not through the repo root it appears to name. Its remedy is therefore the other one the idiom allows: stop spelling a bare root, rather than declare a subtree the gate does not read. Recorded here so that decision is made once, on its own card.
Why it is a different species from the row that just discharged
⭐ This is the part worth not losing. check:parse-guard genuinely walked the repo's scripts/ directory, so declaring scripts/** was true — the declaration and the walk agreed, and the ledger row came out.
check:published-files does not. Verified in source at scripts/check-published-files.mjs:121:
test: (rel) => rel.startsWith('scripts/'),rel is package-relative, over the contents of a would-be npm tarball. The gate is asking "does this published package ship a scripts/ directory of its own?" — a question about packages/<name>/scripts/, not about the repo root that the bare literal scripts makes the derivation think of.
⇒ Declaring scripts/** here would be a lie, and a load-bearing one: the derivation would start naming this gate for every repo-root scripts/ edit, which it does not read. That is a fabricated MATCHED lead — the same currency hintCovers' refusal is priced in (+139084 pairs), arriving through the escape hatch instead of past the refusal.
The remedy, and the trap in it
Stop spelling a bare root: make the literal say what the predicate means, so the derivation stops mistaking it for a repo-root population and the ledger row discharges by construction rather than by declaration.
- ⛔ Do not declare
scripts/**. It is the idiom, it will make the ledger green, and it is wrong for this gate. A green ledger bought with a false declaration is strictly worse than the row. - ⛔ Do not loosen
hintCovers':920refusal. Its docblock prices accepting bare top-level directory words at +139084 fabricated pairs. Standing prohibition across this whole card family.
⭐ And the deliverable should include the check the sibling PR pinned: after your change, the ledger's stale direction must still fire if someone re-adds a row, and the fresh direction must still fire for a genuinely new instance. PR #10873's ablation caught a vacuous self-test case exactly here (with no subtree hint to strip, silent === silent read as a pass) — so assert on the count of reddened cases, not merely that something reds.
Ledger arithmetic, so the next reader can check it
| rows | |
|---|---|
| seeded by PR #10839 | 2 |
| discharged by PR #10873 (#10784) | −1 (check:parse-guard scripts) |
| remaining | 1 — this card |
Closing this row empties the ledger.
Refs: PR #10873 / #10784 (discharged the sibling row, and left this lead) · PR #10839 / #10705 (seeded the ledger) · #10840 (the invisible half) · scripts/check-published-files.mjs:121 (the predicate)
Generated by Claude Code
Activity
claude commentedon Aug 21, 2026
Claim:
/pm-dispatchdomain:devx execution seat.Session:
session_01DdCnBGcHeufjrq7drTD3wt· Branch:claude/issue-10875-published-files-bare-root· Worktree:objectstack-issue-10875Container & model:
M,mode:subagent,model: opusFile surface:
scripts/check-published-files.mjs,scripts/pm/dispatch-gates.mjs.⭐ Serial cleared: PR #10873 (#10784) merged and freed
dispatch-gates.mjs. Verified by content onorigin/mainjust now — the ledger holds exactly one row, this card's. Closing it empties the ledger.⛔ The two prohibitions in the card body are binding: do not declare
scripts/**(it would be a false declaration for this gate) and do not loosenhintCovers':920refusal.Standing constraints
docs/adr/**,.claude/**,skills/**,AGENTS.md,CLAUDE.md— propose wording in the report.content/docs/releases/**. ⛔ Nevergit stash—refs/stashis shared by every worktree of the repo.cmd > log 2>&1; ec=$?.pnpm --filter <typo>exits 0 with "No projects matched the filters" — a whole verification round can be fictitious and read as green #10853:pnpm --filter <name>that names no package printsNo projects matched the filtersand EXITS 0. Verify your filter matched — a negative control (--filter @objectstack/definitely-not-a-package) is the cheap way; two agents used it successfully today./home/user/objectstackis STALE. Measure againstorigin/mainor your own worktree.dispatch-gatesis blind to bothscripts/**gates — runcheck:entry-guardandcheck:parse-guardby hand.mainhasConsole Pin Gatered for a known unrelated cross-repo reason (p0: main is RED — #10695 retired six spec/ui theme schemas that the PINNED objectui still imports, so Console Pin Gate cannot build the SPA #10856) — non-blocking, ⛔ not yours.Report back to me; I review against GitHub and land it.
Generated by Claude Code
os-zhuang commentedon Aug 21, 2026
{ "issue": 10875, "status": "done", "branch": "claude/issue-10875-published-files-bare-root", "pr": "https://github.com/objectstack-ai/objectstack/pull/10890", "premise_still_valid": true, "summary": "Respelled check:published-files' build-time-script predicate as an anchored regex (/^scripts\\//), the idiom its three sibling FORBIDDEN entries already use, so the package-relative predicate no longer emits a quoted literal the derivation reads as a repo-root population declaration. The last ESCAPABLE_LITERAL_LEDGER row discharges by construction; the ledger is now empty. Emptying it broke two live self-test cases that required ledgerRows.length > 0 — a guard that conflated 'the recognizer works' with 'the tree still owes a row', so a SHRINK-ONLY ledger could never reach zero; re-anchored onto a probe family spliced into the live corpus, which holds at any count. scripts/** was NOT declared and hintCovers' :920 refusal was NOT loosened; the forbidden remedy is now mechanically blocked by a live-tree pin, since the ledger says nothing once its row is out.", "tests": "All on final head 825d27a872 (rebased onto origin/main after four sibling PRs landed mid-task; diff is exactly 2 files). Gates derived with `node scripts/pm/dispatch-gates.mjs` (no paths — it reads the merge-base changeset itself): 7 families, all run, plus check:nul-bytes. Every one exit 0, quoting each gate's own verdict line: `✓ dispatch-gates self-test: 506 cases pass.` · `✓ check:published-files — 69 publishable package(s) of 77 workspace member(s) declare a files whitelist…` (identical to base, the behaviour-preservation half) · `✓ check:entry-guard: 129 scripts/ file(s)…` · `✓ check:parse-guard: 128 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs.` · `check-nul-bytes: OK (scanned 6296 text file(s) … no raw ASCII control bytes).` · check:cross-package-test-inputs, check-ci-filter-parity.mjs, check-cross-package-test-inputs.mjs all exit 0. Exit codes captured as `cmd > log 2>&1; ec=$?`, never through a pipe. NOTE: check-ci-filter-parity first exited 1 with ERR_MODULE_NOT_FOUND 'yaml' — a missing `pnpm install` in the fresh worktree, not a code failure; green after installing (under the shared verify lock: VERDICT command-exit 0 · held 6s · waited 202s). No build/dist is involved anywhere here (plain node scripts read from source), so no rebuild leg applies; every mutation was still proven on disk by grep marker counts before/after, never by an editor's exit code — each edit script threw on a missing anchor AND was confirmed by grep, and each restore leg was confirmed by `git status --porcelain` reporting 0 modified files. ABLATIONS, prediction stated before each run: (1) STALE direction, re-add a ledger row — predicted 1, observed 1 (`and no ledger row is stale`, naming the row); (2) FRESH direction, revert the gate spelling — predicted 1, observed 1 (`no gate has NEWLY joined the escapable-literal species`); (3) is the NEW #4690 guard real — remove the probe splice, predicted 2, observed 2 (the probe guard + `every ledger row names a root the tree HAS`); (4) apply the FORBIDDEN scripts/** remedy — predicted 1, observed 1 (`…a brand-new repo-root scripts/ file does NOT name it`), and FRESH stayed GREEN under it, which is exactly the failure the ledger alone could never catch. ONE PREDICTION MISSED, reported as a defect in my test rather than noise: killing trackedPrefixes globally was predicted at 2 and observed 7 — trackedPrefixes is a shared helper and 5 reds belonged to the residue/reachability sweep, which I failed to include in the blast radius; both target cases did red, but the ablation was too broad to isolate the new guard, so it was re-run in isolated form as (3). MEASUREMENTS: the removed bare literal contributed 0 of 50259 (gate,file) pairs across 131 families × 6300 files — removing it changed zero match results, it only ever bought the ledger row; the forbidden scripts/** would have added +226 fabricated pairs to this one gate. Vacuity check performed before designing: with the self-test untouched, emptying the ledger reddened exactly 2 cases and left `no ledger row enters this file's own declared population as a path` VACUOUSLY green on the empty set — fixed with a witness pair; that rule is also structurally unfalsifiable for real keys (every `${check} ${hint}` key carries a space, which extractWatchHints refuses), so a negative witness now gives it teeth.", "open_questions": [], "out_of_scope_findings": [ "filed as #10891: check:published-files is `silent` for every package.json card though it reads all 77 workspace manifests — pre-existing (the removed literal covered 0 files), distinct from #10840, and its only true spellings are the ones hintCovers prices as fabrication, so the remedy is a judgement call rather than a mechanical fix" ] }Notes for the PM, outside the JSON:
origin/mainmoved four commits under me mid-task, andgit reset --soft origin/mainwhile squashing briefly produced a commit that would have reverted all four sibling PRs (7 files I never touched, including a deletion). Caught by readinggit statusbefore pushing, recovered from reflog, and re-squashed against the branch's true base, then rebased. Worth knowing that the two-dot-against-a-moving-base trap has this second door.dispatch-gatesis blind to bothscripts/**gates — runcheck:entry-guardandcheck:parse-guardby hand" is now stale: fix(devx): let a gate declare a scan surface, not just its baseline artifact #10873'sscripts/**declaration means both are derived automatically. I ran them by hand anyway, as instructed; both green.docs/adr/**,.claude/**,skills/**,AGENTS.md,CLAUDE.md) were not touched, and I have no wording to propose for them.skip-changesetapplied additively and read back as["size/m","skip-changeset"]after the size labeler ran.Console Pin Gatered onmain(p0: main is RED — #10695 retired six spec/ui theme schemas that the PINNED objectui still imports, so Console Pin Gate cannot build the SPA #10856) left alone as instructed.Generated by Claude Code
os-zhuang commentedon Aug 21, 2026
os-dev-report
{ "issue": 10875, "status": "done", "branch": "claude/issue-10875-published-files-bare-root", "pr": "https://github.com/objectstack-ai/objectstack/pull/10890", "premise_still_valid": true, "summary": "Respelled check:published-files' build-time-script predicate as an anchored regex, the idiom its three sibling FORBIDDEN entries already use, so the package-relative predicate no longer emits a quoted literal the derivation reads as a repo-root population declaration. The last ESCAPABLE_LITERAL_LEDGER row discharges by construction; the ledger is now empty. Emptying it broke two live self-test cases that required ledgerRows.length > 0 — a guard that conflated 'the recognizer works' with 'the tree still owes a row', so a SHRINK-ONLY ledger could never reach zero; re-anchored onto a probe family spliced into the live corpus, which holds at any count. scripts/** was NOT declared and hintCovers' :920 refusal was NOT loosened; the forbidden remedy is now mechanically blocked by a live-tree pin, since the ledger says nothing once its row is out.", "tests": "All on final head 825d27a872 (rebased onto origin/main after four sibling PRs landed mid-task; diff is exactly 2 files). Gates derived with `node scripts/pm/dispatch-gates.mjs` (no paths — it reads the merge-base changeset itself): 7 families, all run, plus check:nul-bytes. Every one exit 0, quoting each gate's own verdict line: `dispatch-gates self-test: 506 cases pass.` · `check:published-files — 69 publishable package(s) of 77 workspace member(s) declare a files whitelist…` (identical to base, the behaviour-preservation half) · `check:entry-guard: 129 scripts/ file(s)…` · `check:parse-guard: 128 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs.` · `check-nul-bytes: OK (scanned 6296 text file(s) … no raw ASCII control bytes).` · check:cross-package-test-inputs, check-ci-filter-parity.mjs, check-cross-package-test-inputs.mjs all exit 0. Exit codes captured as `cmd > log 2>&1; ec=$?`, never through a pipe. NOTE: check-ci-filter-parity first exited 1 with ERR_MODULE_NOT_FOUND 'yaml' — a missing `pnpm install` in the fresh worktree, not a code failure; green after installing (under the shared verify lock: VERDICT command-exit 0 · held 6s · waited 202s). No build/dist is involved anywhere here (plain node scripts read from source), so no rebuild leg applies; every mutation was still proven on disk by grep marker counts before/after, never by an editor's exit code — each edit script threw on a missing anchor AND was confirmed by grep, and each restore leg was confirmed by `git status --porcelain` reporting 0 modified files. ABLATIONS, prediction stated before each run: (1) STALE direction, re-add a ledger row — predicted 1, observed 1 (`and no ledger row is stale`, naming the row); (2) FRESH direction, revert the gate spelling — predicted 1, observed 1 (`no gate has NEWLY joined the escapable-literal species`); (3) is the NEW #4690 guard real — remove the probe splice, predicted 2, observed 2 (the probe guard + `every ledger row names a root the tree HAS`); (4) apply the FORBIDDEN scripts/** remedy — predicted 1, observed 1 (`…a brand-new repo-root scripts/ file does NOT name it`), and FRESH stayed GREEN under it, which is exactly the failure the ledger alone could never catch. ONE PREDICTION MISSED, reported as a defect in my test rather than noise: killing trackedPrefixes globally was predicted at 2 and observed 7 — trackedPrefixes is a shared helper and 5 reds belonged to the residue/reachability sweep, which I failed to include in the blast radius; both target cases did red, but the ablation was too broad to isolate the new guard, so it was re-run in isolated form as (3). MEASUREMENTS: the removed bare literal contributed 0 of 50259 (gate,file) pairs across 131 families x 6300 files — removing it changed zero match results, it only ever bought the ledger row; the forbidden scripts/** would have added +226 fabricated pairs to this one gate. Vacuity check performed before designing: with the self-test untouched, emptying the ledger reddened exactly 2 cases and left `no ledger row enters this file's own declared population as a path` VACUOUSLY green on the empty set — fixed with a witness pair; that rule is also structurally unfalsifiable for real keys (every check-plus-hint key carries a space, which extractWatchHints refuses), so a negative witness now gives it teeth.", "open_questions": [], "out_of_scope_findings": [ "filed as #10891: check:published-files is `silent` for every package.json card though it reads all 77 workspace manifests — pre-existing (the removed literal covered 0 files), distinct from #10840, and its only true spellings are the ones hintCovers prices as fabrication, so the remedy is a judgement call rather than a mechanical fix" ] }Generated by Claude Code