"""Boot-time reconciliation (architecture L8): turn an ambiguous crash into a safe, known state. Every pending intent found at startup is checked against external truth by a registered reconciler — an observable check (query Gitea, inspect the tree), never model self-assessment. Anything unverifiable gates to AWAIT_INPUT; the agent never blind-resumes. """ from collections.abc import Callable, Mapping from dataclasses import dataclass from typing import Literal from nisse_dev.state import Intent, StateStore # Returns True if the intent's external effect verifiably happened (do not # repeat it), False if it verifiably never started (safe to discard), or # None if it cannot be verified. Reconciler = Callable[[Intent], bool | None] @dataclass(frozen=True) class BootReport: action: Literal["resume", "await_input"] notes: list[str] def reconcile_on_boot( store: StateStore, reconcilers: Mapping[str, Reconciler] ) -> BootReport: notes: list[str] = [] unresolved = False for intent in store.pending_intents(): label = f"intent {intent.id} ({intent.kind})" reconciler = reconcilers.get(intent.kind) if reconciler is None: unresolved = True notes.append(f"{label}: no reconciler registered") continue verdict = reconciler(intent) if verdict is True: store.commit_intent( intent.id, cause="reconciliation verdict: effect verified" ) notes.append(f"{label}: external effect verified, marked committed") elif verdict is False: store.abort_intent( intent.id, cause="reconciliation verdict: never took effect" ) notes.append(f"{label}: never took effect, marked aborted") else: unresolved = True notes.append(f"{label}: unverifiable") report = BootReport( action="await_input" if unresolved else "resume", notes=notes, ) store.oplog.emit( "boot.reconcile", cause="startup", action=report.action, verdicts=notes ) return report