huskies: merge 946
This commit is contained in:
@@ -41,12 +41,15 @@ pub fn set_depends_on(story_id: &str, deps: &[u32]) -> bool {
|
||||
|
||||
/// Set the `item_type` CRDT register for a pipeline item (sub-story 933).
|
||||
///
|
||||
/// `Some(t)` writes the type string (e.g. `"story"`, `"epic"`, `"bug"`).
|
||||
/// `Some(t)` writes the canonical type string (e.g. `"story"`, `"epic"`, `"bug"`).
|
||||
/// `None` clears the register to an empty string, which means "use the
|
||||
/// id-prefix heuristic" (see `item_type_from_id`).
|
||||
///
|
||||
/// Returns `true` if the item was found and the op was applied, `false` otherwise.
|
||||
pub fn set_item_type(story_id: &str, item_type: Option<&str>) -> bool {
|
||||
pub fn set_item_type(
|
||||
story_id: &str,
|
||||
item_type: Option<crate::io::story_metadata::ItemType>,
|
||||
) -> bool {
|
||||
let Some(state_mutex) = get_crdt() else {
|
||||
return false;
|
||||
};
|
||||
@@ -56,18 +59,21 @@ pub fn set_item_type(story_id: &str, item_type: Option<&str>) -> bool {
|
||||
let Some(&idx) = state.index.get(story_id) else {
|
||||
return false;
|
||||
};
|
||||
let value = item_type.unwrap_or("").to_string();
|
||||
let value = item_type
|
||||
.map(|t| t.as_str().to_string())
|
||||
.unwrap_or_default();
|
||||
apply_and_persist(&mut state, |s| s.crdt.doc.items[idx].item_type.set(value));
|
||||
true
|
||||
}
|
||||
|
||||
/// Set the `epic` CRDT register for a pipeline item (sub-story 933).
|
||||
///
|
||||
/// `Some(epic_id)` links the item to its parent epic.
|
||||
/// `Some(id)` links the item to its parent epic (stored as the numeric string,
|
||||
/// e.g. `"9990"` for `EpicId(9990)`).
|
||||
/// `None` clears the register to an empty string (no epic membership).
|
||||
///
|
||||
/// Returns `true` if the item was found and the op was applied, `false` otherwise.
|
||||
pub fn set_epic(story_id: &str, epic_id: Option<&str>) -> bool {
|
||||
pub fn set_epic(story_id: &str, epic_id: Option<crate::crdt_state::types::EpicId>) -> bool {
|
||||
let Some(state_mutex) = get_crdt() else {
|
||||
return false;
|
||||
};
|
||||
@@ -77,7 +83,7 @@ pub fn set_epic(story_id: &str, epic_id: Option<&str>) -> bool {
|
||||
let Some(&idx) = state.index.get(story_id) else {
|
||||
return false;
|
||||
};
|
||||
let value = epic_id.unwrap_or("").to_string();
|
||||
let value = epic_id.map(|e| e.to_string()).unwrap_or_default();
|
||||
apply_and_persist(&mut state, |s| s.crdt.doc.items[idx].epic.set(value));
|
||||
true
|
||||
}
|
||||
|
||||
@@ -154,7 +154,18 @@ fn migrate_story_ids_to_numeric_skips_conflict() {
|
||||
write_item_str(
|
||||
"44_story_foo",
|
||||
"1_backlog",
|
||||
None,
|
||||
Some("Foo slug"),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
write_item_str(
|
||||
"44",
|
||||
"2_current",
|
||||
Some("Foo numeric"),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -162,7 +173,6 @@ fn migrate_story_ids_to_numeric_skips_conflict() {
|
||||
None,
|
||||
None,
|
||||
);
|
||||
write_item_str("44", "2_current", None, None, None, None, None, None, None);
|
||||
|
||||
let result = migrate_story_ids_to_numeric();
|
||||
// The slug entry must NOT be migrated because "44" is already occupied.
|
||||
@@ -202,7 +212,7 @@ fn migrate_story_ids_to_numeric_preserves_stage_and_name() {
|
||||
|
||||
let item = read_item("45").expect("item must be accessible by numeric ID");
|
||||
assert!(matches!(item.stage, crate::pipeline_state::Stage::Coding));
|
||||
assert_eq!(item.name.as_deref(), Some("Crash Bug"));
|
||||
assert_eq!(item.name, "Crash Bug");
|
||||
assert_eq!(item.agent.as_deref(), Some("coder-1"));
|
||||
}
|
||||
|
||||
@@ -223,20 +233,18 @@ fn migrate_names_from_slugs_fills_empty_names() {
|
||||
None,
|
||||
);
|
||||
|
||||
// Before migration the name should be empty.
|
||||
let before = read_item("42_story_my_feature").unwrap();
|
||||
// Before migration: nameless item is filtered by read_item (AC 5).
|
||||
assert!(
|
||||
before.name.as_deref().unwrap_or("").is_empty(),
|
||||
"name should be empty before migration"
|
||||
read_item("42_story_my_feature").is_none(),
|
||||
"nameless item must not be returned by read_item before migration"
|
||||
);
|
||||
|
||||
migrate_names_from_slugs();
|
||||
|
||||
// After migration the name should be derived from the slug.
|
||||
// After migration the item has a name and is visible to read_item.
|
||||
let after = read_item("42_story_my_feature").unwrap();
|
||||
assert_eq!(
|
||||
after.name.as_deref(),
|
||||
Some("My feature"),
|
||||
after.name, "My feature",
|
||||
"name should be derived from slug after migration"
|
||||
);
|
||||
}
|
||||
@@ -261,8 +269,7 @@ fn migrate_names_from_slugs_leaves_existing_names_unchanged() {
|
||||
|
||||
let after = read_item("43_story_named_item").unwrap();
|
||||
assert_eq!(
|
||||
after.name.as_deref(),
|
||||
Some("Already Named"),
|
||||
after.name, "Already Named",
|
||||
"pre-existing name must not be overwritten"
|
||||
);
|
||||
}
|
||||
@@ -300,7 +307,7 @@ fn set_depends_on_round_trip_and_clear() {
|
||||
let view = read_item("872_test_target").unwrap();
|
||||
assert_eq!(
|
||||
view.depends_on,
|
||||
Some(vec![837]),
|
||||
vec![837u32],
|
||||
"CRDT register should hold [837]"
|
||||
);
|
||||
|
||||
@@ -308,8 +315,8 @@ fn set_depends_on_round_trip_and_clear() {
|
||||
let ok = set_depends_on("872_test_target", &[]);
|
||||
assert!(ok, "set_depends_on([]) should return true");
|
||||
let view = read_item("872_test_target").unwrap();
|
||||
assert_eq!(
|
||||
view.depends_on, None,
|
||||
assert!(
|
||||
view.depends_on.is_empty(),
|
||||
"clearing should leave register unset"
|
||||
);
|
||||
|
||||
@@ -412,7 +419,7 @@ fn set_qa_mode_round_trip_server_then_human() {
|
||||
write_item_str(
|
||||
"869_story_qa_roundtrip",
|
||||
"1_backlog",
|
||||
None,
|
||||
Some("Qa Roundtrip"),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -426,9 +433,9 @@ fn set_qa_mode_round_trip_server_then_human() {
|
||||
assert!(ok, "set_qa_mode should return true for known item");
|
||||
let view = read_item("869_story_qa_roundtrip").unwrap();
|
||||
assert_eq!(
|
||||
view.qa_mode.as_deref(),
|
||||
Some("server"),
|
||||
"CRDT register should hold \"server\""
|
||||
view.qa_mode,
|
||||
Some(QaMode::Server),
|
||||
"CRDT register should hold Server"
|
||||
);
|
||||
|
||||
// Set qa=human via typed path and assert CRDT register is updated.
|
||||
@@ -436,9 +443,9 @@ fn set_qa_mode_round_trip_server_then_human() {
|
||||
assert!(ok, "set_qa_mode should return true for known item");
|
||||
let view = read_item("869_story_qa_roundtrip").unwrap();
|
||||
assert_eq!(
|
||||
view.qa_mode.as_deref(),
|
||||
Some("human"),
|
||||
"CRDT register should hold \"human\""
|
||||
view.qa_mode,
|
||||
Some(QaMode::Human),
|
||||
"CRDT register should hold Human"
|
||||
);
|
||||
|
||||
// Clear via None — register goes back to unset.
|
||||
@@ -467,7 +474,7 @@ fn bump_retry_count_increments_by_one() {
|
||||
write_item_str(
|
||||
"9001_story_bump_test",
|
||||
"2_current",
|
||||
None,
|
||||
Some("Bump Test"),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -483,11 +490,7 @@ fn bump_retry_count_increments_by_one() {
|
||||
assert_eq!(v2, 2, "second bump should return 2");
|
||||
|
||||
let item = read_item("9001_story_bump_test").expect("item must exist");
|
||||
assert_eq!(
|
||||
item.retry_count,
|
||||
Some(2),
|
||||
"CRDT must reflect final bump value"
|
||||
);
|
||||
assert_eq!(item.retry_count, 2u32, "CRDT must reflect final bump value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -496,7 +499,7 @@ fn set_retry_count_resets_to_zero() {
|
||||
write_item_str(
|
||||
"9002_story_set_test",
|
||||
"2_current",
|
||||
None,
|
||||
Some("Set Test"),
|
||||
None,
|
||||
Some(5),
|
||||
None,
|
||||
@@ -508,11 +511,7 @@ fn set_retry_count_resets_to_zero() {
|
||||
set_retry_count("9002_story_set_test", 0);
|
||||
|
||||
let item = read_item("9002_story_set_test").expect("item must exist");
|
||||
assert_eq!(
|
||||
item.retry_count,
|
||||
Some(0),
|
||||
"set_retry_count(0) must reset to 0"
|
||||
);
|
||||
assert_eq!(item.retry_count, 0u32, "set_retry_count(0) must reset to 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user