huskies: merge 1036

This commit is contained in:
dave
2026-05-14 15:07:57 +00:00
parent cfccc2e73c
commit ee20e54d40
17 changed files with 72 additions and 2 deletions
+1
View File
@@ -174,6 +174,7 @@ mod tests {
commits_ahead: NonZeroU32::new(3).unwrap(),
claim: None,
retries: 0,
server_start_time: 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
+1
View File
@@ -177,6 +177,7 @@ mod tests {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
},
Some("Test"),
);
+9
View File
@@ -203,6 +203,7 @@ fn block_from_any_active_stage() {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
};
let result = transition(
m,
@@ -359,6 +360,7 @@ fn merge_failed_final() {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
};
let result = transition(
s,
@@ -462,6 +464,7 @@ fn bug_502_agent_not_in_stage() {
commits_ahead: NonZeroU32::new(3).unwrap(),
claim: None,
retries: 0,
server_start_time: 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
@@ -552,6 +555,7 @@ fn reject_from_active_stages() {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
};
let result = transition(
m,
@@ -945,6 +949,7 @@ fn merge_aborted_returns_to_coding() {
commits_ahead: nz(2),
claim: None,
retries: 0,
server_start_time: None,
};
let result = transition(s, PipelineEvent::MergeAborted).unwrap();
assert!(
@@ -1056,6 +1061,7 @@ fn hotfix_requested_rejected_from_non_done_stages() {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
},
] {
let result = transition(stage.clone(), PipelineEvent::HotfixRequested);
@@ -1101,6 +1107,7 @@ fn audit_entry_is_single_line_with_all_fields() {
commits_ahead: nz(3),
claim: None,
retries: 0,
server_start_time: None,
},
event: PipelineEvent::GatesPassed {
feature_branch: fb("feature/story-42"),
@@ -1139,6 +1146,7 @@ fn audit_entry_merge_to_done() {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
},
after: Stage::Done {
merged_at: chrono::Utc::now(),
@@ -1232,6 +1240,7 @@ fn audit_entry_merge_to_merge_failure() {
commits_ahead: nz(1),
claim: None,
retries: 0,
server_start_time: None,
},
after: Stage::MergeFailure {
kind: MergeFailureKind::Other("conflicts".into()),
+3
View File
@@ -166,6 +166,7 @@ pub fn transition(state: Stage, event: PipelineEvent) -> Result<Stage, Transitio
commits_ahead,
claim: None,
retries: 0,
server_start_time: None,
}),
(
Qa,
@@ -178,6 +179,7 @@ pub fn transition(state: Stage, event: PipelineEvent) -> Result<Stage, Transitio
commits_ahead,
claim: None,
retries: 0,
server_start_time: None,
}),
(Qa, GatesFailed { .. }) => Ok(Coding {
claim: None,
@@ -394,6 +396,7 @@ pub fn transition(state: Stage, event: PipelineEvent) -> Result<Stage, Transitio
commits_ahead,
claim: None,
retries: 0,
server_start_time: None,
}),
// ── Demote MergeFailure → Backlog (manual parking) ───────────────
+12 -2
View File
@@ -195,7 +195,7 @@ impl PlanState {
/// | superseded | `Superseded { .. }` |
/// | rejected | `Rejected { .. }` |
/// | abandoned | `Abandoned { .. }` |
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Stage {
/// Story has been created but not yet triaged into the backlog.
Upcoming,
@@ -233,6 +233,12 @@ pub enum Stage {
///
/// `retries` counts how many times the mergemaster agent has been restarted
/// for this item. Replaces the separate `retry_count` CRDT register (story 997).
///
/// `server_start_time` is the Unix timestamp (f64 seconds) captured when
/// the current server process first called `server_start_time()`. Written
/// by the merge runner when it begins a merge task; `None` means no merge
/// task is in flight on any node right now. Used by `reap_stale_merge_jobs`
/// to detect merges left running by a previous server process (story 1036).
Merge {
feature_branch: BranchName,
commits_ahead: NonZeroU32,
@@ -240,6 +246,9 @@ pub enum Stage {
claim: Option<AgentClaim>,
/// Number of mergemaster restarts for this item. Zero on the first attempt.
retries: u32,
/// Unix timestamp of the server process that started the active merge task.
/// `None` means no merge task is currently in flight.
server_start_time: Option<f64>,
},
/// Mergemaster squashed to master. Always carries merge metadata.
@@ -371,6 +380,7 @@ impl Stage {
commits_ahead: NonZeroU32::new(1).expect("1 is non-zero"),
claim: None,
retries: 0,
server_start_time: None,
}),
"merge_failure" => Some(Stage::MergeFailure {
kind: MergeFailureKind::Other(String::new()),
@@ -455,7 +465,7 @@ pub enum ExecutionState {
///
/// The retry count is no longer a top-level field — callers read it from the
/// Stage variant (`Stage::Coding { retries }` / `Stage::Merge { retries }`).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PipelineItem {
pub story_id: StoryId,
pub name: String,