Skip to content

Commit aa49e83

Browse files
os-samclaude
andcommitted
test(devx): pin the regeneration case as AGREEMENT with the register, not a copied verdict
The first revision hard-coded `expect allow` against the one exception row that was cheap to lift. That row was retired upstream the same day -- its surface left the governed fence entirely -- and the case went red over a register change the hook had nothing to do with. A verdict copied out of the register makes the matrix a second register. It now asks the register and requires the hook to answer the same way, over the incident's own file class: four `skills/*/references/_index.md`. Measured both branches -- fail-closed with no toolchain (block, agreed) and lifted with the toolchain present (allow with zero reviews, agreed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
1 parent 3f857e2 commit aa49e83

1 file changed

Lines changed: 57 additions & 19 deletions

File tree

.claude/hooks/guard-governed-enqueue.selftest.sh

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,13 @@
1818
# Needs `jq` (to build fixtures) and `node` (the two real predicates run). No
1919
# pnpm install, no build: measured against a worktree with no `node_modules`.
2020
#
21-
# ⚠️ ONE COUPLING, STATED SO A FAILURE IS NOT MISREAD. The
22-
# `pure-regeneration-only ⇒ ALLOWED` case uses a REAL register-lifted path
23-
# (`.claude/workflows/docs-accuracy-audit.js`, the #9866 row) rather than a
24-
# stub, because the requirement under test is precisely "this guard must never
25-
# re-close the zero-approval path the register clears" and a stub cannot show
26-
# that. The consequence: the case needs that artifact to be in sync with its own
27-
# generator on the tree it runs against — which is what the required
28-
# `check:docs-audit-scope` gate keeps true. If this one case fails while the
29-
# rest pass, look there first; re-run
30-
# node scripts/pm/check-governed-merges.mjs --test .claude/workflows/docs-accuracy-audit.js
31-
# and read what the register says before touching this matrix or the hook.
21+
# ⚠️ THE PURE-REGENERATION CASE IS AN AGREEMENT ASSERTION, NOT A FIXED VERDICT,
22+
# and that is a repair rather than a preference: the first revision of this file
23+
# hard-coded `expect allow` against the one exception row that was cheap to
24+
# lift, and that row was retired upstream hours later — the case then went red
25+
# over a register change the hook had nothing to do with. Copying a verdict out
26+
# of the register makes this matrix a second register. It now ASKS the register
27+
# and requires the hook to answer the same way; see that block for the detail.
3228

3329
set -uo pipefail
3430

