feat(engine): shadow-bake model-vs-deterministic cut divergence comparator - #309
Merged
thejefflarson merged 2 commits intoAug 1, 2026
Conversation
…rator Adds a view-only comparator (engine::cut_divergence) that, for each breach-relevant entry with a decisive cut-choice decision, classifies the model's chosen cut-set against the deterministic fallback set containment_for + quarantine_workload_link would themselves have proposed for the same chains (agree / model_over_cut / model_under_cut / mixed). Journaled per entry (Decision::CutDivergence, durable and replay-restored) and surfaced read-only at GET /api/divergence.json. On by default in shadow, no PROTECTOR_*_ENABLE toggle; every function takes shared references and returns owned data, so computing/journaling/viewing a classification cannot arm or mutate anything (ADR-0016). Also adds docs/adr/0037-shadow-bake-arm-readiness.md, the human-read exit criterion (bake duration, zero unexplained model-over-cut on a clean workload, the ADR-0033 bench threshold, a model-under-cut spot-check, continuous coverage) that informs the single ADR-0021 enforce flip at the ADR-0035 ladder's narrowest rung — the comparator only informs; nothing here auto-arms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VtjoJttCvBY4dzCoE4f9vP
…-vs-deterministic-cut-comparator-then
thejefflarson
enabled auto-merge (squash)
August 1, 2026 09:34
thejefflarson
deleted the
thejefflarson/jef-569-shadow-bake-with-model-vs-deterministic-cut-comparator-then
branch
August 1, 2026 09:42
This was referenced Aug 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Re-scoped JEF-569: a view-only comparator that lets the shadow bake measure
whether the ADR-0034 model-chosen cut-set agrees with what pure determinism
alone would have proposed, plus the human-read exit criterion that informs the
first
enforceflip.engine::cut_divergence(new module): for each breach-relevant entry witha decisive cut-choice decision this pass, classifies the model's cut-set
against the deterministic fallback set
respond::containment_for+respond::quarantine_workload_linkwould themselves have proposed for thesame chains —
agree/model_over_cut/model_under_cut/mixed. Afresh
Uncertain(or no decision at all) is skipped — no fresh signal, nevera divergence claim.
journal::Decision::CutDivergence(durable, restored onreplay into the new
state::DivergenceLogring, mirroring how a reversionrestores today).
GET /api/divergence.json— a read-only,no-storeJSON feed onthe existing dashboard router (same auth/CSP layering as every other
/api/*.jsonroute). Deliberately not wired into the Preact tab/nav system(that's a separate surface with its own likely-parallel ticket); it's a raw
array, not a
strip-enveloped tab.docs/adr/0037-shadow-bake-arm-readiness.md: the exit criterion anoperator reads before the single ADR-0021
enforceflip at the ADR-0035ladder's narrowest rung — bake duration, zero unexplained
model_over_cutona clean workload, the ADR-0033 bench threshold, a
model_under_cutspot-check, continuous coverage. Informs the flip; nothing here or in code
auto-arms (auto-arming is explicitly rejected, same as ADR-0021).
cut_divergence_tests.rs'smulti_hop_incident_snapshot— entry → pivot (critical CVE) → objective (KEV CVE, mounts the secret) — so
the comparator is exercised on downstream divergence, not just the entry.
No
PROTECTOR_*_ENABLEtoggle — on by default in shadow, per CLAUDE.md.View-never-mutates is compiler-enforced: every function in the path takes
shared references and returns owned data.
Divergence classification + journal/view shape
Journaled as
Decision::CutDivergence { entry, class, model_cuts, deterministic_cuts };served read-only as a raw JSON array at
/api/divergence.json.Test plan
npm --prefix engine/web run buildcargo fmt --all -- --checkcargo clippy --all-targets -- -D warningscargo nextest run --workspace— 1133 passed, 2 skipped (pre-existing), 0 failedcut_divergence_tests.rs(classification: agree / over-cut / under-cut /mixed, the multi-hop fixture, decisive-
NoAttackunder-cut,Uncertain/no-decisionskip, a purity/idempotence test),
state/divergence.rs's ring-eviction + class-counttests, a journal round-trip test for
Decision::CutDivergence, and a dashboardHTTP-level test (
GET-only,no-store, raw-array,POST405s).Scope notes / risks
Preact tab/nav system (a real "Divergence" view a human clicks into, vs. today's
raw JSON feed) is deliberately deferred — sibling tickets are touching
dashboard/view_model/propsand the Preact client in parallel this sprint, and atab addition would touch the same
Tabenum / nav / bundle surface./api/divergence.jsonexists today as the stable contract a follow-up tab can read from with no backend
change.
engine/src/engine/mod.rsis now 949 lines (repo cap is 1000) — still under, but afuture addition to this orchestrator should split it into a module directory rather
than grow it further.
journal_tests.rs) integration test for divergence-restore-across-restartwas added (that file is already 657 lines); coverage instead sits at the journal
unit-test boundary (round-trip) + the
state::DivergenceLogring boundary, the sametest-boundary split the file's own docs describe for other decision kinds.
DashboardState's field list and its ~7 struct-literal construction sites(dashboard preview example scenarios + two test-module builders) — each is a single
additive line, the same mechanical footprint every prior dashboard-view ticket in
this repo's history has had.
Closes JEF-569.