Deletion is promised in customer copy, and no tenant-wide deleter exists.
The dead-sweep detector (formerly filed as an open issue here) closed 2026-09-01 β see History. Its unscheduled scheduling half is a separate, newly-filed issue not yet assessed by this page.
Destruction-first: what each defect can destroy if left alone. Of ADR-138's two deleters, the connector-scoped one (stage 4) exists and runs today; the tenant-wide one (stage 6) does not. So the over-deletion defect in the deleter that exists comes first (#2944), the unbuilt deleter's resumability design second (#2941) β the dead-sweep detector this section historically ranked third has since closed; see History.
What it ignores: priority labels (#2944 is p2 and sits first), filing order and age (all three filed 2026-08-01 within the same minute), how cheap a fix looks, and the 30-day promise as an urgency lever β the standing ruling that manual deletion suffices today means the promise alone does not pull the sweep detector up.
Evidence below is generated from the read-only audit of 2026-08-29 and reconciled against the open issues at build time. Every claim cites the issue it came from. Nothing here is a decision β rulings stay in the prose above, which is written by hand.
The subject code does not exist yet, so nothing has closed the design gap. Population enumerated: `git grep -rln 'delete_tenant\|tenant_teardown\|purge_tenant\|delete_all_tenant' origin/main -- backend supabase` β ONE hit, backend/conftest.py (a test fixture), zero in app or migrations; `ls backend/app/slices/source/deleters/` on origin/main β exactly three files, all connector-scoped (connector_data_deleter.py, gmail_connector_deleter.py, whatsapp_connector_deleter.py). Partial credit that narrows the remaining design work, and which the issue predates: the durable-harvest mechanism it asks for EXISTS and is in use at connector scope β `public.storage_deletion_queue` is written before deletion at backend/app/slices/source/deleters/connector_data_deleter.py:288 (`INSERT INTO storage_deletion_queue (tenant_id, storage_key) β¦`) and drained independently by backend/app/services/storage/storage_purge_service.py:154+. So the D7a retry-orphan half has a shipped pattern; transaction granularity, per-table watermark and the kill-mid-run real-DB test remain unwritten.
origin/main:backend/app/slices/source/deleters/connector_data_deleter.py:313-338 β `_delete_graph`'s first statement is still `DELETE FROM nodes_v2 n WHERE n.tenant_id=$1 AND n.provenance_person_ids && $2::uuid[]` + `_NODE_NOT_BOUND_TO_A_VIEWER`, and the load-bearing comment the issue quotes survives verbatim: 'A cross-connector-merged node also bridging a surviving identity is over-deleted, but self-heals: that identity is intact and re-materializes next enrich.' No `bool_and`-style sparing was added on the node path (the `bool_and(ps.source_id = ANY($2))` sparing at line ~100 is still identity-only, in `find_gone_person_ids`). What HAS been added since filing is a different guard: `_NODE_NOT_BOUND_TO_A_VIEWER` (ADR-142 viewer_bindings ON DELETE RESTRICT) and `_sparing_linked_viewers` β those spare VIEWER-bound person nodes, not cross-connector-merged content nodes, so they do not close this. Reachable in production today: `delete_connector_data` is called from gmail_connector_deleter.py:36-37 and whatsapp_connector_deleter.py:35-36,74 (disconnect path). The second `_delete_graph` statement carries an explicit owner acceptance dated 2026-08-05 for the CONTENT half of the same tradeoff ('cross-connector overlap is rare... Accepted by the owner') β the person-node half this issue is about carries no such acceptance.
On origin/main the three deleters still open `pg.async_transaction()` and issue every statement with no budget: `backend/app/slices/source/deleters/gmail_connector_deleter.py:33` and `whatsapp_connector_deleter.py:28,54` open the transaction; `git grep -n 'apply_statement_budget\|timeout=' origin/main -- backend/app/slices/source/deleters/` returns ZERO hits across all three files (population = every file under that directory), while ~30 `conn.execute`/`conn.fetch` sites remain (connector_data_deleter.py:97β419, whatsapp_connector_deleter.py:82β217, gmail_connector_deleter.py:45,55). The sweep's own call site documents the defect as still live: `backend/app/services/connectors/connector_deletion_sweep_service.py:261-268` β "every statement here is capped at the pool's 30s command_timeout and a large tenant's delete cannot completeβ¦ wrapping THIS call is a no-op and was removed for reading as a fix." The statement-timeout lift shipped in PR #3547 landed on the materializer/node-index path (`apply_statement_budget` appears only in pg.py, connector_deletion_sweep_service.py's comment, materialize_manifest_repository.py, materialize_name_surface_repository.py, graph_materializer.py), not in the deleters.
5 assessed issues closed since the audit and are not shown β a closed issue's evidence is history, and printing it as current is how a page starts lying.
ADR-138 merged 2026-08-01 (PR #2871, commit 3d1aae2b2) β the retention-and-deletion policy. Its four-lens adversarial review produced the three open issues above, each blocking a stage of the program, all filed 2026-08-01 within the same minute.
2026-08-27, three of the four stage-5 follow-ups closed: #3479 (reconnect now cancels a pending deletion, PR #3616), #3481 (a disconnected WhatsApp account frees its paid slot, PR #3621), and #3483 (retries bounded at the claim, not the settle, PR #3625). #3480 (the 30s pool timeout on a large tenant's delete) remains open.
2026-09-01, the dead-sweep detector (#2942) closed by the 2026-08-29 track reconciliation: the staleness checker itself is built and tested with a real writer (migration 20260813111854). The 2026-08-27 deletion-sweep cutover had already moved the sweep it watches off cron.job and onto a worker-process drain loop, which the checker needed to be re-pointed at. The unscheduled scheduling half β nothing invokes the checker on a cadence β is re-filed as #3724.