Skip to content

EthenEthenEthen

Reserving a Budget for Verification

An agent that spends its whole budget doing the work has nothing left to check it. Ethen's mission system reserves verification capacity first — computed in exact integer arithmetic.

An agent that spends its whole budget doing the work has nothing left to check it. Ethen's mission system reserves verification capacity first — computed in exact integer arithmetic.

The standard failure mode of an autonomous job is not that it spends too much. It is that it spends everything on acting and leaves nothing for checking. Execution consumes the budget; verification becomes an unfunded afterthought; and the mission either completes without evidence or stalls waiting for a check nobody reserved capacity for. Ethen's missions infrastructure takes the opposite approach: verification capacity is planned first, executor spend second, and both are tracked in integer money arithmetic that cannot silently lose a fraction of a cent to floating-point rounding.

This article traces that mechanism as implemented. The core is a small, dependency-free module — packages/missions/src/budgets/allocations.ts — that defines micros arithmetic and reservation planning, and the Stage-0 exit audit that describes how those reservations fit into the wider mission system. The scope here is deliberately narrow: how money is represented, how remaining capacity is computed, how reservation slices are ordered, and where this planning meets enforcement. No prices, savings figures, or live spending results appear, because the inspected sources contain none.

Why verification gets its own reservation

To understand why the budget code reserves verifier capacity at all, it helps to see what verification means in the mission system. The independent Stage-0 exit audit describes missions as autonomous outcome execution, distinct from interactive Chat and from the Platform control plane. A mission moves through a chain — contract compilation, constraint ledger, durable orchestration, dispatch, observation — and then reaches an independent verifier: a separate service, image, role, and queue. The verifier re-hashes evidence bytes, applies deterministic oracles, and records the result. Completion is gated on that result: the finalize path requires the mission to be in a verifying state with a verifier-recorded PASS, plus hash and freshness checks, no unresolved unknown effects, and mandatory tasks succeeded.

The audit states the consequence plainly: completion without independent evidence is impossible by construction. Finalize authority derives the verdict rather than accepting one, and the finalize grant belongs to the verifier role only — an executor attempting to finalize is denied, and that denial is covered by tests.

That independence is organizational as well as technical. The worker and verifier run as separate processes under restricted database roles, and the audit confirms zero privileged client usage across the missions packages. So verification is not a function the executor calls when it feels like it; it is a separate party with its own capacity, its own queue, and its own authority. A separate party needs a separately reserved budget. If the executor could consume the whole mission limit on its own actions, the verifier's queue would hold work it could never afford to check, and the "no evidence, no completion" invariant would deadlock against an empty wallet. Reserving the verifier's share first is what keeps the invariant fundable.

It is worth noting what the audit does not claim. The verifier mechanism passed its Stage-0 track, but human calibration of verification remains a baseline requirement deferred to a later gate, and several live capabilities — per-connector effect reconcilers, live browser trials, model-judge scoring — are explicitly out of Stage-0 scope. The reservation mechanism budgets for the verifier as it exists in Stage 0: deterministic oracles and evidence checks, not live provider reconciliation. The budget code plans capacity; it does not conjure capabilities that have not shipped.

Money as integers: micros strings and BigInt

The budget module's header comment states its central decision in two sentences: USD micros travel as digit-only decimal strings — never floats, never lossy JSON numbers — and all arithmetic goes through BigInt, so values past 2^53 stay exact end to end. Every part of that sentence carries weight, so it is worth unpacking each choice.

First, micros. A micro is a millionth of a unit, so one US dollar is 1,000,000 micros. Representing money in the smallest accountable unit as an integer is a long-standing practice in billing systems: it turns every amount into a whole number and every computation into integer arithmetic, which is exact by definition. There are no repeating decimals, no binary-fraction approximations of 0.1, and no rounding mode to argue about at the planning layer. The module deals purely in these integer micros; display formatting is somebody else's problem.

Second, digit-only decimal strings. Amounts cross process and serialization boundaries as strings matching ^\d+$ — one or more ASCII digits, nothing else. No sign, no decimal point, no exponent, no whitespace. The assertMicros function enforces this at every entry point: anything that is not a digit-only string is rejected with a MicrosError naming the offending field. Strings are the right carrier here because JSON numbers are IEEE-754 doubles, which cannot represent every integer past 2^53. A large micros balance serialized as a JSON number could arrive off by one or more units — a silent corruption of money. As a string, the digits survive serialization exactly, and BigInt parses them without loss.

