Field note / 18 August 2026 / 2026-08-17-loop-economics
One release, eight defects, nine runs
A field report from a single day operating an autonomous delivery loop: what actually broke, what the receipts show, and why every failure was a specimen of the disease the release itself exists to cure.
The release was called loop-economics: five contract-bound slices that make an autonomous delivery loop legible about its own costs. Refusals that name their paths. Continuation exits that name their mechanism. Context that survives a repair. Batched tool calls. A scope lint at recording time.
Delivering it took one day, four plan revisions, nine runs, and produced eight filed defects. Every one of those defects was a live specimen of a disease the release itself exists to cure. This is what that day actually looked like, with the receipts to check it against.
The driver that had never made a live call
The implementer for this release was gemini-3.7-flash through a native
generateContent adapter we had merged the day before. The release that
built that adapter passed independent verification against recorded
fixtures: byte-exact replay of real exchanges, response-path fidelity
proven. Then certification ran the first live call with production tool
schemas, and Google rejected every request with HTTP 400. Every sworn tool
schema pins additionalProperties: false; Google’s schema proto does not
know the keyword and refuses the whole request (#213).
The fixtures could not have caught this. They verified the response path. No fixture exercised the request path against the provider’s validator, because the recorded probe tool did not happen to use the keyword. Certification, a separate verb that makes one real bounded invocation, is the only thing that could have caught it, and it did, on its first run.
The quota that caching does not move
Three consecutive runs then parked at the same implementation dispatch with
PROVIDER_LIMITED. The journal recorded the code and discarded the
provider’s response body, so diagnosis required an instrumented build. The
recovered body named the quota precisely: three million input tokens per
model per minute, and a retry advisory of about ten seconds.
Two things make that lethal to a naive loop. First, every conversation turn re-sends the full growing context, and Google counts cached tokens against the quota. A ninety percent cache hit rate discounts cost and moves the quota wall not one inch. Second, the engine treated the 429 as a dispatch failure and restarted the try from scratch, re-sending the entire context and re-exhausting the very window it had been asked to wait ten seconds for. The restart was the amplifier (#217).
The fix is pacing, not throttling: a configurable statement of the provider’s cap, a sliding-minute ledger of reported input tokens that delays a request only when the window would actually be crossed, and an in-place retry that holds the conversation and honours the provider’s own retry advisory (7dc266c3). After the fix, the dispatch that had killed three runs completed without a single 429.
The wedge we built ourselves
Between those two discoveries, an operator error met an engine invariant and produced something worse than a failure: an unrecoverable run. The journal’s retry model requires a work item’s attempts to match its retry epoch exactly, and requires the current epoch to be exhausted before another retry is accepted. Retry the outer work twice while the inner work sits one epoch behind and the run is permanently wedged; every verb is either rejected or burns another epoch (#216).
The diagnosis took most of an hour because the real error,
STALE_RETRY_EPOCH, was flattened to a generic operational_failure
before it reached the operator. The slice contract sitting unimplemented
in the parked run, S2, is titled “labelled continuation exits.” The loop
was parked on the exact illegibility it was built to remove.
What the verifier is for
When the loop finally ran clean, the independent verifier failed the first candidate. Not spuriously: the implementer had committed a SQLite journal fixture into testdata, and the journal’s read path requires mode 0600 while git materialises files as 0644. The verifier named the defect, named the fix, and noted that everything else held. The implementer consumed the fail receipt, repaired the candidate, and passed on the second attempt.
That exchange, fail with reasons, repair, pass, is the loop working as designed, and it is readable end to end in the receipt chain on the track ref. The verifier and implementer are different models from different vendors, and neither saw the other’s reasoning. The receipts are the only channel between them, which is precisely what makes the verdict worth something.
The ledger
Eight defects filed in one day, each with mechanism and fix direction: schema subset rendering, a records-root divergence, the retry wedge, the quota pacing, the churn accounting, verifier session continuity, and semver-tolerant closure admission. The umbrella issue (#218) totals the operator cost honestly: of four plan revisions, only one changed a byte of contract content. The other three were re-binds forced by head movement, which is the single highest-leverage fix in the backlog.
None of this appears in the pattern-level discourse about agent loops, because none of it is visible until you run one against real providers, real quotas, real CLI version drift, and real git authority, and keep the receipts. That is the point of keeping them.