Machine-Verifiable Contracts: The Missing Layer Between a Prompt and Production Code
The LLM wrote a pagination function that returned the correct page of results in every test you ran. It also silently dropped the total count field from the response envelope, and three downstream consumers broke in production two days later.
That gap, between what the model produced and what you actually asked for, is the missing layer in most AI coding pipelines today. Prompt engineering and output linting do not close it. What closes it is a machine-verifiable contract sitting between the prompt and the merge.
Why Diff Review Is Not Enough
Code review catches bugs when the reviewer knows what the code was supposed to do. With AI-generated code, reviewers are often reading a diff without the original intent encoded anywhere formal. They check style, they check logic, they sometimes check edge cases. What they rarely check systematically is whether the generated code satisfies every constraint that was in the original prompt, because that constraint set lives nowhere except in the prompt string or in someone's head.
This is structurally different from the usual code review problem. When a human writes code, the intent is often inferable from the design doc, the ticket, or the surrounding architecture. When an LLM writes code, the intent is a natural-language prompt that gets consumed and discarded. The output arrives orphaned from its specification.
Better prompts produce better first drafts. They do not produce a verifiable audit trail. What you need is a formal specification layer that captures the constraints the generated code must satisfy, in a form a machine can evaluate.
What a Machine-Verifiable Contract Actually Looks Like
A contract in this context is not a unit test, though tests can be part of it. A unit test checks one specific input-output pair. A contract makes a claim about a class of behaviors. The distinction matters at scale.
Concretely, a contract for that pagination function would state:
- The response envelope must include
items,page,page_size, andtotal_count. itemsmust never contain more entries thanpage_size.total_countmust reflect the unfiltered result set, not the current page.- If
pageexceeds the last valid page,itemsmust be empty andtotal_countmust still be accurate.
Those four rules are not a test. They are a specification that any valid implementation must satisfy. You can write tests that exercise each rule, but the rules themselves exist at a higher level of abstraction.
Formal specifications have a long history in systems programming. TLA+ and Alloy have been used for decades to verify distributed protocol correctness. What is new is applying that same discipline, in lighter-weight, engineer-friendly forms, to the output of generative models.
The lightest viable form is property-based assertions attached to the change itself: structured claims that describe invariants, required fields, prohibited behaviors, and performance envelopes, all expressed in a format a CI system can evaluate. ThunderLang calls these verify-diff contracts and they live in the repository alongside the code, not in a Notion doc or a Slack thread.
The Three-Layer Verification Stack
If you are building this from scratch, here is the stack that holds up under production load.
Layer 1: Structural contracts. These check that the shape of the output matches the shape that was specified. For an HTTP endpoint, that means response schema validation against an OpenAPI spec. For a database access layer, that means column-level contracts on what gets read and what gets written. Tools like ajv for JSON Schema or zod for TypeScript give you this in about ten minutes. This layer runs in under 50 milliseconds and catches the class of bug the pagination example hit.
Layer 2: Behavioral contracts. These are property-based tests, not example-based tests. Instead of asserting that paginate(items, page=1, size=10) returns the first ten items, you assert that for any valid input, the length of items in the response never exceeds page_size. Frameworks like fast-check in TypeScript and hypothesis in Python automate the input generation. This layer runs in seconds and catches logic errors that pass all handwritten tests.
Layer 3: Provenance contracts. These record what specification the code was generated against, what verification it passed, and when. Without it, you can verify today's code but you cannot answer, six months from now, why a particular constraint was in scope or what changed. A durable artifact, a signed JSON blob, a commit-attached attestation, anything append-only and tamper-evident, is sufficient. This layer has near-zero runtime cost and it is the layer most teams skip entirely.
Skipping layer three is the mistake that makes the other two layers fragile over time.
Wiring This Into Your AI Coding Pipeline
The operational question is where these checks live in the workflow. The answer is: as early as possible, which means before the diff reaches a human reviewer.
Here is the sequence that works:
Engineer writes the specification before invoking the model. Not after. The spec is the prompt's machine-readable twin. If you cannot write the spec before you generate the code, you do not actually know what you want yet.
Model generates code. This step is unchanged. Use Anthropic Claude, OpenAI GPT-4o, or whatever model your team has settled on. The model does not know the spec exists; it does not need to.
CI runs the contract suite against the generated diff before any human sees it. Layer 1 and Layer 2 checks run here. A failed contract blocks the PR. A passed contract attaches a verification badge to the PR, along with the layer 3 provenance artifact.
Human review happens after machine verification, not instead of it. Reviewers focus on architecture, naming, and edge cases the contract did not cover. They are not re-reading the spec to see if the code honors it. The machine already did that.
The key discipline is step one. Teams that try to retrofit specs onto already-generated code get weaker contracts because the spec is unconsciously shaped by what the code already does. Write the spec cold, before you see the output.
One practical number: in a medium-complexity microservice, writing a full behavioral contract takes roughly the same time as writing the tests you would have written anyway, about 45 to 90 minutes. The difference is that a contract is reusable across every future change to that interface, while a test suite tends to accrete debt and false confidence in parallel.
The ThunderLang getting-started guide walks through attaching contracts to a real diff, including how to structure provenance artifacts so they survive a repository migration or a CI platform change.
The Objection You Will Hear
Someone on your team will say that this is too much ceremony for the speed advantage AI coding is supposed to deliver.
That objection treats verification as overhead rather than as the thing that makes speed safe. A change that breaks two downstream consumers and requires two days of incident response is not fast. It is fast at the wrong unit of measurement.
The contract layer also gets cheaper as the codebase matures. Once you have contracts for your core interfaces, new AI-generated changes to those interfaces get verified for free. The marginal cost of verification approaches zero. The marginal cost of skipping verification stays constant, because production never discounts bugs.
Teams that have shipped this in practice, including several using ThunderLang's verify-diff workflow, report that the contract layer catches between 60 and 80 percent of specification drift before it reaches review. That number matters because specification drift is exactly the failure mode that human reviewers are worst at catching: they see correct-looking code and trust it.
Gate your first AI change
ThunderLang lets you declare what a change must satisfy, then gates AI-written code against that intent with a verify-diff and durable proof artifacts. The fastest path to seeing this on a real codebase is the getting-started guide, which covers structural and behavioral contracts in under an hour.
The verification layer is not a gate on AI coding. It is the thing that makes AI coding a credible engineering practice instead of a productivity gamble.