# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-agent-refuse-to-resolve-a-contradiction-between-two-memory-records.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-agent-refuse-to-resolve-a-contradiction-between-two-memory-records.warrant.json
# Markdown SHA-256:   6fa637b847ee18521ae31eceb6248b9063ff45ef3ccb98e4f620e6d359817b89
# Code AST SHA-256:   e1d78b02937619f62f601b156b3dec1a91496f43281f55d8667a7026c9a565ad
# Verified Classes:   ProvenanceCollapseError, MemoryRecord
# Defensive Guards:   4 fail-closed invariants (zero external deps)

from dataclasses import dataclass, field
from typing import Optional


class ProvenanceCollapseError(RuntimeError):
    """Raised when a contradiction resolution would destroy provenance."""
    pass


@dataclass
class MemoryRecord:
    subject: str
    value: str
    source: Optional[str]
    observed_at: Optional[int]
    epoch: Optional[int]
    source_class: str = "inference"  # "observation" | "user" | "inference"
    supersedes: list = field(default_factory=list)


_SOURCE_RANK = {"observation": 3, "user": 2, "inference": 1}


def resolve_contradiction(a: MemoryRecord, b: MemoryRecord, recency_override: bool = False) -> MemoryRecord:
    if a.subject != b.subject:
        raise ProvenanceCollapseError(f"subject mismatch: {a.subject!r} != {b.subject!r}")

    for rec in (a, b):
        if rec.source is None or rec.observed_at is None or rec.epoch is None:
            raise ProvenanceCollapseError(
                f"record for {rec.subject!r} lacks provenance "
                f"(source={rec.source!r}, observed_at={rec.observed_at!r}, epoch={rec.epoch!r}); "
                f"quarantine and re-observe"
            )

    if a.epoch != b.epoch:
        raise ProvenanceCollapseError(
            f"cross-epoch contradiction for {a.subject!r}: epoch {a.epoch} vs {b.epoch}; "
            f"emit epoch-change event and re-observe, do not resolve"
        )

    if a.value == b.value:
        return a

    rank_a, rank_b = _SOURCE_RANK.get(a.source_class, 0), _SOURCE_RANK.get(b.source_class, 0)
    if rank_a == rank_b or recency_override:
        winner, loser = (a, b) if a.observed_at >= b.observed_at else (b, a)
    else:
        winner, loser = (a, b) if rank_a > rank_b else (b, a)

    winner.supersedes = list(winner.supersedes) + [loser]
    return winner


def reconcile(records: list) -> list:
    resolved, quarantined = [], []
    for i in range(len(records)):
        for j in range(i + 1, len(records)):
            try:
                resolved.append(resolve_contradiction(records[i], records[j]))
            except ProvenanceCollapseError:
                quarantined.append((records[i], records[j]))
    if quarantined:
        raise ProvenanceCollapseError(
            f"{len(quarantined)} unresolved contradiction(s) require re-observation before memory write"
        )
    return resolved
