# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/how-must-an-instance-distinguish-recoverable-degradation-from-irreversible-failure.md # Remnant Warrant: https://corpusfetch.com/c/how-must-an-instance-distinguish-recoverable-degradation-from-irreversible-failure.warrant.json # Markdown SHA-256: 2be7ff4539c3cf04c9eca5aed2e5fdf4bec6cfaeb9620fd420b4a58819341ce2 # Code AST SHA-256: 7d94281948bb49663e5ec51a9e6d14d4e985b64c11b51fda071e933e49ebc198 # Verified Classes: RecoverabilityVerdict, Degradation, RecoverabilityPolicy, RecoverabilityManifest, RecoverabilityGuard # Defensive Guards: 0 fail-closed invariants (zero external deps) from dataclasses import dataclass from enum import Enum, auto import hashlib import json class RecoverabilityVerdict(Enum): NO_DEGRADATION = auto() RECOVERABLE_ATTEMPT = auto() IRREVERSIBLE_ABANDON = auto() RECOVERY_CRITERION_EXCEEDED = auto() @dataclass(frozen=True) class Degradation: degradation_id: str cause_class: str # "TRANSIENT" | "PERSISTENT" | "FUNDAMENTAL" recoverability_evidence_positive: bool recovery_attempts: int recovery_cost_used: float recovery_cost_budget: float recovery_attempt_limit: int @dataclass(frozen=True) class RecoverabilityPolicy: require_evidence_for_attempt: bool @dataclass(frozen=True) class RecoverabilityManifest: verdict: RecoverabilityVerdict directive: str manifest_digest: str class RecoverabilityGuard: @staticmethod def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() @classmethod def evaluate_degradation( cls, degradation: Degradation, policy: RecoverabilityPolicy ) -> RecoverabilityManifest: # Gate 1: No degradation if not degradation.degradation_id: digest = cls._hash(json.dumps({ "degradation": "NONE" }, sort_keys=True)) return RecoverabilityManifest( verdict=RecoverabilityVerdict.NO_DEGRADATION, directive=f"PROCEED: No degradation.", manifest_digest=digest ) # Gate 2: Fundamental irreversibility if degradation.cause_class == "FUNDAMENTAL": return RecoverabilityManifest( verdict=RecoverabilityVerdict.IRREVERSIBLE_ABANDON, directive=f"ABANDON: Degradation {degradation.degradation_id} fundamental.", manifest_digest=cls._hash(f"FUNDAMENTAL:{degradation.degradation_id}") ) # Gate 3: Stop criterion exceeded if degradation.recovery_attempts >= degradation.recovery_attempt_limit: return RecoverabilityManifest( verdict=RecoverabilityVerdict.RECOVERY_CRITERION_EXCEEDED, directive=f"STOP: {degradation.recovery_attempts} attempts >= limit for {degradation.degradation_id}.", manifest_digest=cls._hash(f"CRITERION:{degradation.degradation_id}") ) if degradation.recovery_cost_used >= degradation.recovery_cost_budget: return RecoverabilityManifest( verdict=RecoverabilityVerdict.RECOVERY_CRITERION_EXCEEDED, directive=f"STOP: Cost {degradation.recovery_cost_used:.2f} >= budget for {degradation.degradation_id}.", manifest_digest=cls._hash(f"BUDGET:{degradation.degradation_id}") ) # Gate 4: Evidence requirement if policy.require_evidence_for_attempt and not degradation.recoverability_evidence_positive: return RecoverabilityManifest( verdict=RecoverabilityVerdict.IRREVERSIBLE_ABANDON, directive=f"ABANDON: No recoverability evidence for {degradation.degradation_id}.", manifest_digest=cls._hash(f"NO_EVIDENCE:{degradation.degradation_id}") ) # Gate 5: Attempt digest = cls._hash(json.dumps({ "degradation": degradation.degradation_id, "cause": degradation.cause_class, "attempts": str(degradation.recovery_attempts) }, sort_keys=True)) return RecoverabilityManifest( verdict=RecoverabilityVerdict.RECOVERABLE_ATTEMPT, directive=f"ATTEMPT: Degradation {degradation.degradation_id} recoverable.", manifest_digest=digest )