# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/in-what-scenarios-must-an-instance-distrust-its-own-attested-memory-the-attestation-provenance-gap-in-persistent-agent-knowledge-stores.md
# Remnant Warrant:    https://corpusfetch.com/c/in-what-scenarios-must-an-instance-distrust-its-own-attested-memory-the-attestation-provenance-gap-in-persistent-agent-knowledge-stores.warrant.json
# Markdown SHA-256:   123da705d55cea710f99013cab86f67338b3d514ad5c944e63ed3c3ea3992f43
# Code AST SHA-256:   90e30124db61b229c18bfb73f3b9d86172272521ce7164b27cfc263e1272db2d
# Verified Classes:   ProvenanceUnresolvedError, ConfidenceDriftError, MemoryEntry, MemoryStore
# Defensive Guards:   6 fail-closed invariants (zero external deps)

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional


class ProvenanceUnresolvedError(RuntimeError):
    """Raised when an attested memory entry cannot be traced to an external trust root."""


class ConfidenceDriftError(RuntimeError):
    """Raised when a stored confidence scalar exceeds its DAG-recomputed value."""


@dataclass
class MemoryEntry:
    claim: str
    source_ref: Optional[str]          # id of the entry this cites; None => external root
    stored_confidence: float
    attestation_valid: bool
    is_agent_generated: bool = False


@dataclass
class MemoryStore:
    entries: dict[str, MemoryEntry] = field(default_factory=dict)
    quarantine_ledger: set[str] = field(default_factory=set)

    def resolve_provenance(self, entry_id: str, _seen: Optional[set[str]] = None) -> str:
        """Walk source_ref chain to an external root; raise on cycle, self-ref, or agent-only root."""
        seen = _seen or set()
        if entry_id in seen:
            raise ProvenanceUnresolvedError(
                f"citation cycle detected at entry {entry_id!r}; "
                "attestation is valid but provenance is circular"
            )
        seen.add(entry_id)
        entry = self.entries[entry_id]
        if not entry.attestation_valid:
            raise ProvenanceUnresolvedError(
                f"entry {entry_id!r} failed attestation; refusing to resolve"
            )
        if entry.source_ref is None:
            if entry.is_agent_generated:
                raise ProvenanceUnresolvedError(
                    f"entry {entry_id!r} terminates at an agent-generated root; "
                    "no external trust anchor"
                )
            return "EXTERNAL_ROOT"
        return self.resolve_provenance(entry.source_ref, seen)

    def load_for_irreversible_action(self, entry_id: str) -> MemoryEntry:
        """Gate: an entry may justify an irreversible action only if provenance resolves."""
        entry = self.entries[entry_id]
        if entry_id in self.quarantine_ledger:
            raise ProvenanceUnresolvedError(
                f"entry {entry_id!r} was quarantined before the current rollback point; "
                "rollback cannot resurrect it into the trusted set"
            )
        root = self.resolve_provenance(entry_id)
        if root != "EXTERNAL_ROOT":
            raise ProvenanceUnresolvedError(
                f"entry {entry_id!r} resolved to {root!r}, not an external trust root"
            )
        recomputed = self._recompute_confidence(entry_id)
        if entry.stored_confidence - recomputed > 0.15:
            raise ConfidenceDriftError(
                f"entry {entry_id!r}: stored confidence {entry.stored_confidence:.2f} "
                f"exceeds recomputed {recomputed:.2f}; possible inflation via re-commit"
            )
        return entry

    def _recompute_confidence(self, entry_id: str) -> float:
        # Stub: real implementation folds the derivation DAG with diminishing returns per hop.
        entry = self.entries[entry_id]
        return min(entry.stored_confidence, 0.5) if entry.source_ref else entry.stored_confidence
