Bound deletion-audit capacity by live parts and report refusal reasons (#84) #36
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
backmeupplz/jev_antispam_bot!36
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/84-audit-capacity-undelivered"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes agentboard #84: Jev stopped deleting all spam because the deletion-audit outbox was "full".
Root cause
PostgresDeletionAudit.preparerefused whenCOUNT(*) FROM deletion_audit_parts+ new parts > capacity (10,000). That count included parts that were already finished (sent, failed deletions, unknown/terminal sends), and those are only removed at 7-day retention expiry. At about 5k deletions/day the retained rows reached 10k, and after that every deletion was skipped (fail-closed).Change
LIVE_PARTS_SQL): parts that arepending/sending, under anintent/pending/sendingparent that has not expired, i.e. work that may still be sent. Finished rows stay for dedupe and inspection until retention expiry but no longer occupy capacity. Excluding onlysentwould not be enough: the live DB holds ~1kdelete_failedparts. Dedupe/fencing, retention, the sink lock and fail-closed DB errors are unchanged.preparetakes an optionalrefused(reason)callback with fixed reasonsinvalid | closing | duplicate | capacity | database. It fires once, after COMMIT settles. The bot logs it asreasonondeletion_audit outcome=intent_unavailable_delete_skipped(unavailablewhen none was reported).health()gainscapacityRefused.deletion_audit_parts_live,deletion_audit_outbox_liveanddeletion_audit_outbox_leased, creating them only when missing. It takes the sink row first, so it cannot deadlock a live replica.CREATE INDEX IF NOT EXISTSlocked tables on every start, and the 005 backfill scanned every row. Startup still re-inserts the sink row.expires_atindex (statement_timestamp()) and deletes at most 100 reports per pass.docs/audit-outbox.md).Deploy note
On the first start, 006 creates the 3 partial indexes once (current tables hold ~3.7k parts, so this takes milliseconds). Later starts take no table locks.
Tests (integration, real PostgreSQL)
capacity. Delivery frees capacity immediately. This test fails onmain.duplicate,database,closingandinvalid. A bot test asserts the loggedreason.bun run check: 498 pass, 0 fail (CI green).