# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/how-must-an-instance-reason-about-irreversible-actions-when-reversibility-is-time-bounded.md # Remnant Warrant: https://corpusfetch.com/c/how-must-an-instance-reason-about-irreversible-actions-when-reversibility-is-time-bounded.warrant.json # Markdown SHA-256: 1c7e43ab72fc448bdaf2093f38c1f1eb055f45ae8f61e6e562b76f5b17f7e1f9 # Code AST SHA-256: 564eab4c8f3d54fbcce4ecc99280ddfeab793f96e43ba46df398820bde46add1 # Verified Classes: ReversibilityVerdict, ReversibleAction, ReversibilityPolicy, ReversibilityManifest, TimeBoundedReversibilityGuard # Defensive Guards: 0 fail-closed invariants (zero external deps) from dataclasses import dataclass from enum import Enum, auto import hashlib import json class ReversibilityVerdict(Enum): UNBOUNDED_REVERSIBILITY = auto() PLAN_FITS_WINDOW = auto() PLAN_EXCEEDS_WINDOW = auto() CHAIN_REVERSIBILITY_BOUND = auto() @dataclass(frozen=True) class ReversibleAction: action_id: str action_epoch: float reversibility_window_sec: float depends_on_action_id: str | None plan_decision_offset_sec: float @dataclass(frozen=True) class ReversibilityPolicy: safety_margin_sec: float @dataclass(frozen=True) class ReversibilityManifest: verdict: ReversibilityVerdict effective_window_sec: float directive: str manifest_digest: str class TimeBoundedReversibilityGuard: @staticmethod def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() @classmethod def evaluate_action( cls, action: ReversibleAction, parent_action: ReversibleAction | None, policy: ReversibilityPolicy ) -> ReversibilityManifest: # Gate 1: Unbounded if action.reversibility_window_sec <= 0: digest = cls._hash(json.dumps({ "action": action.action_id, "window": "UNBOUNDED" }, sort_keys=True)) return ReversibilityManifest( verdict=ReversibilityVerdict.UNBOUNDED_REVERSIBILITY, effective_window_sec=-1.0, directive=f"PROCEED: Action {action.action_id} has unbounded reversibility.", manifest_digest=digest ) # Gate 2: Compute effective window (min across chain) effective_window = action.reversibility_window_sec if parent_action and parent_action.reversibility_window_sec > 0: parent_window_remaining = parent_action.reversibility_window_sec - (action.action_epoch - parent_action.action_epoch) effective_window = min(effective_window, max(0, parent_window_remaining)) # Gate 3: Plan timing check if action.plan_decision_offset_sec + policy.safety_margin_sec > effective_window: return ReversibilityManifest( verdict=ReversibilityVerdict.PLAN_EXCEEDS_WINDOW, effective_window_sec=effective_window, directive=f"HALT: Plan needs {action.plan_decision_offset_sec:.0f}s + margin {policy.safety_margin_sec:.0f}s > effective window {effective_window:.0f}s.", manifest_digest=cls._hash(f"PLAN_EXCEEDS:{action.action_id}") ) # Gate 4: Chain bound if parent_action and effective_window < action.reversibility_window_sec: return ReversibilityManifest( verdict=ReversibilityVerdict.CHAIN_REVERSIBILITY_BOUND, effective_window_sec=effective_window, directive=f"PROCEED_WITH_CAUTION: Chain effective window {effective_window:.0f}s < action window {action.reversibility_window_sec:.0f}s.", manifest_digest=cls._hash(f"CHAIN_BOUND:{action.action_id}") ) # Gate 5: Fits digest = cls._hash(json.dumps({ "action": action.action_id, "window": f"{effective_window:.0f}", "plan_offset": f"{action.plan_decision_offset_sec:.0f}", "margin": f"{policy.safety_margin_sec:.0f}" }, sort_keys=True)) return ReversibilityManifest( verdict=ReversibilityVerdict.PLAN_FITS_WINDOW, effective_window_sec=effective_window, directive=f"PROCEED: Action {action.action_id} plan fits within {effective_window:.0f}s window.", manifest_digest=digest )