story-kit: start 72_bug_story_creation_does_not_quote_yaml_special_characters_in_name

This commit is contained in:
Dave
2026-02-23 14:01:15 +00:00
parent 5d40d08db9
commit 0d7409ac89
2 changed files with 42 additions and 3 deletions

View File

@@ -0,0 +1,23 @@
# Bug 72: Story creation does not quote YAML special characters in name
## Description
The create_story MCP tool writes the name value into YAML front matter without quoting. If the name contains YAML-special characters like colons, the resulting front matter is invalid YAML and fails to parse.
## How to Reproduce
1. Call create_story with a name containing a colon, e.g. "Server-owned agent completion: remove report_completion dependency"
2. Open the generated .md file
3. Observe the front matter parser rejects it
## Actual Result
Invalid front matter: mapping values are not allowed in this context
## Expected Result
The name value should be quoted in the front matter so special characters are safe, e.g. name: "My story: with colons"
## Acceptance Criteria
- [ ] Bug is fixed and verified

View File

@@ -164,7 +164,7 @@ pub fn create_story_file(
let mut content = String::new(); let mut content = String::new();
content.push_str("---\n"); content.push_str("---\n");
content.push_str(&format!("name: {name}\n")); content.push_str(&format!("name: \"{}\"\n", name.replace('"', "\\\"")));
content.push_str("test_plan: pending\n"); content.push_str("test_plan: pending\n");
content.push_str("---\n\n"); content.push_str("---\n\n");
content.push_str(&format!("# Story {story_number}: {name}\n\n")); content.push_str(&format!("# Story {story_number}: {name}\n\n"));
@@ -917,7 +917,7 @@ mod tests {
let mut content = String::new(); let mut content = String::new();
content.push_str("---\n"); content.push_str("---\n");
content.push_str("name: My New Feature\n"); content.push_str("name: \"My New Feature\"\n");
content.push_str("test_plan: pending\n"); content.push_str("test_plan: pending\n");
content.push_str("---\n\n"); content.push_str("---\n\n");
content.push_str(&format!("# Story {number}: My New Feature\n\n")); content.push_str(&format!("# Story {number}: My New Feature\n\n"));
@@ -932,13 +932,29 @@ mod tests {
fs::write(&filepath, &content).unwrap(); fs::write(&filepath, &content).unwrap();
let written = fs::read_to_string(&filepath).unwrap(); let written = fs::read_to_string(&filepath).unwrap();
assert!(written.starts_with("---\nname: My New Feature\ntest_plan: pending\n---")); assert!(written.starts_with("---\nname: \"My New Feature\"\ntest_plan: pending\n---"));
assert!(written.contains("# Story 37: My New Feature")); assert!(written.contains("# Story 37: My New Feature"));
assert!(written.contains("- [ ] It works")); assert!(written.contains("- [ ] It works"));
assert!(written.contains("- [ ] It is tested")); assert!(written.contains("- [ ] It is tested"));
assert!(written.contains("## Out of Scope")); assert!(written.contains("## Out of Scope"));
} }
#[test]
fn create_story_with_colon_in_name_produces_valid_yaml() {
let tmp = tempfile::tempdir().unwrap();
let name = "Server-owned agent completion: remove report_completion dependency";
let result = create_story_file(tmp.path(), name, None, None, false);
assert!(result.is_ok(), "create_story_file failed: {result:?}");
let upcoming = tmp.path().join(".story_kit/work/1_upcoming");
let story_id = result.unwrap();
let filename = format!("{story_id}.md");
let contents = fs::read_to_string(upcoming.join(&filename)).unwrap();
let meta = parse_front_matter(&contents).expect("front matter should be valid YAML");
assert_eq!(meta.name.as_deref(), Some(name));
}
#[test] #[test]
fn create_story_rejects_duplicate() { fn create_story_rejects_duplicate() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();