Files
fusion/.changeset/fn-db-corruption-resilience.md
gsxdsm f9e551317f Harden fusion.db against recurring corruption
Root cause: node:sqlite SIGSEGVs inside pager_write leave the B-tree
malformed in a way that still opens but fails integrity checks; large
operational-log tables widen the write window where the crash strikes.

- backup: verify every copy with PRAGMA quick_check, quarantine corrupt
  copies as *.corrupt, and never rotate out the last verified-good backup
- db: add Database.recoverIfCorrupt() startup guard (wired into
  TaskStore.init, disk-backed only, opt out via FUSION_DISABLE_DB_AUTORECOVER)
  that rebuilds a malformed db via sqlite3 .recover, preserving the corrupt
  original; also fixes the latent `.recover main` invalid-option bug that made
  recoverDatabase() always fail
- db: drop lost_and_found* scratch tables on init; add pruneOperationalLogs()
- settings: add operationalLogRetentionDays (default 30, 0 = off) and prune
  activityLog/agentLogEntries/runAuditEvents/agentHeartbeats during maintenance
- dashboard: expose retention in Settings -> Backups -> Database Maintenance

Tests: backup 59/59, db 135/135 (incl. real corrupt->recover->reopen),
self-healing cleanup/corruption 10/10, settings 77/77, SettingsModal 460/460.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:55:10 -07:00

1.2 KiB

@runfusion/fusion
@runfusion/fusion
minor

Harden the project database against the recurring "database disk image is malformed" corruption.

  • Integrity-checked backups: every backup copy is now verified with PRAGMA quick_check before it is kept, a verifiably-corrupt copy is quarantined as *.corrupt instead of masquerading as good, and cleanupOldBackups will never rotate out the last verified-good backup.
  • Startup auto-recovery: on open, a malformed fusion.db is detected and rebuilt offline via sqlite3 .recover (corrupt original preserved as fusion.db.corrupt-<ts>, stale -wal/-shm dropped) before any connection is established. Opt out with FUSION_DISABLE_DB_AUTORECOVER=1. This also fixes a latent bug where the recovery path invoked the non-existent .recover main option and always failed.
  • Database shrink + retention: scratch lost_and_found* tables left by prior recoveries are dropped on init, and a new operationalLogRetentionDays setting (default 30 days, configurable in Settings → Backups → Database Maintenance, 0 to disable) prunes unbounded append-only log tables (activityLog, agentLogEntries, runAuditEvents, agentHeartbeats) during periodic maintenance to curb the file growth that widens the corruption window.