{"record":{"id":"5d1d71cfebdc5c54","repo":"Hmbown/CodeWhale","slug":"error-session-manager","errorCode":null,"errorMessage":"{error}","messagePattern":"\\{error\\}","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/session_manager.rs","lineNumber":844,"sourceCode":"            ));\n        }\n        if self\n            .goal_id\n            .as_ref()\n            .is_some_and(|id| id.is_empty() || id.len() > 128)\n        {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid session goal revision\",\n            ));\n        }\n        codewhale_protocol::validate_goal_stall_state(\n            self.last_gap_fingerprint.as_deref(),\n            self.repeated_gap_count,\n            self.last_gap_pass,\n            self.continuation_count,\n        )\n        .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))\n    }\n\n    #[must_use]\n    pub fn to_runtime_snapshot(&self) -> GoalSnapshot {\n        GoalSnapshot {\n            goal_id: self.goal_id.clone(),\n            objective: Some(self.objective.clone()),\n            status: match self.status {\n                SessionGoalStatus::Active => \"active\",\n                SessionGoalStatus::Paused => \"paused\",\n                SessionGoalStatus::Complete => \"complete\",\n                SessionGoalStatus::Blocked => \"blocked\",\n            }\n            .to_string(),\n            token_budget: self.token_budget,\n            tokens_used: self.tokens_used,\n            time_used_seconds: self.time_used_seconds,\n            continuation_count: self.continuation_count,","sourceCodeStart":826,"sourceCodeEnd":862,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/session_manager.rs#L826-L862","documentation":"Session goal stall tracking (last_gap_fingerprint, repeated_gap_count, last_gap_pass, continuation_count) is validated by codewhale_protocol::validate_goal_stall_state. Any validation error returned there is wrapped verbatim into an InvalidData io::Error — so the inner protocol message ('{error}') is the actual diagnostic.","triggerScenarios":"Loading or validating a goal state whose stall-state fields violate protocol invariants — e.g. a gap fingerprint present without counts, mismatched pass/continuation counters, or inconsistent combinations of these fields.","commonSituations":"Hand-edited goal files with partially updated stall fields; merging session state from two machines; truncation or manual patching of counters during debugging.","solutions":["Read the wrapped message for the specific protocol rule broken and correct the stall-state fields accordingly.","Reset the stall fields (clear last_gap_fingerprint, zero the counters) so validation passes and tracking restarts.","Recreate the goal via the TUI instead of editing state files directly."],"exampleFix":"// before: fingerprint set but counters inconsistent\n{\"last_gap_fingerprint\": \"abc\", \"repeated_gap_count\": 0, \"continuation_count\": 7}\n// after: reset stall tracking\n{\"last_gap_fingerprint\": null, \"repeated_gap_count\": 0, \"continuation_count\": 0}","handlingStrategy":"validation","validationCode":"fn stall_state_plausible(fp: &Option<String>, counts: (u32,u32,u32)) -> bool {\n    fp.is_some() == (counts.0 > 0 || counts.1 > 0 || counts.2 > 0)\n}","typeGuard":null,"tryCatchPattern":"match load_goal(path) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        eprintln!(\"stall-state invalid: {e}\"); // message is the protocol's own diagnostic\n    }\n    other => other?,\n}","preventionTips":["Update all stall fields together, never partially.","Reset stall fields to defaults when unsure.","Don't merge or patch goal state files from multiple machines by hand."],"tags":["validation","protocol","goals"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}