Disciplines · Audits

Eve Task 13.6 backup, restore, migration, and deletion-replay proof

The source-bound Task 13.6 drill passed all 11 required recovery families over the product's production store implementations.

7sections8 minread

On this page

Date: 2026-09-15

Task: 13.6

Implementation and execution source: 245b92f03e556f2beb6115652ca995cda1fd52be

Retained receipt: docs/audits/eve-backup-recovery/2026-09-15-05.json

Canonical record digest: 15c193610071a9db85382ed1b8aa8ef98123921d61dd87c54f7b6aa1b55602f1

Decision#

The source-bound Task 13.6 drill passed all 11 required recovery families over the product's production store implementations. It used real local PostgreSQL 16.14, Qdrant 1.19.1, and Linux filesystem substrates. Every family restored the independently counted backup census, produced an equal independently read semantic digest after migration, retained at least one control record, and met its declared RPO and RTO.

The maximum measured RPO was 1 second and the maximum measured RTO was 5 seconds. These are measurements from one isolated drill, not rolling production attainment.

Capability-family results#

Family Production substrate Backup → restored Retained Objective RPO Objective RTO Measured RPO/RTO Migration and integrity Deletion contract
Conversations PostgreSQL 2 → 2 1 25 h 4 h 1 s/5 s Pass Pass
Memory PostgreSQL 2 → 2 1 25 h 4 h 1 s/5 s Pass Pass
Vectors PostgreSQL + Qdrant 2 → 2 1 25 h 4 h 1 s/5 s Pass Pass
Index metadata Qdrant 3 → 3 3 0 s 4 h 0 s/5 s Pass Non-subject
Workbench PostgreSQL 12 → 12 12 25 h 4 h 1 s/5 s Pass Pass
Ledger PostgreSQL 54 → 54 54 25 h 4 h 1 s/5 s Pass Pass
Schedules PostgreSQL 2 → 2 1 25 h 4 h 1 s/5 s Pass Pass
Watchers PostgreSQL 2 → 2 1 25 h 4 h 1 s/5 s Pass Pass
Task state PostgreSQL + filesystem 4 → 4 2 25 h 4 h 1 s/5 s Pass Pass
Audit PostgreSQL 2 → 2 1 25 h 4 h 1 s/5 s Pass Pass
Evidence manifests Filesystem 2 → 2 2 6 h 4 h 1 s/5 s Pass Non-subject

PostgreSQL authorities inherit the checked nightly-backup age plus one-hour tolerance, so their conservative objective is 90,000 seconds. Evidence files inherit the six-hour off-box cycle. Qdrant vector data is derived from the PostgreSQL authority, and index metadata is recreated from source configuration; the latter therefore has a zero-second data-loss objective.

Production-store and migration boundary#

The drill created isolated source and clean-target PostgreSQL databases and Qdrant collections. It seeded the actual conversation, Iris memory, personalization-vector authority/projection, workbench/ledger, schedule, PostgreSQL watcher, lifecycle, RUN-002 file, audit, and evidence-manifest store paths. The PostgreSQL database was backed up with pg_dump custom format and restored with pg_restore; RUN-002 and evidence files were copied with retained SHA-256 facts.

The fixture deliberately downgraded conversation, memory, vector, schedule, watcher-fence, lifecycle, and RUN-002 representations before backup. Startup used the production hydration/migration seams. Conversation and memory current formats were read back from PostgreSQL, watcher and Workbench deletion-fence tables were created, lifecycle/RUN-002 current state was persisted, Workbench projections and their append-only ledger were replayed through the production store. The recovered Workbench/ledger census now includes accepted goal and delivery-plan revisions, their normalized requirement/work/proof graph, every planning event, authenticated fleet activation facts for both the deletion subject and retained peer, and populated operator-labor trajectory, interval, coverage, reclassification, and independent QA/product evaluation facts. Legacy Qdrant payloads were replaced through the deployed PersonalizationVectorIndex reconciliation path.

Qdrant is intentionally not treated as an authority or snapshot source. The target collection was proven absent, rebuilt from the restored PostgreSQL vector authority, checked for dimensions/distance/indexed payload fields, queried through the real adapter, and read back record by record before admission.

Semantic digests bind subject identity and recovered content while excluding only migration-local revision counters and the physical source/target Qdrant collection name. Focused controls prove that changes to conversation content, memory content, or vector values still change the digest. The first live candidate correctly failed when those transport-local fields had not yet been normalized; no record from that attempt was admitted. The first adjacent-plane candidate likewise failed before evidence emission when its recovery census used stale delivery-plan column names; the replacement candidate corrected the bindings and added a populated all-table integration assertion. Independent review then found that planning_fleet_operation.actor was still absent from the subject census, redaction scope, snapshot, and admission fence. The current source repairs that entire boundary, and this receipt is its first and only live drill.

Deletion and resurrection protection#

Nine families contain the controlled deletion subject: conversations, memory, vectors, workbench, ledger, schedules, watchers, task state, and audit. In each one, the older backup visibly resurrected the subject before replay. The clean target then reconciled one encrypted create-only recovery receipt, verified four service attestations, replayed the actual signed deletion fanout before admission, removed or privacy-redacted only the deleted subject, retained its peer, and rejected a later write that attempted resurrection. Workbench and ledger proof uses authenticated subject actors, recursively discovered event identities/references, the shared write barrier and durable recreation fence, identity-only schema-governed redaction across planning and operator-labor facts—including immutable fleet-operation actor identity—exact projection replay, and independently read post-replay censuses. Both activation and cancellation writers consult the durable subject fence before idempotency replay while holding the shared side of the global erasure barrier.

