---
title: "Review & approval"
description: "How o8 decides what's safe to merge — risk-classified blind review and a five-layer recovery ladder with a hard cost ceiling."
canonical_url: https://o8.run/docs/review-and-approval
md_url: https://o8.run/docs/review-and-approval.md
last_updated: 2026-06-25
version: "0.1.431"
stability: stable
---

# 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.**
