story-kit: merge 311_story_server_enforced_retry_limits_for_failed_merge_and_empty_diff_stories

This commit is contained in:
Dave
2026-03-19 16:34:11 +00:00
parent 662e00f94a
commit 3b887e3085
9 changed files with 346 additions and 65 deletions

View File

@@ -49,6 +49,10 @@ pub struct StoryMetadata {
pub agent: Option<String>,
pub review_hold: Option<bool>,
pub qa: Option<QaMode>,
/// Number of times this story has been retried at its current pipeline stage.
pub retry_count: Option<u32>,
/// When `true`, auto-assign will skip this story (retry limit exceeded).
pub blocked: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -77,6 +81,10 @@ struct FrontMatter {
qa: Option<String>,
/// Legacy boolean field — mapped to `qa: human` (true) or ignored (false/absent).
manual_qa: Option<bool>,
/// Number of times this story has been retried at its current pipeline stage.
retry_count: Option<u32>,
/// When `true`, auto-assign will skip this story (retry limit exceeded).
blocked: Option<bool>,
}
pub fn parse_front_matter(contents: &str) -> Result<StoryMetadata, StoryMetaError> {
@@ -119,6 +127,8 @@ fn build_metadata(front: FrontMatter) -> StoryMetadata {
agent: front.agent,
review_hold: front.review_hold,
qa,
retry_count: front.retry_count,
blocked: front.blocked,
}
}
@@ -245,6 +255,37 @@ pub fn set_front_matter_field(contents: &str, key: &str, value: &str) -> String
result
}
/// Increment the `retry_count` field in the story file's front matter.
///
/// Reads the current value (defaulting to 0), increments by 1, and writes back.
/// Returns the new retry count.
pub fn increment_retry_count(path: &Path) -> Result<u32, String> {
let contents =
fs::read_to_string(path).map_err(|e| format!("Failed to read story file: {e}"))?;
let current = parse_front_matter(&contents)
.ok()
.and_then(|m| m.retry_count)
.unwrap_or(0);
let new_count = current + 1;
let updated = set_front_matter_field(&contents, "retry_count", &new_count.to_string());
fs::write(path, &updated).map_err(|e| format!("Failed to write story file: {e}"))?;
Ok(new_count)
}
/// Write `blocked: true` to the YAML front matter of a story file.
///
/// Used to mark stories that have exceeded the retry limit and should not
/// be auto-assigned again.
pub fn write_blocked(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, "blocked", "true");
fs::write(path, &updated).map_err(|e| format!("Failed to write story file: {e}"))?;
Ok(())
}
/// Append rejection notes to a story file body.
///
/// Adds a `## QA Rejection Notes` section at the end of the file so the coder