Executable guarantees: make proof
Architectural claims are executable here, not merely documented. make proof runs the tests
that back each guarantee in proofs.toml
and prints one verdict per guarantee:
ARCHITECTURE PROOF
Dependency rule PASS ADR-001, ADR-006
Feature isolation PASS ADR-001
Repository contract PASS ADR-008
Optimistic concurrency PASS ADR-010
Transaction boundary PASS ADR-004
Events after commit PASS ADR-005
Authorization in the application ring PASS ADR-009
HTTP error contract PASS no ADR
Example removal PASS ADR-001
9/9 executable guarantees passed in 17.5s
Exit code 0 only when every guarantee is PASS; 1 when one is FAIL, SKIPPED or
NO EVIDENCE; 2 when the registry itself is inconsistent.
How it is wired
Three moving parts, no duplication:
proofs.tomlis the registry: a stable id, a human title, the one-sentence claim, and the ADRs that made the decision.- Evidence is ordinary tests carrying
@pytest.mark.proof("<id>"). The runner deselects everything else, somake prooftakes ~20 s. - Traceability is checked by
tests/template/proofs/test_registry.py(and again by the runner before it starts): every ADR either citesproof:<id>lines or statesNo executable proof: <reason>; every id cited anywhere must exist; every registered id must appear in the README table; an ADR listed for a proof must cite it back.
Falsifiable, on purpose
tests/template/proofs/test_proof_system.py proves the prover:
- a mapping broken in any direction is reported (unknown id in an ADR, in a test, in the README; ADR without a proof statement; non-reciprocated reference);
- a guarantee nothing ran for is
NO EVIDENCE, neverPASS; one failing or skipped test taints the whole guarantee; - on a temporary copy of the repository, a smuggled import from
domainintoinfrastructureturnsDependency rulered with exit code1, and the report names the module.
Adding a guarantee
- Write the test that would fail if the property were false.
- Mark it
@pytest.mark.proof("my-guarantee"). - Add
[my-guarantee]toproofs.tomlwithtitle,claimandadr. - Add
- proof:my-guaranteeto the## Proofsection of each ADR you listed. - Add a row to the README table.
make proof (and CI) will tell you if you skipped a step.
In your project
make proof, proofs.toml and the ADR/README traceability are the template's way of
proving its own claims; scripts/init_project.py removes them. What you keep is what has
durable value: the dependency rule as a tool in make check and CI, and tests for the
mechanisms you inherit (tests/http, tests/bootstrap). Your guarantees are your tests -
the template does not impose a registry, a marker or a documentation contract on you.
What it does not claim
It does not prove that the architecture is correct, complete or right for your problem, and it does not cover the code you will write. Decisions with no runtime property (no DI library, no mediator, the stack, where validation lives) say so in their ADR.