{"record":{"id":"9242496aec7a5f65","repo":"JuliusBrussee/caveman","slug":"record-applied-fix-w","errorCode":null,"errorMessage":"record applied fix: %w","messagePattern":"record applied fix: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/learn_outcomes.go","lineNumber":110,"sourceCode":"\tif err != nil {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"encode before evidence: %w\", err)\n\t}\n\t// Fingerprint the edited artifact as it stands NOW — which at\n\t// `caveman learn applied` time is immediately after the approved edit. This\n\t// is the provenance anchor: a later scan re-hashes the same path and can\n\t// state whether the change we proposed is still the change that is there.\n\ttarget := fingerprintFixTarget(*sink)\n\ttargetJSON := \"\"\n\tif target != nil {\n\t\tif encoded, encodeErr := json.Marshal(target); encodeErr == nil {\n\t\t\ttargetJSON = string(encoded)\n\t\t}\n\t}\n\tresult, err := s.db.Exec(`INSERT INTO applied_fixes\n\t\t(sink_id, practice_id, fix_kind, applied_at, before_tokens_per_turn, before_evidence_json, note, target_json)\n\t\tVALUES (?, ?, ?, ?, ?, ?, ?, ?)`, sink.SinkID, sink.PracticeID, fixKind, appliedAt, sink.TokensPerTurn, string(evidence), note, targetJSON)\n\tif err != nil {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"record applied fix: %w\", err)\n\t}\n\tid, err := result.LastInsertId()\n\tif err != nil {\n\t\treturn AppliedFixRecord{}, fmt.Errorf(\"read applied fix id: %w\", err)\n\t}\n\treturn AppliedFixRecord{\n\t\tRecorded: true, ID: id, SinkID: sink.SinkID, PracticeID: sink.PracticeID,\n\t\tFixKind: fixKind, AppliedAt: appliedAt, BeforeTokensPerTurn: sink.TokensPerTurn,\n\t\tBeforeEvidence: beforeEvidence, BeforeSource: beforeSource, Note: note,\n\t\tTarget: target,\n\t}, nil\n}\n\nfunc beforeSinkForAppliedFix(plan LearnPlan, sinkID string, live *Sink, fallbackCutoff time.Time) (*Sink, string) {\n\tcutoff := fallbackCutoff\n\tif parsed, err := time.Parse(time.RFC3339Nano, plan.computedAt); err == nil {\n\t\tcutoff = parsed\n\t}","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/store/learn_outcomes.go#L92-L128","documentation":"The final INSERT into the applied_fixes table failed; the driver error is wrapped as \"record applied fix\". This is the durable write of the outcome row, so any SQLite-level problem (schema, constraints, I/O) surfaces here.","triggerScenarios":"The 8-column INSERT into applied_fixes fails: table missing (store not migrated), constraint violation (e.g. UNIQUE on sink_id+applied_at if defined), disk full, or read-only database file.","commonSituations":"Opening the store against an old database file without the applied_fixes migration; concurrent writers hitting SQLITE_BUSY; corrupt or locked DB in a container with a read-only mount.","solutions":["Run the store migrations so applied_fixes exists before recording","Check the wrapped %w error for the SQLite cause (no such table, busy, readonly)","Verify the DB file and its directory are writable and not on a read-only mount","Retry on SQLITE_BUSY or configure a busy_timeout"],"exampleFix":"// before\ns.db, _ = sql.Open(\"sqlite\", path) // migrations skipped\n// after\ns.db, _ = sql.Open(\"sqlite\", path)\nif err := s.migrate(ctx); err != nil { return err }","handlingStrategy":"try-catch","validationCode":"var exists int; _ = db.QueryRow(\"SELECT count(*) FROM sqlite_master WHERE type='table' AND name='applied_fixes'\").Scan(&exists); if exists == 0 { runMigrations() }","typeGuard":null,"tryCatchPattern":"if _, err := store.RecordAppliedFix(ctx, sink, kind, note); err != nil { var busy bool; busy = strings.Contains(err.Error(), \"SQLITE_BUSY\"); if busy { time.Sleep(backoff); retry } else { return err } }","preventionTips":["Run store migrations on startup before any writes","Set a busy_timeout on the SQLite connection","Check DB file writability when running in containers"],"tags":["sqlite","database","persistence"],"backgroundTag":"database-write-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}