Add flow-control data to STAGE_COMPLETED event

Add status, preferred_label, and suggested_next_ids fields to the
StageCompleted event so pipeline flow decisions are visible in CLI
output and the web UI, making it easier to debug why a pipeline
took a particular path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-02-23 16:32:42 -05:00
parent 95a4ab24d5
commit 480364c2b0
4 changed files with 31 additions and 5 deletions

View file

@ -30,8 +30,11 @@ function eventDetail(event: PipelineEvent): string {
return `${data.error} (${data.duration_ms}ms)`;
case "StageStarted":
return `${data.name} [${data.index}]`;
case "StageCompleted":
return `${data.name} [${data.index}] ${data.duration_ms}ms`;
case "StageCompleted": {
let detail = `${data.name} [${data.index}] ${data.duration_ms}ms ${data.status}`;
if (data.preferred_label) detail += ` → "${data.preferred_label}"`;
return detail;
}
case "StageFailed":
return `${data.name} [${data.index}]: ${data.error}${data.will_retry ? " (will retry)" : ""}`;
case "StageRetrying":

View file

@ -54,7 +54,7 @@ export type PipelineEvent =
| { PipelineCompleted: { duration_ms: number; artifact_count: number } }
| { PipelineFailed: { error: string; duration_ms: number } }
| { StageStarted: { name: string; index: number } }
| { StageCompleted: { name: string; index: number; duration_ms: number } }
| { StageCompleted: { name: string; index: number; duration_ms: number; status: string; preferred_label?: string; suggested_next_ids: string[] } }
| { StageFailed: { name: string; index: number; error: string; will_retry: boolean } }
| { StageRetrying: { name: string; index: number; attempt: number; delay_ms: number } }
| { ParallelStarted: { branch_count: number } }

View file

@ -164,8 +164,18 @@ pub fn format_event_summary(event: &PipelineEvent, styles: &Styles) -> String {
name,
index,
duration_ms,
status,
preferred_label,
suggested_next_ids,
} => {
format!("[STAGE_COMPLETED] name={name} index={index} duration={duration_ms}ms")
let mut s = format!("[STAGE_COMPLETED] name={name} index={index} duration={duration_ms}ms status={status}");
if let Some(label) = preferred_label {
s.push_str(&format!(" preferred_label=\"{label}\""));
}
if !suggested_next_ids.is_empty() {
s.push_str(&format!(" suggested_next_ids={}", suggested_next_ids.join(",")));
}
s
}
PipelineEvent::StageFailed {
name,
@ -263,8 +273,18 @@ pub fn format_event_detail(event: &PipelineEvent, styles: &Styles) -> String {
name,
index,
duration_ms,
status,
preferred_label,
suggested_next_ids,
} => {
format!("{d}── STAGE_COMPLETED ──────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}duration_ms:{r} {duration_ms}\n")
let mut s = format!("{d}── STAGE_COMPLETED ──────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}duration_ms:{r} {duration_ms}\n {d}status:{r} {status}\n");
if let Some(label) = preferred_label {
s.push_str(&format!(" {d}preferred_label:{r} {label}\n"));
}
if !suggested_next_ids.is_empty() {
s.push_str(&format!(" {d}suggested_next_ids:{r} {}\n", suggested_next_ids.join(", ")));
}
s
}
PipelineEvent::StageFailed {
name,

View file

@ -23,6 +23,9 @@ pub enum PipelineEvent {
name: String,
index: usize,
duration_ms: u64,
status: String,
preferred_label: Option<String>,
suggested_next_ids: Vec<String>,
},
StageFailed {
name: String,