Uh oh!
There was an error while loading. Please reload this page.
feat(pm): H17 — render the on-hold trigger-file index on the patrol anchor - #10041
Merged
Conversation
os-warren
marked this pull request as ready for review
August 19, 2026 18:25
os-warren
enabled auto-merge
August 19, 2026 18:26
This was referenced Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#10034
Adds H17 — the on-hold trigger-file index to
scripts/pm/check-half-states.mjs: a report-only section on the patrol anchor listing, for every openpm:on-holdcard, the repo-relative files its hold comment(s) or body name as opportunistic-restart triggers.Why the patrol side, not
dispatch-gates.mjsThe card's direction ① as-written (teach the dispatch gate to grep hold comments) is rejected for transport reasons, per the PM's direction comment.
dispatch-gates.mjsruns in a seat container, whose live GitHub read is 403 — measured again on this branch:Building the intersection there would re-create the disease one layer down: a second mechanism that cannot execute. The patrol runs on a runner where the transport prerequisite is met, so it gathers and renders; the dispatching seat reads the result during the "read the anchor first" step it already performs. Zero new seat-side dependency.
The census that decided the branch (mandatory step 1)
Nine cards' hold comments/bodies were read live before any code was written. Seven carry a trigger-file clause, and all seven name their paths as backticked repo-relative paths that exist in the tree — so a high-precision deterministic extraction is possible, and this PR takes branch 2, not branch 3.
Named restart conditions: ①…— anchor and path on one line**Restart condition (trigger files):**3. **opportunistic:** …**Trigger file: …**inside a numbered item**Trigger files** (opportunistic-restart clause)— in the card body, which has zero comments**Opportunistic trigger files**, blank line, then a bullet listRestart-whencard-closure holds)No card uses a canonical machine-readable prefix. So the extractor reads the prose shapes that exist and the proposed canonical
Restart-touch:channel (zero live matches today by design — the mechanism precedes the convention, so no second change is owed the day a hold is written with it). That is branch 3's deliverable folded in for free, since its mechanism is a strict subset of branch 2's.Extraction — deterministic, and it drops what it cannot verify
Two closed stages, no fuzzy parsing and no LLM in the loop:
trigger file,opportunistic,restart condition) or a canonicalRestart-touch:line. ⛔rideris deliberately excluded — it is the word the audit and release comments use, and admitting it would render dead triggers as live ones (measured on lint.yml's "Build the ledgered packages' dependencies" step duplicates the closure refresh once #8330 lands #8331's release comment, which contains a tracked path and nominates nothing).git ls-files. A token that is not a tracked file is dropped, never guessed at. The measured decoys this removes are real:Field([spec] 13 of 49 declared field types have noField.*builder, so authors silently drop to the literal{ type: … }form #8656),FIXTURE_CAPTURED_NEGATED(finding: check-where-matcher-conformance cannot grade an INVERTED survivor filter — the control probe drops it, so a delete double's combinator blindness stays ungraded #8662), andpath.mjs:1679line-suffixed citations.The index therefore under-reports and never invents. That error direction is deliberate: a missing row costs a seat the intersection it would not have had anyway, while a wrong row sends it to intersect against a file nobody nominated — the original defect wearing a new mask.
Report-only, no labels, no thresholds, and it can never produce a finding: a hold naming trigger files is a hold in good standing. The only bound is a render budget (
H17_INDEX_ROW_CAP), the same class of constant asMARKDOWN_BODY_BUDGET.End-to-end on the real census data
Driving the shipped exported functions over the seven cards' verbatim text against the real 6,360-file oracle:
11 paths, zero decoys, and #9276 correctly contributes nothing.
Reverse verification — directions predicted in writing, then driven
No rebuild leg exists to declare: node executes this
.mjssource directly, so there is nodist/layer an ablation could measure the wrong side of.opportunisticfrom the anchor setgit ls-filesvalidationpath:linecitation, the untrackedRestart-touch:value⭐ The fence ablation is the one worth reading. It came back green, which falsified my own test rather than the code: the fixture used #8656's verbatim
path:linecitations, and the:234suffix already fails the tracked-file check on its own — so the case was measuring the oracle while vouching for a fence parser it never exercised. A bare path in a fence does not exercise it either (nothing unbackticked is ever harvested). The shape that actually needs the strip is the one these threads are full of: a comment quoting a prior comment wholesale, anchor term and backticks included. Rewritten to that shape, the ablation turns red with the exact wrong-inheritance value (packages/spec/src/data/field.zod.tsattributed to the quoting card). The fixture and the reasoning are recorded in the test.That pass also surfaced a real under-report — a path on a hard-wrapped continuation line is not harvested — recorded as a stated boundary rather than fixed, since widening the scan would re-admit the prose it bounds away.
Gates
All at
08664f256, exit codes captured by redirecting to a file and reading$?before any pipe.node scripts/pm/dispatch-gates.mjs(no args, real diff) — re-derived at the final commit; 1 path, 6 families, added nothing beyond the dispatched list.pnpm check:pm-half-states—✓ check-half-states self-test: 414 cases pass.pnpm check:partof-closing-keyword—✓ check-partof-closing-keyword self-test: 28 cases pass.pnpm check:cross-package-test-inputs—OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.node scripts/check-cross-package-test-inputs.mjs— same verdict line, exit 0.pnpm check:nul-bytes—check-nul-bytes: OK (scanned 6355 text file(s) ... no raw ASCII control bytes).node scripts/check-partof-closing-keyword.mjs— exit 2,NOT WIRED. That is the CI-only entry point, which requiresPR_BODY/PR_NUMBERfrom its workflow and says of itself that it is "a wiring or usage failure, NOT a verdict". This body was separately run through it withPR_BODYset, and it passed.node scripts/pm/check-half-states.mjs(live sweep) — cannot run in this container by construction (exit 3, transport prerequisite). It is the gate whose unavailability this PR is about.Self-test: 352 before → 414 after (+62), all H17: the seven measured clause shapes, both negative-census cards, the decoy drops, the anchor-set exclusion of
rider, the fence quote, the canonical channel including its case-sensitivity, the continuation bounds, the gathering policy, row assembly, and both renderers in all three of the section's states (rows / read-and-empty / oracle-unreadable).No changeset: this publishes nothing (one PM tooling script).
skip-changesetapplied and read back.Generated by Claude Code