Skip to content

fix(cli): stats never hides a failed task behind a cancelled sibling - #1213

Merged
aviggiano merged 1 commit into
mainfrom
claude/fup-stats-failed-task-without-state
Sep 29, 2026
Merged

aviggiano merged 1 commit into
mainfrom
claude/fup-stats-failed-task-without-state

Conversation

@aviggiano

@aviggiano aviggiano commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #1200, from Greptile's P1 on #1200.

Problem

stats reports a failed node as canceled when Smithers cancelled every failed task of it (#1087, #1200). workflowCancelled in packages/cli/src/run-statistics.ts used a missing Smithers state as the mark of a fan-out aggregate record. So it also skipped a failed task record without a state. For a fan-out node with one cancelled task and one failed task without a state, it saw only cancelled and reported the node canceled. The failure disappeared from totals.status_counts, which contradicts docs/reference/cli.md ("When Smithers cancelled every failed task of a node").

A triage of the finding found no writer on main, or in past releases, that records a failed task without a state. So this fixes the rule, not an observed run.

Change

  • Skip only records that carry aggregate_attempt_statuses (the fan-out aggregate).
  • Count any other failed record without a Smithers state as "not cancelled", so the node stays failed.
  • The rule now names the aggregate explicitly instead of inferring it from a missing field. The function stays the same size.

Verification

  • stats counts a failed node whose task Smithers cancelled as canceled gains the mixed case: a cancelled task plus a failed task without a state. On origin/main it fails with actual: ['canceled', 0, 1], expected: ['failed', 1, 0]. It passes here.
  • run-statistics.test.ts: 18/18.
  • prettier, eslint, lint:strict:ci and CLI tsc --noEmit pass.

Risk

A failed record without a state or provenance that is not an aggregate now keeps its node failed, as the documentation says. The only records skipped are aggregates, and they always carry aggregate_attempt_statuses (required by the run-state schema).

🤖 Generated with Claude Code

RetriggerConfidence Score: 5/5

The PR appears safe to merge.

Summary

The PR changes stats to exclude fan-out aggregate records explicitly when deciding whether Smithers canceled every failed task. It adds a mixed canceled/stateless-failure test and documents the correction in the changelog.

Reviews (1) · Last reviewed commit: "fix(cli): stats never hides a failed tas..."

workflowCancelled treated a missing Smithers state as the mark of a
fan-out aggregate, so it also skipped a failed task record that had no
state. A fan-out node with one cancelled task and one such failed task
was then reported canceled, and the failure dropped out of
totals.status_counts. That contradicts the documented rule that a node
is canceled only when Smithers cancelled every failed task of it.

Skip only records that carry aggregate_attempt_statuses, and count any
other failed record without a state as not cancelled. No writer on main
produces such a task record today (Greptile, on #1200), so this is a
correctness fix for the rule rather than for an observed run.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@aviggiano
aviggiano requested a review from a team as a code owner September 29, 2026 14:43
@aviggiano
aviggiano merged commit 7728e7b into main Sep 29, 2026
17 checks passed
@aviggiano
aviggiano deleted the claude/fup-stats-failed-task-without-state branch September 29, 2026 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant