feat(FN-4042): add SQLite lock contention recovery in core database layer

Adds SQLite lock contention recovery for WAL-mode databases, covering both the core database layer (db.ts, central-db.ts, store.ts) and the run-audit subsystem, with comprehensive unit and integration test coverage and updated storage documentation.

Fusion-Task-Id: FN-4042
This commit is contained in:
Fusion
2026-05-12 00:40:40 -07:00
committed by gsxdsm
parent 6d6eb7488b
commit 4d47cb4bd6
8 changed files with 540 additions and 36 deletions

View File

@@ -7,6 +7,15 @@
- `config.nextId` is retained only as a legacy compatibility field and optional seed source; runtime task creation no longer mutates it as allocator truth.
- Startup allocator reconciliation bumps each active prefix sequence to `max(current nextSequence, max(existing task suffix)+1)` across live + archived tasks to self-heal stale allocator drift.
## SQLite write-path lock recovery (FN-4042)
- Project and central SQLite connections run in WAL mode with a configured `busy_timeout`, but executor-style writes now add a second bounded recovery layer around outermost write transactions.
- `Database.transaction()` and `CentralDatabase.transaction()` acquire outermost transactions with `BEGIN IMMEDIATE`, so writer-lock contention is detected before the callback executes. This allows retrying lock acquisition without re-running user code.
- Recovery is intentionally bounded: transient `SQLITE_BUSY` / `SQLITE_LOCKED` failures on outermost `BEGIN IMMEDIATE` and `COMMIT` are retried for a short additional window with small synchronous backoff sleeps. If the lock does not clear, the original write still fails loudly.
- Nested transactions still use SQLite `SAVEPOINT` / `ROLLBACK TO` / `RELEASE`, so inner rollback semantics are unchanged: an inner failure can roll back independently and the outer transaction can continue.
- Task writes that use `atomicWriteTaskJsonWithAudit()` still keep the task-row upsert and matching `runAuditEvents` insert in one SQLite transaction. They either commit together or roll back together; the compatibility `task.json` write still happens only after the SQLite transaction succeeds.
- Direct `recordRunAuditEvent()` writes now also execute inside the shared transaction helper so they benefit from the same lock recovery and do not duplicate rows during transient contention.
## 1) Summary
- **localStorage keys in runtime dashboard code:** **20**