from __future__ import annotations import json from pathlib import Path from k1link.perception.contracts import LocalObstacleMap, SourceAccounting from k1link.perception.graph_contracts import ( REFERENCE_GRAPH_ID_V2, DeliveredFrame, GraphRunMode, GraphState, TerminalOutcome, TerminalOutcomeType, build_graph_run_result_v2, ) from k1link.perception.providers import ReferencePerceptionGraphConfigV2 from k1link.perception.reference_graph_parity import ReferenceGraphParityReport from k1link.perception.reference_graph_result import seal_reference_graph_result REPOSITORY_ROOT = Path(__file__).resolve().parents[1] def _parity(accepted: bool = True) -> ReferenceGraphParityReport: return ReferenceGraphParityReport( expected_frames=1, compared_frames=1, temporal_frames_sha256="a" * 64, threat_frames_sha256="b" * 64, mismatch_counts=(("threat_assessments", 0 if accepted else 1),), accepted=accepted, ) def _result(outcome: TerminalOutcomeType = TerminalOutcomeType.DELIVERED): terminal = TerminalOutcome( source_id="RAVNOVES00", session_id="20260720T065719Z_viewer_live", frame_id="frame-000000", sequence=0, outcome=outcome, stage_id="threat" if outcome is TerminalOutcomeType.DELIVERED else "detector", reason=( "object-payload-delivered" if outcome is TerminalOutcomeType.DELIVERED else "bounded-queue-latest-wins" ), ) deliveries = ( ( DeliveredFrame( sequence=0, obstacle_map=LocalObstacleMap( source_id="RAVNOVES00", session_id="20260720T065719Z_viewer_live", frame_id="frame-000000", graph_id=REFERENCE_GRAPH_ID_V2, generated_monotonic_ns=123, output_age_ns=45, occupied=(), unknown=(), camera_uncertainty=(), accounting=SourceAccounting(1, 1, 0, 0), ), threats=(), ), ) if outcome is TerminalOutcomeType.DELIVERED else () ) return build_graph_run_result_v2( graph_id=REFERENCE_GRAPH_ID_V2, source_profile_id="m4-ravnoves00-recorded-realtime/v1", run_mode=GraphRunMode.LOSSLESS_REPLAY, state=GraphState.STOPPED, admitted_count=1, outcomes=(terminal,), deliveries=deliveries, queue_high_watermarks=(("detector", 1), ("threat", 1)), ) def test_m47_graph_config_round_trips_and_pins_rolling_stage() -> None: path = REPOSITORY_ROOT / "config/perception/m4-reference-graph-v2.json" document = json.loads(path.read_text("utf-8")) config = ReferencePerceptionGraphConfigV2.from_dict(document) assert config.to_dict() == document assert config.graph_id == REFERENCE_GRAPH_ID_V2 assert {provider.role.value for provider in config.providers} == { "source", "detector", "geometry", "temporal", "motion", "rolling", "threat", } assert {queue.stage_id for queue in config.queues} == { "detector", "geometry", "temporal", "rolling", "threat", } def test_reference_graph_result_is_content_addressed_and_reproducible(tmp_path: Path) -> None: first = seal_reference_graph_result( _result(), output_root=tmp_path / "one", expected_frames=1, parity=_parity(), ) second = seal_reference_graph_result( _result(), output_root=tmp_path / "two", expected_frames=1, parity=_parity(), ) assert first.accepted is True assert first.result_id == second.result_id assert first.report["gates"] == { "lossless_replay_mode": True, "graph_stopped": True, "admitted_frame_count": True, "terminal_accounting_closed": True, "delivery_count": True, "delivery_payload_count": True, "no_failed_frames": True, "no_stale_frames": True, "no_superseded_frames": True, "no_rejected_frames": True, "no_unavailable_frames": True, "accepted_m45r_m46_parity": True, } assert { path.name: path.read_bytes() for path in first.result_root.iterdir() } == {path.name: path.read_bytes() for path in second.result_root.iterdir()} def test_reference_graph_result_fails_closed_on_supersession(tmp_path: Path) -> None: sealed = seal_reference_graph_result( _result(TerminalOutcomeType.SUPERSEDED), output_root=tmp_path, expected_frames=1, parity=_parity(), ) assert sealed.accepted is False assert sealed.report["gates"]["no_superseded_frames"] is False assert sealed.report["gates"]["delivery_count"] is False