fix: merge_agent_work blocks until complete instead of requiring polling
The mergemaster agent was burning all 30 turns polling get_merge_status every 2 seconds while the merge pipeline takes ~2 minutes. It would exhaust turns, exit, restart, and repeat — never seeing the result. merge_agent_work now blocks with a 10-second internal poll loop and returns the final result directly. The agent calls it once and gets the answer. No more polling turns wasted. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -139,15 +139,27 @@ impl AgentPool {
|
||||
);
|
||||
let empty_diff_reason = "Feature branch has no code changes — the coder agent \
|
||||
did not produce any commits.";
|
||||
// Write merge_failure and blocked to content store + CRDT.
|
||||
let contents = crate::db::read_content(story_id)
|
||||
.unwrap_or_else(|| "---\nname: unknown\n---\n".to_string());
|
||||
let updated = crate::io::story_metadata::write_merge_failure_in_content(
|
||||
&contents,
|
||||
empty_diff_reason,
|
||||
);
|
||||
let blocked = crate::io::story_metadata::write_blocked_in_content(&updated);
|
||||
crate::db::write_item_with_content(story_id, stage_dir, &blocked);
|
||||
// Write merge_failure and blocked to content store.
|
||||
if let Some(contents) = crate::db::read_content(story_id) {
|
||||
let updated = crate::io::story_metadata::write_merge_failure_in_content(
|
||||
&contents,
|
||||
empty_diff_reason,
|
||||
);
|
||||
let blocked = crate::io::story_metadata::write_blocked_in_content(&updated);
|
||||
crate::db::write_content(story_id, &blocked);
|
||||
crate::db::write_item_with_content(story_id, stage_dir, &blocked);
|
||||
} else {
|
||||
// Fallback: filesystem.
|
||||
let story_path = project_root
|
||||
.join(".huskies/work")
|
||||
.join(stage_dir)
|
||||
.join(format!("{story_id}.md"));
|
||||
let _ = crate::io::story_metadata::write_merge_failure(
|
||||
&story_path,
|
||||
empty_diff_reason,
|
||||
);
|
||||
let _ = crate::io::story_metadata::write_blocked(&story_path);
|
||||
}
|
||||
let _ = self.watcher_tx.send(crate::io::watcher::WatcherEvent::StoryBlocked {
|
||||
story_id: story_id.to_string(),
|
||||
reason: empty_diff_reason.to_string(),
|
||||
|
||||
@@ -209,10 +209,15 @@ impl AgentPool {
|
||||
message: format!("Failed to advance to QA: {e}"),
|
||||
});
|
||||
} else {
|
||||
// Set review_hold in the content store + CRDT.
|
||||
if let Some(contents) = crate::db::read_content(story_id) {
|
||||
let updated = crate::io::story_metadata::write_review_hold_in_content(&contents);
|
||||
crate::db::write_item_with_content(story_id, "3_qa", &updated);
|
||||
let story_path = project_root
|
||||
.join(".huskies/work/3_qa")
|
||||
.join(format!("{story_id}.md"));
|
||||
if let Err(e) =
|
||||
crate::io::story_metadata::write_review_hold(&story_path)
|
||||
{
|
||||
eprintln!(
|
||||
"[startup:reconcile] Failed to set review_hold on '{story_id}': {e}"
|
||||
);
|
||||
}
|
||||
eprintln!("[startup:reconcile] Moved '{story_id}' → 3_qa/ (qa: human — holding for review).");
|
||||
let _ = progress_tx.send(ReconciliationEvent {
|
||||
@@ -262,25 +267,29 @@ impl AgentPool {
|
||||
if item_type == "spike" {
|
||||
true
|
||||
} else {
|
||||
let story_path = project_root
|
||||
.join(".huskies/work/3_qa")
|
||||
.join(format!("{story_id}.md"));
|
||||
let default_qa = crate::config::ProjectConfig::load(project_root)
|
||||
.unwrap_or_default()
|
||||
.default_qa_mode();
|
||||
if let Some(contents) = crate::db::read_content(story_id) {
|
||||
matches!(
|
||||
crate::io::story_metadata::resolve_qa_mode_from_content(&contents, default_qa),
|
||||
crate::io::story_metadata::QaMode::Human
|
||||
)
|
||||
} else {
|
||||
matches!(default_qa, crate::io::story_metadata::QaMode::Human)
|
||||
}
|
||||
matches!(
|
||||
crate::io::story_metadata::resolve_qa_mode(&story_path, default_qa),
|
||||
crate::io::story_metadata::QaMode::Human
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if needs_human_review {
|
||||
// Set review_hold in the content store + CRDT.
|
||||
if let Some(contents) = crate::db::read_content(story_id) {
|
||||
let updated = crate::io::story_metadata::write_review_hold_in_content(&contents);
|
||||
crate::db::write_item_with_content(story_id, "3_qa", &updated);
|
||||
let story_path = project_root
|
||||
.join(".huskies/work/3_qa")
|
||||
.join(format!("{story_id}.md"));
|
||||
if let Err(e) =
|
||||
crate::io::story_metadata::write_review_hold(&story_path)
|
||||
{
|
||||
eprintln!(
|
||||
"[startup:reconcile] Failed to set review_hold on '{story_id}': {e}"
|
||||
);
|
||||
}
|
||||
eprintln!(
|
||||
"[startup:reconcile] '{story_id}' passed QA — holding for human review."
|
||||
|
||||
Reference in New Issue
Block a user