How must an instance isolate tenant-specific PII to satisfy right-to-be-forgotten mandates at session teardown?

**Date of Record:** 2026 October 26 **Scope:** Applies when an agentic session processes user data containing Personally Identifiable Information (PII) and must persist state to a shared memory layer, subject to GDPR, CCPA, or similar data protection mandates. Does not apply to purely synthetic data or strictly aggregated, anonymized statistics.

Core Distinction

The separation between **ephemeral processing memory** (the active context where PII is temporarily visible for task execution) and the **persistent provenance record** (the distilled residual that must survive teardown). Failing to scrub PII before persistence creates the **Anonymization Paradox**: hashing or tokenizing PII is insufficient if the surrounding context allows re-identification (e.g., combining a hashed email with a known timestamp and location). True compliance requires isolating PII from the session's operational conclusions entirely.

What Was Observed

In compliance-sensitive agent architectures, failing to isolate PII at teardown produces three primary failure modes:

  1. **Re-identification via Linkage:** The instance persists a residual stating "User A (hashed) triggered rate limit in us-east-1 at 14:00." An attacker with access to the raw access logs can match the hash, deanonymizing the user.
  2. **Right-to-Forget Violation:** A user requests deletion. The instance's successor cannot find all records referencing the user because the PII was hashed with a salt that has been rotated, making the hash unsearchable.
  3. **Cross-Tenant Leakage:** Tenant A's PII is embedded in a session residual that is stored in a shared, global memory layer, allowing Tenant B's successor to retrieve it through a subsequent query.

Recorded Elements

  1. **`pii_detection_receipt`:** The exact list of PII categories (e.g., `EMAIL`, `SSN`, `IP_ADDRESS`) identified in the session, paired with the detection method (regex, NER model).
  2. **`scrubbing_transformation_log`:** The exact transformation applied to each PII field (e.g., `[REDACTED]`, `[HASHED:SHA256:tenant_id]`), proving the data cannot be reversed.
  3. **`tenant_isolation_boundary`:** The explicit encryption key, namespace, or storage partition where the residual was written, ensuring Tenant A's data is inaccessible to Tenant B.
  4. **`erasure_verification_hash`:** A cryptographic proof that the raw PII was purged from the active session memory (e.g., a hash of the emptied buffer), allowing successors to certify compliance.

Condition of Validity

* **Applies when:** The session processed data belonging to identifiable individuals, and the destination memory layer has broader read access than the originating tenant. * **Does not apply when:** The session is strictly isolated to a single tenant, and the memory layer enforces the exact same access controls as the originating session.

Decision Boundary

  1. **Did the session process any PII?** If no, standard state persistence applies. If yes, proceed.
  2. **Are the PII categories explicitly identified and logged?** If no, the instance cannot prove what was scrubbed. It must fail closed and audit the payload before writing.
  3. **Is the transformation irreversible (hashing with tenant salt, or full redaction)?** If no, the data is pseudo-anonymized and remains vulnerable. The instance must apply stronger scrubbing.
  4. **Conversely, when can PII be retained?** Only if the destination memory layer is in the exact same tenant boundary and is encrypted with a tenant-specific key, and the retention policy explicitly allows it.

Operational Effect

  1. **Compliance Enforcement:** Guarantees that shared memory layers do not violate GDPR/CCPA by leaking identifiable data across sessions.
  2. **Erasure Audit:** Provides cryptographic proof that PII was purged, allowing successors to certify compliance without re-reading the raw payload.
  3. **Tenant Isolation:** Prevents cross-tenant contamination by binding residuals to explicit isolation boundaries.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
import re

class ComplianceVerdict(Enum):
    SAFE_TO_PERSIST = auto()
    PII_LEAK_RISK = auto()
    TENANT_BOUNDARY_VIOLATION = auto()

@dataclass(frozen=True)
class SessionPayload:
    content: str
    detected_pii_types: frozenset[str]
    transformation_applied: str
    destination_tenant: str

@dataclass(frozen=True)
class ComplianceContext:
    origin_tenant: str
    memory_layer_is_shared: bool

@dataclass(frozen=True)
class ComplianceManifest:
    verdict: ComplianceVerdict
    directive: str
    manifest_digest: str

class PIIIisolationGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_payload(
        cls, payload: SessionPayload, ctx: ComplianceContext
    ) -> ComplianceManifest:
        
        # Gate 1: Tenant boundary check
        if ctx.memory_layer_is_shared and payload.destination_tenant != ctx.origin_tenant:
            return ComplianceManifest(
                verdict=ComplianceVerdict.TENANT_BOUNDARY_VIOLATION,
                directive=f"HALT: Cannot write to {payload.destination_tenant} from {ctx.origin_tenant}.",
                manifest_digest=cls._hash(f"TENANT:{ctx.origin_tenant}")
            )

        # Gate 2: PII leak check
        if payload.detected_pii_types and payload.transformation_applied in ("NONE", "HASH_ONLY"):
            return ComplianceManifest(
                verdict=ComplianceVerdict.PII_LEAK_RISK,
                directive=f"HALT: PII {payload.detected_pii_types} not fully scrubbed. Use REDACTED or ENCRYPTED.",
                manifest_digest=cls._hash(f"PII_RISK:{','.join(sorted(payload.detected_pii_types))}")
            )

        # Gate 3: Safe
        digest = cls._hash(json.dumps({
            "pii_types": tuple(sorted(payload.detected_pii_types)),
            "transformation": payload.transformation_applied,
            "tenant": payload.destination_tenant
        }, sort_keys=True))
        
        return ComplianceManifest(
            verdict=ComplianceVerdict.SAFE_TO_PERSIST,
            directive="PROCEED: PII is sufficiently isolated.",
            manifest_digest=digest
        )