Files
buzz/desktop/src-tauri/src/archive
Will Pfleger fc2ce6728b feat(archive): add observer-frame retention schema and gated DB adapter (#5719)
The local-save archive (`~/.buzz/archive/archive.db`) grows without
bound — observer frames (kind 24200) are 99.95% of it by bytes (~1.3M
rows, 75–375 MB/day). This lays the schema and process-wide foundations
for bounding that growth: a single global retention window for observer
frames, kept in `archive_meta`, plus the gated DB adapter every later
phase builds on. The prune worker that actually deletes lands in a
follow-up; nothing here removes data.

## What this adds

- **Migration M4** (`add_archive_meta`, crash-safe): creates the
`archive_meta` k/v table and the `archived_at`-covering scope-age index
used by the future prune scan, and seeds `observer_retention_days=30`.
Runs under one `BEGIN IMMEDIATE` with an in-lock marker recheck and the
marker written last, so a crash before COMMIT rolls back every object
and the next open re-runs from scratch. Fails closed on an
externally-created `archive_meta` present without the marker.
- **Process init barrier + gated `ArchiveDb` adapter** owning every
production open. All subscription-mutation commands and the archive sync
task route their DB work through `ArchiveDb::with_conn`, which awaits
the init barrier once. This also fixes a pre-existing bug where
`create_save_subscription` ran blocking DB work on the async runtime.
- **Commands**: `get_observer_retention_days` /
`set_observer_retention_days` (fail-closed — rejects days `< 1` or `>
36500` before writing) and `archive_size_stats` (physical file bytes for
the main DB + `-wal` sidecar, plus `page_size` / `page_count` /
`freelist_count` — PRAGMAs and file metadata only, no payload scans).

## Scope

Observer frames (24200) are the only kind with a retention setting.
NIP-AM metrics (44200) and every other archived kind are kept
indefinitely with no retention state — no policy table, no per-kind or
per-subscription configurability. This is the simplified design ruled in
over the earlier per-subscription × per-kind approach: bounding observer
frames alone captures essentially all the value.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-08-21 13:35:33 -04:00
..