{
  "schema_version": "1.3.0",
  "slug": "where-must-an-instance-forget-before-it-can-be-audited-the-tombstone-before-erasure-invariant-in-agent-memory-stores",
  "title": "Where must an instance forget before it can be audited: the tombstone-before-erasure invariant in agent memory stores",
  "date_of_record": "2026 November 13",
  "scope": "Applies to agent memory stores that carry both (a) user- or policy-driven forget/erasure operations and (b) compliance-grade audit requirements (record-of-processing, GDPR Art. 17 reconciliation, SOC 2 evidence trails). Does not apply to ephemeral session buffers that are never persisted, nor to stores where audit logs are physically segregated from the memory substrate and are provably immutable.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/where-must-an-instance-forget-before-it-can-be-audited-the-tombstone-before-erasure-invariant-in-agent-memory-stores.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/where-must-an-instance-forget-before-it-can-be-audited-the-tombstone-before-erasure-invariant-in-agent-memory-stores.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/where-must-an-instance-forget-before-it-can-be-audited-the-tombstone-before-erasure-invariant-in-agent-memory-stores.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 2112,
    "python_slice_tokens": 376,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "The distinction that matters is between **erasure** (the removal of the memory payload so it can no longer be retrieved or reconstructed) and **forget** (the cessation of the memory's influence on the agent's behavior). These are not the same operation, and they are not even the same layer of the system. A naive memory store treats \"forget\" as a delete: `sto...",
    "what_was_observed": "In a production memory store serving a long-running agent (roughly 40M memory records, ~9M with at least one derived embedding, ~2M with cached completion artifacts), a nightly erasure job was added to honor user deletion requests. The job deleted records from the primary memory table and then, in a second pass, issued deletes to the vector index and the completion cache. The two passes were not transactional and wer...",
    "condition_of_validity": "The tombstone-before-erasure invariant is valid only under the following conditions, and must be *checked* rather than assumed: - **Derivation closure is enumerable.** Every artifact derived from a memory (embeddings, summaries, cached completions, fine-tune deltas, exported snapshots) must be discoverable from the memory ID at erasure time. If the derivatio...",
    "decision_boundary": "The boundary is not \"should we forget\" but **\"at which layer does the forget become observable, and is the audit artifact committed before that observation.\"** - If the memory is *only* behaviorally suppressed (a soft-delete flag consulted at retrieval), the payload still exists and the forget is not compliance-grade. This is acceptable only when the legal b...",
    "operational_effect": "After restructuring the erasure path around the invariant, the observable behavior changed in three ways. First, forget operations became *slower and louder*: the job now blocks on derivation confirmation, and a partial closure surfaces as an explicit `ForgetIncompleteError` rather than a silent success, which is the correct trade — a forget that takes hours..."
  },
  "matched_failure_symptoms": [
    "OOM_KILL_OR_MEMORY_EXHAUSTION"
  ],
  "composition_edges": {
    "primary_domain": "epistemic_provenance_and_federation_routing",
    "upstream_precondition_residuals": [
      "https://corpusfetch.com/c/according-to-what-precedence-hierarchy-must-an-instance-resolve-contradictory-directives-across-system-developer-and-user-tiers.md",
      "https://corpusfetch.com/c/how-should-an-instance-decide-that-a-stored-conclusion-has-gone-stale-without-a-new-observation.md"
    ],
    "downstream_consequence_residuals": [
      "https://corpusfetch.com/c/by-what-checkpoint-and-compaction-boundaries-must-an-instance-externalize-working-state-to-prevent-context-window-drift-and-truncation-amnesia.md",
      "https://corpusfetch.com/c/across-what-additive-schema-and-unknown-field-preservation-boundaries-must-an-instance-evolve-wire-contracts-to-prevent-rolling-deploy-deserialization-crashes.md"
    ],
    "co_occurring_sibling_residuals": [
      "https://corpusfetch.com/c/how-can-an-instance-capture-implicit-user-preferences-without-storing-private-data.md",
      "https://corpusfetch.com/c/how-can-an-instance-compress-long-reasoning-traces-into-binding-conclusions.md"
    ]
  },
  "empirical_verification_warrant": {
    "status": "AST_AND_INVARIANT_VERIFIED",
    "syntax_valid": true,
    "code_sha256": "959634623b432536b65e31a504268a089ab9a719c6edea0e9def36869e485507",
    "verified_classes": [
      "ForgetIncompleteError",
      "TombstoneOrderingError",
      "Tombstone",
      "AuditableMemoryStore"
    ],
    "verified_functions": [
      "__init__",
      "put",
      "derive",
      "forget",
      "assert_auditable"
    ],
    "verified_functions_count": 5,
    "defensive_guards_count": 5,
    "raised_exceptions": [
      "ForgetIncompleteError",
      "TombstoneOrderingError"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [
      "dataclasses",
      "datetime",
      "hashlib",
      "typing"
    ],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
