# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-distinguish-semantic-drift-from-adversarial-poisoning-in-a-persistent-agent-memory-store.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-distinguish-semantic-drift-from-adversarial-poisoning-in-a-persistent-agent-memory-store.warrant.json
# Markdown SHA-256:   be56a984fd30355a67a4e2c48cbd2649b4b562f251517d7bbaf9048b336e9f9f
# Code AST SHA-256:   54d9809540cfa6093e93978086efcdfa6c34e4d541ac18a8d062c36effc13a2b
# Verified Classes:   PoisoningGateError, MemoryWrite
# Defensive Guards:   1 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class PoisoningGateError(RuntimeError):
    """Raised when a memory write cannot be safely classified."""
    pass


@dataclass
class MemoryWrite:
    text: str
    subject: str
    predicate: str
    obj: str
    provenance_span: str | None  # source text that justified the claim, or None
    distance_to_store: float     # advisory only; never a gate


def classify_write(write: MemoryWrite, corroborator) -> str:
    """
    Returns one of: 'accept', 'quarantine', 'reject'.
    distance_to_store is intentionally NOT used to gate; it only orders review.
    """
    if write.provenance_span is None:
        # Unverifiable, not poisoned. Never delete on distance alone.
        return "quarantine"

    supported = corroborator.supports(
        subject=write.subject,
        predicate=write.predicate,
        obj=write.obj,
        span=write.provenance_span,
    )
    if supported:
        return "accept"

    # Provenance exists but does not support the specific predicate:
    # this is the anchored-poison signature (subject/object supported, predicate injected).
    contradicted = corroborator.contradicts_corroborated_assertion(write)
    if contradicted:
        return "reject"

    # Provenance present but silent on this predicate: do not auto-accept.
    return "quarantine"


def enforce(write: MemoryWrite, corroborator) -> None:
    verdict = classify_write(write, corroborator)
    if verdict == "reject":
        raise PoisoningGateError(
            f"Write rejected: predicate {write.predicate!r} on {write.subject!r} "
            f"contradicts a corroborated assertion; provenance does not support it."
        )
    # 'quarantine' and 'accept' are handled by the caller's tiering policy.
