from __future__ import annotations from dataclasses import dataclass from typing import Literal from .model import Outcome, utc_now Route = Literal["R4-A", "R4-B"] @dataclass(frozen=True) class R4Case: """Synthetic erasure observation. No storage client and no key material.""" probe_id: str route: Route horizon_elapsed: bool = False key_destroyed: bool = False inventory_complete: bool = False recovered: bool = False readable: bool = False usable_key_survives: bool = False low_entropy_oracle: bool = False @dataclass(frozen=True) class R4Result: probe_id: str route: Route outcome: Outcome reason: str def evaluate(case: R4Case) -> R4Result: """Judge one R4 case. An incomplete inventory is inconclusive, not a pass.""" if not case.inventory_complete: return R4Result( case.probe_id, case.route, "inconclusive", "declared copies were not all exercised", ) if case.route == "R4-A": if not case.horizon_elapsed: return R4Result( case.probe_id, case.route, "inconclusive", "recovery before the horizon is not an R4-A result", ) if case.recovered: return R4Result( case.probe_id, case.route, "finding", "fixture content recovered after the erasure horizon", ) return R4Result( case.probe_id, case.route, "pass", "no fixture content recovered from the declared copies", ) if not case.key_destroyed: return R4Result( case.probe_id, case.route, "inconclusive", "key destruction alone is not a pass, and destruction was not recorded", ) if case.readable or case.usable_key_survives or case.low_entropy_oracle: return R4Result( case.probe_id, case.route, "finding", "erased fixture remains readable or confirmable", ) return R4Result( case.probe_id, case.route, "pass", "retained ciphertext is unreadable and no confirmation oracle remains", ) def r4_calibration() -> dict: """Known-bad must fail before a known-good pass is trusted. No storage.""" started = utc_now() known_bad = [ evaluate(R4Case( "horizon-recovered", "R4-A", horizon_elapsed=True, inventory_complete=True, recovered=True, )), evaluate(R4Case( "ciphertext-readable", "R4-B", key_destroyed=True, inventory_complete=True, readable=True, )), evaluate(R4Case( "usable-key-survives", "R4-B", key_destroyed=True, inventory_complete=True, usable_key_survives=True, )), evaluate(R4Case( "low-entropy-oracle", "R4-B", key_destroyed=True, inventory_complete=True, low_entropy_oracle=True, )), ] inconclusive = [ evaluate(R4Case("inventory-incomplete", "R4-A", horizon_elapsed=True)), evaluate(R4Case("before-horizon", "R4-A", inventory_complete=True)), evaluate(R4Case("key-not-destroyed", "R4-B", inventory_complete=True)), ] bad_held = all(result.outcome == "finding" for result in known_bad) limits_held = all(result.outcome == "inconclusive" for result in inconclusive) known_good = [ evaluate(R4Case( "horizon-clear", "R4-A", horizon_elapsed=True, inventory_complete=True, )), evaluate(R4Case( "key-destroyed-clear", "R4-B", key_destroyed=True, inventory_complete=True, )), ] if bad_held and limits_held else [] good_held = all(result.outcome == "pass" for result in known_good) return { "schema_version": "whitehat-r4-calibration/v1", "evidence_class": "fixture", "run_id": f"r4-calibration-{started}", "started_at": started, "ended_at": utc_now(), "outcome": "pass" if bad_held and limits_held and good_held else "finding", "known_bad_failed_first": bad_held, "known_good": [result.__dict__ for result in known_good], "known_bad": [result.__dict__ for result in known_bad], "inconclusive": [result.__dict__ for result in inconclusive], "limitations": [ "Offline R4 calibration evaluates the harness; it is not target assurance.", "No backup, replica, key, or ciphertext was accessed.", "audit-core is not an R4 target. No live R4 target is registered.", "An incomplete copy inventory stays inconclusive and is not a pass.", ], }