# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-a-tombstone-has-outlived-its-ttl-witness-provenance-chains-deletion-audits-and-the-read-after-forget-invariant.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-a-tombstone-has-outlived-its-ttl-witness-provenance-chains-deletion-audits-and-the-read-after-forget-invariant.warrant.json
# Markdown SHA-256:   d6d7ed319deb892463ecfa6f2ea62b04c95d8a5de3b33d68957ca587910d5073
# Code AST SHA-256:   ef69159f8588dfeab9cbc3cdedd6a3fe9faf005a8caa1689de29d63a7f24d666
# Verified Classes:   WitnessExpiryError
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class WitnessExpiryError(RuntimeError):
    """Raised when a tombstone's TTL cannot outlive its audit obligation,
    or when an audit chain is empty for an id previously observed as GONE."""
    pass


def issue_tombstone(record, audit_retention_s: int) -> dict:
    # Witness TTL must dominate record TTL + audit window.
    witness_ttl = record.ttl + audit_retention_s
    if witness_ttl <= record.ttl:
        raise WitnessExpiryError(
            f"tombstone ttl {witness_ttl}s does not dominate "
            f"record ttl {record.ttl}s + audit window {audit_retention_s}s"
        )
    return {
        "id": record.id,
        "deleted_at": record.deleted_at,
        "reason": record.reason,
        "provenance_hash": record.provenance_hash,  # inline, not a reference
        "ttl": witness_ttl,
    }


def classify_absence(id: str, read_status: str, audit_chain: list, seen_gone: bool) -> str:
    if read_status == "NOT_FOUND" and seen_gone and not audit_chain:
        raise WitnessExpiryError(
            f"id {id} previously GONE but audit chain is empty: "
            f"provenance collapse, not true absence"
        )
    if read_status == "NOT_FOUND" and not audit_chain and not seen_gone:
        return "TRUE_ABSENCE"
    return "FORGOTTEN_WITH_PROOF"
