Skip to content

Implement phase-aware interactive terminal progress and fix activity lifecycle #213

Description

@Teakowa

Goal

Make Wright's interactive terminal provide immediate, truthful, phase-aware feedback for human users, while keeping machine-oriented output deterministic and presentation-free.

Context

#210 / PR #211 introduced the first TUI-lite activity indicator, and PR #216 attempted to refine it. Real-project use after merge shows that the intended interactive behavior is still not implemented.

Current main still behaves as follows:

  • Activity::start() waits 150 ms and then prints the fixed string wright: working…;
  • there is no spinner animation and no workflow phase information such as loading, parsing, semantic resolution, analysis, linting, or emission;
  • run_command() keeps the activity guard alive through present::render(), so final output can still appear on the same live line as the activity text, e.g. wright: working…PASS analyze;
  • the existing cleanup test verifies the escape sequence used to clear a line, but not the end-to-end lifecycle activity → workflow → stop/clear → final render on a TTY.

The original issue wording was too weak: it required only a delayed transient activity state and explicitly discouraged a progress-event abstraction before real evidence existed. Real usage now provides that evidence. Wright's session already has meaningful workflow boundaries such as input resolution, frontend/project loading, parsing, validation/lowering, semantic analysis, lint execution, and emission. The CLI should be able to observe those real phases without coupling terminal text into the driver.

A representative human experience should be closer to:

  ⠹ Loading project…
  ⠸ Parsing 18 files…
  ⠼ Resolving semantics…
  ⠴ Running 12 lint rules…

The exact wording and number of phases should follow real workflow events; do not manufacture fake progress percentages or phases that did not occur.

Scope

Immediate feedback and animation

  • Interactive TTY text commands should show an initial activity/status line immediately when work begins rather than waiting 150 ms before any feedback.
  • Separate initial feedback from animation: a static status may appear immediately, while spinner animation may begin only after a short implementation-level threshold (for example roughly 50–80 ms) to avoid flicker.
  • The animation threshold is presentation behavior, not a public semantic/configuration contract unless later evidence requires configurability.

Phase-aware progress

  • Introduce the smallest transport-neutral progress/observer contract needed for the driver/session to expose truthful workflow phase transitions to interested callers.
  • Keep phase events semantic rather than terminal-specific. The driver must not emit ANSI, spinner frames, or human presentation strings.
  • Use real phases that exist in each workflow. Examples may include input/project loading, parsing, semantic resolution, validation/lowering, analysis, lint-rule execution, and emission.
  • Do not force every command through the same phase list. check, lint, analyze, compile, convert, and inspect should expose only work they actually perform.
  • When real counts are available without expensive duplicate work, progress may include useful bounded metadata such as file count or lint-rule count. Do not invent counts.

Terminal lifecycle

  • Progress/activity must be stopped and its live line fully cleared before final diagnostics, verdicts, reports, or source output are rendered.
  • Fix the current guard lifetime so present::render() cannot run while an interactive activity line is still active.
  • Prefer transient phase output that collapses/clears into a concise final summary rather than permanently leaving several boilerplate progress lines after every successful fast command.

Environment boundaries

  • Apply interactive progress only to human TTY text rendering.
  • --format json, explicit plain rendering, redirected/piped output, non-TTY environments, TERM=dumb, and GitHub Actions must remain static, deterministic, and free of spinner/progress artifacts.
  • Agents and embedding consumers must use structured results/events rather than scrape terminal presentation.

Non-goals

  • Do not build a full-screen TUI or persistent dashboard.
  • Do not add fake percentage progress.
  • Do not introduce terminal presentation concerns into language frontends or semantic owner repositories.
  • Do not redesign analysis semantics in this issue; Redesign analyze as a concise semantic report instead of exhaustive fact dump #214 owns the human analyze report contract.
  • Do not add a broad async/task framework merely to support progress.
  • Do not preserve wright: working… as the long-term activity UX.

Acceptance criteria

  • An interactive TTY receives immediate visible feedback when a workflow starts, including for commands that commonly complete in well under 150 ms.
  • A slower representative workflow visibly transitions through at least two truthful workflow phases before completion.
  • Spinner animation, when used, starts only after a short anti-flicker threshold while the initial status is already visible.
  • Final output is rendered only after the live activity/progress line has been stopped and cleared.
  • No accepted implementation can produce output of the form wright: working…PASS ... or otherwise concatenate transient activity with final output.
  • lint can surface a real lint-execution phase, and workflows with different pipelines do not present fabricated identical phase sequences.
  • Successful completion collapses transient progress into a concise final result instead of permanently retaining every intermediate phase by default.
  • --format json, plain/piped output, CI, GitHub Actions, and non-TTY output contain no ANSI spinner frames or progress text and remain deterministic.
  • Tests include an end-to-end pseudo-TTY/TTY lifecycle case that proves ordering: activity starts → workflow/phase updates occur → activity stops/clears → final render begins.
  • Tests do not merely unit-test the line-clearing escape sequence; they fail if final render occurs while activity is still alive.

Planning notes

Keep the progress contract small and evidence-driven. A callback/observer/event sink owned at the session/orchestration boundary is preferable to coupling the driver to a specific terminal library. The CLI may choose its own lightweight spinner/status implementation.

Use real-project latency as the UX reference: Wright is fast enough that a 150 ms delay often suppresses all feedback, so the design should optimize for immediate responsiveness without introducing visible spinner flicker.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions