Review & approval
How o8 decides what's safe to merge — risk-classified blind review and a five-layer recovery ladder with a hard cost ceiling.
"Nothing risky merges without your sign-off" has two halves: an AI half that catches what a human would miss on a fast-moving fleet, and a human half that keeps you the final gate. Here's how the AI half decides.
Risk is a path, not a vibe
Before any model reads a diff, a fast mechanical pass reads its shape — how much changed, whether whole files were rewritten, whether anything matches a dangerous pattern (an eval, an injection-flavored string, a mass deletion). That's triage, not the verdict.
Then risk is decided by what the diff touches:
| The diff touches… | Risk | What it gets |
|---|---|---|
| Schema, migrations, the lane state machine, the merge gate | High | a blind second review |
| Whole-file rewrites or dangerous patterns | High | a blind second review |
| Ordinary feature and UI code | Standard | one review, then merge |
The logic: a subtle bug in a button color breaks one screen; a subtle bug in schema or the merge gate breaks the system every other agent depends on. So the dangerous diffs earn a second look, and the ordinary ones don't waste one.
The blind second reviewer
For a standard diff, a passing first review is enough — it clears the merge. For a high-risk diff, the first approval is deliberately not enough: it can only nominate the change. The merge stays blocked until a second, independent reviewer agrees.
And that reviewer is blind by design. It's handed only the diff and the checks it must produce — never the first reviewer's verdict, score, or reasoning. There is nothing to rubber-stamp. It has to satisfy the protocol on its own: every guard live, every write partitioned correctly, every sub-requirement covered, and the execution path actually reaching the changed code. It returns one of a fixed set of verdicts — agree, disagree, or inconclusive — and only an independent agree turns the nomination into a cleared merge. Anything else sends the change back up the chain.
On the dangerous diffs, one model saying "looks good" doesn't open the gate. It opens a second, independent review.
When a merge fails: the escalation ladder
A branch can be green when it's written and still fail at merge time — main moved underneath it. o8 rebases onto current main and re-runs the typecheck before landing; if that fails, the lane doesn't stall and it doesn't loop forever. It climbs a fixed five-layer ladder — cheap and automatic at the bottom, you at the top — only as far as it has to:
| Layer | What happens | Who decides |
|---|---|---|
| 1 — Auto-rerun | one automatic retry, handing the worker the full typecheck output to fix its own branch | the system |
| 2 — Escalate | layer 1 failed → hand the lane to the orchestrator with the reason attached | the system |
| 3 — Steer | nudge the still-warm session to fix it in place — it already has full context | the orchestrator |
| 4 — Redispatch | the session's dead or the diff's wrong at the root → a fresh worker, with feedback | the orchestrator |
| 5 — Human card | the orchestrator tried 1–4 and it's still wrong → an explicit handoff to you | you |
Two things make this a budget instead of a loop:
- Layer 1 means one. Exactly one free automatic retry, counted since the lane's most recent dispatch — so a deliberate re-dispatch starts fresh, but a single failing run never spirals.
- Warm before cold. The orchestrator prefers steering the warm session (cheap — the worker still has everything loaded) over a fresh worker, and only escalates to a human when both are exhausted. The order is the point.
Most tools answer a failed merge by retrying until it works or until you notice — a runaway bill, a silent stall, or both. o8's answer is bounded: one automatic turn, then bounded attention, then you. Recovery is a budget, not a loop.