huskies: merge 961

This commit is contained in:
dave
2026-05-13 11:22:57 +00:00
parent 78b1ecdc3c
commit 8b53e20ca9
38 changed files with 327 additions and 146 deletions
@@ -384,18 +384,18 @@ mod tests {
crate::db::ensure_content_store();
let dep_content = "---\nname: Dep\n---\n";
std::fs::write(done.join("1_story_dep.md"), dep_content).unwrap();
crate::db::write_content("1_story_dep", dep_content);
crate::db::write_content(crate::db::ContentKey::Story("1_story_dep"), dep_content);
// Story B depends on story 1.
let story_b_content = "---\nname: B\ndepends_on: [1]\n---\n";
std::fs::write(backlog.join("2_story_b.md"), story_b_content).unwrap();
crate::db::write_content("2_story_b", story_b_content);
crate::db::write_content(crate::db::ContentKey::Story("2_story_b"), story_b_content);
let pool = AgentPool::new_test(3001);
pool.auto_assign_available_work(root).await;
// The lifecycle function updates the content store (not the filesystem),
// so verify the move via the DB.
let content = crate::db::read_content("2_story_b")
let content = crate::db::read_content(crate::db::ContentKey::Story("2_story_b"))
.expect("story B should be in content store after promotion");
assert!(
content.contains("name: B"),
@@ -458,11 +458,14 @@ mod tests {
crate::db::ensure_content_store();
let dep_content = "---\nname: CRDT Spike\n---\n";
std::fs::write(archived.join("490_spike_crdt.md"), dep_content).unwrap();
crate::db::write_content("490_spike_crdt", dep_content);
crate::db::write_content(crate::db::ContentKey::Story("490_spike_crdt"), dep_content);
// Story 478 depends on 490 (the archived spike).
let story_content = "---\nname: Dependent\ndepends_on: [490]\n---\n";
std::fs::write(backlog.join("478_story_dependent.md"), story_content).unwrap();
crate::db::write_content("478_story_dependent", story_content);
crate::db::write_content(
crate::db::ContentKey::Story("478_story_dependent"),
story_content,
);
let pool = AgentPool::new_test(3001);
pool.auto_assign_available_work(root).await;
@@ -470,7 +473,7 @@ mod tests {
// Story 478 must be promoted even though dep 490 is only in 6_archived
// (not in 5_done), because archived = satisfied. The lifecycle function
// updates the content store, so verify via the DB.
let content = crate::db::read_content("478_story_dependent")
let content = crate::db::read_content(crate::db::ContentKey::Story("478_story_dependent"))
.expect("story 478 should be in content store after promotion");
assert!(
content.contains("name: Dependent"),
@@ -531,7 +534,7 @@ mod tests {
// After master c228ae16, has_content_conflict_failure reads from
// {story_id}:gate_output (not the story description), so seed it there.
crate::db::write_content(
"9860_story_conflict:gate_output",
crate::db::ContentKey::GateOutput("9860_story_conflict"),
"CONFLICT (content): server/src/lib.rs",
);
@@ -690,11 +693,14 @@ mod tests {
// After master c228ae16, has_content_conflict_failure reads from
// {story_id}:gate_output (not the story description), so seed it there.
crate::db::write_content(
"920_story_transient:gate_output",
crate::db::ContentKey::GateOutput("920_story_transient"),
"CONFLICT (content): foo.rs",
);
// Simulate two previous transient exits (below cap of 3) recorded in DB.
crate::db::write_content("920_story_transient:mergemaster_spawn_count", "2");
crate::db::write_content(
crate::db::ContentKey::MergeMasterSpawnCount("920_story_transient"),
"2",
);
// mergemaster_attempted must still be false (transient exits don't set it).
let pool = AgentPool::new_test(3001);
@@ -74,9 +74,8 @@ pub(super) fn has_content_conflict_failure(
}
// The projection does not carry the reason string; read the gate output
// (where the merge runner persists the failure message) and scan for
// conflict markers. NB: the key is `{story_id}:gate_output`, not `{story_id}`
// — the latter is the story's *description* text and would never match.
crate::db::read_content(&format!("{story_id}:gate_output"))
// conflict markers.
crate::db::read_content(crate::db::ContentKey::GateOutput(story_id))
.map(|content| {
content.contains("Merge conflict") || content.contains("CONFLICT (content):")
})
@@ -242,7 +242,7 @@ max_turns = 10
// watchdog's retry/block path has something to read+update.
let story_id = "42_story_runaway";
let initial = "---\nname: Runaway Story\n---\n# Runaway Story\n";
crate::db::write_content(story_id, initial);
crate::db::write_content(crate::db::ContentKey::Story(story_id), initial);
crate::crdt_state::write_item_str(
story_id,
"2_current",
@@ -369,7 +369,10 @@ max_turns = 10
);
let story_id = "story_e_per_session";
crate::db::write_content(story_id, "---\nname: Per-Session Test\n---\n");
crate::db::write_content(
crate::db::ContentKey::Story(story_id),
"---\nname: Per-Session Test\n---\n",
);
crate::crdt_state::write_item_str(
story_id,
"2_current",
@@ -448,7 +451,7 @@ max_turns = 10
let story_id = "88_story_retry_watchdog";
let initial = "---\nname: Retry Test\n---\n";
crate::crdt_state::init_for_test();
crate::db::write_content(story_id, initial);
crate::db::write_content(crate::db::ContentKey::Story(story_id), initial);
crate::crdt_state::write_item_str(
story_id,
"2_current",