feat(selfhost): add retention for agent_context_snapshots - #3937
Conversation
Every table originally flagged as unbounded in #3896 except one turned out already handled: audit_events/ai_usage_events/product_usage_events already have cron-scheduled retention via RETENTION_POLICY (the original audit's grep for literal .delete() calls missed the dynamic DELETE FROM ${table} SQL this module uses), and webhook_events is deliberately excluded per a prior fix (#666) since GitHub can redeliver a webhook long after the original event and this table is the idempotency record that detects that -- adding it back would reintroduce that fixed bug. agent_context_snapshots (one payloadJson blob per agent run, capped only by a per-runId .limit(50) READ, never deleted) was genuinely the only unaddressed table. Add it to RETENTION_POLICY with a 30-day window, reusing the existing generic prune mechanism. Closes #3896
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-07 07:25:24 UTC
⏸️ Suggested Action - Manual Review Review summary Nits — 5 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3937 +/- ##
=======================================
Coverage 93.66% 93.66%
=======================================
Files 372 372
Lines 34859 34859
Branches 12746 12746
=======================================
Hits 32652 32652
Misses 1588 1588
Partials 619 619
🚀 New features to boost your workflow:
|
Summary
This narrows significantly from the original issue after implementation research:
RETENTION_POLICYinsrc/db/retention.ts(pruneExpiredRecords, dispatched by theprune-retentionjob type enqueued daily fromsrc/index.ts). The original audit'sgrep -rn ".delete("check missed this because the deletes are dynamic SQL strings (DELETE FROM ${rule.table} WHERE ...), not literal Drizzle.delete(table)calls.67c11f2e, "fix(db): preserve webhook replay cache during retention" fix(db): exclude webhook_events from destructive retention policy #666) — GitHub can redeliver a webhook long after the original event, and this table is the idempotency/dedup record that detects that. There's a dedicated regression test (test/unit/retention.test.ts, "the policy only targets append-only/log/snapshot tables") assertingwebhook_eventsis never inRETENTION_POLICY. Adding it back would reintroduce that fixed bug — so I did NOT touch it.payloadJsonblob per agent run, capped only by a per-runId.limit(50)read, never deleted) was the one table genuinely still unaddressed. Added it toRETENTION_POLICYwith a 30-day window (shorter than the audit/usage-log tables since it's a per-run diagnostic blob with no cross-run rollup depending on it), reusing the existing generic prune mechanism — no new code path, no new risk surface.Posted a correction comment on #3896 before implementing so the tracking issue reflects this.
Found via a fresh performance/scalability/accuracy hardening audit of the self-host ORB stack. Tracked under #1667.
Scope
src/db/retention.ts— one newRETENTION_POLICYentrytest/unit/retention.test.ts— new test covering the prune behavior foragent_context_snapshotsValidation
npm run typechecknpm run test:coverage(full unsharded) — 560 files / 11067 tests passedgit diff --checkcleanSafety
pruneExpiredRecordsmechanism verbatim — no new deletion code path. Explicitly did NOT touchwebhook_events, avoiding a regression of a previously-fixed bug.Closes #3896