openai / openai/codex-plugin-cc
Stop-review gate: hung jobs pile up into livelock; review --wait can exit 0 without a verdict
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 33.3k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
Observed on plugin version 1.0.6 (macOS, Claude Code, Codex CLI via npm) during a long multi-agent session with the stop-review gate enabled. Three related defects in the review machinery, plus a skill-surface papercut. The review content was excellent throughout — one stop-gate run returned a correct, specific BLOCK on a real cross-tenant bug — so this is purely about the plumbing around the reviewer.
1. review --wait can exit 0 with no verdict (fails open)
Intermittently, codex-companion.mjs review --wait prints only the startup progress lines and exits 0:
[codex] Starting Codex review thread.
[codex] Thread ready (…).
[codex] Reviewer started: current changes
EXIT=0
No findings section, no # Codex Review block — while the underlying job stayed running for 11+ minutes with result: null until manually cancelled. Re-running the identical command worked (6m06s, full verdict). An agent taking the short output at face value reports a clean review that never happened.
Two contributing causes visible in the source:
handleReviewCommand(scripts/codex-companion.mjs, ~line 713) parses--wait/--backgroundbut never uses either — review always takes the same code path.- In
scripts/lib/codex.mjs,review/startruns against a source thread while the actual review executes on a spawnedreviewThreadId. Theturn/completedhandler (~line 541) treats completions for non-state.threadIdthreads as subagent turns and callsscheduleInferredCompletion; if the source thread's own turn completes immediately,completeTurnfires withfinalTurn.status === "completed"→buildResultStatusreturns 0 withreviewTextnever captured. Whether a verdict is captured is a race between the two threads' notifications, which matches the observed intermittency.
Suggested fix: exit non-zero (or a distinguishable status) whenever a review run produces no reviewText, regardless of turn status.
2. Jobs hang indefinitely; no idle timeout anywhere
Four stop-gate/review jobs hung with their progress logs frozen at ~2 tool calls in (typically a git show + one rg), and never advanced. There is no idle timeout, heartbeat, or watchdog in scripts/lib/app-server.mjs or the broker — a stalled turn sits running forever. The Stop hook's own 15-minute spawnSync timeout (stop-review-gate-hook.mjs:16) kills only the CLI child; the broker-side turn and job record stay running.
Also, when a job produces no result, parseStopReviewOutput / the JSON-parse catch (stop-review-gate-hook.mjs:69-139) reports it as "returned invalid JSON" — misleading: the job returned nothing. "No result / job hung" and "unparseable result" need different messages, because they need different operator responses (inspect the stuck job vs. re-run the review).
Suggested fix: an idle/no-progress timeout on turns that fails closed with a distinguishable status, and a hook message that separates the two failure modes.
3. Every blocked stop spawns a fresh gate job; they pile up into livelock
stop-review-gate-hook.mjs (~line 148) finds the already-running job for the session — and uses it only to compose a courtesy note, then unconditionally spawns a new task (~line 166). A session blocked N times accumulates N concurrent reviews of the same diff. Combined with #2: hung job → block → new job → also hangs → the session cannot end without manual /codex:cancel of each job. One session ended with five stop-gate jobs plus two manual reviews for ~three turns of actual work.
Suggested fix: reuse or supersede an in-flight gate job for the same session/diff instead of spawning per stop attempt.
4. Papercut: focus text is rejected by review, accepted by a variant the listing hides
/codex:review <focus text> fails at runtime (exit 1 after launching) because the native reviewer rejects focus text; the variant that accepts it (adversarial-review) is not surfaced in the skill listing, so agents discover this only by failing. The review skill also mandates an interactive wait-vs-background question, which autonomous (non-interactive) runs cannot answer.
Suggested fix: surface the focus-accepting variant in the listing, and make the wait/background choice defaultable for non-interactive use.
Happy to provide the full job records / progress logs for the hung runs if useful.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with handleReviewCommand in scripts/codex-companion.mjs, the turn/completed handling in scripts/lib/codex.mjs, and timeout/job behavior in scripts/lib/app-server.mjs and stop-review-gate-hook.mjs. Trace review --wait, stalled turns, and repeated stop-hook invocations; done means missing verdicts fail closed, hung jobs have a distinct outcome, in-flight gate jobs are reused or superseded, and the supported focus variant is surfaced.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- cli, devtools, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100