Skip to main content

amberfork_attrib/
lib.rs

1//! Counterfactual attribution: verify a fork by re-running the agent, not just observing it.
2//!
3//! `amberfork diff` localizes the fork and labels attribution `Static` — a structural claim
4//! ("they diverge here, and it propagates downstream") that no re-execution ever checked. This
5//! crate is the consumer the record/replay path was built for (epic #35): it patches the fork
6//! step with the good run's behaviour, re-drives the agent through [`amberfork_replay`] against
7//! the patched cassette, and reports whether the run *recovered* — the difference between "they
8//! differ here" and "this is what broke it".
9//!
10//! It is the one crate that turns [`AttributionMode::Counterfactual`](amberfork_model::AttributionMode)
11//! — defined in the frozen model but produced nowhere — into real output.
12//!
13//! ## Offline by default, opt-in to re-execute
14//!
15//! Nothing here runs unless the CLI is invoked with `--verify`: default `amberfork diff` stays
16//! 100% offline and structural. Re-execution needs a live provider seam and a re-runnable agent
17//! command, both injected by the caller; the whole test suite substitutes an in-process stub for
18//! each, so `cargo test --workspace` stays offline and deterministic.
19//!
20//! ## Shape of the pipeline
21//!
22//! ```text
23//! DiffResult + bad/good cassettes
24//!   └─ patch_cassette        (pure) → the bad cassette with the fork step's response swapped
25//!        └─ re-execute × N    (I/O) → each re-run's own cassette, via ReplayServer + the agent
26//!             └─ recovery oracle (pure) → recovered / not recovered / inconclusive, per run
27//!                  └─ consensus over N (pure) → Recovery tri-state → upgraded Attribution
28//! ```
29//!
30//! [`verify`] is the entry that runs the whole pipeline; the CLI wires it behind `diff --verify`.
31
32mod cause;
33mod ddmin;
34mod driver;
35mod oracle;
36mod patch;
37mod verify;
38
39#[cfg(test)]
40mod testkit;
41
42pub use driver::{AgentDriver, AgentError, ReexecError};
43pub use patch::patch_cassette;
44pub use verify::verify;