Third, BigInt arithmetic. Comparison, addition, and subtraction each convert validated strings with BigInt(...) and compute on arbitrary-precision integers. The cmpMicros function returns -1, 0, or 1; addMicros returns the exact sum as a string; subMicros returns the exact difference but throws if the result would go negative. That last behavior is a design decision worth pausing on: subtraction that would go negative is not clamped to zero, it is an error. Clamping would hide overspending by silently reporting an empty remainder; throwing forces the caller to confront the fact that the numbers do not add up. In a budget system, an exception is more honest than a zero.

The module is pure and dependency-free — no imports, no I/O, no clock, no randomness. That purity is what makes it testable and auditable: given the same strings in, it always produces the same strings out. There is no configuration that changes rounding, no environment flag that relaxes validation. The audit lists this module alongside the constraint ledger and the SQL claim gates as the missions-side authority for spending decisions, which is exactly the company a pure arithmetic core should keep: it computes, and the database enforces.

The allocation triple: limit, reserved, spent

Money representation answers "how much," but budgeting also needs "how much of what, and in which state." The module answers with the AllocationState interface: three readonly micros strings named limit, reserved, and spent.

The limit is the mission's total spending authority — the ceiling. The spent figure is what has already been consumed and cannot come back. The reserved figure is the interesting one: capacity earmarked for work that has been authorized but not yet executed or settled. Reservation is the mechanism that prevents double-spending a budget across concurrent actions. Without it, two actions could each check the balance, each find it sufficient, and each spend it — the classic check-then-act race. With it, the first action reserves its share before acting, and the second action sees the reduced remainder.

Remaining capacity is computed by remainingAllocation: limit minus reserved minus spent. Reservations encumber the budget just as firmly as spending does. And because subtraction goes through subMicros, any state where reserved plus spent exceeds the limit throws rather than reporting a negative remainder. An inconsistent allocation state is a bug to surface, not a balance to display.

The fitsInAllocation check then compares a proposed amount against that remainder: the amount fits if it is less than or equal to what remains. The module's documentation calls out one edge explicitly — an explicit zero fits. A zero-cost operation, properly represented as the string "0", always passes the fit check (assuming the state itself is consistent). That matters because missions contain actions that cost nothing but still need authorization to proceed; a budget check that rejected zero-amount actions would force callers to bypass budgeting for free operations, creating exactly the unmonitored path that budgets exist to close. Zero is a first-class amount here, validated and compared like any other.

Note the deliberate boundary of this layer: fitsInAllocation is a planning predicate, not an enforcement lock. It tells the caller whether an amount fits right now. Preventing two concurrent callers from both fitting into the same remainder is the job of the atomic reserve at claim time, which lives in the database layer. The audit describes that claim path as re-reading revision, membership, grant, contract digest, kill-switch, and world generation, then consuming the approval and reserving budget atomically — with the TypeScript layer explicitly advisory-only: "the database decides." The pure functions compute the numbers; the database serializes the decision. Confusing the two layers — treating a fit check as a guarantee — would reintroduce the race the reservation exists to prevent.

Verifier first: ordering reservation slices

The module's most opinionated function is planReservationSlices, and its opinion is stated directly in its documentation: order reservation slices with verifier capacity first and executor spend second. Given an executor amount and an optional verifier amount, it returns an ordered list of slices, each tagged with its kind and amount.

Three behaviors define the function. First, the verifier slice comes first whenever it is nonzero. Ordering matters because reservations are consumed against a finite remainder in sequence: what is reserved first is guaranteed its share, and what comes second gets what is left. Placing the verifier first means the check is funded before the work — the budgetary expression of "no evidence, no completion." If the mission cannot afford both acting and checking, the planning order ensures the shortfall lands on execution, not on verification. A mission that cannot afford its own verification should not start acting with the verifier's share.

Second, a zero verifier amount is omitted — there is no slice to reserve. This is not the same as treating verification as optional; it handles missions or steps where no separate verifier capacity is priced. When the verifier amount is absent entirely (null or undefined), it defaults to zero and is likewise omitted. The function distinguishes "no verifier cost to reserve" from "executor costs nothing," and only the former collapses away.

