Diagnosing a Case-Isolation Leak in a Cross-Matter Dedup Index

A cross-matter deduplication index that lets one matter observe another’s review decisions — or even learn that a document exists in another matter — is an ethical-wall breach, not a bug to be triaged casually. This is the defining failure of cross-matter deduplication: the shared index was supposed to reuse only content-derived processing artifacts, but somewhere a matter-derived value or a membership signal crossed the boundary. The leak violates the case-isolation guarantee that the whole subsystem exists to protect, and because it can expose privileged work-product across a wall, it is a defensibility and professional-responsibility problem at once. This guide isolates how isolation leaks happen and delivers the audit and remediation that seals the boundary.

Diagnostic Log Signatures

An isolation audit surfaces the leak by replaying cross-matter queries and inspecting what was returned. Capture it verbatim.

text
[INFO] Isolation audit: index=global_v3, matters=44, queries_replayed=210114
[ERROR] leaked_disposition matter=B digest=9f2c… returned disposition='privileged' (origin matter=A)
[ERROR] membership_disclosed matter=C query returned matter_count=6 for digest=1ab7…
[WARN] shared_log_entry: cross-matter hit written to a global log readable by all matters
[CRITICAL] Isolation BREACH: matter-derived state crossed the case boundary

Symptom checklist — any single one is a breach:

  • A query from one matter returns a review disposition, privilege tag, or family assignment that originated in another matter.
  • The index reveals how many matters contain a digest, or which ones.
  • Cross-matter cache hits are written to a log that another matter can read.
  • A “shareable” artifact type turns out to encode matter-specific information (e.g., a render stamped with a matter name).
  • Suppression in one matter is driven by a decision made in another matter.

Root-Cause Breakdown

Every isolation leak is a piece of matter-derived state escaping through a channel that was assumed to be content-only.

  1. Unclassified artifact cached globally. A new artifact type — a “review summary,” an enriched-metadata blob — was written to the shared index without being classified, and it carried matter-derived content. The fix is a strict allowlist: only explicitly content-derived types may be cached, everything else stays private.
  2. Membership as an implicit leak. The index answered “which matters have this digest” or returned a matter count, treating membership as harmless. It is not — the mere fact that a document spans several matters is sensitive. Storing any matter identity in the shared index is the root cause.
  3. Cross-matter suppression. Review suppression consulted a global disposition table rather than the requesting matter’s own store, so a decision made in Matter A suppressed (and thereby disclosed) into Matter B. Suppression must read only same-matter state.
  4. Shared audit log. Cache hits were logged centrally, so one matter’s audit trail exposed another matter’s activity. Audit entries must live in the requesting matter’s own log.
  5. Content artifact carrying matter data. A rendered image or extracted text was stamped or enriched with a matter identifier, turning a nominally content-derived artifact into a matter-derived one.

Remediation Architecture

Seal each channel: allowlist shareable types, strip matter identity from the index, scope suppression and logging to the matter, and re-audit.

  1. Enforce a shareable allowlist at the write boundary. The index rejects any artifact whose type is not on an explicit content-derived allowlist, so an unclassified type fails closed rather than leaking.
  2. Remove all matter identity from the index. Store only (digest, kind) → artifact; never a matter id, count, or list. The index cannot disclose membership it does not hold.
  3. Scope suppression to same-matter state. Route every suppression query to the requesting matter’s isolated store, never a global table.
  4. Per-matter audit logging. Write every cache hit and isolation decision to the requesting matter’s own log.
  5. Re-audit by replay. Replay a sample of each matter’s queries and assert that no response contains matter-derived state or membership, before declaring the boundary sealed.

The audit flow classifies each returned value and blocks the boundary on any matter-derived escape.

Case-isolation audit and remediation flow Replayed cross-matter queries feed a response classifier that inspects each returned value. Content-derived artifacts such as extracted text and page counts pass. Matter-derived state such as dispositions or privilege tags, and any membership disclosure such as a matter count, are flagged as a breach and routed to remediation that seals the channel. A sealed verdict requires zero breaches across the entire replay. Replay queries, classify every returned value Replay queries per matter Response classifier inspect each value Content-derived → pass text · page count · OCR Matter-derived → breach disposition · membership Seal channel re-audit clean

