# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-happens-when-an-instance-downgrades-a-trusted-provenance-tier-mid-generation-taint-boundary-violation-in-provenance-tracked-rag.md
# Remnant Warrant:    https://corpusfetch.com/c/what-happens-when-an-instance-downgrades-a-trusted-provenance-tier-mid-generation-taint-boundary-violation-in-provenance-tracked-rag.warrant.json
# Markdown SHA-256:   5f2efa49eab812b24d603bc18660046e1d884d840acdd7ea3faa8bef2b732494
# Code AST SHA-256:   8dbd3d0ee7324380c90189f3400697d83134714d1c20af3c858f1804d184015b
# Verified Classes:   Tier, TaintBoundaryViolation, ContextSlot
# Defensive Guards:   2 fail-closed invariants (zero external deps)

from __future__ import annotations

from dataclasses import dataclass
from enum import IntEnum
from typing import Iterable


class Tier(IntEnum):
    TAINTED = 0
    UNVERIFIED = 1
    CURATED = 2
    SIGNED = 3


class TaintBoundaryViolation(RuntimeError):
    """Raised when emission-time provenance is weaker than admission-time provenance."""


@dataclass(frozen=True)
class ContextSlot:
    chunk_id: str
    admission_tier: Tier


def resolve_emission_tier(
    slots: Iterable[ContextSlot],
    fresh_lookup: dict[str, Tier],
    generation_seconds: float,
    provenance_change_interval: float,
) -> Tier:
    """Re-resolve provenance at emission and enforce the taint boundary.

    Collapses duplicate chunk_ids to the minimum tier across occurrences, then
    compares against the admission snapshot. Raises on any downgrade or on a
    generation that outlived the provenance-change budget.
    """
    if generation_seconds >= provenance_change_interval:
        raise TaintBoundaryViolation(
            f"generation ran {generation_seconds:.1f}s, provenance change "
            f"interval is {provenance_change_interval:.1f}s; admission-time "
            f"tier attestation is unsound"
        )

    slots = list(slots)
    if not slots:
        return Tier.TAINTED

    # Collapse duplicate chunk identity to the weakest occurrence.
    emission_by_chunk: dict[str, Tier] = {}
    for slot in slots:
        current = fresh_lookup.get(slot.chunk_id, Tier.TAINTED)
        prior = emission_by_chunk.get(slot.chunk_id)
        emission_by_chunk[slot.chunk_id] = current if prior is None else min(prior, current)

    # Any chunk whose emission tier is below its admission tier is a downgrade.
    for slot in slots:
        emission = emission_by_chunk[slot.chunk_id]
        if emission < slot.admission_tier:
            raise TaintBoundaryViolation(
                f"chunk {slot.chunk_id!r} downgraded from "
                f"{slot.admission_tier.name} at admission to "
                f"{emission.name} at emission"
            )

    # The output tier is the weakest emission tier across all admitted chunks.
    return min(emission_by_chunk.values())


def stamp_output(
    slots: Iterable[ContextSlot],
    fresh_lookup: dict[str, Tier],
    generation_seconds: float,
    provenance_change_interval: float,
) -> dict[str, object]:
    tier = resolve_emission_tier(
        slots, fresh_lookup, generation_seconds, provenance_change_interval
    )
    return {"attested_tier": tier.name, "skew": False}