Third, the executor slice is always explicit, including zero-cost operations. Even when the executor amount is "0", the plan contains an executor slice with that amount. This mirrors the fitsInAllocation treatment of zero: free work is still planned work, visible in the reservation list rather than silently unaccounted. An auditor reading a reservation plan can see that the executor's share was considered and found to be zero, rather than wondering whether it was forgotten. Explicitness is the cheaper property to verify.

The asymmetry between the two slices — verifier omitted when zero, executor always present — reflects their different roles. The executor slice describes the work being authorized, which always exists as a concept even when free. The verifier slice describes priced verification capacity, which may genuinely be absent for a given step. The planner does not invent verifier costs where none were given, and it does not hide executor authorization where the cost is zero.

It is important to keep this function's role in proportion. It plans the order and shape of reservations; it does not set the amounts, approve the mission, or move any money. The amounts arrive as parameters from callers upstream, and the slices depart as data for enforcement downstream. Its entire contribution is ordering plus explicitness — but in a system where the party that reserves first is the party that gets funded, ordering is the policy.

Where reservations meet authorization

Reservation planning would be mere bookkeeping if nothing enforced it. The audit places enforcement at the dispatch claim: missions_claim_dispatch re-reads the mission's revision, membership, grant, contract digest, kill-switch state, and world generation, consumes the matching approval exactly, and reserves budget — atomically. Atomicity is the load-bearing word. The re-reads defeat stale decisions (a grant revoked after planning, a contract amended after approval, a world observation gone stale), and the atomic reserve defeats the double-spend race: two claims against the same remainder are serialized by the database, and the loser is denied rather than overdrawn.

The audit frames this as one half of a broader invariant: the model proposes, the system authorizes. Proposing an action stages it with a server-recomputed digest; claiming it for dispatch re-validates everything against live database state. The TypeScript admission layer is explicitly advisory — it can say no early to save a round trip, but only the database can say yes. Budget planning in allocations.ts sits on the advisory side of that line: it computes remainders and orders slices so callers can construct well-formed claims, but the claim gate is what actually encumbers the funds.

This layering also explains the audit's architectural note that the missions authority consists of the constraint ledger, the budget allocations module, and the SQL claim gates together. The ledger decides what authority exists and how it narrows; the allocations module computes what the money allows and in what order; the claim gates decide, atomically, what actually happens. No single layer is the whole story. The mechanism needs all three, and the audit's verification covered the composition: approval-budget race tests, stale-binding denials, and unconsumed-approval handling all appear in the listed suites.

One honest boundary: this article's inspected sources are the allocations module itself and the audit's description of the claim path. The SQL migrations and dispatch code behind the atomic reserve were not opened for this piece, so the enforcement details above rest on the audit's account, not on direct inspection. That is consistent with the audit's own authority ordering — live code and tests first — and it marks the exact point where a follow-up article with the dispatch sources in hand could go deeper. What is directly verified here is the planning layer: every statement about micros validation, remainder computation, fit checks, and slice ordering traces to the module's fourteen readable functions and interfaces.

What the audit certified — and what it did not

Because budgets only make sense inside the system they fund, the audit's verdicts set the perimeter for every claim in this article. Stage-0 exit passed: the core invariants hold, completion requires evidence, authority never silently expands, unknown effects stay fenced rather than flipping to failed, and the six technical gates re-ran green from the current tree. The verifier track specifically passed on mechanism — separate process, image, role, and queue; deterministic oracles; byte re-hashing; false-green and false-red matrices in the test suites.

The non-scope list is just as important. Live per-connector effect reconcilers do not exist; the reconciler's live lookup throws, honestly retaining the obligation rather than fabricating a result. Human calibration of verification is a deferred baseline requirement. Scheduling, recurring missions, continuous autonomy, and the model-judge calibration dataset are all later-gate items. The audit classifies these as specified-but-not-fully-implemented or planned-only, with exact requirements registered — not as exit blockers, but not as shipped capabilities either.

For verification budgets, the practical consequence is that reservations fund the Stage-0 verifier: evidence re-hashing, coverage and freshness checks, contradiction handling, deterministic oracles. They do not fund live provider lookups or calibrated human review, because those capabilities are not in the Stage-0 contract. A budget line is only as real as the capacity behind it, and the audit is precise about which capacity exists. Any discussion of verification costs that implies live reconciliation or production autonomy would be spending the reservation on work the system cannot yet perform.

