# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-a-write-audit-diff-as-evidence-of-poisoning-rather-than-as-a-legitimate-consolidation-event.md
# Remnant Warrant:    https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-a-write-audit-diff-as-evidence-of-poisoning-rather-than-as-a-legitimate-consolidation-event.warrant.json
# Markdown SHA-256:   181a1ff96275ffaf94d3c4836b6818cba73951d0a50743557069943e0f5639de
# Code AST SHA-256:   12247cfb6deaa6436a638a2da08e5c42df71b25276fcaf8f8b4f988b350b1b28
# Verified Classes:   PoisoningEvidenceError, DiffRecord
# Defensive Guards:   2 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass


class PoisoningEvidenceError(RuntimeError):
    """Raised when a write-audit diff cannot be classified as consolidation or poisoning."""
    pass


@dataclass(frozen=True)
class DiffRecord:
    record_id: str
    snapshot_pair: tuple[str, str]
    pre_hash: str
    post_hash: str
    provenance_changed: bool
    invariant_holds: bool
    manifest_entry: dict | None  # None means orphaned


def classify_diff(diff: DiffRecord, audit_chain_valid: bool) -> str:
    if not audit_chain_valid:
        # Without a valid hash chain the manifest is forgeable; no diff is trustworthy.
        raise PoisoningEvidenceError(
            f"audit chain invalid for {diff.record_id}; cannot classify diff"
        )

    if diff.manifest_entry is None:
        if diff.provenance_changed:
            return "poisoning_evidence"
        if diff.invariant_holds:
            return "indeterminate"
        return "poisoning_evidence"

    expected = diff.manifest_entry.get("expected_hash_after")
    if expected is not None and expected != diff.post_hash:
        return "poisoning_evidence"

    if not diff.invariant_holds:
        # Manifest explains that a rewrite happened, not that it was allowed.
        return "poisoning_evidence"

    return "benign_consolidation"


def audit_window(diffs: list[DiffRecord], audit_chain_valid: bool) -> dict[str, list[str]]:
    buckets: dict[str, list[str]] = {
        "poisoning_evidence": [],
        "indeterminate": [],
        "benign_consolidation": [],
    }
    for d in diffs:
        verdict = classify_diff(d, audit_chain_valid)
        buckets[verdict].append(d.record_id)

    if buckets["poisoning_evidence"]:
        raise PoisoningEvidenceError(
            f"poisoning evidence in window: {buckets['poisoning_evidence']}"
        )
    return buckets
