From c98d856d9e0697f021ed9d0a1e28e1e0909d1b52 Mon Sep 17 00:00:00 2001 From: Chris Tonkinson Date: Sat, 14 Feb 2026 14:54:07 -0500 Subject: [PATCH] Fix #3 The `gov why` command was incorrectly showing tasks with historical failures even after they had successfully completed. This was caused by the `whyTaskKind()` function checking `task.Attempts.Failed > 0`, which matches any task that has ever failed, regardless of its current state. Root cause: - When `gov stop -w` kills a worker, `Attempts.Failed` is incremented - The task transitions to `blocked` state - When the task is resumed and completes successfully, it transitions to success states (merged, etc.) but `Attempts.Failed` remains > 0 - The `gov why` command would still show the task because of the historical failure count Fix: - Removed the `Attempts.Failed > 0` check from `whyTaskKind()` - Tasks in `TaskStateBlocked` are still shown (currently blocked/failing) - Planning tasks that caused supervisor failure are still shown - Historical failures no longer cause completed tasks to appear in output This preserves the `Attempts.Failed` counter for observability while fixing the display issue. Co-Authored-By: Claude Sonnet 4.5 --- main.go | 3 --- main_test.go | 12 +++++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index 7cb1db6..4153542 100644 --- a/main.go +++ b/main.go @@ -1099,9 +1099,6 @@ func whyTaskKind(task index.Task, supervisorState supervisor.SupervisorStateInfo if task.State == index.TaskStateBlocked { return "blocked" } - if task.Attempts.Failed > 0 { - return "failed" - } if task.Kind == index.TaskKindPlanning && hasSupervisorState && supervisorState.State == supervisor.SupervisorStateFailed && diff --git a/main_test.go b/main_test.go index f53099f..52329e6 100644 --- a/main_test.go +++ b/main_test.go @@ -745,7 +745,8 @@ func TestWhyCommand(t *testing.T) { "id": %q, "path": "_governator/tasks/%s.md", "kind": "execution", - "state": "triaged", + "state": "blocked", + "blocked_reason": "worker failed", "role": "default", "dependencies": [], "retries": {"max_attempts": 2}, @@ -816,7 +817,7 @@ func TestWhyCommand(t *testing.T) { got := string(output) if strings.Count(got, "=== ") != 3 { - t.Fatalf("expected exactly 3 sections (supervisor + blocked + failed), got output:\n%s", got) + t.Fatalf("expected exactly 3 sections (supervisor + 2 blocked tasks), got output:\n%s", got) } if !strings.Contains(got, "=== Supervisor 0 (unknown) last 2 lines ===\nline-29\nline-30\n") { t.Fatalf("missing supervisor section in output:\n%s", got) @@ -824,8 +825,8 @@ func TestWhyCommand(t *testing.T) { if !strings.Contains(got, "=== Task "+blockedID+" (blocked) last 3 lines from _governator/_local-state/task-"+blockedID+"/_governator/_local-state/worker-2-work-default/stdout.log ===\nnew-2\nnew-3\nnew-4\n") { t.Fatalf("missing blocked section with most recent stdout log in output:\n%s", got) } - if !strings.Contains(got, "=== Task "+failedID+" (failed) last 3 lines from _governator/_local-state/task-"+failedID+"/_governator/_local-state/worker-1-test-default/stdout.log ===\nf-1\nf-2\nf-3\n") { - t.Fatalf("missing failed section in output:\n%s", got) + if !strings.Contains(got, "=== Task "+failedID+" (blocked) last 3 lines from _governator/_local-state/task-"+failedID+"/_governator/_local-state/worker-1-test-default/stdout.log ===\nf-1\nf-2\nf-3\n") { + t.Fatalf("missing second blocked section in output:\n%s", got) } if strings.Contains(got, openID) { t.Fatalf("unexpected open task section in output:\n%s", got) @@ -908,7 +909,8 @@ func TestWhyCommand(t *testing.T) { "id": "T-ERR-001", "path": "_governator/tasks/T-ERR-001.md", "kind": "execution", - "state": "triaged", + "state": "blocked", + "blocked_reason": "worker failed", "role": "default", "dependencies": [], "retries": {"max_attempts": 1},