The published scope-v3 migration remains byte-immutable. Its explicit transaction first takes the same exclusive Workbench write-plane advisory lock used by subject erasure, writes exact-record privacy approvals, redacts every fleet actor still matching a v2 tombstone, proves that the upgraded set has zero remaining matches, and only then advances the fences to v3 and commits. Its database INSERT trigger rejects deleted fleet actors during mixed-version deployment.

A separate ordered follow-up migration takes that barrier, installs a DEFERRABLE INITIALLY DEFERRED inverse constraint trigger on scope-v3 tombstones, repairs any fleet actor exposed by a predecessor eraser that won the narrow gap between the two history entries, proves zero leaks, drains its constraint events, and commits. The deferred check lets the current eraser redact within one transaction but rejects an older eraser at COMMIT before it can report a false deletion success. Startup readiness requires both fleet triggers and the zero-leak invariant.

The Hetzner deploy path now mounts the complete read-only Prisma directory and runs pinned Prisma 7.8.0 migrate deploy before any application rollout. Structural schema diff is no longer an apply authority because it omits custom backfills, barriers, functions, and triggers. Split database credentials are URL-encoded inside the config rather than exposed as a password-bearing process argument; absent or inconsistent _prisma_migrations history fails closed for operator reconciliation and is never silently baselined. The production-path regression drives that exact config against dirty v2, queues an old eraser between the two real migration entries, proves the follow-up repairs it, and then proves a post-migration old eraser is rejected at COMMIT.

Only index metadata and evidence manifests are non-subject schema/release material; their receipt rows carry explicit non-subject reasons.

Production startup now requires the recovery journal, Redis, and attestation signer and refuses HTTP admission until replay succeeds. The production S3 replica adapter requires an independent HTTPS endpoint, create-only writes, Object Lock compliance retention beyond the backup horizon, and readback. The live local drill uses an in-process independent write-once replica boundary; provider IAM and Object Lock behavior remain focused-test evidence rather than a claimed provisioned service.

Fail-closed controls#

All eight retained controls passed:

  • stale per-family RPO is rejected;
  • a corrupt PostgreSQL archive is rejected;
  • malformed Qdrant dimensions/index metadata are rejected;
  • an absent target Qdrant collection is rebuilt and queried before admission;
  • a corrupt evidence manifest is rejected by the production schema verifier;
  • a modified authenticated deletion receipt is rejected;
  • restore without completed deletion replay is rejected; and
  • startup without any required replay dependency is rejected.

The direct retained-record verifier independently checks the canonical record digest and every source-file hash against the published source commit. It also mutates deletion proof, family completeness, and RPO in memory and requires each negative control to fail before admitting the unchanged record. Its result was 11/11 families, maximum RPO 1 second, and RTO 5 seconds.

Reused source/static receipts#

No green suite was replayed during evidence assembly. The source candidate already had passing receipts for:

  • 17 RUN-002 durable-run contract tests;
  • 12 PostgreSQL watcher-store tests;
  • 6 backup/recovery evaluator tests;
  • 35 focused BFF journal, lifecycle, Ori, and vector tests, followed by the exact 12-test lifecycle and 12-test journal/vector repair selections;
  • 36 earlier directly affected real-PostgreSQL Workbench, goal, plan, fleet, and operator-labor tests, plus the final 5/5 adjacent-erasure suite covering populated recovery snapshots, identity-only redaction, late-write refusal, both sides of the global create/erase barrier, the immutable 63-entry Prisma ledger, dirty-v2 application of its final two entries, repair of an eraser queued between them, both fleet triggers, and commit-time predecessor rejection;
  • 18 subject-data-map tests and 14 production scanner negative controls;
  • Task 13.6 runner/verifier contracts and tool typechecking;
  • BFF ratchet typechecking with zero backlog and the production server/reprojection CLI build;
  • nine affected project typechecks executed serially, the two deployment-path contract tests, shell syntax, changed-source lint with zero errors, and architecture ratchets;
  • Docker Compose validation; and
  • 16 disaster-recovery runbook operation tests.

The broader workbench spec typecheck has 25 pre-existing errors outside the changed subject-erasure files. Its exact 40-test subject-erasure contract and scanner are green; this unrelated baseline is not represented as passing.

Limits and remaining work#

  • This is an isolated local drill over minimized records, not a production restore, regional failover, or rolling RPO/RTO window.
  • PostgreSQL and Qdrant each ran as one local node.
  • No provisioned production immutable-object repository or IAM ceremony was exercised; that path remains fail-closed until configured.
  • Recovery-key rotation remains an operator ceremony, and keys for restorable receipts must remain escrowed through their backup horizon.
  • Task 13.6 still requires an updated hash-bound evidence manifest and independent confirmatory and adversarial review before its checkbox can close.
  • Phase 13 and G13 remain open: Task 13.5 still needs its credentialed external channel outage lane, and Task 13.7 owns deployed observability and the supervised game day.