huskies: merge 1100 bug Multiple LLM agents can run concurrently on the same story (coder + mergemaster + others) — enforce one-agent-per-story invariant

This commit is contained in:
dave
2026-05-15 20:24:31 +00:00
parent 9f4f493486
commit 4216ced493
7 changed files with 429 additions and 13 deletions
+36
View File
@@ -271,6 +271,42 @@ impl AgentPool {
'{conflicting_name}' is already active at the same pipeline stage"
));
}
// Cross-stage LLM agent guard: reject if any Coder/Qa/Mergemaster agent
// is already Running or Pending on this story at a *different* pipeline stage.
// These are stale agents left over from a previous stage transition that has
// since advanced. The periodic reconciler (reconcile_canonical_agents) stops
// them; here we surface the conflict so the caller waits for reconciliation.
if matches!(
resolved_stage,
PipelineStage::Coder | PipelineStage::Qa | PipelineStage::Mergemaster
) && let Some(stale_name) = agents.iter().find_map(|(k, a)| {
let k_story = k.rsplit_once(':').map(|(s, _)| s).unwrap_or(k);
if k_story != story_id || a.agent_name == resolved_name {
return None;
}
if !matches!(a.status, AgentStatus::Running | AgentStatus::Pending) {
return None;
}
let a_stage = config
.find_agent(&a.agent_name)
.map(agent_config_stage)
.unwrap_or_else(|| pipeline_stage(&a.agent_name));
if matches!(
a_stage,
PipelineStage::Coder | PipelineStage::Qa | PipelineStage::Mergemaster
) && a_stage != resolved_stage
{
Some(a.agent_name.clone())
} else {
None
}
}) {
return Err(format!(
"story '{story_id}' already has an active LLM agent '{stale_name}'; \
refusing to spawn '{resolved_name}'"
));
}
// Enforce single-instance concurrency for explicitly-named agents:
// if this agent is already running on any other story, reject.
// Auto-selected agents are already guaranteed idle by