Uh oh!
There was an error while loading. Please reload this page.
feat(pm): bound the escapable-literal species with a shrink-only ledger - #10839
Conversation
A gate whose declared population is a bare top-level word the tree HAS is unnameable by any dispatch derivation and lands already invisible: hintCovers refuses a separator-less literal as too generic, a refusal measured at +139084 fabricated pairs that stays. The escape is the ROOT_DIR_WATCH_HINTS subtree declaration, but nothing tracked who still needed to take it -- six instances were found one at a time on six unrelated cards, the sixth a re-discovery of the fourth. Enumerate the species and refuse new members, mirroring KNOWN_IMPORT_UNSAFE: shrink-only, fresh and stale both fail, and the one remedy is named in the failure text. check:pm-dispatch-gates runs the self-test on every PR, so a gate written tomorrow fails at authoring time instead of landing silent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
✅ ACCEPT — reviewer of record: |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32489707921 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes#10705
A gate whose declared population is a bare top-level word the tree has is unnameable by
any dispatch derivation and, in
check-plugin-teardown-shape.mjs' words, "lands alreadyinvisible".
hintCoversrefuses a separator-less literal as too generic; that refusal ismeasured at +139084 fabricated pairs and is untouched here. What was missing is any record
of which gates still need the escape.
Re-measured on today's
main, not taken from the cardThe card's 4-row table was measured at
47cd3ec1f8. Branched froma7ea3289eb, the residueblock reports 3 unreachable-by-construction families, not 4:
check:driver-memory-census@objectstack/driver-memorycheck:parse-guardscriptscheck-test-completeness.mjs@objectstack/*namesThe
check:examples-live-imports/examplesrow is discharged: #10314 landed at 10:29Zand that gate now carries
ROOT_DIR_WATCH_HINTS = ['examples/**']. The ledger reflects thelanded state rather than re-listing it.
The silent-bucket remainder, enumerated
The card asked for the escapable shape living inside the
silentbucket (84 of 128 families),"where the unbounded remainder is". Swept with the tool's own predicates, the class is 4
literals, two of which the card never named:
check:examples-live-importsexamplesexamples/**(#10314)check:pm-governed-mergesskillsskills/**check:parse-guardscriptscheck:published-filesscriptscheck:published-filesis the row that forced a design decision. It namesscripts/check-published-files.mjs, whichhintCoversaccepts against the bare directoryscriptsthrough its reverse-containment branch while covering no other file under that root.Treating that as an escape would retire a row for a gate still unnameable for every card under
the root it appears to declare — so escape is tested as
collapseHint(sibling) === plain,the same population declared as a subtree, and nothing weaker.
What landed
discoverFamilies()lifted out ofderive(). The ledger asks the same question thederivation asks, from the same implementation — a second discovery pass would let the two
disagree, and a ledger enumerating a population no dispatch prompt is derived from is the
drift this file refuses everywhere else. Output is byte-identical to pre-refactor.
escapableLiteralRows()— the species, stated ashintCovers' own two refusal conditionsplus
deepestTrackedPrefix(hint) === plain(which is exactly howunreachableReasonalreadyseparates this species from the dead one).
ESCAPABLE_LITERAL_LEDGER— ⛔ shrink-only, mirroringKNOWN_IMPORT_UNSAFE(check-entry-guard: reject an exporting scripts/ file whose top level runs on import #10665): freshand stale both fail, the one remedy is named in the failure text, and a new line is
explicitly not the remedy.
check:pm-dispatch-gatesruns that self-test on every PR with no pathfilter, so a gate written tomorrow that spells a bare root word fails at authoring time
instead of landing silent. That is the prospective half the six historical instances could
not fix, since each was archaeology.
The
:920refusal is not touched —hintCoversis byte-identical tomain, verified bydiffing the function body; the sole deleted line in this PR is
derive's own signature, movedby the refactor.
Reverse verification
Three legs, each confirming the mutation reached disk before the result was read (
grep -con the edited text, both directions). No build step is involved: the tool is a
.mjsrunfrom source, so there is no
dist/for a stale artifact to hide in.no gate has NEWLY joined … — FRESH: check:parse-guard scripts· exit 1and no ledger row is stale — STALE: check:invented-by-the-ablation scripts· exit 1check-parse-guard.mjsgivenROOT_DIR_WATCH_HINTS = ['scripts/**'](0 → 1)matched via … ⇢ gate source 'scripts/**'; unreachable-by-construction drops 3 → 2Leg C is the discharge path end to end: a gate that takes the escape leaves the ledger and
becomes nameable in the same step. Every restore leg was re-confirmed on disk and re-run green
(474 cases).
What this bounds, and what it does not
The ledger bounds every literal that reaches the hint set, which needs a separator in the
source spelling (
'scripts/'trims toscripts). It does not see a gate that spells itsroot with no separator at all (
const POPULATION = 'packages') —looksPathybuilds no hint,so it is invisible to the derivation and to the ledger. That is the same remainder #10107
recorded for the directory half, and it is filed separately with its measurement rather than
guessed at here: a sweep wide enough to catch it was measured at 73 (family, word) pairs
across 52 of 128 families, overwhelmingly
join(ROOT, 'packages', …)path components — the+139084 fabrication re-introduced one level up. That half stays with each gate's own
ROOT_DIR_WATCH_HINTSdeclaration and self-test, because only the gate knows its realpopulation.
Gates — verdict lines, all at
5144b50dbbDerived with
node scripts/pm/dispatch-gates.mjs(no paths; merge basea7ea3289e), plus thetwo the derivation is structurally blind to, run by hand.
Each exit code was captured as
cmd > log 2>&1; ec=$?before any pipe.No changeset
scripts/**is build-time tooling and reaches no tarball —check:published-filesenforcesexactly that. Unanimous precedent: 12 of the last 12 scripts-only merges carry no changeset,
including #10314's and #10662's own fixes for this very class. Labelled
skip-changeset.Generated by Claude Code