story-kit: merge 311_story_server_enforced_retry_limits_for_failed_merge_and_empty_diff_stories
This commit is contained in:
@@ -1156,7 +1156,7 @@ fn tool_get_pipeline_status(ctx: &AppContext) -> Result<String, String> {
|
||||
items
|
||||
.iter()
|
||||
.map(|s| {
|
||||
json!({
|
||||
let mut item = json!({
|
||||
"story_id": s.story_id,
|
||||
"name": s.name,
|
||||
"stage": stage,
|
||||
@@ -1165,7 +1165,19 @@ fn tool_get_pipeline_status(ctx: &AppContext) -> Result<String, String> {
|
||||
"model": a.model,
|
||||
"status": a.status,
|
||||
})),
|
||||
})
|
||||
});
|
||||
// Include blocked/retry_count when present so callers can
|
||||
// identify stories stuck in the pipeline.
|
||||
if let Some(true) = s.blocked {
|
||||
item["blocked"] = json!(true);
|
||||
}
|
||||
if let Some(rc) = s.retry_count {
|
||||
item["retry_count"] = json!(rc);
|
||||
}
|
||||
if let Some(ref mf) = s.merge_failure {
|
||||
item["merge_failure"] = json!(mf);
|
||||
}
|
||||
item
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@ pub struct UpcomingStory {
|
||||
/// QA mode for this item: "human", "server", or "agent".
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub qa: Option<String>,
|
||||
/// Number of retries at the current pipeline stage.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub retry_count: Option<u32>,
|
||||
/// True when the story has exceeded its retry limit and will not be auto-assigned.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub blocked: Option<bool>,
|
||||
}
|
||||
|
||||
pub struct StoryValidationResult {
|
||||
@@ -123,12 +129,12 @@ fn load_stage_items(
|
||||
.to_string();
|
||||
let contents = fs::read_to_string(&path)
|
||||
.map_err(|e| format!("Failed to read story file {}: {e}", path.display()))?;
|
||||
let (name, error, merge_failure, review_hold, qa) = match parse_front_matter(&contents) {
|
||||
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string())),
|
||||
Err(e) => (None, Some(e.to_string()), None, None, None),
|
||||
let (name, error, merge_failure, review_hold, qa, retry_count, blocked) = match parse_front_matter(&contents) {
|
||||
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked),
|
||||
Err(e) => (None, Some(e.to_string()), None, None, None, None, None),
|
||||
};
|
||||
let agent = agent_map.get(&story_id).cloned();
|
||||
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa });
|
||||
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked });
|
||||
}
|
||||
|
||||
stories.sort_by(|a, b| a.story_id.cmp(&b.story_id));
|
||||
|
||||
@@ -739,6 +739,8 @@ mod tests {
|
||||
agent: None,
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
};
|
||||
let resp = WsResponse::PipelineState {
|
||||
backlog: vec![story],
|
||||
@@ -878,6 +880,8 @@ mod tests {
|
||||
agent: None,
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
}],
|
||||
current: vec![UpcomingStory {
|
||||
story_id: "2_story_b".to_string(),
|
||||
@@ -887,6 +891,8 @@ mod tests {
|
||||
agent: None,
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
}],
|
||||
qa: vec![],
|
||||
merge: vec![],
|
||||
@@ -898,6 +904,8 @@ mod tests {
|
||||
agent: None,
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
}],
|
||||
};
|
||||
let resp: WsResponse = state.into();
|
||||
@@ -1056,6 +1064,8 @@ mod tests {
|
||||
}),
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
}],
|
||||
qa: vec![],
|
||||
merge: vec![],
|
||||
|
||||
Reference in New Issue
Block a user