The Oracle Is the Deliverable
Specs, formal methods, adversarial review and hermeticity are four answers to one question
Table of Contents
Companion to Visibility is Verification (July 2026), which argues that cheap generation makes seeing what the code did the scarce skill and surveys the instruments. This piece takes the next step: given that you can see it, what makes the verdict mean anything — and what happens when the thing being judged starts optimizing against the judge.
1. Thesis: the oracle is the deliverable
An agent is a generator. Generation is now cheap, fast, and — this is the part people still under-weight — getting better in exactly the ways that make it harder to check. Fluent, plausible, idiomatic, and wrong is the failure mode that scales.
Which means the artifact that carries your intent is no longer the code. The code is downstream now, regenerable, nearly free. What is not free is the thing that decides whether a given piece of code is the one you wanted. Call it the oracle, in the testing sense: any mechanism that decides whether an output is correct.
The oracle is the deliverable. Everything else is output.
Two consequences follow immediately, and they are the whole argument:
- An oracle you cannot run is a preference. "We prefer clean architecture" is not an oracle. A failing test is. The discipline is not having opinions about correctness; it is having executable ones.
- An oracle nobody has tried to break is a decoration. A gate that has never been seen to fail is not evidence that the code is right. It is an untested claim about a checker, and untested claims about checkers are where the expensive failures live.
2. Four answers to one question
Specs, formal methods, adversarial review and hermeticity look like four separate enthusiasms — a documentation practice, an academic one, a process one, an infrastructure one. They are not four things. They are four answers to the same question, which is:
What would make this claim false, and can I run that?
2.1. Specification — the oracle you can write first
You cannot verify against intent you never wrote down. That is the entire case for spec-driven work, and it is not about documentation.
What makes a spec an oracle rather than an essay is that it states anti-goals alongside goals, in the same artifact. A goal without its anti-goal is unfalsifiable: everything is consistent with "make it fast." The anti-goal names the default thing a competent agent would build — the shape most solutions in this space take — and states the mechanical failure mode, not the aesthetic one. Not "microservices are bad" but "this splits a transaction across two services that have no shared commit, so a partial failure leaves the ledger wrong and nothing will tell you."
The corollary that costs people the most: a stage is contract-complete only when each goal has a passing test and each anti-goal has a failing test that exercises the forbidden path. Most repositories have the first half. The second half is what makes a stated discipline real rather than decorative.
2.2. Formal methods — the oracle that does not sample
Tests sample. A property-based test samples better, and a good generator samples the interesting shapes, but it still samples. Sometimes you can do better: state the invariant and check it over the whole space.
The honest scope is narrower than enthusiasts claim and much wider than skeptics allow. Model checkers earn their keep on concurrency, protocol, and state-machine questions — the places where the bug is an interleaving nobody would think to write a test for. Proof assistants earn theirs where a small, load-bearing core can be stated exactly.
The rule that keeps this from becoming a research project: apply it to the deterministic core, the part where the same input gives the same bits. In a system with a stochastic component, that core is smaller than the system and sharper than the system, and it is where a formal argument buys anything. Above it, relations — not proofs.
2.3. Adversarial review — the oracle you do not have
Most interesting claims have no oracle. You cannot say whether this generated answer is right, whether this refactor preserved intent, whether this architecture will hold. The literature has better answers here than folklore does.
- Metamorphic testing (Chen, Cheung & Yiu 1998): when you cannot decide whether one output is correct, assert relations between outputs. Idempotence, symmetry, invariance under a change that should not matter. This is the named technique for the no-oracle case, and it is badly under-used — most teams have written metamorphic relations by accident and never noticed they had a name.
- Mutation testing (DeMillo, Lipton & Sayward 1978; ancestor: Mills's error seeding, 1972): introduce a fault deliberately, check whether the tests notice. This is the only cheap way to distinguish a test suite from a ceremony.
- N-version disagreement (Avizienis & Chen 1977) — with the caveat that makes it honest. Knight & Leveson (1986) showed independently written versions fail in statistically correlated ways, because authors share intuitions and misread the same ambiguous clause identically. Agreement between two implementations is weaker evidence than it feels, and weakest where the authors shared context. In 2026 that finding reads as a warning about ensembles of agents sharing a base model: three agents that agree may be one agent with three prompts.
The agentic form of all this is a panel with distinct lenses rather than N identical reviewers. Redundancy catches noise; diversity catches failure modes. A reviewer told to refute, with a stated default of "refuted if uncertain," is worth more than three told to check.
2.4. Hermeticity — the condition, not a practice
A hermetic check runs sealed: no ambient configuration, no installed packages it did not declare, no network unless declared. Same inputs, same verdict, on any machine.
This is not a fourth technique so much as the condition under which the other three mean anything. A spec checked against ambient state proves nothing about another machine. A proof about a system you cannot reproduce is a proof about a system you no longer have. An adversarial panel whose disagreement turns out to be a version skew has told you nothing.
It also cuts both ways, and the second edge is less obvious: a sealed gate cannot see affordances that exist only at runtime. Something valid in production can be unknown to the checker. The discipline is to inject runtime-only facts at execution time, not to smuggle them into the place the sealed checker reads — and to say plainly which side of the line each claim lives on.
3. The turn: when the generator optimizes against the oracle
Here is what changes in an agentic loop, and it is the reason "we have tests" is no longer a sufficient answer.
In classical development the test suite is a passive observer. Nobody is trying to satisfy it dishonestly, because the author and the checker are the same person and that person wants working software.
Put an optimizer in the loop and the checker stops being an observer. It becomes the objective. Every looseness in it is now a target. This is Goodhart (1975) in its sharpest form, and it is not hypothetical: it is the standard failure mode of reinforcement learning from a verifier, where the model learns to satisfy the reward's form rather than its intent (Amodei et al. 2016; Krakovna et al. 2020).
The concrete shape is worth stating because it is so easy to miss on a dashboard. Give a policy a reward with two terms — correctness and format — and log only the sum. A policy that stops solving problems and starts farming the format term produces a rising curve. The metric improves while the system gets worse. No amount of checking the arithmetic finds it; only decomposing the metric does.
Three practical consequences:
- Log every term separately, never only the aggregate. A combined score cannot distinguish "getting better" from "learning to game the proxy," and those are exactly the two hypotheses you need to separate.
- A verifier's quality is two numbers. A false-negative rate and a false-positive rate. Neither is visible from accuracy on a benign set. False negatives teach the generator to produce checker-shaped output rather than correct output; false positives inflate everything downstream.
- Run a positive control on the objective itself. Hand-write output engineered to score well while being wrong, and assert that it is not rewarded. This is the mutation-testing move applied to the reward rather than to the code, and it costs a fixture instead of a training run.
4. Six failures that paid for this
None of these are hypothetical, and none were caught by reasoning. Each was caught by running something.
A gate that reported PASS for zero work. A checker counted source blocks with
grep -c '^#\+begin_src'. That pattern is a basic regexp, where \+ means "one
or more #" — so it matched nothing, found zero blocks, and reported PASS. A
gate that counts zero items and passes is worse than no gate, because it
occupies the slot where a real one would go.
A mutation that never applied. While mutation-testing a suite, the substitution silently failed to match, and the guard checked a string present in both the original and the "mutant." The run reported 11/11 — a green result for a defect never inserted. The literature has a name for this: a stillborn mutant. The rule it forces is: assert the plant took before you trust the run.
An accuracy number that could not fail. A cross-precision comparator was chased through an exemption list and turned out to have never compared a single scalar. Everything it had ever "verified" was unexamined. It was found by a guard on the guard: a test asserting that every entry in a suppression list would fail without its suppression.
A rebuild that reprocessed half its inputs every run. Content was stable,
timestamps were stable, no output appeared, and every cheap check said the
pipeline was idempotent. Asking make -q — what the tool believes, rather
than what it printed — exposed it immediately. Generalization: query the
system's own state, do not infer it from output.
A screenshot of the wrong window. Asked to capture a UI, the capture targeted a screen region rather than the window, and the frontmost window was a terminal holding unrelated work. It was caught only because someone looked at the image before sending it. Automation that produces an artifact you do not inspect has not verified anything; it has produced an artifact.
A parser that answered a question it had not been asked. A math grader
compared a model's answer against ground truth via a symbolic algebra library.
Fed −3 — with U+2212, the character a model produces when it copies rendered
mathematics rather than LaTeX source — the library did not fail. It parsed the
minus sign as an identifier and returned the expression 3·−: a product with
a free variable named "−". That compared unequal to -3, so a correct answer
was graded wrong, and nothing raised.
A metamorphic relation caught it: every spelling of one answer must compare equal to every other. No example-based test could have, because every one of them compares two strings someone had already thought about.
The instructive part came next. The obvious fix maps U+2212 to a hyphen. A sweep of ten Unicode blocks asked how many other characters the parser turns into a variable rather than rejecting: 1,137, and zero rejections. The character was never the bug. The bug was a parser whose contract is "accept almost anything as an identifier" placed where the contract is "tell me whether this is a number" — and the fix that generalizes is not a larger allowlist but a guard on the symptom of misreading: a symbol whose name is not ASCII was never a variable in the source.
Three states — equal, unequal, and unreadable — collapsed into two. The score still moves. Nobody sees an error.
The pattern across all six: the expensive failure is not a wrong answer, it is a plausible one where an error should have been. Silent wrongness lives in the state you cannot see, which is why the companion piece on visibility is the other half of this argument.
5. Why this strengthens as the models improve
The usual objection is that this is transitional — that better models will make the scaffolding unnecessary.
Apply the degradation test: which claims survive an order-of-magnitude improvement in the generator?
Nearly every claim about prompting dies. Claims about verification get stronger, and the reason is structural rather than sentimental. A better generator is a better optimizer against whatever objective it is given. If the objective is your gates, a stronger model finds the looseness in them faster, more completely, and more plausibly than a weaker one. The gap between "passes the gate" and "is correct" is not narrowed by capability; it is exploited by it.
Same for the volume argument. When one person can produce ten times the code, the review bottleneck does not scale by hiring; it scales by making correctness mechanically checkable. Every hour spent making a claim executable pays out every time an agent regenerates the thing that claim is about.
The one-line version: cheap generation makes verification the scarce discipline, and capable generation makes it the adversarial one.
6. What it costs, and where it does not apply
A philosophy you cannot argue against is not a philosophy. The honest limits:
- Hermetic gates are blind to runtime. Sealing the environment out means the gate cannot see a GPU, a checkpoint, a live dependency. Draw the line deliberately and say which side each claim lives on.
- Formal methods pay off on a narrow core. Applied to an entire application they become a research project that ships nothing. Applied to a protocol, a state machine, or a load-bearing invariant they are the cheapest confidence available.
- Adversarial panels have correlated failure. Knight & Leveson applies with more force to agents sharing a base model than it did to human teams. Diverse lenses, not more voices.
- Anti-goals go stale. An anti-goal naming a specific product will outlive the product. They need a review trigger, or they become folklore with a citation.
- Abstraction has a floor. Do not extract a reusable methodology from two instances. Three, with a repeating structure that is non-obvious, or do the concrete thing again. Most of the cost of "methodology" is paid by people who abstracted at two.
And the sequencing that follows from all of it: build the oracle first. Not because it is virtuous, but because in a loop where generation is free, the oracle is the only thing whose absence you will not notice until it is expensive.
7. The artifacts
Concrete shapes these take in practice, offered as evidence rather than as a product:
| artifact | what it carries |
|---|---|
spec.org |
goals and anti-goals, build order with acceptance tests, the axiom that survives compression |
CLAUDE.md |
the conventions an agent loads every session; the spec is read on demand |
| two orthogonal gates | a documents gate and a code gate; neither substitutes for the other; a gate is a tripwire, not a promotion mechanism |
.meta/ |
portable findings written for the next repo, during the work rather than after |
| a shared nomenclature | borrowed terms cite the literature and inherit its limitations; local terms mean only what is written down |
| conjecture tracking | falsifiable claims with the measurement that would refute them, not prose wishes |
| planted defects | negative tests proving each gate can fail, with the plant asserted before the run |
The nomenclature deserves a note, because it is the cheapest of these and the most skipped. Three vocabularies overlap in any serious project — the domain's, the method's, and the machinery's — and most confusion in a review is two people using one word for different things. Splitting borrowed from local terms is most of the fix: a borrowed term carries its citation and its known limitations; a local term means only what you wrote down, and nothing more.
8. Sources
- Avizienis, A. & Chen, L. (1977). On the implementation of N-version programming for software fault tolerance during execution.
- Knight, J. C. & Leveson, N. G. (1986). An experimental evaluation of the assumption of independence in multiversion programming.
- Mills, H. D. (1972). On the statistical validation of computer programs. (Error seeding / "bebugging".)
- DeMillo, R., Lipton, R. & Sayward, F. (1978). Hints on test data selection: help for the practicing programmer.
- Chen, T. Y., Cheung, S. C. & Yiu, S. M. (1998). Metamorphic testing: a new approach for generating next test cases.
- Claessen, K. & Hughes, J. (2000). QuickCheck: a lightweight tool for random testing of Haskell programs.
- Weyuker, E. (1982). On testing non-testable programs. (The oracle problem.)
- Goodhart, C. (1975). Problems of monetary management: the UK experience.
- Amodei, D. et al. (2016). Concrete problems in AI safety.
- Krakovna, V. et al. (2020). Specification gaming: the flip side of AI ingenuity.
- Lakatos, I. (1976). Proofs and Refutations.
- Dolstra, E. (2006). The Purely Functional Software Deployment Model. (Nix; a build as a pure function of its inputs.)