openai / openai/codex-plugin-cc

stop-review-gate-hook.mjs: fail-closed reason strings do not mention the /codex:setup --disable-review-gate escape valve

Open
#483 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
33.3k
Forks
2.3k
PR merge metrics
No merged PRs in 30d

Description

Summary

When stopReviewGate: true, scripts/stop-review-gate-hook.mjs emits {"decision":"block","reason":"..."} on any of 5 fail-closed branches (timeout, task failure, invalid JSON, empty rawOutput, unexpected first-line). The reason string is the ONLY message operators see — Claude Code's Stop-hook does not offer a UI for hook decisions beyond the reason text.

The reason strings currently include "Run /codex:review --wait manually or bypass the gate." — but the concrete "bypass the gate" command is not spelled out. Operators in a fail-closed loop (e.g., 3 consecutive infra failures with empty rawOutput) cannot discover the escape valve /codex:setup --disable-review-gate from the message they see.

Failure scenario (observed)

A derivative Claude Code session on 2026-07-09 hit 3 consecutive status: 1 / rawOutput: "" failures from the underlying Codex CLI. Each time, the Stop hook fired at 15-min timeout limits and re-blocked. The session became terminaion-incapable — CC's built-in ~9-iteration recursive-stop limit was the only path out.

The operator recovered manually by finding the escape valve in tritool-side docs (.claude/rules/safety-gate.md §14). Without those tritool-side docs, the escape valve is not discoverable.

Proposed fix (3 options, any one closes the loop)

(a) Reason-string literal command (smallest change)

Append the literal command to all 5 fail-closed branches:

"Run /codex:review --wait manually or bypass the gate by running /codex:setup --disable-review-gate."
(b) Distinguish infra failure vs rule violation via reasonCategory field

CC's Stop-hook decision schema accepts extra fields. Adding:

{
  "decision": "block",
  "reason": "...",
  "reasonCategory": "infra_failure" | "rule_violation"
}

lets downstream (e.g., tritool-side wrapper Stop hook) handle infra failures differently — e.g., downgrade to advisory after N consecutive infra failures.

(c) Consecutive-N counter + downgrade

Persist a counter in the plugin's state file (stateModule.setConfig). After N consecutive infra failures (recommended default N=3), downgrade decision: block → advisory ({"continue":true, "systemMessage":"..."}) so the session can terminate. Reset the counter on any allow / successful review / rule-violation block.

Reproduction

  1. stopReviewGate: true (/codex:setup --enable-review-gate)
  2. Make the underlying Codex CLI fail 3 times consecutively (e.g., simulate by unavailable auth or config drift)
  3. Observe Stop hook blocks each iteration with the same reason string
  4. Confirm the operator cannot discover the escape valve from the reason string alone

Environment

  • codex-plugin-cc: v1.0.4 (sha 807e03a at time of investigation)
  • Claude Code: v2.1.198
  • OS: Linux (verified 2026-07-09), likely applies to all platforms

Cross-reference

Tritool-template documented the discovery gap in docs/runbook-cc-codex-outage.md §8 (see linked repo URL) and .claude/rules/safety-gate.md §14 (Plugin hooks Stop row) as short-term workaround for their derivative projects. Filing here so the fix can land upstream and eliminate the need for the downstream doc.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with scripts/stop-review-gate-hook.mjs and inspect the five fail-closed branches that emit the block reason. Compare their current messages with the proposed escape-valve wording and decide which of the three proposed fixes is intended. Done means the selected fix covers the reported repeated-failure scenario and the operator can discover an escape path.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.