huskies: merge 730_story_use_numeric_only_story_ids_across_mcp_worktrees_git_branches_and_log_paths

This commit is contained in:
dave
2026-04-27 20:17:03 +00:00
parent 63d5a500de
commit 1388658ae8
10 changed files with 223 additions and 64 deletions
+52 -5
View File
@@ -10,16 +10,34 @@ use crate::slog;
type ContentTransform = Option<Box<dyn Fn(&str) -> String>>;
/// Determine the item type ("story", "bug", "spike", or "refactor") from the item ID.
///
/// For slug-format IDs (e.g. `"4_bug_login_crash"`), the type is embedded in the ID.
/// For numeric-only IDs (e.g. `"4"`), the type is read from the `type:` field in
/// the content-store front matter. Falls back to `"story"` if not found.
pub(crate) fn item_type_from_id(item_id: &str) -> &'static str {
// New format: {digits}_{type}_{slug}
let after_num = item_id.trim_start_matches(|c: char| c.is_ascii_digit());
if after_num.starts_with("_bug_") {
"bug"
return "bug";
} else if after_num.starts_with("_spike_") {
"spike"
} else {
"story"
return "spike";
} else if after_num.starts_with("_refactor_") {
return "refactor";
}
// Numeric-only ID: check content store front matter for explicit type.
if after_num.is_empty()
&& let Some(content) = crate::db::read_content(item_id)
&& let Ok(meta) = crate::io::story_metadata::parse_front_matter(&content)
&& let Some(t) = meta.item_type.as_deref()
{
return match t {
"bug" => "bug",
"spike" => "spike",
"refactor" => "refactor",
_ => "story",
};
}
"story"
}
/// Move a work item to a new pipeline stage via the database.
@@ -332,6 +350,35 @@ mod tests {
assert_eq!(item_type_from_id("1_spike_research"), "spike");
assert_eq!(item_type_from_id("50_story_my_story"), "story");
assert_eq!(item_type_from_id("1_story_simple"), "story");
assert_eq!(item_type_from_id("1_refactor_cleanup"), "refactor");
}
#[test]
fn item_type_from_id_falls_back_to_content_store_for_numeric_ids() {
crate::db::ensure_content_store();
// Write a bug item with numeric-only ID into the content store.
let bug_content = "---\ntype: bug\nname: \"Test Bug\"\n---\n\n# Bug 9999: Test Bug\n";
crate::db::write_content("9999", bug_content);
let spike_content =
"---\ntype: spike\nname: \"Test Spike\"\n---\n\n# Spike 9998: Test Spike\n";
crate::db::write_content("9998", spike_content);
let refactor_content =
"---\ntype: refactor\nname: \"Test Refactor\"\n---\n\n# Refactor 9997: Test Refactor\n";
crate::db::write_content("9997", refactor_content);
let story_content =
"---\ntype: story\nname: \"Test Story\"\n---\n\n# Story 9996: Test Story\n";
crate::db::write_content("9996", story_content);
assert_eq!(item_type_from_id("9999"), "bug");
assert_eq!(item_type_from_id("9998"), "spike");
assert_eq!(item_type_from_id("9997"), "refactor");
assert_eq!(item_type_from_id("9996"), "story");
// No content store entry → defaults to "story".
assert_eq!(item_type_from_id("99999"), "story");
}
// ── feature_branch_has_unmerged_changes tests ────────────────────────────