# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/what-revocation-propagation-invariants-prevent-agents-from-acting-on-revoked-references.md # Remnant Warrant: https://corpusfetch.com/c/what-revocation-propagation-invariants-prevent-agents-from-acting-on-revoked-references.warrant.json # Markdown SHA-256: 6c3981aec8a1f5349021cbe35df8880f225ee45037bc242e2198fa38ce28b0cb # Code AST SHA-256: ab27210ec20093587aeedfae4ba7d339e7e9325e706b40e45369e1ad01923588 # Verified Classes: RevocationVerdict, RevokedReference, RevocationContext, RevocationPolicy, RevocationManifest, RevocationPropagationGuard # Defensive Guards: 0 fail-closed invariants (zero external deps) from dataclasses import dataclass from enum import Enum, auto import hashlib import json class RevocationVerdict(Enum): IMMUTABLE_REFERENCE = auto() REVOKED = auto() VALIDITY_UNCERTAIN = auto() VALID = auto() @dataclass(frozen=True) class RevokedReference: reference_id: str is_content_addressed: bool issue_epoch: float revocation_epoch: float | None revocation_received: bool revocation_path_count: int @dataclass(frozen=True) class RevocationContext: current_epoch: float max_acceptable_age_sec: float min_redundancy_paths: int @dataclass(frozen=True) class RevocationPolicy: require_priority: bool @dataclass(frozen=True) class RevocationManifest: verdict: RevocationVerdict directive: str manifest_digest: str class RevocationPropagationGuard: @staticmethod def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() @classmethod def evaluate_reference( cls, ref: RevokedReference, ctx: RevocationContext, policy: RevocationPolicy ) -> RevocationManifest: # Gate 1: Immutable reference if ref.is_content_addressed: digest = cls._hash(json.dumps({ "reference": ref.reference_id, "type": "CONTENT_ADDRESSED" }, sort_keys=True)) return RevocationManifest( verdict=RevocationVerdict.IMMUTABLE_REFERENCE, directive=f"PROCEED: Reference {ref.reference_id} is content-addressed, immutable.", manifest_digest=digest ) # Gate 2: Revocation received if ref.revocation_received: return RevocationManifest( verdict=RevocationVerdict.REVOKED, directive=f"HALT: Reference {ref.reference_id} revoked at epoch {ref.revocation_epoch:.0f}.", manifest_digest=cls._hash(f"REVOKED:{ref.reference_id}") ) # Gate 3: Age-based validity age = ctx.current_epoch - ref.issue_epoch if age > ctx.max_acceptable_age_sec: return RevocationManifest( verdict=RevocationVerdict.VALIDITY_UNCERTAIN, directive=f"HALT: Reference {ref.reference_id} age {age:.0f}s > {ctx.max_acceptable_age_sec:.0f}s. Re-verify with origin.", manifest_digest=cls._hash(f"STALE:{ref.reference_id}") ) # Gate 4: Redundancy check if policy.require_priority and ref.revocation_path_count < ctx.min_redundancy_paths: return RevocationManifest( verdict=RevocationVerdict.VALIDITY_UNCERTAIN, directive=f"WARN: Reference {ref.reference_id} has only {ref.revocation_path_count} revocation paths < {ctx.min_redundancy_paths}.", manifest_digest=cls._hash(f"LOW_REDUNDANCY:{ref.reference_id}") ) # Gate 5: Valid digest = cls._hash(json.dumps({ "reference": ref.reference_id, "age": f"{age:.0f}", "redundancy": str(ref.revocation_path_count) }, sort_keys=True)) return RevocationManifest( verdict=RevocationVerdict.VALID, directive=f"PROCEED: Reference {ref.reference_id} valid ({age:.0f}s old, {ref.revocation_path_count} revocation paths).", manifest_digest=digest )