Code ships faster than
anyone can vouch for it.
Proof audits the code paths where being wrong is expensive, and keeps auditing them as the code changes. Expert-signed, machine-verified: every finding is validated by a named reviewer before it reaches you, and it arrives with a reproducer you can run in your own CI.
Nine layers live in one sentence. Five of them got written down.
Here is a requirement anyone would approve in a planning document. It reads as one small behavior. Cut it open and it's a control system with four layers missing, and each missing layer is a question the tests were never asked.
specimen · one line from a product backlog
Users can cancel their subscription at any time.
unwritten questionWhat happens when a payment is mid-capture?
unwritten questionWhat does the user see when it worked?
unwritten questionBy when does it have to take effect?
unwritten questionWhich charge must never land after this?
The defect lives in the question nobody wrote down.
Five layers made it into the document. The other four became assumptions in the code, where nothing checks them.
nine layers · five stated · four unwritten
# the same requirement with every layer written down contract subscription_cancellation { actor: user(account.authenticated) trigger: cancel_intent(user) guard: ¬payment.processing → defer(effective_at) temporal: effective_at ≤ now + 24h state: subscription.status → cancelled effects: invoices.void(pending); access.revoke(period_end) observes: confirmation.visible(user) prohibits: charge.after(effective_at) idempotent: cancel(cancelled) ≡ cancel }
What the contract turns into
A word and a phrase carry most of the risk. “Can” grants a capability and says nothing about the states where it is withheld. “At any time” is the widest clause in the sentence: it quantifies over every state the system can reach, including the ones nobody enumerated.
The contract is what generates the deliverable. The clauses that assert something the
system must do become obligations, and every obligation is a question a test has to ask out
loud. Here are the seven these clauses produce; actor and trigger
set the precondition rather than adding one.
Each one traces to a clause above. How many a real requirement yields depends on how many states the billing model actually has, which is one of the things an audit finds out.
Why this is the whole thesis
Ambiguity is compressed complexity. The sentence stayed short because nobody counted the behavior it implies, and the compression survives into the code, the tests, and the review that approved both.
Code is only ever as correct as the question it was asked, and a test suite inherits every gap in the question.
What we hand back is the covered version: the contract, the obligations that fall out of it, and one runnable check per obligation.
Four of nine layers missing is the normal state of a requirement that shipped. That's why the first week of an audit goes on recovering intent, before anyone opens the implementation.
Security firms audit whether your software can be broken into.
We audit whether it works.
Logic that drifts from what you promised. Fault tolerance that was never exercised. Regressions that pass review because the tests only ask the questions someone thought to write down. There is a well-worn route for having your perimeter reviewed from outside. There is no equivalent route for having your behavior reviewed, and that is the gap this firm was built into.
keys[depth:][0][0].
The same unsafe assumption survived behind different syntax, on a tree the search had already reported clean. Matching a pattern finds instances. Closing a class needs someone who understands the class.
Set([1,2], "9", "[5]") returned [9]. No panic, valid JSON,
elements gone. Coverage confirmed the branch was reachable and had nothing to say about
which output was correct. We published that as a
postmortem
instead of hardening the tool and saying nothing.
Both findings are on our own open-source library, so you can check every claim against a public repository. The full entry. Severity is our own assessment, weighted by reachability and impact, and it is offered as a starting point for your triage. It is not a CVSS score and not a vendor determination.
The tests agreed with the code. Neither agreed with the intent.
The data-loss defect above is worth opening up, because it's the shape most of what we find takes, and because it happened to us on a library with 123 formal requirements and full MC/DC coverage. Run the autopsy on it and the missing layer is obvious in hindsight.
# before: the question the suite asked assert err == nil assert valid_json(out) PASS # after: the question the obligation asks forall a, i: elements(a) \ {a[i]} ⊆ elements(out) FAIL Set([1,2], "9", "[5]") → [9] lost: 1, 2
Every honest audit method has a floor. Ours is that coverage measures whether logic ran and says nothing about whether the answer was right. We published the gap on our own library rather than waiting for someone else to find it there.
Set([1,2], "9", "[5]"). Write the value 9 at
index 5 of a two-element array.
[9]. No error, no panic, output still parses as JSON, and
both original elements are gone.
Does it return without an error, and is the result valid JSON. Both answers were yes, so the suite stayed green.
The branch was reached and each condition independently affected the outcome. MC/DC settles whether logic was exercised. It has no opinion on which output was correct.
Prohibited outcomes, layer 09. Nobody had written down that elements outside the target index have to survive the write. Returning an error, padding with nulls, or appending would each have been a defensible answer, and discarding the two existing elements was outside all of them. No artifact on the repository said so.
For every array and every index, elements not at the target index are present in the output. That's a property over all inputs, so it gets proven rather than sampled.
Drift accumulates. Tests keep passing.
Drift is the slow separation of what the code does from what everyone agreed it should do. A refactor here, an AI-assisted rewrite there, a hotfix under pressure. Each one green in CI, each one a little further from the intent. Because every requirement is linked to its code and its tests, the divergence surfaces as it happens: change the code and the requirement goes suspect, change the requirement and the stale tests show up.
Six links between a promise and a proof.
Requirements tools, formal methods, coverage tools, and ordinary software development have lived in four separate worlds. We fuse them into one chain where every link is checkable, and a reviewer reads the output of every link before anything is called a finding.
The five validation gates a finding clears, and the declared-limits table.
Plain English in, structured FRETISH out. Three levels, stakeholder down to software, all in git as YAML, and your architects approve the list before any code is judged.
when cancel_intent and ¬payment.processing the billing_service shall always satisfy subscription.status = cancelled
Realizability, pairwise consistency, vacuity, and gap analysis, run with model checkers before a line of code is on trial. NASA's published FRET research reports this class of checker catching a requirements defect that would have allowed a reviewed aircraft specification to permit backwards flight. That's their work rather than ours, and it's why the specification goes first.
$ proof verify ✓ realizable (Kind2) ✓ consistent · 300/300 pairs ! 1 output unconstrained
Two-line annotations carry the trace. They're explicit rather than inferred, so the link is exact, and changing either side marks it suspect until someone looks.
// SYS-REQ-016 func Cancel(...) { ... } // Verifies: SYS-REQ-016 func TestCancel(...) { ... }
Invariants, merge rules and special values proven with the Z3 solver across every input the function accepts. The array-preservation obligation in §3 is exactly this shape.
$ proof properties verify ✓ elements outside the index survive ✓ -1 means unlimited in quota 19/19 proven for all inputs
Every boolean condition shown to independently affect the outcome. Go in production, JS and TypeScript in beta. It answers whether the logic ran, which is a different question from whether the answer was right.
$ proof mcdc measure ./pkg/... decisions 38/42 covered conditions 93.6% hotspot hasAuth (skipped)
Every pass updates the evidence corpus and regenerates the audit-ready SRS and compliance documents. What passed last month has to pass again this month.
$ proof audit ✓ spec · ✓ implement ✓ verify · ✓ document evidence corpus updated
Terminal output on this page is illustrative. The commands and the shape of what they return are real; the figures are not measurements from any one engagement.
What audit firms got right, rebuilt for software that changes daily.
The great security audit firms proved something worth copying: companies will pay for outside experts who go deep and sign the result. Two things about that model don't fit a codebase that ships every day. The report is accurate the day it lands and stale after the next merge. And the subject is almost always security, so nobody outside your own engineering org ever checks whether the logic is right.
We keep the standard and drop the end date. The chain above does the exhaustive part, and the judgment stays with the reviewer who signs the result. The audit reruns on your cadence, per release or weekly, and every pass leaves the evidence corpus stronger than it found it.
Findings frozen at a commit. Two merges later, nobody can say which conclusions still hold.
A queue of unranked alerts that your engineers learn to scroll past. High recall, low signal, and nobody's name on any of it.
Intent formalized, spec proven, chain traced, findings validated with reproducers. Retested on every pass, reusable in every review.
A corpus in your repository, not a report in your inbox.
A point-in-time audit decays the day you merge. Ours leaves durable objects behind, so the next release is checked against everything established before it instead of being read from scratch. Everything the audit produces is a file in git that your engineers own and your CI can rerun. When an enterprise security review asks how you know, you open the corpus and rerun it in front of them.
It fails the build the day the defect tries to come back.
No console to log into, no format only we can read.
If we stop working together, none of it stops working.
your-repo/ proof/requirements/ what the component must do, approved by your architects proof/known-issues/ every finding, with disposition and severity reasoning testsuite/tripwires/ one runnable reproducer per finding evidence/mcdc/ witness rows and coverage, per requirement evidence/formal/ realizability, consistency and property proofs docs/generated-srs.html audit-ready SRS, regenerated on every pass .github/workflows/ the gate, running on your runners
Fixed fee. One component. About four weeks.
Scoped before work starts, so nobody is billing discovery. The first engagement covers one path rather than your whole system: the path customers depend on, auditors question, or releases keep touching. If the shape below doesn't fit what you're trying to buy, you can stop reading here and we'll both keep the hour.
One component or code path, agreed in writing before we start.
Fixed for the defined scope. Quoted after a scoping conversation, never per finding.
About four weeks, from formalizing the intended behavior to a live walkthrough of the findings and the corpus in your repository.
A monthly retainer afterwards, at a cadence you set: per release, weekly, or faster.
Scoped separately and never bundled into an audit. Route every fix to your own engineers if you prefer.
We take a limited number of engagements each quarter. Every finding is validated by a named reviewer before it reaches you, and if a delivered finding fails its own reproducer on the scoped tree, we pull it.
We build the instruments we audit with.
At the centre is Proof, our own audit engine. It holds the requirements model, drives the verification chain, and produces the corpus. It is proprietary and it stays that way. Around it sit instruments we've published, because a tool nobody can run is a claim rather than an instrument.
The engine. Requirements, MC/DC for Go, Kind2 realizability, Z3 property proofs, and one gate over specification, code, tests and documentation.
A code context engine for enterprise-scale repositories. You can't audit behavior you were never able to locate.
Grammar-aware fuzzing that mutates where meaning changes, not at random byte offsets.
Publish the evidence. Keep the engine.
Everything we deliver has to be inspectable without trusting a black box: the methodology, the requirements, the reproducers, the MC/DC and formal artifacts, and the reasoning behind every severity. The engine that makes it repeatable is the part we keep. Assurance is bounded on purpose: within a declared scope, for declared behaviors, with evidence commensurate to the consequence of failure. You can audit our audit, which is the point.
Four boxes to tick before the next release.
If all four are already true on your critical paths, you don't need an outside audit and we'd rather you spent the money elsewhere.
What each critical path must do exists as reviewable requirements, so an engineer who joined last month can find out without asking anyone.
Break the intended behavior and the suite goes red. A suite pinned to whatever the code does today stays green while the intent walks away from it.
When a hotfix or an AI-assisted rewrite lands on a critical path, something flags that the requirement, the tests and the docs no longer agree.
When an enterprise security review asks how you know, there's an evidence packet rather than screenshots and a week of Jira archaeology.
Five seats at the table, one shared problem.
The problem is the same in every seat: the pace of change has outrun the pace of vouching. What differs is which evidence makes the difference.
| Seat | The situation | What the audit changes |
|---|---|---|
| CTO · VP Engineering | Releases ship faster than any reviewer can vouch for, and sign-off runs on memory. | Critical paths get approved requirements, verified links to code and tests, and an outside audit on a cadence you set. Sign-off points at evidence. |
| Founder · CEO | Enterprise deals keep asking how you know the product is correct, and the honest answer available today is that CI is green. | An evidence packet you can take into procurement: what was promised, what was checked, what was found, and how to rerun all of it. |
| Platform · Infrastructure | One defect in routing, auth or billing reaches every customer at once, and the state transitions live in folklore. | Intent recovered and formalized, gap analysis over the inputs the path depends on, and MC/DC where the blast radius justifies it. The next change lands against a written spec. |
| Security · AppSec | AI-assisted changes create more review volume than the reviewers can inspect, and another alert queue makes it worse. | Findings arrive traced to the requirement they violate, with a deterministic reproducer to run before believing any of it. Remediation targets the whole class. |
| Compliance · Sales engineering | Requirements, code, tests and docs each tell a different story, so every customer review turns into a week of reconstruction. | A traceability corpus kept in agreement by the audit cadence, with SRS and compliance documents regenerated on every pass. Reviews become a lookup. |
Open-source maintainers are a sixth case we treat separately: outside review with public-safe findings you disclose on your own terms, plus a spec and a regression corpus that protect every later release. Our own library is where that method was worked out.
Who this is for, and who it isn't.
An audit lands when someone owns the outcome and something has already gone wrong, or is about to. Without that, it becomes a document nobody acts on.
| A fit | Not a fit, and we'll say so |
|---|---|
| Series B or later, with revenue that depends on the component being right. | Pre-Series-B. The budget isn't there and an audit is premature. |
| A named owner for the path we audit, who can approve what it's supposed to do. | Mid-rewrite. Known defects are expected and deliberately deprioritized, so we'd hand you a list you already agreed to ignore. |
| A live trigger: an incident you promised cannot recur, a release that bounced, a security review blocking a deal. | No named owner. Findings land nowhere and nothing changes. |
| Infrastructure or developer tools, where a logic defect reaches customers directly. | You want a scanner, a pentest, or a compliance certificate. Those are all real things, and none of them is this. |
Engineers who would find these defects themselves, given two uninterrupted weeks per release, are the people this works best with. We won't tell you your software is correct, and we'll put that refusal in the contract.
Three documents, no call required.
You'll be asked to justify this internally, probably to a staff engineer who has read a lot of machine-generated bug reports and trusts none of them. Forward these rather than forwarding a scroll position.
The requirement it violates, the runnable reproducer, the triage boundary, the severity reasoning, and the name of the reviewer who validated it. Read the standard.
Every gate we run, in order, plus the declared-limits table: what this catches, what it flags for deeper work, and what it can't see. Read the method.
Where source access goes, retention defaults, running inside your own CI, disclosure handling, and what happens to the corpus if we're not here. Read the answers.
Bring one critical code path.
We'll scope the path, name the evidence worth producing, and say plainly whether a Continuous Correctness Audit is the right thing to buy. If it isn't, you'll leave knowing that too.
The scoping conversation is twenty minutes and produces a fixed quote or an honest no. Bring the sentence in your backlog that worries you most, and we'll run the autopsy on it.
Proof is built by ProbeLabs and led by Leonid
Bugaev, author of GoReplay and
jsonparser, with two decades in API
infrastructure. Dependents of that library include Grafana Loki, Keybase, Coroot, the
Kubernetes CNI plugins, and the official Sentry and Solana Go SDKs, which is a public
go.mod fact rather than a client list.