One commit, one change, one honest verdict.
Monorepo review the way the biggest shops actually run it: the unit of review is a commit with a stable Change-Id, approval sufficiency is computed from OWNERS files in your tree, and landing goes through a queue that promotes trunk fast-forward — through the same compare-and-swap every push uses.
Changes and patchsets, not branch soup
A change is one commit's review identity, keyed by its Change-Id trailer, so it survives rebase and amend. Each revision becomes a numbered patchset; registering the same commit twice acks instead of duplicating. Push a branch, register its tip, review commit by commit.
OWNERS files govern, and explain
Hierarchical OWNERS files — people, teams, *, set noparent — resolved against your org's live membership on every evaluation. Every verdict arrives in words:
blocked: needs an owner of /payments/gateway.rs (owners: alice@acme.dev, @payments)
Approvals that mean something
Approvals attach to a patchset, never to the change: push a revision and the count starts over, because yesterday's approval says nothing about code it never saw. Approvals come from people — a service token asking to approve is refused, in those words.
A queue, not a merge button
Landing re-verifies sufficiency at claim time, proves the fast-forward with a bounded ancestry walk, and promotes trunk by compare-and-swap. Landing a stack's top lands the whole stack. Ejections say exactly why —ejected: not fast-forward from 3f2a91c04d1b — and webhooks announce change.landed and change.ejected beside push.
A trunk nobody can push around
Protect a branch and it moves only through the queue. Every other door —git push over HTTP and SSH, the commits API, reset, revert, delete — answers with one sentence: branch 'main' is protected: land through review. Set the default branch per repo; protect it, and the verdict stops being advice.
Review at line resolution
The change view is one screen: the line diff, the conversation and the verdict side by side. Comments anchor to the exact line of the patchset and stay pinned when a revision answers them — "this was about patchset 1" is visible forever, and CI can say the perf suite regressed as honestly as a person.
How a landing works
The land request prechecks the verdict and refuses with its words if it blocks. Otherwise the change enters the queue as landing.
The lander re-runs sufficiency at claim time. An approval revoked in between counts: ejected: sufficiency lost.
A bounded ancestor walk proves the patchset descends from trunk's tip. Moved trunk? ejected: not fast-forward.
One compare-and-swap moves the ref. A racing push simply wins or loses the same CAS — never a forced ref, never a corrupt clone.
What ships today, and what is in design
Shipping now: changes, patchsets, per-patchset approvals, the OWNERS sufficiency engine with per-path explanations, the fast-forward land queue with stack landing, branch protection with a per-repo default branch, line-anchored review comments, and the Changes tab in the dashboard. In design for Repos customers: speculative batching in the queue, target-aware parallel landing, three-way merge for changes that drift, and interdiff review between patchsets. We publish what the queue cannot do as plainly as what it can.