Ledger-Mediated Orchestration: Vendor-Independent Autonomous Software Delivery over a Pool of Coding Agents

Abstract. A single autonomous coding session is not autonomous software delivery: it loses its state when it crashes, it dies when one vendor's quota is exhausted mid-task, and it has no place where a person is required to decide. We present a ledger-mediated orchestration model built on three constraints and one calculus. All delivery state is a pure function of an append-only ledger, \(\mathrm{state}(t) = f(\mathrm{ledger}_{\leq t})\), so a handoff between engines is a scheduling event rather than a loss of state; the database now enforces the invariant, and we state what it still cannot refuse. A handoff is admitted only by a pure, model-free no-loss predicate. Four human gates in a six-phase machine each require a recorded verdict, which silence never supplies. And an exact-head calculus binds every automated verdict to the revision it judged, with a production trace in which a budget guard ran before the freshness test and escalated a head that no longer existed. Beside these, a capacity taxonomy gives a rate window a deadline and exhausted credits none, and lets a capacity verdict outrank a completion claim. Supporting mechanisms follow: a leased PostgreSQL queue, an allow-listed engine environment, and a reviewer bound to what it read. The evidence is one project's tracked records. On one 24 GB machine with a fixed local model and a 900 s deadline, successful throughput sat between 0.99 and 2.00 generations per minute for offered concurrency 2 through 32, left that band at 64 and 96, and collapsed at 128: a single-slot saturation curve, not a general law. The local reviewer caught 18 of 25 small planted defects (Wilson 95% interval 0.524 to 0.857), blocked none of 14 clean changes, and twice passed a defect its own summary named. A scan of the integration branch found that only BUILD ran without a person and that the forty merges before it went in through the ruleset bypass. Adversarial verifiers refuted 16 of 18 leading claims of a storm audit. We say what the records do not show, including that no controlled comparison with another delivery system has been run.

Artifacts. This paper is typeset from docs/paper.md and published as PDF, DOCX and HTML. The complete documentation is published as a book: PDF, DOCX, EPUB and print HTML. Every empirical figure in the section on what the records measure is recomputed from tracked sources: scripts/paper_evidence.py recomputes its numbers, scripts/paper_figures.py redraws its figures, the storm's storm-evidence.py regenerates its evidence table, scripts/minimum_specs.py its tables of minimum requirements, and scripts/autonomy_scorecard.py its autonomy scorecard. The one exception, the storm throughput audit, is named where we use it. The large-diff study we report is in progress, and its committed record is cited at the cutoff its own log gives. Unless a passage names its own, the evidence cutoff is develop at 3bb577a4e (#1354), with the forge read on 2026-10-02 between about 10:55 and 11:20Z; what the paper says of the 3.4.0 release is at develop at 4d51a764c (#1365), with the forge read at about 17:45Z. This revision restructures the paper after an external review, at develop at c8d8d2cce (#1440) on 2026-10-06; it adds no measurement, and where it names the 4.0.0 and 4.1.0 releases it reads CHANGELOG.md at that revision. The visual atlas holds forty figures: twenty-five drawn from the model as deterministic TikZ in this source, and fifteen computed from tracked repository records, so the PDF, its labels and its diagrams are reviewable and reproducible rather than screenshots detached from the system. An executive summary follows, naming the section that carries each claim. Every section from the Introduction to the Appendix closes with a box headed In plain words that restates it for a reader who is not a specialist; the boxes add nothing the formal text does not say, and a specialist may skip them.

Executive summary

Each item names the section that carries it.

  • Introduction. A coding session is not a delivery system: it loses its state on a crash, dies with one vendor's quota, and has no place where a person must decide. The paper's three contributions are the ledger invariant with what the database does and does not enforce, the no-loss handoff gate, and exact-head evaluation with its production counterexample, with the capacity taxonomy beside them; everything else is a supporting mechanism or a measurement.
  • The ledger invariant. All delivery state is a pure function of an append-only ledger, so a crash is a replay and a handoff is a scheduling event. The invariant was a convention of the application until 3.0.0; the database now refuses updates, deletes and truncation of the ledger, and still cannot stop the application role from forging provenance.
  • The no-loss handoff gate. A handoff between engines is admitted only by a pure, model-free predicate over the brief and the ledger. A failing handoff is retried, escalated to the full transcript, or parked for a person, never a silent partial.
  • Capacity verdicts. A rate window may carry a deadline; exhausted credits never acquire one, which the type, a property test and a database constraint each enforce. A capacity verdict outranks a completion claim, in the orchestrator and inside every runner.
  • Exact-head evaluation and the release calculus. Every automated verdict is a claim about one exact commit and speaks for no other; the review and repair loop terminates in a bounded number of repairs; a production trace shows a budget guard that ran before the freshness test and escalated a head that no longer existed. The local reviewer is bound to what it read, caught 18 of 25 small planted defects (Wilson 95% interval 0.524 to 0.857) and blocked none of 14 clean changes, and its failures on large diffs are under a preregistered study (research/large-diff-review/experiments/) with production unchanged.
  • Queue semantics. Work is claimed with FOR UPDATE SKIP LOCKED under renewable leases; execution is at least once and the acknowledgement is fenced so exactly one commit lands per job; a priority lane is derived from the record, never remembered, and never admits past a gate.
  • The six-phase machine. Four human gates, each a parked job plus a recorded verdict; silence never decides unless a project has declared, kind by kind, that a deployment gate may resolve to its stored default; an operator can abandon a project from any phase.
  • The engine family. One bounded, never-blocking core under every runner; an environment assembled from an allow-list, never copied from the worker; a sovereign local driver with a measured fit; local engines chosen first by smooth weighted round robin, paid engines as the fallback.
  • Deterministic retrieval and fail-closed bootstrap. Lexical retrieval a reviewer can replay, and a bootstrap layer that appends before it acts.
  • What the records measure. A single-slot saturation curve on one 24 GB machine: 0.99 to 2.00 generations per minute from offered concurrency 2 through 32, leaving the band at 64 and 96 and collapsing at 128. A local pilot; a storm ledger whose audit adversarial verifiers refuted in 16 of 18 leading claims; host benchmarks and weekly minimum requirements; the repository's own history; an autonomy scan that found only BUILD running without a person and forty merges made through the ruleset bypass; and a completion-time prediction that holds inside the band only, with what would falsify it and what it does not cover.
  • Comparison with alternatives. How ledger-mediated orchestration differs in kind from a session runner that keeps its transcript as truth, from an outbox plus a workflow engine, and from a CI ruleset plus a human approval; and that no controlled head-to-head has been run.
  • Discussion. Convergence-Driven Development kept as a scoreboard, and the claim that governance is the scarce input narrowed to this project's record.
  • Validation. The property, chaos and live levels at which the model is checked, and how the paper's own figures are reproduced.
  • Related work. Where the ledger, the gate and the calculus sit beside schedulers, event sourcing, agent frameworks, workflow engines and platform automation.
  • Conclusion. The ledger, not the session, at the centre; and what remains to be measured.
  • Declarations. Where the data and code are, how generative AI was used, who the author is and under what funding and interests, and which reporting guidelines and registrations apply.
  • Appendix. The operational record from 3.0.0 to 4.1.0, for an operator of this repository.
\begin{plainwords}[The paper in plain words]
Computers can now write computer programs. But one robot programmer working alone is not enough to finish a real project. It forgets everything when it crashes. It runs out of its allowance in the middle of a job. And it does not know when a person needs to make a decision. Vibey fixes this with three ideas. First, a notebook that nobody can erase: every decision, every finding and every handoff is written in the notebook before it counts, so a new helper can pick up exactly where the old one stopped. Second, a queue with rules: jobs wait in line, a helper borrows a job for a short time and must keep renewing it, and a job that a crashed helper dropped goes back in the line by itself. Third, six checkpoints, and at four of them a person must say ``yes'' out loud before the work moves on. We also timed one small computer. Asked to do more at once, it finished about one or two pieces a minute until it was overloaded, and then it fell over. That says what one machine can do, not what the world can do. And we say plainly what we have not yet measured. Every section below ends with a box like this one.
\end{plainwords}

Introduction

Let an engine be an autonomous coding session runner over one vendor's model, and let \(E = \{e_1, \dots, e_m\}\) be a pool of such engines with independent failure and capacity behavior. A coding session is not a delivery system: it loses its state when the process holding it crashes, it dies with the quota of the one vendor it runs on, and it has no place at which a person must decide. The delivery problem is to carry a specification from human intent to deployed software over \(E\) under three constraints that single-session tooling violates: (i) no vendor session may be the source of truth; (ii) human decisions must occur at defined points, not wherever a session stalls; (iii) exhaustion of one vendor's capacity must not lose work.

We answer them with three rules, each stated formally below and checked against the project's own records. First, state is a pure function of an append-only ledger: nothing is updated or deleted, a correction is a new event that supersedes an earlier one, and a worker that dies is replaced by one that replays. Second, a handoff from an exhausted engine to the next is admitted only by a model-free no-loss predicate, a check on the brief that no model evaluates; a brief that fails it is never passed on as a silent partial. Third, silence never counts as a verdict, and a parked job is a row in the database, not a thread waiting on a terminal: a gate no person has answered stays open unless a project has declared, kind by kind, that a deployment gate may resolve to its stored default.

The system that embodies these rules is one repository holding a family of packages: the orchestrator; session runners over paid vendor models and over a local model; a tool that owns provenance, merging and release; a retrieval engine over a skill library; and a bootstrap layer for cloud workloads. Fig. 1 shows the path a unit of work takes: a triaged issue is claimed under a lease held in PostgreSQL, becomes a project in its own worktree, is built by the local engine, stops at a human review gate, and is published as a draft pull request that the merge train takes only when every check is green. The bridge that feeds the machine never edits a branch: the worker writes code, the phase machine decides when it may, and the forge decides when it merges. Every exit that is not a success (an expired lease, a capacity pause, an open gate, a red check) is written to the project's evidence record as what it was, never as a completion.

Figure 1. The durable delivery path. A triaged issue is claimed under a lease, becomes an ordinary vibey project in its own worktree, is built by the sovereign engine, stops at the human review gate, and is published through the push gate as a draft pull request, promoted by the pull-request automation, that the merge train takes only when every check is green. Each non-success exit (dashed) is written to the project's evidence record as what it was.

Our contributions are three. The first contribution is the ledger invariant, with a soundness argument and a statement of what the database enforces about it and what it does not: an application role can still write provenance it did not earn. The second contribution is the no-loss handoff gate, a predicate on a handoff brief that no model evaluates. The third contribution is exact-head evaluation, a release calculus that binds a verdict to the revision it judged, with a repair bound, the condition under which it terminates, and a recorded production counterexample. Beside these three sits the capacity taxonomy: a credit balance is never given a clock, and a capacity verdict always outranks a completion claim.

Supporting mechanisms carry the contributions into a running system, each stated below with its own evidence: the onion architecture of the orchestrator; a queue on PostgreSQL with leases, so a dead worker's job is reclaimed; the six-phase machine and its four human gates; an environment every engine starts from by allow-list; a priority lane whose contents are derived from the record rather than remembered, so that it orders work without preempting it or admitting it past a gate; the checks that bind a reviewer's verdict to the input the model actually read; and the sovereign driver that runs the local model.

The evidence is one project's records: a single-slot saturation curve measured on one machine; a canary that measured the local reviewer's recall on planted defects; an audit of a local storm that located its binding constraint, its conversion losses and its declared but unenforced controls; and a scan, on 2026-09-30, of how far the delivery loop ran without a person.

The orchestrator itself is an onion of four layers with dependencies pointing inward only (Fig. 2): a pure domain with no I/O, no clock and no network; an application layer of services; an infrastructure layer that talks to PostgreSQL, the bus and telemetry; and the cli and tui shells. A single composition root, bootstrap.py, wires them. The rule is enforced by an import linter in CI, and four of the five layers fail the build under 100% branch coverage.

Figure 2. The orchestrator is an onion. Code may only depend on the layers inside it, and the pure domain at the centre never touches a database, a clock or the network. One file, bootstrap.py, wires the layers together from outside, and four of the five layers must keep every branch of their code tested. Line counts are read at revision d4c4e1f8, the revision the history figures are read at.

What the body does not do matters as much. We ran no controlled head-to-head against another system. Every measurement is one project's records read at a named cutoff, and none is a claim about other projects or other models. Convergence-Driven Development appears only as a scoreboard in Discussion. The operational record from release 3.0.0 to 4.1.0 is an appendix.

\begin{plainwords}
Think of a team of robot helpers, each from a different company. Any of them can quit halfway through a job, and none of them remembers anything once it crashes. Vibey is the team captain. It keeps one shared notebook that nobody may erase, hands out jobs one at a time so that a job whose helper quit can be picked up by the next one, and stops at fixed moments to ask a person. The rest of this paper explains each part, and then checks the whole design against real records from the project's own history, including the places where it did not work.
\end{plainwords}

The ledger invariant

\begin{invariant}[Write-ahead intent]
Every decision, finding, and handoff is a row in an append-only ledger before it
takes effect; consequently $\mathrm{state}(t) = f(\mathrm{ledger}_{\leq t})$ for a
pure $f$, independent of any vendor session.
\end{invariant}

The ledger admits inserts and nothing else: no updates, no deletes. A correction is a new event that supersedes the one it corrects, and the record of the mistake stays. The per-project sequence number is claimed inside the same transaction as the insert, so every ledger range has a well-defined digest. Every event also carries a link, the SHA-256 of the link before it and of every stored field of the event, from a genesis of the project's own; the chain is derived from the rows rather than stored, so it covers all of history, and a published ledger shard carries its verified chain head. The chain detects a rewrite. It does not detect a forged append, a limit we return to below. The function \(f\) is a set of pure projections (the open items, the decision log, the cost report) computed from the event sequence alone.

Two properties follow from the invariant rather than from any worker: a crash is a replay, and a handoff is a scheduling event. Every job is idempotent under replay: a worker that dies mid-job has recorded its intent before each effect, its lease expires, and the next worker re-derives the same state from the record and continues, with duplicates dropped by identity. Crash recovery and engine handoff follow as corollaries: a successor engine re-derives its context from the ledger alone, so a credit exhaustion on \(e_i\) between turns of an item reschedules the item onto \(e_j\) with the open-question set intact. Fig. 3 draws the cycle: each engine turn appends its events before anything acts on them, and when an engine runs dry the brief that seeds its successor is checked against that ledger by the no-loss gate (see The no-loss handoff gate), then retried, escalated or parked for a person, never silently dropped.

Figure 3. Append before act. Every intent and engine turn is written to the ledger before anything acts on it. When an engine exhausts its credits, a handoff brief is checked against that ledger by the no-loss gate; only a passing brief seeds the next engine. A failing brief is retried, escalated, or parked for a person, never silently dropped.

The same rule holds at two further scales, in two other parts of the system, and Fig. 4 shows the three side by side. At the orchestrator scale the ledger event is appended, the state is projected from it, and only then may the job proceed. At the service scale a transactional outbox row is committed in the same transaction as the state change it announces, a dispatcher reads committed rows only, and the external call is made at least once and marked delivered once. At the audit scale a chain link \(c_i = H(c_{i-1} \| r_i)\) is appended, a verifier re-hashes from \(c_0 = H(r_0)\), and any edit breaks every later link. In each lane the record is durable before the effect is allowed, and a crash at any step replays from the record.

Figure 4. Append before act, at three scales. Each row is one part of vibey (the ledger, the outbox, the audit chain) and reads the same way: the intent is saved, the state is derived from that record, and only then may the effect happen. A crashed worker restarts from the record. The bootstrap layer below keeps the same rule at start-up.

What the database enforces, and what it does not

Until 3.0.0 the invariant was manners, a convention of the application. It held against vibey's own queries and against little else: two DO INSTEAD NOTHING rules on the partitioned parent table event. ADR-0055 records what a scratch database with every migration applied (PostgreSQL 18) did on 2026-09-24 when addressed as the role vibey connected as. An UPDATE of event changed nothing, silently, so the attempt was hidden rather than refused. An UPDATE and a DELETE addressed to the default partition changed and deleted rows, because a rule on a partitioned parent does not fire for a statement aimed at a partition. TRUNCATE event emptied the ledger, because rules never fire on TRUNCATE. After DISABLE RULE an update went through. The role that connected owned the table, and in the Helm chart it was also the image's superuser; the same DSN had reached every engine session (What an engine may see), so a session steered by text a model had read held the means to erase the ledger unrecorded.

