Skip to content

fix(recovery): tolerate -shm sidecars when WAL is safe (issue #51) - #53

Merged
pablontiv merged 1 commit into
mainfrom
fix/issue-51-recover-shm
Aug 22, 2026
Merged

fix(recovery): tolerate -shm sidecars when WAL is safe (issue #51)#53
pablontiv merged 1 commit into
mainfrom
fix/issue-51-recover-shm

Conversation

@pablontiv

Copy link
Copy Markdown
Owner

Root Cause

The recover --dry-run command fails with "unexpected SQLite sidecar namespace entry" when recovering against a WAL-mode database with a -shm file, even when the -wal file is zero bytes (indicating no pending changes).

The chicken-and-egg bug:

  1. Startup phase (index_prepare) opens the database → creates -shm sidecar
  2. Recovery handler runs and calls ensureSourceSidecarsSafe
  3. Sidecar check rejects the -shm file that startup just created

Root cause: ensureSourceSidecarsSafe rejected -shm unconditionally, without considering whether the database had active writers. A zero-byte -wal file guarantees no uncheckpointed changes, meaning no active writer is modifying the database.

Solution (Approach B)

Modified ensureSourceSidecarsSafe to tolerate -shm files when the -wal is zero bytes or absent, matching the existing logic for -wal files. The safety property is preserved: if WAL has no pending changes, -shm is safe to tolerate.

This is narrower and more surgical than approach (A) which would skip the entire startup phase for recover commands.

Safety Property

  • Zero-byte -wal file = no uncheckpointed changes
  • No uncheckpointed changes = no active writer
  • No active writer = -shm is safe to read immutably
  • Therefore: tolerating -shm when -wal is safe maintains the invariant

Tests

Added unit tests (internal/recovery/recovery_test.go):

  • TestEnsureSourceSidecarsToleratesZeroByteWAL: confirms zero-byte -wal is tolerated
  • TestEnsureSourceSidecarsToleratesSHMWithZeroWAL: new fix - tolerates -shm when -wal is zero
  • TestEnsureSourceSidecarsToleratesSHMWithoutWAL: new fix - tolerates -shm when -wal is absent
  • TestEnsureSourceSidecarsRejectsSHMWithNonZeroWAL: verifies -shm is still rejected when -wal has pending changes

Added CLI integration test (cmd/backscroll/main_test.go):

Updated existing test:

  • TestRecoverSQLiteSidecarPolicy/empty_active_shm_tolerated_before_replacement: changed from expecting rejection to expecting tolerance (now verifies the fix)

Verification

$ just ci
Coverage: 86.5%  ✓

All tests pass, coverage maintained above 85% gate.

Closes #51

https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF

The recover --dry-run command would fail with "unexpected SQLite sidecar
namespace entry" when recovering against a WAL-mode database that had a
-shm file, even with a zero-byte -wal file indicating no pending changes.

The chicken-and-egg bug: startup index_prepare opens the database
(creating -shm), then recovery rejects the sidecar it just created.

**Root cause**: ensureSourceSidecarsSafe rejected -shm unconditionally,
without considering whether the database had active writers.

**Fix (approach B)**: Tolerate -shm files when the -wal is zero bytes or
absent, matching the existing logic for -wal files. The safety property
is preserved: if WAL has no pending changes, no active writer is
modifying the database. This mirrors SQLite's own reasoning about when
WAL sidecars are safe.

**Safety**: A zero-byte -wal file guarantees no uncheckpointed changes.
A -shm file alone does not prove an active connection, so when -wal is
safe, -shm is also safe to tolerate.

Added three new unit tests:
- TestEnsureSourceSidecarsToleratesSHMWithZeroWAL
- TestEnsureSourceSidecarsToleratesSHMWithoutWAL
- TestEnsureSourceSidecarsRejectsSHMWithNonZeroWAL

Added CLI integration test:
- TestRecoverDryRunWithWALSidecars: verifies recover --dry-run succeeds
  against a WAL-mode database with -shm sidecar

Updated existing test:
- TestRecoverSQLiteSidecarPolicy/empty_active_shm_tolerated_before_replacement:
  changed from expecting rejection to expecting tolerance (reflects the fix)

Closes #51

Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
@pablontiv
pablontiv merged commit 45caf51 into main Aug 22, 2026
6 checks passed
@pablontiv
pablontiv deleted the fix/issue-51-recover-shm branch August 22, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: recover --from <active-db> rejects the -shm sidecar its own startup creates

1 participant