Automated contract verification, detection, and remediation across multiple languages using formal preconditions, postconditions, and invariants. This skill provides both reference documentation AND execution capabilities for the full PLAN -> CREATE -> VERIFY -> REMEDIATE workflow.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Design-by-Contract (DbC) is a programming methodology that uses formal specifications (contracts) to define component behavior. This skill enables:
Core Contract Types:
Design-by-Contract is ideal for:
[<start>Requirements] -> [Phase 1: PLAN]
[Phase 1: PLAN|
Identify contracts
Design predicates
Map obligations
] -> [Phase 2: CREATE]
[Phase 2: CREATE|
Generate annotations
Add to .outline/contracts/
Wire dependencies
] -> [Phase 3: VERIFY]
[Phase 3: VERIFY|
Enable runtime flags
Run test suite
Check violations
] -> [Phase 4: REMEDIATE]
[Phase 4: REMEDIATE|
Diagnose violation type
Fix caller/callee/state
Re-verify
] -> [<end>Success]
Principle: Use compile-time verification before runtime contracts. If a property can be verified statically, do NOT add a runtime contract for it.
Static Assertions (compile-time) > Test/Debug Contracts > Runtime Contracts
| Property | Static | Test Contract | Debug Contract | Runtime Contract |
|---|---|---|---|---|
| Type size/alignment | static_assert (C++), assert_eq_size! (Rust) | - | - | - |
| Trait/interface bounds | assert_impl_all! (Rust), Concepts (C++) | - | - | - |
| Const value bounds | const_assert!, static_assert | - | - | - |
| Null/type safety | Type checker (tsc/pyright/kotlinc) | - | - | - |
| Exhaustiveness | Pattern matching + never/Never | - | - | - |
| Expensive O(n)+ checks | - | test_ensures | - | - |
| Reference impl equivalence | - | test_ensures | - | - |
| Internal state invariants | - | - | debug_invariant | - |
| Development preconditions | - | - | debug_requires | - |
| Public API input validation | - | - | - | requires |
| Safety-critical postconditions | - | - | - | ensures |
| External/untrusted data | - | - | - | Required (Zod/icontract) |
Legend: - = Do not use for this property
Can type system encode it? ──yes──> Use types (typestate, newtype)
│no
v
Verifiable at compile-time? ──yes──> static_assertions / const_assert!
│no
v
Expensive O(n)+ check? ──yes──> test_* (test builds only)
│no
v
Internal development aid? ──yes──> debug_* (debug builds only)
│no
v
Must enforce in production? ──yes──> Runtime contracts
│no
v
Consider if check is needed at all
Understand Requirements
Artifact Detection (Conditional)
# Rust (contracts crate)
rg '#\[pre\(|#\[post\(|#\[invariant\(' $ARGUMENTS
# TypeScript (Zod)
rg 'z\.object|z\.string|\.refine\(' $ARGUMENTS
# Python (icontract)
rg '@pre\(|@post\(|@invariant\(' $ARGUMENTS
# Java/Kotlin
rg 'checkArgument|checkState|require\s*\{' $ARGUMENTS
Design Contract Architecture
Prepare Run Phase
.outline/contracts/Use sequential-thinking for:
- Contract decomposition
- Obligation ordering
- Inheritance chain planning
Use actor-critic-thinking for:
- Contract strength evaluation
- Precondition completeness
- Postcondition sufficiency
Use shannon-thinking for:
- Contract coverage gaps
- Runtime verification costs
- Weakest precondition analysis
// Target: .outline/contracts/{module}_contracts.rs
// From requirement: {requirement text}
#[pre(input > 0, "Input must be positive")]
#[post(ret.is_some() => ret.unwrap() > input)]
fn process(input: i32) -> Option<i32> {
// Implementation in run phase
}
// Class invariant
#[invariant(self.balance >= 0)]
impl Account {
// Methods maintain invariant
}
// Target: .outline/contracts/{module}.contracts.ts
// From requirement: {requirement text}
const InputSchema = z.object({
value: z.number().positive("Value must be positive"),
}).refine(
(data) => /* precondition */,
{ message: "Precondition: {description}" }
);
// Postcondition validator
const OutputSchema = z.object({
result: z.number(),
}).refine(
(data) => /* postcondition */,
{ message: "Postcondition: {description}" }
);
# Target: .outline/contracts/{module}_contracts.py
# From requirement: {requirement text}
@icontract.require(lambda x: x > 0, "Input must be positive")
@icontract.ensure(lambda result: result is not None)
def process(x: int) -> Optional[int]:
# Implementation in run phase
pass
Requirements Analysis
Contract Architecture
Target Artifacts
.outline/contracts/* file listVerification Commands
# Create .outline/contracts directory
mkdir -p .outline/contracts
// .outline/contracts/{module}_contracts.rs
// Generated from plan design
use contracts::*;
// Source Requirement: {traceability from plan}
// Precondition: {from plan design}
// Postcondition: {from plan design}
#[pre(input > 0, "Input must be positive")]
#[post(ret.is_some() => ret.unwrap() > input, "Output must exceed input")]
pub fn process(input: i32) -> Option<i32> {
// Implementation
Some(input + 1)
}
// Class invariant: {from plan design}
#[invariant(self.balance >= 0, "Balance must be non-negative")]
impl Account {
#[post(self.balance == old(self.balance) + amount)]
pub fn deposit(&mut self, amount: u64) {
self.balance += amount;
}
}
// .outline/contracts/{module}.contracts.ts
// Generated from plan design
import { z } from 'zod';
// Source Requirement: {traceability from plan}
// Precondition schema: {from plan design}
export const InputSchema = z.object({
value: z.number().positive("Value must be positive"),
name: z.string().min(1, "Name required"),
}).refine(
(data) => data.value < 1000,
{ message: "Precondition: value must be under 1000" }
);
// Postcondition schema: {from plan design}
export const OutputSchema = z.object({
result: z.number(),
success: z.boolean(),
}).refine(
(data) => data.success || data.result === 0,
{ message: "Postcondition: failed operations must return 0" }
);
// Validation wrapper
export function withContracts<I, O>(
inputSchema: z.ZodType<I>,
outputSchema: z.ZodType<O>,
fn: (input: I) => O
): (input: I) => O {
return (input: I) => {
const validInput = inputSchema.parse(input);
const output = fn(validInput);
return outputSchema.parse(output);
};
}
# .outline/contracts/{module}_contracts.py
# Generated from plan design
import icontract
# Source Requirement: {traceability from plan}
# Precondition: {from plan design}
# Postcondition: {from plan design}
@icontract.require(lambda x: x > 0, "Input must be positive")
@icontract.ensure(lambda result: result is not None, "Must return value")
@icontract.ensure(lambda x, result: result > x, "Output must exceed input")
def process(x: int) -> int:
return x + 1
# Class invariant: {from plan design}
@icontract.invariant(lambda self: self.balance >= 0)
class Account:
def __init__(self):
self.balance = 0
@icontract.require(lambda amount: amount > 0)
@icontract.ensure(lambda self, amount, OLD: self.balance == OLD.balance + amount)
def deposit(self, amount: int) -> None:
self.balance += amount
# Ensure contracts are enabled (not disabled)
unset CONTRACTS_DISABLE
# Verify contracts exist
rg '#\[pre\(|#\[post\(|#\[invariant\(' .outline/contracts/ || exit 12
# Run tests with contracts
cargo test || exit 13
# Verify Zod schemas exist
rg 'z\.object|\.refine\(' .outline/contracts/ || exit 12
# Run tests (Zod validates at runtime)
npx vitest run || exit 13
# Enable thorough contract checking
export ICONTRACT_SLOW=true
# Verify decorators exist
rg '@icontract\.(require|ensure|invariant)' .outline/contracts/ || exit 12
# Run tests
pytest || exit 13
# Verify Guava preconditions exist
rg 'checkArgument|checkState|checkNotNull' .outline/contracts/ || exit 12
# Run tests
mvn test || exit 13
# Ensure NDEBUG is NOT set for contract checking
unset NDEBUG
# Verify contracts exist
rg 'Expects\(|Ensures\(' .outline/contracts/ || exit 12
# Build and test
cmake --build build && ./build/tests || exit 13
| Violation | Exit Code | Fix Strategy |
|---|---|---|
| Precondition | 1 | Fix caller to meet requirements |
| Postcondition | 2 | Fix implementation to meet guarantee |
| Invariant | 3 | Fix state management logic |
Precondition Violation (Caller's fault)
# Error: icontract.ViolationError: Pre: x > 0
# The CALLER passed invalid input
# Debug: Check call site
# Before:
result = process(-5) # WRONG: violates x > 0
# After:
if x > 0:
result = process(x)
else:
handle_invalid_input(x)
Postcondition Violation (Callee's fault)
# Error: icontract.ViolationError: Post: result > x
# The IMPLEMENTATION doesn't meet its guarantee
# Debug: Fix the function
# Before:
@icontract.ensure(lambda x, result: result > x)
def process(x: int) -> int:
return x # WRONG: not > x
# After:
@icontract.ensure(lambda x, result: result > x)
def process(x: int) -> int:
return x + 1 # Correct
Invariant Violation (State corruption)
# Error: icontract.ViolationError: Inv: self.balance >= 0
# Object state became invalid after operation
# Debug: Find state mutation that breaks invariant
# Before:
@icontract.invariant(lambda self: self.balance >= 0)
class Account:
def withdraw(self, amount):
self.balance -= amount # WRONG: can go negative
# After:
@icontract.require(lambda self, amount: amount <= self.balance)
def withdraw(self, amount):
self.balance -= amount # Now protected by precondition
Precondition (Caller's Duty)
INPUT --> VALIDATE --> PROCESS
|
v
FAIL FAST if invalid
Postcondition (Callee's Promise)
PROCESS --> OUTPUT --> VALIDATE
|
v
ASSERT guarantee met
Invariant (Always True)
OPERATION --> STATE CHANGE --> CHECK INVARIANT
|
v
ASSERT still valid
Verify all contracts satisfied in codebase.
Usage: dbc-verify [--lang LANG] [--path PATH] [--runtime-flags]
Algorithm:
1. Detect language(s) in scope (fd file extensions)
2. Check runtime flags enabled per language
3. Scan for contract library usage (rg patterns)
4. Execute language-specific verification
5. Report violations with exit codes
Detect contract usage and missing contracts.
Usage: dbc-detect [--lang LANG] [--missing] [--violations]
Algorithm:
1. Scan for contract library imports (rg)
2. Find functions without contracts (ast-grep negative match)
3. Identify contract violations (pattern analysis)
4. Generate coverage report
Auto-fix violations or add missing contracts.
Usage: dbc-remediate [--add-missing] [--fix-violations] [--dry-run]
Algorithm:
1. Identify remediation targets (missing/violated contracts)
2. Generate contract code per language
3. Apply fixes via ast-grep or native-patch
4. Verify fixes with dbc-verify
| Code | Meaning | Action |
|---|---|---|
| 0 | All contracts pass | Ready for deployment |
| 1 | Precondition fail | Fix caller to meet requirements |
| 2 | Postcondition fail | Fix implementation |
| 3 | Invariant fail | Fix state management |
| 11 | Library missing | Install contract library |
| 12 | No contracts | Run plan phase, create contracts |
| 13 | Verification failed | Debug and fix violations |
# Find contracts
rg '#\[pre\(|#\[post\(|#\[invariant\(|debug_assert!' --type rust
# Find functions without contracts
ast-grep -p 'fn $NAME($$$) { $$$ }' -l rust | \
rg -v '#\[pre\(|debug_assert!' --files-without-match
Remediation template:
#[pre($CONDITION)]
#[post(ret $POSTCONDITION)]
fn $NAME($PARAMS) -> $RET {
debug_assert!($CONDITION, "$ERROR_MSG");
$BODY
}
Runtime flags: Check CARGO_BUILD_TYPE != release or cfg(debug_assertions)
# Find contracts
rg 'z\.object|invariant\(|\.parse\(|\.safeParse\(' --type ts
# Find functions without validation
ast-grep -p 'function $NAME($$$): $$$ { $$$ }' -l typescript | \
rg -v 'z\.|invariant' --files-without-match
Remediation template:
const ${NAME}Schema = z.object({
$FIELDS
});
function $NAME(params: unknown): $RET {
const validated = ${NAME}Schema.parse(params);
invariant($CONDITION, "$ERROR_MSG");
$BODY
}
Runtime flags: Check process.env.NODE_ENV === 'development'
# Find contracts
rg '@pre\(|@post\(|@invariant|@require|@ensure' --type python
# Find functions without contracts
ast-grep -p 'def $NAME($$$): $$$' -l python | \
rg -v '@pre|@post|@invariant' --files-without-match
Remediation template:
@pre(lambda $PARAMS: $CONDITION)
@post(lambda result: $POSTCONDITION)
def $NAME($PARAMS) -> $RET:
"""$DOCSTRING"""
$BODY
Runtime flags: Check __debug__ is True (not python -O)
# Find contracts
rg 'checkArgument|checkState|validate\(|Preconditions\.' --type java
# Find methods without contracts
ast-grep -p 'public $RET $NAME($$$) { $$$ }' -l java | \
rg -v 'checkArgument|validate' --files-without-match
Remediation template:
public $RET $NAME($PARAMS) {
checkArgument($CONDITION, "$ERROR_MSG");
$BODY
validate($POSTCONDITION, "$POST_ERROR");
return $RESULT;
}
Runtime flags: Check assertions enabled with -ea flag
# Find contracts
rg 'contract \{|Either<|Validated|require\(|check\(' --type kotlin
# Find functions without contracts
ast-grep -p 'fun $NAME($$$): $$$ { $$$ }' -l kotlin | \
rg -v 'contract|require|check' --files-without-match
Remediation template:
fun $NAME($PARAMS): Either<$ERR, $RET> {
contract {
returns() implies ($CONDITION)
}
return if (!$CONDITION) "$ERROR".left()
else { $BODY }.right()
}
Runtime flags: Check -ea for JVM assertions
# Find contracts
rg 'Guard\.Against|Contract\.Requires|Contract\.Ensures|Debug\.Assert' --type cs
# Find methods without contracts
ast-grep -p 'public $RET $NAME($$$) { $$$ }' -l csharp | \
rg -v 'Guard\.|Contract\.' --files-without-match
Remediation template:
public $RET $NAME($PARAMS) {
Guard.Against.Null($PARAM, nameof($PARAM));
Contract.Ensures(Contract.Result<$RET>() $POSTCONDITION);
$BODY
}
Runtime flags: Check Debug configuration
# Find contracts
rg 'Expects\(|Ensures\(|boost::contract|gsl::' --type cpp
# Find functions without contracts
ast-grep -p '$RET $NAME($$$) { $$$ }' -l cpp | \
rg -v 'Expects|Ensures' --files-without-match
Remediation template:
$RET $NAME($PARAMS) {
Expects($PRECONDITION);
$BODY
Ensures($POSTCONDITION);
return $RESULT;
}
Runtime flags: Check NDEBUG not defined
# Find contracts
rg 'assert\(|static_assert' --type c
# Find functions without asserts
ast-grep -p '$RET $NAME($$$) { $$$ }' -l c | \
rg -v 'assert\(' --files-without-match
Remediation template:
$RET $NAME($PARAMS) {
assert($PRECONDITION && "$ERROR_MSG");
$BODY
assert($POSTCONDITION && "$POST_ERROR");
return $RESULT;
}
Runtime flags: Check NDEBUG not defined
| Language | Library | Runtime Flag |
|---|---|---|
| Rust | contracts | CONTRACTS_DISABLE |
| TypeScript | Zod | (always active) |
| Python | icontract | ICONTRACT_SLOW |
| Java | Guava | (always active) |
| Kotlin | native | (always active) |
| C# | Guard | (always active) |
| C++ | GSL/Boost | NDEBUG |
| Language | Contract Library | Error Type | Error Handling | Recovery Strategy |
|---|---|---|---|---|
| Rust | contracts, prusti | panic! | catch_unwind (discouraged) | Result/Option types |
| TypeScript | zod, io-ts | ZodError, thrown | try/catch | Either/Result pattern |
| Python | dpcontracts, icontract | AssertionError | try/except | Optional/Result |
| Java | Guava, Bean Validation | IllegalArgumentException | try/catch | Optional/Either |
| Kotlin | Arrow, require/check | IllegalArgumentException | try/catch | Either<E, A> |
| C# | Code Contracts, Guard | ArgumentException | try/catch | Result<T> |
| C++ | GSL, Boost.Contract | std::terminate | noexcept | std::expected |
| C | assert.h | abort() | Signal handler | Return codes |
Contract Type: [PRECONDITION|POSTCONDITION|INVARIANT]
Location: file.rs:42 in function_name()
Condition: x > 0 && x < 100
Actual Value: x = -5
Expected: Positive integer less than 100
Context: Processing user input for order ID
| Symptom | Cause | Resolution |
|---|---|---|
| Exit 1 | Precondition violation | Caller must provide valid input (fix call site) |
| Exit 2 | Postcondition violation | Implementation doesn't meet guarantee (fix function) |
| Exit 3 | Invariant violation | Object state became invalid (fix state mutation) |
| Exit 11 | Contract library missing | Install: pip install icontract, cargo add contracts, npm i zod |
| Exit 12 | No contract annotations | Run plan phase first |
| Exit 13 | Tests failed with contracts | Debug violation type |
CONTRACTS_DISABLE set | Contracts silently skipped | unset CONTRACTS_DISABLE |
| No error but wrong behavior | Contract too weak | Strengthen pre/post conditions |
| Performance impact | Contracts in hot path | Use @icontract.require(enabled=DEBUG) |
| Contract not firing | Debug assertions disabled | Check NDEBUG, -O flags |
| False positive | Contract too strict | Review expected vs actual |
| False negative | Contract too weak | Add edge case tests |
| Stack overflow | Recursive contract | Check for cycles |
| Flaky failures | Race condition in contract | Add synchronization |
# Check if contracts are enabled (Rust)
cargo build && rg 'debug_assert' target/debug/*.d
# Check if contracts are enabled (Node.js)
node -e "console.log(process.env.NODE_ENV)"
# Check if assertions enabled (Java)
java -ea -version 2>&1 | head -1
# Check if assertions enabled (C/C++)
cpp -dM /dev/null | grep NDEBUG
# Python - Verbose contract errors
ICONTRACT_SLOW=true pytest -v --tb=long
# Python - Find contract decorators
rg '@icontract\.(require|ensure|invariant)' src/
# Rust - Enable backtrace
RUST_BACKTRACE=1 cargo test
# Rust - Find contract attributes
rg '#\[(pre|post|invariant)\(' src/
# TypeScript - Verbose Zod errors
DEBUG=zod:* npm test
# TypeScript - Find Zod schemas
rg 'z\.(object|refine|string|number)' src/
# General - Check contracts not disabled
env | rg -i 'contract|ndebug'
Identify the violation location:
# Run with debug symbols
RUST_BACKTRACE=1 cargo run # Rust
node --enable-source-maps # Node.js
python -c "import traceback" # Python
Examine the call stack:
Add tracing at contract boundary:
// Rust example
#[pre(x > 0)]
fn process(x: i32) {
tracing::debug!("process called with x = {}", x);
// ...
}
Common causes:
Instrument the function exit:
// TypeScript example
function calculate(x: number): number {
const result = /* computation */;
console.log(`calculate returning: ${result}`);
invariant(result > 0, `Expected positive, got ${result}`);
return result;
}
Check intermediate state:
Common causes:
Track state transitions:
# Python example with dpcontracts
@invariant(lambda self: self.balance >= 0)
class Account:
def __init__(self):
self._log_state("init")
def withdraw(self, amount):
self._log_state(f"before withdraw {amount}")
self.balance -= amount
self._log_state(f"after withdraw {amount}")
Find mutation that breaks invariant:
Common causes:
Problem: Contract check modifies program state.
Solution:
// WRONG: Contract has side effect
#[pre(counter.increment() > 0)] // Modifies counter!
fn process() { ... }
// RIGHT: Contract is pure
#[pre(counter.value() > 0)] // Only reads counter
fn process() { ... }
Problem: Contract check is O(n) or worse, causing performance issues.
Solution:
// WRONG: O(n) check on every call
function process(items: Item[]) {
invariant(items.every(i => isValid(i)), "All items must be valid");
// Called millions of times...
}
// RIGHT: Check once at boundary, trust internally
function publicApi(items: Item[]) {
const validated = items.filter(isValid); // Validate at boundary
processInternal(validated); // Internal trusts input
}
Problem: Contract failure message doesn't help debugging.
Solution:
# WRONG: No context
assert x > 0
# RIGHT: Full context
assert x > 0, f"Expected positive x, got {x} (type={type(x).__name__}, caller={inspect.stack()[1].function})"
Problem: Critical contracts disabled, bugs reach production.
Solution:
// Separate debug-only from critical contracts
#[cfg(debug_assertions)]
debug_assert!(validation_heavy_check()); // Debug only
// Critical contracts always enabled
assert!(user_id.is_valid(), "Invalid user ID"); // Always runs
Problem: Contract A checks contract B which checks contract A.
Solution:
// WRONG: Circular dependency
class A {
@Requires("b.isValid()") // Calls B
void process(B b) { ... }
}
class B {
@Requires("a.isValid()") // Calls A, which calls B...
void validate(A a) { ... }
}
// RIGHT: Break cycle with primitive checks
class A {
@Requires("b.id != null && b.state == State.READY")
void process(B b) { ... }
}
Too Weak (misses bugs)
@icontract.require(lambda x: True) # Useless
def divide(x, y):
return x / y # Will crash on y=0
Appropriate Strength
@icontract.require(lambda y: y != 0, "Divisor must be non-zero")
@icontract.ensure(lambda x, y, result: abs(result * y - x) < 1e-10)
def divide(x, y):
return x / y
Too Strong (rejects valid inputs)
@icontract.require(lambda x: x > 0 and x < 100) # Overly restrictive
def process(x):
return x * 2 # Works for any number
Public API Layer: [Strong Preconditions]
|
Service Layer: [Moderate Preconditions]
|
Domain Layer: [Minimal Preconditions + Strong Invariants]
|
Infrastructure: [Postconditions on I/O]
// Base contract
interface Processor {
@Requires("input != null")
@Ensures("result != null")
Result process(Input input);
}
// Subtype strengthens postcondition (allowed)
// Subtype weakens precondition (allowed)
class SafeProcessor implements Processor {
@Requires("true") // Weaker: accepts any input
@Ensures("result != null && result.isValid()") // Stronger: guarantees validity
Result process(Input input) { ... }
}
// Start with weak contract, refine as understanding grows
// Version 1: Basic
fun process(x: Int): Int {
require(true) { "No constraints yet" }
// ...
}
// Version 2: After discovering constraints
fun process(x: Int): Int {
require(x > 0) { "x must be positive" }
// ...
}
// Version 3: After discovering more constraints
fun process(x: Int): Int {
require(x in 1..1000) { "x must be between 1 and 1000" }
// ...
}
| Scenario | Better Alternative |
|---|---|
| Proving mathematical properties | Proof-driven (Lean 4) |
| Compile-time guarantees | Type-driven (Idris 2) |
| Complex state machine correctness | Validation-first (Quint) |
| Performance-critical inner loops | Disable in release, use types |
| Third-party library integration | Wrapper with contracts at boundary |
| Already have strong types | Contracts may be redundant |
| Aspect | Development | Production |
|---|---|---|
| Preconditions | Always enabled | Critical only |
| Postconditions | Always enabled | Disabled |
| Invariants | Full checking | Disabled |
| Logging | Verbose | Minimal |
| Cost per check | O(1) acceptable | O(1) required |
// Conditional compilation
#[cfg(debug_assertions)]
fn expensive_check() { ... }
// Feature flags
#[cfg(feature = "contracts")]
fn contract_check() { ... }
// Inline for hot paths
#[inline(always)]
fn fast_precondition() { ... }
[<start>Start] -> [dbc-detect]
[dbc-detect] found contracts -> [dbc-verify]
[dbc-detect] no contracts -> [dbc-remediate --add-missing]
[dbc-verify] pass -> [<end>Success]
[dbc-verify] fail -> [dbc-remediate --fix-violations]
[dbc-remediate --add-missing] -> [dbc-verify]
[dbc-remediate --fix-violations] -> [dbc-verify]