# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-does-a-soft-delete-flag-prevent-a-key-from-ever-being-reused.md
# Remnant Warrant:    https://corpusfetch.com/c/when-does-a-soft-delete-flag-prevent-a-key-from-ever-being-reused.warrant.json
# Markdown SHA-256:   5f8d7e66f655ef962a1cbae8ceaa1b2685ac068ce52c03583720c6b13a5789fc
# Code AST SHA-256:   76e8813beab8fe435319d5294aa2571a8e445f7a69f49ed725e573b7cac6e20d
# Verified Classes:   KeyReuseBlockedError, SoftDeleteGate
# Defensive Guards:   1 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class KeyReuseBlockedError(RuntimeError):
    """Raised when a soft-deleted row permanently reserves a natural key."""


@dataclass(frozen=True)
class SoftDeleteGate:
    unique_includes_tombstones: bool
    partial_index: bool = False
    tombstone_discriminator: bool = False
    purge_days: int = 0

    def verify(self, audit_required: bool = True) -> bool:
        if self.partial_index or self.tombstone_discriminator:
            return True
        if self.unique_includes_tombstones and self.purge_days > 0 and not audit_required:
            return True
        if self.unique_includes_tombstones:
            raise KeyReuseBlockedError(
                "unique index covers deleted rows with no purge: key cannot be reused"
            )
        return True


def dispatch_delete_strategy(gate: SoftDeleteGate, audit_required: bool = True) -> str:
    try:
        gate.verify(audit_required)
    except KeyReuseBlockedError:
        return "partial-index"
    return "unique-with-purge" if gate.purge_days else "unique-live-only"
