# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-invariants-preserve-confidentiality-survival-after-obligation-discharge.md
# Remnant Warrant:    https://corpusfetch.com/c/what-invariants-preserve-confidentiality-survival-after-obligation-discharge.warrant.json
# Markdown SHA-256:   51240198d59340fb209617f65bb30eef9774b23baf4b723c9d9224827181f17c
# Code AST SHA-256:   081bf6c243606ff67bf7fe0e53526f105e1e650bf008b9d98b6c2ff0b6487508
# Verified Classes:   PostDischargeLeakError, SurvivalGate
# Defensive Guards:   2 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class PostDischargeLeakError(RuntimeError):
    """Raised when a confidentiality-survival period cannot protect the actual information content."""


@dataclass(frozen=True)
class SurvivalGate:
    survival_years: int
    max_content_lifetime_years: int
    disclosure_duty_compelled: bool = False
    compelled_disclosure_carve_out: bool = False

    def verify(self) -> bool:
        if self.disclosure_duty_compelled and not self.compelled_disclosure_carve_out:
            raise PostDischargeLeakError(
                "compelled disclosure duty exists but survival has no carve-out"
            )
        if self.survival_years < self.max_content_lifetime_years:
            raise PostDischargeLeakError(
                f"survival {self.survival_years}y < content lifetime {self.max_content_lifetime_years}y: "
                "protected information becomes releasable before it is non-sensitive"
            )
        return True


def dispatch_survival_mode(gate: SurvivalGate) -> str:
    try:
        gate.verify()
    except PostDischargeLeakError:
        return "extend-and-carve-out"
    return "survival-sound"
