huskies: merge 487_story_display_story_dependencies_in_web_ui_and_chat_commands

This commit is contained in:
dave
2026-04-07 11:46:25 +00:00
parent 05eb13eab3
commit 4e082009c2
8 changed files with 140 additions and 4 deletions
+33 -4
View File
@@ -50,6 +50,9 @@ pub struct UpcomingStory {
/// True when the story has exceeded its retry limit and will not be auto-assigned.
#[serde(skip_serializing_if = "Option::is_none")]
pub blocked: Option<bool>,
/// Story numbers this story depends on.
#[serde(skip_serializing_if = "Option::is_none")]
pub depends_on: Option<Vec<u32>>,
}
pub struct StoryValidationResult {
@@ -143,12 +146,12 @@ fn load_stage_items(
.to_string();
let contents = fs::read_to_string(&path)
.map_err(|e| format!("Failed to read story file {}: {e}", path.display()))?;
let (name, error, merge_failure, review_hold, qa, retry_count, blocked) = match parse_front_matter(&contents) {
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked),
Err(e) => (None, Some(e.to_string()), None, None, None, None, None),
let (name, error, merge_failure, review_hold, qa, retry_count, blocked, depends_on) = match parse_front_matter(&contents) {
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked, meta.depends_on),
Err(e) => (None, Some(e.to_string()), None, None, None, None, None, None),
};
let agent = agent_map.get(&story_id).cloned();
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked });
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked, depends_on });
}
stories.sort_by(|a, b| a.story_id.cmp(&b.story_id));
@@ -526,6 +529,32 @@ mod tests {
assert_eq!(item.agent.as_ref().unwrap().status, "pending");
}
#[test]
fn pipeline_state_includes_depends_on() {
let tmp = tempfile::tempdir().unwrap();
let backlog = tmp.path().join(".huskies/work/1_backlog");
fs::create_dir_all(&backlog).unwrap();
fs::write(
backlog.join("20_story_dependent.md"),
"---\nname: Dependent Story\ndepends_on: [10, 11]\n---\n",
)
.unwrap();
fs::write(
backlog.join("21_story_independent.md"),
"---\nname: Independent Story\n---\n",
)
.unwrap();
let ctx = crate::http::context::AppContext::new_test(tmp.path().to_path_buf());
let state = load_pipeline_state(&ctx).unwrap();
let dependent = state.backlog.iter().find(|s| s.story_id == "20_story_dependent").unwrap();
assert_eq!(dependent.depends_on, Some(vec![10, 11]));
let independent = state.backlog.iter().find(|s| s.story_id == "21_story_independent").unwrap();
assert_eq!(independent.depends_on, None);
}
#[test]
fn load_upcoming_parses_metadata() {
let tmp = tempfile::tempdir().unwrap();