# CARD: scaffold-d-differential-oracle — Differential / Characterization Oracle {#root}

@status:spec/done

[p01] @fact:reference-instance-note *Reference instance of the AI-Native Pattern Card format.* @status:impl/done

[p02] @fact:demonstrates-all-three-bands *Demonstrates all three bands, especially the operational Band 3.* @status:impl/done

[p03] @fact:card-is-beta *This card is itself BETA: its oracle-presence half ships (`cell-has-oracle`, mounted in `rust-ai-native-conform`), and its replacement-time checker `replacement-has-oracle` is specified and not yet implemented — see the @fact:CHECKER row.* @status:impl/done

## Band 1 — Identity & Recognition {#band-one-identity}

[p04] @fact:CLASSIFICATION **Classification:** layer = E (Verification coupling); mechanism = scaffold class D. @status:impl/done

[p05] @fact:INTENT **Intent:** When code is replaced or refactored, pin its observable behavior with a runnable check that compares the new implementation against the old one (differential) or against a captured baseline (characterization), so that a reader — especially a weak one — can change code freely and receive a pass/fail signal on whether behavior moved. @status:impl/done

[p06] @fact:ALSO-KNOWN-AS **Also Known As:** golden test; snapshot test; characterization test (Feathers); approval test; back-to-back test; differential testing; oracle test. @status:spec/done

[p07] @fact:applicability-recognition-lead **Applicability / Recognition:** Apply when ANY of these signals are present — @status:impl/done

- [p08] @fact:SIGNAL-CELL-IS-BEING-REPLACED a cell is being *replaced* or its internals *rewritten* while its contract is meant to stay fixed (the replacement protocol, R-040); @status:impl/done
- @fact:SIGNAL-LEGACY-BEHAVIOR-IS-UNDERSTOOD-BY-NOBODY legacy behavior exists that nobody fully understands but must be preserved (no spec, only observed behavior); @status:impl/done
- @fact:SIGNAL-REFACTOR-SPANS-MULTIPLE-FILES a refactor spans multiple files and the reader cannot prove by inspection that behavior is unchanged (the Rust multi-file-edit failure mode, R2C-006); @status:impl/done
- @fact:SIGNAL-WEAK-AGENT-NEEDS-A-SAFETY-NET a weak agent is assigned a modification task and needs a safety net it cannot derive itself. @status:impl/done

[p09] @fact:DETECTOR-SEED *Detector seed:* a diff that modifies the body of an item carrying `#[spec(implements …)]` without a corresponding oracle artifact in the cell's test module → recognition fires. @status:impl/done

## Band 2 — Justification & Tradeoffs {#band-two-justification}

[p10] @fact:MOTIVATION **Motivation:** A Qwen-32B-class agent is asked to optimize a parser cell authored by Opus. It rewrites the hot loop. By inspection, neither the agent nor a fast human reviewer can be sure the 200-line change preserved behavior across edge cases. With a differential oracle — proptest feeding identical random inputs to `old_parse` and `new_parse` and asserting equal outputs — the agent gets an immediate, mechanical verdict: behavior held, or here is a minimized counterexample. The expensive cognition ("what are all the edge cases?") was materialized once, by the author, as a runnable harness; the weak agent consumes the verdict instead of re-deriving the edge-case analysis. @status:spec/done

[p11] @fact:structure-and-participants-lead **Structure & Participants:** @status:impl/done

- [p12] @fact:PARTICIPANT-SUBJECT-OLD *Subject-old* — the prior implementation (kept temporarily, or captured as goldens). @status:impl/done
- @fact:PARTICIPANT-SUBJECT-NEW *Subject-new* — the replacement. @status:impl/done
- @fact:PARTICIPANT-INPUT-SOURCE *Input source* — a proptest strategy, a fuzz corpus, or a recorded production-input set. @status:impl/done
- @fact:PARTICIPANT-COMPARATOR *Comparator* — the equality/equivalence predicate (exact, or domain-specific tolerance). @status:impl/done
- @fact:PARTICIPANT-ORACLE-HARNESS *Oracle harness* — the runnable test binding these, living in the cell's test module. @status:impl/done

[p13] @fact:COLLABORATIONS **Collaborations:** Pairs with Class B (typed builders shrink the input space the oracle must cover) and Class C (contracts define what "equivalent" means). Consumes Class E (the per-cell fast loop runs the oracle). Emits Class F diagnostics (a failure cites the violated REQ + the minimized counterexample). In a raid (§3 of the format), this card is the *differential-safety* gate that every behavior-changing card application must pass. @status:impl/done

[p14] @fact:goals-and-non-goals-lead **Goals / Non-Goals:** @status:impl/done

- [p15] @fact:GOALS *Goals:* detect unintended behavior change during replacement/refactor; give weak readers a modification safety net; make "behavior preserved" a machine fact, not a claim. @status:impl/done
- @fact:NON-GOALS *Non-Goals:* NOT a correctness proof (it checks new-vs-old agreement, so it inherits any bug the old code had); NOT a substitute for the spec (it pins behavior, it does not justify it); NOT for greenfield code with no prior behavior to differ against. @status:impl/done

[p16] @fact:consequences-lead **Consequences:** @status:impl/done

