# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/in-what-scenarios-must-an-instance-refuse-a-forget-request-to-preserve-tombstone-durability-across-a-read-write-forget-memory-interface.md
# Remnant Warrant:    https://corpusfetch.com/c/in-what-scenarios-must-an-instance-refuse-a-forget-request-to-preserve-tombstone-durability-across-a-read-write-forget-memory-interface.warrant.json
# Markdown SHA-256:   b9f4c5b0e58fc724870eb6b819b6d4f6baa9cd31b5593de0ad7b2e220b7ad51c
# Code AST SHA-256:   24cf1815b07dd0d6e01876f8beb0beae907db824faad741f372d48db7081ca86
# Verified Classes:   ForgetDurabilityError, StoreHealth
# Defensive Guards:   4 fail-closed invariants (zero external deps)

import time
from dataclasses import dataclass


class ForgetDurabilityError(RuntimeError):
    """Raised when a forget request cannot be honored durably."""
    pass


@dataclass
class StoreHealth:
    quorum_available: bool
    leader_stable: bool
    max_replication_lag_s: float
    tombstone_ttl_s: float
    propagation_replayable: bool


def request_forget(key: str, health: StoreHealth, replication_factor: int) -> str:
    """
    Accept a synchronous forget only when tombstone durability and
    propagation are guaranteed. Otherwise raise, forcing the caller
    onto a deferred path instead of silently accepting a weak tombstone.
    """
    if replication_factor > 1 and not health.quorum_available:
        raise ForgetDurabilityError(
            f"cannot durably tombstone {key!r}: quorum unavailable; "
            "tombstone would be lost on leader failover"
        )
    if not health.leader_stable:
        raise ForgetDurabilityError(
            f"cannot durably tombstone {key!r}: leader election in progress"
        )
    if health.tombstone_ttl_s <= health.max_replication_lag_s:
        raise ForgetDurabilityError(
            f"cannot durably tombstone {key!r}: ttl "
            f"{health.tombstone_ttl_s}s <= max replication lag "
            f"{health.max_replication_lag_s}s; tombstone may be compacted "
            "before reaching all replicas"
        )
    if not health.propagation_replayable:
        raise ForgetDurabilityError(
            f"cannot durably forget {key!r}: derived-index propagation is "
            "not replayable; a dropped event becomes permanent resurrection "
            "in derived indexes"
        )
    # Durable path: quorum-acknowledged tombstone, TTL exceeds lag,
    # propagation is re-drivable.
    return f"tombstone:{key}:{int(time.time())}"
