Driver
Review markers (<pr>-rex.approved, <pr>-ceo.approved, <pr>-design.approved) are bound to a specific HEAD SHA. When the author pushes new commits to an approved PR, the markers go stale — the merge gate catches this, but only at gh pr merge time, which can be hours or days after the push. The gap creates user-visible confusion ("Rex already approved, why is the merge blocked?") and false-starts at merge time.
Scope
Add .claude/hooks/warn-stale-review-markers.sh, wired to PostToolUse on Bash matching git push ….
The hook:
-
After a successful git push, detect the PR number for the current branch (gh pr view --json number --jq '.number').
-
If no PR exists, exit 0.
-
Check $(git rev-parse --show-toplevel)/.claude/session/reviews/<pr>-*.approved for markers.
-
For each existing marker, compare its SHA (file contents) against the current pushed HEAD.
-
If they differ, print a one-line warning per stale marker:
⚠ Stale review marker: <pr>-rex.approved (was <old-sha>, now <new-sha>)
Invoke /code-review again on the new HEAD before merging.
-
Optional per-config: auto-delete stale markers instead of warning (belt-and-braces — the merge gate still catches missed re-reviews, so deletion is conservative):
# .claude/project-config.json
review_markers:
on_stale: warn # or: delete
Acceptance Criteria
Risks / Dependencies
git push into a branch that doesn't have a PR yet should produce no output. Covered by the early-exit.
gh pr view requires network. On offline push, the hook should fail silently (exit 0) — covered.
- Choosing
on_stale: delete as default is tempting but would silently undo review state. Default to warn and let fork owners opt in.
Glossary
| Term |
Definition |
| Review marker |
A file under .claude/session/reviews/ containing the 40-char SHA of the commit that was approved. Written by the reviewer (Rex / CEO skill / design skill), checked by the merge gate. |
| Stale marker |
A review marker whose SHA no longer matches the current HEAD of the PR — usually because new commits were pushed after approval. |
| PostToolUse |
A Claude Code hook that runs after a tool call succeeds. Cannot block; used for warnings, auditing, and cleanup. |
Driver
Review markers (
<pr>-rex.approved,<pr>-ceo.approved,<pr>-design.approved) are bound to a specific HEAD SHA. When the author pushes new commits to an approved PR, the markers go stale — the merge gate catches this, but only atgh pr mergetime, which can be hours or days after the push. The gap creates user-visible confusion ("Rex already approved, why is the merge blocked?") and false-starts at merge time.Scope
Add
.claude/hooks/warn-stale-review-markers.sh, wired toPostToolUseonBashmatchinggit push ….The hook:
After a successful
git push, detect the PR number for the current branch (gh pr view --json number --jq '.number').If no PR exists, exit 0.
Check
$(git rev-parse --show-toplevel)/.claude/session/reviews/<pr>-*.approvedfor markers.For each existing marker, compare its SHA (file contents) against the current pushed HEAD.
If they differ, print a one-line warning per stale marker:
Optional per-config: auto-delete stale markers instead of warning (belt-and-braces — the merge gate still catches missed re-reviews, so deletion is conservative):
Acceptance Criteria
git push; silent if no PR exists for the branch.on_stale: deletemode removes stale markers; default mode only warns..claude/hooks/tests/cover: no markers, fresh markers, stale markers (warn), stale markers (delete), no PR.docs/rule-audit.mdentry added.Risks / Dependencies
git pushinto a branch that doesn't have a PR yet should produce no output. Covered by the early-exit.gh pr viewrequires network. On offline push, the hook should fail silently (exit 0) — covered.on_stale: deleteas default is tempting but would silently undo review state. Default towarnand let fork owners opt in.Glossary
.claude/session/reviews/containing the 40-char SHA of the commit that was approved. Written by the reviewer (Rex / CEO skill / design skill), checked by the merge gate.