REQPROOF // CONTINUOUS CORRECTNESS AUDIT
SCANNING · SIX LANES IN PARALLEL
FIG. 0 · BEHAVIORS UNDER CONTINUOUS SCAN
reqproof
reqproof · an audit firm for software correctness

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.

EVERY RELEASE RE-CHECKED REQUIREMENTS FROM INTENT REPRODUCER WITH EVERY FINDING
see §3 · the layer that escaped on our own library
§1 The requirement autopsy

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.

fig. 1 · requirement autopsy

specimen · one line from a product backlog

Users can cancel their subscription at any time.

01 Actor Users
02 Permission can
03 Trigger cancel
04 System state their subscription
05 Temporal scope at any time.
06 Exceptions not stated

unwritten questionWhat happens when a payment is mid-capture?

07 Observable result not stated

unwritten questionWhat does the user see when it worked?

08 Completion deadline not stated

unwritten questionBy when does it have to take effect?

09 Prohibited outcomes not stated

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

contract · subscription.cancellation verified
# 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
}

fig. 1 · one line from a product backlog, dissected into nine layers, then restated as a formal obligation. The dissection animates where the browser allows it, and every layer, question and clause is listed here either way.

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.

  • Cancellation requested while a payment is mid-capture: rejected or deferred, and the user is told which.
  • Cancellation succeeds: status reads cancelled on the next read, and the user gets a confirmation they can point at later.
  • No charge lands against the subscription after the cancellation is effective. This one is a prohibition, so it needs a test that tries.
  • Effective within 24 hours, which means a test that passes at 23 hours and fails at 24 hours and a minute.
  • A second cancellation on an already-cancelled subscription returns the same answer and voids nothing twice.
  • Access survives to the end of the paid period, and revocation fires there rather than at the moment of the request.
  • Pending invoices are voided. Invoices already paid are left alone, because a refund nobody asked for is its own incident.

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.

§2 What kind of audit this is

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.

jsonparser · eight panic sites
A pattern sweep found seven. Review found an eighth, written as 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.

jsonparser · where our own method fell short
We reached 100% MC/DC. A data-loss defect escaped anyway.

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.

§3 A worked example

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.

The call

Set([1,2], "9", "[5]"). Write the value 9 at index 5 of a two-element array.

What came back

[9]. No error, no panic, output still parses as JSON, and both original elements are gone.

What the tests asked

Does it return without an error, and is the result valid JSON. Both answers were yes, so the suite stayed green.

What coverage said

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.

The missing layer

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.

The obligation now

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.

§4 How correct systems go wrong

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.

fig · two lines that agree, then separate
intent: what was promised implementation: what actually ships v2.1 refactor AI-assisted rewrite hotfix under pressure suspect links caught · drift repaid the suite was green the whole way ✓
fig. 2 · spec-to-code drift on one critical path, across a single release cycle the gap is the audit surface
see §7 · what the chain leaves in your repository
§5 The verification chain

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.

fig · intent threads crossing implementation threads

The five validation gates a finding clears, and the declared-limits table.

link 1 · formalize
Intent becomes a requirement

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
link 2 · prove the spec
The specification gets verified first

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
link 3 · trace
Requirement, code and test, linked both ways

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(...) { ... }
link 4 · prove the data
Properties hold for every input

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
link 5 · cover
MC/DC closes the loop on logic

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)
link 6 · gate
One gate over spec, code, tests and docs

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.

§6 The audit model

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.

point-in-time audit
One engagement, one report

Findings frozen at a commit. Two merges later, nobody can say which conclusions still hold.

scanner subscription
Volume without judgment

A queue of unranked alerts that your engineers learn to scroll past. High recall, low signal, and nobody's name on any of it.

continuous correctness audit
Expert judgment that reruns

Intent formalized, spec proven, chain traced, findings validated with reproducers. Retested on every pass, reusable in every review.

§7 What you keep

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.

fig · one pass of the gate, check by check, one flagged amber
durable
Every fixed finding becomes a regression test.

It fails the build the day the defect tries to come back.

portable
Plain files, in your git history.

No console to log into, no format only we can read.

independent
The gate runs without us.

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
§8 The engagement shape

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.

Scope

One component or code path, agreed in writing before we start.

Fee

Fixed for the defined scope. Quoted after a scoping conversation, never per finding.

Baseline

About four weeks, from formalizing the intended behavior to a live walkthrough of the findings and the corpus in your repository.

Continuous

A monthly retainer afterwards, at a cadence you set: per release, weekly, or faster.

Fix work

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.

see /tools · what the instruments don't do
§9 The instruments and the boundary

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.

proprietary
Proof

The engine. Requirements, MC/DC for Go, Kind2 realizability, Z3 property proofs, and one gate over specification, code, tests and documentation.

public
probe

A code context engine for enterprise-scale repositories. You can't audit behavior you were never able to locate.

public
json-fuzz · graphql-fuzz

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.

How the instruments work, and what they don't do.

§10 The honest questions

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.

question 01
The intent is written down.

What each critical path must do exists as reviewable requirements, so an engineer who joined last month can find out without asking anyone.

question 02
Tests hold the code to that intent.

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.

question 03
Drift shows up before customers do.

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.

question 04
Buyers get evidence they can open.

When an enterprise security review asks how you know, there's an evidence packet rather than screenshots and a week of Jira archaeology.

§11 Who hires an audit firm for this

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.

§12 Fit

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 fitNot 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.

§13 Check the work first

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.

findings
What a finding contains

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.

method
The method and its limits

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.

review
Answers for your reviewers

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.

§ Q.E.D. · Start

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.