fix(daemon): detect external db file replacement

When git merge replaces the .beads/beads.db file, the daemon's
SQLite connection becomes stale (still reading deleted inode).
This adds FreshnessChecker that detects file replacement via
inode/mtime comparison and triggers automatic reconnection.

Implementation:
- freshness.go: monitors db file for replacement
- store.go: adds EnableFreshnessChecking() and reconnect()
- queries.go: calls checkFreshness() on GetIssue/SearchIssues
- daemon.go: enables freshness checking at startup
- freshness_test.go: comprehensive tests including merge scenario

Code quality (per review):
- Extract configureConnectionPool() helper to reduce duplication
- Handle Close() error in reconnect() (log but continue)
- Use t.Cleanup() pattern in tests per project conventions
- Rename setupFreshnessTest() per naming conventions

Overhead: ~2.6μs per read op (~0.8% of total query time)

Signed-off-by: Alessandro De Blasis <alex@deblasis.net>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alessandro De Blasis
2025-12-15 09:40:34 +01:00
parent ac8f5ca590
commit 78c248a17a
5 changed files with 1149 additions and 6 deletions

View File

@@ -371,7 +371,11 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush, localMode bool,
return // Use return instead of os.Exit to allow defers to run
}
defer func() { _ = store.Close() }()
log.log("Database opened: %s", daemonDBPath)
// Enable freshness checking to detect external database file modifications
// (e.g., when git merge replaces the database file)
store.EnableFreshnessChecking()
log.log("Database opened: %s (freshness checking enabled)", daemonDBPath)
// Auto-upgrade .beads/.gitignore if outdated
gitignoreCheck := doctor.CheckGitignore()