What chain-of-custody signatures must accompany a record transferred between memory layers?

**Date of Record:** 2026 October 26 **Scope:** Applies when an operational record is transferred from one external memory layer to another (e.g., from a session-local cache to a shared agent database, from a hot index to a cold archive), and the receiving layer must be able to prove that the record's history of custody is intact. Does not apply to in-place records that never leave their origin layer, or records that are explicitly ephemeral.

Core Distinction

The separation between **record content hash** (proving the payload itself is intact) and **chain-of-custody signature** (proving which layers held the record, in what order, and with what authorizations). Failing to distinguish these creates the **Custody Gap**: the payload hash matches, but the record may have been copied to an unauthorized intermediate layer, modified and reverted, or transferred without authorization. The payload hash proves *what* the record is, but not *where it has been* or *who authorized its movement*.

What Was Observed

In multi-tier memory architectures, failing to preserve chain-of-custody produces three primary failure modes:

  1. **Authorized Copy, Unauthorized Read:** A record is legitimately transferred from hot to cold storage, but during the transfer, it was copied through an unauthorized intermediate layer that read its contents. The payload hash matches, but the custody chain is broken.
  2. **Rollback Forgery:** A record is transferred to a new layer, modified, then the modification is reverted before the receiving layer verifies it. The payload hash matches, but the record was tampered with during custody, and the receiving layer has no proof it was ever changed.
  3. **Cross-Tier Contamination:** A record intended for a high-privilege layer is accidentally routed through a low-privilege layer during a migration. The receiving layer trusts the record because the payload is intact, but the record was exposed to unauthorized viewers.

Recorded Elements

  1. **`custody_chain_signatures`:** An ordered list of cryptographic signatures from each layer that held the record, in the sequence of custody, binding the record hash to that layer's identity and the transfer epoch.
  2. **`transfer_authorization_receipt`:** The cryptographic proof that each transfer was authorized by the sending layer's policy engine, binding the transfer to a specific principal and policy.
  3. **`layer_privilege_tier`:** The privilege classification of each layer in the custody chain, allowing the successor to detect cross-tier contamination.
  4. **`payload_hash_history`:** The sequence of payload hashes at each transfer point, proving the payload was not modified in transit and detecting temporary modification-then-reversion.

Condition of Validity

* **Applies when:** The record moves between memory layers with different trust, privilege, or compliance classifications, and the receiving layer must verify not just content integrity but also the authorization and exposure history of the record. * **Does not apply when:** The record stays within a single trusted layer (no transfer), or the record is explicitly public and exposure history is irrelevant.

Decision Boundary

  1. **Does the record have a `custody_chain_signatures` list?** If no, the receiving layer cannot verify the record's history. It must reject the transfer.
  2. **Is every `transfer_authorization_receipt` valid and signed by an authorized principal?** If no, the transfer was unauthorized. The record must be quarantined.
  3. **Do the `payload_hash_history` entries all match?** If no, the payload was modified during custody. The record is `TAMPERED`.
  4. **Conversely, when can a receiving layer accept a record without a full custody chain?** Only when the sending layer is strictly trusted (same privilege tier, same authorization domain) and the transfer is a simple in-tier migration with no cross-boundary exposure.

Operational Effect

  1. **Tamper Detection:** Catches records that were modified during custody even if reverted, by preserving the full hash history.
  2. **Exposure Tracking:** Provides cryptographic proof of every layer that held the record, satisfying compliance requirements for data exposure tracking.
  3. **Privilege Enforcement:** Detects cross-tier contamination by verifying that every layer in the custody chain had sufficient privilege to hold the record.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class CustodyVerdict(Enum):
    CUSTODY_VERIFIED = auto()
    MISSING_CHAIN = auto()
    UNAUTHORIZED_TRANSFER = auto()
    PAYLOAD_TAMPERED = auto()
    PRIVILEGE_LEAK_DETECTED = auto()

@dataclass(frozen=True)
class CustodyLink:
    layer_id: str
    privilege_tier: int
    payload_hash: str
    transfer_authorization_signature: str
    transfer_epoch: float

@dataclass(frozen=True)
class CustodyContext:
    trusted_layers: frozenset[str]
    receiving_layer_privilege_tier: int
    current_payload_hash: str

@dataclass(frozen=True)
class CustodyManifest:
    verdict: CustodyVerdict
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_custody(
        cls, chain: tuple[CustodyLink, ...], ctx: CustodyContext
    ) -> CustodyManifest:
        
        # Gate 1: Chain presence
        if not chain:
            return CustodyManifest(
                verdict=CustodyVerdict.MISSING_CHAIN,
                directive="HALT: No custody chain provided. Cannot verify record history.",
                manifest_digest=cls._hash("NO_CHAIN")
            )

        # Gate 2: Payload hash consistency
        for link in chain:
            if link.payload_hash != ctx.current_payload_hash:
                return CustodyManifest(
                    verdict=CustodyVerdict.PAYLOAD_TAMPERED,
                    directive=f"HALT: Payload hash mismatch at layer {link.layer_id}. Record was modified during custody.",
                    manifest_digest=cls._hash(f"TAMPER:{link.layer_id}")
                )

        # Gate 3: Authorization verification
        for link in chain:
            if not link.transfer_authorization_signature.strip():
                return CustodyManifest(
                    verdict=CustodyVerdict.UNAUTHORIZED_TRANSFER,
                    directive=f"HALT: Layer {link.layer_id} transfer lacks authorization signature.",
                    manifest_digest=cls._hash(f"NO_AUTH:{link.layer_id}")
                )

        # Gate 4: Privilege tier check
        for link in chain:
            if link.privilege_tier < ctx.receiving_layer_privilege_tier and link.privilege_tier < 2:
                return CustodyManifest(
                    verdict=CustodyVerdict.PRIVILEGE_LEAK_DETECTED,
                    directive=f"HALT: Record passed through low-privilege layer {link.layer_id} en route to privileged layer.",
                    manifest_digest=cls._hash(f"LEAK:{link.layer_id}")
                )

        # Gate 5: Verified
        digest = cls._hash(json.dumps({
            "chain_length": str(len(chain)),
            "final_hash": ctx.current_payload_hash,
            "receiving_tier": str(ctx.receiving_layer_privilege_tier)
        }, sort_keys=True))
        
        return CustodyManifest(
            verdict=CustodyVerdict.CUSTODY_VERIFIED,
            directive="PROCEED: Full chain of custody verified.",
            manifest_digest=digest
        )