Proof-driven development
Prove properties from requirements before writing code. Proofs guide implementation, not the reverse. Zero unproven properties in final code.
Modern insight (2025): PBT + example tests pairing is the standard -- properties discover edge cases, example tests prevent regressions and serve as documentation. Counterexamples from shrinking should always become permanent regression tests. AI-assisted PBT (Anthropic 2025) can generate properties from docstrings, but human judgment for property selection remains essential.
See frameworks for language-specific PBT and stateful testing tools.
See examples for brief property test patterns per language.
See formal-tools for theorem provers and bounded model checkers.
Property Categories
| Category |
Description |
Example |
| Postcondition |
Output satisfies contract |
sorted(sort(xs)) |
| Invariant |
Property preserved by operation |
len(xs) == len(sort(xs)) |
| Idempotence |
f(f(x)) == f(x) |
deduplicate(deduplicate(xs)) |
| Inverse / Round-trip |
g(f(x)) == x |
decode(encode(x)) == x |
| Model-based |
Implementation matches reference |
my_sort(xs) == stdlib_sort(xs) |
| Commutativity |
Order doesn't matter |
a + b == b + a |
| Metamorphic |
Relationship between outputs |
sin(-x) == -sin(x) |
Most effective (OOPSLA 2025): Model-based properties (80% bug detection), postconditions (65%). Least effective: properties that reimplement the logic under test.
Anti-pattern: Don't reimplement the function in the property. Properties should be simpler than the code they test.
When to Apply
- Critical algorithms (sort, search, crypto, compression)
- Financial calculations (rounding, currency conversion)
- Consensus/distributed protocols (invariants across nodes)
- Safety-critical systems (medical, automotive, aerospace)
- Data structure invariants (balanced tree, heap property)
- Serialization round-trip (encode/decode fidelity)
- Stateful systems (databases, queues, caches) -- via stateful PBT
When NOT to Apply
- UI rendering, visual layout
- Simple CRUD endpoints
- Configuration management
- Non-critical utility code
- Rapidly changing requirements (properties are expensive to maintain)
Anti-patterns
- Happy-path-only properties: Properties must cover edge cases -- that's their primary value
- Skipping stateful testing for stateful systems: Use model-based stateful PBT (Hypothesis RuleBasedStateMachine, jqwik stateful)
- Ignoring counterexamples: Shrunk counterexamples are gold -- always convert to permanent regression tests
- Properties that test the framework:
assert fast_check works is not assert my_code works
- Permanently skipped/pending properties: Zero-skip policy -- skip = unfinished work
- Conflating PBT with unit testing: PBT explores input space; unit tests verify known examples. Use both.
- Not using shrinking: If counterexample is 500-line input, it's useless. Shrinking finds minimal failing case.
- Reimplementing logic in properties: Property should be simpler than the code. If property is as complex as implementation, it adds no confidence.
Shrinking
Shrinking transforms a failing complex input into the minimal input that still fails. This is the most valuable feature of PBT frameworks.
- Integrated shrinking (Hypothesis, Hedgehog): Generates shrink tree during generation. Preserves generator invariants. Superior approach.
- Type-based shrinking (QuickCheck): Separate shrinker functions. Can violate generator constraints.
- Always investigate shrunk counterexamples: They reveal the essential failure, stripped of noise.
PBT vs Fuzzing (decision guidance)
| Aspect |
PBT |
Fuzzing |
| Input generation |
Guided by properties |
Guided by code coverage |
| Oracle |
User-written property assertions |
Crashes/exceptions/timeouts |
| Best for |
Correctness, algorithms, contracts |
Security, memory safety, crash detection |
| Convergence (2025) |
Hybrid tools (Bolero, Antithesis) combine both approaches |
|
Proof Strategies
- Simplification: Reduce by known rules, use shrinking to find minimal counterexamples
- Arithmetic: Generate numeric edge cases (0, 1, MAX, negative, overflow boundaries)
- Case analysis: Split on constructors/variants, test each branch independently
- Induction: Recursive/sequential properties via stateful testing
- Fuzzing: Empirical exploration when properties are hard to specify formally
- Metamorphic relations: When oracle is unknown, test relationships between outputs
Theorem Hierarchy
Main Property (Goal)
|-- Supporting Property 1
| +-- Helper Property 1a
|-- Supporting Property 2
+-- Edge Case Property 3
Workflow (language-neutral)
- PLAN -- Identify correctness, safety, invariant, and termination properties. Design hierarchy. Choose property categories.
- CREATE -- Write property test files. One property per concern. Tag by category (postcondition, invariant, inverse, etc.).
- VERIFY -- Run all properties. Count unproven (skipped/pending). Analyze counterexamples via shrinking.
- REMEDIATE -- Fill in each skipped property using proof strategies. Convert every counterexample to a permanent regression test.
Constitutional Rules (Non-Negotiable)
- CREATE First: Generate all property test artifacts from plan design before verification
- Complete All Proofs: Zero skipped/pending properties in final code
- Totality Required: All definitions must terminate
- Target Mirrors Model: Implementation structure corresponds to proven model
- Iterative Remediation: Fix proof failures, don't abandon verification
Validation Gates
| Gate |
Pass Criteria |
Blocking |
| Framework |
PBT framework available and configured |
Yes |
| Properties |
All property tests pass |
Yes |
| Unproven |
Zero skipped/pending properties |
Yes |
| Coverage |
>= 80% line coverage |
If present |
Exit Codes
| Code |
Meaning |
| 0 |
All properties pass, zero unproven/skipped |
| 11 |
Property testing framework not available |
| 12 |
No property tests created |
| 13 |
Property tests failed or proofs incomplete |
| 14 |
Coverage gaps (properties missing) |
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: proof-driven3description: Proof-driven development - design proofs from requirements, then execute CREATE -> VERIFY -> REMEDIATE cycle. Use when implementing with formal verification using property-based testing, theorem proving, or proof tactics; zero unproven property policy enforced. Use when this capability is needed.4---56# Proof-driven development78Prove properties from requirements before writing code. Proofs guide implementation, not the reverse. Zero unproven properties in final code.910**Modern insight (2025)**: PBT + example tests pairing is the standard -- properties discover edge cases, example tests prevent regressions and serve as documentation. Counterexamples from shrinking should always become permanent regression tests. AI-assisted PBT (Anthropic 2025) can generate properties from docstrings, but human judgment for property selection remains essential.1112See [frameworks](references/frameworks.md) for language-specific PBT and stateful testing tools.13See [examples](references/examples.md) for brief property test patterns per language.14See [formal-tools](references/formal-tools.md) for theorem provers and bounded model checkers.1516---1718## Property Categories1920| Category | Description | Example |21|----------|-------------|---------|22| **Postcondition** | Output satisfies contract | `sorted(sort(xs))` |23| **Invariant** | Property preserved by operation | `len(xs) == len(sort(xs))` |24| **Idempotence** | `f(f(x)) == f(x)` | `deduplicate(deduplicate(xs))` |25| **Inverse / Round-trip** | `g(f(x)) == x` | `decode(encode(x)) == x` |26| **Model-based** | Implementation matches reference | `my_sort(xs) == stdlib_sort(xs)` |27| **Commutativity** | Order doesn't matter | `a + b == b + a` |28| **Metamorphic** | Relationship between outputs | `sin(-x) == -sin(x)` |2930**Most effective** (OOPSLA 2025): Model-based properties (~80% bug detection), postconditions (~65%). Least effective: properties that reimplement the logic under test.3132**Anti-pattern**: Don't reimplement the function in the property. Properties should be *simpler* than the code they test.3334---3536## When to Apply3738- Critical algorithms (sort, search, crypto, compression)39- Financial calculations (rounding, currency conversion)40- Consensus/distributed protocols (invariants across nodes)41- Safety-critical systems (medical, automotive, aerospace)42- Data structure invariants (balanced tree, heap property)43- Serialization round-trip (encode/decode fidelity)44- Stateful systems (databases, queues, caches) -- via stateful PBT4546## When NOT to Apply4748- UI rendering, visual layout49- Simple CRUD endpoints50- Configuration management51- Non-critical utility code52- Rapidly changing requirements (properties are expensive to maintain)5354---5556## Anti-patterns5758- **Happy-path-only properties**: Properties must cover edge cases -- that's their primary value59- **Skipping stateful testing for stateful systems**: Use model-based stateful PBT (Hypothesis RuleBasedStateMachine, jqwik stateful)60- **Ignoring counterexamples**: Shrunk counterexamples are gold -- always convert to permanent regression tests61- **Properties that test the framework**: `assert fast_check works` is not `assert my_code works`62- **Permanently skipped/pending properties**: Zero-skip policy -- skip = unfinished work63- **Conflating PBT with unit testing**: PBT explores input space; unit tests verify known examples. Use both.64- **Not using shrinking**: If counterexample is 500-line input, it's useless. Shrinking finds minimal failing case.65- **Reimplementing logic in properties**: Property should be simpler than the code. If property is as complex as implementation, it adds no confidence.6667---6869## Shrinking7071Shrinking transforms a failing complex input into the minimal input that still fails. This is the most valuable feature of PBT frameworks.7273- **Integrated shrinking** (Hypothesis, Hedgehog): Generates shrink tree during generation. Preserves generator invariants. Superior approach.74- **Type-based shrinking** (QuickCheck): Separate shrinker functions. Can violate generator constraints.75- **Always investigate shrunk counterexamples**: They reveal the essential failure, stripped of noise.7677## PBT vs Fuzzing (decision guidance)7879| Aspect | PBT | Fuzzing |80|--------|-----|---------|81| Input generation | Guided by properties | Guided by code coverage |82| Oracle | User-written property assertions | Crashes/exceptions/timeouts |83| Best for | Correctness, algorithms, contracts | Security, memory safety, crash detection |84| **Convergence (2025)** | Hybrid tools (Bolero, Antithesis) combine both approaches |8586---8788## Proof Strategies8990- **Simplification**: Reduce by known rules, use shrinking to find minimal counterexamples91- **Arithmetic**: Generate numeric edge cases (0, 1, MAX, negative, overflow boundaries)92- **Case analysis**: Split on constructors/variants, test each branch independently93- **Induction**: Recursive/sequential properties via stateful testing94- **Fuzzing**: Empirical exploration when properties are hard to specify formally95- **Metamorphic relations**: When oracle is unknown, test relationships between outputs9697## Theorem Hierarchy9899```100Main Property (Goal)101|-- Supporting Property 1102| +-- Helper Property 1a103|-- Supporting Property 2104+-- Edge Case Property 3105```106107---108109## Workflow (language-neutral)1101111. **PLAN** -- Identify correctness, safety, invariant, and termination properties. Design hierarchy. Choose property categories.1122. **CREATE** -- Write property test files. One property per concern. Tag by category (postcondition, invariant, inverse, etc.).1133. **VERIFY** -- Run all properties. Count unproven (skipped/pending). Analyze counterexamples via shrinking.1144. **REMEDIATE** -- Fill in each skipped property using proof strategies. Convert every counterexample to a permanent regression test.115116---117118## Constitutional Rules (Non-Negotiable)1191201. **CREATE First**: Generate all property test artifacts from plan design before verification1212. **Complete All Proofs**: Zero skipped/pending properties in final code1223. **Totality Required**: All definitions must terminate1234. **Target Mirrors Model**: Implementation structure corresponds to proven model1245. **Iterative Remediation**: Fix proof failures, don't abandon verification125126## Validation Gates127128| Gate | Pass Criteria | Blocking |129|------|---------------|----------|130| Framework | PBT framework available and configured | Yes |131| Properties | All property tests pass | Yes |132| Unproven | Zero skipped/pending properties | Yes |133| Coverage | >= 80% line coverage | If present |134135## Exit Codes136137| Code | Meaning |138|------|---------|139| 0 | All properties pass, zero unproven/skipped |140| 11 | Property testing framework not available |141| 12 | No property tests created |142| 13 | Property tests failed or proofs incomplete |143| 14 | Coverage gaps (properties missing) |144145---146> Converted and distributed by [TomeVault](https://tomevault.io/claim/outlinedriven) — claim your Tome and manage your conversions.147<!-- tomevault:4.0:skill_md:2026-04-11 -->