Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Subprocess Mode** - Removed the experimental subprocess execution mode (`experimental.subprocess_mode`), including the `internal/streamjson/` package, `subprocessFactory`, and all related config/TUI/wiring plumbing. Pipeline instances now always use the tmux-based execution backend.

### Fixed
- **Pipeline Execution Count Exceeds Total** - Fixed `exec 3/2` display bug where the task done count exceeded the total count. `UpdateTeamCompleted` overwrote `TasksDone`/`TasksFailed` with backend-authoritative values but left `TasksTotal` at the stale incremental count from bridge start events. Now reconciles `TasksTotal` and clears `ActiveTasks` on team completion.
- **Ultraplan h/l Navigation Reversed** - Fixed `h` and `l` keybindings navigating in the opposite visual direction in ultraplan mode with groups. Navigation used plan-execution order (`getNavigableInstances`) while the sidebar rendered in group-structure order (`FlattenGroupsForDisplay`), causing the two orderings to diverge. Navigation now follows the visual display order filtered to navigable instances.
- **Silent Plan Validation Failure** - Fixed `handlePlanFileCheckResult` silently swallowing `SetPlan` errors, leaving users stuck in a session that would never progress. Now sets an error message and transitions to `PhaseFailed`, matching the identical error handling in `handlePlanParsed`.
- **Missing Sentinel File in Pipeline Execution** - Fixed task instances not writing `.claudio-task-complete.json` in the Orchestration 2.0 pipeline path. The bridge's `BuildTaskPrompt` relied solely on `--append-system-prompt-file` to inject the completion protocol, which left instances unaware of the sentinel file convention. The completion protocol is now embedded directly in the task prompt as defense-in-depth.
Expand Down
6 changes: 2 additions & 4 deletions internal/tui/view/pipeline_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ var (

// TeamSnapshot holds a point-in-time snapshot of a team's status.
// This is a TUI-local type with no backend imports.
//
// TasksTotal is an incremental count from bridge start events and may diverge
// from TasksDone+TasksFailed after UpdateTeamCompleted, which overwrites
// TasksDone/TasksFailed with backend-authoritative final counts.
type TeamSnapshot struct {
ID string
Name string
Expand Down Expand Up @@ -117,6 +113,8 @@ func (p *PipelineState) UpdateTeamCompleted(teamID, teamName string, success boo
}
p.Teams[i].TasksDone = tasksDone
p.Teams[i].TasksFailed = tasksFailed
p.Teams[i].TasksTotal = tasksDone + tasksFailed
p.Teams[i].ActiveTasks = 0
if teamName != "" {
p.Teams[i].Name = teamName
}
Expand Down
34 changes: 34 additions & 0 deletions internal/tui/view/pipeline_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,24 @@ func TestPipelineState_UpdateTeamCompleted(t *testing.T) {
}
})

t.Run("reconciles TasksTotal with backend counts", func(t *testing.T) {
p := &PipelineState{
Phase: "execution",
Teams: []TeamSnapshot{{
ID: "t1", Phase: "working",
TasksDone: 1, TasksTotal: 2, ActiveTasks: 1,
}},
}
// Backend reports 3 done — more than bridge tracked starts
p.UpdateTeamCompleted("t1", "", true, 3, 0)
if p.Teams[0].TasksTotal != 3 {
t.Errorf("TasksTotal = %d, want %d (should reconcile with backend)", p.Teams[0].TasksTotal, 3)
}
if p.Teams[0].ActiveTasks != 0 {
t.Errorf("ActiveTasks = %d, want 0 (team is done)", p.Teams[0].ActiveTasks)
}
})

t.Run("nil safety", func(t *testing.T) {
var p *PipelineState
p.UpdateTeamCompleted("t1", "n", true, 1, 0) // should not panic
Expand Down Expand Up @@ -341,6 +359,22 @@ func TestPipelineState_GetIndicator(t *testing.T) {
}
})

t.Run("execution label after team completion reconciles counts", func(t *testing.T) {
p := &PipelineState{
Phase: "execution",
Teams: []TeamSnapshot{{ID: "t1", Phase: "working", TasksTotal: 2}},
}
// Simulate backend reporting more tasks than bridge tracked
p.UpdateTeamCompleted("t1", "", true, 3, 0)
ind := p.GetIndicator()
if ind == nil {
t.Fatal("GetIndicator() = nil, want non-nil")
}
if ind.Label != "exec 3/3" {
t.Errorf("Label = %q, want %q (done should never exceed total)", ind.Label, "exec 3/3")
}
})

t.Run("execution phase without tasks shows team count", func(t *testing.T) {
p := &PipelineState{
Phase: "execution",
Expand Down
Loading