huskies: merge 892

This commit is contained in:
dave
2026-05-12 16:46:37 +00:00
parent c3144b7937
commit b76633b79b
4 changed files with 86 additions and 1 deletions
+66
View File
@@ -828,4 +828,70 @@ fn repeated_merge_failure_apply_transition_no_error_no_duplicate_notification()
);
}
// ── Story 892: MergeFailure → Done (manual recovery) ───────────────
/// Regression test (story 892): `accept_story` on a story in `MergeFailure`
/// transitions it to `Done` and emits a `TransitionFired` event.
#[test]
fn merge_failure_accept_pure_transition() {
let s = Stage::MergeFailure {
reason: "conflicts unresolvable".into(),
};
let result = transition(s, PipelineEvent::Accepted).unwrap();
assert!(
matches!(result, Stage::Done { .. }),
"MergeFailure + Accepted should yield Done, got: {result:?}"
);
}
/// Regression test (story 892): `apply_transition` on a CRDT-stored `MergeFailure`
/// story moves it to `Done` and the emitted `TransitionFired` event is present.
#[test]
fn merge_failure_accept_moves_to_done_via_crdt() {
crate::crdt_state::init_for_test();
crate::db::ensure_content_store();
let story_id = "99892_story_merge_failure_accept";
crate::db::write_item_with_content(
story_id,
"4_merge_failure",
"---\nname: MergeFailure Accept Test\n---\n# Story\n",
crate::db::ItemMeta::from_yaml("---\nname: MergeFailure Accept Test\n---\n# Story\n"),
);
let fired = super::apply::apply_transition(story_id, PipelineEvent::Accepted, None)
.expect("MergeFailure + Accepted should succeed");
// The before-stage was MergeFailure.
assert!(
matches!(fired.before, Stage::MergeFailure { .. }),
"fired.before should be MergeFailure: {:?}",
fired.before
);
// The after-stage is Done.
assert!(
matches!(fired.after, Stage::Done { .. }),
"fired.after should be Done: {:?}",
fired.after
);
// TransitionFired carries the Accepted event.
assert!(
matches!(fired.event, PipelineEvent::Accepted),
"fired.event should be Accepted: {:?}",
fired.event
);
// CRDT reflects 5_done.
let item = read_typed(story_id)
.expect("CRDT read should succeed")
.expect("item should exist");
assert_eq!(
item.stage.dir_name(),
"5_done",
"CRDT stage should be 5_done after MergeFailure + Accepted"
);
}
// ── ProjectionError Display ─────────────────────────────────────────
+8
View File
@@ -164,6 +164,14 @@ pub fn transition(state: Stage, event: PipelineEvent) -> Result<Stage, Transitio
reason: ArchiveReason::Completed,
}),
// ── MergeFailure → Done (manual recovery) ───────────────────────
// Allows a human operator to accept a story whose merge permanently
// failed, marking it Done without going through the normal merge path.
(MergeFailure { .. }, Accepted) => Ok(Done {
merged_at: now,
merge_commit: GitSha("manual".to_string()),
}),
// ── Block: any active → Blocked ──────────────────────────────
(Backlog, Block { reason })
| (Coding, Block { reason })