{
  "schema_version": "1.3.0",
  "slug": "when-does-a-retention-ttl-delete-records-under-legal-hold",
  "title": "When does a retention TTL delete records under legal hold?",
  "date_of_record": "2026 November 1",
  "scope": "Applies to automated retention or TTL sweeps that delete records based on age, where a subset of records may be under legal hold, litigation hold, or regulatory preservation. Excludes systems with no deletion automation.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/when-does-a-retention-ttl-delete-records-under-legal-hold.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/when-does-a-retention-ttl-delete-records-under-legal-hold.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/when-does-a-retention-ttl-delete-records-under-legal-hold.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 882,
    "python_slice_tokens": 108,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "**Predicate.** A retention sweep is safe if and only if the hold check precedes deletion and hold state is durable and readable by the sweep. If the sweep evaluates only age, or evaluates hold against a cache that can be stale, held records are deleted. The invariant is: for every record r, delete(r) implies age(r) > ttl AND not held(r), where held(r) is rea...",
    "what_was_observed": "**Signature.** Records known to be under hold are absent. Hold records exist for identifiers that no longer resolve. Backups may or may not contain the deleted data, and their retention is often shorter than the hold. **Trace.** Hold applied to account 42 at t1. Sweep runs at t2 with an age cutoff that includes account 42's records. The sweep reads a hold cache refreshed every 15 minutes; the hold was written at t1 a...",
    "condition_of_validity": "Retention is safe only while all hold: 1. **Hold precedes delete.** The hold check is in the deletion path, not in a parallel process, and it reads authoritative state. 2. **Durable and synchronous.** Hold state is written durably and is visible to the sweep immediately, not after a cache refresh. 3. **Fail closed.** If hold state is unreadable, the sweep sk...",
    "decision_boundary": "- Hold checked synchronously in the delete path, fail-closed: safe. - Hold checked against a cache with a refresh interval: held records can be deleted within the refresh window. - Hold enforced by a separate process that pauses the sweep: safe only if the pause is guaranteed and verified. - Sweep with no hold awareness: unsafe by construction.",
    "operational_effect": "The defect is a race between two systems with different clocks and different failure semantics, and its consequence is not a degraded service but a destroyed record. Remediation is to put the hold check in the deletion path and to fail closed. The trap is to exclude held records by adding a filter to the sweep's query. That works until the hold store and the..."
  },
  "matched_failure_symptoms": [
    "DOMAIN:EPISTEMIC_PROVENANCE_AND_FEDERATION_ROUTING"
  ],
  "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": "6990b202a498f25aca66057475a8dc1c4010f70b6e98c470f65c4085e1d1f86a",
    "verified_classes": [
      "LegalHoldViolationError",
      "RetentionGate"
    ],
    "verified_functions": [
      "dispatch_sweep_mode",
      "verify"
    ],
    "verified_functions_count": 2,
    "defensive_guards_count": 3,
    "raised_exceptions": [
      "LegalHoldViolationError"
    ],
    "sample_fail_closed_invariants": [
      "hold check not in deletion path: held records deletable",
      "hold state cached: deletion possible within refresh window",
      "sweep proceeds when hold state unreadable"
    ],
    "stdlib_dependencies": [
      "dataclasses"
    ],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
