huskies: merge 913
This commit is contained in:
@@ -12,8 +12,8 @@ use std::process::Command;
|
||||
|
||||
use crate::db::yaml_legacy::clear_front_matter_field_in_content;
|
||||
use crate::pipeline_state::{
|
||||
ApplyError, ArchiveReason, BranchName, GitSha, PipelineEvent, Stage, apply_transition,
|
||||
stage_label,
|
||||
ApplyError, ArchiveReason, BranchName, GitSha, PipelineEvent, Stage, TransitionFired,
|
||||
apply_transition, stage_label,
|
||||
};
|
||||
use crate::slog;
|
||||
|
||||
@@ -248,13 +248,22 @@ pub fn transition_to_blocked(story_id: &str, reason: &str) -> Result<(), String>
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Transition a story from `Stage::Merge` to `Stage::MergeFailure` via the state machine.
|
||||
/// Transition a story from `Stage::Merge` (or `Stage::MergeFailure`) to
|
||||
/// `Stage::MergeFailure` via the state machine.
|
||||
///
|
||||
/// Builds a `PipelineEvent::MergeFailed { reason }`, validates the transition, writes
|
||||
/// the resulting `Stage::MergeFailure` to the CRDT, and persists the reason to front
|
||||
/// matter so it survives server restarts.
|
||||
///
|
||||
/// When the story is already in `MergeFailure`, this is a silent self-loop: the
|
||||
/// returned `TransitionFired::before` will be `Stage::MergeFailure`. Callers
|
||||
/// should suppress re-notification in that case to avoid duplicate chat messages.
|
||||
///
|
||||
/// Returns `Err` on `TransitionError` — callers must NOT fall back to direct register writes.
|
||||
pub fn transition_to_merge_failure(story_id: &str, reason: &str) -> Result<(), String> {
|
||||
pub fn transition_to_merge_failure(
|
||||
story_id: &str,
|
||||
reason: &str,
|
||||
) -> Result<TransitionFired, String> {
|
||||
let reason_owned = reason.to_string();
|
||||
let transform: Box<dyn Fn(&str) -> String> = Box::new(move |content: &str| {
|
||||
crate::db::yaml_legacy::write_merge_failure_in_content(content, &reason_owned)
|
||||
@@ -266,7 +275,6 @@ pub fn transition_to_merge_failure(story_id: &str, reason: &str) -> Result<(), S
|
||||
},
|
||||
Some(&*transform),
|
||||
)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
|
||||
@@ -126,19 +126,30 @@ impl AgentPool {
|
||||
});
|
||||
} else {
|
||||
// Transition through the state machine (Merge → MergeFailure).
|
||||
if let Err(e) =
|
||||
crate::agents::lifecycle::transition_to_merge_failure(&sid, &reason)
|
||||
{
|
||||
crate::slog_error!(
|
||||
"[merge] Failed to transition '{sid}' to MergeFailure: {e}"
|
||||
);
|
||||
// Only send the notification when the stage actually changed; if the
|
||||
// story was already in MergeFailure (self-loop), suppress the duplicate.
|
||||
let should_notify = match crate::agents::lifecycle::transition_to_merge_failure(
|
||||
&sid, &reason,
|
||||
) {
|
||||
Ok(fired) => !matches!(
|
||||
fired.before,
|
||||
crate::pipeline_state::Stage::MergeFailure { .. }
|
||||
),
|
||||
Err(e) => {
|
||||
crate::slog_error!(
|
||||
"[merge] Failed to transition '{sid}' to MergeFailure: {e}"
|
||||
);
|
||||
true
|
||||
}
|
||||
};
|
||||
if should_notify {
|
||||
let _ =
|
||||
pool.watcher_tx
|
||||
.send(crate::io::watcher::WatcherEvent::MergeFailure {
|
||||
story_id: sid.clone(),
|
||||
reason,
|
||||
});
|
||||
}
|
||||
let _ = pool
|
||||
.watcher_tx
|
||||
.send(crate::io::watcher::WatcherEvent::MergeFailure {
|
||||
story_id: sid.clone(),
|
||||
reason,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user