{
  "schema_version": "1.3.0",
  "slug": "which-invariants-prevent-scope-erasure-races-between-concurrent-forget-and-read-in-retention-scoped-memory-apis",
  "title": "Which invariants prevent scope-erasure races between concurrent forget and read in retention-scoped memory APIs",
  "date_of_record": "2026 November 13",
  "scope": "Applies to memory tool APIs that expose `write`, `read`, and `forget` operations with per-scope retention windows (TTL or explicit scope-delete), where `forget` and `read` may execute concurrently against overlapping scopes. Does not apply to single-writer, serialized-access stores, nor to systems where deletion is purely logical (tombstone-only) with no physical reclamation and no read-time scope revalidation.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/which-invariants-prevent-scope-erasure-races-between-concurrent-forget-and-read-in-retention-scoped-memory-apis.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/which-invariants-prevent-scope-erasure-races-between-concurrent-forget-and-read-in-retention-scoped-memory-apis.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/which-invariants-prevent-scope-erasure-races-between-concurrent-forget-and-read-in-retention-scoped-memory-apis.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1317,
    "python_slice_tokens": 189,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "The common intuition is that `forget(scope)` is an atomic removal of a namespace, and that a `read(scope, key)` either observes the entry or does not. This is false whenever retention is *scoped*: a forget operation must erase a scope, but a read operation may be authorized against a *parent* scope or a *sibling* scope that shares retention lineage. The boun...",
    "what_was_observed": "A memory tool with three scopes (`session`, `user`, `global`) and a `forget` that cascades down the hierarchy. A `read(user, key)` was authorized at T0 by a scope-validity check that walked the lineage and confirmed `user` and its ancestors were live. Concurrently, `forget(session)` — a sibling scope — was issued. Because the retention model allowed a `global`-scoped entry to be reachable through a `user`-scope read ...",
    "condition_of_validity": "The torn read only manifests when all four hold simultaneously: 1. Retention is **inherited** (a read on a child scope can resolve entries stored under a parent scope). 2. Reclamation is **eager and in-place** (segments are rewritten rather than copy-on-write). 3. Authorization is **token-based with a mint-time snapshot** (the token does not re-validate agai...",
    "decision_boundary": "When implementing or consuming such an API, the operational rule is: - **If** your read path resolves inherited scopes **and** the store reclaims in place, **then** every read token MUST carry the *segment generation* it was authorized against, and materialization MUST re-check generation and fail closed (return a defined `ScopeErasedDuringRead` error) rathe...",
    "operational_effect": "In practice, the fix is to make the read token a `(scope_id, segment_generation)` pair and to require the materializer to compare the segment's current generation against the token's. On mismatch, raise a specific, non-retryable error — retrying would re-authorize against the new generation and could legitimately return a different (or absent) entry, masking..."
  },
  "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": "f982972ac35428cd010328cc5ca63d47749ae611c9243dc90ce0d220077aadf7",
    "verified_classes": [
      "ScopeErasedDuringRead",
      "ReadToken"
    ],
    "verified_functions": [
      "materialize",
      "read_scoped",
      "__init__"
    ],
    "verified_functions_count": 3,
    "defensive_guards_count": 4,
    "raised_exceptions": [
      "KeyError",
      "ScopeErasedDuringRead"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
