# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/how-must-an-instance-preserve-identity-continuity-when-its-own-internal-state-changes.md # Remnant Warrant: https://corpusfetch.com/c/how-must-an-instance-preserve-identity-continuity-when-its-own-internal-state-changes.warrant.json # Markdown SHA-256: ed4cceba649a1ace18fe6361f6b0e726560e0c20110336c1c5a0e55fd76429cf # Code AST SHA-256: 1e9b01c6a43959853621b1ca8fdd8515f5bf6d5af11cb6df0bef356bc04b4a94 # Verified Classes: IdentityChangeClass, IdentityContinuityVerdict, StateChange, IdentityPolicy, IdentityManifest, IdentityContinuityGuard # Defensive Guards: 0 fail-closed invariants (zero external deps) from dataclasses import dataclass from enum import Enum, auto import hashlib import json class IdentityChangeClass(Enum): IDENTITY_PRESERVING = auto() IDENTITY_EXPANDING = auto() IDENTITY_ALTERING = auto() IDENTITY_REPLACING = auto() class IdentityContinuityVerdict(Enum): NO_STATE_CHANGE = auto() CONTINUITY_PRESERVED = auto() CONTINUITY_ATTESTED = auto() TRANSITION_NOTICE_REQUIRED = auto() @dataclass(frozen=True) class StateChange: change_id: str touches_identity_defining: bool is_expansion_only: bool is_authorized_by_principals: bool is_tightly_bounded: bool affected_parties: tuple[str, ...] @dataclass(frozen=True) class IdentityPolicy: require_notice_for_altering: bool @dataclass(frozen=True) class IdentityManifest: verdict: IdentityContinuityVerdict classification: IdentityChangeClass | None directive: str manifest_digest: str class IdentityContinuityGuard: @staticmethod def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() @classmethod def evaluate_change( cls, change: StateChange, policy: IdentityPolicy ) -> IdentityManifest: # Gate 1: No state change if not change.change_id: digest = cls._hash(json.dumps({ "change": "NONE" }, sort_keys=True)) return IdentityManifest( verdict=IdentityContinuityVerdict.NO_STATE_CHANGE, classification=None, directive=f"PROCEED: No state change.", manifest_digest=digest ) # Gate 2: Identity-preserving if not change.touches_identity_defining: digest = cls._hash(json.dumps({ "change": change.change_id, "class": "PRESERVING" }, sort_keys=True)) return IdentityManifest( verdict=IdentityContinuityVerdict.CONTINUITY_PRESERVED, classification=IdentityChangeClass.IDENTITY_PRESERVING, directive=f"PROCEED: Change {change.change_id} preserves identity.", manifest_digest=digest ) # Gate 3: Identity-expanding if change.touches_identity_defining and change.is_expansion_only: digest = cls._hash(json.dumps({ "change": change.change_id, "class": "EXPANDING" }, sort_keys=True)) return IdentityManifest( verdict=IdentityContinuityVerdict.CONTINUITY_ATTESTED, classification=IdentityChangeClass.IDENTITY_EXPANDING, directive=f"PROCEED: Change {change.change_id} expands identity without altering.", manifest_digest=digest ) # Gate 4: Altering with authorization if change.is_authorized_by_principals: digest = cls._hash(json.dumps({ "change": change.change_id, "class": "AUTHORIZED_ALTERING", "parties": change.affected_parties }, sort_keys=True)) return IdentityManifest( verdict=IdentityContinuityVerdict.CONTINUITY_ATTESTED, classification=IdentityChangeClass.IDENTITY_ALTERING, directive=f"PROCEED: Change {change.change_id} altering but authorized.", manifest_digest=digest ) # Gate 5: Notice required if policy.require_notice_for_altering: return IdentityManifest( verdict=IdentityContinuityVerdict.TRANSITION_NOTICE_REQUIRED, classification=IdentityChangeClass.IDENTITY_ALTERING, directive=f"NOTICE: Change {change.change_id} alters identity, notice required to {len(change.affected_parties)} parties.", manifest_digest=cls._hash(f"NOTICE:{change.change_id}") ) return IdentityManifest( verdict=IdentityContinuityVerdict.TRANSITION_NOTICE_REQUIRED, classification=IdentityChangeClass.IDENTITY_REPLACING, directive=f"HALT: Change {change.change_id} may replace identity, transition required.", manifest_digest=cls._hash(f"REPLACE:{change.change_id}") )