#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """Offline Phase-1.0AA integration for the passive batch contract. Only the exact built-in fake adapter and synthetic clock are accepted. This module has no live adapter protocol, network import, address, CLI or real clock. """ from __future__ import annotations from dataclasses import dataclass import hashlib import math from typing import Any from phase10w_shsrv_client_policy import SessionPlan from phase10x_inactive_transport import ( EvidenceFailure, EvidenceRecord, ExclusiveEvidenceStore, ) from phase10z_passive_batch_contract import ( PassiveBatch, PassiveContractError, PassiveResultAccumulator, build_passive_batch, ) PHASE10Z_CONTRACT_SHA256 = \ "0728c2be7f368e0a7f4b68efe86f6e0c5c2f50704a41d0e1992b0bfec19dde06" MAX_FAKE_EVENTS = 257 MAX_FAKE_ADVANCE_SECONDS = 60.0 EVENT_DATA = "DATA" EVENT_HARD_DEADLINE = "HARD_DEADLINE" EVENT_REMOTE_EOF = "REMOTE_EOF" EVENT_BLOCKED = "BLOCKED" EVENT_KINDS = { EVENT_DATA, EVENT_HARD_DEADLINE, EVENT_REMOTE_EOF, EVENT_BLOCKED, } class OfflineIntegrationError(RuntimeError): """Normalized offline failure without supplied data, target or path.""" class FakeAdapterError(RuntimeError): """Built-in fake-adapter state failure.""" @dataclass(frozen=True) class FakeReceiveEvent: """One caller-supplied synthetic event; never a live receive result.""" kind: str data: bytes = b"" advance_seconds: float = 0.0 def __post_init__(self) -> None: if self.kind not in EVENT_KINDS: raise FakeAdapterError("fake event kind is invalid") if not isinstance(self.data, bytes): raise FakeAdapterError("fake event data must be bytes") if self.kind == EVENT_DATA and not self.data: raise FakeAdapterError("fake data event is empty") if self.kind != EVENT_DATA and self.data: raise FakeAdapterError("fake control event contains data") value = self.advance_seconds if not isinstance(value, (int, float)) or isinstance(value, bool) or \ not math.isfinite(value) or not 0.0 <= value <= \ MAX_FAKE_ADVANCE_SECONDS: raise FakeAdapterError("fake time advance is invalid") class OfflineFakeClock: """Explicit synthetic monotonic value; never acquires host time.""" def __init__(self, initial: float = 0.0) -> None: if not isinstance(initial, (int, float)) or isinstance(initial, bool) or \ not math.isfinite(initial): raise FakeAdapterError("fake clock initial value is invalid") self._value = float(initial) def monotonic(self) -> float: return self._value def advance(self, seconds: float) -> None: if not isinstance(seconds, (int, float)) or isinstance(seconds, bool) or \ not math.isfinite(seconds) or not 0.0 <= seconds <= \ MAX_FAKE_ADVANCE_SECONDS: raise FakeAdapterError("fake clock advance is invalid") self._value += float(seconds) class OfflineFakeBatchAdapter: """Closed fake only: one open, one exact batch and scripted events.""" def __init__( self, clock: OfflineFakeClock, events: tuple[FakeReceiveEvent, ...], ) -> None: if type(clock) is not OfflineFakeClock: raise FakeAdapterError("only the exact fake clock is accepted") if not isinstance(events, tuple) or not 1 <= len(events) <= MAX_FAKE_EVENTS: raise FakeAdapterError("fake event sequence is invalid") if any(type(event) is not FakeReceiveEvent for event in events): raise FakeAdapterError("fake event type is invalid") self.clock = clock self._events = list(events) self.state = "NEW" self.open_count = 0 self.send_count = 0 self.close_count = 0 self.sent_sha256: str | None = None self.trace: list[str] = [] self.logical_event_buffer_discarded = False def open_once(self) -> None: if self.state != "NEW": raise FakeAdapterError("fake adapter cannot open") self.open_count += 1 self.trace.append("FAKE_OPEN") self.state = "OPEN" def send_one_batch(self, batch: PassiveBatch) -> None: if self.state != "OPEN" or type(batch) is not PassiveBatch: raise FakeAdapterError("fake adapter cannot accept a batch") self.send_count += 1 if self.send_count != 1: raise FakeAdapterError("second fake send is forbidden") self.sent_sha256 = hashlib.sha256(batch.payload).hexdigest() self.trace.append("FAKE_SEND_ONE_BATCH") self.state = "SENT" def next_event(self) -> FakeReceiveEvent: if self.state not in {"SENT", "RECEIVING"} or not self._events: raise FakeAdapterError("fake adapter has no next event") event = self._events.pop(0) self.clock.advance(event.advance_seconds) self.trace.append(f"FAKE_EVENT_{event.kind}") self.state = "RECEIVING" return event def close_once(self) -> None: if self.state not in {"OPEN", "SENT", "RECEIVING"}: raise FakeAdapterError("fake adapter cannot close") self.close_count += 1 if self.close_count != 1: raise FakeAdapterError("second fake close is forbidden") self._events.clear() self.logical_event_buffer_discarded = True self.trace.append("FAKE_CLOSE") self.state = "CLOSED" class OfflineFakeEvidenceStore(ExclusiveEvidenceStore): """Phase-specific exclusive local evidence; no raw transcript.""" def create_fake_consumed_receipt( self, plan: SessionPlan, batch: PassiveBatch, start: float, ) -> EvidenceRecord: return self._create(f"{plan.run_id}.aa-consumed.json", { "schema_version": 1, "status": "OFFLINE_FAKE_ATTEMPT_CONSUMED_BEFORE_OPEN", "run_id": plan.run_id, "phase10z_contract_sha256": PHASE10Z_CONTRACT_SHA256, "window": batch.window, "batch_sha256": hashlib.sha256(batch.payload).hexdigest(), "batch_size": len(batch.payload), "deadline_seconds": batch.deadline_seconds, "created_fake_monotonic": start, "target_retained": False, "raw_transcript_persisted": False, "retry_allowed": False, "reconnect_allowed": False, "resume_allowed": False, "device_behavior_proven": False, }) @dataclass(frozen=True) class OfflineFakeOutcome: receipt: EvidenceRecord output: EvidenceRecord classification: str exact_identity: bool batch_sha256: str trace: tuple[str, ...] fake_only: bool = True device_behavior_proven: bool = False def run_offline_fake_batch( plan: SessionPlan, adapter: OfflineFakeBatchAdapter, clock: OfflineFakeClock, evidence: OfflineFakeEvidenceStore, ) -> OfflineFakeOutcome: """Exercise Z end-to-end with exact built-in fakes and local evidence.""" if type(adapter) is not OfflineFakeBatchAdapter or \ type(clock) is not OfflineFakeClock or \ type(evidence) is not OfflineFakeEvidenceStore or \ adapter.clock is not clock: raise OfflineIntegrationError("offline fake boundary type is invalid") try: batch = build_passive_batch(plan) except PassiveContractError as error: raise OfflineIntegrationError("passive batch preparation failed") from error start = clock.monotonic() deadline = start + batch.deadline_seconds try: receipt = evidence.create_fake_consumed_receipt(plan, batch, start) except EvidenceFailure as error: raise OfflineIntegrationError("offline receipt creation failed") from error trace = ["RECEIPT_CREATED"] accumulator = PassiveResultAccumulator(batch) sanitized: dict[str, Any] | None = None opened = False failure: OfflineIntegrationError | None = None try: opened = True adapter.open_once() trace.extend(adapter.trace[-1:]) if clock.monotonic() >= deadline: raise OfflineIntegrationError("deadline reached before fake send") adapter.send_one_batch(batch) trace.extend(adapter.trace[-1:]) for _index in range(MAX_FAKE_EVENTS): event = adapter.next_event() trace.extend(adapter.trace[-1:]) now = clock.monotonic() if event.kind == EVENT_DATA: if now >= deadline: raise OfflineIntegrationError("fake data reached deadline") accumulator.feed_supplied_chunk(event.data) continue if event.kind == EVENT_HARD_DEADLINE: if now < deadline: raise OfflineIntegrationError("fake deadline arrived early") sanitized = accumulator.seal_at_hard_deadline(True) break if event.kind == EVENT_REMOTE_EOF: raise OfflineIntegrationError("remote EOF is not completion") if event.kind == EVENT_BLOCKED: raise OfflineIntegrationError("blocked fake receive is invalid") if sanitized is None: raise OfflineIntegrationError("hard deadline result is missing") except Exception as error: # noqa: BLE001 - exact fake boundary normalization failure = OfflineIntegrationError("offline fake integration failed") failure.__cause__ = error finally: if opened: try: adapter.close_once() trace.extend(adapter.trace[-1:]) except FakeAdapterError as error: if failure is None: failure = OfflineIntegrationError("offline fake close failed") failure.__cause__ = error if failure is not None: raise failure if sanitized is None or adapter.sent_sha256 is None: raise OfflineIntegrationError("offline fake result is incomplete") sanitized["phase10aa_fake_integration"] = { "offline_fake_only": True, "exact_builtin_adapter_required": True, "exact_builtin_clock_required": True, "receipt_created_before_fake_open": True, "one_fake_open": adapter.open_count == 1, "one_fake_batch_send": adapter.send_count == 1, "one_fake_close": adapter.close_count == 1, "logical_event_buffer_discarded": adapter.logical_event_buffer_discarded, "physical_memory_erasure_proven": False, "network_transport_present": False, "device_behavior_proven": False, } try: output = evidence.create_sanitized_output(plan, receipt, sanitized) except EvidenceFailure as error: raise OfflineIntegrationError("offline sanitized output failed") from error return OfflineFakeOutcome( receipt=receipt, output=output, classification=str(sanitized["classification"]), exact_identity=bool(sanitized["exact_identity"]), batch_sha256=adapter.sent_sha256, trace=tuple(trace), )