# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-happens-when-an-instance-compacts-a-context-window-whose-fidelity-budget-is-exhausted-mid-summarization.md
# Remnant Warrant:    https://corpusfetch.com/c/what-happens-when-an-instance-compacts-a-context-window-whose-fidelity-budget-is-exhausted-mid-summarization.warrant.json
# Markdown SHA-256:   b9ac692cf808b9f7b47e57b7940dd7af7b450dde0e7ab4deef3d08c50044b30d
# Code AST SHA-256:   3550ccafe6c00bbeae6ccc6c3e31a26b5fdb8d9b8be443010b4ecf1cb32f9dfd
# Verified Classes:   FidelityBudgetExhausted
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class FidelityBudgetExhausted(RuntimeError):
    """Raised when a compaction checkpoint cannot cover a span segment within budget."""
    pass


def compact_span(span_tokens: int, budget_tokens: int, min_facts_per_segment: int,
                 segments: list[dict]) -> dict:
    """
    segments: list of {"name": str, "tokens": int, "facts": int}
    Fails loudly if any segment's source-to-summary ratio exceeds the coverage ceiling
    or if per-segment fact floor cannot be met within remaining budget.
    """
    COVERAGE_CEILING = 40.0  # source tokens per summary token, hard cap
    remaining = budget_tokens
    checkpoint = {"segments": [], "uncovered": []}

    for seg in segments:
        # Proportional allocation, but bounded by the coverage ceiling.
        alloc = max(1, round(seg["tokens"] * budget_tokens / span_tokens))
        ratio = seg["tokens"] / alloc

        if ratio > COVERAGE_CEILING:
            raise FidelityBudgetExhausted(
                f"segment {seg['name']!r}: ratio {ratio:.1f}:1 exceeds ceiling "
                f"{COVERAGE_CEILING}:1; externalize or mark uncovered"
            )
        if alloc > remaining:
            raise FidelityBudgetExhausted(
                f"segment {seg['name']!r}: needs {alloc} tokens, {remaining} remain; "
                f"budget exhausted mid-span — do not emit gloss"
            )
        if seg["facts"] < min_facts_per_segment:
            raise FidelityBudgetExhausted(
                f"segment {seg['name']!r}: {seg['facts']} facts < floor "
                f"{min_facts_per_segment}; aggregate floor is not a per-segment floor"
            )

        remaining -= alloc
        checkpoint["segments"].append(
            {"name": seg["name"], "summary_tokens": alloc, "ratio": round(ratio, 1)}
        )

    return checkpoint
