chore(#115): warn-stale-review-markers.sh PostToolUse hook#120
Merged
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new PostToolUse hook
warn-stale-review-markers.shthat fires aftergit pushand surfaces review markers invalidated by new commits — immediately, instead of atgh pr mergetime.The gap it closes: when an author pushes new commits to a PR that already has Rex / CEO / design approvals on record, those markers are now stale (their recorded SHA ≠ PR HEAD). The merge gate catches this, but only at merge attempt — which can be hours or days after the push. Result: confusing "why is my merge blocked, Rex already approved?" moments. This hook makes the invalidation visible the moment it happens.
.claude/hooks/warn-stale-review-markers.sh(~135 LOC, PostToolUse, non-blocking).claude/hooks/tests/test_warn_stale_review_markers.sh— 8 cases, all pass.review_markers.on_stale(warndefault,deleteopt-in) via the shared config lib landed in [Chore] Make ticket-prefix whitelist + schema project-configurable (not hardcoded) #109.claude/project-config.defaults.jsonwith areview_markerssubtree.claude/settings.json— PostToolUse matcher onBashcommands matchinggit pushdocs/rule-audit.mdHow it works
git push. Non-blocking by design — PostToolUse exit 2 would push noise into the conversation; this hook is purely informational.gh pr view --json number. Silent exit 0 if no PR.gh pr view --json headRefOid— same source of truth the merge-gate hooks use post-fix: merge gate hooks don't catch gh api .../merge bypass #47 / [Bug] Merge-gate hooks read local HEAD instead of PR HEAD — forces manual 'gh pr checkout' before every merge #55. Falls back to local HEAD with a visible warning ifghis offline.$(git rev-parse --show-toplevel)/.claude/session/reviews/<pr>-*.approvedfor files whose recorded SHA doesn't match HEAD.review_markers.on_stale: "delete"): removes stale markers so the merge gate's "marker missing" message is crisper than "marker stale".git pushoutput and the natural property that a failed push means the remote HEAD didn't advance — markers stay fresh).Testing
Ran the committed test fixture — 8 cases, all pass:
Small tangential fix in the test fixture: the sandbox setup now copies the shared config reader (
_lib-read-config.sh) and the shipped defaults (project-config.defaults.json) into the isolated repo, so the sandboxed hook resolves config the same way it would in a real fork. Previously the sandbox didn't include the shared lib, and thedelete-modetest would silently fall back towarnbecauseconfig_get_orreturned the default. Not a production issue (real forks always have both files after #109), but a correctness improvement to the test harness.Scope — what this does NOT do
block-unreviewed-merge.sh) — that still catches stale markers at merge time as a final backstop./approve-merge,/approve-design, or the Rex agent.--no-verifypushes bypass this hook (same as any PostToolUse). Acceptable — bypass discipline is covered by the existing rule ("never skip hooks").Glossary
.claude/session/reviews/<pr>-<reviewer>.approvedcontaining the 40-char SHA of the approved commit. Written by Rex //approve-merge//approve-design.warn/deletewarnprints a stderr line per stale marker; opt-indeleteremoves the marker so the merge gate reports "missing" rather than "stale".Closes #115