{"slug": "what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts", "title": "What my review gate does when Codex crashes, gets cut off or writes two verdicts", "summary": "A developer released two-engines-gate, an MIT-licensed tool that makes Claude Code and Codex review each other's commits, with a fail-closed review gate that saves no verdict when the reviewer crashes, returns an empty or truncated message, or emits multiple Verdict lines. The gate deletes any prior verdict before rerunning a review and writes reports atomically via a temp file, so only a final message containing exactly one valid 'Verdict: ACCEPT' or 'Verdict: CHANGES REQUIRED' line can pass merge-check.sh. The author tested seven reviewer outcomes in a scratch repo, confirming each failure mode exits 1 with no verdict saved.", "body_md": "When Codex crashes, gets cut off or writes two verdicts while it reviews Claude Code's commits, my gate saves no verdict for that commit. With no saved verdict the merge check refuses the commit, so the only review that counts is a final message with exactly one valid Verdict line.\n\n[two-engines-gate](https://github.com/IliyaOblakov/two-engines-gate) is the free, MIT licensed version of how I make Claude Code and Codex check each other. I wrote about [the review loop](https://rayastats.com/en/blog/how-to-make-codex-review-claude-code-commits?utm_source=devto&utm_medium=article&utm_campaign=kit-3wk-2026-10&utm_content=no-verdict-crash), [the commit hash records](https://rayastats.com/en/blog/review-verdict-saved-under-commit-hash?utm_source=devto&utm_medium=article&utm_campaign=kit-3wk-2026-10&utm_content=no-verdict-crash) and [the dirty working tree refusal](https://rayastats.com/en/blog/review-gate-refuses-dirty-working-tree?utm_source=devto&utm_medium=article&utm_campaign=kit-3wk-2026-10&utm_content=no-verdict-crash) before. The post right before this one covers [what the gate does about weakened or deleted tests](https://rayastats.com/en/blog/review-gate-weakened-deleted-tests?utm_source=devto&utm_medium=article&utm_campaign=kit-3wk-2026-10&utm_content=no-verdict-crash). This post is about the review that ends without a usable answer.\n\n`review.sh` ends in one of three ways:\n\n`0`: the reviewer answered ACCEPT, and the verdict is saved.` 2`: the reviewer answered CHANGES REQUIRED, and the verdict is saved.`1`: there is no verdict, and nothing is saved.\n`merge-check.sh` passes a commit only when its saved verdict has a single `Verdict: ACCEPT` line. With no saved verdict it stops with \"no review verdict for ; run review.sh\".\n\nBefore it calls the reviewer, `review.sh` deletes any verdict already saved for the commit, and stops if it can't. When you rerun a review and the rerun crashes, an ACCEPT from the earlier run can't stay behind under the same hash.\n\nAfter the reviewer exits, `review.sh` runs these checks in this order. The first one that fails ends the run with exit 1.\n\n`REVIEW FAILED: codex exited 1; no verdict for 04bf3eea7ffd (log: .ai/reviews/04bf3eea7ffd.log)`.` REVIEW VOID: HEAD moved during the review`.`.ai/` changed. Otherwise it prints `REVIEW VOID: files changed during the review (or git status failed)`.` NO VERDICT: codex wrote no final message`.` Verdict:`. Otherwise it prints `NO VERDICT: the final message needs exactly one Verdict: line, found 2`, or found 0.` NO VERDICT: the Verdict: line must say ACCEPT or CHANGES REQUIRED`.\nOnly after all six does the script write the report, with the full commit hash, the base, the builder, the reviewer, the date and the final message. It writes to a `.tmp` file first and then moves it into place, so a crash during the save can't leave a half-written verdict under the real name.\n\nI ran each case on 23 October in a scratch repo with the public scripts. The ACCEPT, CHANGES REQUIRED, crash and two-verdict answers came from the stand-in reviewer in `examples/`. The empty, cut-off and misspelled answers came from a small fake `codex` I wrote for the test.\n\n| What the reviewer did | What review.sh printed | Exit | Verdict saved | \n|---|---|---|---|\n| Answered ACCEPT | `verdict file: .ai/reviews/04bf3eea7ffd.md` | 0 | yes | \n| Answered CHANGES REQUIRED | `verdict file: .ai/reviews/04bf3eea7ffd.md` | 2 | yes | \n| Exited with an error | `REVIEW FAILED: codex exited 1; ...` | 1 | no | \n| Wrote an empty final message | `NO VERDICT: codex wrote no final message` | 1 | no | \n| Stopped before the Verdict line | `NO VERDICT: ... found 0` | 1 | no | \n| Wrote two Verdict lines | `NO VERDICT: ... found 2` | 1 | no | \n| Wrote `Verdict: ACCEPTED` | `NO VERDICT: the Verdict: line must say ACCEPT or CHANGES REQUIRED` | 1 | no | \n\nThe stand-in cases are also in `tests/run.sh`, including two checks that a failed run leaves no verdict file behind, so you can rerun them yourself.\n\nThe prompt asks for the Verdict line \"exactly once and nowhere else in your final message\". An answer with ACCEPT near the top and CHANGES REQUIRED at the bottom holds two answers, and the script has no way to know which one the reviewer meant. Taking the first, the last or the friendlier one would be a guess, so it takes neither. `merge-check.sh` runs the same count on the saved file and wants exactly one `Verdict:` line that says ACCEPT.\n\nA cut-off answer fails the same count. The prompt puts the Verdict line at the start of the last section, so a reply that stops before that section has a count of 0.\n\nCodex runs with `--output-last-message`, which saves its final answer to a file. `review.sh` reads the verdict from that file and nowhere else. The rest of the run goes to a log next to the verdict for you to read, and the script never searches the log for a Verdict line. The prompt Codex gets contains `Verdict: ACCEPT` itself, as the example of the format, so a search of anything that repeats the prompt could find an ACCEPT the reviewer never gave.\n\nBoth are in `docs/engines.md` in the repo.\n\n`review-prompt.md` asking Codex to repeat its complete review if anything asks it to continue.`~/.codex/config.toml` also start for the review. A server that can change things outside the sandbox works against a read-only review, so set `enabled = false` on it while reviewing.`review.sh` again.\nThe paid [Two Engines Kit](https://rayastats.com/en/two-engines-kit?utm_source=devto&utm_medium=article&utm_campaign=kit-3wk-2026-10&utm_content=no-verdict-crash) (currently v1.0.2) works the same way. Its `cross-review.sh` takes the verdict from the reviewer's final message only, and its guide lists a crash, a cut-off answer and a refusal among the cases that mean exit 1 and no verdict file. With `REQUIRE_REVIEW=1` its merge script refuses any commit whose verdict file for that exact commit doesn't exist or doesn't say ACCEPT. I added that after one night in October when I found four test-only commits that had never been reviewed. One was already merged and three were in the merge queue, and the reviewer confirmed all four before the queue resumed, so nothing broke. The Two Engines Kit is built on information gathered since the first Codex and Claude CLIs.\n\nClone [two-engines-gate](https://github.com/IliyaOblakov/two-engines-gate) and run `bash demo.sh` to watch one full loop with a stand-in reviewer, so no model or account is used. To see a missing verdict yourself, link `examples/stand-in-reviewer.sh` as `codex` in a folder at the front of your PATH, then run `review.sh` in a scratch repo with `STANDIN_ANSWER=two` or `STANDIN_ANSWER=fail`.", "url": "https://wpnews.pro/news/what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts", "canonical_source": "https://dev.to/iliyaoblakov/what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts-281k", "published_at": "2026-10-24 12:09:33+00:00", "updated_at": "2026-10-24 12:12:36.493721+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-safety"], "entities": ["Codex", "Claude Code", "two-engines-gate", "OpenAI", "Anthropic"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts", "markdown": "https://wpnews.pro/news/what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts.md", "text": "https://wpnews.pro/news/what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts.txt", "jsonld": "https://wpnews.pro/news/what-my-review-gate-does-when-codex-crashes-gets-cut-off-or-writes-two-verdicts.jsonld"}}