# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-lossy-compaction-has-crossed-the-rehydration-boundary.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-lossy-compaction-has-crossed-the-rehydration-boundary.warrant.json
# Markdown SHA-256:   91ca10684645b71c18a2f094472fef56e0d2626097dc281bfc07223bb2dacf88
# Code AST SHA-256:   9b7577ed25535d4803200d17894757a35db7af02bbe51150c1a67456ad08f63a
# Verified Classes:   RehydrationBoundaryError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class RehydrationBoundaryError(RuntimeError):
    """Raised when a summary claim cannot be substantiated by retrieval at the point of use."""
    pass


def assert_claim_substantiated(claim: dict, retrieval) -> dict:
    """
    claim: {
        "text": str,
        "self_sufficient": bool,
        "dependency_key": str | None,
    }
    retrieval: object exposing .fetch(key) -> {"status": "ok"|"empty"|"tombstone", "span": str}
    Returns the substantiating span, or raises if the claim is unbacked.
    """
    if claim["self_sufficient"]:
        return {"span": claim["text"], "source": "summary"}

    key = claim["dependency_key"]
    if key is None:
        raise RehydrationBoundaryError(
            f"Claim {claim['text']!r} is not self-sufficient and has no derivable "
            f"dependency key; it cannot be substantiated."
        )

    result = retrieval.fetch(key)
    if result["status"] == "tombstone":
        raise RehydrationBoundaryError(
            f"Dependency key {key!r} resolves to a tombstone; the span was re-chunked "
            f"or evicted after compaction. Summary authority has decayed."
        )
    if result["status"] == "empty":
        raise RehydrationBoundaryError(
            f"Dependency key {key!r} returned empty context; treating as unbacked "
            f"rather than silently proceeding on summary authority."
        )
    if result["status"] != "ok":
        raise RehydrationBoundaryError(
            f"Unexpected retrieval status {result['status']!r} for key {key!r}."
        )

    # Polarity/quantifier re-check happens here against result["span"] before use.
    return {"span": result["span"], "source": "retrieval"}


def pre_action_gate(claims: list[dict], retrieval) -> list[dict]:
    """Fail closed: any unbacked claim blocks the irreversible action."""
    substantiated = []
    for claim in claims:
        substantiated.append(assert_claim_substantiated(claim, retrieval))
    return substantiated