@@ -71,7 +67,15 @@ approved_at() { # approved_at <login> <sha>
7167
NO_REVIEWS='[]'
7268
GOVERNED_FILES="$(files_of AGENTS.md packages/spec/src/index.ts)"
7369
CLEAR_FILES="$(files_of packages/spec/src/index.ts README.md)"
74-
REGEN_FILES="$(files_of .claude/workflows/docs-accuracy-audit.js)"
70+
# The incident's own file class, and four of them, the way it actually happened:
71+
# `skills/*/references/_index.md` is a governed `skills/**` path whose generator
72+
# (`gen:skill-refs`) owns it, so a byte-exact regeneration is lifted and needs no
73+
# approval at all. Every path here must be one the generator DECLARES — a skill
74+
# absent from its map is hand-authored content that stays governed, which is the
75+
# ruling's own limit and not a bug to route around.
76+
REGEN_PATHS="skills/objectstack-data/references/_index.md skills/objectstack-query/references/_index.md skills/objectstack-ui/references/_index.md skills/objectstack-api/references/_index.md"
77+
# shellcheck disable=SC2086
78+
REGEN_FILES="$(files_of $REGEN_PATHS)"
7579

7680
F_UNAPPROVED="$(fixture governed-unapproved "$GOVERNED_FILES" "$NO_REVIEWS")"
7781
F_PINNED="$(fixture governed-pinned "$GOVERNED_FILES" "$(approved_at os-zhuang "$HEAD_SHA")")"
@@ -169,14 +173,48 @@ echo "== nothing governed in the diff: allowed, and no review is ever consulted
169173
expect allow 'an ordinary diff enqueues freely' \
170174
"$(mcp $AUTO 14070)" "OS_GOVERNED_ENQUEUE_FIXTURE=$F_CLEAR"
171175

172-
echo "== PURE REGENERATION clears with ZERO approvals — the register decides, not this hook =="
173-
# Real path, real lift (see the coupling note in this file's header): the #9866
174-
# row, byte-exact against its own generator recomputed on this tree. The hook
175-
# must never be what re-closes it (maintainer 2026-09-01: 纯生成的指针行 …
176-
# 不需要我审核吧).
177-
expect allow 'a governed-register path the generator certifies byte-exact, zero reviews' \
176+
echo "== PURE REGENERATION: the hook must AGREE with the register, never re-decide =="
177+
# The requirement (maintainer 2026-09-01: 纯生成的指针行 … 不需要我审核吧) is that
178+
# this hook never re-closes a zero-approval path the register clears. Pinned
179+
# against a REAL exception-row candidate, and pinned as AGREEMENT rather than as
180+
# a fixed verdict, for a reason this matrix learned the hard way: an earlier
181+
# revision hard-coded `expect allow` on the one row that was cheap to lift, that
182+
# row was RETIRED upstream the same day (its surface left the governed fence
183+
# entirely), and the case then failed for a reason that had nothing to do with
184+
# the hook. A verdict copied from the register is a second register.
185+
#
186+
# So: ask the register what it says about this path list on THIS tree, and
187+
# require the hook to answer the same way.
188+
# exit 0 => lifted (the generator toolchain is present and the bytes match)
189+
# => the hook MUST allow with zero reviews. This is the branch CI
190+
# takes, where dependencies are installed.
191+
# exit 3 => not lifted (fail-closed: no toolchain, or a hand edit)
192+
# => the hook MUST refuse, exactly as the register asked.
193+
# Either way the property under test holds: the hook contributes no judgment of
194+
# its own about the exemption.
195+
# shellcheck disable=SC2086
196+
node "$repo_root/scripts/pm/check-governed-merges.mjs" --test $REGEN_PATHS >/dev/null 2>&1
197+
regen_rc=$?
198+
if [ "$regen_rc" -eq 0 ]; then
199+
regen_want=allow
200+
regen_branch='LIFTED — byte-exact regeneration, so zero approvals must pass (the toolchain is present here)'
201+
else
202+
regen_want=block
203+
regen_branch="NOT lifted (exit $regen_rc, fail-closed: no generator toolchain, or a hand edit) — the refusal must stand"
204+
fi
205+
printf ' .. register verdict on the four %s: %s\n' 'skills/*/references/_index.md' "$regen_branch"
206+
expect "$regen_want" 'the hook agrees with the register about an exception-row candidate' \
178207
"$(mcp $AUTO 14070)" "OS_GOVERNED_ENQUEUE_FIXTURE=$F_REGEN"
179208

209+
# ...and the structural half, which no fixture can go stale on: the ONLY branch
210+
# that can reach a refusal is the register's own "governed" exit code. Anything
211+
# the register clears leaves through `exit 0` before a single review is read.
212+
if grep -qE '^[[:space:]]*0\)[[:space:]]*exit 0' "$hook"; then
213+
pass=$((pass + 1)); printf ' ok wired a cleared predicate verdict exits before any review is read\n'
214+
else
215+
fail=$((fail + 1)); printf ' FAIL the hook no longer allows unconditionally on a cleared predicate verdict\n'
216+
fi
217+
180218
echo "== the Bash spellings reach the same decision =="
181219
expect block 'gh pr merge <n> -R owner/repo' \
182220
"$(bash_call 'gh pr merge 13794 -R objectstack-ai/objectstack --squash')" \
@@ -257,7 +295,7 @@ echo "== a generated-exception row on a repo with no checkout to recompute again
257295
# against another's files would be worse than not answering: fail open, say so.
258296
expect allow 'an exception-row path in a repo this container cannot resolve' \
259297
"$(mcp $AUTO 999 objectstack-ai cloud)" \
260-
"OS_GOVERNED_ENQUEUE_FIXTURE=$(fixture cross-repo-regen "$(files_of skills/objectstack-spec/references/_index.md)" "$NO_REVIEWS")"
298+
"OS_GOVERNED_ENQUEUE_FIXTURE=$(fixture cross-repo-regen "$(files_of skills/objectstack-data/references/_index.md)" "$NO_REVIEWS")"
261299

262300
echo "== the deliberate exception switch =="
263301
expect allow 'OS_ALLOW_GOVERNED_ENQUEUE=1 on the blocking case' \

0 commit comments

Comments
 (0)