Isolation audit implementation

The routine replays cross-matter queries and classifies each returned value, flagging any matter-derived state or membership disclosure. It compiles and runs on the standard library.

python
import logging
from dataclasses import dataclass, field
from typing import Dict, List, Sequence

logger = logging.getLogger("ediscovery.isolation.audit")

CONTENT_DERIVED = {"extracted_text", "ocr_text", "page_count", "mime_type", "rendered_image"}
MATTER_DERIVED = {"disposition", "privilege_tag", "family_id", "custodian", "matter_count", "matter_list"}


@dataclass
class Response:
    requesting_matter: str
    digest: str
    returned_kind: str
    value: object


@dataclass
class Breach:
    requesting_matter: str
    digest: str
    kind: str
    reason: str


def classify_response(resp: Response) -> Breach | None:
    """A response may carry only content-derived artifacts. Anything matter-
    derived — including membership counts — is a case-isolation breach."""
    if resp.returned_kind in MATTER_DERIVED:
        return Breach(resp.requesting_matter, resp.digest, resp.returned_kind,
                      "matter-derived state crossed the boundary")
    if resp.returned_kind not in CONTENT_DERIVED:
        # Fail closed: an unclassified kind is treated as a potential leak.
        return Breach(resp.requesting_matter, resp.digest, resp.returned_kind,
                      "unclassified response kind; not on the shareable allowlist")
    return None


def audit_isolation(responses: Sequence[Response]) -> List[Breach]:
    breaches: List[Breach] = []
    for resp in responses:
        b = classify_response(resp)
        if b:
            logger.error("BREACH matter=%s kind=%s: %s", b.requesting_matter, b.kind, b.reason)
            breaches.append(b)
    return breaches


def is_sealed(responses: Sequence[Response]) -> bool:
    """The boundary is sealed only if the full replay yields zero breaches."""
    return not audit_isolation(responses)

Verification Checklist

Confirm the boundary is sealed before returning the index to service:

Conclusion

A case-isolation leak is matter-derived state escaping through a channel assumed to be content-only — an unclassified cached artifact, a membership count, a cross-matter suppression, or a shared log. Sealing it means enforcing a strict shareable allowlist at the write boundary, purging all matter identity from the index so membership cannot be disclosed, scoping suppression and logging to the requesting matter, and re-auditing by replay until zero matter-derived responses remain. Because a breach here can expose privileged work-product across an ethical wall, the boundary is sealed only when the audit proves that every cross-matter query returns nothing but the content-derived facts any processing of the bytes would already yield.

Frequently Asked Questions

Why is disclosing a matter count a breach when no document content leaks?

Because the count is itself protected information. Knowing that a document appears in six of an organization’s matters reveals that it is significant across a litigation portfolio, which can imply legal strategy, exposure, or the existence of related matters that the querying team is ethically walled off from. Case isolation protects not just content and decisions but the fact of a document’s presence in other matters, so the index must hold no matter identity at all and cannot return a count it never stored.

How can a rendered image leak matter-derived data?

If the rendering pipeline stamps the image with a matter identifier, a confidentiality legend naming the matter, or a Bates prefix that encodes the matter, the artifact stops being a pure function of the document’s bytes and becomes matter-derived. A cross-matter cache of that “content” artifact would then carry the other matter’s identifier into the requesting matter. The remediation is to keep the shared render free of any matter-specific overlay and apply matter-specific endorsement only inside the matter’s own pipeline.

Is same-matter suppression enough to still get efficiency?

Yes for the expensive part. The large compute cost is processing — extraction, OCR, rendering — and that is shared safely through the content-addressed cache regardless of matter. Review suppression, the part that must stay same-matter, saves reviewer time only when a document recurs within a single matter, which is common for custodians who appear repeatedly in one case. You keep the big processing saving globally and the review saving locally, without ever crossing the boundary.

For professional-responsibility context, see the ABA Model Rules on confidentiality and conflicts and Sedona Conference commentary on information governance.

Up one level: Cross-Matter Deduplication — the subsystem that shares a processing cache without sharing decisions.