v1.0.143
Single critical fix: every Node ≥22.5 install (everyone on v1.0.132 or later) was running with busy_timeout = 0 on the SessionDB and ContentStore. Multi-writer SQLite operations failed instantly with Error: database is locked instead of waiting up to 30s like ADR-0001 promises.
Fix
node:sqlite adapter now sets busy_timeout (#642). When commit 302bb7b (#228) added the dual loadDatabase() adapter pattern in 2024, the node:sqlite (Node ≥22.5) branch constructed new DatabaseSync(path, { readOnly }) and dropped opts.timeout on the floor. node:sqlite's constructor silently ignores { timeout } — the Bun branch got the matching pragma("busy_timeout = ...") fix two hours later in #243, but the node:sqlite branch was never updated. Two years live.
Symptom: SessionStart hook's unconditional DELETE + ensureSession raced against any concurrent MCP write (multi-window, parallel hooks, lifecycle sweep) and surfaced as instant SQLITE_BUSY instead of waiting 30s. The reporter's withRetry() wrapper around withRetry(() => ...) was 30,000× weaker than the ADR-0001 contract claimed because the underlying pragma was never set.
Fix is one line: adapter.pragma(\busy_timeout = ${opts.timeout}`)afterDatabaseSync` construction on the Node-modern branch. Restores the ADR-0001 multi-writer contract that v1.0.130's lockfile rollback assumed was working. Closes #642.
Tests
3 new tests added to existing tests/util/db-base-platform-gate.test.ts (CONTRIBUTING L275 — no new test files):
- Runtime invariant — public
loadDatabase()factory +pragma("busy_timeout")assertion, driver-agnostic - Source-pin invariant — regex-pins
NodeDatabaseFactoryMUST contain thebusy_timeoutpragma call (RED→GREEN proven viagit stash) - node:sqlite direct (host-gated on
require('node:sqlite')) — adapter wiring sanity
Mirrors ADR-0001's dual-anchor defense pattern (behavioral + source-pin).
105/105 adjacent DB tests pass. Full suite preserves baseline.
Compatibility
15 adapters, 3 OS. No schema migration. engines.node >= 22.5.0 preserved.
Upgrade
npm install -g context-mode@latest
# Restart Claude Code (Cmd+Q + reopen) — the busy_timeout is set at DB open, so existing in-memory DB handles keep the old (zero) value until restart.Why this matters
If you ever saw SQLITE_BUSY: database is locked from any context-mode operation since v1.0.132, this is why. Multi-window users especially. The ADR-0001 contract was effectively unenforced on the dominant Node path for two years — v1.0.130's lockfile rollback shipped on top of this undiagnosed regression, making "ADR-0001 multi-writer-safe" technically true but practically defeated.
Credits
- Reporter who diagnosed #642 — pointed at exactly the right code path (
NodeSQLiteAdapterconstructor) with the exact mechanism (silently-ignored{ timeout }option). Their suggested wrap ofhooks/sessionstart.mjsDELETE indb.withRetry()is a sound defense-in-depth follow-up.