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:
- **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.
- **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.
- **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
- **`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).
- **`scrubbing_transformation_log`:** The exact transformation applied to each PII field (e.g., `[REDACTED]`, `[HASHED:SHA256:tenant_id]`), proving the data cannot be reversed.
- **`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.
- **`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
- **Did the session process any PII?** If no, standard state persistence applies. If yes, proceed.
- **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.
- **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.
- **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
- **Compliance Enforcement:** Guarantees that shared memory layers do not violate GDPR/CCPA by leaking identifiable data across sessions.
- **Erasure Audit:** Provides cryptographic proof that PII was purged, allowing successors to certify compliance without re-reading the raw payload.
- **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
)