story-kit: merge 265_story_spikes_skip_merge_and_stop_for_human_review

This commit is contained in:
Dave
2026-03-17 16:33:55 +00:00
parent 7b324ea96e
commit 86694a4383
3 changed files with 187 additions and 17 deletions

View File

@@ -8,6 +8,7 @@ pub struct StoryMetadata {
pub coverage_baseline: Option<String>,
pub merge_failure: Option<String>,
pub agent: Option<String>,
pub review_hold: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -31,6 +32,7 @@ struct FrontMatter {
coverage_baseline: Option<String>,
merge_failure: Option<String>,
agent: Option<String>,
review_hold: Option<bool>,
}
pub fn parse_front_matter(contents: &str) -> Result<StoryMetadata, StoryMetaError> {
@@ -64,6 +66,7 @@ fn build_metadata(front: FrontMatter) -> StoryMetadata {
coverage_baseline: front.coverage_baseline,
merge_failure: front.merge_failure,
agent: front.agent,
review_hold: front.review_hold,
}
}
@@ -98,6 +101,17 @@ pub fn write_merge_failure(path: &Path, reason: &str) -> Result<(), String> {
Ok(())
}
/// Write `review_hold: true` to the YAML front matter of a story file.
///
/// Used to mark spikes that have passed QA and are waiting for human review.
pub fn write_review_hold(path: &Path) -> Result<(), String> {
let contents =
fs::read_to_string(path).map_err(|e| format!("Failed to read story file: {e}"))?;
let updated = set_front_matter_field(&contents, "review_hold", "true");
fs::write(path, &updated).map_err(|e| format!("Failed to write story file: {e}"))?;
Ok(())
}
/// Remove a key from the YAML front matter of a story file on disk.
///
/// If front matter is present and contains the key, the line is removed.
@@ -328,4 +342,29 @@ workflow: tdd
let input = " - [ ] Indented item\n";
assert_eq!(parse_unchecked_todos(input), vec!["Indented item"]);
}
#[test]
fn parses_review_hold_from_front_matter() {
let input = "---\nname: Spike\nreview_hold: true\n---\n# Spike\n";
let meta = parse_front_matter(input).expect("front matter");
assert_eq!(meta.review_hold, Some(true));
}
#[test]
fn review_hold_defaults_to_none() {
let input = "---\nname: Story\n---\n# Story\n";
let meta = parse_front_matter(input).expect("front matter");
assert_eq!(meta.review_hold, None);
}
#[test]
fn write_review_hold_sets_field() {
let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("spike.md");
std::fs::write(&path, "---\nname: My Spike\n---\n# Spike\n").unwrap();
write_review_hold(&path).unwrap();
let contents = std::fs::read_to_string(&path).unwrap();
assert!(contents.contains("review_hold: true"));
assert!(contents.contains("name: My Spike"));
}
}