Files
siloqy/prod/clean_arch/violet/v4_readiness.py

76 lines
2.3 KiB
Python
Raw Normal View History

"""V4 arm-readiness reporter — DARK, read-only, non-colliding.
Aggregates V4 gate outcomes into a typed report answering: "is V4 ready
to ARM the live canary?" Does NOT run gates — CONSUMES their results
(passed in) and applies fail-closed readiness logic.
Spec: prod/docs/VIOLET_PASS_MM1_V4_READINESS_REPORTER.md
"""
from __future__ import annotations
from .domain import StrictModel, typed
__all__ = ["V4ReadinessReport", "assess_v4_readiness"]
class V4ReadinessReport(StrictModel):
"""Typed V4 readiness report — all six gates must pass for ready_to_arm."""
creds_ok: bool
canary_passed: bool
arming_gate_present: bool
conviction_bit_identical: bool
selection_parity_ok: bool
feed_live: bool
reasons: list[str]
@property
def ready_to_arm(self) -> bool:
return all((
self.creds_ok,
self.canary_passed,
self.arming_gate_present,
self.conviction_bit_identical,
self.selection_parity_ok,
self.feed_live,
))
@typed
def assess_v4_readiness(
*,
creds_ok: bool,
canary_passed: bool,
arming_gate_present: bool,
conviction_bit_identical: bool,
selection_parity_ok: bool,
feed_live: bool,
) -> V4ReadinessReport:
"""Build a V4ReadinessReport from gate outcomes. Fail-closed: any False
means ready_to_arm is False. No partial-arm."""
reasons: list[str] = []
if not creds_ok:
reasons.append("creds_ok: PASS2.1 not satisfied")
if not canary_passed:
reasons.append("canary_passed: PASS2.3 canary not round-tripped flat")
if not arming_gate_present:
reasons.append("arming_gate_present: PASS2.2 not satisfied")
if not conviction_bit_identical:
reasons.append("conviction_bit_identical: PASS2.5 fidelity mismatch")
if not selection_parity_ok:
reasons.append("selection_parity_ok: PASS2.7/3.1 parity mismatch")
if not feed_live:
reasons.append("feed_live: PASS2.6 HZ feed stale or deaf")
return V4ReadinessReport(
creds_ok=creds_ok,
canary_passed=canary_passed,
arming_gate_present=arming_gate_present,
conviction_bit_identical=conviction_bit_identical,
selection_parity_ok=selection_parity_ok,
feed_live=feed_live,
reasons=reasons,
)