Adds the M9 purge re-materialization feature: a WAL-replay background
engine that rebuilds community cohort aggregates for a (user, community)
pair after retroactive signal purge, restoring ranking correctness without
modifying the immutable WAL.
Key additions:
- cohort::rematerialization module: PurgeJobQueue, RematerializationEngine,
WAL replay, atomic CohortSignalLedger swap, BLAKE3 audit log, metrics counters
- TidalDb::{submit_purge_job, purge_job_status, rematerialization_metrics}
public API (db/rematerialization.rs)
- Engine auto-starts in persistent mode; clean shutdown before WAL teardown
- 6 integration tests in tests/m9_purge_remat.rs covering ephemeral and
persistent modes, job lifecycle, and multi-job independence
- Split oversized files to comply with 600-line limit: db/mod.rs →
db/from_parts.rs, entities/revocation.rs → revocation/{mod,tests}.rs,
schema/validation/builders.rs → builders/{mod,tests}.rs,
signals/warm.rs → warm/{mod,tests,proptests}.rs
- Fix pre-existing bootstrap errors: export AuditKind from session module,
add overrides_rejected to SessionSnapshot deserialization
2.6 KiB
2.6 KiB
QA Plan: Re-materialization after Purge
Unit Tests (lib)
job.rs
submit_and_claim: submit job → claim → status Runningfifo_order: three jobs claimed in submission orderstatus_transitions: Running → Succeededpermanently_failed_after_max_attempts: 5 failures → PermanentlyFailedrequeue_interrupted: Running → Pending on requeue_interruptedlist_jobs_preserves_order: order matches submissionserde_round_trip: JSON roundtrip of PurgeJob
metrics.rs (covered by integration)
replay.rs
empty_contributions_returns_zero_excluded: no filter → no exclusionsexclusion_set_excludes_matching_events: exact 4-tuple matchevents_not_in_set_are_replayed: non-matching events pass through
swap.rs
swap_replaces_entry_values: scratch count wins over live countabsent_from_scratch_removes_from_live: zero-event entries removedunrelated_community_untouched: other cohorts not affected
audit.rs
write_and_read_single_entry: roundtrip success entryread_audit_log_multiple_entries: multiple entries preserved in orderchecksum_mismatch_detected: corrupt entry detectedwrite_failure_entry: failure entry fields correctverification_checksum_is_deterministic: same ledger → same hash
mod.rs (engine)
engine_starts_and_stops: worker starts and stops cleanlyjob_with_empty_wal_succeeds: empty WAL → Succeededshutdown_within_one_second: shutdown latency < 1s
purge.rs (fixed pre-existing)
purge_returns_manifest_with_drained_entriessecond_purge_produces_empty_entriespurge_retracts_from_ledger(fixed ancient timestamp bug)manifest_json_roundtripmanifest_from_malformed_json_returns_none
Integration Tests (m9_purge_remat.rs)
submit_purge_job_returns_job_id— API surface works, JobId is non-zeropurge_job_status_pending_after_submit— Pending immediately after submit (ephemeral, no engine)unknown_job_id_returns_none— unknown job → Nonerematerialization_metrics_snapshot_is_valid— fresh db has zero countersjob_succeeds_in_persistent_mode— engine starts, processes job, metrics updated (< 10s)multiple_jobs_processed_independently— two jobs for different users both succeed (< 15s)
Regression Tests (m9_retroactive_purge.rs)
Existing 8 tests cover request_community_purge correctness; all must still pass.
Acceptance Criteria
- All 1299 lib tests pass
- All 6 m9_purge_remat integration tests pass
- All 8 m9_retroactive_purge integration tests pass
cargo clippy -- -D warningscleancargo fmt --checkclean