fix: honor stop_hook_active in the stop-review-gate hook - #565
Open
mittalpk wants to merge 1 commit into
Open
Conversation
When the review gate is enabled, main() ran the stop-time Codex review
and emitted {"decision":"block"} on any non-ok outcome (no output,
timeout, failure, invalid JSON) without checking whether this
invocation was already a forced retry. Claude Code re-invokes Stop
hooks with stop_hook_active: true after a block decision, so a review
that times out or fails would re-run and re-block on every retry,
until the harness's forced-retry cap force-ends the turn -- worst in
exactly the cases where the gate is least useful.
Fix: skip the review and return cleanly when stop_hook_active is set,
matching the fix the issue reporter suggested. The issue also flagged
codex-companion.mjs's `config.stopReviewGate` branches as worth
auditing for the same problem; traced them and confirmed they're only
config get/set/report code, not the review-blocking logic itself
(that lives solely in stop-review-gate-hook.mjs), so no second file
needs the fix.
Added a regression test that snapshots the fake Codex binary's
appServerStarts counter before and after a stop_hook_active retry,
proving the review subprocess is not spawned a second time and no
"decision":"block" is emitted. Confirmed the test fails against the
pre-fix code (git stash isolation) with the exact stale block
decision the issue describes. Full suite: 92/92 passed, no
regressions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
Fixes #548.
Summary
When the review gate is enabled,
main()instop-review-gate-hook.mjsruns the stop-time Codex review and emits{"decision":"block"}on any non-okoutcome (no output, timeout, failure, invalid JSON) — without checking whether this invocation is already a forced retry.Claude Code re-invokes Stop hooks with
stop_hook_active: trueafter ablockdecision. Since this hook never checked that flag, a review that times out or errors would re-run and re-block on every retry, until the harness's forced-retry cap force-ends the turn — worst in exactly the cases where the gate is least useful (a broken/slow review blocking the session 9× before being overridden).Fix
Skip the review and return cleanly when
input.stop_hook_activeis set, matching the fix the issue itself suggested:The issue also flagged
codex-companion.mjs'sconfig.stopReviewGatebranches as "worth auditing... for the same issue." I checked — those are only config get/set/report code (buildSetupReport,handleSetup), not the review-blocking logic itself, which lives solely instop-review-gate-hook.mjs. Confirmed viagrep -rl "decision.*block\|runStopReview\|stop_hook_active"acrossplugins/that only this one file implements it, so no second file needs the fix.Tests
Added a regression test that:
appServerStartscounter.stop_hook_active: true.appServerStartsis unchanged — proving the review subprocess was never spawned a second time, not just that the output happened to look right.Confirmed the test fails against the pre-fix code via
git stashisolation, reproducing the exact stale block decision the issue describes (Codex stop-time review found issues that still need fixes...).Verification
npm test: 92/92 passed, no regressions..eslintrc*/eslint.config.*).npm run build(tsc) requires a livecodex app-server generate-tsrun to produce.generated/app-server-types, which needs an actual Codex CLI installation not available in this environment — this change touches no TypeScript files, so it's out of scope for this fix, but flagging honestly rather than silently skipping it.