Addresses review feedback (Greptile P1/P2, CodeRabbit) on the async
background integrity check. All three issues shared one root cause:
state read/cleared from a pre-await snapshot across the async boundary.
- Closed-instance race (P1): runBackgroundIntegrityCheck guards `this.closed`
before every in-process integrityCheck() call (both before the offload and
after the await). A connection closing mid-offload no longer throws out of
the scheduler.
- Stuck-pending on throw + late-subscriber race (P1/P2): the scheduler now
clears integrityCheckPending UNCONDITIONALLY in a finally, iterating the
CURRENT shared.subscribers set rather than a pre-await snapshot. A thrown
check, or a Database that subscribed during the seconds-long await window,
can no longer be left pinned at integrityCheckPending=true forever.
- No spawn timeout (P2): integrityCheckSqliteFileAsync now passes
AbortSignal.timeout(5m); a disk-stalled/hung sqlite3 child always settles
the promise (→ verified:false fallback) instead of leaking and stranding
the shared entry. AbortSignal.timeout's timer is unref'd, so it never keeps
the process alive at shutdown.
- FNXC markers added to the two new symbols (per AGENTS.md convention).
Rejected: the suggestion to remove the `// FNXC:Database` marker — FNXC is a
mandatory project convention (AGENTS.md), and a prior review flagged the
absence of these markers as a defect.
Tests: regression test that pending clears for all participants when the
check throws; test that runBackgroundIntegrityCheck returns ok without
throwing on a closed instance; strengthened the healthy-DB assertion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>