- [p17] @fact:CONSEQUENCE-REFACTORING-BECOMES-SAFE (+) The reader can refactor aggressively; the net catches behavior drift mechanically. @status:spec/done
- @fact:CONSEQUENCE-IMPLEMENTATION-AND-CONTRACT-VARY-INDEPENDENTLY (+) Decouples "change the implementation" from "preserve the contract" — they vary independently. @status:spec/done
- @fact:CONSEQUENCE-STRATEGY-AND-COMPARATOR-COST-EFFORT (−) Cost: authoring the input strategy and comparator; maintaining goldens (which can rot — they must fail loudly when stale, never auto-update silently). @status:spec/done
- @fact:CONSEQUENCE-CHARACTERIZATION-ENSHRINES-CURRENT-BEHAVIOR (−) Characterization variant *enshrines current behavior including its bugs* — must be paired with a spec edge that says which behaviors are intentional vs incidental. @status:spec/done

[p18] @fact:alternatives-lead **Alternatives:** @status:impl/done

- [p19] @fact:ALTERNATIVE-FORMAL-PROOF *Full formal proof* (Kani/Creusot): stronger, but far costlier and not always tractable; choose for safety-critical invariants, not routine refactors. @status:spec/done
- @fact:ALTERNATIVE-MANUAL-REVIEW *Manual review:* the status quo; fails exactly where we need it (large multi-file Rust edits, weak readers). @status:spec/done
- @fact:ALTERNATIVE-FRESH-UNIT-TESTS *Unit tests written fresh:* test what the author thought to test; the differential oracle tests behavior the author never enumerated. Prefer differential when preserving opaque legacy behavior. @status:spec/done

[p20] @fact:risks-and-assumptions-lead **Risks & Assumptions:** @status:impl/done

- [p21] @fact:RISK-OLD-IMPLEMENTATION-IS-AVAILABLE Assumes the old implementation is available or its behavior is capturable. @status:spec/done
- @fact:RISK-INPUTS-ARE-GENERATABLE-WITH-COVERAGE Assumes inputs are *generatable* with enough coverage; a weak input strategy gives false confidence. @status:spec/done
- @fact:RISK-SUNSET *Sunset condition:* if generation-time tools (`vibe-tcg`) plus full contracts ever make behavior-preservation statically provable for a class of cells, the differential oracle becomes redundant for that class and retires there. @status:spec/done
- @fact:RISK-TRANSFER Transfer risk: the value of executable scaffolds for *modification* (vs generation) is [E-mid], not yet measured on our codebase — this card is a prime R4 validation target. @status:spec/done

[p22] @fact:EVIDENCE-AND-TRANSFER-STRENGTH **Evidence & Transfer-strength:** findings R-040 (replacement protocol, production), R2C-008 (+Lib executable scaffolds transformative for weak agents, benchmark), Feathers characterization method (production). Evidence class: production + benchmark. Transfer tag: **[E-mid]** (executable-scaffold value shown for generation; modification transfer to be validated in R4). @status:spec/done

## Band 3 — Operation {#band-three-operation}

[p23] @fact:TRIGGER **Trigger:** WHEN a diff modifies the body of an item bearing `#[spec(implements …)]`, OR a cell is marked for replacement, OR a refactor touches > 1 file in a cell whose contract is unchanged — THEN apply this card before merge. @status:impl/done

[p24] @fact:MODE **Mode:** gate (runs at the cell's verification gate, not per keystroke). @status:impl/done

[p25] @fact:routine-lead **Routine** (≤7 steps, each verifiable): @status:impl/done

1. [p26] @fact:ROUTINE-IDENTIFY-THE-BEHAVIORAL-SURFACE Identify the behavioral surface to preserve (the seam's public functions). @status:impl/done
2. @fact:ROUTINE-KEEP-OLD-REACHABLE Keep `old` reachable (rename to `old_*`, or capture goldens from it on a fixed input set). @status:impl/done
3. @fact:ROUTINE-WRITE-THE-STRATEGY Write/extend a proptest strategy generating representative inputs for that surface. @status:impl/done
4. @fact:ROUTINE-BIND-OLD-VS-NEW Bind `old` vs `new` (or `golden` vs `new`) under an equality/equivalence comparator. @status:impl/done
5. @fact:ROUTINE-RUN-IN-THE-LOOP Run under the per-cell loop; on counterexample, fix `new` (NOT the oracle) until green. @status:impl/done
6. @fact:ROUTINE-REMOVE-OLD-ONCE-GREEN Once green, remove `old` (or commit the goldens) and leave the oracle in the test module. @status:impl/done
7. @fact:ROUTINE-CITE-THE-ORACLE Cite the oracle from the replacement's `#[spec(verifies …)]` edge. @status:impl/done

[p27] @fact:CHECKER **Checker:** conform T-sem rule `replacement-has-oracle` — flags any modification of a `#[spec(implements)]` item body whose cell lacks a differential/characterization test referencing it. Backed by `cargo test -p <cell>` running the oracle. *(Status: specified, NOT yet implemented in pilot → this card is BETA.)* @status:spec/done

[p28] @fact:RAID-ROLE **Raid role:** layer = *behavior-preserving* phase (runs in any raid that rewrites implementations); order = applied AS A GATE around every other behavior-changing card (no ordering dependency of its own, but nothing that changes behavior may merge in a raid without it); batch = per-cell. @status:impl/done

[p29] @fact:BUDGET **Budget:** competes with few rules (it is gate-time, not inline, so it does not crowd the edit-time active set); first-signal latency = one per-cell proptest run (target < 60s; tune case count to stay in budget). @status:impl/done

