huskies: merge 920
This commit is contained in:
@@ -657,6 +657,92 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Story 920: transient vs genuine mergemaster termination ──────────────
|
||||
|
||||
/// AC4 (transient): a mergemaster that was killed transiently (no
|
||||
/// report_merge_failure, spawn count below cap) must be re-spawned by the
|
||||
/// next auto-assign pass — `mergemaster_attempted` stays false.
|
||||
#[tokio::test]
|
||||
async fn transient_mergemaster_exit_allows_respawn() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let sk = tmp.path().join(".huskies");
|
||||
std::fs::create_dir_all(&sk).unwrap();
|
||||
std::fs::write(
|
||||
sk.join("project.toml"),
|
||||
"[[agent]]\nname = \"mergemaster\"\nstage = \"mergemaster\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
crate::crdt_state::init_for_test();
|
||||
crate::db::ensure_content_store();
|
||||
crate::db::write_item_with_content(
|
||||
"920_story_transient",
|
||||
"4_merge_failure",
|
||||
"---\nname: Transient\nmerge_failure: \"CONFLICT (content): foo.rs\"\n---\n",
|
||||
crate::db::ItemMeta::from_yaml(
|
||||
"---\nname: Transient\nmerge_failure: \"CONFLICT (content): foo.rs\"\n---\n",
|
||||
),
|
||||
);
|
||||
// Simulate two previous transient exits (below cap of 3) recorded in DB.
|
||||
crate::db::write_content("920_story_transient:mergemaster_spawn_count", "2");
|
||||
|
||||
// mergemaster_attempted must still be false (transient exits don't set it).
|
||||
let pool = AgentPool::new_test(3001);
|
||||
pool.auto_assign_available_work(tmp.path()).await;
|
||||
|
||||
let agents = pool.agents.lock().unwrap();
|
||||
let respawned = agents.iter().any(|(key, a)| {
|
||||
key.contains("920_story_transient")
|
||||
&& a.agent_name == "mergemaster"
|
||||
&& matches!(a.status, AgentStatus::Pending | AgentStatus::Running)
|
||||
});
|
||||
assert!(
|
||||
respawned,
|
||||
"mergemaster must re-spawn after transient terminations while below cap"
|
||||
);
|
||||
}
|
||||
|
||||
/// AC4 (genuine): after report_merge_failure, mergemaster_attempted is set
|
||||
/// to true and auto-assign must not trigger another re-spawn.
|
||||
#[tokio::test]
|
||||
async fn genuine_mergemaster_exit_no_respawn() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let sk = tmp.path().join(".huskies");
|
||||
std::fs::create_dir_all(&sk).unwrap();
|
||||
std::fs::write(
|
||||
sk.join("project.toml"),
|
||||
"[[agent]]\nname = \"mergemaster\"\nstage = \"mergemaster\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
crate::crdt_state::init_for_test();
|
||||
crate::db::ensure_content_store();
|
||||
// mergemaster_attempted is set by the exit path when genuine give-up occurs.
|
||||
crate::db::write_item_with_content(
|
||||
"920_story_genuine",
|
||||
"4_merge_failure",
|
||||
"---\nname: Genuine\nmerge_failure: \"CONFLICT (content): bar.rs\"\n---\n",
|
||||
crate::db::ItemMeta::from_yaml(
|
||||
"---\nname: Genuine\nmerge_failure: \"CONFLICT (content): bar.rs\"\n---\n",
|
||||
),
|
||||
);
|
||||
// The CRDT register is the sole authority; set it explicitly as the
|
||||
// spawn exit path would after report_merge_failure.
|
||||
crate::crdt_state::set_mergemaster_attempted("920_story_genuine", true);
|
||||
|
||||
let pool = AgentPool::new_test(3001);
|
||||
pool.auto_assign_available_work(tmp.path()).await;
|
||||
|
||||
let agents = pool.agents.lock().unwrap();
|
||||
let spawned = agents.iter().any(|(key, a)| {
|
||||
key.contains("920_story_genuine")
|
||||
&& a.agent_name == "mergemaster"
|
||||
&& matches!(a.status, AgentStatus::Pending | AgentStatus::Running)
|
||||
});
|
||||
assert!(
|
||||
!spawned,
|
||||
"mergemaster must not re-spawn after genuine give-up (mergemaster_attempted=true)"
|
||||
);
|
||||
}
|
||||
|
||||
/// Two concurrent auto_assign_available_work calls must not assign the same
|
||||
/// agent to two stories simultaneously. After both complete, at most one
|
||||
/// Pending/Running entry must exist per agent name.
|
||||
|
||||
Reference in New Issue
Block a user