Skip to content

feat(check): live progress TUI for multi check via PresenterActor (MULTI-1369)#146

Open
RobbieMcKinstry wants to merge 1 commit into
trunkfrom
robbie/multi-1369
Open

feat(check): live progress TUI for multi check via PresenterActor (MULTI-1369)#146
RobbieMcKinstry wants to merge 1 commit into
trunkfrom
robbie/multi-1369

Conversation

@RobbieMcKinstry

Copy link
Copy Markdown
Contributor

Surface what multi check is doing while it runs. A fourth, display-only
Kameo actor (PresenterActor) consumes a fire-and-forget UiEvent stream
emitted by the discovery/execution pipeline at each per-check milestone
(queued → started → retrying → settled) and renders progress through a
RenderBackend chosen at spawn from whether stdout is a TTY:

  • InlineTuiBackend (TTY): a Ratatui inline viewport — a requirement→check
    tree + progress gauge with per-check spinners and climbing elapsed timers
    (the liveness signal). Completed requirements flush into permanent scrollback
    via insert_before as they finish, so the viewport only holds in-flight work
    and the full record persists by end-of-run with no separate reprint. Never
    uses the alternate screen.
  • HeartbeatBackend (non-TTY): a slow-cadence one-line progress heartbeat on
    stderr so piped/CI runs show liveness. stdout is left untouched — the
    reporting actor's byte-for-byte report and 0/1 exit code are preserved exactly
    as MULTI-1368.
  • NullBackend / RecordingBackend (tests): headless.

Events are a concrete enum (exhaustiveness, one Message impl, no per-message
boxing); polymorphism lives on the backend. A separate periodic Tick drives
redraws so animations keep moving between events. The presenter holds a single
PresenterState view-model with from-scratch tally scans (retry-safe), and the
flushed TTY record reuses the reporting actor's exact text + AND-aggregation, so
the TTY scrollback and non-TTY stdout differ only in inter-requirement order
(completion vs declaration), never per-requirement content.

Terminal restore is covered on all four paths: on_stop (normal/error), a panic
hook (panic), and an async-signal-safe SIGINT handler (Ctrl-C) that shows the
cursor and exits 130. The redraw ticker is owned by the actor and joined on stop.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

…MULTI-1369)

Surface what `multi check` is doing *while it runs*. A fourth, display-only
Kameo actor (`PresenterActor`) consumes a fire-and-forget `UiEvent` stream
emitted by the discovery/execution pipeline at each per-check milestone
(queued → started → retrying → settled) and renders progress through a
`RenderBackend` chosen at spawn from whether stdout is a TTY:

- `InlineTuiBackend` (TTY): a Ratatui inline viewport — a requirement→check
  tree + progress gauge with per-check spinners and climbing elapsed timers
  (the liveness signal). Completed requirements flush into permanent scrollback
  via `insert_before` as they finish, so the viewport only holds in-flight work
  and the full record persists by end-of-run with no separate reprint. Never
  uses the alternate screen.
- `HeartbeatBackend` (non-TTY): a slow-cadence one-line progress heartbeat on
  stderr so piped/CI runs show liveness. stdout is left untouched — the
  reporting actor's byte-for-byte report and 0/1 exit code are preserved exactly
  as MULTI-1368.
- `NullBackend` / `RecordingBackend` (tests): headless.

Events are a concrete enum (exhaustiveness, one `Message` impl, no per-message
boxing); polymorphism lives on the backend. A separate periodic `Tick` drives
redraws so animations keep moving between events. The presenter holds a single
`PresenterState` view-model with from-scratch tally scans (retry-safe), and the
flushed TTY record reuses the reporting actor's exact text + AND-aggregation, so
the TTY scrollback and non-TTY stdout differ only in inter-requirement order
(completion vs declaration), never per-requirement content.

Terminal restore is covered on all four paths: `on_stop` (normal/error), a panic
hook (panic), and an async-signal-safe SIGINT handler (Ctrl-C) that shows the
cursor and exits 130. The redraw ticker is owned by the actor and joined on stop.

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