Verification & gates
What stands between an agent's diff and your branch — the contract, the gates, the evidence critic, and the rules they all obey.
In most coding harnesses, whether tests run is the model's choice, and the only thing that blocks a bad change is a person reading the diff. In baro, acceptance is machinery. This page is what that machinery actually is.
Contract first
Before any code is written, the Architect compiles your goal into a machine-checkable contract: invariants (what must stay true) and obligations (what a story must prove, each carried as an acceptance criterion). The planner cannot close a run while an obligation has no owner — that check is fail-closed, and the coverage gap is announced on the run stream at every fragment admission, while it is still fixable.
The gates
Every gate lives in a gate registry that binds three things together: the rule, the module that enforces it, and a conformance test that proves the enforcement. A run announces the gates it will enforce at start — enforced means announced: nothing judges your work silently.
| Gate | What it blocks |
|---|---|
| declared tests | a story merges only after the tests it declared pass — run through a fail-closed command translator (see below) |
| build-before-commit | the project must build before a commit is accepted |
| evidence critic | a cheap model judges each story against its acceptance criteria using captured command output — fingerprinted, fresh, tied to the exact bytes changed — not the agent's claims |
| write surfaces | each story declares the files it owns; a diff outside the surface is refused, and two stories can't own the same file |
| altitude | a file already past 1,500 lines that gains 80+ in one story is reported to the reviewer — growth of god-objects is flagged, not silent |
Merges happen in isolated git worktrees with sealed lineage — a story's work integrates onto exactly the base it was reviewed against.
Declared tests are translated, never trusted
A story doesn't get a shell. Its declared test commands pass through a
translator with an allowlist — npm / pnpm / yarn / npx, cargo, node,
git, composer / phpunit / ddev — and are executed with no shell in between
(execFile, not sh -c). A command the translator can't prove safe is
rejected, and the rejection says why. Fail-closed: the run gate then proves
the whole tree once, after integration.
The repair recipe
Gates judge meaning, never spelling. Three rules, learned the hard way and now enforced at every gate that talks to a model:
- Reject meaning, never spelling. Harmless format drift — an extra field, a paraphrased criterion whose id is unambiguous, a dropped element the host already holds — is canonicalized host-side with an announced warning. The canonical form is what downstream consumers see, so canonicalization is strictly stronger enforcement, not weaker.
- Every rejection carries the complete defect list — plus the exact shape to produce — so a repair round fixes everything at once instead of dying one error at a time.
- Never ask the model to reproduce what the host already knows. Ownership is claimed by name (an obligation id, a predicate index), and the host supplies the canonical text itself.
The one hard exception: authority is never canonicalized. Host-assigned correlation fields — run ids, session ids, lease generations — are checked fail-closed on receipt; a model-supplied value there is rejected, never silently repaired. That rule has its own conformance test, and it has caught a real regression before merge.
What the human sees
A pull request the gates already accepted: the goal, the plan, a story table with commit SHAs, the verification evidence, and any advisory findings (like altitude reports). Review is still yours — it just starts from verified, not from claimed.
How it works
Two processes, a mozaik event bus, bounded contexts, and an anti-corruption layer in front of every model — the architecture behind a run.
Run from the cloud — baro connect
Pair a machine as a remote runner. Fire goals from a dashboard, a teammate, or a GitHub issue — they run on your machine over your own subscription, code never leaving it.