Found while verifying the #590 fix (2026-08-13). Severity: the WAL subsystem's core guarantee is silently void.
Chain:
wal.NewWriter (cmd/arc/main.go:710) creates the writer, which immediately rotates in its active file (header-only, 7 bytes).
- Startup recovery (cmd/arc/main.go:771) calls
RecoverWithOptions without SkipActiveFile — the periodic flush-failure recovery path (main.go:842) passes it correctly, the startup call forgot it.
internal/wal/recovery.go deletes empty (header-only) files after scanning — which is the writer's own active file.
- The writer keeps appending to the now-unlinked inode for the whole session.
data/wal/ is empty while the server runs; on crash, nothing exists to replay.
Observed: every crash-replay test performed today (multiple binaries, fsync mode, multi-second waits) recovered 0 entries; the WAL directory is empty during operation on any WAL-enabled instance.
Fix: pass SkipActiveFile: walWriter.CurrentFile() in the startup recovery call, mirroring main.go:842.
🤖 Generated with Claude Code
Found while verifying the #590 fix (2026-08-13). Severity: the WAL subsystem's core guarantee is silently void.
Chain:
wal.NewWriter(cmd/arc/main.go:710) creates the writer, which immediately rotates in its active file (header-only, 7 bytes).RecoverWithOptionswithoutSkipActiveFile— the periodic flush-failure recovery path (main.go:842) passes it correctly, the startup call forgot it.internal/wal/recovery.godeletes empty (header-only) files after scanning — which is the writer's own active file.data/wal/is empty while the server runs; on crash, nothing exists to replay.Observed: every crash-replay test performed today (multiple binaries, fsync mode, multi-second waits) recovered 0 entries; the WAL directory is empty during operation on any WAL-enabled instance.
Fix: pass
SkipActiveFile: walWriter.CurrentFile()in the startup recovery call, mirroring main.go:842.🤖 Generated with Claude Code