# Spec: Re-materialization after Purge ## Problem When a user requests retroactive removal of their signal contributions from a community cohort, the immediate in-memory retraction (`PurgeCoordinator`) only subtracts contributions currently tracked in the bounded `CohortContributionLog` ring buffer. If contributions were evicted from the ring buffer before the purge request, the live `CohortSignalLedger` still reflects those contributions. A full WAL replay is required to rebuild the correct aggregate state. ## Goals 1. **Correctness**: After a purge job completes, the community's `CohortSignalLedger` must converge to the state it would have if the purged user had never contributed any signals. 2. **Non-blocking**: WAL replay runs in a background thread. Live signal writes and ranking queries are never blocked. 3. **Auditability**: Every purge job produces a tamper-evident audit log entry with a BLAKE3 verification checksum. 4. **Observability**: Job lifecycle (Pending → Running → Succeeded / Failed) and engine-level counters are queryable via public API. 5. **Crash safety**: Jobs interrupted by a crash are requeued on the next startup. ## Non-Goals - Cross-shard WAL replay (single-node scope). - Persistent job queue (queue is in-memory; restarted jobs must be re-submitted if the process crashes before processing). - Real-time progress reporting (callers poll `purge_job_status`). ## Key Invariants - Cohort ledger scores must never go below 0.0 after a purge. - Purging user A must not alter user B's contributions. - Purging the same user twice is safe and idempotent. ## Public API Surface ```rust // Submit a background re-materialization job. db.submit_purge_job(user_id, community_id, signal_type_filter) -> Result // Poll job status. db.purge_job_status(&job_id) -> Result> // Snapshot engine counters. db.rematerialization_metrics() -> Result ``` ## Acceptance Criteria - [ ] `submit_purge_job` returns a `JobId` without blocking. - [ ] `purge_job_status` returns `Pending` immediately after submission. - [ ] In persistent mode, jobs transition to `Succeeded` within 10 seconds for an empty WAL. - [ ] After a job succeeds, cohort ledger reflects the purged user's contributions removed. - [ ] `rematerialization_metrics` reflects jobs processed. - [ ] Interrupted (Running) jobs are requeued on startup. - [ ] Audit log entries are written after each job completion.