# Native TUI Playback Regression Tests

Use `tests/coding/native_tui_playback.py` when a native TUI change can affect terminal behavior, not just pure component rendering.

Good candidates include:

- composer input echo
- Working timer frames
- streaming updates
- completion open and close
- overlay and surface interactions
- viewport or cursor positioning
- long transcript resume behavior
- product-composed interactions that combine transcript, running state,
  pending queues, surfaces, completion, and composer selection
- streaming product control flows that combine long transcripts, live assistant
  draft, follow-up queueing, steering, resize, surfaces, and abort

Prefer focused component tests for pure rendering functions. Use the playback harness when the test needs a `NativeCodingTuiApp`, `TuiRuntime`, and `FakeTerminalPort` together.

Useful assertions:

- `assert_no_clear(step)` for no `clear_screen` and no `clear_scrollback`
- `assert_operation_class(step, "...")` for differential update expectations
- `assert_visible_contains(text)` and `assert_visible_not_contains(text)` for visible terminal output
- `assert_cursor_matches_diagnostics(step)` when cursor anchoring is part of the behavior
- `assert_last_cursor_on_visible_line(text, column=n)` when a long transcript
  makes logical cursor rows differ from visible screen rows

Avoid broad snapshot-only tests. Prefer targeted assertions on terminal operations, diagnostics, visible text, and cursor/viewport invariants.

JSONL traces include `logical_cursor`, `viewport`, `hardware_cursor`, and
`screen_cursor`. Use `screen_cursor` for the fake terminal's final physical
cursor position, and keep `logical_cursor`/`viewport` for diagnosing render-loop
line mapping.

If a playback scenario fails after producing a `PlaybackResult`, attach that
result to the `AssertionError` as `playback_result`. The scenario runner will
write the normal error file plus the JSONL trace and final screen artifact, so
reviewers can inspect the last frames without rerunning the scenario locally.

Useful direct smoke commands:

```bash
uv --cache-dir .uv-cache run --extra dev python -m loushang.coding.ui.playback_runner composer-selection-stress --artifacts /tmp/loushang-selection-playback --include-frames
uv --cache-dir .uv-cache run --extra dev python -m loushang.coding.ui.playback_runner product-composed-interaction --artifacts /tmp/loushang-product-playback --include-frames
uv --cache-dir .uv-cache run --extra dev python -m loushang.coding.ui.playback_runner product-streaming-control-flow --artifacts /tmp/loushang-product-streaming-playback --include-frames
```

For a public, product-neutral playback example, see
`examples/tui/42_playback_smoke.py`.