The repair (#1100, ADR-0055) has two parts, because neither alone is a boundary. First, triggers replace the rules: a row trigger before update or delete and a statement trigger before truncate refuse every rewrite, the owner's included, with an error rather than a silent no-op. PostgreSQL clones the row trigger onto every partition, present and future, but not the statement trigger, so a function attaches the truncate guard to every partition on every migration run. Second, the roles split. The owner's DSN runs migrations and nothing else. The application role, which every worker, command, operator and scaler connects as, owns nothing and holds on event only SELECT and INSERT, with no DELETE or TRUNCATE anywhere. Its grants are declared in code, derived from the application's own queries, and reconciled on every migration run, so a grant added by hand does not survive the next one. The whole test suite now runs as that restricted role; its first run found 35 failures, none a missing grant in application code, all of them test setup doing owner-only work or assertions of the old silent no-op.

What the guard refuses is recorded three ways. The independent review of #1100, as the application role, tried updates, deletes and truncations of the parent and of partitions, disabling, re-enabling as replica and dropping the triggers, detaching and attaching partitions, and switching the session to replica mode, and every one was refused (review probes of 2026-09-24). The merged tests pin the refusals of updates, deletes and truncations of the parent and of a partition, and of disabling or dropping the triggers; the rest remain review probes, not tracked tests. At the cluster level a cluster-smoke step checks the same contract: as the worker's role, an update, a delete and a truncation of the ledger are refused for want of privilege and disabling a trigger is refused as not the owner; as the owner, all three are refused by the triggers (#1100).

The guard's reach is narrower than the word append-only suggests, and we state it. The triggers refuse the owner's rewrites of rows, not the owner's schema changes: the owner can still disable a trigger, drop a partition, detach one and delete from it, or truncate a partition created since the last migration run, so the owner's DSN is the thing to guard. Event triggers that would refuse such changes need a superuser to install and are future work; a superuser can do anything. The application role cannot rewrite what is there, but it can still insert into event directly, so it can forge an event's provenance, sequence number or production time, and it can update the sequence counter; an append function running with the owner's rights, as the only write path, would close that, and it is the next step, not a done one (ADR-0055). And the split protects the ledger only once the owner and every superuser need a password: a local PostgreSQL that trusts its socket, the common developer default, lets any process running as the right operating-system user connect as a superuser with no DSN at all, and ADR-0055 records exactly that on the operator's machine. Same user, same authority: no grant separates processes of one operating-system account.

The record of the repair is not clean, and we keep it. The review found the design sound and five defects in its first implementation, two rated high, and #1100 had merged while the review said not yet; #1112 closed all five on 2026-09-24. The worst: where the application role may create objects in the public schema, the PostgreSQL 14 default and that of any database upgraded from it, it could plant an operator that the owner's unqualified catalog query resolved during migration, run code as the owner, and leave a backdoor that erased the ledger while the migration reported the guard in force. ADR-0055, as first merged, had judged that privilege harmless to the ledger, and was wrong; the repair pins the search path of the guard functions and of the owner's session and takes CREATE on public from every role but its owner, and the appendix records the migration that does so. The second: the owner's DSN reached any process whose shell exported it, because the application's start-up read it and the README exported it; now only the migration command reads it. #1112 promised an independent re-review before the operator's merge; no verdict on the merged result is recorded in a tracked source, so we report the fix, not a review of it.

One privilege the guard must revoke is not per database. The grant that lets a role set session_replication_role, which silences every trigger, the ledger's guard included, lives in one pg_parameter_acl row for the whole cluster, so two reconciles on different databases of one cluster race on it, and the per-database migration lock cannot serialize them. Until #1310 the loser's revoke failed and the reconciler swallowed every database error at that step, so the grant could stay in place without a word. It was CI, not the authors, that found it: a pull request's checks on PostgreSQL 16 showed the application role still able to set the parameter after a reconcile. One race then produced three distinct error messages, and chasing them one at a time sent us after its cause in the tests (#1332); the tests now serialize their grants of that privilege, which repairs the tests only. In production the race remains, and what holds is a bounded retry that matches the three messages; a lock that spans the cluster is a recorded follow-up, not a repair (#1326, #1332).

\begin{plainwords}
The ledger is a diary written in pen. You can add a page but never tear one out; a mistake gets a new page that says so. Because the diary is the only source of truth, any helper can read it and catch up. Until recently that promise was only good manners: anyone with the main key could tear pages out. Now the database itself refuses, helpers hold a key that can only read and add pages, and the key that could switch the refusal off is kept from them. A helper can still add a page that lies about who wrote it; closing that is the next job, and the computer's owner can still do almost anything.
\end{plainwords}

The no-loss handoff gate

A handoff from engine \(e_i\) to engine \(e_j\) carries a brief \(\beta\): objective, constraints, done and remaining work, open questions, decisions, assumptions, findings, artifacts, and a reference \(\rho\) to the ledger range it summarises. The brief is admitted only if a pure predicate \(\mathrm{gate}(\mathrm{ledger}_{\rho}, \beta)\) holds, evaluated without any model call. Pure means the predicate is a function of its two inputs, the ledger range and the brief, and of nothing else.

\begin{invariant}[No loss]
Let $\mathrm{open}_k(\rho)$ be the ids opened by event kind $k$ in range $\rho$ and
not closed or superseded. The gate holds iff $\mathrm{open}_k(\rho) \subseteq
\mathrm{ids}_k(\beta)$ for $k \in \{$questions, decisions, assumptions, findings,
artifacts$\}$ (R2--R5, R7); every remaining-work item of the last verdict appears in
$\beta$ (R1); the digest of $\rho$ recomputed from the ledger equals the digest
carried by $\beta$ (R6); the budget carried by $\beta$ agrees with the ledger's (R8);
every hard constraint of the specification is restated (R9); and no free-text field
of $\beta$ carries a tool grant, a permission change, or an acceptance-criteria
mutation (R10).
\end{invariant}

The gate has modes. In strict mode all ten rules apply. A failing brief is regenerated with the specific violations fed back, up to three strict attempts. The gate then escalates to full-transcript mode, which makes the brief advisory: the successor is to work from the whole range \(\rho\), so the gate stops checking R1--R5, R7 and R9, while R6, R8 and R10 still run, because they check facts about the range and the brief's containment rather than its completeness. Further failure parks the item on a human gate, a parked job that a person decides. A fourth, forced mode is reserved for an explicit operator override. As Fig. 3 shows, a handoff that fails the gate is a retry, an escalation, or a human decision, never a silent partial.

The full ledger range is always written to disk inside the receiving worktree, and the seed prompt names it. In the current implementation that file is how the range reaches the successor; it is not inlined into the seed. In full-transcript mode, therefore, completeness rests on the successor reading the file, not on the gate. Inlining the range into the seed, or keeping the closure rules enabled until it is inlined, is open work.

The same gate guards a second handoff that never touches the project ledger (ADR-0070): the operator's own driving session, on a capacity rejection, fails over to the sovereign engine and later hands back. Its brief names the session transcript by path, line count and SHA-256 with the repository head, and the gate checks that digest against the transcript as it stands (vibey.domain.driver_brief). The modes are the same; the failover is appended to the driver's own append-only, hash-chained ledger before the local run starts; the handback is allowed only after a successful probe of the exhausted engine is recorded, and its return brief is gated the same way; nothing starts on a failed gate.

\begin{plainwords}
When one helper hands a job to another, it writes a short note: what the job is, what is done, what is left, and which questions are still open. Before the new helper may start, a strict checker compares the note with the diary. If the note forgot an open question, the checker says no and asks for a better note, up to three times. After that it tells the new helper to read the whole diary instead. If even that fails, a person is asked. Nothing is ever quietly lost.
\end{plainwords}

Capacity verdicts

Every answer an engine returns is sorted into a capacity value before its completion claim is read. The discrimination the family is built around separates a window, a rate limit that will reopen, from exhausted credits, a balance that no amount of waiting refills.

\begin{invariant}[Waitability]
A window is waitable under a deadline: a bounded probe re-tests capacity and the
excursion is capped by $W_{\max}$. A credits state carries no deadline at all. It may
be re-probed on a bounded backoff in case a human tops the balance up, but it is never
scheduled as if it will reopen at a time.
\end{invariant}

In the orchestrator capacity is four-valued: available, a waitable window with an optional reset time, exhausted credits, and failed authentication. The rule that credits have no clock is enforced at three independent layers. The credits type has no reset field; a property test asserts that no credits state ever produces a deadline; and a database CHECK constraint rejects an engine-health row that pairs exhausted credits with a reset time.

The runners classify in the same order of precedence. claudeloop checks credit signals before the window path, so a billing failure is never read as a waitable window even when a stray reset time rides along with it. codexloop keys on the vendor's machine-readable error code and type before anything else (insufficient_quota is an exhausted quota, never a window), consults the HTTP status only when neither decides it, and never lets a status, a retry header or a completion claim outrank a body-level billing marker.

\begin{theorem}[Capacity outranks completion]
A completion claim observed while capacity is not available is recorded but not
believed: a starved model emits plausible final output, so a run that ends for
capacity is always attributed to capacity and never laundered into success.
\end{theorem}

Completion is read from a structured per-turn verdict where the vendor supports one, with an explicit done marker as the fallback, and the capacity verdict is consulted first either way (Fig. 5).

Figure 5. The orchestrator sorts every engine answer into four capacity values. A window is a rate limit that will reopen, so waiting is allowed under a cap. Exhausted credits have no clock: three separate checks, in the type, a test and the database, stop anyone from scheduling them like a window. Each runner maps its own states onto these four.

The taxonomy was stretched at both ends. The Gemini runner still drawn in the figure, retired by ADR-0078 on 2026-10-03, metered per-model quotas whose dimensions did not collapse, so it carried a five-member state and computed quota boundaries from the vendor's Pacific-time day; its probes could tune when the next probe fired, never whether a wait ended, and every excursion stayed capped by \(W_{\max}\). The local runner has no vendor. Its capacity is hardware, with the states available, locally busy and misconfigured, and nobody refills it by adding a payment method. Model acquisition is explicit: the install-health check never downloads weights, and installing a model is a separate, deliberate command, because a surprise multi-gigabyte download is itself a capacity event on the constrained machine the runner exists to respect.

The same order holds above the runners. A capacity rejection defers the job and opens the rejecting engine's circuit until its backoff passes, and the queue counts a capacity deferral among the conditions that decide whether an item may run at all, which a priority bump can never override (Queue semantics). The delivery bridge that feeds the six phases from the forge applies the rule once more (Fig. 6): after every worker run it reads the project's status, and if any job is awaiting capacity or any engine's circuit reports a capacity state other than available, it records a pause for capacity and stops before it acts on the run's phase or its open gates. The phase is acted on only on the branch where capacity was available, so a starved run cannot be laundered into success at either level.

Figure 6. Capacity precedence in the delivery bridge. The capacity check runs before the bridge acts on the run's phase, so an exhausted or busy engine records a pause, never progress; the same order holds inside each session runner, where a capacity verdict outranks a completion claim.
\begin{plainwords}
An engine can stop for two very different reasons. Sometimes it has hit a speed limit
that lifts by itself, so waiting a bounded time is sensible. Sometimes the account is
simply empty, and no amount of waiting fills it. The system keeps those two apart in
three places at once, so nobody can mark an empty account as ``try again at four
o'clock''. And whenever an engine says ``I finished'' while it was also out of
capacity, the system believes the capacity signal and not the finish, because a
starved model still produces confident-looking output. The same check runs again one
level up, before any stage of the work is marked done.
\end{plainwords}

Exact-head evaluation and the release calculus

The orchestrator's output is a pull request, and what happens to it is governed by vibey-gh. Let a pull request's evolution be the finite sequence of heads \(H = \langle h_0, h_1, \dots, h_n \rangle\). An automation system emits claims (scan results, review verdicts, gate conclusions) and acts on them by merging, releasing, or halting for an operator. The folk assumption is that a claim about \(h_i\) speaks for the pull request. It does not: it speaks for \(h_i\) alone.

\begin{invariant}[Exact-head]
Every claim is a pair $(c, h_i)$, and no decision procedure over head $h_j$ may
consume a claim $(c, h_i)$ with $i \neq j$.
\end{invariant}

The calculus and its termination

Evaluation is a pure function over the head, its check results, and a persisted state \(\sigma = (a, r, v, k)\): attempts consumed, last-reviewed revision, its verdict, and refills used. For head \(h\) and repair budget \(A\),

\[E(h, \sigma) = \begin{cases} \mathsf{pending} & \text{checks incomplete} \\ \mathsf{review} & r \neq h \\ \mathsf{ready} & r = h \land v = \top \\ \mathsf{repair} & r = h \land v = \bot \land a < A \\ \mathsf{blocked} & r = h \land v = \bot \land a \geq A \end{cases}\]
\begin{invariant}[Budget placement]
The guard $a \geq A$ is evaluated only where a repair would be spent, strictly
after the freshness test $r \neq h$. Reviews are free; only repairs are counted.
\end{invariant}

The implementation refines \(E\). It adds a sixth state, \(\mathsf{conflict}\), for a head that no longer merges with its base, budgeted by the same counter as \(\mathsf{repair}\). A failing verdict whose only findings came from the sovereign lane never spends a repair: the head returns to \(\mathsf{review}\). Where no paid lane is declared, as in this repository, \(\mathsf{repair}\) and \(\mathsf{conflict}\) are answered by a person, and a review that reaches no verdict is recorded with a code from a closed vocabulary, never as a pass. A branch-sync workflow can refill the budget, resetting \(a\) to zero, at most \(k_{\max}\) times per lineage (default 2, at most 10); this repository refills only by hand, under the same bound. Fig. 7 draws the function as a state machine.

Figure 7. The release calculus as a state machine. A pull request waits in Pending until its checks finish, then goes to Review because its newest commit \(h\) has no verdict yet. A pass leads to Ready; a fail leads to Repair while attempts remain, and every repair pushes a new commit that must be reviewed again. Only when the fail arrives with the budget spent does it become Blocked. An automatic refill, the branch-sync workflow's self-heal, reopens it at most \(k_{\max}\) times, two by default, and after that only a person can. Not drawn: a failing verdict whose only findings come from the local model's review returns the head to Review without spending a repair.
\begin{theorem}[Bounded repair]
Absent contributor pushes, every lineage performs at most $A\,(1+k_{\max})$ repairs,
where $k_{\max}$ (\texttt{branch\_sync.max\_self\_heals}, default 2) bounds the refills
of its budget, automatic or not. If, in addition, every check and review completes and
every failing verdict carries a finding that automated repair acts on, the lineage
reaches $\mathsf{ready}$, or $\mathsf{blocked}$ with every refill spent, within that
bound.
\end{theorem}
\begin{proof}[Proof sketch]
Heads advance only via repairs, since a contributor push begins a new lineage by
definition. A repair is dispatched only while $a < A$, and each one either increments
$a$ or, when the repairing agent reports the findings unfixable, spends nothing and
blocks the lineage for a person. $a$ resets only by a refill, and a refill is refused
once $k = k_{\max}$, so at most $A$ repairs follow each of at most $1 + k_{\max}$
fillings of the budget: the first claim. Under the second claim's hypothesis every
failing verdict either spends a repair or, with $a \ge A$, blocks, so every loop through
$\mathsf{review}$ strictly decreases the lexicographic measure
$\mu = (k_{\max} - k,\; A - a)$; $\mathsf{ready}$ absorbs, and so does
$\mathsf{blocked}$ once $k = k_{\max}$.
\end{proof}

The hypothesis of the second claim is not a formality, and we state the case it excludes as a limitation rather than prove past it. A failing verdict whose only findings come from the sovereign lane returns the head to \(\mathsf{review}\) with \((a, k)\) unchanged, so \(\mu\) does not decrease: the lineage spends no repair, but nothing in the calculus makes it terminate, and the implementation keeps no bound on those re-reviews. The same holds where no paid lane is declared. Fig. 8 shows stale claims invalidated across heads.

Figure 8. Every review verdict is a claim about one exact commit, written \((c,h_i)\). A repair moves the head from \(h_2\) to \(h_3\), so each earlier claim goes stale and cannot speak for the new head. The current head must be reviewed again, and only a fresh verdict on \(h_3\) can lead to a merge or release.

A production violation

With the budget guard evaluated before the freshness test, the following trace is reachable: reviews of \(h_0\) to \(h_2\) fail with findings, repairs produce \(h_3\) addressing all of them, \(a = A\), and evaluation of \(h_3\) hits the budget guard first and emits \(\mathsf{blocked}\). The lineage is escalated as unrepairable on the verdict of \(h_2\), a revision that no longer exists in the pull request. This trace occurred in production, and its terminal artifact, the escalation report, listed an empty set of remaining failures. That report is not tracked in this repository. Commit 4afafbae reordered the two guards, restoring the budget-placement invariant, and its regression test asserts that the counterexample now yields \(\mathsf{review}\).

Trust separation and release monotonicity

Four principals operate the loop, and the separation that matters is between judging and acting. The per-job platform token publishes claims. The reviewers judge: the paid reviewer through its API key, the sovereign lane on the self-hosted runner. The merge train merges with the automation token, and the same token pushes the guarded repair and conflict-resolution commits, so proposing revisions and merging are not held by disjoint credentials; in this repository paid repair and conflict resolution are declared off, so that path is dormant here. The fourth principal is bounded by a grant: a delegated approver, refused by vibey-gh approve-check on any change its own account wrote; it is declared, and by 2026-10-01 its account had approved no merge. The non-collusion property follows: a compromised judge cannot ship, and a compromised actor cannot write itself a passing verdict, though it could push a revision that must then be judged afresh. Third-party revisions are data to every principal (Fig. 9).

Figure 9. Four principals. The platform token publishes what the scans found. The reviewers, the paid reviewer's API key and the self-hosted runner of the local review, produce verdicts and can neither push nor merge. One automation token both pushes repair and conflict-resolution commits and merges, so revising and merging are not separated; where it is not set, the platform token stands in for it. The delegated approver approves, under the operator's grant, only changes its account did not write. No key that grades a change can ship it, and code from strangers is data to all of them.

Versions are derived, not remembered: for mainline \(M\) and change set \(\Delta\), \(\mathrm{ver}(M \cup \Delta) \geq \mathrm{ver}(M)\), with equality exactly when \(\Delta\) carries no shippable content, and the derivation is idempotent, so re-promoting identical content never compounds a bump. Published versions form a monotone sequence, and publishing an already-published version is a no-op, never an error.

Binding the reviewer to what it read

The exact-head invariant binds a claim to the revision it evaluated. A reviewer running on a local model needs a second binding, to the input the model actually read, because a local server can read less than it was sent without saying so. In 3.0.0 the review lane became sovereign by declaration (#1087, #1088): paid review, repair and conflict resolution are off, and a self-hosted runner, declared as code (#1086), answers the whole review.

Its first review, of #1090, failed with an unparseable answer. The first diagnosis (#1094) was silent truncation: at an estimated three characters per token the prompt came to about 41,000 tokens against a 32,768-token window. That diagnosis was wrong, and #1101 restates it: the server's counters show 31,765 prompt tokens read and 1,004 generated, the whole window, so the model read its entire prompt and ran out of room to answer. The error was in the estimate, which now decides only what to trim; the request itself refuses to be cut. Real truncation looks different, and #1101 reproduced it: a prompt the server counted as 36,798 tokens was answered with HTTP 200 and a prompt count of 16,386, about half the window, and refused once truncation was disabled. An upper-bound check on the server's count cannot see this cut.

The fixes refuse a verdict on a cut prompt four ways (#1094, #1101; Fig. 10). Every request asks the server to refuse rather than truncate. Every request carries a fresh random check code at the start of the system prompt and another after the diff, and the answer must echo both, so a cut at either end is caught. A diff too large for one request is never cut: since 3.1.0 it is reviewed whole in a bounded number of parts, six by default, split by file and hunk under every guard, and a pass needs every part to pass at the one head reviewed (#1252); since 3.2.0 a hunk that only adds lines is split between lines (#1278); a diff that still cannot be reviewed whole is refused before anything is sent, and the gate asks a person. And when a supporting document was cut or left out, the verdict claims only the diff-grounded half of the review and is refused as the whole. A verdict on a prompt the model did not read in full is refused.

Figure 10. The exact-head lifecycle extended to the reviewer's input. After \(r = h\), a sovereign verdict must survive four checks, each of which refuses rather than passes: every part of the diff fits (a large diff is reviewed in at most six parts, and only one that cannot be split that far goes unsent to a person), the server may not truncate, both check codes return, and the supporting documents were read whole.

Still unmeasured are the check codes' false-refusal rate on live reviews and whether any pull request has passed the gate on the sovereign verdict alone, which the repository does not record. The 3.1.0 promotion's own head got no sovereign verdict: one added file was a single hunk of 136,308 characters.

Bounded parts were not enough for a large diff. The review of #1312 ended with no verdict, coded model_timeout after two attempts. The model server's untracked log, quoted in #1316, shows a free model that wrote about 9,950 tokens on the first part, past the 8,192 the request had reserved for reasoning and answer. Nothing capped the output, and a fixed 600 s deadline that did not grow with the request cut the answer off unfinished; the retry at temperature 0 ran the same way. The same log holds the failure this one had been taken for: on 2026-09-30 a review waited about ten minutes behind another client's request and was then cut off seconds into its own work. Two causes shared one code.

Pull request #1316, merged on 2026-10-01, separates them and bounds both. The reserve is sent as the request's output cap, 16,384 tokens by default, and a model that fills it is refused as out of room, never as a timeout. The deadline grows with the request, \(t = \max(t_0,\; p/r_p + R/r_o)\) for \(p\) prompt tokens, reserve \(R\), fixed \(t_0 = 600\) s and declared rates \(r_p = 200\) and \(r_o = 20\) tokens per second. A one-token probe first waits up to 900 s for the model's one slot, so a busy model is coded model_busy and retried, while a request that started on a free slot and still ran past its deadline is coded model_timeout and is not retried, because at temperature 0 the same request would run the same way.

In every review run between #1316's merge at 18:16Z on 2026-10-01 and 03:50Z on 2026-10-02, the lane gave seven verdicts, every one on a diff reviewed in a single request, and blocked one; it gave none on six: three filled the reserve with reasoning and no answer, two were refused before anything was sent because a hunk or the part count exceeded what a review may carry, and one part missed its deadline. Two of the six had been merged before their review ended, #1317 before its review began. Under #1316 no diff needing more than one request has reached a sovereign verdict; before it one had, a documentation change passed in four parts, one verdict and not a rate. The repair did what it promised, a bounded attempt and a refusal that names its cause, and not what it was for: no large diff has been brought to a verdict in production under it, and what would let one finish is not known.

What the record shows against the model

Until 2026-10-01 nothing had measured the reviewer's recall; earlier studies measured agreement on pull requests with no known defect. vibey-gh review-canary (#1325) measures it on a fixed corpus of 41 small single-file diffs against this repository's own code, 27 planted defects in nine classes and 14 controls, each sent through the production entry point. A defect counts as caught only when the verdict blocks and a finding names the planted file, its lines or an anchor, and the defect's class; a review with no verdict is counted apart. The first measurement (#1331), on 2026-10-01, caught 18 of the 25 defects that drew a verdict (Wilson 95% interval 0.524 to 0.857), blocked none of the 14 controls (0 to 0.215), and gave no verdict on 2 of 41. It is one run on one host at temperature 0, on small diffs, and it meets a floor set low on purpose (a recall lower bound of at least 0.5). By hand, two of the seven misses are real catches the matching rule refused, so hand recall is 20 of 25. Five passed with no findings, and in two the reviewer's own summary named the defect, one as "introducing a potential SQL injection vulnerability", while pass was true; the gate reads pass, so those two would have merged. The response schema writes pass before findings, and a rule that lets the findings decide recovers neither, because those verdicts carry none.

The weekly workflow repeated the measurement on 2026-10-02 on the self-hosted runner, over the same corpus and settings: 23 of 27 (0.675 to 0.941), every case a verdict, no control blocked, its misses not adjudicated by hand. The runs differ in their commit and in where the client ran, so the second repeats the procedure, not the conditions, and we do not read the difference as an improvement. It was recorded only after the workflow that dropped it was repaired: the artifact handover had put the new ledger beside the tracked one, so the job read the unchanged file and reported no change, and the figures were recovered from the retained artifacts.

Why the lane gives no verdict on a large diff is the subject of a study in progress, preregistered before any data on 2026-10-01 (research/large-diff-review/experiments/) over 45 diffs that production cannot review in one request; we report mechanism and screening, not result. Screening finished on four diffs and saw three failure modes: at temperature 0 the reasoning loops to the output cap with no answer (on the one part measured, 86% of its word 8-grams were repeats); under sampling the loop ends but an answer can escape the response grammar or come back empty. Five arms answered on all four diffs, every arm that bounds the reasoning and then forces a verdict among them, the one remedy seen to repair a failed answer; four of four bounds an arm's answering rate from below only at 0.51, no finding has been adjudicated, and no arm's recall has been measured. Production is unchanged.

The record also speaks against the model. The forty merges before the 2026-09-30 scan went in through the ruleset bypass with no review, as What the records measure records. The reviewer's own summary named a SQL injection while pass stayed true, and the gate reads pass. The merge train closed pull requests it reported as merged, and since #1301 it counts a merge only when the forge reports one; the incident's record is in What the records measure. The first diagnosis of the #1090 failure was wrong, and #1312's two timeouts were at first taken for the earlier failure of a review that had only waited its turn. And a lineage that a sovereign-only verdict sends back to review has no termination bound in the calculus or the implementation.

\begin{plainwords}
A pull request is rewritten over time, and a grade belongs to one draft, never a later one. Once a draft was failed on a vanished draft's grade; that was fixed and tested. Only repairs count, so a draft only the local grader fails is graded again, and nothing yet stops that repeating. The grading key never merges. The local grader proves it read the whole draft by repeating two hidden words. Our first guess at one failed grade was wrong: it had read everything and run out of room. On short drafts with planted mistakes it caught 18 of 25 and failed no clean one, but twice named the mistake and still passed. Long drafts still get no grade.
\end{plainwords}

Queue semantics

Work items form a relation \(Q\) in PostgreSQL. Workers claim with

\begin{verbatim}SELECT ... FOR UPDATE SKIP LOCKED\end{verbatim}

which yields two properties without any global lock: mutual exclusion per item, at most one worker holds item \(w\) at any instant, and non-blocking progress, a worker never waits on a peer's claim, so the rate of claims scales as \(\min(|Q|, |\mathrm{workers}|)\); the rate of finished work is bounded by the engines, as What the records measure shows. The backend is PostgreSQL, never SQLite, which has no row-level locking, hence no SKIP LOCKED, and whose usual substitute, a row marked taken and returned, leaks when the worker dies after the mark (docs/architecture/decisions/0002-postgres-not-sqlite.md).

A claim skips items whose dependencies have not succeeded or whose phase this vibey does not know; the rest are ordered by the priority lane below, then earliest permitted run time, then id.

Every hold by a worker that dies is bounded by a lease: a claim sets the expiry to \(\mathrm{now} + L\), a live worker renews it, and a reaper returns an expired lease to ready while the item's attempts remain and parks it for a person once they are spent, so a crashed worker costs at most \(L\) of delay and never a lost item. A lease bounds a crash, not a hang, since a live worker renews it whether or not its engine progresses: until #1296 a BUILD session whose event stream never ended held its job indefinitely, and nothing reported it; since #1296 it stops at a wall-clock limit, 240 minutes by default with no value that switches it off. Since 3.1.0 a job whose last three failures share one normalized signature parks on a defect gate rather than retrying until its attempts run out (#1251). Because workers die and leases expire, every job is idempotent under replay.

Execution itself is at-least-once: a worker that outlives its lease may run a job that another worker has reclaimed, but the acknowledgement is fenced on the lease owner, so the stale one is refused and exactly one commits per job. It is checked under chaos, as Validation describes: concurrent workers process a job set against a real PostgreSQL, each randomly abandoning claimed jobs mid-flight while a concurrent reaper reclaims expired leases; the verified property is no double commit, no lost job and every job terminal.

Every reap is a QueueReaped ledger event; a lease reap writes it in the row's transaction. 3.0.0 extended the lease reaper by measured rule to everything a queue guards (ADR-0056, proposed), with faults on record: for an ownerless lock the push-gate reaper can signal processes other than the push, the worst of seven defects its re-review found, fixed on an unmerged branch; on 2026-10-02 a real push waited 30 minutes behind a lock a test held; the bus port acknowledges on take, so a dying consumer loses its message; one bad lease row halted every reap while the broker policy was reported verified when not in force, both repaired by #1203, and whether it covers two further findings cannot be settled from tracked sources.

The same primitive serves the bridge from a forge's triaged issues to delivery (Fig. 11): a reconcile pass mirrors the open ones into rows, a claim takes the first ready row under a 900 s lease, and a dispatch is marked on the issue by a comment naming the project, so a bridge that lost its database would not dispatch an issue twice.

Figure 11. The triage ticket. Rows mirror the forge's triaged issues and are claimed under a lease with FOR UPDATE SKIP LOCKED; an expired lease returns the row to ready. The claim order is derived from labels and update time, so no one reorders the queue by hand. Blocked is set by the bridge for an untrusted, abandoned or retired issue, after three failed dispatches, or by a person.

The derived priority lane

A bumped item runs next rather than waiting its turn, in the PostgreSQL job queue and the storm's lane queue alike, under one contract (ADR-0054). Next means next after whatever is running: a bump never preempts a claimed or leased item or touches its lease (sub-doctrine 8.c), and never admits: phases, human gates, admission, capacity deferral, budget brake and handoff gate still decide whether an item may run; it decides only which runnable item runs first, never making one runnable before its dependencies finish. The lane is derived, never remembered.

\begin{invariant}[Derived priority lane]
Let $B$ be the unfinished items bumped, or enqueued prioritised, by name and not since
un-bumped. The lane is exactly $B$ together with every unfinished transitive dependency
of a member of $B$, ordered first-in-first-out by when each item first entered the lane.
Un-bumping $x$ removes $x$ from $B$, and is refused, naming them, while another member
of $B$ depends on $x$.
\end{invariant}

A named item that ends cancelled or failed leaves \(B\) by the derivation. The one exception is a job whose phase or state a newer vibey wrote: it stays in the lane unwritten with what it needs, named in the request's record, and un-bumping what it needs is refused (ADR-0054, item 6). The derived form replaced a first rule, un-bump undoes what that bump moved, after an independent review of #1091 found an orphan: with \(a\) and \(b\) both needing \(d\), bumping and un-bumping both left \(d\) in the lane with nothing needing it. Every admitted request re-derives the lane and sweeps what is no longer derived (#1103); a refused one changes nothing but its own record.

Only the operator, the operating-system account owning the queue's reviewed declaration, checked by process user id, or an automation it lists running as that account, may bump or un-bump; nothing reads the forge to decide priority, so no label, issue or comment moves work forward (sub-doctrine 12.j). The grant separates operating-system accounts, not the operator's own processes, which reach the queue below it whenever they can reach the database; since #1093 an engine's environment no longer carries the means, but such a process can still reach a local server trusting its socket (see What an engine may see). Every request is recorded, authorisation preceding lookup so a stranger learns nothing about any item: in vibey a ledger event in the row change's transaction, in the storm an append-only log, loss-evident but not tamper-evident, as its code says.

A Hypothesis state machine runs random, overlapping bumps and un-bumps with jobs finishing, failing or cancelled part-way, and asserts after every step that the stored lane equals the derivation, except what this vibey cannot write and what it still needs, and that un-bumping every named job clears the rest; breaking the derivation on purpose makes it fail (#1095, #1103). Five workers claiming at once under SKIP LOCKED take exactly the first five in order. Reviewers' untracked probes found no double claim with five workers claiming through 450 random bumps and un-bumps on a real database, and no false order unknown in over 9,000 concurrent reads of the storm's log.

\begin{plainwords}
Jobs wait in a line in a database. A helper takes the front job with a timer and renews it while working. If the helper crashes, the timer runs out and the job goes back into the line, so it is never lost; a job that keeps crashing its helpers, or fails the same way three times running, goes to a person instead. Helpers never wait for each other, and a late helper cannot finish a job another helper already took. The owner can say ``do this one next'': that job goes to the front with what it needs, never out of a helper's hands or past a checkpoint, and every such request is written down, even the refused ones.
\end{plainwords}

The six-phase machine

A human gate is a parked job plus a recorded row, never a thread waiting on input. The machine is

\[\Sigma = \langle D, B, R, D_d, D_e, D_r \rangle\]

design, build, review, deploy-design, deploy-execute and deploy-review. The four in the human-gated subset \(G = \{D, R, D_d, D_r\}\) talk to a person; build and deploy-execute run unattended. The deployment triple is entered only on an explicit opt-in recorded in the ledger; declining it records a successful local completion. An optional visual-design interstitial \(V\) is gated likewise. Fig. 12 draws the path, omitting intake, abandonment, the return from build to design on an item blocked by ambiguity, and the loop-backs out of deploy review.

Figure 12. The six-phase delivery machine. Gold boxes are human gates, where the item is parked until a person answers; blue boxes run unattended. Review sends open findings back to Build, or to Design when a finding needs clarification, so nothing is lost in a transcript. Deployment is a separate, opt-in lane; declining it is still a successful local completion.
\begin{invariant}[Gate soundness]
For every $\sigma \in G$ the exit guard is a conjunction of a verdict recorded as a
ledger row, given by a person unless the project has declared otherwise (below), and, where the phase accumulates open items, the emptiness
of a ledger-derived open set. $D \to B$ requires at least one acceptance criterion,
every criterion mapped, no blocking question open, every DESIGN job of the cycle
settled, the visual interstitial explicitly declined, and an accepting verdict;
$R \to \mathrm{Done}$ requires
$\mathrm{open}_{\mathrm{findings}}(R) = \varnothing$ and an accepting verdict; $D_d
\to D_e$ requires the deployment specification accepted and consent recorded; $D_r
\to \mathrm{Done}$ requires the demonstration accepted. Emptiness is never
sufficient: no gate exits on the absence of objections alone, and none on the absence
of an answer unless the project has declared that gate's kind under
\texttt{[human\_gates] timeout\_defaults} (\#1299), where the declaration is the consent.
\end{invariant}

A review finding therefore cannot vanish into a transcript: it is a ledger row holding \(\mathrm{open}(R) \neq \varnothing\), and the machine cannot leave \(R\) for completion until a person closes it. Loop-back is a ledger transition: an unambiguous finding routes to \(B\); one that needs clarification, or a project configured for strict loop-back, routes to \(D\).

Silence never supplies a verdict. A gate resolves to its stored default only for a kind the project has declared, after a declared wait, and only the deployment choice and the deployment gates are declarable; the worker answers it as gate-timeout by the path every answer takes. DESIGN's gates and REVIEW's approval never time out; the table is empty by default (#1299).

A handler that needs a human returns a park value; the worker records a gate row, marks the item awaiting a person, releases its lease and claims the next. The answer is itself a ledger row that re-readies the item; human latency never holds a queue slot. An answer is a compare-and-set: a replay is a no-op, a second answer refused. Since 3.1.0 whether a person was told is itself evidence: every gate notice ends in a GateNotified or GateNoticeUndeliverable event with its reason, never an assumption (#1251).

The verdict row names who gave it; Fig. 13 maps that authority over the delivery path of Introduction, which the bridge feeds from the forge. A person labels and prioritises an issue, gives the review verdict, approves the merge unless the operator's declared grant lets the delegated approver do so, and alone opts into deployment, which is never inferred; the bridge admits, claims, orders and publishes; the engine writes code only inside BUILD, in its own worktree; the forge's required checks gate the merge. On an explicit opt-in only, the bridge answers the design interview with its declared defaults under its own name, automation:triaged-delivery, and accepts the design once the design chain has settled (#1258). The rule is a repair: on the first delivered issue the bridge answered three of the four interview gates within a second under the operator's own name, and the ledger could not tell them from a person's: a bridge defect, not a property of the model, and the concrete instance of the limit in The ledger invariant. The approver's grant exists in declaration only: no workflow calls it, and its account had reviewed no pull request by 2026-10-01.

Figure 13. The authority map of the delivery path. Gold marks a decision a person records, blue an automated step. The two design steps are a person's by default; red marks that the bridge performs them, with declared defaults recorded under its own name, only when the operator opts in. The bridge admits an issue only when everyone who wrote, edited or labelled it is trusted. Review, deployment and abandoning a project remain a person's; merge approval is a person's or, under the operator's grant, the delegated approver's (12.f), never the bridge's; and deployment is never inferred.

Two edges bound the path. Before an issue enters it, a trust check: since 3.1.0 an issue a stranger wrote, edited or labelled is held for a person, never dispatched; an admitted one reaches DESIGN framed by PromptShield (#1248). Every phase short of done, intake included since 3.2.0, has an edge to abandoned, the operator's exit: one transaction withdraws every open gate, recorded as GateWithdrawn and never deleted, cancels every unsettled job, and records one PhaseTransitioned with the reason; an abandoned project also releases its checkout, and the claim never hands out an abandoned project's jobs (#1263, #1276, #1279).

\begin{plainwords}
Every job takes six steps: plan it, build it, check it, and, only if the person wants, plan the launch, launch it and check it. Four of the six are gates where a person says yes. Saying nothing is not saying yes, unless the owner wrote down in advance that one kind of launch checkpoint may take its usual answer after a set wait. A busy person's job waits in the notebook while the helpers do other jobs. A stranger's request waits for a person before it is taken up. The owner can stop a project at any step before the end: its open questions are withdrawn, its waiting jobs cancelled, and the stop written down with the reason.
\end{plainwords}

The engine family

ADR-0078 (4.0.0, 2026-10-03) retired cursorloop and agyloop; a configuration that still names either is refused, and Fig. 14 is redrawn without them. Since then three runner packages implement the family and the orchestrator declares five engine identities (src/vibey/domain/engine.py): claudeloop over Claude Code and codexloop over OpenAI Codex, the paid tier; gptossloop, the sovereign default on GPT-OSS 20B, and opt-in qwenloop on a Qwen model, one runner package over Ollama; and claudeloop-local, the claudeloop binary on a local backend profile.

Figure 14. The two-package publication surface and the engine family. The dark box names the engine distribution; the apps publish separately as krypton-app. Beneath it sit the orchestrator, three runner packages (claudeloop and codexloop on their shared library, and the local runner package), and three tools. Every tenant requires Python 3.12 or newer. The teal package exposes gptossloop, the sovereign default on GPT-OSS 20B, and opt-in qwenloop; claudeloop-local, the claudeloop binary on a local backend profile, is the fifth selectable identity. cursorloop and agyloop, retired by ADR-0078 in 4.0.0, are no longer drawn.

The identities form exactly two loops, sovereignloop (local) and paidloop (paid), and every runner honours one narrow contract: a bounded run, a done marker, an event vocabulary, a capacity mapping, and a shared wind-down exit code (75) meaning the engine ran out of window capacity mid-item and stopped cleanly after writing its state.

Bounded runs that never block

Unattended operation needs three things: no turn waits on a person, every metered resource is bounded by the operator rather than the model, and a run's outcome is auditable from durable state rather than a vendor transcript. A run is admitted only under an explicit bound vector (turns, spend, wall clock, per-turn and output-silence watchdogs, and a ceiling \(W_{\max}\) on any single capacity wait; the exact members vary by runner) and ends at the first bound reached, that bound recorded. Budgets are checked only at turn boundaries, so a run can pass a dollar cap by at most the turn that crossed it. Above the runners, the orchestrator bounds every BUILD session on its own clock, 240 minutes by default, and a stop ends the session's whole process group (#1296, #1297); before those changes a session whose event stream never ended held its job with nothing reporting it (Queue semantics).

\begin{invariant}[No interactive waits]
No execution path may block on standard input. Where the vendor's tool can prompt,
managed hooks pre-answer it and the session preamble declares unattended operation;
everywhere, the watchdogs convert any residual hang into a loud, bounded failure.
\end{invariant}

Each turn, verdict and spend entry is one JSON line in an append-only trail under the run directory: write-ahead at session scale.

The delivery bridge treats an overrunning worker the same way (Fig. 15): past a 900-second default deadline it terminates the worker's process tree deepest descendants first, waits two seconds and kills what survives; only then is the timeout recorded, and the lease is left to expire rather than released, so the queue's own reaper returns the job by a crashed worker's fenced path and a late acknowledgement is refused.

Figure 15. Worker timeout handling in the delivery bridge. The whole process tree is stopped before the timeout is recorded, and the lease is left to expire and reaped by the queue's own reaper on the bridge's next pass, so a timed-out job returns to the queue by the same fenced path as a crashed worker's.

What an engine may see

A bound on spend is not a bound on reach: until 3.0.0 every engine process started from a copy of the worker's whole environment with four Python variables removed, so the shell commands a model chose held the queue and ledger connection string, every VIBEY_* secret, libpq's PG* variables and the worker's GitHub and cloud credentials, and could rewrite queue rows and, before the guard of The ledger invariant, the ledger, unrecorded (#1093).

Since 3.0.0 every child's environment is assembled from an allow-list and never copied (Fig. 16): the system basics every process needs, the engine's own declared variables and credential, and what the project declares in reviewed configuration. Beneath them sits a forbidden set, VIBEY_* and PG* for every child, GIT_* for gates, and for engines any name containing DSN, DATABASE_URL, PASSWORD or PASSWD; a declaration naming one fails when the worker is built. A forge or cloud token is on no default list and reaches only an engine the project names.

Figure 16. The engine environment boundary. A session's environment is assembled from three allow-listed sources, never copied from the worker, and a declaration that names a forbidden variable fails when the worker is built.

The independent review of #1093 found planted programs running with the connection string in hand, rated critical, and a notifier that could run injected shell commands; both are reproduced in tests that failed before the fix. No verdict on the merged result is recorded in a tracked source.

The control keeps secrets out of a child's environment; it is not a boundary between the worker and the processes it starts, which share its operating-system user (ADR-0055 calls the list hygiene, not a boundary). A local PostgreSQL with trust or peer authentication needs no connection string, so there the allow-list does not keep an engine from the queue and vibey doctor fails. A same-user process can read the worker's environment and files; the container boundary that would separate them is implemented but not wired in, and a separate low-privilege user is in no release through 3.2.0.

The sovereign driver and measured fit

The editor driver, a VS Code extension (ADR-0059), adds no agent loop of its own: a task is a run of a family runner, on sovereignloop by default and on paidloop only after paid use is declared.

The driver makes the local fit explicit (Fig. 17). A probe runs a grid of context and output sizes against the local server and records the endpoint, model, source revision, prompt shape and the fastest fit that answered validly. The runtime loads that record only if endpoint and model match, the fit is marked valid, and the revision matches when the running revision is named (VIBEY_REVISION, which nothing in vibey sets, so the revision is recorded but not checked by default); a stale, malformed or mismatched record falls back to the configured ceilings, and a prompt larger than the measured shape runs under the defaults of 8,192 context and 2,048 output tokens.

Figure 17. The measured-capacity lifecycle. A probed fit is bound to its endpoint, model and prompt shape, and to its revision when the running revision is named; any mismatch at load falls back to the configured ceilings, and a prompt longer than the one measured to the conservative defaults, rather than to a guess.

Budgets and selection

The transplant thesis held: everything vendor-specific fits in the lexicons that read a vendor's failure text and the transport that speaks to it. Four retargets of claudeloop's core, two since retired, kept the invariants while the capacity vocabularies differed, from three members in qwenloop to six in codexloop, so the orchestrator can treat the pool as substitutable executors and choose by policy rather than by state.

Budget caps are per cycle, in dollars and turns, summed from the cost and turns the engines report on each completed turn and read afresh at every BUILD session; engines carry cost rates, not caps. An exhausted budget parks the item on a budget_exhausted gate before a session starts, never after, and a per-item turn cap exists only as a configuration key nothing reads.

Local engines are preferred (sub-doctrine 8.a); paid engines are the fallback when none is eligible, and the selector does not yet read the paid declaration sub-doctrine 8.b asks for (Fig. 18). Within a tier the eligible engines are ranked by smooth weighted round robin under \(w_i = \max(1, \mathrm{round}(b_i h_i f_i c_i a_i))\), its cost factor fixed at 1 in the current implementation; the sequence is deterministic and spreads load in proportion to weight. Rotation fires only at a boundary (a new item, a capacity rejection, which opens that engine's circuit, a wind-down, an effort escalation, a crash or a phase transition), never inside a turn, so every handoff has a well-defined ledger range \(\rho\). A wind-down sends a handoff brief, checked as The no-loss handoff gate describes, to a successor that excludes the outgoing engine; a capacity rejection defers the job instead, and no brief is produced on that path yet (ADR-0007).

Release 4.0.0 adds a hybrid mode (ADR-0079): local engines fill their declared slots first; a paid engine takes a BUILD job only once every eligible local slot is occupied, the job has waited a configured overflow delay and the project's paid cap for the UTC day is not reached. singleton is the selection above; auto, the default, chooses between them from a ledger measurement of local-slot contention and falls back to singleton when that measurement is missing, stale, invalid or failed. Every overflow, slot wait and measurement is a ledger event, and the cap is counted from the ledger under the project row's lock, so it holds across restarts and workers.

Figure 18. Choosing an engine. Local engines (teal) are preferred; paid engines (blue) are the fallback, and the selector does not yet read the paid declaration sub-doctrine 8.b asks for. Under the hybrid dispatch mode of ADR-0079 (4.0.0) a paid engine may also take a BUILD job once every declared local slot is occupied, the job has waited its overflow delay and the day's paid cap is not reached; cursorloop and agyloop, retired by ADR-0078, are no longer drawn. The selector ranks eligible engines by smooth weighted round robin. A graceful wind-down (exit 75, out of window capacity mid-item) sends a handoff brief through the no-loss gate to the next engine, excluding the one that wound down; a capacity rejection instead defers the job and opens that engine's circuit, and no brief is produced on that path yet (ADR-0007). Rotation happens only at a boundary, so each handoff has a well-defined ledger range \(\rho\).

Dispatch experiments

On 2026-09-26 we timed three dispatch paths on one laptop, Ollama with gpt-oss:20b and RabbitMQ 4.3.6 on loopback; the table gives the rates. The model-turn experiment used two samples at hybrid concurrency \(2\) and the orchestration-bus experiment twelve messages; hybrid won model turns and the multiplexer won the bus. The model-turn result was persisted as per-machine benchmark evidence and the bus result as that machine's auto winner; the two bus runs agree on the winner while their rates vary, so the implementation recomputes rather than fixing one measurement. They are machine-local observations of dispatch paths only, establishing no model quality, paid-provider quality or cross-machine performance. Paid-provider experiments were not run and no live paid-provider result is claimed: the provider benchmark executor and the durable global paid budget guard are implemented and unit-tested, but a live result needs an enabled adapter, a representative run, reported usage and charging within the authorized cap. The raw results were kept on the machine, not committed, so the table cannot be recomputed from the repository.

\begin{table}[t]
\centering\small
\begin{tabular}{@{}p{1.45in}rrr@{}}
\textbf{Surface} & \textbf{Single} & \textbf{Hybrid} & \textbf{Mux.}\\
Model turns (turns/s) & 0.1162 & 0.2597 & 0.1297\\
Bus, first run (msg/s) & 41.2398 & 271.8715 & 422.8348\\
Bus, repeat run (msg/s) & 33.6749 & 251.2280 & 412.2460\\
\end{tabular}
\caption{Bounded local dispatch experiments. Hybrid won model turns; the multiplexer won the orchestration bus. The column names are the bus's; for model turns the three policies are the runner's direct, hybrid and RabbitMQ dispatch.}
\label{tab:dispatch-experiments}
\end{table}
\begin{plainwords}
A runner lets one robot helper work by itself. Every run has limits on turns, money and time; the runners never wait for a person to type, and a helper that runs too long is stopped, all of it, before its timeout is written down. Each helper is handed only the keys its job needs, never the whole key ring, though a helper running as the same computer user could still go looking, and we say so. Local helpers are tried first and a fair rotation shares the work. We also timed three ways of handing out work on one laptop: two local jobs side by side beat one after another, but those are one afternoon's numbers from one machine.
\end{plainwords}

Deterministic retrieval and fail-closed bootstrap

Two further components apply the ledger's rule, append before acting and fail closed, at other scales.

A skill library of 745 documents across 138 plugins at the source cutoff cannot be loaded whole into a context window, and a fragment of safety-critical guidance is worse than none.

\begin{invariant}[Deterministic, whole, fail-closed retrieval]
The index is a pure function of the corpus: identical corpus bytes yield identical
manifests, chunk identifiers and scores. The retrieval unit is a heading-bounded
section, returned whole with its path, line range and content hash. For a request
with mandatory content $M$ and budget $B$, if $\mathrm{tokens}(M) > B$ assembly returns
\texttt{budget\_insufficient} and never truncates a mandatory section to fit.
\end{invariant}

The engine is lexical, over SQLite FTS5; dense retrieval would reintroduce the nondeterminism the reviewability invariant forbids. Over-budget mandatory content yields no packet; omitted optional content is listed in the manifest, and a low-confidence flag returns the caller to native full-skill activation. No retrieval metric is reported here, and none is the objective: the criterion is cost per accepted work item, unmeasured here, since a packet that halves token spend but raises rework is a regression.

The bootstrap layer starts a cloud workload in one call under one rule: a missing required precondition halts the start, named, and an optional capability degrades as a recorded decision, never a silent absence. Above it a transactional outbox commits intent beside the state change, so every committed intent is delivered at least once and marked delivered exactly once, and audit records form a hash chain, \(c_0 = H(r_0)\) and \(c_i = H(c_{i-1} \| r_i)\), so any edit, insertion or truncation breaks every later link and verification needs no trust in the writer. Ledger, outbox and chain are one principle at three scales (Fig. 4): intent is durable before its effect, state is derived from it, and a crashed worker replays from it, duplicates dropped by identity. These guarantees are stated, not measured here.

A proposed contract (ADR-0075, Fig. 19) extends the rule to everything loaded into a window: a converter cuts a source into numbered slices carrying identity, purpose, provenance and explicit requires and links relations; a retriever loads the matching slice with its required closure only when that closure fits the budget, otherwise splitting or parking it. Neither the measured size nor the retriever is implemented, the slice boundaries are mechanical and still need review, and a split is no claim that each slice reads well alone.

Figure 19. The context-microslice contract (proposed ADR-0075). Source material is converted into identified, bounded slices with provenance and explicit links; retrieval loads a slice with its required closure only when the closure fits the budget, and otherwise splits or parks it rather than dropping the tail.
\begin{plainwords}
Two smaller tools follow the same rule of writing things down before acting. One looks
up instructions in a large library and always returns whole pages, never half a page;
when the pages it must include do not fit, it says so instead of cutting them. The
other starts cloud programs and refuses to start at all if something it needs is
missing, rather than limping along quietly, and it notes what it is about to do before
doing it, so a crash can be replayed from the note. A planned extension would cut every
document into numbered, linked pieces so the same rule applies to everything the
system reads. It is not built yet.
\end{plainwords}

What the records measure

Every measurement we recompute here is read from one project's tracked records at a named cutoff: the sovereignty stress record of 2026-08-30, a controlled escalation of the local review lane; the local Qwen pilot record of 2026-09-20; and the QwenStorm 3.0.0 evidence ledger of 2026-09-22 and 2026-09-23. scripts/paper_evidence.py recomputes the stress and Qwen figures, scripts/paper_figures.py redraws every computed figure from the tracked files, and the storm's own storm-evidence.py regenerates its evidence table between markers that no sentence of ours lies inside. Two sources we cite are not tracked, and we name them where we use them: the storm throughput audit of 2026-09-23 and the forge's own records of pull requests and their merge times.

A single-slot saturation curve

A harness fired \(N\) simultaneous generations at qwen2.5-coder:14b, served by ollama on one machine with 24 GB of memory and 10 cores, for \(N\) from 1 to 128, with a 900 s deadline per generation. Each generation was a real unit of work, an issue triaged or a pull-request diff reviewed, drawn from a pool of seven artifacts of 2 to 22 KB. Throughput is successful generations per minute of rung wall clock; every rung's throughput and success fraction is in Fig. 20.

Figure 20. The sovereignty stress record in four views. (a) Successful throughput rises into a broad stable band, 0.99–2.00 generations per minute, across offered concurrency \(N=2\) to \(32\), then peaks at 3.52 per minute at \(N=96\) before collapsing. (b) The success fraction stays at or above 87.5% through \(N=32\) and falls beyond it. (c) Median latency and the slowest generation of each rung approach the 900 s deadline as the substrate saturates. (d) Free memory oscillated in a narrow band throughout; paging space, not free memory, marked the collapse. Every point reproduces the record's rung table.

The serial rung ran at 0.36 per minute: one job cannot saturate the substrate. Across the nine rungs from \(N = 2\) to \(N = 32\) (107 generations, 102 succeeded, every rung at or above 87.5%), throughput stayed between 0.99 and 2.00 per minute while offered concurrency rose sixteen-fold; the least-squares slope of log throughput on \(\log N\) over those rungs is 0.20, where output that scaled with demand would have slope 1. The band is a band, not a constant: its spread is a quarter of its mean, and it drifts upward with \(N\) because the server batches concurrent sequences into shared forward passes. A band fitted on the rungs with \(N \leq 16\) is \([0.99, 1.72]\); of the two stable rungs held out, \(N = 24\) (1.40) fell inside and \(N = 32\) (2.00) fell 16% above, in the direction batching predicts, so we claim the floor and the scale of the ceiling, not a tight window. Above the band the success fraction gives way before the throughput does: 1.60 per minute at \(N = 48\) with 50.0% success; 2.66 at \(N = 64\) with 62.5%, where the server crashed and restarted itself; a peak of 3.52 at \(N = 96\) with 55.2%; and at \(N = 128\) a fall to 1.53 at 18.0%, with paging space at 99.1% and the server restarting again. Free memory stayed in a narrow band throughout; paging space, not free memory, marked the collapse. In all, 243 of 444 generations succeeded over 2.18 hours (Fig. 21), and every failure was a clean timeout, none malformed.

Figure 21. Cumulative generations across the fourteen rungs of the stress record: 444 attempted, 243 succeeded. The gap opens only after the stable region; every failure in the run was a clean timeout, never a malformed response.

This is what one local model slot does when more clients are offered to it, with hardware, model, serving stack, deadline and admission rule held fixed on one machine. The completion-time prediction of Time to completion and what modulates it takes its zero-shortfall rate from this band and holds inside the band, for this workload, only. The curve is not evidence about another host, model or task class, and not evidence that governance rather than the model is the scarce input in general. The host's own memory budget, measured in Host benchmarks and context headroom, confounds every timing here. One correction: the vibey-gh tenant paper once reported this experiment as 61 generations at a success rate of 95.3% (9 rungs, N=2..32) with throughput held to \(1.4 \pm 0.25\) per minute; neither survives comparison with the record, and that paper now carries a dated correction.

The local Qwen pilot

A local storm on 2026-09-20 ran the then-latest qwenloop runner against the open backlog with qwen3:14b through Ollama. It is not a replication of the stress record: the work items were heterogeneous, the offered concurrency was not controlled, and several runs were still alive or had produced no events at the evidence cutoff, 2026-09-21T00:19:23-04:00.

Thirteen run directories were observed. Four completed with both a verdict and the completion marker; two emitted verdicts without the marker; two ended without a verdict, one of them after exhausting its 40-turn limit with a failed terminal event; one produced a tool error after one turn; four had no events; and one storm process was still alive. Across the thirteen the logs hold 105 model turns, 85 tool calls, 550,576 input tokens, 83,609 output tokens and 42 file writes totalling 32,073 bytes (Fig. 22). The accepted completion rate at the cutoff was therefore 4/13, or 30.8%, where a verdict alone would have suggested 6/13, or 46.2%.

Figure 22. The thirteen run directories of the cutoff-bounded local Qwen storm, in order of start. (a) Model turns and tool calls; (b) input and output tokens, 550,576 and 83,609 in all. The strip beneath each panel colours every run by its disposition at the cutoff: only 4 of 13 both emitted a verdict and wrote the completion marker, and the largest run, forty turns and 238,608 input tokens, ended without a verdict at all.

This is a runner-reliability observation, not a model-quality or throughput estimate, and it does not enlarge the throughput claim above. It is an empirical check of the completion contract: a verdict without the marker did not count, and unfinished event trails stayed unfinished rather than being promoted to completed work (Fig. 23). The requested context setting was 32,768 tokens while the server reported 40,960 at the cutoff, so no claim about a controlled context-window effect is made.

Figure 23. The thirteen Qwen storm run directories at the evidence cutoff, each segment as wide as its share of runs. Only the four with both a verdict and a completion marker count as delivered; a verdict alone does not. One process was still running and belongs to none of the thirteen. Counting every visible artifact as finished would overstate delivery.

The storm evidence ledger and its audit

The QwenStorm 3.0.0 run of 2026-09-22 and 2026-09-23 drove the open backlog through one local model, gpt-oss:20b on Ollama, one lane at a time, each lane one issue, one source file with its interface and one test file, reviewed against its specification and its diff before it may become a pull request, with at most three attempts. The record is an append-only evidence ledger that a consumer fills from the storm's progress log and lane results. Its 30 lanes logged 70 attempts and 2,606 model turns. Seventeen lanes ended in a completion claim, and a claim is not delivery: of the 30, four were integrated (three claimants and one that had failed all three attempts), twelve were abandoned, and fourteen, all of them claimants, were unsettled at the cutoff; the reviewer's totals of 12 integrated and 14 abandoned reach beyond the ledger's 30.

Derived from docs/plans/qwenstorm-3.0.0/evidence/ledger.jsonl, an append-only record consumed under sub-doctrine 10.g. Regenerated automatically; do not edit inside these markers. This block states figures only — every claim about them is written by a person outside it.

quantity value
ledger records 277
span consumed from 2026-09-23T04:40:49Z
span consumed to 2026-09-24T00:24:17Z
lanes observed 30
lanes claiming completion 17
lane starts / ends logged 49 / 42
lanes integrated / abandoned 12 / 14
recorded attempts 70
total turns across attempts 2606

Gaps in this span: none; every byte and record between the watermarks was read.

The consumer reads by position, never by time (Fig. 24): its watermark is a byte offset into each source plus an identity set over the records, since records that share the cutoff second, arrive late or out of order fall through a timestamp comparison silently; it appends and flushes before advancing, so a crash re-reads rather than skips, duplicates are dropped by identity, and a source shorter than its offset is reported as a gap, never reset. The table's no-gap statement was proved on the storm's host and cannot be re-proved from a checkout: the repository tracks the ledger (277 records, no identity repeated) but only an early copy of the progress log, 3,821 bytes against a recorded offset of 15,087, so the check reports that copy as short and we leave the block as the host generated it. Recounting the ledger reproduces every row, after one correction to the lane-start counter, whose pattern required a space after the issue number and so skipped the storm's first start line (49 starts, not 48).

Figure 24. The unbroken read. A job that consumes a growing record remembers its place as a position in the data, not as a time on a clock, so late and out-of-order records are never skipped. It writes what it read into the ledger before moving its bookmark, so a crash means reading again, never losing anything.

Fig. 25 draws every lane with its attempts. One model instance served every lane in turn, so attempts never overlapped: the bars of Fig. 26 never overlap, and the blank stretches are the reviewer's and the operator's time, not the machine's.

Figure 25. Every lane of the QwenStorm 3.0.0 evidence ledger, one row per lane in issue order. Each bar is one attempt, its length the turns the local model spent, green where the attempt ended in a completion claim and red where it failed; a lane gets at most three. Of 30 lanes, 17 claimed completion, and a claim is not delivery: over the same span the reviewer integrated 12 lanes and abandoned 14 in all, of which 4 and 12 are among these 30, and 14 of these were settled neither way. Read from the ledger between 2026-09-23T04:40:49Z and 2026-09-24T00:24:17Z with no gaps.
Figure 26. Lane starts and ends as the storm's progress log recorded them, over 23.1 hours from 2026-09-22 12:03 UTC. One local model served every lane in turn, one instance per model; the bars therefore never overlap in time, and the blank stretches are the reviewer's and the operator's, not the machine's.

An audit on 2026-09-23 asked why the storm could not run more lanes and which safety controls had to hold first. Its working record is not tracked: a page kept outside the repository, fed by lane run logs that were never tracked and that a reboot of the host on 2026-09-24 erased, by the progress log, the model server's log and the forge. Every figure is the audit's unless we say we recomputed it. Across the 82 run directories then on disk, model calls took 9.68 of the 10.01 hours those runs spanned, 96.7%, and the progress log's 41 closed lane intervals never overlap; we recomputed both from the local files on 2026-09-24, before the reboot, and they agree. Three serialisers stack: the queue script waited for any running lane on the host, the project's rule gave a model on the operator's own hardware one run at a time, and the server had one slot. Amdahl's law then bounds what more lanes sharing that slot could buy at \(1/0.967 \approx 1.03\). These 82 runs are not the ledger's population, and we reconcile neither to the other.

No lane reached the integration branch without a human step. Of 40 lanes started, 13 had work on the branch at the audit, three through the automated path; but none of the last 60 merged pull requests had a successful required review gate, the merge train logged merged 0 on every pass, so every merge was made by hand, and ten lanes needed a hand-built pull request. More lanes multiply this conversion rate rather than escaping it, and the hand repair is capacity nothing records. Seven safety controls existed in configuration or documentation and were read by nothing, or bound only in a mode not in use, among them an unattended merge fallback with --admin; none was exploited, because every one of the 594 queued issues was the operator's. All seven were enforced by merged code on 2026-09-24, beside the yield fixes the audit ranked (a retry on an empty reply, a per-lane time limit, real search and file tools); the storm had not run since, so their effect on yield is unmeasured. One control stayed unsettled: the rulesets carried a bypass actor nobody declared, and 78 of the last 200 merges went in while the forge reported a review still required; who and how needs the organisation's audit log, and The autonomy scan of 2026-09-30 returns to it.

Most of the audit's first claims were wrong. Twenty-five agents audited six dimensions; adversarial verifiers then checked the leading claims before anything was written up and refuted 16 of 18. Some corrections were of degree and some of kind: the claimed serialisation point was the wrong line, the single slot is serialised by code, canon and configuration rather than by hardware, and the account of #1090 as a silently truncated prompt was wrong, as Exact-head evaluation and the release calculus records. This is a finding about method: a first pass by capable agents over complete logs was wrong more often than right on its headline numbers, and verification, not analysis, made the audit usable. It applies to this paper: an earlier revision claimed that a 64k context window generated 16% faster; the same verifiers found decode speed varying from 26 to 34 tokens per second within one allocation, so the difference is inside the noise and no longer claimed.

\begin{plainwords}
We measured three things, all from one project's saved records. First, we gave one
local model on one computer more and more jobs at once: from two to thirty-two jobs at
a time it finished about one to two a minute however many we offered, and past that it
began failing and finally crashed. That says what one model on one machine can do, and
nothing more. Second, a trial of the local runner finished only four of thirteen jobs
properly. Third, an overnight run of thirty tasks claimed seventeen done, but only four
were integrated, and a re-check of the audit of that run found most of its first
conclusions were wrong.
\end{plainwords}

Host benchmarks and context headroom

On 2026-09-22 the same ten-turn session was replayed against five server configurations on the one 24 GB Apple M5 host that every timing in this section comes from (Fig. 27). For every llama.cpp configuration of Qwen2.5-Coder-14B, generation fell as the context grew, from about 11 tokens per second on the first turn to between 6 and 9 on the tenth, and the four finished in 212 to 220 s; gpt-oss:20b on Ollama finished in 86 s, and the same model on llama.cpp at a 64k context did not load. The record does not separate the model from the serving stack, so the difference is reported, not explained.

Figure 27. The host benchmark of 2026-09-22: the same ten-turn session replayed against five server configurations on one 24 GB machine. (a) Generation speed falls as the context fills for every llama.cpp configuration of Qwen2.5-Coder-14B, whatever the slot count or cache type. (b) The gpt-oss:20b model on Ollama completed the session in a fraction of the wall time; the same model served by llama.cpp at a 64k context failed to load at all. Every point is one row of the tracked results file.

On Apple Silicon a model's weights and key-value cache are wired memory, reserved in proportion to the context window: at 131,072 tokens the server wired 18.55 GB of the 24 GB. The storm's run ledgers record what 838 real turns used, a median of 20,070 tokens, a 99th percentile of 42,979 and a maximum of 49,118 (Fig. 28). A 32k window would have truncated 71 turns; the 64k window chosen covers every recorded turn with a third again as headroom and wires 1.3 GB less than the 128k baseline, which no turn reached.

Figure 28. Fitting the model to the iron. The percentiles mark how much context 838 real storm turns used; the dashed lines are the three context windows considered. A 32k window would have truncated 71 turns, and the 128k baseline, never reached by any turn, wired 18.55 GB of a 24 GB machine. The 64k window chosen covers every recorded turn with a third again as headroom. Beneath each window, the sweep's configurations measured at it report what each setting cost and delivered.

The minimum requirements follow from the same host. Memory was the binding constraint, set by the context rather than the model file: with vibey, PostgreSQL and the operating system the host needs 24 GB at minimum and 32 GB recommended, and a GPU is not optional for BUILD, since on the CPU alone the worst BUILD turn does not fit the 900 s timeout. These are seed measurements from 2026-09-29 and 2026-09-30; the weekly workflow that would refresh them had not run at our cutoff, so every figure is stale since its seed. The full tables are in the appendix, and the record is docs/architecture/evidence/minimum-specs.json.

The host's health record held two points at our cutoff, too few for a trend; memory sat exactly at the 24 GB minimum, and swap in use was 0.60 and then 0.68 of memory, past its 0.5 threshold in two of the three records that would confirm it. A measurement on 2026-10-02 with the model loaded found process footprints of about 49 GiB on the 24 GiB machine, 18.5 GiB of it the model server, and the SSD taking 152.5 GB of writes an hour, 85% of them swap-outs: by elimination rather than by trace, its 36.55 TB written in 337 power-on hours is mostly the price of overcommitted memory. It is a confound for every timing in What the records measure: the rate at which a review generates depends on what else the host holds.

Field data from the repository

The git history is field data: nothing in it was held fixed. At the pinned revision, d4c4e1f8, 1,331 commits are reachable across nine root histories; since 2026-08-09, when the family's own development begins, 1,319 landed on 34 active days, between 1 and 191 a day, and the longest pause, nine days, has no recorded cause (Fig. 29). Every count is lower than at the previous pin, c78049b6, although the work grew: the 3.0.0 release reached develop as one squash commit (#1244) in place of the 213 commits of its cycle, so the week of 2026-09-21 reads as the quietest when it held 218. The daily figures record how commits reached the integration branch, not when the work was done.

Figure 29. Commits per day since 2026-08-09, when the family's own development begins, read at revision f5b38b4a: 1,585 commits on 49 active days, with the busiest day at 191. Gold marks are the 28 vibey release tags in the window; the brace marks the longest pause.

The daily rate's spread is 106% of its mean, against 24% inside the saturated region of A single-slot saturation curve; almost any model predicts that of an uncontrolled process, so the history does not test the curve; we report it so the controlled band is never mistaken for a field rate. Fig. 30 gives the hour, weekday and Conventional Commit type of every commit.

Figure 30. The rhythm of production since 2026-08-09, at revision f5b38b4a. (a) A 24-hour clock of commits in US Eastern time: every hour of the day carries commits, the busiest at 18:00 with 93 and the quietest at 09:00 with 33. (b) The weekday distribution. (c) The Conventional Commit types the pre-commit hook enforces, most common first.

Fig. 31 sets the 538 commits whose subject closes a pull request against the whole.

Figure 31. Cumulative production at revision f5b38b4a: commits since 2026-08-09 and, beneath them, the commits whose subject closes a pull request. The violet marks on the baseline are the days on which the absorbed packages' own histories begin; the family was written as several repositories and merged into one tree with every history preserved.

Nineteen vibey release tags run from 2026-08-16 to 2026-09-30; one version number ships the whole family (Fig. 32).

Figure 32. Every release tag created by the time of revision f5b38b4a, 28 tags on the repository; a tag is selected by its date, not by whether the revision's history reaches it, except that a tag cut at or after the revision itself is left out: it did not exist when the revision was the tip. The 28 vibey releases run from vibey-v0.1.0 on 2026-08-16 to vibey-v4.5.0 on 2026-10-23; since the packages were absorbed into one tree, one version number ships the whole family, and the packages' earlier tags were never carried into this repository, whose pre-absorption repositories have since been removed.

Fig. 33 is the shape of the tree at the pin, 420,679 lines of Python in 2,364 files and 11,384 test functions; it still lists two engine packages that ADR-0078 has since retired.

Figure 33. The shape of the tree at revision f5b38b4a: 470,996 lines of Python in 2,361 files and 12,484 test functions. (a) Lines and (b) test functions per package, each package counted together with the test suite its pytest configuration collects, vibey's in the top-level tests/; runners-common, agyloop, cursorloop have no test functions at this revision. (c) The orchestrator's layers, four of which fail the build below 100% branch coverage.

The autonomy scan of 2026-09-30

On 2026-09-30 a scan read develop at 15e909d4c (#1290) with four parallel code reviews and live evidence from the forge and the local queue, asking how close the system was to running on its own; we read every figure again on 2026-10-01, and the queries are tracked beside the paper.

Only BUILD ran without a person. DESIGN parks its interview for a person unless told to answer with defaults; REVIEW's gates wait for a person by design, and nothing answered them, so no project could reach DONE unattended; and a gate's stored deadline was read by nothing, so an unanswered gate waited forever. Part of that is design, since sub-doctrine 12.d bounds unattended authority by a gate; the rest was defects. The forge shows the same from the other side.

\begin{table}[t]
\centering\small
\begin{tabular}{@{}p{1.75in}p{1.45in}@{}}
\textbf{Measure, read 2026-10-01} & \textbf{Value}\\
The 40 pull requests merged into \texttt{develop} up to \#1290 (\#1226 to \#1290) & 0 reviewed; all 40 merged by the operator's account\\
What both \texttt{develop} rulesets require & one approving review; their bypass actors may bypass \emph{always}\\
Rule-suite evaluations of pushes to \texttt{develop}, the week to capture & 280, every one by the operator's account and every one a bypass\\
Reviews by the delegated approver's account (\texttt{thevibeyproject}, write role) & 0\\
PR review, the 15 runs created before 2026-10-01T00:00Z & 10 failed (9 in the sovereign diff review), 3 succeeded, 2 cancelled\\
Merge train, the 30 runs created before 2026-10-01T00:00Z & 22 dispatched, 7 after a review run, 1 on its schedule\\
\end{tabular}
\caption{The forge's record of who merged into the integration branch, read on 2026-10-01 at 11:39:49Z. The queries and their output are in the tracked evidence record of 2026-10-01.}
\label{tab:autonomy-forge}
\end{table}

The forty pull requests merged into develop up to the scan's revision carried no review; every one was merged by the operator's account through the ruleset bypass, and the delegated approver, its grant enabled, was never called. One reading did not survive the second pass: the 22 dispatched merge-train runs were not started by hand, as the scan read them, but by the review workflow once its gate was green. The first diagnosis of the sovereign reviewer's failure on #1090, a silently truncated prompt, was also wrong, as Exact-head evaluation and the release calculus records; in each case going back to the source, not the analysis, caught it.

The code reviews found seven defects, three of them failures of evidence rather than capacity: REVIEW was shown a test report and a coverage figure nobody had measured, a fallback supplied when the handler's payload was empty, so every human REVIEW in production had seen a fabricated report; the evidence guards between phases were reached only from tests; and the deadline nobody read. The other four were a paid engine's login trusted for 24 hours and every job needing one deferred indefinitely thereafter, a BUILD session with no wall-clock limit, a stop that ended the runner alone, and worktrees never removed. The repairs landed within a day, every one through the bypass the table records, so at this revision they are themselves evidence of the gap they address.

The merge train added a defect of its own: with the approval missing, the forge's merge command enables auto-merge and exits 0, which the train read as a merge, printing merged 1 and deleting the head branch, so the forge closed the pull request. On 2026-10-01 it closed six pull requests eight times, the fix for this very defect among them, before the train was made to count only a pull request whose state reads merged (#1301): automation reporting a success it did not observe, which sub-doctrine 12.e names. Replaying eight merged pull requests at their exact heads, once each, showed the sovereign reviewer passing all eight at low effort, the four the gate had blocked included, while seven of the gate's own eight block findings named something the file contains, six of them on lines outside the diff the reviewer was shown; given each changed file's full text (#1303), none of the seven came back. No pull request in the sample carries a known defect, so recall is unmeasured here, and agreement with the gate is agreement, not correctness.

The scan's questions are now asked weekly by a script whose stages, figures and thresholds are declared in configuration; the sentence and table below are generated from its append-only record, never edited by hand. At our cutoff the weekly workflow had not yet run, the readings were taken by hand with the same script, and at each of the three, one of the eleven declared stages met its thresholds.

At the latest measurement's cutoff, 2026-10-22 12:56Z, 0 of the 11 declared stages of the delivery loop met every threshold for running without a person; not yet autonomous: DESIGN resolves without a person (unknown), BUILD runs unattended (unknown), Paid engines stay available (unknown), REVIEW resolves without a person (partial), The pull-request review reaches a verdict (manual), The review's verdict is trustworthy (manual), Approval comes from the delegated approver (manual), Merges land without the operator (manual), Promotion and release run without hand steps (manual), CI stays green without human re-runs (partial), The queue delivers projects to DONE (unknown). The record is docs/architecture/evidence/autonomy-scorecard.jsonl.

\begin{table*}[t]
\centering\footnotesize
\begin{tabular}{@{}p{1.55in}p{2.2in}p{1.25in}p{0.75in}p{0.65in}@{}}
\textbf{Stage} & \textbf{Metric} & \textbf{Value} & \textbf{Threshold} & \textbf{Status}\\
\hline
DESIGN resolves without a person & DESIGN gates answered without a person & unknown & $\geq$ 95\%, n $\geq$ 5 & unknown\\
BUILD runs unattended & BUILD jobs finished per finished job or escalation & unknown & $\geq$ 90\%, n $\geq$ 10 & unknown\\
Paid engines stay available & paid engines with a login check inside its time-to-live & unknown & $\geq$ 100\% & unknown\\
REVIEW resolves without a person & REVIEW gate kinds that may resolve without a person & 1 of 2 (50\%) & $\geq$ 100\% & partial\\
REVIEW resolves without a person & REVIEW gates answered without a person & unknown & $\geq$ 95\%, n $\geq$ 3 & partial\\
The pull-request review reaches a verdict & merged PRs with a review verdict at their head & 0 of 74 (0\%) & $\geq$ 95\%, n $\geq$ 5 & manual\\
The review's verdict is trustworthy & the latest review-canary measurement meets its floor & no & yes & manual\\
Approval comes from the delegated approver & merged PRs approved by the delegated approver & 0 of 74 (0\%) & $\geq$ 95\%, n $\geq$ 5 & manual\\
Approval comes from the delegated approver & the review gate is a required check on the integration branch & no & yes & manual\\
Merges land without the operator & merged PRs merged by an account other than the operator's & 0 of 74 (0\%) & $\geq$ 95\%, n $\geq$ 5 & manual\\
Merges land without the operator & merged PRs carrying an approving review (no bypass) & 0 of 74 (0\%) & $\geq$ 95\%, n $\geq$ 5 & manual\\
Promotion and release run without hand steps & promotion runs a person dispatched by hand & 4 & $\leq$ 0 & manual\\
Promotion and release run without hand steps & promotions merged into the release branch by an account other than the operator's & 0 of 3 (0\%) & $\geq$ 95\%, n $\geq$ 2 & manual\\
Promotion and release run without hand steps & release publishes that succeeded & 3 of 3 (100\%) & $\geq$ 90\%, n $\geq$ 2 & manual\\
CI stays green without human re-runs & CI runs on the integration branch that succeeded & 43 of 61 (70\%) & $\geq$ 90\%, n $\geq$ 10 & partial\\
CI stays green without human re-runs & CI runs on the integration branch that were re-run & 1 of 80 (1\%) & $\leq$ 5\%, n $\geq$ 10 & partial\\
The queue delivers projects to DONE & projects that reached DONE & unknown & $\geq$ 1 & unknown\\
The queue delivers projects to DONE & hours since the queue's latest event & unknown & $\leq$ 24 h & unknown\\
\end{tabular}
\caption{The autonomy scorecard: each declared stage of the delivery loop, the figures that judge it, and the threshold at which it counts as running without a person. A stage is as far along as its weakest criterion, and unknown when nothing judged falls short but something could not be judged. Cutoff 2026-10-22 12:56Z; forge figures over the 14 days before it, queue figures over 30. A stale value is the last good one, with the date it was measured. Record docs/architecture/evidence/autonomy-scorecard.jsonl, regenerated by scripts/autonomy\_scorecard.py.}
\label{tab:autonomy-scorecard}
\end{table*}

Nothing the scan found was a shortage of production: BUILD ran. What stopped the loop at every other link was evidence, authority, or automation that misreported its own act. Gate timeouts became opt-in, and REVIEW keeps its person. Every merge into develop up to ca9e47452 (#1341) was still the operator's, through the bypass, this paper's own revisions among them, so the repairs are not yet evidence that the loop will deliver a change with nobody present.

Time to completion and what modulates it

vibey-gh postulates six materials, network, hardware, software, agent, information and agency, each available, stable and reliable, so a state is \(x \in \mathbb{R}^{18}\) and the shortfall from the stable peak \(x^{*}\) is \(d = x^{*} - x\); agency is not agent, since an agent may be present, rested, correct and informed and still lack the power to act, as the release calculus imposes on the credential that reviews. An operation is feasible when \(x \succeq r_o\), and its duration is \(T(o) = T_0(o) \prod_i \phi_i(d_i)\), where \(\phi_i\) is unity at \(d_i = 0\) and diverges as the coordinate nears its floor (Fig. 34). It is a postulate, not a law, and it carries no measurement of its own.

Figure 34. Network, hardware, software, agent, information and agency each supply three coordinates (availability, stability, reliability) of the state \(x \in \mathbb{R}^{18}\). An operation is feasible when \(x\) meets its requirement \(r_o\). Agency, the permission to act, is gold because governance sets it through human gates. Grey links are couplings: coordination, not a seventh material. Right: shortfalls \(d\) stretch the duration \(T(o)\).

The prediction it supports holds inside the saturation band only. Let \(r_{\min}\) and \(r_{\max}\) bound the band measured in A single-slot saturation curve. For \(W\) units of the same task class, admitted in the saturated region with every coordinate at its target,

\[T_0 \in \left[ \frac{W}{r_{\max}}, \frac{W}{r_{\min}} \right]\]

and in any other state \(T = T_0 \prod_i \phi_i(d_i) \geq T_0\): every shortfall dilates \(T_0\) and none shortens it. For that substrate and \(W = 100\), the band \([0.99, 2.00]\) per minute gives \(T_0\) between 50 and 101 minutes, where the serial rate alone would give 278 (Fig. 35). The interval is wide because the band is, and replication would narrow it; because the held-out check exceeded the band's ceiling, only the upper end is firm.

Figure 35. The completion-time prediction. At the stable band's rates, 100 units of the task class take between 50 and 101 minutes on the fixed substrate with every coordinate at its target; the serial rung alone would take about 278. Shortfalls in any material coordinate stretch the interval to the right and never shorten it.

Of the modulators that would move the band, only hardware is measured: paging space reached 99.1% at \(N = 128\), where the collapse and the crashes coincide, and the serving process died and was restarted at rungs 64 and 128. Network stability and operator availability are not measured, governance is set rather than measured, and information freshness has one measured instance, the stale figures this revision corrected. The delivery-estimate ledger applies the same form to the project (Fig. 36): from the observed merge rate it forecast 45 to 58 active days to completion at its last record, with every coordinate unmeasured and so at \(\phi_i = 1\), after the remaining work jumped from 25 to 708 units on 2026-09-23 when the storm filed its lanes as issues.

Figure 36. The delivery-estimate ledger, one forecast per record. (a) Remaining and completed work units as the tracker held them: remaining jumped from 25 to 708 on Sep 23, as open issues rose from 23 to 706 when the storm filed its lanes as issues. (b) The zero-shortfall time to completion the forecast derives from the observed merge rate, 42–56 active days at the last record, with every material coordinate unmeasured and so at \(\phi_i = 1\). Read from the ledger at the pinned revision, 54 records through 2026-10-24 18:09Z; records appended after the pin appear when the paper is re-pinned.

Governance has a price in time, and the price can be lowered without lowering the bar: computing the four per-layer coverage floors from one instrumented run took the gates from about 1,530 s to 136 s, an 11.3-fold reduction, and the bare suite from 383 s to 135 s, with no gate removed (Fig. 37), a governance dilation made smaller while the requirement stayed the same.

Figure 37. A governance dilation made smaller without lowering the bar. Computing the four per-layer coverage floors from one instrumented run took the gates from about 1,530 s to 136 s, and the suite itself from 383 s to 135 s, with no gate removed.

Falsification and scope

The saturation band is falsified, for its substrate, by any of the following:

  • a replication on the same substrate and task pool in which a saturated rung, one with success at or above 87.5%, runs below 0.99 per minute, or in which the band's mean moves by more than its measured spread of 0.33 per minute;
  • a log-log slope of throughput on \(N\) near 1 inside the region, which would make the rate demand-set rather than substrate-set;
  • a set of \(W\) units, admitted in the region with every coordinate at its target, that takes longer than \(W / r_{\min}\) to complete.

This is evidence, not proof, and narrow: one machine, one model served one way, one deadline, one artifact pool whose payload mix was not balanced across rungs, one stress session, one local Qwen pilot and one operator, with two of the five modulators named, mapped and unmeasured. We claim neither a natural law nor a constant rate, only a band on a substrate with the conditions under which it fails. The storm audit is narrower still, one storm on one model slot read from local logs never tracked and now gone, and merging ahead of review is one day of one project, not a controlled comparison. The autonomy scan is one revision read again a day later, and its review-lane replay is eight pull requests run once each with no known defect, so it says nothing of recall. The canary's recall is two runs on one host over 41 small single-file diffs by one author, matched by a lexical rule, and the large-diff study has no arm with a measured recall. The scorecard held three readings and the host's health record two, all within two days, so neither shows a trend.

\begin{plainwords}
We also measured the one computer all of this ran on. It is full: the model takes most
of its memory, the rest spills to disk, and that slows everything else we timed. Our
list of what a machine needs is measured again every week, and most of it is still
marked as old. Only the building step of the whole job runs with nobody watching; every
change still went in by the owner's own hand, and some of our own first conclusions
were wrong until we re-read the records. From the saturation curve we predict how long
a batch of work should take on that machine, and we list exactly what would prove us
wrong.
\end{plainwords}

Comparison with alternatives

A reader who grants every invariant can still ask whether the machine does more than its parts. We compare it with three alternatives on five axes: a session runner whose transcript is its source of truth, as Claude Code and Codex CLI are (the engines of The engine family wrap such runners); a transactional outbox (Richardson) under a workflow engine such as Temporal or Cadence, which never mentions agents; and a forge ruleset of required checks and a required approving review, as on this repository's integration branch. The table sets the four side by side.

\begin{table*}[t]
\centering\footnotesize
\begin{tabular}{@{}p{0.85in}p{1.35in}p{1.3in}p{1.35in}p{1.5in}@{}}
\textbf{Axis} & \textbf{(a) Session runner} & \textbf{(b) Outbox and workflow engine} & \textbf{(c) Ruleset and approval} & \textbf{Ledger-mediated}\\
Source of truth & the vendor's transcript, read by no other vendor & a durable record the engine replays & the repository and the forge's record & the append-only ledger; transcripts are attachments\\
Survives a crash & the run directory; resume by session id & replay of the durable record & the pull request and its check runs & the lease: at most $L$ of delay, no lost item, no double commit\\
A vendor's capacity exhausted & the run waits; moving it means a model-written summary & a failed step, retried or timed out & out of scope & a capacity verdict; credits carry no deadline; handoff only through the gate\\
Where a person decides, and the record & none defined; a denied question becomes a stated assumption & a waiting step; its timeout means what the author chose & the approving review, unless a bypass actor merges & a parked job and a \texttt{human\_gate} row before the lease is released; silence counts only where declared\\
What binds a verdict to a revision & a run-directory verdict, no completion evidence by its own docs & not in scope & checks bound to a revision; freshness left to the consumer & exact head: a verdict speaks for one revision\\
\end{tabular}
\caption{Three alternatives beside ledger-mediated orchestration on five axes. The (b) column describes the pattern generically; no tracked record of this repository measures it.}
\label{tab:comparison-axes}
\end{table*}

Against (a) the difference is in kind: a run's decisions, assumptions and open questions sit in a transcript shaped by one vendor, which the next engine cannot read, and a model-written summary drops them silently (docs/case-studies/how-vibey-survives-a-crashed-agent.md); a deterministic check over a log is feasible, over a chat transcript it is not (docs/architecture/decisions/0003-event-sourced-ledger.md). There it does not differ: the runner alone keeps an append-only trail and save points, tells a window from exhausted credits, and resumes by session id. The ledger's price: every meaningful engine output must be translated into events.

Against (b) the difference is not the durable record. By design the family's own job dispatch writes its outbox row in the transaction of the state change (docs/architecture/decisions/0044-job-queue-port-and-loop-services.md, a proposed record), a dispatch that docs/architecture/decisions/0056-everything-a-queue-guards-is-reaped-by-measurement.md records as declared, not wired; and a durable-execution library was rejected as Postgres-backed anyway (docs/architecture/decisions/0002-postgres-not-sqlite.md). The difference is what the record admits: a model-free predicate over minted ids at every handoff (docs/architecture/decisions/0004-no-loss-gate-on-handoff.md), a capacity taxonomy in which a window may carry a deadline and exhausted credits may not, held by a database constraint, and gates whose silence is a verdict only where the project declared it (src/vibey/domain/gate_timeout.py).

Against (c) the difference is narrowest. The forge's checks are revision-bound; it leaves the verdict's freshness to its consumers, and a green branch is not a green merge (docs/architecture/decisions/0036-the-merge-queue-is-declared-not-clicked.md). Exact-head evaluation and the release calculus adds the freshness test, the budget guard after it, and a judging credential separate from the merging one. This repository's loop ran as (c) with its approval bypassed rather than given: seven pull requests each reached fifty-one passing checks and landed only when the operator woke and merged them (docs/architecture/decisions/0049-the-delegated-approver.md), and the forty merged into the integration branch in the 2026-09-30 scan's window carried no review, each through the ruleset bypass (docs/architecture/evidence/autonomy-2026-10-01.md).

No controlled head-to-head was run. The chaos test proves the lease fence's property, no double commit and no lost job over 500 jobs and 8 workers, by abandoning claims in-process, not under a kill (tests/infrastructure/db/test_chaos.py); it compares nothing, and no record kills a runner alone and counts what survives. The live forced rotation has no tracked run record, and the gated handoff has run only on the wind-down path: the capacity-rejection path produces no brief (docs/architecture/decisions/0007-rotate-at-boundaries.md) and hard credits exhaustion is not wired (docs/plans/handoff-protocol.md). The autonomy scan is evidence about this project's loop, not the model: only BUILD ran unattended, merges ran ahead of review, and its repairs merged the same way; at the 2026-10-02 11:39Z cutoff one of eleven stages met every threshold for running without a person (docs/reference/autonomy.md).

The comparison that would settle it is only outlined. Hold fixed one host and a pinned gpt-oss:20b, an item pool fixed before the run, the deadline, and a kill schedule, kills at fixed turn boundaries and injected credits exhaustion, and run three arms on identical items: a lone runner resumed from its save points, the same runner behind the queue and ledger with gated handoffs, and the same work landed only through the ruleset and a human approval. Count, per item and before analysis, items lost or committed twice after a kill, closable items scored by the gate's id-set rules as an external key to every arm, wall clock to terminal state including gate waits, and changes merged without a verdict at their exact head, every run appended to the evidence ledger before scoring.

\begin{plainwords}
We set our system beside three familiar things: a coding assistant whose chat is its record, a job system that saves each step first, and a hosting rule demanding green tests and one human approval. Ours keeps a notebook no vendor owns, checks a handover by rule, not by a model's opinion, treats "out of money" differently from "wait an hour", and reads silence as a yes only where a project opted in. The job system shares the notebook; the hosting rule already ties tests to one version. We have not raced them, and one person merged our changes past the approval; we describe the race, not its result.
\end{plainwords}

Discussion

Convergence-Driven Development as a scoreboard

Specification-driven development states acceptance criteria and test-driven development makes them executable; neither says whether an unattended worker edited the tracked repository, kept its package boundaries, removed exploratory artifacts, or produced something deliverable. Convergence-Driven Development (ADR-0039) encloses both: ground in the tracked tree, map criteria to code and tests, implement, test, inspect, repair and deliver, until the evidence agrees. For an item let

\begin{equation}
D = U + F + B + A,
\end{equation}

where \(U\) is the set of unmet acceptance criteria, \(F\) the failing or missing checks, \(B\) the unresolved blockers and assumptions, and \(A\) the unreviewed or unrelated repository changes. An iteration is converging when it lowers \(D\), or when a bounded discovery step turns an unknown into a criterion, test or blocker; neutral when it gathers needed evidence without changing \(D\); diverging when it adds unresolved work, leaves the tracked stack, loses a known fact, or widens the change without a delivery path. A divergence bounded in size and duration is kept only with a named step back to a lower \(D\); an unbounded one is discarded and work resumes from the last sound state (Fig. 38). Activity is not a proxy: elapsed time, model confidence, a verdict or a done marker lowers \(D\) by nothing. The score is kept at four nested scopes, story, epic, phase and project, with missing parent context recorded as unknown, never invented, since a pass at one scope proves nothing about the one around it.

Figure 38. Each pass reads the tracked repository, turns criteria into tests, builds the smallest slice, runs the tests and classifies its trajectory. Converging work is delivered: committed, reviewed and published with its evidence. Neutral or slightly divergent work continues only with a written bound and reconvergence step. Unbounded divergence is discarded and work resumes from the last sound state; activity alone is never evidence.

The scoreboard is a useful instrument and nothing more: it does not make a model's final sentence true, a local marker cannot prove remote delivery, and a generated file cannot prove a feature exists in the tracked product. The project's governance canon extends this scoreboard into a broader biological philosophy, recorded in ADR-0041 and set out on the documentation site's page The biological philosophy, which this paper neither relies on nor argues for. The local Qwen pilot applied it per backlog item (Fig. 39): a verdict naming criteria, tests, trajectory and delivery, bounded retries, no advance past an unresolved item; partial verdicts, a failed forty-turn run and a live process were observable; none was evidence of a finished Python feature.

Figure 39. In a Qwen storm, each backlog item moves through five steps: read the tracked repository, change it, run the tests and gates, inspect the diff, and deliver. Whatever is not evidence, such as a partial verdict, a live process or generated files, sends the item back for a bounded retry; the next item waits until this one is proven done.

Governance as the scarce input, in this record

An earlier revision read the stress record as a thesis that production is a commodity and governance the scarce input; here we say only what this project's records show. The design treats executors as substitutable and priced; the inputs that stopped work in the tracked record were decisions and judgments. The stress run's collapse was the substrate's bound exceeded, not a malfunction; at the break the heal probe recorded lane responsive; no heal needed. Every remedy is an operator's decision; the lasting correction was a rule: admission should gate on payload size, not on concurrency count. ADR-0035 records the same shape: a review-independence rule made absolute in two places deadlocked BUILD on a one-engine pool, deferring one job forever with nothing in the ledger; capacity to produce was present, and the repair was a decision about the rule.

In this record, judgment is the other scarce input: self-grading is the weakest check (ADR-0035), and a human gate needs an explicit verdict, not an absence of objections. The record shows why: the production violation in Exact-head evaluation and the release calculus was automation acting correctly on a stale verdict, and the throughput figures corrected in What the records measure were a confident, wrong claim that stood unchallenged in a tracked paper until this revision.

On 2026-09-24 every change for 3.0.0 was sent for independent review and merging outran the reviews: the day's release-gate record, which is not tracked, counts seven pull requests merged before or during their reviews, open between 30 s and 49 min 44 s. Each finding went into a rescue pull request or branch while live on develop and published to the development package index, the worst being two high findings in the ledger guard; two changes that each passed their own gates broke develop together. None of this is a claim about anyone's care: producing the changes was cheap and fast that day, independent judgment took tens of minutes each, and where a merge ran ahead of it the judgment was still paid later. The storm audit and the autonomy scan in What the records measure say the same of this loop: the inputs that stopped work were decisions and judgments. The stress curve cannot say it about systems in general; it is a single-slot saturation curve on one machine, and which input is scarce elsewhere is beyond this record.

\begin{plainwords}
Being busy is not the same as being done. The loop keeps a simple score: how many
promises are not yet kept, how many tests still fail, how many questions are still
open, and how many stray changes were made. Every step must lower that score, or say
how the next one will; otherwise the work goes back to the last good state. In this
project's record the workers had not broken; what stopped work was a rule that needed
changing, a decision that needed making, or a check that needed a person. On the day
merges ran ahead of reviews, the reviews still had to be done, only later.
\end{plainwords}

Validation

The model is checked at three levels, and the paper's own figures are reproduced. At the property level, the gate, the phase guards and the selector are pure functions under a 100% branch-coverage floor per architectural layer, with property tests on the selector and the credits type. At the chaos level, concurrent workers process a job set against a real PostgreSQL while each randomly abandons claimed jobs mid-flight and a concurrent reaper reclaims the expired leases; the verified property is no double commit, no lost job, and every job terminal. Execution is at-least-once: a worker that outlives its lease may run a job another worker has reclaimed, but the acknowledgement is fenced on the lease owner, so the stale one is refused and exactly one commits per job. At the live level, a runbook drives one project from design to local completion on two paid engines, claudeloop and agyloop, with a forced rotation. That run is dated: agyloop has since been retired (ADR-0078), and live runs over the other engines are not reported here. Where the binaries are installed, a conformance suite drives claudeloop and codexloop through their own offline agents; agyloop and the local engines have none and rest on an in-memory double. Production-rate claims are validated separately by the stress record (What the records measure), and the local Qwen pilot does not enlarge them.

The 3.0.0 additions are validated the same three ways, and each went through an independent adversarial review. Its probes are review records, not tracked tests. The orchestrator suite runs as the restricted application role, so a query needing an undeclared privilege fails as permission denied, and a cluster-smoke step checks that the ledger refuses update, delete and truncation to the worker's role for want of privilege and to the owner by its triggers (#1100). The full suite at #1105's head passed 3,627 tests, with 18 skipped and 1 expected failure, under the four floors at 100%; the count is dated to that head, not this revision.

The 3.1.0 and 3.2.0 additions carry their own tests under the same four floors, declared since 3.2.0 as a forge rule on both permanent branches (#1277), though the forge refused every reconcile of it until #1321, after 3.2.0; read on 2026-10-02, both rulesets carry it. One measurement is reported as it came out, not as hoped: on a canary-injection issue, the frame that quotes an admitted issue to DESIGN did not stop the canary (4 of 10 runs with the raw intake, 5 of 10 framed), so the trust check that holds a stranger's issue, not the frame, is the control that holds (CHANGELOG.md, 3.1.0).

The changes after 3.2.0 are validated more narrowly than they are built, and we say where. The review lane's repair (#1316) is held by 31 tests, but its rates and 900 s wait come from the model server's log, and at our cutoff every production verdict was on a diff reviewed in one request. The review canary (#1325) has one measured run, and the weekly workflow that would repeat it has not run. The autonomy scorecard (#1335) and the host's health and tuning (#1330, #1334) are tested against fixture records; the scorecard's workflow has not run, its readings were taken outside it, and the Linux probes have seen only fixture trees. The client-build stage first ran in earnest on 3.3.0 (#1317, #1320); macOS signing and notarisation have run only against a fake, because no credential exists, the iOS build only in dry runs, and the Linux requirements (#1313) only in containers on one Mac; the native matrix has not run. The shutdown and database repairs were found by CI, not by review (#1309, #1310, #1314, #1326); the intermittent test race behind them was closed by #1332, which green runs alone cannot show; the fix holds by construction.

The paper is held to the same discipline (Fig. 40). docs/paper.md is its one source: one script recomputes the evidence, another writes the computed figures between revision-pinned markers and in check mode fails CI on drift, and pinned tools write the LaTeX, DOCX and PDF and compile each figure into SVG for the site and book. Two steps are not automated: a figure that fails to compile for the site shows its caption with a warning rather than failing the release, and a drawing's legibility is judged by a person, which is how this revision's figure defects were found.

Figure 40. Publication provenance. Evidence and computed figures are written into the one source, from which every output is derived by a pinned tool; the legibility of a drawing is still judged by a person, and a defect found that way is repaired in the source.
\begin{plainwords}
We check the system three ways. Tests walk every branch of the important code. A chaos test crashes helpers on purpose while a real database is running, to show that no job is lost and none is finished twice. A live run takes one whole project through two different robot helpers, with a forced switch between them in the middle; that run is old, and we do not report one on the newer helpers. The newest parts were also attacked on purpose by separate reviewers. Where a newer part was tested less than it was built, we say so. The paper itself is rebuilt from its records by pinned tools, and a person still checks that the pictures are readable.
\end{plainwords}

Queue-based job schedulers built on SKIP LOCKED provide claims, leases and retries but no delivery semantics. The ledger here is event sourcing in Fowler's and Helland's sense applied above the queue, with the write-ahead discipline of ARIES and the lease bound of Gray and Cheriton. Selection reuses nginx's smooth weighted round robin and the circuit breaker pattern as Nygard describes it.

Session runners and agent frameworks. SWE-agent drives one model through a thought, action and observation loop and saves each run as a trajectory file. During the run its state is the model's context; the trajectory is a record to inspect, not a state another model resumes from. Session runners such as Claude Code and Codex CLI go further: they persist each session's transcript on disk and can resume it by session id. When a long session fills the context window, older turns are replaced by a summary that the model itself writes. AutoGen coordinates several agents in conversation, and the conversation is again the state. In all of them the unit that survives is a transcript in one vendor's shape. Moving the work to another vendor's model, or past a context limit, passes through a summary that no procedure checks. Here a transcript is copied in as an attachment that events reference. It is evidence rather than state, so the session is disposable and the ledger is not.

Durable workflow engines. Temporal, and Cadence before it, persist an event history for every workflow execution. When a worker dies, another worker replays that history through deterministic workflow code and rebuilds the workflow's state exactly. Activities run at least once under retry policies and timeouts, and signals and timers let a workflow wait for a person. For crash recovery this is the guarantee the lease and the ledger replay give here, and a team already running Temporal would get it from Temporal. The transactional outbox pattern (Richardson) gives the matching guarantee for messages; this family's own job dispatch is designed around one, though it is not yet wired. What these engines record about a step is that it completed and what it returned. If the step is a coding agent, the returned value is opaque to the engine. Replay restores the fact that the agent finished and the payload it handed on, but nothing checks that the payload kept every question the agent had opened. Capacity is opaque as well: a rate window and exhausted credits are both failed activities. They are retried under whatever policy the author wrote, unless the author declared one error type non-retryable.

The property the gate adds. Neither family admits a handoff between two nondeterministic workers on a checked condition. The no-loss predicate of The no-loss handoff gate does. It computes without a model the ids opened and not closed in the summarised ledger range, for questions, decisions, assumptions, findings and artifacts. The brief is admitted only if it carries every one of them, together with the range's recomputed digest. "The successor knows what the predecessor knew" thus becomes a set inclusion a reviewer can re-run, instead of a property of a model's summary. It is one predicate, and a workflow engine could host it as a step. We claim the predicate and its placement at every engine boundary, not the durable record beneath it, which Comparison with alternatives sets out row by row.

Platform-native automation, merge queues and required checks, enforces revision-bound checks but leaves verdict freshness to its consumers. A ruleset that also requires an approving review, alternative (c), binds the checks to a revision but still not the verdict's freshness: a pull request whose checks passed against an older base proves only that that combination was green. The exact-head calculus closes that gap. Yanking semantics for published artifacts (PEP 592) informed the report-only supersession of releases, whose monotone sequence of published versions Trust separation and release monotonicity states, and keyless publishing through PyPI's Trusted Publishers removes stored release credentials.

Degraded-mode design follows the fail-operational tradition, with the difference that our refusals include commercial ones, which is why the order in which a lane falls back is set by how hard each fallback is to refuse rather than by mean time between failures. The retrieval engine is lexical over SQLite FTS5; dense retrieval would reintroduce the nondeterminism the reviewability invariant forbids.

The upward drift within the curve of A single-slot saturation curve is the continuous batching of Orca, and the coordination cost that the six-material postulate of Time to completion and what modulates it treats as a coupling rather than a seventh material is the one Brooks described for human teams. The bound on what more lanes sharing one model slot could buy is Amdahl's. The ledger guard uses PostgreSQL's own trigger and privilege machinery rather than rules, whose documented behaviour on partitions and TRUNCATE is what left the earlier guard open.

\begin{plainwords}
Other people have built pieces of this before: queues that hand out jobs, notebooks that are never erased, tools that let robots write code, and systems that replay work after a crash. What is different here is the combination: a strict rule for when a handoff counts, a strict line between ``slow down'' and ``out of money'', and checkpoints where silence never means yes. This section says where each borrowed idea came from.
\end{plainwords}

Conclusion

Putting the ledger, not the session, at the centre makes autonomous delivery survivable and auditable: engines become fungible, crashes become replays, and human authority is a structural property of the state machine rather than a prompt-engineering hope. The same discipline, binding every claim to the state it describes, governs the runners beneath the orchestrator and the release calculus above it, and the guarantees that 3.0.0 added, a ledger the database refuses to rewrite among them, are each stated with the limits they do not cross.

What the records show is narrower than the model. The throughput measurement is a single-slot saturation curve on one machine, not evidence that production is bounded in general; in this project's records, the inputs that stopped work were decisions and judgments. A local storm bound by one model slot converted no lane without a person, and the audit that found this was mostly wrong until it was verified. On the day a release's fixes landed, the step that limited delivery was independent review, which merging outran and then had to repay. A scan of the integration branch on 2026-09-30 found this project's loop autonomous only in BUILD, every merge made through the ruleset bypass, and seven defects, three of them failures of evidence, among them a review shown numbers nobody measured; the repairs landed within a day, still through the bypass. The reviewer's recall has been measured once, on small planted defects, and it showed a reviewer that can describe a defect and still pass it. Why it fails on large diffs is under a preregistered study, its registration kept in research/large-diff-review/experiments/, that has reached its mechanism and finished screening four diffs, not its result; production is unchanged until it does. The distance from running without a person is now measured again rather than written once, and at each of its first three readings one of eleven stages met its thresholds.

The engineering that remains is less about producing faster than about deciding well and cheaply.

\begin{plainwords}
Put the notebook, not the robot, at the centre. Then any robot can be swapped out, a crash just means reading the notebook again, and people stay in charge at the moments that need them. The measurements here are modest: one machine, one reading of how fast it could go, one test of a reviewer that noticed a defect and let it through anyway, and a study of why that is not yet finished. One mistake we found was a review shown numbers nobody had measured. In this project's own records, what held work up was a decision nobody had made yet. The work ahead is making those decisions easier to reach and cheaper to get right.
\end{plainwords}

Declarations

Data and code availability

Every record this paper measures is tracked in the repository at https://github.com/the-vibey-project/vibey, and every figure and table computed from one is regenerated from it by a named script: scripts/paper_evidence.py recomputes the numbers, scripts/paper_figures.py redraws the computed figures, scripts/minimum_specs.py the requirements tables, scripts/autonomy_scorecard.py the autonomy scorecard, and the storm's storm-evidence.py its evidence table. The sources are the stress record (src/vibey_tools/gh/docs/sovereignty-stress-2026-08-30.md), the evidence records under docs/architecture/evidence/ (the review canary's corpus and ledger, the autonomy scorecard, the host-health record, the minimum-specs record), the storm ledger under docs/plans/qwenstorm-3.0.0/, the large-diff study under research/large-diff-review/experiments/, and the git history itself. The one record the paper draws on that is not tracked, the storm throughput audit, is named as untracked where it is used. The source of this paper is docs/paper.md, and the renderer that typesets it, vibey-gh paper, ships in the same repository.

Use of generative AI

The text of this paper was drafted and revised with large language models used as writing and analysis assistants under the author's direction: Anthropic's Claude through Claude Code, OpenAI's Codex, and the GPT-OSS and Qwen models that vibey's own local runners drive. The same tools wrote much of the software the paper describes, which is the subject of the paper rather than a confound of it. No AI tool is an author. Every empirical statement was checked against the tracked records named above, and the author takes full responsibility for all of the content, including the parts those tools produced and every citation.

Authorship, funding and competing interests

Adam Matthew Steinberger is the sole author: he conceived and designed the system and the studies, built and operated the system, analysed the records, drafted and revised the text, approves this version and is accountable for all of it, which are the four criteria the International Committee of Medical Journal Editors sets for authorship. The repository records no funding source for this work, which ran on the author's own hardware and on GitHub-hosted runners, and the author declares no competing interests.

Reporting guidelines and registrations

No reporting guideline in the EQUATOR Network's library covers a systems paper of this kind; the library's checklists are written for health-research designs, and computer science runs its work through conference review. We therefore follow the basic level of the Transparency and Openness Promotion guidelines (TOP 2025) and state, above, where the data, code and materials are. One study here is registered: the large-diff review study, whose preregistration, log and data are tracked under research/large-diff-review/experiments/ and which is reported as in progress. No other study in this paper was registered; the remaining measurements are observational records of one project, read at the cutoffs each passage names.

\begin{plainwords}
Everything we measured is in the open repository, with the scripts that redraw every figure from it. We used AI writing and coding tools to help write this paper and to build the system it describes, and we say which ones; the author checked every claim and answers for all of it, and no tool is an author. The project's records show no one paying for this work, and the author has no competing interest to declare. The medical-style reporting checklists do not fit a systems paper, so we follow the open-science rule of saying where the data and code are; one study was registered in advance and is still running.
\end{plainwords}

References

  • PostgreSQL Global Development Group, SELECT — The Locking Clause (FOR UPDATE SKIP LOCKED, available since PostgreSQL 9.5). PostgreSQL documentation, https://www.postgresql.org/docs/current/sql-select.html, accessed 2026-10-06.
  • M. Fowler, Event Sourcing, 2005. https://martinfowler.com/eaaDev/EventSourcing.html.
  • P. Helland, "Immutability Changes Everything," Communications of the ACM 59(1):64–70, 2016. doi:10.1145/2844112.
  • C. Mohan, D. Haderle, B. Lindsay, H. Pirahesh, and P. Schwarz, "ARIES: A Transaction Recovery Method Supporting Fine-Granularity Locking and Partial Rollbacks Using Write-Ahead Logging," ACM Transactions on Database Systems 17(1):94–162, 1992. doi:10.1145/128765.128770.
  • C. Gray and D. Cheriton, "Leases: An Efficient Fault-Tolerant Mechanism for Distributed File Cache Consistency," Proceedings of the 12th ACM Symposium on Operating Systems Principles, 1989, pp. 202–210. doi:10.1145/74850.74870.
  • C. Richardson, Microservices Patterns: With Examples in Java, Manning, 2018 (the transactional outbox pattern; https://microservices.io/patterns/data/transactional-outbox.html).
  • Temporal Technologies, Temporal documentation: Workflows and durable execution, https://docs.temporal.io/workflows, 2024; and Uber Engineering, Cadence, https://cadenceworkflow.io/, 2017.
  • Anthropic, Claude Code documentation, https://docs.claude.com/en/docs/claude-code/overview, 2026; and OpenAI, Codex CLI, https://github.com/openai/codex, 2026 (session runners whose transcript is their state).
  • nginx, smooth weighted round-robin upstream balancing, introduced in nginx 1.3.1 (2012), ngx_http_upstream_round_robin.c.
  • M. T. Nygard, Release It! Design and Deploy Production-Ready Software, 2nd ed., Pragmatic Bookshelf, 2018 (the circuit breaker pattern).
  • J. Yang, C. E. Jimenez, A. Wettig, K. Lieret, S. Yao, K. Narasimhan, and O. Press, "SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering," NeurIPS, 2024. arXiv:2405.15793.
  • Q. Wu et al., "AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation," 2023. arXiv:2308.08155.
  • G.-I. Yu, J. S. Jeong, G.-W. Kim, S. Kim, and B.-G. Chun, "Orca: A Distributed Serving System for Transformer-Based Generative Models," 16th USENIX Symposium on Operating Systems Design and Implementation (OSDI), 2022.
  • F. P. Brooks, Jr., The Mythical Man-Month: Essays on Software Engineering, Addison-Wesley, 1975.
  • PEP 592, Adding "Yank" Support to the Simple API, Python Packaging Authority, 2019.
  • PyPI, Trusted Publishers, https://docs.pypi.org/trusted-publishers/, 2023.
  • GitHub, About protected branches and rulesets, GitHub Docs, 2024.
  • SQLite, FTS5 Extension, https://www.sqlite.org/fts5.html, accessed 2026-10-06.
  • G. M. Amdahl, "Validity of the Single Processor Approach to Achieving Large Scale Computing Capabilities," Proceedings of the AFIPS Spring Joint Computer Conference, 1967, pp. 483–485. doi:10.1145/1465482.1465560.
  • PostgreSQL Global Development Group, The Rule System and CREATE TRIGGER (rules and row-level triggers on partitioned tables; TRUNCATE triggers). PostgreSQL documentation, https://www.postgresql.org/docs/current/, accessed 2026-10-06.
  • International Committee of Medical Journal Editors, Recommendations for the Conduct, Reporting, Editing, and Publication of Scholarly Work in Medical Journals, 2026. https://www.icmje.org/icmje-recommendations.pdf.
  • Center for Open Science, Transparency and Openness Promotion (TOP) Guidelines, 2025. https://www.cos.io/initiatives/top-guidelines.
  • The vibey repository: the sovereignty stress record, src/vibey_tools/gh/docs/sovereignty-stress-2026-08-30.md; the evidence script, scripts/paper_evidence.py; the figure generator, scripts/paper_figures.py; the minimum-requirements record and its generator, docs/architecture/evidence/minimum-specs.json and scripts/minimum_specs.py; the review canary's corpus and ledger, docs/architecture/evidence/review-canary/; the autonomy scorecard's record and its generator, docs/architecture/evidence/autonomy-scorecard.jsonl and scripts/autonomy_scorecard.py; the host-health record, docs/architecture/evidence/host-health.jsonl; the large-diff study's preregistration, log and data, research/large-diff-review/experiments/; the architecture decision records, docs/architecture/decisions/; https://github.com/the-vibey-project/vibey, 2026.

Citing this work

To cite this paper, use the entry below; the repository's CITATION.cff carries the same record for citation managers and for GitHub's Cite this repository button. No DOI or preprint identifier has been assigned yet, so the entry points at the published PDF.

@misc{steinberger2026ledger,
  author = {Steinberger, Adam Matthew},
  title  = {Ledger-Mediated Orchestration:
            Vendor-Independent Autonomous
            Software Delivery over a Pool
            of Coding Agents},
  year   = {2026},
  url    = {https://the-vibey-project.github.io/vibey/main/paper.pdf},
  note   = {Source: docs/paper.md in
            github.com/the-vibey-project/vibey}
}

Appendix. The operational record from 3.0.0 to 4.1.0

The operator's record by release, each fact with its pull request, issue, ADR or migration.

Minimum system requirements

The minimum requirements are measured weekly, and the table is regenerated from a record that keeps measured, declared and derived figures apart and marks a figure it could not re-measure stale, with its date. At our cutoff, 2026-10-02, the weekly workflow had never run: every figure comes from three seed passes on one host on 2026-09-29 and 2026-09-30, and every row is a dated measurement, not a statement about this revision.

\begin{table*}[t]
\centering\footnotesize
\begin{tabular}{@{}p{1.3in}p{2.3in}p{2.0in}p{0.9in}@{}}
\textbf{Requirement} & \textbf{Minimum} & \textbf{Recommended} & \textbf{Basis}\\
\hline
Memory, Apple Silicon (unified) & 24 GB (stale since 2026-09-30: derived from stale input(s): ram.minimum\_need\_gib) (needs 20.30 GiB (stale since 2026-09-30: derived from stale input(s): ram.model\_process.ctx32768)) & 32 GB (stale since 2026-09-30: derived from stale input(s): ram.recommended\_need\_gib) (needs 27.46 GiB (stale since 2026-09-30: derived from stale input(s): ram.model\_process.ctx131072)) & derived, stale\\
Memory, 16 GB Mac & insufficient (stale since 2026-09-30: derived from stale input(s): ram.design\_only\_need\_gib): DESIGN alone needs 19.63 GiB (stale since 2026-09-30: derived from stale input(s): ram.model\_process.ctx8192); the GPU part is -6,344.0 MiB (stale since 2026-09-30: derived from stale input(s): bench.gpt-oss:20b.ctx8192.device\_mib, gpu.metal\_limit\_16gb\_mib) over its limit at 8,192 & - & derived, stale\\
GPU memory for gpt-oss:20b & 12,339 MiB (stale since 2026-09-30: no accounting line in the log) at 8,192; 12,974 MiB (stale since 2026-09-30: no accounting line in the log) at 32,768 & discrete GPU: 16 GB (stale since 2026-09-30: derived from stale input(s): bench.gpt-oss:20b.ctx32768.device\_mib) card (not verified on CUDA) & measured, stale; derived, stale\\
Model throughput at 24k depth & 10 tok/s generation, 100 tok/s prompt (worst BUILD turn 512 s of 900 s) & 25 / 500 tok/s (worst turn 143 s); measured here 18.1 tok/s (stale since 2026-10-02: Ollama failed at depth, num\_ctx 32768: timed out) / 379 tok/s (stale since 2026-10-02: Ollama failed at depth, num\_ctx 32768: timed out) & derived; measured, stale\\
CPU only (no GPU) & DESIGN call 373 s (fits: yes); worst BUILD turn 4,814 s (fits: no) & use a GPU; CPU only measured 4.2 tok/s generation, 7.1 tok/s prompt & derived; measured\\
Free disk & 20 GB (stale since 2026-09-30: derived from stale input(s): disk.minimum\_need\_gb) (needs 17.3 GB (stale since 2026-09-30: derived from stale input(s): disk.ollama\_app\_bytes)) & 50 GB (stale since 2026-09-30: derived from stale input(s): disk.recommended\_need\_gb) (needs 44.7 GB (stale since 2026-09-30: derived from stale input(s): disk.minimum\_need\_gb)) & derived, stale\\
Python & 3.12 (declared $\geq$3.12) & works on 3.12, 3.13, 3.14 & derived; declared\\
PostgreSQL & 14 (checked on connect) & measured on 14.24: 22 migrations applied & declared; measured\\
Ollama with gpt-oss:20b (sovereign default) & required unless a paid engine is set up; measured on 0.40.11 & - & measured\\
Model download, gpt-oss:20b & 13.79 GB & qwen3:14b 9.28 GB (opt-in) & measured\\
Install download, vibey-engine & 161.2 MB & with {[}hub{]} 162.8 MB; krypton-app 162.8 MB & measured\\
Internet at runtime (sovereign path) & none & - & measured\\
\end{tabular}
\caption{Minimum and recommended requirements for the sovereign default (vibey, gpt-oss:20b on Ollama and PostgreSQL on one host), as the weekly measurement last recorded them. Measured on GitHub-hosted ubuntu-24.04-arm, Mac17,2 $\cdot$ Apple M5 $\cdot$ 24 GiB $\cdot$ macOS 26.6.2 (25G83), aarch64 $\cdot$ unknown chip $\cdot$ 23 GiB $\cdot$ Ubuntu 24.04.4 LTS, figures dated 2026-09-29 to 2026-10-26 (UTC); record \texttt{docs/architecture/evidence/minimum-specs.json}. A stale figure is the last good value, marked with the date it was last measured.}
\label{tab:minimum-requirements}
\end{table*}

At the seed, memory was the binding constraint, set by the context rather than the model file; with vibey, PostgreSQL and the operating system the host needs 24 GB at minimum and 32 GB recommended. A 16 GB Mac cannot run the sovereign default, a verdict that is derived, since no 16 GB machine was measured. And a GPU is not optional for BUILD: on the CPU alone, at about 4 tokens per second, a DESIGN call fits the 900 s timeout and the worst BUILD turn does not. Linux is measured as a matrix of distributions and architectures, each in its own container image.

\begin{table*}[t]
\centering\footnotesize
\begin{tabular}{@{}p{1.2in}p{0.55in}p{0.65in}p{0.8in}p{0.8in}p{0.9in}p{1.2in}@{}}
\textbf{Distribution} & \textbf{Arch} & \textbf{Run} & \textbf{Cores min / rec} & \textbf{Disk min / rec} & \textbf{PostgreSQL} & \textbf{glibc}\\
\hline
Ubuntu 24.04 LTS & x86\_64 & native & not measured / not measured & 20 GB / 50 GB & 16 ($\geq$ 14: yes) & 2.39 (wheels need 2.34: yes)\\
Ubuntu 24.04 LTS & aarch64 & native & unreachable (stale) / 5 (stale) & 20 GB / 50 GB & 16 ($\geq$ 14: yes) & 2.39 (wheels need 2.34: yes)\\
Ubuntu 26.04 LTS & x86\_64 & native & not measured / not measured & 20 GB / 50 GB & 18 ($\geq$ 14: yes) & 2.43 (wheels need 2.34: yes)\\
Ubuntu 26.04 LTS & aarch64 & native & unreachable (stale) / 5 (stale) & 20 GB / 50 GB & 18 ($\geq$ 14: yes) & 2.43 (wheels need 2.34: yes)\\
Arch Linux & x86\_64 & native & not measured / not measured & 20 GB / 50 GB & 18.6 ($\geq$ 14: yes) & 2.44 (wheels need 2.34: yes)\\
Arch Linux & aarch64 & not run & unreachable (stale) / 5 (stale) & - & - & -\\
Fedora (current release) & x86\_64 & native & not measured / not measured & 20 GB / 50 GB & 18.6 ($\geq$ 14: yes) & 2.43 (wheels need 2.34: yes)\\
Fedora (current release) & aarch64 & native & unreachable (stale) / 5 (stale) & 20 GB / 50 GB & 18.6 ($\geq$ 14: yes) & 2.43 (wheels need 2.34: yes)\\
\end{tabular}
\caption{The Linux matrix: each supported distribution on each architecture, measured in the distribution's own container image. Memory is the same for every cell, 24 GB (stale) minimum and 32 GB (stale) recommended, from the least-squares line $M(c) = M_0 + kc$ fitted to the measured model memory ($M_0$ = 15,684 MiB (stale), $k$ = 33.088 (stale) KiB/token, $R^2$ = 0.999402 (stale)) with a declared headroom factor. Cores come from Amdahl's law fitted per architecture: the minimum reaches the minimum generation rate, the recommended is the knee where $dT/dn$ falls to a declared threshold. An emulated cell's sizes and versions stand; its timings are refused. Measured on GitHub-hosted ubuntu-24.04-arm, Mac17,2 $\cdot$ Apple M5 $\cdot$ 24 GiB $\cdot$ macOS 26.6.2 (25G83), aarch64 $\cdot$ unknown chip $\cdot$ 23 GiB $\cdot$ Ubuntu 24.04.4 LTS, archlinux:latest (linux/amd64, native) on GitHub-hosted ubuntu-24.04, fedora:latest (linux/amd64, native) on GitHub-hosted ubuntu-24.04, fedora:latest (linux/arm64, native) on GitHub-hosted ubuntu-24.04-arm, ubuntu:24.04 (linux/amd64, native) on GitHub-hosted ubuntu-24.04, ubuntu:24.04 (linux/arm64, native) on GitHub-hosted ubuntu-24.04-arm, ubuntu:26.04 (linux/amd64, native) on GitHub-hosted ubuntu-24.04, ubuntu:26.04 (linux/arm64, native) on GitHub-hosted ubuntu-24.04-arm, figures dated 2026-09-29 to 2026-10-26 (UTC).}
\label{tab:linux-requirements}
\end{table*}

Most of what the method promises is not yet in the table: no native runner has run a cell, the x86_64 cells ran under emulation, where the installer crashed, and no Linux memory, core count or ledger growth has been measured. What stands is that every cell that ran packages a Python, a PostgreSQL and desktop libraries that meet the floors.

3.0.0

The ledger guard (#1100, ADR-0055; amended by #1112, merged 15:18Z 2026-09-24). Migration 0016 replaces the rules with a BEFORE UPDATE OR DELETE row trigger and a BEFORE TRUNCATE statement trigger that refuse every rewrite of event. Migration 0017 pins the guard functions and the owner's session to search_path = pg_catalog, pg_temp; vibey migrate itself takes CREATE on public from every role but the owner before any migration runs; and the ledger-guard doctor check fails when the application role may create objects, owns any, may call a SECURITY DEFINER function or may set session_replication_role. Migration 0019's AFTER INSERT trigger only announces appends. A one-role install fails ledger-guard and exits migrate with 1.

Merges that outran review, 2026-09-24. The release-gate record (12:22Z, untracked) counts seven pull requests merged before or during their reviews (#1094, #1095, #1100, #1101, #1102, #1103, #1105); #1089 merged 30 s after opening and #1092 while its review said not yet. #1100 and #1103 passed separately and broke develop together (repaired by #1109). #1106, a rewrite of the merged migration 0015, closed unmerged at 13:24Z; ADR-0054 records the gap.

The priority lane. ADR-0054 states one contract for the job queue (#1091, #1095) and the storm's lane queue (#1089, #1092), with follow-ups #1102, #1103, #1111 and #1122.

The engine environment is assembled from system basics, the engine's own variables and credential, and the project's engine_environment; a declaration naming a forbidden variable (vibey's own, libpq's, anything shaped like a database credential) is refused when the worker is built; a forge or cloud token reaches only an engine the project names.

The delivery bridge (scripts/triaged_delivery.py) terminates an overrunning worker's tree deepest first with a 2 s grace, because uv run children outlive a signal to their parent, then reaps with vibey queue reap --project (#1244); the DESIGN-interview repair is #1258, #1261 and #1270; the fit probe is scripts/sovereign_probe.py.

The review lane became sovereign by declaration (#1086, #1087, #1088) and refuses a cut prompt four ways (#1094, #1101). #1101 corrects #1094's misdiagnosis of #1090, records #1090's 3.95 characters per token, and reproduces a silent half-window read on Ollama 0.34.2 (an 80,060-character prompt, counted as 36,798 tokens, answered HTTP 200 with prompt_eval_count 16,386; with truncate: false and shift: false, HTTP 400 in 0.3 s); five rounded ratios for denser text sit beside chars_per_token in src/vibey_tools/gh/docs/configuration.md.

3.1.0 and 3.2.0

vibey abandon (#1263; from intake since #1276) releases the checkout (migration 0021, #1279). BUILD branches are vibey/<project8>/<cycle>/<item>; an unprovable one parks on foreign_branch (#1269). Review runs in at most max_chunks parts, six by default, refused pre-send as diff_exceeds_window or chunk_budget_exceeded (#1252); split_added_hunks (#1278) exists because the 3.1.0 promotion's 136,308-character CHANGELOG.md hunk got no verdict. The trust seam is #1248 (scripts/intake_trust.py).

3.3.0

Released 2026-10-02 (main at 4188aad66, promoted by #1343).

The scan's seven gaps at 15e909d4c, repair state at 4acb9be5c. review.demo was queued with no payload and its handler fell back to a JUnit report of failures='0' and 100% coverage (#1294, merged). The two evidence guards were reached only from tests (open). A paid login trusted only while younger than 24 hours deferred paid jobs indefinitely (#1295, merged: rechecked at half its life). A BUILD session had no wall-clock limit (#1296, merged: 240 minutes). stop() terminated the runner alone (#1297, merged: a process group per session). No worktree was ever removed (#1298, open at 4acb9be5c, merged 12:06Z 2026-10-01; #1305 at 12:09Z). A gate's timeout_at and default_answer were acted on by nothing (#1299, merged). #1300 declares the standing grant in [autonomy]; #1302 adds 21 forbidden paths for the approver.

The merge train's own incident. With the required approval missing, gh pr merge --squash enables auto-merge and exits 0; merge() read that as a merge and deleted the head branch. Between 01:24Z and 06:47Z on 2026-10-01 six pull requests were closed eight times (#1295 and #1298 twice; #1293, #1297, #1301, #1302 once); every branch was restored and every pull request reopened by 09:17Z. #1301, merged 09:27:44Z, counts only a forge-reported MERGED state and leaves an OPEN one queued.

Repairs found by CI, not review. #1309 reproduces the cross-loop shutdown error (#1297's stop awaited a reap from another event loop). The session_replication_role grant is one pg_parameter_acl row per cluster, so parallel reconciles race on it: #1310 (tuple concurrently updated, PostgreSQL 16; retried up to five times with a linear backoff, other errors raised), #1314 (tuple concurrently deleted), #1326 (a parameter-ACL cache-lookup failure on PostgreSQL 18, run 36925371389); #1332 serializes the tests' grants. That repairs the tests only: production databases sharing a cluster still race on the row, the per-database migration lock cannot serialize them, the bounded three-message retry is what holds, and a cluster-wide lock is a recorded follow-up, not a repair (#1326, #1332).

CI. The KEDA contract raced a worker's drain under Helm 4, whose --wait counts a terminating pod as in progress; it now waits for deployment availability and scaler readiness, with Helm pinned (#1327). The Arch desktop job falls through four official mirrors and retries the install three times (#1333). vibey-gh advisory-check replaces npm audit --audit-level=high; an exception in .github/advisory-exceptions.toml names one advisory in one package, expires within 30 days, and fails when expired, unmatched or patched upstream (#1336); the one, GHSA-86w9-cpqp-85rv in node-forge 1.4.0, runs 2026-10-01 to 2026-10-31, a risk accepted with a date, not a fix.

The reviewer. #1312 (run 36879717279) got two model_timeout attempts on a free model: nothing enforced the output reserve, and a queued review had worn the same code. #1316 sends the reserve as num_predict (16,384), refuses a filled reserve as done_reason=length, sets the deadline \(t = \max(t_0, p/r_p + R/r_o)\) with \(t_0 = 600\) s, \(r_p = 200\) and \(r_o = 20\) tokens per second, and retries model_busy but not model_timeout; its re-plan of #1312 (deadlines 1,065 s and 1,044 s) is a plan, not a run. #1317 was merged at 19:53Z on 2026-10-01 before its review started and #1334 at 02:40Z before its ended. Canary (#1325): first measurement #1331 (2026-10-01), weekly run 37002135164 (2026-10-02), corpus pinned at 0f88412 (first 2b17eb7), ledger docs/architecture/evidence/review-canary/ledger.jsonl. Cut for room: the lane's per-pull-request verdicts and run ids to 03:50Z 2026-10-02, and the study's arms, thresholds and Stage 0 and 1 figures (research/large-diff-review/experiments/).

Clients. The release attached eleven client files, each checked by the operator against its checksum and attestation (#1317, #1320), and first listed the extension on Open VSX.

After 3.3.0, and 3.4.0

At the body's cutoff 3.4.0 was not cut and this work was planned for it (#1349) on develop at 4d51a764c; CHANGELOG.md at this revision dates 3.4.0 to 2026-10-02, a later cutoff. It adds krypton desktop for Apple silicon on macOS 15 or newer, ad-hoc signed until the Developer ID secrets exist, Intel Macs unsupported (#1351); an iOS build through EAS (#1346, #1347, #1348, #1350); clients/ among the version's code paths (#1348); and desktop pairing by one-time code (#1359). The dry run 36976031188 on #1351's head was a rehearsal: no Developer ID or notarisation credential, nothing submitted to TestFlight, Gatekeeper on a quarantined .dmg unexercised. Weekly canary and minimum-requirements results lost to an artifact path were recovered (#1361, #1365; #1360 holds downloads to their uploads' root).

4.0.0 and 4.1.0

4.0.0 (2026-10-03) retires and deletes cursorloop and agyloop (ADR-0078, #1376): configuration naming either is refused, and old ledger, health and rotation rows stay valid. Hybrid dispatch (ADR-0079) adds [engines] mode: singleton; hybrid, where a paid engine takes a BUILD job only once every eligible local slot is occupied, the job has waited overflow_after_seconds and the UTC day's paid_daily_cap is unreached; or auto, the default, which falls back to singleton when its ledger measurement of local-slot contention is missing, stale, invalid or failed; sub-doctrine 8.a's overflow clause awaits the operator's ratifying merge. scripts/install.sh installs vibey in one command, repairs it when run again, and copies the whole codebase with --from-source; scripts/uninstall-krypton.sh removes every krypton interface and never touches vibey-engine's core (sub-doctrine 10.m, ADR-0082). The backlog loop now compares an issue against its latest verdict, after issue #1204 received six identical reports (2026-09-27 to 2026-09-29). The 4.1.0 entry (2026-10-05) is a heading with nothing under it.

\begin{plainwords}
This last part is the logbook for the people who run the system, version by version, with the ticket numbers to look each fact up by. It says what each guard now refuses, which changes were merged before their reviews had finished, how the merge robot once closed six changes by mistake and how every one was put back, which bugs the test computers found that no reviewer did, and which apps each release ships. Where a fix mends only the tests and not the running system, it says so.
\end{plainwords}

A call to FOSS developers

Everything in this paper is free and open-source software, built in the open, and it is not finished. The machines that write code are cheap now; what is scarce is infrastructure a person can own, governance that holds up when nobody is watching, and evidence honest enough to publish. If you write software and any of that speaks to you, come and build it with us.

Bring your questions, your critiques and your pull requests. Whether you care about queues and ledgers, sovereign local models, reproducible benchmarks, or the measurement of a delivery loop that is honest about what it has not yet shown, there is a lane for you.

\begin{plainwords}
All of this is free software that anyone can read, run and improve. If you like queues, notebooks that cannot be erased, running models on your own computer, or honest measurements, there is work here for you, and the links above are where to start.
\end{plainwords}