huskies: merge 868

This commit is contained in:
dave
2026-04-29 23:28:57 +00:00
parent e02e566648
commit 1d86202abb
15 changed files with 135 additions and 60 deletions
+5 -23
View File
@@ -1,7 +1,6 @@
//! MCP merge tools — merge agent work to master and report merge failures.
use crate::agents::move_story_to_merge;
use crate::http::context::AppContext;
use crate::io::story_metadata::write_merge_failure;
use crate::slog;
use crate::slog_warn;
use serde_json::{Value, json};
@@ -189,30 +188,14 @@ pub(super) fn tool_report_merge_failure(args: &Value, ctx: &AppContext) -> Resul
reason: reason.to_string(),
});
// Persist the failure reason to the story file's front matter so it
// survives server restarts and is visible in the web UI.
if let Ok(project_root) = ctx.state.get_project_root() {
let story_file = project_root
.join(".huskies")
.join("work")
.join("4_merge")
.join(format!("{story_id}.md"));
if story_file.exists() {
if let Err(e) = write_merge_failure(&story_file, reason) {
slog_warn!(
"[mergemaster] Failed to persist merge_failure to story file for '{story_id}': {e}"
);
}
} else {
slog_warn!(
"[mergemaster] Story file not found in 4_merge/ for '{story_id}'; \
merge_failure not persisted to front matter"
);
}
// Route the failure through the typed state machine (Merge → MergeFailure).
// This persists the reason in front matter and updates the CRDT stage.
if let Err(e) = crate::agents::lifecycle::transition_to_merge_failure(story_id, reason) {
slog_warn!("[mergemaster] Failed to transition '{story_id}' to MergeFailure: {e}");
}
Ok(format!(
"Merge failure for '{story_id}' recorded. Story remains in work/4_merge/. Reason: {reason}"
"Merge failure for '{story_id}' recorded. Reason: {reason}"
))
}
@@ -451,7 +434,6 @@ mod tests {
assert!(result.is_ok());
let msg = result.unwrap();
assert!(msg.contains("42_story_foo"));
assert!(msg.contains("work/4_merge/"));
assert!(msg.contains("Unresolvable merge conflicts"));
}
}
+1
View File
@@ -144,6 +144,7 @@ pub(crate) fn tool_show_epic(args: &Value, _ctx: &AppContext) -> Result<String,
Stage::Merge { .. } => "merge",
Stage::Done { .. } => "done",
Stage::Archived { .. } => "archived",
Stage::MergeFailure { .. } => "merge_failure",
Stage::Frozen { .. } => "frozen",
Stage::Blocked { .. } => "blocked",
};
+1
View File
@@ -149,6 +149,7 @@ pub fn load_pipeline_state(ctx: &AppContext) -> Result<PipelineState, String> {
Stage::Blocked { .. } => state.current.push(story), // blocked shown with current
Stage::Qa => state.qa.push(story),
Stage::Merge { .. } => state.merge.push(story),
Stage::MergeFailure { .. } => state.merge.push(story), // show merge failures with merge
Stage::Done { .. } => state.done.push(story),
Stage::Archived { .. } => {} // skip archived
Stage::Frozen { .. } => state.backlog.push(story), // show frozen with backlog