- check
- test · cargo nextest run -p acme-billing -p acme-tax -p acme-ledger
- tests
- 213 green · 1 red · 0 skipped · 214 judged (target 214)
- failed
- billing::invoice_rounds_half_up
- log
assertion `left == right` failed left: 400 right: 201 at crates/billing/src/invoice.rs:188- reproduce
- modernci ci --from lane-billing --only test -- billing::invoice_rounds_half_up
- diff
- 3 files, +41 −12 · crates/billing/src/invoice.rs, …/config.rs, …/tests/invoice.rs
- second witness
- not a flake: fails alone, and on a second machine, 3 of 3
- attempts
- none yet
- precedent
- r-12: "Invoice totals round half-up, never per customer."
- sealed
- **/tests/**, golden/** · only a human order unseals them; weakening goes to Questions
Committed, judged, merged — or appealed.
An agent says it's done. ModernCI opens the pull request, judges it on the cheapest machine that finishes in time, and merges it on a green verdict. On red, the move is appealed: a work item goes to an agent with everything a fix needs. Every step goes on the record, metered.
Committed
The agent pushes its branch and calls done over MCP, naming a parent if the branch is stacked. ModernCI opens the pull request, or reuses the open one. Agents use four tools: done, claim, report and ask.
// request { "name": "done", "arguments": { "repo": "acme/monorepo", "branch": "lane-billing", "parent": null } } // result { "move": "lane-billing → predev", "pr": 4399, "state": "judging", "checks": 7, "deadline": "20m" }
Judged
Each check's input key is looked up first: the content of every file, env var and toolchain the check read. A stored green costs nothing. The rest run on the cheapest backend that finishes before the branch file's deadline, using each check's measured duration. The result is a verdict, green or red, and it cites its evidence. Moves waiting for a backend sit on the docket.
| Check | Input key | Result | Time |
|---|---|---|---|
| build | reused | 0s | |
| clippy | reused | 0s | |
| test · 3 crates affected | red | 4m 21s | |
| gates | green | 1m 02s | |
| oracle | reused | 0s |
| Backend | Free slots | Finishes in | Price | Chosen |
|---|---|---|---|---|
| warm-1 · your server, hot build dir | 1 | 6m | $0.000 | yes |
| laptop-ana · your laptop | 1 | 14m | $0.000 | slower, cold |
| cloud-c7 · spot, 16 vCPU | 8 | 5m | $0.012/min | not needed |
Merged
The verdict lands as one ci status on the head commit, stamped with the engine and config that made it. On a green verdict, the target fast-forwards onto the judged commit. If the target moved and the moved commits touch the move's inputs, only the affected checks re-run first.
● ci green 7 checks · 5 reused · 2 run on warm-2 · 3m 40s evidence 1,418 tests judged (target 1,418) · logs · input keys stamp engine 0.4.2 · config predev.yaml@3f9c0e1 merged predev fast-forwarded to 8f3a2c1 · done to merge 11m
A verdict made by an older engine or config is stale. ModernCI judges the move again on its own, and a new engine shadows the old one before it judges anything.
Red becomes a work item
Every red has an owner within one tick. The work item carries what a fix needs, and nothing the agent has to go and find.
Appealed
The failure ladder sends the item to an available agent host, which pushes a fix. ModernCI judges the failing check first, on a warm host, and judges the full move again only if that comes back green. A bad fix costs one check, not a whole move.
Limits and questions
A host that hits a usage limit reports limited with its reset time. It gets no work, its items go back on the docket without counting an attempt, and it resumes on its own. An agent that needs a decision calls ask, and its item stays under a stay, shown with its reason, until a person answers. The answer becomes a ruling, and later prompts follow it as precedent.
| Host | Runtime | State | Item |
|---|---|---|---|
| mbp-3 | claude | busy | wi-0412 |
| studio-1 | codex | limited until 14:00, resumes itself | returned to the docket |
| laptop-ana | claude | ready | none |
The golden for invoice totals has the old half-even rounding. Update the golden, or change the code back to half-even?
- Update
golden/billing/invoice.jsonto half-up. (agent recommends: matches ruling r-12) - Revert the code to half-even.
What keeps agents honest
Built for agents means built for agents that cut corners. ModernCI takes no agent's word.
- Per-test truth. Per-test results (JUnit, nextest and the like) are judged, not just the exit code. Zero tests, a duration collapse or a count drop against the target is red. Tests that disappear are listed on the move.
- Evidence, not claims. A fix for a failing test must show red before and green after, measured by ModernCI.
- Sealed paths. Deleting or loosening an assertion, skipping a test or editing a golden is sealed: only a human order unseals it. It goes to Questions, not to merge.
- Flakes named by cause. A suspect gets a second witness: it is re-run alone, under load and in isolation on a second backend, and classed as load, shared state, clock, port race or infra. The agent fixes the cause instead of adding a retry.
- Evidence on every verdict: logs, test counts, input keys and stamps.
The engine underneath
One desired-state loop runs everything. Webhooks, polls, agent reports and timers only mark a move dirty. A green, unmerged move stays in the gap until it merges, even if no event arrives. Silence was the most expensive failure we lived, so nothing stalls without an alarm.
The loop runs at least once every 20 seconds. If the last full pass is older than three ticks, stall.loop fires.