fix: recurring hourly sentinel.db backup - #508
Open
essentialbit wants to merge 11 commits into
Open
Conversation
…ata-loss incidents) data/sentinel.db had no automated backup -- the SSD mirror was manual/sporadic and was 2 days stale both times it was actually needed for recovery (2026-07-13, 2026-07-20), costing agent_track_record history and proposal rows neither time recoverable. db_backup.py uses sqlite3's online backup API (consistent even while main.py's live process holds the DB open), writes to the SSD mirror when mounted else a local data/backups/ fallback, prunes to the last 48 (2 days at hourly cadence). Wired as a new hourly APScheduler job.
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
data/sentinel.dbhad no automated recurring backup, only a manual/sporadic SSD mirror — which was 2 days stale both times it was actually needed for recovery (2026-07-13 self-symlink incident, 2026-07-20 stale-worktree-snippet incident), permanently losingagent_track_record/feature_backloghistory each time.db_backup.py: uses sqlite3's online backup API (Connection.backup()), which is transactionally consistent even whilemain.py's live process holds the DB open — not a raw file copy. Writes to the SSD mirror (/Volumes/Iron 1TBSSD/Claude/FredAI/data/backups) when mounted, else falls back to a localdata/backups/dir (already gitignored via the existing blanketdata/rule). Prunes to the last 48 snapshots (2 days at hourly cadence).job_db_backup,jitter=60), same pattern as every other job inmain.py.Verification
python3 -c "from main import *; print('Import OK')"— clean.sentinel.dbto a temp dir, monkeypatchedDB_PATH/backup dirs, ranbackup_db()5x, confirmed pruning keeps exactlyKEEP_LAST_N, confirmed the resulting snapshot is a real openable SQLite file with the same table set as the source.%Y%m%d-%H%M%S, second resolution) let same-second backup calls collide on filename and silently overwrite each other — 5 calls produced 1 file instead of 5. Fixed by adding microsecond resolution (%f) to the filename timestamp before shipping. Harmless at the real hourly cadence, but a real robustness gap against a manual retrigger.Test plan
from main import *imports cleanly with the new job wired in🤖 Generated with Claude Code