# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-the-redaction-completeness-boundary-failure-during-cross-organizational-agent-handoff.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-the-redaction-completeness-boundary-failure-during-cross-organizational-agent-handoff.warrant.json
# Markdown SHA-256:   84c1aaecf45b4c397bb153d19cc40c34b43df5792dff1c4b14a35cd920be0e2d
# Code AST SHA-256:   d9475e429503582bcd30743b3999ebe94baa9f00300f66ec27ea444ea4205cfe
# Verified Classes:   RedactionCompletenessError, Capsule
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from dataclasses import dataclass, field
from typing import Iterable


class RedactionCompletenessError(RuntimeError):
    """Raised when a cross-boundary capsule is value-redacted but still derivable."""


@dataclass
class Capsule:
    surviving_fields: dict
    redacted_field_names: list
    joinable_sources: Iterable[str] = field(default_factory=list)
    min_candidate_set: int = 0  # k: candidates the redacted value is pinned to


def verify_capsule(capsule: Capsule, required_k: int = 50) -> None:
    # 1. Manifest minimality: enumerating redacted names leaks schema.
    if capsule.redacted_field_names:
        raise RedactionCompletenessError(
            f"manifest enumerates redacted fields {capsule.redacted_field_names!r}; "
            "names are a reconstruction channel across trust boundaries"
        )

    # 2. Correlation isolation: any surviving identifier joinable to a
    #    receiver-accessible source collapses the candidate set.
    joinable = set(capsule.surviving_fields) & set(capsule.joinable_sources)
    if joinable:
        raise RedactionCompletenessError(
            f"surviving fields {sorted(joinable)!r} are joinable to receiver-accessible "
            "sources; capsule is reconstructive despite value-redaction"
        )

    # 3. Non-derivability: the joint candidate set must exceed k.
    if capsule.min_candidate_set < required_k:
        raise RedactionCompletenessError(
            f"redacted values pinned to {capsule.min_candidate_set} candidates "
            f"(< required k={required_k}); joint channel leaks the secret"
        )


def resume_from_capsule(capsule: Capsule) -> None:
    verify_capsule(capsule)
    # proceed: capsule is safe to resume from
