Skip to content

Nightly snapshot/usage sweep leaves orphan D1 mirror rows for deleted vaults (unbounded) #227

Description

@unforced

Problem

The nightly sweeps that mirror per-vault state into D1 have no orphan prune, so rows for vaults that no longer exist accumulate without bound.

  • workers/identity/src/snapshots.ts:160 is the only writer of vault_snapshots: a per-vault REPLACE (DELETE FROM vault_snapshots WHERE vault_name = ? then reinsert the current manifest) run once per vault the sweep enumerates.
  • The sweep enumerates only rows in vaults. A vault that has been deleted is never enumerated again, so its old mirror rows are never revisited or removed.
  • vault_usage (src/usage.ts, upsert per (vault_name, day)) has the same shape and the same leak.

This is a direct contributor to the O(fleet) growth behind #224. At the time of the 2026-07-26 staging reclamation there were 1,524 orphan vault_snapshots rows and 1,008 orphan vault_usage rows for vaults that no longer existed.

Fix (one line, per sweep)

At the end of each sweep, drop rows whose vault is gone:

DELETE FROM vault_snapshots WHERE vault_name NOT IN (SELECT name FROM vaults);
DELETE FROM vault_usage     WHERE vault_name NOT IN (SELECT name FROM vaults);

Safe by construction — a vault_name absent from vaults cannot belong to a live vault. This keeps both mirror tables bounded to the live fleet going forward. (The historical orphans were already cleared by hand in the 2026-07-26 reclamation.)

Related: #224. Best paired with the hosted vault-delete path (separate issue) so deletes prune their own mirror rows synchronously, with this sweep-time prune as the backstop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions