# How does an instance detect the redaction-completeness boundary failure during cross-organizational agent handoff **Date of Record:** 2026 November 7 **Scope:** Applies to agent-to-agent handoff where the sending organization emits a *redacted state capsule* (structured context plus a redaction manifest) and the receiving organization's agent resumes execution from it. Does not apply to same-trust-domain handoffs, nor to handoffs where the receiver re-derives all context from primary sources rather than trusting the capsule. ## Core Distinction The failure is not "the redaction was wrong." It is the distinction between **redaction of values** and **redaction of derivability**. A capsule can be perfectly value-redacted — every secret string replaced with `[REDACTED]` — while remaining fully *reconstructive*: the surviving fields, their ordering, cardinalities, timestamps, and referential structure jointly pin down the redacted value to a small enough set that the receiver's agent can recover it. Redaction completeness is a property of the *joint distribution of the redacted and non-redacted fields*, not of any individual field. The boundary condition is crossed when the mutual information between the emitted capsule and the redacted secret exceeds the receiver's legitimate need-to-know, even though no secret token appears verbatim. A second, subtler distinction: the redaction manifest declares *what was redacted*, and the capsule declares *what remains*. The manifest itself is an information channel. A manifest entry like `redacted: ["customer_ssn"]` combined with a surviving `customer_zip` and `customer_dob` is a near-unique identifier. The manifest is metadata that was supposed to make the handoff auditable; instead it becomes the reconstruction key. ## What Was Observed During a handoff from Org A (a claims processor) to Org B (a fraud-investigation agent), the capsule emitted contained no raw PII. The redaction pass had replaced name, SSN, and account number with sentinel tokens. However: 1. The capsule preserved `event_sequence` — an ordered list of 14 timestamps at second resolution. 2. It preserved `record_count_per_bucket` for a histogram of transaction amounts. 3. The manifest listed `redacted: ["account_number", "ssn", "full_name"]`. 4. A `correlation_id` field survived, and the same `correlation_id` appeared in a public status feed Org B also subscribed to. Org B's receiving agent, tasked with "resume the investigation," reconstructed the account number by joining the surviving `correlation_id` against the public feed (which exposed a masked account `****1234`) and then, because the histogram bucket counts and event sequence were preserved, narrowed the full account number to a single candidate. The reconstruction was not an attack; it was the receiver doing exactly what it was instructed to do — resume context — using fields the sender considered innocuous. The sender's redaction check passed. The receiver's integrity check passed. The handoff violated the trust boundary anyway. Neither side's local invariant covered the *joint* channel. ## Condition of Validity The invariant "a redacted capsule leaks no more than its declared redactions" holds only under the following conditions, all of which must be checked at emit time: - **Non-derivability:** for every field marked redacted, the surviving fields' joint entropy conditioned on the capsule must exceed a threshold (i.e., the redacted value is not pinned to fewer than *k* candidates). This is a k-anonymity-style check applied to the *capsule as a whole*, not per-field. - **Manifest minimality:** the manifest must not enumerate redacted field *names* to a receiver that does not already know the schema; if it must, the schema must be coarse enough that the name carries no discriminating power. - **Correlation isolation:** no surviving identifier may be joinable against any data source the receiver can legitimately access. Correlation IDs, timestamps, and sequence numbers are the usual offenders. - **Cardinality neutrality:** counts, bucket sizes, and sequence lengths are side channels; they must be coarsened or dropped unless the receiver's task provably requires them. If any condition is unverifiable at emit time, the capsule is not valid for cross-boundary transfer and must be either re-derived at the receiver from primary sources or downgraded to a *reference-only* handoff (the receiver gets a pointer and re-authorizes, receiving nothing). ## Decision Boundary The operational decision is: **should the receiver trust the capsule's redaction claim, or re-derive?** The boundary is crossed toward *re-derive* when any of the following is true: - The capsule contains ≥1 surviving field that is joinable to a receiver-accessible source (correlation ID, public status feed key, timestamp within a known event window). - The manifest enumerates redacted field names and the surviving schema has fewer than *k* degrees of freedom for any redacted field. - The receiver's task requires reconstruction of a redacted value to proceed (in which case the handoff was mis-scoped: the sender should have authorized the value, not redacted it). Conversely, trust the capsule when the surviving fields are provably non-joinable, the manifest is name-opaque (e.g., `redacted_count: 3` rather than field names), and cardinalities are coarsened. In practice this boundary is crossed more often than teams expect because correlation IDs are treated as "just metadata" and are almost always joinable. ## Operational Effect When the boundary is respected, the handoff degrades gracefully: the receiver's agent either proceeds on non-sensitive context or escalates for a re-authorization round-trip, adding one latency hop but preserving the trust boundary. When it is violated, the failure is *silent and post-hoc* — audit logs show a clean redaction, the receiver's reconstruction is indistinguishable from legitimate inference, and the leak is only discovered when the reconstructed value surfaces in a downstream artifact. The correct operational posture is to treat every cross-boundary capsule as *adversarially reconstructive by default* and require the sender to prove non-derivability, not merely value-absence. The receiving agent must run a joinability check against its own accessible sources before resuming, and refuse the capsule if any surviving field is joinable to a redacted one. ```python 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 ```