Part of #303 (process hardening). Ships the last Wave-3 hook, H10.
What
A PR merge is allowed only when a Review-verdict: comment references the PR's current head sha — proving the latest commit was reviewed, not a stale earlier diff. Mechanizes the ersatztv#242 lesson ("re-review the fix commit, not just the initial PR diff").
Folds into the existing H6 pretooluse-merge-consent.sh as condition (c) — reusing its PR fetch, docs-only exemption, and Gitea-auth-from-env, so there's one detection path, no drift (per the #303 methodology review). No new hook file, no settings.json change (already wired on the merge tool).
Convention
After an adversarial/Codex review of a PR (or its latest fix commit), post a PR comment with a line:
Scope: the Claude PreToolUse gate on the Gitea merge tool only (a direct git push origin main has no PR comments; docs-only PRs stay exempt via H6's file-set exemption).
Verification
Pipe-tested 12 cases end-to-end against the real hook via a fake curl on PATH (positive@head short/full sha, stale@old-sha, negative@head, marker-no-sha, quoted-convention-no-sha, comments-fetch-fail, docs-only-exempt, H6 unticked-Done-when regression, non-merge passthrough, positive-among-noise). bash -n clean. All green.
Docs
docs/decisions.md — new H10 entry + TOC line (pure append; passes the H9 append-only guard without [decisions-edit]).
CLAUDE.md — Task Completion Protocol updated to describe condition (c) + the Review-verdict: convention.
This PR is docs/process-only → exempt from the merge gate itself. Adversarial review + a dogfooded Review-verdict: comment to follow.
Part of #303 (process hardening). Ships the last Wave-3 hook, **H10**.
## What
A PR merge is allowed only when a `Review-verdict:` comment references the PR's **current head sha** — proving the *latest* commit was reviewed, not a stale earlier diff. Mechanizes the ersatztv#242 lesson ("re-review the fix commit, not just the initial PR diff").
Folds into the existing H6 `pretooluse-merge-consent.sh` as condition (c) — reusing its PR fetch, docs-only exemption, and Gitea-auth-from-env, so there's **one detection path, no drift** (per the #303 methodology review). No new hook file, no settings.json change (already wired on the merge tool).
## Convention
After an adversarial/Codex review of a PR (or its latest fix commit), post a PR comment with a line:
```
Review-verdict: <MERGEABLE|APPROVED|BLOCKED|NOT-MERGEABLE> @ <head-sha>
```
## Decision tiers (mirror H6's graceful adoption)
| State | Decision |
|---|---|
| positive verdict @ current head | **allow** |
| verdict @ an older sha (stale review) | **deny** — the #242 failure mode |
| head verdict is negative (BLOCKED) | **deny** |
| `Review-verdict:` marker but no sha / none yet | **ask** |
| comments unfetchable / head sha unresolvable | **ask** |
Scope: the Claude PreToolUse gate on the Gitea merge tool only (a direct `git push origin main` has no PR comments; docs-only PRs stay exempt via H6's file-set exemption).
## Verification
Pipe-tested 12 cases end-to-end against the **real** hook via a fake `curl` on PATH (positive@head short/full sha, stale@old-sha, negative@head, marker-no-sha, quoted-convention-no-sha, comments-fetch-fail, docs-only-exempt, H6 unticked-Done-when regression, non-merge passthrough, positive-among-noise). `bash -n` clean. All green.
## Docs
- `docs/decisions.md` — new H10 entry + TOC line (pure append; passes the H9 append-only guard without `[decisions-edit]`).
- `CLAUDE.md` — Task Completion Protocol updated to describe condition (c) + the `Review-verdict:` convention.
This PR is docs/process-only → exempt from the merge gate itself. Adversarial review + a dogfooded `Review-verdict:` comment to follow.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Folds condition (c) into pretooluse-merge-consent.sh (H6): a PR merge is
allowed only when a `Review-verdict:` comment references the PR's CURRENT
head sha — proving the latest commit was reviewed, not a stale earlier diff
(mechanizes the ersatztv#242 "re-review the fix commit" lesson).
Graceful adoption mirrors H6's Done-when tiering:
- positive verdict @ head -> allow
- verdict @ older sha (stale) -> deny (#242 failure mode)
- head verdict negative -> deny
- marker with no sha / none yet -> ask
- comments unfetchable -> ask
Reuses H6's PR fetch, docs-only exemption, and Gitea-auth-from-env (one hook,
no detection drift — per the #303 methodology review). Pipe-tested 12 cases.
Docs: decisions.md (new H10 entry + TOC), CLAUDE.md Task Completion Protocol.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review found false-opens in the first cut:
- `grep -F "$short"` was an unanchored substring test: a MERGEABLE verdict for
a DIFFERENT/older commit was accepted whenever the head 7-prefix appeared
anywhere on the line (inside a longer sha, or an unrelated commit URL). Now
each verdict line's `@ <sha>` token is extracted and matched to head by git
short-sha prefix semantics (head begins with token, token >=7 chars).
- No retraction semantics: a later `BLOCKED @ head` didn't override an earlier
`MERGEABLE @ head`. Now a negative verdict on head wins -> deny.
- A 7-digit build number falsely tripped the "references an older commit" deny;
the `@`-anchored parse fixes it -> a marker with no @sha now asks, not denies.
Also documents the issue-comment scope (gate reads issues/{pr}/comments, not
Gitea formal-review bodies). Pipe-tested: 16 cases incl. 4 adversarial
false-open reproductions, all now deny/ask. bash -n + shellcheck clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second adversarial re-review (of the fix commit itself — dogfooding H10) found
a remaining false-open: the `review-verdict:` marker was matched anywhere on a
line, so a comment merely QUOTING the positive template — an instruction
("please post: Review-verdict: MERGEABLE @ <head>"), a blocking comment
explaining how to clear itself, or the gate's OWN suggestion text echoed into a
comment — was classified as a real head verdict and self-approved the merge.
Fix: anchor the marker to line-start (`^[[:space:]]*review-verdict:`). A real
verdict line starts with the marker; quoted/instructional uses have text before
it. Also drops the dead `nosha` var (SC2034).
Finding 2 (a BLOCKED mis-anchored to an OLDER sha doesn't retract a
MERGEABLE@head) is deliberately NOT "fixed": staleness is symmetric — a
pre-fix BLOCKED@oldsha must not block forever after the fix changes the sha and
earns a fresh MERGEABLE@head. To retract, re-review head and post BLOCKED@head.
Documented in decisions.md.
Pipe-tested 21 cases (5 new: instructional-quote, self-reference reason-text,
line-start-in-multiline, leading-whitespace, blocking-quotes-template), all
deny/ask/allow correct. bash -n + shellcheck clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Final re-review returned SHIP-IT with one contrived, pre-existing residual: a
line starting `Review-verdict: BLOCKED …` that ALSO contains a second literal
`review-verdict: mergeable` substring later on the same line read as positive.
Anchor the is_pos check to line-start so only the line's OWN leading verdict
word counts. Safe-by-construction: anchoring a positive matcher can only REDUCE
the allow-surface, so it cannot introduce a false-open (the dangerous
direction); the 21-case regression confirms no false-deny (all still
allow/deny/ask as before) + a new B6 case for this exact vector. No further
review round needed — the change is monotonic. shellcheck clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dogfooding the convention this PR ships. Three independent adversarial review rounds (one per fix commit — the #242 discipline H10 encodes):
R1 found 3 false-opens (unanchored grep -F "$short" substring sha match; no retraction semantics; false-deny on 7-digit build numbers) → fixed by @ <sha>-field parsing + git short-sha prefix matching + negative-verdict-wins.
R2 (re-review of the R1 fix) found the self-reference false-open (a comment quoting the positive template — including the gate's own suggestion text — self-approved) → fixed by anchoring the marker to line-start.
R3 (re-review of the R2 fix) returned SHIP-IT; the one contrived pre-existing residual (double-marker on one BLOCKED line) closed by anchoring is_pos too (monotonic, safe-by-construction).
Verification: 22 pipe-tested cases incl. 6 adversarial false-open reproductions, all deny/ask/allow correct; bash -n + shellcheck clean. Non-blocking accepted residual: markdown-formatted verdicts (**bold**, - list) fall to ask (safe) — the plain line-start convention is documented in decisions.md.
Note: this PR is docs/process-only → exempt from the H6/H10 gate itself; verdict posted for demonstration.
Review-verdict: MERGEABLE @ 938733c3
Dogfooding the convention this PR ships. Three independent adversarial review rounds (one per fix commit — the #242 discipline H10 encodes):
- **R1** found 3 false-opens (unanchored `grep -F "$short"` substring sha match; no retraction semantics; false-deny on 7-digit build numbers) → fixed by `@ <sha>`-field parsing + git short-sha prefix matching + negative-verdict-wins.
- **R2** (re-review of the R1 fix) found the self-reference false-open (a comment *quoting* the positive template — including the gate's own suggestion text — self-approved) → fixed by anchoring the marker to line-start.
- **R3** (re-review of the R2 fix) returned SHIP-IT; the one contrived pre-existing residual (double-marker on one BLOCKED line) closed by anchoring `is_pos` too (monotonic, safe-by-construction).
Verification: 22 pipe-tested cases incl. 6 adversarial false-open reproductions, all deny/ask/allow correct; `bash -n` + shellcheck clean. Non-blocking accepted residual: markdown-formatted verdicts (`**bold**`, `- list`) fall to `ask` (safe) — the plain line-start convention is documented in decisions.md.
Note: this PR is docs/process-only → exempt from the H6/H10 gate itself; verdict posted for demonstration.
timothy
merged commit 2879c012ba into main2026-07-12 19:32:00 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of #303 (process hardening). Ships the last Wave-3 hook, H10.
What
A PR merge is allowed only when a
Review-verdict:comment references the PR's current head sha — proving the latest commit was reviewed, not a stale earlier diff. Mechanizes the ersatztv#242 lesson ("re-review the fix commit, not just the initial PR diff").Folds into the existing H6
pretooluse-merge-consent.shas condition (c) — reusing its PR fetch, docs-only exemption, and Gitea-auth-from-env, so there's one detection path, no drift (per the #303 methodology review). No new hook file, no settings.json change (already wired on the merge tool).Convention
After an adversarial/Codex review of a PR (or its latest fix commit), post a PR comment with a line:
Decision tiers (mirror H6's graceful adoption)
Review-verdict:marker but no sha / none yetScope: the Claude PreToolUse gate on the Gitea merge tool only (a direct
git push origin mainhas no PR comments; docs-only PRs stay exempt via H6's file-set exemption).Verification
Pipe-tested 12 cases end-to-end against the real hook via a fake
curlon PATH (positive@head short/full sha, stale@old-sha, negative@head, marker-no-sha, quoted-convention-no-sha, comments-fetch-fail, docs-only-exempt, H6 unticked-Done-when regression, non-merge passthrough, positive-among-noise).bash -nclean. All green.Docs
docs/decisions.md— new H10 entry + TOC line (pure append; passes the H9 append-only guard without[decisions-edit]).CLAUDE.md— Task Completion Protocol updated to describe condition (c) + theReview-verdict:convention.This PR is docs/process-only → exempt from the merge gate itself. Adversarial review + a dogfooded
Review-verdict:comment to follow.🤖 Generated with Claude Code
Adversarial review found false-opens in the first cut: - `grep -F "$short"` was an unanchored substring test: a MERGEABLE verdict for a DIFFERENT/older commit was accepted whenever the head 7-prefix appeared anywhere on the line (inside a longer sha, or an unrelated commit URL). Now each verdict line's `@ <sha>` token is extracted and matched to head by git short-sha prefix semantics (head begins with token, token >=7 chars). - No retraction semantics: a later `BLOCKED @ head` didn't override an earlier `MERGEABLE @ head`. Now a negative verdict on head wins -> deny. - A 7-digit build number falsely tripped the "references an older commit" deny; the `@`-anchored parse fixes it -> a marker with no @sha now asks, not denies. Also documents the issue-comment scope (gate reads issues/{pr}/comments, not Gitea formal-review bodies). Pipe-tested: 16 cases incl. 4 adversarial false-open reproductions, all now deny/ask. bash -n + shellcheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Second adversarial re-review (of the fix commit itself — dogfooding H10) found a remaining false-open: the `review-verdict:` marker was matched anywhere on a line, so a comment merely QUOTING the positive template — an instruction ("please post: Review-verdict: MERGEABLE @ <head>"), a blocking comment explaining how to clear itself, or the gate's OWN suggestion text echoed into a comment — was classified as a real head verdict and self-approved the merge. Fix: anchor the marker to line-start (`^[[:space:]]*review-verdict:`). A real verdict line starts with the marker; quoted/instructional uses have text before it. Also drops the dead `nosha` var (SC2034). Finding 2 (a BLOCKED mis-anchored to an OLDER sha doesn't retract a MERGEABLE@head) is deliberately NOT "fixed": staleness is symmetric — a pre-fix BLOCKED@oldsha must not block forever after the fix changes the sha and earns a fresh MERGEABLE@head. To retract, re-review head and post BLOCKED@head. Documented in decisions.md. Pipe-tested 21 cases (5 new: instructional-quote, self-reference reason-text, line-start-in-multiline, leading-whitespace, blocking-quotes-template), all deny/ask/allow correct. bash -n + shellcheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Review-verdict: MERGEABLE @
938733c3Dogfooding the convention this PR ships. Three independent adversarial review rounds (one per fix commit — the #242 discipline H10 encodes):
grep -F "$short"substring sha match; no retraction semantics; false-deny on 7-digit build numbers) → fixed by@ <sha>-field parsing + git short-sha prefix matching + negative-verdict-wins.is_postoo (monotonic, safe-by-construction).Verification: 22 pipe-tested cases incl. 6 adversarial false-open reproductions, all deny/ask/allow correct;
bash -n+ shellcheck clean. Non-blocking accepted residual: markdown-formatted verdicts (**bold**,- list) fall toask(safe) — the plain line-start convention is documented in decisions.md.Note: this PR is docs/process-only → exempt from the H6/H10 gate itself; verdict posted for demonstration.