Summary
A session dispatched sidecar subagents to open PRs, then relayed each subagent's terminal-readiness claim to the user verbatim, without running scripts/check-pr-fully-clean.py itself. Both claims were false when measured:
Why the existing guard missed both
hooks/no-incomplete-check-enumeration.py already blocks a terminal clean claim backed only by a partial CI reading (gh pr checks, statusCheckRollup). It missed both cases here:
(a) Vocabulary: "green, awaiting your merge" asserts the same terminal fact as "ready to merge" but used none of RX_DECLARE's phrases, so it tripped nothing.
(b) Evidence source: a dispatched subagent's own report is a claim, not an instrument reading, and is stale by construction (the agent stops, then reviews/checks keep landing). The original guard required a partial CI reading to even fire; relaying a subagent's report with no reading at all by the conducting session tripped nothing.
Fix
Extended hooks/no-incomplete-check-enumeration.py (rather than adding a sibling -- see PR) to:
- add
RX_DECLARE_MERGE_READY for the broader vocabulary, and
- track the most recent point a dispatched Agent/Task call's report landed in the transcript (
last_subagent, via tool_use_id correlation, the same technique remind-brief-premises.py uses), requiring a complete check-pr-fully-clean.py read after that point too, not just after the last push.
Both new conditions WARN (systemMessage) rather than BLOCK; the original narrow condition (original vocabulary + partial CI reading + no subagent involved) keeps blocking exactly as before.
Per README's activation gate, the hook stays registered-but-inert until this PR merges.
Summary
A session dispatched sidecar subagents to open PRs, then relayed each subagent's terminal-readiness claim to the user verbatim, without running
scripts/check-pr-fully-clean.pyitself. Both claims were false when measured:check-pr-fully-clean.pyexited 1 -- a verdict-bearing review landed at 2026-09-09T20:30:36Z, AFTER the subagent finished its report. The claim was true when written and stale when relayed.\def\v0/\def\v1, which broke\vfor every other argument d-morrison/macros#87: reported "green, awaiting your merge" across four separate messages.check-pr-fully-clean.pyexited 1 with "No automated review comments or reviews found on PR ums: skill-builder Step 0 — scan local branches + worktrees, not just remote #87" -- CI was genuinely green, but no automated reviewer ever produced a verdict (only Copilot quota-exhaustion notices, which are not reviews).Why the existing guard missed both
hooks/no-incomplete-check-enumeration.pyalready blocks a terminal clean claim backed only by a partial CI reading (gh pr checks,statusCheckRollup). It missed both cases here:(a) Vocabulary: "green, awaiting your merge" asserts the same terminal fact as "ready to merge" but used none of
RX_DECLARE's phrases, so it tripped nothing.(b) Evidence source: a dispatched subagent's own report is a claim, not an instrument reading, and is stale by construction (the agent stops, then reviews/checks keep landing). The original guard required a partial CI reading to even fire; relaying a subagent's report with no reading at all by the conducting session tripped nothing.
Fix
Extended
hooks/no-incomplete-check-enumeration.py(rather than adding a sibling -- see PR) to:RX_DECLARE_MERGE_READYfor the broader vocabulary, andlast_subagent, viatool_use_idcorrelation, the same techniqueremind-brief-premises.pyuses), requiring a completecheck-pr-fully-clean.pyread after that point too, not just after the last push.Both new conditions WARN (
systemMessage) rather than BLOCK; the original narrow condition (original vocabulary + partial CI reading + no subagent involved) keeps blocking exactly as before.Per README's activation gate, the hook stays registered-but-inert until this PR merges.