There is a broader lesson in how the audit handles this. Each deferred item carries a requirement naming what would close it — a certified sandbox adapter, a model-judge seam, a schedule engine — rather than a vague promise. Budgets work the same way: an amount reserved for a named slice is a commitment to fund that slice, and an unreserved capability is visibly unfunded. Both documents share an ethic of explicitness. The reservation planner omits nothing silently and the audit defers nothing silently, and in both cases the reader can see exactly what is and is not covered.

A worked example (illustrative arithmetic only)

An example helps make the mechanics concrete. What follows uses small illustrative integers purely to exercise the arithmetic — these are not prices, quotes, or measurements of any real mission's cost. Think of them as the budget equivalent of foo and bar.

Suppose a mission has a limit of "1000000" micros, with "200000" already reserved by an earlier authorized step and "100000" spent. The remaining capacity is the limit minus reserved minus spent: "1000000" → "800000" → "700000". A proposed executor amount of "500000" fits, since it is less than or equal to "700000"; a proposed "800000" does not, and the fit check returns false without throwing — rejection of a proposal is routine, not an error. An explicit "0" fits, authorizing a cost-free step through the same path as priced work. And if the state were ever inconsistent — reserved plus spent exceeding the limit — the remainder computation throws instead of reporting a negative balance, surfacing the inconsistency.

Now suppose the next step needs "500000" of executor capacity and "200000" of verifier capacity. The reservation planner returns two slices in order: verifier "200000" first, executor "500000" second. Reserved in that sequence against the "700000" remainder, the verifier's share is secured before the executor's. If instead only "500000" remained, the verifier-first order would fund the "200000" check and leave the executor short — which is the intended policy outcome: the step as priced does not fit, and the shortfall is visible on the execution side rather than silently deducted from verification. Had the order been reversed, the executor would have consumed the remainder and the verifier's reservation would have failed — funding work that could never be checked.

Finally, consider a step with executor amount "300000" and no verifier amount given. The planner returns a single slice: executor "300000". No verifier slice is invented. And a fully free step — executor "0", no verifier amount — returns one slice, executor "0": the authorization is explicit even though the cost is zero. Every plan tells the same kind of story: what is funded, in what order, with nothing implied.

Limitations

Every mechanism in this article carries the limits of its layer. The allocations module computes but does not enforce; a caller that plans slices and never claims them has reserved nothing, and a caller that spends without planning bypasses the ordering policy entirely. Enforcement lives in the atomic claim gate, whose implementation sits outside this article's inspected sources. The fit check is a point-in-time predicate, correct at the moment of computation and stale the moment a concurrent claim lands — which is precisely why the database, not the planner, has the final word.

The verifier-first order is a policy embedded in a pure function, which makes it easy to verify and equally easy to bypass by calling the pieces in a different order. Its strength comes from every legitimate path using the planner — a property of the callers, not of the function. The inspected sources do not enumerate every call site, so this article cannot certify universal use; it can only describe what the planner does when used.

And the largest limitation is scope. Integer-exact reservations for a Stage-0 verifier fund exactly what Stage 0 built: deterministic, evidence-gated checking inside a supervised system. They say nothing about what verification should cost in production, how human review should be priced, or whether any particular mission is worth its budget. Those are economic and product questions. This module answers a narrower, prior question: given a budget and a verification requirement, is the check funded before the work begins? Within its scope, the answer is exact down to the micro.

Reserving the check first

The design compresses to three decisions. Represent money as digit-only micros strings and compute with BigInt, so arithmetic is exact at any scale. Track limit, reserved, and spent as separate figures, so earmarked capacity encumbers the budget as firmly as consumed capacity. And plan verifier slices before executor slices, so the mission funds its own checking before it funds its own acting. Each decision is small; together they make verification budgets a structural property rather than a line-item hope.

The audit's ethic and the module's ethic rhyme: nothing silent, nothing implied. The planner states its order, the arithmetic throws rather than clamps, the audit names its deferrals. For infrastructure that exists to make agent work reviewable, that explicitness is the feature. A budget you can read exactly is a budget you can trust — and a verifier with a reserved share is a verifier that can afford to say no.