Uh oh!
There was an error while loading. Please reload this page.
fix(pm): read decorated Restart-when: / Blocked-by: directive lines, and stop prescribing a close for an unparsed one - #10204
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019T1sSZbQTnLhrK9HhNdNiB
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019T1sSZbQTnLhrK9HhNdNiB
This was referenced Aug 20, 2026
qq9340100
marked this pull request as ready for review
August 20, 2026 13:57
qq9340100
enabled auto-merge
August 20, 2026 13:57
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 20, 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#10102
Ruled scope: option C (tolerate decoration AND soften the remedy text), plus the channel-asymmetry documentation from the round-30 comment.
The defect
Restart-when:andBlocked-by:are machine-readable lines written by hand in markdown, so authors code-format them. The old anchors (^\s*for H9,^[ \t]*for H4/H14) accept only whitespace before the key, and a backtick is not whitespace — so a decorated directive read as an absent one. Two confirmed instances, on both predicates, failing in opposite directions.I measured both against the live, unedited card bodies (fetched from the API, run through the predicate at
origin/main33024d9 and at this branch):pm:on-hold)`Restart-when: the v18 major development cycle opens …`Restart-when:body line"the v18 major development cycle opens (…)with no trailing backtickpm:blocked)`Blocked-by: #9612`hasBlockedByLinefalse, index targets[]{repo: null, number: 9612}Neither card was edited — the ruling forbids appeasing the scanner, and the point is that both were correctly authored all along.
The two harms want different urgencies, which is why B alone was insufficient: the first is loud and destructive (H9's own remedy text told the reading seat to close a maintainer-commissioned card), the second is silent and permanent (the unlock sweep greps that same literal, so nothing could ever have returned the card — no row, no alarm, no expiry, and no detection channel of its own).
What changed
1. One shared decorated-directive reader (
directiveValues), used by H9,blockedByTargets(the H14 index) andhasBlockedByLine(H4) — so a decoration tolerated for one is tolerated for all. This deliberately includes the comment-channel read H4 gained from PR #10075: it goes through the same two functions, so fixing only the body read would have propagated the blindness into the newer surface.Tolerated: indentation, one
-/*list bullet, and any run of`/**markers — including**Blocked-by**:,**Blocked-by:**and`Blocked-by:`(the marker may sit either side of the colon). A trailing marker matching one that opened the line is stripped from the captured value.Deliberately not tolerated, and pinned as negatives: the key's spelling and case (the unlock scan greps the literal, so
restart-when:must still flag); a bullet without its space (-Blocked-by:is a word, not a list item); anything mid-sentence (the prefix stays line-anchored, so 「seats park the`Blocked-by: #1`line in comments」 is still prose); and a line whose "value" is only its own closing marker — the extractor drops empties after cleaning, because stripping can empty a value.2. H9's remedy text is re-ordered: verify → unwrap → add → and only then close. Tolerating decoration removes the measured cause but cannot remove the class — any future unparsed spelling produces the same "no line" row — so the row now names the possibility it cannot rule out ("a line that IS there but which this scan cannot parse looks exactly like an absent one") instead of offering a close as a co-equal branch. The
manualrow deliberately carries no such hedge: a line was read there, and hedging the one row that really does mean "this hold has no exit" would make it read as uncertain.3. The channel asymmetry is documented rather than closed — my call, per ruling item 3. H4/H14 read body OR comment; H9 reads the body only. Documenting, because (a) H9's body-only read is correct on its own terms: the unlock scan greps issue bodies, so a condition parked in a comment genuinely does not exist to the machinery, and that population is exactly what H9 exists to surface — widening it would hide it; (b) H4's widening rests on a measurement H9 has no counterpart for (26 of 40 blocked cards body-clean, 2026-08-19) plus a sweep taught to read both; (c) the LOCATION half of this family belongs to #8941, which is explicitly not closed by this card and is not closed by it here either. It is stated in three places: the H4/H9 header rows, both predicates' section docs, and — because a code comment does not reach the seat reading a row — in H9's finding sentence itself. The stale claim that H9 used "the same single body channel" as
Blocked-by:is corrected; it had been false since PR #10075 landed.Tests
scripts/pm/check-half-states.mjsself-test: 489 → 558 cases (+69), green at781690e.Every decoration has a positive and a negative case, on each reader it reaches (
directiveValues, H9, H4 body, H4 comment,blockedByTargets,commentBlockedByTargets). #9591's line is pinned by its measured shape, and #10063's likewise.Three separate ablations, each mutated and restored with the change confirmed on disk by grep before and after (no build step — this is a plain
.mjsthe self-test runs directly):`/**, and a valueless`Restart-when:`returnsnull— a false clear on a hold with no exitThe third is the one worth reading: it shows the strip is not cosmetic. Without it, decoration tolerance would have traded a false positive for a false negative on the same predicate.
One pre-existing test was made non-throwing (
[0].repo→.map(…).join(',')): an assertion that throws when the reader returns nothing aborts the whole self-test and hides every case after it, which is exactly what a regression in this reader produces. The first ablation run hit that and reported one crash instead of 27 failures.Gates
Re-derived on the actual diff with
node scripts/pm/dispatch-gates.mjs(no paths passed — it takes its own change set from the merge base), run at781690e:pnpm check:pm-half-states—✓ check-half-states self-test: 558 cases pass.pnpm check:cross-package-test-inputs—OK: 12 package(s) read outside themselves, all declared…pnpm check:partof-closing-keyword—✓ check-partof-closing-keyword self-test: 28 cases pass.pnpm check:nul-bytes—check-nul-bytes: OK (scanned 6074 text file(s)…; no raw ASCII control bytes).node scripts/pm/check-half-states.mjs(half-state-patrol.yml), is the live sweep and cannot run in this container — it exits 3 withPREREQUISITE NOT MET — the token in the environment is not a valid GitHub credential. That is an environment limit, not a result. Its substance is covered another way above: I fetched #9591 and #10063 anonymously and ran the changed predicates against those real bodies directly.No changeset —
scripts/pm/is internal agent tooling and publishes nothing user-visible (skip-changeset).Not in this PR
os migrate meta --write— the AST codemod that rewrites authored sources for the mechanicalappliedset (v18) #9591 and The draft→active promotion door cannot state its write's package, so #9612's package-closure narrowing never fires forpublishMetaItem#10063 are left exactly as their authors wrote them.Blocked-by:lines in COMMENTS — blocked cards go invisible and sat 24h+ past discharged upstreams #8941 (directives parked in a comment rather than the body) is the location half of this family and stays its own card; neither closes the other.Generated by Claude Code