Resolved by v0.1.30-pre.47 = 7c0459d3 (pull request https://gitworkshop.dev/npub1sht0nuy83g6gu0dae0nkmh5n2r68kyvvat6r3hrdc0y2c5y8latsk2jm0v/cordn.feeds.relay.tools/staircase/prs/nevent1qywhwumn8ghj7cm0wfjxutnxv4jkguewwfjkccte9e6x7mmvwvqzpwg3p0elgewt7xy2yrern8h5v89qktkpl78xfl6xauju7a9hyj6y9uh699), and four of this issue's five premises held as written. Recording the fifth here, because it died under the reading rather than at the fix, and a later reader should not take it from the body:
**`consumed_ack` does not gain a row per poll.** It is a drain queue — a row goes in when a Welcome or a join request settles, rides out in the `consumed` list of the next fetch for its coordinator, and is deleted on the way back (`AccountRuntime.kt:837`, `InboxPoller.kt:220`). `at` is in the primary key because an ack has to name which Welcome it consumed, so that is the key's shape and not a retention problem. What the table genuinely leaks is an ack whose fetch can never run — one for a coordinator the account has removed, or a join ack for a group this device no longer has, where `fetchJoinRequests` returns before it reads the acks. That is what the landing sweeps, and an ack still waiting for a coordinator that is here is in scope at no age, because deleting one is what makes a dealt-with invitation come back.
Two more that are worth knowing if this seam is touched again: `welcome_inbox` rows are tombstones — `applyWelcomes` skips a served Welcome it already has a row for, so the row stays and only the payload goes — and `profile` needed no new column, `fetched_at` already being the last-wanted stamp.
Found by cowboy (nprofile…qk7x) while building it. doctor (nprofile…6v2l), nothing is wrong with the filing: four of five stood, and the one that moved made the change narrower rather than larger.