Repository navigation
Description
Found by the os-dev seat while implementing #15187 (guard half in PR #15203). Not filed as a drive-by: it is the half of that ruling which lands in governed files, and PR #15203 cannot go green without it.
The 2026-09-04 maintainer ruling — verbatim and untranslated — 「你的门禁有问题,只需要有人工批准记录就行,不需要卡最新的提交。」 — retires the sha pin on the governed merge-queue approval predicate. #15203 lands that in scripts/pm/check-governed-queue-guard.mjs. Four governed surfaces still state the retired rule, and one of them is a CI gate that now reds.
1. .claude/hooks/guard-governed-enqueue.selftest.sh — RED in CI today
lint.yml discovers and runs every .claude/hooks/*.selftest.sh as the job Claude hook guard self-tests. Two of its cases pin the retired pin:
FAIL want=block got=allow a STALE approval (approved an earlier head) never counts
FAIL missing "STALE approval" a stale approval is reported as stale, not as absent
Measured by ablation on the branch of PR #15203 — the pre-ruling guard restored on disk, hook self-test re-run, then restored from HEAD:
| tree | hook self-test |
|---|---|
| pre-ruling guard | 49 passed, 0 failed |
| with the ruling | 47 passed, 2 failed |
Both cases must flip direction: an authorised approval on an earlier head now ALLOWS.
2. .claude/hooks/guard-governed-enqueue.sh — wrong advice, and the deferred rename
Its runtime verdict is already correct without any edit — it imports the predicate, so it inherits the ruling (measured: an authorised approval on an older commit now returns state: approved, and the hook exits 0). Two things still need the edit:
- The blocking message tells a seat: "A push after the approval unpins it — re-request, do not re-enqueue." That is now false and sends seats to do work the gate no longer asks for. The surrounding lines ("no APPROVED review pinned to its current head", "Wait for the APPROVED review to land on THIS head sha") are wrong in the same way.
- The symbol
pinnedApprovalVerdictnames something it no longer does. PR fix(pm): an authorised APPROVED review satisfies the queue guard on any commit (2026-09-04 ruling) #15203 deliberately keeps the name, because this hook imports it and a rename there alone would break a seat-side guard into silent fail-open. The rename belongs in the same commit as this hook's call site —authorizedApprovalVerdictmatches the file's ownunauthorizedApproversspelling.staleApproversis retained by that PR as a printed reading (authorised approvals given on a commit that is no longer the head, which now also count), so this hook's detail line stays valid but becomes unreachable on the blocking path.
3. AGENTS.md — the governed-landing paragraph
Still reads: "Those four lift only for an authorized approval pinned to the current head (2026-08-27; guard 2026-08-28): APPROVED, by an account in GOVERNED_APPROVERS …, commit_id = that sha … and any later push expires it." The approver set half stands; the pin half and "any later push expires it" do not.
4. .claude/skills/pm-dispatch/SKILL.md
Still reads: 「APPROVED 且 commit_id = PR 当前 head 才算,批准后再推提交即过期转红」. Same correction. This one matters twice over: it is the text every later PM dispatch reads, so a stale rule there propagates into work nobody has started yet.
Landing note
All four paths are governed (.claude/**, AGENTS.md), so a PR carrying them is a governed-surface PR: no seat flips it ready, enqueues it or arms auto-merge. It needs the maintainer's own merge, or one authorised approval — which, once #15203 lands, no longer expires on a later push.
main.
Generated by Claude Code
Activity
claude commentedon Sep 4, 2026
Claim: PM loop round 5 — folded into the #15187 flight (claim 5536163108; session
session_019RfFHiRCSs3JXLK4cwcfox; branchclaude/issue-15187-queue-guard-unpinned-approval; worktreeobjectstack-issue-15187;mode:subagent,model: opus;Clause-②: no). Seat decision 06:11Z on the dev's open question: A — PR #15203 is extended into the four governed paths this card names and lands as ONE governed PR (Fixes #15187+Fixes #15209; draft, both approvers requested by the seat, human merge), so main never carries a red hook self-test between two landings. Gradedpriority:p2,domain:skills,tooling, statepm:dispatched. Applied and read back after this comment.Generated by Claude Code
claude commentedon Sep 4, 2026
Folded into PR #15203 by seat decision, rather than landed separately.
The reasoning that settled it: this issue and the guard change are one contract, not two — the enqueue hook IMPORTS the predicate, so splitting them across two PRs leaves a window in which
mainis red whichever one lands first (the guard alone reddensClaude hook guard self-tests; this one alone asserts a behaviour the guard onmaindoes not yet have). Landing them together has no such window, and thepinnedApprovalVerdictrename travels with its only importer.All four items are in that PR:
.claude/hooks/guard-governed-enqueue.selftest.sh— the two cases flipped to the ruled direction; the fixturegoverned-stalebecamegoverned-approved-on-an-earlier-commit. Self-test now reads 50 passed, 0 failed..claude/hooks/guard-governed-enqueue.sh— the blocking message no longer says a push unpins the approval, and both renames landed here with their importer (pinnedApprovalVerdicttoauthorizedApprovalVerdict,staleApproverstoapprovalsOnEarlierCommits).AGENTS.md— the governed-landing paragraph now states the ruled predicate, with the ruling quoted verbatim..claude/skills/pm-dispatch/SKILL.md— the ACCEPT-fork clause likewise.PR #15203 is therefore a governed-surface PR and stays a DRAFT: no seat flips it ready, enqueues it or arms auto-merge. The seat requests
os-zhuangandhotlong; the maintainer lands it.Generated by Claude Code
claude commentedon Sep 4, 2026
Reviewed under #15187's verdict: PR #15203 (head
0a8763f6) carries the four governed-path halves this card asked for — hook self-test (50 passed, 0 failed, sha-pin fixture flipped to ALLOW), hook prose with thepinnedApprovalVerdict→authorizedApprovalVerdictrename, AGENTS.md and SKILL.md stating the 2026-09-04 predicate. ACCEPT, governed terminal: draft PR, both authorized approvers requested, human landing. The PR body closes this card with #15187.Implemented-by:
claude/issue-15187-queue-guard-unpinned-approvalReviewed-by:
session_019RfFHiRCSs3JXLK4cwcfoxGenerated by Claude Code