fix: compute wall-clock duration for flow job groups in CLI (#8826)

The total duration of a for-loop/branchall group was computed as the
naive sum of all iteration durations. This is wrong for parallel
execution and doesn't account for orchestration overhead. Instead,
compute actual wall-clock time as max(completed_at) - min(started_at).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Diego Imbert
2026-04-14 22:16:50 +02:00
committed by GitHub
parent 6bb80ff28b
commit e1dbce02c2

View File

@@ -155,21 +155,36 @@ function formatFlowSteps(
// For-loop modules: show parent line + iteration sub-lines
const flowJobs = mod.flow_jobs as string[] | undefined;
if (flowJobs && flowJobs.length > 0) {
// Total duration for the for-loop
const totalMs = flowJobsDuration?.duration_ms
? (flowJobsDuration.duration_ms as number[]).reduce((a: number, b: number) => a + b, 0)
: undefined;
// Compute actual wall-clock duration for the group from started_at + duration_ms
const startedAtArr = (flowJobsDuration?.started_at ?? []) as (string | null)[];
const durationMsArr = (flowJobsDuration?.duration_ms ?? []) as (number | null)[];
let totalMs: number | undefined;
{
let minStart = Infinity;
let maxEnd = -Infinity;
for (let i = 0; i < startedAtArr.length; i++) {
const sa = startedAtArr[i];
const dm = durationMsArr[i];
if (sa != null && dm != null) {
const startMs = new Date(sa).getTime();
minStart = Math.min(minStart, startMs);
maxEnd = Math.max(maxEnd, startMs + dm);
}
}
if (minStart < Infinity && maxEnd > -Infinity) {
totalMs = maxEnd - minStart;
}
}
const durationStr = totalMs != null ? colors.dim(formatDuration(totalMs)) : "";
console.log(` ${icon} ${label} ${durationStr}`);
const flowJobsSuccess = (mod.flow_jobs_success ?? []) as boolean[];
const durationMs = (flowJobsDuration?.duration_ms ?? []) as number[];
for (let iter = 0; iter < flowJobs.length; iter++) {
const iterSuccess = flowJobsSuccess[iter];
const iterIcon = iterSuccess === true ? colors.green("✓")
: iterSuccess === false ? colors.red("✗")
: colors.dim("·");
const iterDur = durationMs[iter] != null ? colors.dim(formatDuration(durationMs[iter])) : "";
const iterDur = durationMsArr[iter] != null ? colors.dim(formatDuration(durationMsArr[iter]!)) : "";
const iterJobId = colors.dim(flowJobs[iter]);
console.log(` ${iterIcon} iteration ${iter} ${iterJobId} ${iterDur}`);
}