Three of the four leads were clean; the second was real and is now fixed.
197 dead tuples held plaintext that an UPDATE had blanked — 'we
deleted it' was true of the live row and false of the heap. buddies 19
against 2 live, group_members 9 against 0. That last one is why lead 1
looked clean: both live groups ARE sealed, and the plaintext member rows
were still in the heap underneath.
The root cause is an autovacuum default worth knowing generally.
Autovacuum triggers at 50 dead rows + 20% of the table, so a two-row table
needs fifty dead tuples before it is ever looked at — meaning the SMALLEST
tables, which here are the ones holding account and contact data, were
never vacuumed at all. buddies had an empty last_autovacuum.
Fixed in two parts because neither suffices alone: per-table thresholds
(5 rows, scale factor 0) bound the accumulation, and a weekly VACUUM FULL
erases it. Plain autovacuum only marks space reusable — the bytes
survive until overwritten. Only a rewrite removes them.
197 -> 0, relay healthy throughout.
Clean: attachments has no content column at all, all 20 on-disk blobs are
opaque under a magic-number scan, the legacy non-E2E upload route no
longer exists (one upload route remains), and the legacy messages table is
empty.
Recorded as NOT covered: the WAL archive and base backups hold the old
tuples and the vacuum does not reach them. They are encrypted, so it is
bounded rather than open — but retention, not the vacuum, is what decides
when that ends.
Three of the four leads were clean; the second was real and is now fixed.
**197 dead tuples held plaintext that an UPDATE had blanked** — 'we
deleted it' was true of the live row and false of the heap. `buddies` 19
against 2 live, `group_members` 9 against 0. That last one is why lead 1
looked clean: both live groups ARE sealed, and the plaintext member rows
were still in the heap underneath.
**The root cause is an autovacuum default worth knowing generally.**
Autovacuum triggers at 50 dead rows + 20% of the table, so a two-row table
needs fifty dead tuples before it is ever looked at — meaning the SMALLEST
tables, which here are the ones holding account and contact data, were
never vacuumed at all. `buddies` had an empty `last_autovacuum`.
Fixed in two parts because neither suffices alone: per-table thresholds
(5 rows, scale factor 0) bound the accumulation, and a weekly VACUUM FULL
erases it. Plain autovacuum only marks space reusable — the bytes
survive until overwritten. Only a rewrite removes them.
197 -> 0, relay healthy throughout.
Clean: attachments has no content column at all, all 20 on-disk blobs are
opaque under a magic-number scan, the legacy non-E2E upload route no
longer exists (one upload route remains), and the legacy messages table is
empty.
Recorded as NOT covered: the WAL archive and base backups hold the old
tuples and the vacuum does not reach them. They are encrypted, so it is
bounded rather than open — but retention, not the vacuum, is what decides
when that ends.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Three of the four leads were clean; the second was real and is now fixed.
197 dead tuples held plaintext that an UPDATE had blanked — 'we
deleted it' was true of the live row and false of the heap.
buddies19against 2 live,
group_members9 against 0. That last one is why lead 1looked clean: both live groups ARE sealed, and the plaintext member rows
were still in the heap underneath.
The root cause is an autovacuum default worth knowing generally.
Autovacuum triggers at 50 dead rows + 20% of the table, so a two-row table
needs fifty dead tuples before it is ever looked at — meaning the SMALLEST
tables, which here are the ones holding account and contact data, were
never vacuumed at all.
buddieshad an emptylast_autovacuum.Fixed in two parts because neither suffices alone: per-table thresholds
(5 rows, scale factor 0) bound the accumulation, and a weekly VACUUM FULL
erases it. Plain autovacuum only marks space reusable — the bytes
survive until overwritten. Only a rewrite removes them.
197 -> 0, relay healthy throughout.
Clean: attachments has no content column at all, all 20 on-disk blobs are
opaque under a magic-number scan, the legacy non-E2E upload route no
longer exists (one upload route remains), and the legacy messages table is
empty.
Recorded as NOT covered: the WAL archive and base backups hold the old
tuples and the vacuum does not reach them. They are encrypted, so it is
bounded rather than open — but retention, not the vacuum, is what decides
when that ends.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
assigned to @paulhitt
mentioned in commit
045112d1b6mentioned in issue #17
changed the description