Skip to content

fix: restore run TUI elapsed timer across retry, failure, cancel, and remote paths#1

Open
MatheusBBarni wants to merge 4 commits into
mainfrom
fix/tui-retry-success-timer
Open

fix: restore run TUI elapsed timer across retry, failure, cancel, and remote paths#1
MatheusBBarni wants to merge 4 commits into
mainfrom
fix/tui-retry-success-timer

Conversation

@MatheusBBarni

Copy link
Copy Markdown
Owner

Summary

Fixes the run TUI bug where the elapsed timer disappears after a retried job succeeds — and completes the fix so the timer is correct for every terminal outcome (success, failure, cancel) and for remote tabs that attach after a job already finished.

Root cause: the UI derived a job's elapsed time from a locally-tracked startedAt that the retry flow never seeds (retry attempts emit no fresh JobStarted, and a remote tab can bootstrap a job mid-retry), while discarding the authoritative duration the executor already computes.

What changed

Core fix (e6d1214) — thread the executor's authoritative JobCompletedPayload.DurationMs into the UI:

  • jobFinishedMsg gains DurationMs; translateJobCompletedEvent carries it; handleJobFinished prefers it and backfills startedAt for triple-coherence.

Completion across all terminal outcomes (4cbce91) — no persistence/schema migration required:

  • Part A (live failure/cancel): DurationMs added to JobFailedPayload/JobCancelledPayload, populated in executor/lifecycle.go via a zero-guarded elapsedMs() (guard matters: markGiveUp/markCanceled can fire before any attempt starts), threaded through the failure and cancel UI translators.
  • Part B (remote pre-attach): DurationMs added to the RunJobSummary contract; the daemon snapshot builder populates it from the authoritative payload with a JobStarted → terminal timestamp fallback for historical journals; remote.go threads it into all three terminal bootstrap arms.

Why this altitude

Duration was only carried on the live JobCompleted event. Generalizing it to all terminal payloads + the remote summary contract fixes the whole class (blank timer on retry→failure/cancel; ~00:00 on remote pre-attach) instead of special-casing the success arm.

Testing

  • gofmt -s: clean · go build ./...: OK · golangci-lint (5 packages): 0 issues
  • go test -race: pkg/compozy/events/kinds, internal/core/run/ui, internal/core/run/executor, internal/daemon, internal/api/contract — all pass
  • New tests: executor terminal-duration (failed/canceled/zero-guard), UI translator threading (failure + cancel), remote bootstrap threading (all 3 arms), daemon resolveDurationMs (payload-wins / timestamp-fallback / no-start), plus a translator guard and reproduction test in the core fix.

🤖 Generated with Claude Code

MatheusBBarni and others added 2 commits July 1, 2026 16:36
Thread the executor's authoritative JobCompletedPayload.DurationMs through
jobFinishedMsg into handleJobFinished, which previously derived elapsed time
from a startedAt that the retry flow never seeds (retry attempts emit no
JobStarted; a remote tab can bootstrap a job mid-retry). The sidebar timer no
longer stays blank after a retried job completes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e jobs

Complete the retry-timer fix across every terminal outcome. Add DurationMs to
JobFailedPayload/JobCancelledPayload and populate it in the executor
(markGiveUp/markCanceled, zero-guarded when no attempt started), thread it
through the failure and cancel UI translators, and add DurationMs to the
RunJobSummary contract populated by the daemon snapshot builder (authoritative
payload value with a JobStarted->terminal timestamp fallback for historical
journals). The remote bootstrap threads it into every terminal arm, so a tab
attaching to a job that finished before attach shows the real elapsed time
instead of a bogus ~00:00. No persistence/schema migration required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

MatheusBBarni and others added 2 commits July 2, 2026 03:37
Addresses PR review: rename the TestJobLifecycleTerminalEventsCarryDuration and
TestRunSnapshotJobResolveDurationMs subtests to the repo's Should-prefixed
convention and mark the independent lifecycle subtests t.Parallel().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses the remaining CodeRabbit review comment: the two
TestTranslateEvent*ThreadsDuration cases now run inside a Should-prefixed
t.Run subtest, matching the ui package's dominant convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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