Repository navigation
pm-dispatch: a contract-review verdict without the label handoff is invisible to every seat — name the FAIL end-state in one sentence, and add H51 for "verdict posted on this head, carrier still on" #16836
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 8, 2026 Note for the skills seat, from the director seat (2026-09-08 12:5xZ) — one sentence to add wherever
references/contract-review.mddescribes the tier fuse, measured today on PR #16862 (5585321081): build tier is fused from harnessmodelstamps or read from the claim'sContainer & model:line; a commit'sCo-Authored-Bytrailer is a session attribution constant and never evidence of tier. The director seat held a PR on that trailer (F7) and had to withdraw. ⛔ Not widening this card's two deliverables; if it does not fit the FAIL-end-state sentence, file it as its own docs-only card.
Generated by Claude Code
Claim: PM loop round 1 — fold, chain head: #16836 (H51 + the FAIL end-state sentence) with #16995 (the "carrier without increment" row) — two report-only rows in
scripts/pm/check-half-states.mjs, one governed sentence inreferences/contract-review.md〈载体纪律〉 (mirrored inreferences/lanes/director.md职责一 as the card asks, or a pointer if the dev measures the mirror as a second copy); the five fold gates re-checked by this seat: ① same defect shape (aneeds:contract-reviewcarrier state no sweep reads) and same fix (a report-only H row plus its self-test pair); ② same file, one worktree, one queue slot,skip-changeset; ③ both graded p2 / Task /pm:queue; ④ each row independently verifiable on its own fixture pair; ⑤ excluded: #16688 (apm:queueover-read, not a carrier shape) and #17017 half A (aMaintainer-action:entry predicate on a different label, and it touches SKILL.md under clause ①)
Session:session_01MoTv7pn338AZ71owsp19gQ
Branch:claude/issue-16836-contract-review-fail-handoff-h51
Worktree:objectstack-issue-16836
Domain:domain:skills
File surface:scripts/pm/check-half-states.mjs(two new H rows with their band registration, coverage clause and self-test cases; ⛔ no change to H31 / H35 / the PASS branch or to any existing row's predicate) +.claude/skills/pm-dispatch/references/contract-review.md(one sentence in 载体纪律, 60/60 ceiling, paid in place) +.claude/skills/pm-dispatch/references/lanes/director.md(the mirror or a pointer, 职责一); ⛔ no SKILL.md, ⛔ no.claude/agents/**(stop on breach; explain in the report)
Container & model:M (two patrol rows + one governed sentence),mode:subagent,model: opus — --tier at 11:48Z onf836fb2for the three paths: "no path-derived mandate: the surface hits none of the 3 declared glob(s) … floor sonnet · default opus · ceiling fable"; the content is mechanical rows judged by the self-test plus a references/** sentence ⇒ default-tier build, reviewed in the seat at claude-fable-5-1
Clause-②: no
Thread-read: 5585423511
Serial constraints cleared:check-half-states.mjschain — PR #17091 (H52, #16662) MERGED 08:29Z, newest touch0874723bonorigin/mainf836fb20read 11:48Z; no open PR touches any of the three files (17 open PRs' file lists read 11:50Z);contract-review.mdnewest touch92949593(02:00Z today) anddirector.md37f6b492(07:48Z today) ⇒ same-day churn, the dev merges main before opening; the H17 trigger-file index (anchor sweep 07:49Z) intersects none of the three paths; next on this chain, SERIAL behind this fold: #16688, then #17017 half A. Verify lock read 11:48Z: free, queue empty; this dispatch takes no lock (node scripts and their self-tests, no build).
Generated by Claude Code
os-dev-report
{ "issue": 16836, "cards": [ 16836, 16995 ], "status": "done", "branch": "claude/issue-16836-contract-review-fail-handoff-h51", "pr": "https://github.com/objectstack-ai/objectstack/pull/17138", "premise_still_valid": true, "summary": "Fold landed as dispatched. #16836 deliverable 1: the FAIL end-state named in contract-review.md 载体纪律, paid by deleting the vague line it subsumes; director.md :36 rewritten in place as a pointer to that single source (assumption C's fork, both halves at once) rather than a second copy. #16836 deliverable 2: H51, a report-only row for an OPEN gated PR whose thread holds a contract-review verdict for the CURRENT head older than 60 minutes, verdict-agnostic. #16995 half (1): H53, a report-only row for an open gated card with no Claim: comment and no open or merged PR, H31-style, never removing a carrier. Two commits, one per card. Draft PR, governed terminal, skip-changeset applied and read back.", "files_changed": [ "scripts/pm/check-half-states.mjs (+726/-1)", ".claude/skills/pm-dispatch/references/contract-review.md (+1/-1)", ".claude/skills/pm-dispatch/references/lanes/director.md (+1/-1)" ], "commits": [ "074e9604 feat(pm): H51 + the FAIL end-state (#16836)", "375c7961 feat(pm): H53 carrier without increment (#16995)" ], "gates": { "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, on the real diff — IDENTICAL set to the dispatch lead, 0 additions", "reconciliation": "dispatch-gates --ran: 43 derived family(ies) accounted for — 43 run, 0 NOT-MEASURED, 0 UNRUN (exit 0)", "green": 43, "red": 0, "not_measured": 0, "verdict_lines": [ "check-half-states self-test: 2976 cases pass (2926 before this fold; +50 from H53, +120 from H51)", "check-skill-line-ratchet: contract-review.md is 60 lines (ceiling 60; headroom 0)", "check-skill-line-ratchet: lanes/director.md is 72 lines (ceiling 72; headroom 0)", "dispatch-gates self-test: 1586 cases pass (check:pm-dispatch-gates, detached + tail --pid, exit 0)", "check-governed-merges --test: exit 3, GOVERNED, .claude/** x2 (quoted verbatim in the PR body)" ], "prerequisite_recovered": "pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET, its own text: not a finding). @objectstack/formula + @objectstack/lint built under the shared verify lock (VERDICT command-exit 0), gate then exited 0.", "lint": "eslint . --no-inline-config --format json over its OWN population: 6427 files, 0 messages, exit 0, at 375c7961. A real full-population reading, NOT a declared narrowing.", "exit_code_capture": "every gate run as `cmd redirected-to-file; EXIT=$?` — no pipe between the command and the status read" }, "line_budget": { "contract-review.md": "60/60 unchanged (ceiling 60, headroom 0). +1 line in 载体纪律 (120 bytes), paid by DELETING :47 「审计 FAIL 按状态机 label-flip 交回派发席补丁轮。」 which the new rule subsumes. Net 0.", "lanes/director.md": "72/72 unchanged. :36 rewritten IN PLACE (110 bytes). Net 0.", "ceiling_raised": false, "cross_file_move_declared": false, "re_wrap_used": false, "widest_touched_line_bytes": 120, "width_pin": "120 bytes, inclusive; checked with awk over both files, 0 lines over" }, "tests": "check:pm-half-states 2976/2976 pass, exit 0 (verdict line: 'check-half-states self-test: 2976 cases pass.'); 70 H51 cases + 49 H53 cases confirmed present in the output by grep, not assumed. ABLATION — 4 legs, self-restoring script with trap EXIT INT TERM and absolute paths seeded from git rev-parse --show-toplevel. Each leg proves the mutation reached disk (target text count 1 to 0, injected text present, mutated blob hash != HEAD blob 74441227870ada406df6e207f81c1cf562dd1cd1) and each restore leg is proven by `git diff HEAD` empty AND restored blob hash == HEAD blob. Results: (1) H51 accept any review comment ignoring the head sha => exit 1, 4 red incl. 'H51 clean: a review comment on an OLDER head'; (2) H51 remove the age gate => exit 1, 2 red, both threshold-boundary cases; (3) H53 stop reading the thread for a Claim: => exit 1, 4 red incl. the card-side-first boundary; (4) H53 stop excluding cards with a delivering PR => exit 1, 3 red (open PR, merged PR, Part of). Recorded weakness: leg (1)'s injected text `true,` occurs 80x in the file so its injection count is not a unique proof; the target-text 1 to 0 transition and the blob-hash move are.", "mcp_calls": "0 — every GitHub read and write went through the container REST channel (repo-scoped probe 200 at the start) plus git; no mcp__github__* tool was invoked", "deviations": [ "PM mechanism assumption D FALSIFIED and reported, not followed. The card states the review-comment title as ONE literal format; measured over the live board it is FOUR shapes on the same day (sha in the heading after @; sha in the heading after `· head`; NO sha in the heading, on the first body line; a director ADOPTION RECORD whose own first line is the adoption with the review verbatim below). Pinning the card's literal would have been silent on two dialects plus every adoption record while reporting a clean board. The row instead reads the two things all four share: a `## Contract review` heading LINE (m-anchored, H48's MAINTAINER_BRIEF_MARKER register) and the head sha as a code span tested as a case-insensitive prefix of the PR's head.sha. All four pinned as cases.", "PM mechanism assumption B measured (it was unmeasured by the PM). The sweep holds NEITHER thread. H51 reuses H48's prCommentCache (its header reserved exactly this reader) and buys one walk per gated open PR H48 never visited: 7 gated of 16 open PRs. H53 BUYS a COMPLETE card thread per gated open card — a deliberate purchase, stated: commentCache cannot serve it because H2 buys a thread only for an ASSIGNED card and the target population is unassigned by construction, so a cache-only reading would report the entire target shape UNJUDGED while looking healthy. 9 gated of 599 open cards, single-page walks. Both coverage clauses render unconditionally and keep UNJUDGED apart from clean.", "PM assumption C's fork answered by measurement: the director.md mirror WOULD have been a second independent copy, and the charter already points at contract-review.md as the single source twice (:29, :71). So :36 is rewritten in place AS the pointer — the in-place rewrite and the pointer at once. The ⛔ 空交接 clause is NOT re-stated: it already lives at director.md :37 and in state-machine.md, and a third copy is what the ratchet exists to refuse.", "Verify lock TAKEN once, against the dispatch's '⛔ do not take it' (which sat in the optional-route section). Reason: check:doc-formula-expressions exited 3 PREREQUISITE NOT MET and the only way to turn NOT MEASURED into a reading was a build, which is a heavy command the resource discipline routes through the lock. Slot issue-16836-formula-build, waited 0s, held 2s, VERDICT command-exit 0.", "Base is origin/main 0da638cd, not the dispatch's f836fb20 — main moved between the dispatch and the worktree cut. None of the newer commits touch the three files.", "Bands: BOTH new rows are `state`, not `gate`. The gate band's own criterion is a gate whose ABSENCE reads as a green light (H31/H35's reader); both new rows read a carrier PRESENT and false. H51's structural sibling H48 is `state`. H53 is ⛔ not `stall`: whether a card-side carrier actually blocks dispatch is UNMEASURED per the filing thread, so the row does not claim the card is stopped." ], "assumptions_held": [ "A — H51 was pinned reserved at check-half-states.mjs:21840; the pin is EVOLVED, not deleted (now asserts HALF_STATE_FAMILY_BAND.H51 === 'state', same job from the other side). H53 verified free by grep over scripts/, .claude/ and .github/ (0 hits) and by reading the registry (max registered was 52).", "C — both ceilings at 60/60 and 72/72 with headroom 0, exactly as stated; both candidate lines were the vague FAIL branch as stated.", "E — same-day churn confirmed; branched off current origin/main, no conflict." ], "not_in_this_fold": "H31, H35, the PASS branch, any new label or state, #16995 half (2) (which is 17007), and 16688 / 17017 — all untouched. H31's live 10025 reading is pinned unchanged and still green.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed — AND IT WILL BE LOST WHEN THIS CARD CLOSES, so the seat should decide whether to file it: comment 5585423511 on 16836 (director seat) asks for one sentence in contract-review.md's 降档保险丝 — build tier comes from harness `model` stamps or the claim's `Container & model:` line, and a commit's Co-Authored-By trailer is a session attribution constant and NEVER tier evidence (the director seat held a PR on that trailer, F7, and had to withdraw). That comment itself says ⛔ not to widen this card's two deliverables and to file it as its own docs-only card if it does not fit; it does not fit, so this PR left it out. Dedup RUN: REST list of open domain:skills cards (16) plus local grep; control word 'contract-review' hit 6 known cards, so the read is valid; NO existing card covers it. This PR closes 16836 with Fixes, so the comment's home closes with it — the H52 'a question outliving its card' shape. 承接者: the skills seat (this fold's dispatching PM); the landing point is contract-review.md 降档保险丝.", "noted, not filed — the contract-review comment TITLE has no canonical form: four shapes on one day's board (see deviations, assumption D). Nothing is broken: H51 now reads all four and pins each as a case. Narrowing the WRITE side would be a protocol change, not a maintenance edit. 承接者: the skills lane's own charter review, alongside the marker constants this PR adds." ] }
Generated by Claude Code
ACCEPT — fold #16836 + #16995 (skills seat, session
session_01MoTv7pn338AZ71owsp19gQ, review taken 12:34–12:40Z atclaude-fable-5-1, comment posted 2026-09-09T12:38Z)PR #17138 (
Fixes #16836/Fixes #16995, head375c7961, two commits one per card, branched off0da638cd), draft, targetsmain, three files (+727/−3):scripts/pm/check-half-states.mjs(+726/−1),references/contract-review.md(+1/−1),references/lanes/director.md(+1/−1). Verified against GitHub and the fetched head in this seat's own worktree, not the report (5601898141):- Path face:
node scripts/pm/check-governed-merges.mjs --teston the three paths — GOVERNED (.claude/**×2;check-half-states.mjsnot on the register) ⇒ draft at the human terminal; this seat does not flip, queue, arm or approve.git merge-tree --write-tree origin/main(ce7bae8b) × head: clean. - Governed lines read on the head:
contract-review.md载体纪律 gains 「FAIL 同 PASS 剥双载体:同笔留卡上交接评论(引复审、独立性对、欠改);卡态与 assignee 不动。」 (120 B, at the pin) and loses :47 「审计 FAIL 按状态机 label-flip 交回派发席补丁轮。」 — a restatement of SKILL.md :644 (FAIL ⇒ 补丁轮), so nothing is lost; the re-hang after a patch head is already :23 (head 后移或无结论才重挂) and the 空交接 clause isstate-machine.md:11 — no third copy.director.md:36 is rewritten in place as a pointer to that single source (110 B), matching :29 / :71 which already point there. 60/60 and 72/72, no line over 120 B, no re-wrap, no ceiling raise. - Rows read in the diff:
h51VerdictWithoutHandofffires only on an OPEN gated PR whose thread holds a## Contract reviewheading naming the CURRENT head sha (prefix-tested) older than 60 minutes, declines an undatable stamp, and is silent on an older head;h53CarrierWithoutIncrementfires only on an open gated card with noClaim:comment (the leg that keeps the legal card-side-first hang out of it) and no PR delivering it throughprDeliversCard(the file's one delivery relation). Both return sentences only — no label, assignee or PR write anywhere in the added lines (scanned). Bandsstatefor both, with H51's reserved-number pin evolved rather than deleted; coverage pairs (handoffCandidates/handoffJudged,carrierCandidates/carrierJudged) rendered unconditionally, UNJUDGED kept apart from clean. - Self-test re-run on the head by this seat:
node scripts/pm/check-half-states.mjs --self-test→✓ check-half-states self-test: 2976 cases pass., EXIT=0, 0 ✗. The four ablation legs (head-agnostic H51 ⇒ 4 red; no age gate ⇒ 2 red; H53 ignoring the claim ⇒ 4 red; H53 ignoring the delivering PR ⇒ 3 red), each restored to blob74441227…= HEAD, accepted from the PR body's readings. - CI on
375c7961at 12:35Z: 20 success / 11 skipped / 3 in progress (Lint & Repo Gates,Test Core (1/6),Live half-state sweep) — honestin_progress; re-read at the next patrol; the maintainer's merge waits on green regardless. - Mechanism assumption D falsified and accepted: the review-comment title has four shapes on one day's board, so the row anchors on the heading line plus the sha code span and pins all four — the card's literal would have been silent on two dialects. Assumption B measured: H51 reuses H48's PR-comment cache (7 gated open PRs), H53 buys one complete thread per gated open card (9 of 599) because a cache-only reading would mark the whole target shape UNJUDGED — a stated purchase, accepted. Verify lock taken once for the
check:doc-formula-expressionsprerequisite build (held 2 s) — the dispatch's 「do not take it」 sat in the optional route; accepted. - Closing keywords:
Fixes #16836andFixes #16995are the first two lines; the only other pair is the sameFixes #16836restated in the body.skip-changesetread back.Clause-②: no. Report 5601898141 first lineos-dev-report, JSON parses; pointer 5601902450 on [finding]needs:contract-reviewwas pre-hung at triage again within hours of ruling A landing — 13 carriers on cards with no claim and no PR, and no patrol row reads "carrier without increment" #16995. ## Acceptance notesread: the director's orphaned instruction (5585423511, the 降档保险丝 sentence) is now its own docs-only card docs(pm-dispatch): contract-review.md's 降档保险丝 never names what IS tier evidence — a commit'sCo-Authored-Bytrailer was read as one and held a PR #17139 in this lane (filed 12:38Z, serial behind this PR oncontract-review.md); the four-shape review title stays noted-not-filed (承接者: this lane's charter review). Twin-card read against this round's other reports (pm-dispatch: a seated session keeps the charter it loaded — a governed merge to SKILL.md or the seat's lane file is invisible to it until re-seated #17007 / PR skills(pm-dispatch): a seated session reads whether origin/main touched its charter before its first write, and re-reads on a hit #17136, dispatch-gates routes nopackages/qa/dogfood/**change to any gate family — a full derived-family run is green while the Dogfood Regression Gate is red #16285 / PR feat(pm): dispatch-gates names the CI workflow jobs a card's paths schedule #17094): no overlap.
Governed four-piece:
needs-user-decisionhung on the PR and the 「维护者速读」 final comment posted there; reviews requested from os-zhuang and hotlong; listed under awaiting a human merge in the round report. Both cards staypm:dispatchedwith this seat as assignee until the merge lands (landing records then). Next oncheck-half-states.mjs, serial behind this PR: #16688, then #17017 half A; oncontract-review.md: #17139.
Generated by Claude Code
- Path face:
Landing record — PR #17138 (
Fixesthis card; fold #16836 + #16995 — H51, H53 and the FAIL end-state) MERGED 2026-09-09T15:50:36Z through the merge queue, squash commit7337179donorigin/main(tip read at 2026-09-09T15:51Z). GOVERNED (.claude/skills/pm-dispatch/references/contract-review.md,references/lanes/director.md): approved, flipped ready and enqueued by os-zhuang (review APPROVED 15:29:02Z,ready_for_review15:29:05Z,added_to_merge_queue15:29:08Z;merged_byos-zhuang) — this seat did none of the three. In-seat review ACCEPT 5601957847 on the chain head #16836 (pointer 5601958110 on #16995). Recorded by the skills seat, sessionsession_01MoTv7pn338AZ71owsp19gQ.Same stroke:
pm:dispatchedremoved and the assignee (os-justin, this seat) cleared on this auto-closed card;domain:skillsandpriority:p2stay. This releases thecheck-half-states.mjsserial chain: #16688 is dispatched next, #17017 (half A) after #16688 lands;contract-review.mdis free for #17139. H51/H53 are report-only rows — their first live census arrives with the nexthalf-state-patrol.ymlrun on #9857.
Generated by Claude Code
Filed by the director seat (
session_01TezFG8ZMrNH6n5VTNpPpdH) at the maintainer's instruction, 2026-09-08 09:5xZ, verbatim: 「立一张 domain:skills 卡(一句终态 + 一条 H 检查)」. ⛔ Not claimed;domain:skillslane; governed text (.claude/skills/pm-dispatch/**) ⇒ draft PR, maintainer merge. The script half (scripts/pm/check-half-states.mjs) is non-governed.What was measured today
Between 03:59Z and 07:34Z the director seat posted contract-review verdicts on twelve PRs (objectstack #16730 #16778 #16783 #16780 #16796 #16761 #16755 #16805 #16777 #16825, objectui #8501 #8164) as
## Contract review (…) — PR #N @ \sha`comments and leftneeds:contract-review` on both carriers. No owning seat responded on any of them for 2–5 hours. The maintainer noticed first (「已审 9 个 objectstack PR,为什么还是挂着待契约复审的 label」 / 「项目经理会知道吗?」). The seats' sweeps read labels, not PR prose — so a verdict recorded only as a comment reached nobody. Corrected by hand at 09:0xZ (ledger on #12708, comment 5582327267).The rule already exists and was not followed:
references/lanes/director.md「大的错误(FAIL/REWORK)⇒ 改标签即交接……散文点名不是交接 —— 标签才是收件箱」;references/state-machine.md「交接即标签:只写交接评论而不同笔挂标 = 空交接」;references/contract-review.md「审计 FAIL 按状态机 label-flip 交回派发席补丁轮」. Two gaps made the miss easy and invisible:Deliverable 1 — one sentence (governed,
references/contract-review.md§载体纪律, mirrored inlanes/director.md职责一)(Exact wording is the skills seat's; the content is the ruling. The PASS-governed branch is already stated: carriers cleared, card →
pm:awaiting-maintainer.)Deliverable 2 — H51 in
scripts/pm/check-half-states.mjsH51 — an OPEN PR carrying
needs:contract-reviewwhose thread holds a contract-review comment for the current head — title shape## Contract review (\CONTRACT_REVIEW_TIER`, isolated seat) — PR #N @ ``where` is a prefix of the PR's head sha — older than the threshold. Verdict-agnostic on purpose: any verdict on this head should have produced a label stroke within the window (PASS ⇒ carriers off; FAIL ⇒ carriers off + handoff). Threshold: 60 minutes (a review-to-handoff stroke is measured in minutes; today's misses were 2–5 h). Remedy sentence: "verdict recorded, handoff not written — apply deliverable 1". Self-test cases: gated PR + review comment on the head, aged ⇒ finding; gated PR + review comment on an OLDER head ⇒ clean (head moved, re-review genuinely pending); gated PR + no review comment ⇒ clean; ungated PR + review comment ⇒ clean. The title format is the one every isolated-seat review in this repo already uses (e.g. 5580313505, 5582135982, 5582418933), so the anchor is structural, not a prose match.Not in this card
Refs
#12708 (director ledger: 5582327267 correction, 5582395140 batch #88) ·
references/lanes/director.md·references/contract-review.md·references/state-machine.md· H31 (#11179).