huskies: merge 593_bug_web_ui_work_item_detail_panel_returns_404_for_crdt_only_stories

This commit is contained in:
dave
2026-04-17 13:53:36 +00:00
parent 43ca0cbc59
commit b77e139347
+72
View File
@@ -402,6 +402,34 @@ impl AgentsApi {
}
}
// Filesystem miss — fall back to CRDT-only path (story exists in the CRDT
// but has no corresponding .md file on disk).
if let Some(content) = crate::db::read_content(&story_id.0) {
let item = crate::pipeline_state::read_typed(&story_id.0)
.map_err(|e| bad_request(format!("Pipeline read error: {e}")))?;
let stage = item
.as_ref()
.map(|i| match &i.stage {
crate::pipeline_state::Stage::Backlog => "backlog",
crate::pipeline_state::Stage::Coding => "current",
crate::pipeline_state::Stage::Qa => "qa",
crate::pipeline_state::Stage::Merge { .. } => "merge",
crate::pipeline_state::Stage::Done { .. } => "done",
crate::pipeline_state::Stage::Archived { .. } => "archived",
})
.unwrap_or("unknown")
.to_string();
let metadata = crate::io::story_metadata::parse_front_matter(&content).ok();
let name = metadata.as_ref().and_then(|m| m.name.clone());
let agent = metadata.and_then(|m| m.agent);
return Ok(Json(WorkItemContentResponse {
content,
stage,
name,
agent,
}));
}
Err(not_found(format!("Work item not found: {}", story_id.0)))
}
@@ -953,6 +981,50 @@ allowed_tools = ["Read", "Bash"]
assert!(result.is_err());
}
#[tokio::test]
async fn get_work_item_content_falls_back_to_crdt_when_no_file() {
let tmp = TempDir::new().unwrap();
let root = tmp.path().to_path_buf();
// Seed content + CRDT with no .md file on disk.
crate::db::write_item_with_content(
"44_story_crdt_only",
"1_backlog",
"---\nname: \"CRDT Only\"\n---\n\nCRDT content.",
);
let ctx = AppContext::new_test(root);
let api = AgentsApi { ctx: Arc::new(ctx) };
let result = api
.get_work_item_content(Path("44_story_crdt_only".to_string()))
.await
.unwrap()
.0;
assert!(result.content.contains("CRDT content."));
assert_eq!(result.stage, "backlog");
assert_eq!(result.name, Some("CRDT Only".to_string()));
}
#[tokio::test]
async fn get_work_item_content_crdt_fallback_with_current_stage() {
let tmp = TempDir::new().unwrap();
let root = tmp.path().to_path_buf();
// Seed a CRDT-only story in the coding/current stage.
crate::db::write_item_with_content(
"45_story_crdt_current",
"2_current",
"---\nname: \"Current CRDT\"\n---\n\nIn progress.",
);
let ctx = AppContext::new_test(root);
let api = AgentsApi { ctx: Arc::new(ctx) };
let result = api
.get_work_item_content(Path("45_story_crdt_current".to_string()))
.await
.unwrap()
.0;
assert!(result.content.contains("In progress."));
assert_eq!(result.stage, "current");
assert_eq!(result.name, Some("Current CRDT".to_string()));
}
#[tokio::test]
async fn get_work_item_content_returns_error_when_no_project_root() {
let tmp = TempDir::new().unwrap();