fix: Enhance error classification for PRAGMA integrity check failures

Apply the same enhanced error classification to PRAGMA integrity_check
failures as we do for database open failures.

This ensures users see detailed, actionable recovery steps regardless of
which stage the corruption is detected (open vs integrity check).

Tested with real corruption scenarios - all error paths now provide
specific recovery guidance with exact commands.
This commit is contained in:
kraitsura
2025-12-30 00:43:54 -08:00
parent 602c59eb48
commit 3e453cdc3a

View File

@@ -317,28 +317,66 @@ func CheckDatabaseIntegrity(path string) DoctorCheck {
// This checks the entire database for corruption // This checks the entire database for corruption
rows, err := db.Query("PRAGMA integrity_check") rows, err := db.Query("PRAGMA integrity_check")
if err != nil { if err != nil {
// Classify the error type for better recovery guidance
errMsg := err.Error()
var errorType string
var recoverySteps string
// Check if JSONL recovery is possible // Check if JSONL recovery is possible
jsonlCount, _, jsonlErr := CountJSONLIssues(filepath.Join(beadsDir, "issues.jsonl")) jsonlCount, _, jsonlErr := CountJSONLIssues(filepath.Join(beadsDir, "issues.jsonl"))
if jsonlErr != nil { if jsonlErr != nil {
jsonlCount, _, jsonlErr = CountJSONLIssues(filepath.Join(beadsDir, "beads.jsonl")) jsonlCount, _, jsonlErr = CountJSONLIssues(filepath.Join(beadsDir, "beads.jsonl"))
} }
// Classify error type (same logic as opening errors)
if strings.Contains(errMsg, "database is locked") {
errorType = "Database is locked"
recoverySteps = "1. Check for running bd processes: ps aux | grep bd\n" +
"2. Kill any stale processes\n" +
"3. Remove stale locks: rm .beads/beads.db-shm .beads/beads.db-wal .beads/daemon.lock\n" +
"4. Retry: bd doctor --fix"
} else if strings.Contains(errMsg, "not a database") || strings.Contains(errMsg, "file is not a database") {
errorType = "File is not a valid SQLite database"
if jsonlErr == nil && jsonlCount > 0 { if jsonlErr == nil && jsonlCount > 0 {
return DoctorCheck{ recoverySteps = fmt.Sprintf("Database file is corrupted beyond repair.\n\n"+
Name: "Database Integrity", "Recovery steps:\n"+
Status: StatusError, "1. Backup corrupt database: mv .beads/beads.db .beads/beads.db.broken\n"+
Message: fmt.Sprintf("Failed to run integrity check (JSONL has %d issues for recovery)", jsonlCount), "2. Rebuild from JSONL (%d issues): bd doctor --fix --force --source=jsonl\n"+
Detail: err.Error(), "3. Verify: bd stats", jsonlCount)
Fix: "Run 'bd doctor --fix' to recover from JSONL backup", } else {
recoverySteps = "Database file is corrupted and no JSONL backup found.\n" +
"Manual recovery required:\n" +
"1. Restore from git: git checkout HEAD -- .beads/issues.jsonl\n" +
"2. Rebuild database: bd doctor --fix --force"
}
} else if strings.Contains(errMsg, "migration") || strings.Contains(errMsg, "validation failed") {
errorType = "Database migration or validation failed"
if jsonlErr == nil && jsonlCount > 0 {
recoverySteps = fmt.Sprintf("Database has validation errors (possibly orphaned dependencies).\n\n"+
"Recovery steps:\n"+
"1. Backup database: mv .beads/beads.db .beads/beads.db.broken\n"+
"2. Rebuild from JSONL (%d issues): bd doctor --fix --force --source=jsonl\n"+
"3. Verify: bd stats\n\n"+
"Alternative: bd doctor --fix --force (attempts to repair in-place)", jsonlCount)
} else {
recoverySteps = "Database validation failed and no JSONL backup available.\n" +
"Try: bd doctor --fix --force"
}
} else {
errorType = "Failed to run integrity check"
if jsonlErr == nil && jsonlCount > 0 {
recoverySteps = fmt.Sprintf("Run 'bd doctor --fix --force --source=jsonl' to rebuild from JSONL (%d issues)", jsonlCount)
} else {
recoverySteps = "Run 'bd doctor --fix --force' to attempt recovery"
} }
} }
return DoctorCheck{ return DoctorCheck{
Name: "Database Integrity", Name: "Database Integrity",
Status: StatusError, Status: StatusError,
Message: "Failed to run integrity check", Message: errorType,
Detail: err.Error(), Detail: fmt.Sprintf("%s\n\nError: %s", recoverySteps, errMsg),
Fix: "Run 'bd doctor --fix' to back up the corrupt DB and rebuild from JSONL (if available), or restore from backup", Fix: "See recovery steps above",
} }
} }
defer rows.Close() defer rows.Close()