story-kit: merge 226_bug_mergemaster_accepts_stories_without_squash_merging_code

This commit is contained in:
Dave
2026-02-27 10:37:27 +00:00
parent d2973377f1
commit 850ca15a6c
2 changed files with 279 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
use crate::agents::{close_bug_to_archive, move_story_to_archived, move_story_to_merge, move_story_to_qa, PipelineStage};
use crate::agents::{close_bug_to_archive, feature_branch_has_unmerged_changes, move_story_to_archived, move_story_to_merge, move_story_to_qa, PipelineStage};
use crate::config::ProjectConfig;
use crate::log_buffer;
use crate::slog;
@@ -1432,6 +1432,17 @@ fn tool_accept_story(args: &Value, ctx: &AppContext) -> Result<String, String> {
.ok_or("Missing required argument: story_id")?;
let project_root = ctx.agents.get_project_root(&ctx.state)?;
// Bug 226: Refuse to accept if the feature branch has unmerged code.
// The code must be squash-merged via merge_agent_work first.
if feature_branch_has_unmerged_changes(&project_root, story_id) {
return Err(format!(
"Cannot accept story '{story_id}': feature branch 'feature/story-{story_id}' \
has unmerged changes. Use merge_agent_work to squash-merge the code into \
master first."
));
}
move_story_to_archived(&project_root, story_id)?;
ctx.agents.remove_agents_for_story(story_id);
@@ -3113,6 +3124,76 @@ mod tests {
assert!(result.is_err());
}
/// Bug 226: accept_story must refuse when the feature branch has unmerged code.
#[test]
fn tool_accept_story_refuses_when_feature_branch_has_unmerged_code() {
let tmp = tempfile::tempdir().unwrap();
setup_git_repo_in(tmp.path());
// Create a feature branch with code changes.
std::process::Command::new("git")
.args(["checkout", "-b", "feature/story-50_story_test"])
.current_dir(tmp.path())
.output()
.unwrap();
std::fs::write(tmp.path().join("feature.rs"), "fn main() {}").unwrap();
std::process::Command::new("git")
.args(["add", "."])
.current_dir(tmp.path())
.output()
.unwrap();
std::process::Command::new("git")
.args(["commit", "-m", "add feature"])
.current_dir(tmp.path())
.output()
.unwrap();
std::process::Command::new("git")
.args(["checkout", "master"])
.current_dir(tmp.path())
.output()
.unwrap();
// Create story file in current/ so move_story_to_archived would work.
let current_dir = tmp.path().join(".story_kit/work/2_current");
std::fs::create_dir_all(&current_dir).unwrap();
std::fs::write(
current_dir.join("50_story_test.md"),
"---\nname: Test\n---\n",
)
.unwrap();
let ctx = test_ctx(tmp.path());
let result =
tool_accept_story(&json!({"story_id": "50_story_test"}), &ctx);
assert!(result.is_err(), "should refuse when feature branch has unmerged code");
let err = result.unwrap_err();
assert!(
err.contains("unmerged"),
"error should mention unmerged changes: {err}"
);
}
/// Bug 226: accept_story succeeds when no feature branch exists (e.g. manual stories).
#[test]
fn tool_accept_story_succeeds_when_no_feature_branch() {
let tmp = tempfile::tempdir().unwrap();
setup_git_repo_in(tmp.path());
// Create story file in current/ (no feature branch).
let current_dir = tmp.path().join(".story_kit/work/2_current");
std::fs::create_dir_all(&current_dir).unwrap();
std::fs::write(
current_dir.join("51_story_no_branch.md"),
"---\nname: No Branch\n---\n",
)
.unwrap();
let ctx = test_ctx(tmp.path());
let result =
tool_accept_story(&json!({"story_id": "51_story_no_branch"}), &ctx);
assert!(result.is_ok(), "should succeed when no feature branch: {result:?}");
}
// ── tool_check_criterion tests ────────────────────────────────
#[test]