* perf(notifications): save mobile dismissal history as per-delivery SQLite rows
Each alert or dismissal rewrote the whole pretty-printed history file (hundreds of KB).
Rows now save individually through a shared row cache that fails fast on a locked file,
rebuilds once on corruption, and re-reads its baseline after outside commits. Unread
history is never replaced: events queue and merge once a retry reads it. An older build's
file is imported with a receipt committed alongside its rows, then removed only while it
is still that file.
The mobile-restore test now drains the original host's recovery-capsule work before
starting the recovered host, instead of relying on the old asynchronous file write.
* perf(model-catalog): save the agent model catalog as per-entry SQLite rows
Every listing change rewrote the whole multi-megabyte file. Entries now save only when
they change and failed saves retry with backoff. An older build's file is imported with a
receipt; an unreadable file is kept. If stored state cannot be read (a lock elsewhere),
the session starts cold and saves nothing, deciding nothing between the file and the rows.