huskies: merge 986
This commit is contained in:
@@ -5,24 +5,6 @@ use crate::worktree;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Return `true` when `gate_output` matches a self-evident-fix class of failure
|
||||
/// that a short fixup coder session can resolve without human intervention.
|
||||
///
|
||||
/// Patterns covered: fmt drift (`cargo fmt --check`), clippy warnings promoted
|
||||
/// to errors (`-D warnings`), and missing doc comments detected by clippy or
|
||||
/// the source-map-check gate.
|
||||
fn is_self_evident_fix(gate_output: &str) -> bool {
|
||||
let patterns: &[&str] = &[
|
||||
"Diff in ", // cargo fmt --check output
|
||||
"would reformat", // rustfmt --check output
|
||||
"error[clippy::", // clippy error
|
||||
"warning[clippy::", // clippy warning (treated as error via -D warnings)
|
||||
"missing_doc_comments", // clippy missing-doc lint
|
||||
"missing-docs direction", // source-map-check gate
|
||||
];
|
||||
patterns.iter().any(|p| gate_output.contains(p))
|
||||
}
|
||||
|
||||
use super::super::super::AgentPool;
|
||||
use super::time::{
|
||||
decode_server_start_time, encode_server_start_time, server_start_time, unix_now,
|
||||
@@ -130,31 +112,28 @@ impl AgentPool {
|
||||
// On any failure: record merge_failure in CRDT and emit notification.
|
||||
if !success {
|
||||
let kind = match &report {
|
||||
Ok(r) if r.no_commits => crate::pipeline_state::MergeFailureKind::NoCommits,
|
||||
Ok(r) if r.had_conflicts => {
|
||||
crate::pipeline_state::MergeFailureKind::ConflictDetected(
|
||||
r.conflict_details.clone(),
|
||||
)
|
||||
}
|
||||
Ok(r) => {
|
||||
if r.had_conflicts {
|
||||
crate::pipeline_state::MergeFailureKind::ConflictDetected(
|
||||
r.conflict_details.clone(),
|
||||
)
|
||||
} else {
|
||||
crate::pipeline_state::MergeFailureKind::GatesFailed(
|
||||
r.gate_output.clone(),
|
||||
)
|
||||
}
|
||||
crate::pipeline_state::MergeFailureKind::GatesFailed(r.gate_output.clone())
|
||||
}
|
||||
Err(e) => crate::pipeline_state::MergeFailureKind::Other(e.clone()),
|
||||
};
|
||||
let is_no_commits = matches!(
|
||||
&kind,
|
||||
crate::pipeline_state::MergeFailureKind::Other(r) if r.contains("no commits to merge")
|
||||
);
|
||||
// Self-evident fix: gate-only failure whose output matches a pattern
|
||||
// a fixup coder can resolve in one short session (story 981).
|
||||
let fixup_output = match &kind {
|
||||
crate::pipeline_state::MergeFailureKind::GatesFailed(o) => o.as_str(),
|
||||
_ => "",
|
||||
};
|
||||
let is_fixup =
|
||||
!is_no_commits && !fixup_output.is_empty() && is_self_evident_fix(fixup_output);
|
||||
let is_no_commits =
|
||||
matches!(&kind, crate::pipeline_state::MergeFailureKind::NoCommits);
|
||||
// Self-evident fix: gate-only failure whose typed kind a fixup coder
|
||||
// can resolve in one short session (story 981, 986).
|
||||
let is_fixup = !is_no_commits
|
||||
&& report
|
||||
.as_ref()
|
||||
.ok()
|
||||
.and_then(|r| r.gate_failure_kind.as_ref())
|
||||
.map(|k| k.is_self_evident_fix())
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_no_commits {
|
||||
let reason = kind.display_reason();
|
||||
@@ -301,6 +280,8 @@ impl AgentPool {
|
||||
conflict_details: merge_result.conflict_details,
|
||||
gates_passed: merge_result.gates_passed,
|
||||
gate_output: merge_result.output,
|
||||
gate_failure_kind: merge_result.gate_failure_kind,
|
||||
no_commits: merge_result.no_commits,
|
||||
worktree_cleaned_up: false,
|
||||
story_archived: false,
|
||||
});
|
||||
@@ -330,6 +311,8 @@ impl AgentPool {
|
||||
conflict_details: merge_result.conflict_details,
|
||||
gates_passed: true,
|
||||
gate_output: merge_result.output,
|
||||
gate_failure_kind: None,
|
||||
no_commits: false,
|
||||
worktree_cleaned_up,
|
||||
story_archived,
|
||||
})
|
||||
|
||||
@@ -29,6 +29,8 @@ impl AgentPool {
|
||||
conflict_details: None,
|
||||
gates_passed: false,
|
||||
gate_output: String::new(),
|
||||
gate_failure_kind: None,
|
||||
no_commits: false,
|
||||
worktree_cleaned_up: false,
|
||||
story_archived: false,
|
||||
});
|
||||
|
||||
@@ -590,23 +590,27 @@ async fn merge_agent_work_zero_commits_ahead_stays_in_merge_stage() {
|
||||
let pool = Arc::new(AgentPool::new_test(3001));
|
||||
let job = run_merge_to_completion(&pool, repo, "675_zero_commits").await;
|
||||
|
||||
// The job must have failed with a "no commits to merge" error.
|
||||
// The job must have completed with success=false and no_commits=true.
|
||||
// Since story 986 the "no commits" path returns Ok(result) not Err, so the
|
||||
// job status is Completed (not Failed).
|
||||
match &job.status {
|
||||
MergeJobStatus::Failed(e) => {
|
||||
MergeJobStatus::Completed(report) => {
|
||||
assert!(
|
||||
e.contains("no commits to merge"),
|
||||
"error must contain 'no commits to merge', got: {e}"
|
||||
!report.success,
|
||||
"merge must not have succeeded when feature branch is empty"
|
||||
);
|
||||
assert!(
|
||||
e.contains("675_zero_commits"),
|
||||
"error must name the story_id, got: {e}"
|
||||
report.no_commits,
|
||||
"report.no_commits must be true for a zero-ahead branch"
|
||||
);
|
||||
assert!(
|
||||
report.gate_output.contains("no commits to merge"),
|
||||
"gate_output must contain 'no commits to merge', got: {}",
|
||||
report.gate_output
|
||||
);
|
||||
}
|
||||
MergeJobStatus::Completed(report) => {
|
||||
panic!(
|
||||
"expected Failed status, got Completed with success={}: {}",
|
||||
report.success, report.gate_output
|
||||
);
|
||||
MergeJobStatus::Failed(e) => {
|
||||
panic!("expected Completed(success=false) status, got Failed: {e}");
|
||||
}
|
||||
MergeJobStatus::Running => panic!("should not still be running"),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user