feat(pm): report a [Decision]-titled card sitting in the dispatch pool (H54) - #17197
Conversation
…ool (H54) `pm:queue` is the dispatch pool: a PM seat reads it as capacity and picks from it. A card whose title opens `[Decision]` declares its deliverable is a ruling, and a PM seat may not rule a contract or product decision — so the one act the pool invites is the one act forbidden on that card. The filing card measured the cost on one lane twice: 8 read as dispatchable and 1 was, then 21 read and at most 3 were. H54 is a report-only row over the `pm:queue` label page this sweep's loop already consumes: one label and one title, both fields of a payload already paid for, so the row costs no request and its population is covered by construction. It fires on an OPEN issue (never a PR, never a closed card) carrying `pm:queue` whose title, after optional leading whitespace, begins with `[Decision]` — anchored at the start, never a substring. The row reports the DISAGREEMENT between two carriers and hands it to the triage seat, which owns the second one. It never relabels, never treats the prefix as the state (the prefix is the filer's, the state is triage's), and needs no new label: the vocabulary already carries the state. H26's deferred-target note said this shape was deliberately not reported because a title heuristic would make the sweeper guess at intent. That stance was about H26 inferring a block's fate from its target's title and it stands — H26 is not widened. Both prose sites now point at H54 so the file does not contradict itself; two self-test cases pin the pointers and pin that H26's own criterion survives at both. Self-tests: 43 cases — a positive control plus six negatives that each differ from it in exactly one feature, driven over a length-pinned table so a fixture that stops being exercised fails. Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ Co-authored-by: Claude <noreply@anthropic.com>
|
CI disposition (skills seat, session Generated by Claude Code |
Fixes #16688
One report-only row in
scripts/pm/check-half-states.mjs. No new label, no vocabulary change, no workflow change, no exit-code change, and ⛔ no live card relabelled.What the row is
H54 — an OPEN issue (⛔ never a PR, ⛔ never a closed card) carrying
pm:queuewhose title, after optional leading whitespace, begins with[Decision].pm:queueis the dispatch pool: a PM seat reads it as capacity and picks from it. A card whose title opens[Decision]declares its deliverable is a ruling, and 「⛔ PM 席不得裁决契约或产品决定」 — so the one act the pool invites is the one act forbidden on that card. The filing card measured the cost on one lane, twice: 8 read as dispatchable and 1 was (2026-09-07), then 21 read and at most 3 were (2026-09-09).This is exactly the shape triage's acceptance criterion names (§验收口径 2 on #16688): 「一张标题以
[Decision]开头的卡带着pm:queue」 — 「最便宜的一道网」.⛔ The prefix is not the state
The same ruling fences the row in the same breath: 「⛔ 不要把闸门做成"标题前缀即状态":前缀是作者写的,状态是分诊判的,让前者决定后者就是把分诊席的职责交给了立卡人」.
So the row reports the disagreement between two carriers and hands it to the seat that owns the second one. It does not say which carrier is wrong. Its remedy names the reader — the triage seat, who re-judges the card:
pm:queuestands as it is;needs-user-decision, carrying its four-facet analysis at the moment the label lands.⛔ No new label is needed or wanted (§验收口径 1):
needs-user-decisionis live on cards and PRs,pm:awaiting-maintaineris live on cards, and the ruled deliverable is 逐卡改判.The row also declares what it cannot see, so a reader does not over-trust it: a hot-file hold releases on MERGE, a contract-review-tier wait shows in no carrier at all, and a ruled card keeps its prefix until someone edits the title. ⛔ None of those is readable from a title or a label, and none is claimed.
Reconciling the file's own prose (⛔ H26 is NOT widened)
The deferred-target row said this shape was 「deliberately NOT reported … a title heuristic would make this sweeper guess at intent」, at two sites — the header block and the predicate's own comment. That stance was about H26 inferring a BLOCK's fate from its TARGET's title, and it stands: H26 still reads labels only, and is not widened to chase it. Both sites now point at H54 so the file does not contradict itself.
Two self-test cases pin the reconciliation off the source: both sites carry the pointer, and both still carry H26's own criterion. The needles are assembled at runtime so the cases cannot satisfy themselves out of their own source text.
Placement
Band
state, by the file's own band criteria — two carriers on one live card contradicting each other, the whole repair on the board in one seat's judgement. ⛔ Notgate(that band is for an ABSENCE reading as a green light; here both carriers are present). ⛔ Notstall(whether any of these cards is actually stopped is UNMEASURED by this row — the filing thread's own correction found the lane's binding constraint to be contract-review-tier headroom, not rulings). ⛔ Notinventory(it alarms about one card). No new band, no new render section, no reservation change.Quota: free. The carrier holds
pm:queue, which is a label page the sweep's loop already consumes, and the title rides in on the same payload — so the population is covered by construction and no card outside the listing can reach the row.Mechanism assumptions, measured
^\[PM seat\] …regex for seat stickers — a[PM seat]-specific parser, not a general bracket-prefix helper, and there is no[finding]reader at all. So there was nothing to reuse; H54 declares its own anchoredDECISION_TITLE_PREFIXbeside the row it serves. ⛔ The three[PM seat]sites are left alone — refactoring them is not this card./^\s*\[decision\]/iu, with[Decision]later in a title pinned silent.HALF_STATE_FAMILY_BANDdecides render order and trim survival, and the file states a placement rulewhatfield written to be read before placing a new family;stateis the one that fits, so the fallback ("take the lowest band and say so") was not needed.7337179dis the newest touch and the baseorigin/mainhad advanced toc3756ff0by the time the worktree was cut (four docs commits plusscripts/pm/check-skill-line-ratchet.mjs); none touches this file. Branched fromc3756ff0.Reading the case sensitivity, stated rather than assumed
The matcher is case-insensitive on the word and exact on the brackets.
[decision]and[Decision]are one author's one intent, and this file's standing doctrine is that an unknown reading must never present as a clean one (#4690) — a carrier missed on its capitalisation reads as a clean queue. It widens nothing that matters:[finding], the 80-strong prefix that must never be caught, differs in the word, not in its case; and the closing bracket is required immediately after the word, so[Decisions log]and[Decision-log]are not this prefix. All four are pinned.Tests
node scripts/pm/check-half-states.mjs --self-test— 3019 cases pass (2976 before; +43). The 43 are a positive control, six negatives each differing from it in exactly one feature (no prefix · a[finding]prefix ·[Decision]withoutpm:queue· closed · a PR ·[Decision]later in the title), driven over a length-pinned table so a fixture that stops being exercised fails; plus anchor, population, adjacency (H24/H3/H45 all silent on the specimen), row-text, band/registry and reconciliation cases.Ablation, once, on the committed implementation and reverted in the same run — evidence in the report.
Every gate
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives for this diff was run; verdict lines are quoted in theos-dev-reportcomment on #16688.Acceptance notes
⛔ Observed, not this card's, and ⛔ not filed:
5600821612/5600838579/5601308373: the over-read is real, but on the measured lane its largest bucket is not "cards nobody has judged" — it is cards that were judged correctly and cannot move because the contract-review tier that must review them is unavailable (8 cards against 2 genuinely awaiting a ruling). A carrier that distinguished "queued" from "awaiting judgement" would still show all 8 as ready. H54 does not claim otherwise and says so in its own sentence.pm:queueunder-reads as well as over-reads (5600838579): two cards were dispatchable only in part, or only after a ruling, and neither fact is recoverable from the label.[PM seat]title parsers are the same regex written out three times. A cleanup, not a defect: nothing misreads today. ⛔ Not filed; ⛔ not touched. Carrier: whoever next changes the seat-sticker title shape.Landing
Draft.
scripts/pm/**with no.mdin the diff ⇒ not a governed surface, but the PM flips ready after the in-seat review. No changeset:scripts/pmis not a package and nothing published moves — the changeset gate's verdict is quoted in the report.🤖 Generated with Claude Code
https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
Generated by Claude Code