huskies: merge 895

This commit is contained in:
dave
2026-05-13 08:48:36 +00:00
parent 4a8ed4348b
commit 6bd11d41f9
7 changed files with 405 additions and 49 deletions
+254
View File
@@ -682,3 +682,257 @@ fn snippet_skips_leading_empty_lines() {
let result = first_non_empty_snippet(text, 120);
assert_eq!(result, "actual error here");
}
// -- AC1: blocked items appear in-place, not in a separate "Blocked" section --
#[test]
fn blocked_item_appears_in_in_progress_not_separate_section() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![make_item(
"42_story_blocked",
"Blocked Story",
Stage::Blocked {
reason: "retry limit exceeded".to_string(),
},
)];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
// Must NOT appear under a separate "Blocked" section.
assert!(
!output.contains("**Blocked**"),
"output must not have a separate Blocked section: {output}"
);
// Must appear under "In Progress".
let in_progress_pos = output
.find("**In Progress**")
.expect("In Progress section must exist");
let qa_pos = output.find("**QA**").expect("QA section must exist");
let story_pos = output
.find("42 [story]")
.expect("story must appear in output");
assert!(
story_pos > in_progress_pos && story_pos < qa_pos,
"blocked story should be in In Progress section: in_progress={in_progress_pos} story={story_pos} qa={qa_pos}\n{output}"
);
}
#[test]
fn blocked_item_shows_red_dot_in_in_progress_section() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![make_item(
"50_story_blocked_dot",
"Blocked With Dot",
Stage::Blocked {
reason: "too many failures".to_string(),
},
)];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
assert!(
output.contains("\u{1F534} "), // 🔴
"blocked story should show red circle emoji: {output}"
);
}
// -- AC2: stage counts include blocked items --
#[test]
fn in_progress_count_includes_blocked_items() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![
make_item("10_story_coding", "Coding Story", Stage::Coding),
make_item(
"11_story_blocked",
"Blocked Story",
Stage::Blocked {
reason: "failed".to_string(),
},
),
];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
// "In Progress" header should show count of 2 (one coding + one blocked).
assert!(
output.contains("**In Progress** (2)"),
"In Progress count should include blocked items: {output}"
);
}
// -- AC4: frozen items appear in-place, with ❄️ indicator --
#[test]
fn frozen_coding_item_appears_in_in_progress_section() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![make_item(
"60_story_frozen",
"Frozen Coding Story",
Stage::Frozen {
resume_to: Box::new(Stage::Coding),
},
)];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
let in_progress_pos = output
.find("**In Progress**")
.expect("In Progress section must exist");
let qa_pos = output.find("**QA**").expect("QA section must exist");
let story_pos = output
.find("60 [story]")
.expect("story must appear in output");
assert!(
story_pos > in_progress_pos && story_pos < qa_pos,
"frozen-coding story should appear in In Progress: in_progress={in_progress_pos} story={story_pos} qa={qa_pos}\n{output}"
);
}
#[test]
fn frozen_qa_item_appears_in_qa_section() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![make_item(
"70_story_frozen_qa",
"Frozen QA Story",
Stage::Frozen {
resume_to: Box::new(Stage::Qa),
},
)];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
let qa_pos = output.find("**QA**").expect("QA section must exist");
let merge_pos = output.find("**Merge**").expect("Merge section must exist");
let story_pos = output
.find("70 [story]")
.expect("story must appear in output");
assert!(
story_pos > qa_pos && story_pos < merge_pos,
"frozen-QA story should appear in QA section: qa={qa_pos} story={story_pos} merge={merge_pos}\n{output}"
);
}
#[test]
fn frozen_item_shows_snowflake_indicator() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![make_item(
"80_story_frozen_flake",
"Frozen Flake Story",
Stage::Frozen {
resume_to: Box::new(Stage::Coding),
},
)];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
assert!(
output.contains("\u{2744}\u{FE0F}"), // ❄️
"frozen story should show snowflake prefix: {output}"
);
}
#[test]
fn frozen_and_blocked_use_distinct_indicators() {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![
make_item(
"90_story_blocked_ind",
"Blocked Story",
Stage::Blocked {
reason: "failed".to_string(),
},
),
make_item(
"91_story_frozen_ind",
"Frozen Story",
Stage::Frozen {
resume_to: Box::new(Stage::Coding),
},
),
];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
assert!(
output.contains("\u{1F534} "), // 🔴 for blocked
"blocked story should show red dot: {output}"
);
assert!(
output.contains("\u{2744}\u{FE0F}"), // ❄️ for frozen
"frozen story should show snowflake: {output}"
);
}
// -- merge-failure items appear in Merge section --
#[test]
fn merge_failure_item_appears_in_merge_section_not_blocked() {
use crate::pipeline_state::BranchName;
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let items = vec![make_item(
"100_story_merge_fail",
"Merge Failure Story",
Stage::MergeFailure {
reason: "conflict in lib.rs".to_string(),
feature_branch: BranchName("feature/100".to_string()),
commits_ahead: std::num::NonZeroU32::new(1).unwrap(),
},
)];
let agents = AgentPool::new_test(3000);
let output = build_status_from_items(tmp.path(), &agents, &items);
// Must not be in a separate "Blocked" section.
assert!(
!output.contains("**Blocked**"),
"output must not have a separate Blocked section: {output}"
);
let merge_pos = output.find("**Merge**").expect("Merge section must exist");
let done_pos = output.find("**Done**").expect("Done section must exist");
let story_pos = output
.find("100 [story]")
.expect("story must appear in output");
assert!(
story_pos > merge_pos && story_pos < done_pos,
"merge-failure story should appear in Merge section: merge={merge_pos} story={story_pos} done={done_pos}\n{output}"
);
assert!(
output.contains("\u{26D4}"), // ⛔
"merge failure should show stop sign: {output}"
);
assert!(
output.contains("conflict in lib.rs"),
"merge failure reason should be shown: {output}"
);
}