huskies: merge 1009

This commit is contained in:
dave
2026-05-13 22:50:13 +00:00
parent a5cd3a2152
commit 4e007bb770
56 changed files with 453 additions and 384 deletions
+26 -20
View File
@@ -19,7 +19,7 @@ fn sid(s: &str) -> StoryId {
fn happy_path_backlog_through_archived() {
let s = Stage::Backlog;
let s = transition(s, PipelineEvent::DepsMet).unwrap();
assert!(matches!(s, Stage::Coding));
assert!(matches!(s, Stage::Coding { .. }));
let s = transition(
s,
@@ -52,7 +52,7 @@ fn happy_path_backlog_through_archived() {
#[test]
fn happy_path_with_qa() {
let s = Stage::Coding;
let s = Stage::Coding { claim: None };
let s = transition(s, PipelineEvent::GatesStarted).unwrap();
assert!(matches!(s, Stage::Qa));
@@ -69,7 +69,7 @@ fn happy_path_with_qa() {
#[test]
fn qa_retry_loop() {
let s = Stage::Coding;
let s = Stage::Coding { claim: None };
let s = transition(s, PipelineEvent::GatesStarted).unwrap();
assert!(matches!(s, Stage::Qa));
@@ -80,7 +80,7 @@ fn qa_retry_loop() {
},
)
.unwrap();
assert!(matches!(s, Stage::Coding));
assert!(matches!(s, Stage::Coding { .. }));
}
// ── Bug 519: Merge with zero commits is unrepresentable ─────────────
@@ -154,7 +154,7 @@ fn cannot_start_gates_from_backlog() {
#[test]
fn cannot_accept_from_coding() {
let result = transition(Stage::Coding, PipelineEvent::Accepted);
let result = transition(Stage::Coding { claim: None }, PipelineEvent::Accepted);
assert!(matches!(
result,
Err(TransitionError::InvalidTransition { .. })
@@ -165,7 +165,7 @@ fn cannot_accept_from_coding() {
#[test]
fn block_from_any_active_stage() {
for s in [Stage::Backlog, Stage::Coding, Stage::Qa] {
for s in [Stage::Backlog, Stage::Coding { claim: None }, Stage::Qa] {
let result = transition(
s.clone(),
PipelineEvent::Block {
@@ -178,6 +178,7 @@ fn block_from_any_active_stage() {
let m = Stage::Merge {
feature_branch: fb("f"),
commits_ahead: nz(1),
claim: None,
};
let result = transition(
m,
@@ -194,7 +195,7 @@ fn unblock_returns_to_coding() {
reason: "test".into(),
};
let result = transition(s, PipelineEvent::Unblock).unwrap();
assert!(matches!(result, Stage::Coding));
assert!(matches!(result, Stage::Coding { .. }));
}
#[test]
@@ -251,7 +252,7 @@ fn legacy_unblock_archived_blocked_returns_to_backlog() {
fn abandon_from_any_active_or_done() {
for s in [
Stage::Backlog,
Stage::Coding,
Stage::Coding { claim: None },
Stage::Qa,
Stage::Done {
merged_at: chrono::Utc::now(),
@@ -267,7 +268,7 @@ fn abandon_from_any_active_or_done() {
fn supersede_from_any_active_or_done() {
for s in [
Stage::Backlog,
Stage::Coding,
Stage::Coding { claim: None },
Stage::Qa,
Stage::Done {
merged_at: chrono::Utc::now(),
@@ -291,7 +292,7 @@ fn review_hold_from_active_stages() {
// Story 945: `ReviewHold` transitions to `Stage::ReviewHold { resume_to }`
// with the resume_to set to the originating stage, replacing the legacy
// boolean flag.
for s in [Stage::Backlog, Stage::Coding, Stage::Qa] {
for s in [Stage::Backlog, Stage::Coding { claim: None }, Stage::Qa] {
let result = transition(
s.clone(),
PipelineEvent::ReviewHold {
@@ -316,6 +317,7 @@ fn merge_failed_final() {
let s = Stage::Merge {
feature_branch: fb("f"),
commits_ahead: nz(1),
claim: None,
};
let result = transition(
s,
@@ -336,7 +338,7 @@ fn merge_failed_final() {
#[test]
fn merge_failed_only_from_merge() {
let result = transition(
Stage::Coding,
Stage::Coding { claim: None },
PipelineEvent::MergeFailedFinal {
reason: "conflicts".into(),
},
@@ -413,6 +415,7 @@ fn bug_502_agent_not_in_stage() {
let merge = Stage::Merge {
feature_branch: BranchName("feature/story-1".into()),
commits_ahead: NonZeroU32::new(3).unwrap(),
claim: None,
};
// Stage::Merge has exactly two fields: feature_branch and commits_ahead.
// There is no way to attach an agent name to it. The type system
@@ -480,7 +483,7 @@ fn cannot_deps_met_from_upcoming() {
#[test]
fn reject_from_active_stages() {
for s in [Stage::Backlog, Stage::Coding, Stage::Qa] {
for s in [Stage::Backlog, Stage::Coding { claim: None }, Stage::Qa] {
let result = transition(
s.clone(),
PipelineEvent::Reject {
@@ -493,6 +496,7 @@ fn reject_from_active_stages() {
let m = Stage::Merge {
feature_branch: fb("f"),
commits_ahead: nz(1),
claim: None,
};
let result = transition(
m,
@@ -561,7 +565,7 @@ fn freeze_transitions_to_frozen_variant_with_resume_to() {
);
let item = read_typed(story_id).unwrap().unwrap();
assert!(matches!(item.stage, Stage::Coding));
assert!(matches!(item.stage, Stage::Coding { .. }));
assert!(!matches!(item.stage, Stage::Frozen { .. }));
super::apply::transition_to_frozen(story_id).expect("freeze should succeed");
@@ -569,7 +573,7 @@ fn freeze_transitions_to_frozen_variant_with_resume_to() {
let item = read_typed(story_id).unwrap().unwrap();
match &item.stage {
Stage::Frozen { resume_to } => assert!(
matches!(**resume_to, Stage::Coding),
matches!(**resume_to, Stage::Coding { .. }),
"resume_to should preserve the previous stage; got {resume_to:?}"
),
other => panic!("stage should be Stage::Frozen after freeze; got {other:?}"),
@@ -583,7 +587,7 @@ fn freeze_transitions_to_frozen_variant_with_resume_to() {
let item = read_typed(story_id).unwrap().unwrap();
assert!(
matches!(item.stage, Stage::Coding),
matches!(item.stage, Stage::Coding { .. }),
"stage should return to Coding after unfreeze: {:?}",
item.stage
);
@@ -884,10 +888,11 @@ fn merge_aborted_returns_to_coding() {
let s = Stage::Merge {
feature_branch: fb("feature/story-73"),
commits_ahead: nz(2),
claim: None,
};
let result = transition(s, PipelineEvent::MergeAborted).unwrap();
assert!(
matches!(result, Stage::Coding),
matches!(result, Stage::Coding { .. }),
"Merge + MergeAborted should return to Coding, got: {result:?}"
);
}
@@ -915,7 +920,7 @@ fn merge_aborted_moves_to_coding_via_crdt() {
fired.before
);
assert!(
matches!(fired.after, Stage::Coding),
matches!(fired.after, Stage::Coding { .. }),
"fired.after should be Coding: {:?}",
fired.after
);
@@ -958,7 +963,7 @@ fn move_story_merge_to_current_succeeds() {
.expect("CRDT read should succeed")
.expect("item should exist");
assert!(
matches!(item.stage, Stage::Coding),
matches!(item.stage, Stage::Coding { .. }),
"story should be in Coding after move_story_to_stage(merge → current): {:?}",
item.stage
);
@@ -974,7 +979,7 @@ fn hotfix_requested_from_done_lands_in_coding() {
};
let result = transition(done, PipelineEvent::HotfixRequested).unwrap();
assert!(
matches!(result, Stage::Coding),
matches!(result, Stage::Coding { .. }),
"Done + HotfixRequested must land in Coding; got: {:?}",
result
);
@@ -984,11 +989,12 @@ fn hotfix_requested_from_done_lands_in_coding() {
fn hotfix_requested_rejected_from_non_done_stages() {
for stage in [
Stage::Backlog,
Stage::Coding,
Stage::Coding { claim: None },
Stage::Qa,
Stage::Merge {
feature_branch: fb("feature/story-1"),
commits_ahead: nz(1),
claim: None,
},
] {
let result = transition(stage.clone(), PipelineEvent::HotfixRequested);