Skip to content

fix: bound TUI transcript rendering - #3386

Merged
breznknecht merged 1 commit into
mainfrom
codex/issue-3309-bounded-transcript-render
Sep 16, 2026
Merged

breznknecht merged 1 commit into
mainfrom
codex/issue-3309-bounded-transcript-render

Conversation

@jsmestad

Copy link
Copy Markdown
Owner

TL;DR

Reading older TUI chat now stays responsive as the transcript grows. The TUI renders only the visible viewport plus bounded overscan, preserves the reader's local anchor across transcript changes, and retains styled rows within explicit row and byte caps.

Closes #3309

Context

The unpinned transcript path previously laid out and styled every resident message during each update. An unchanged 10,000-message transcript took about 731 ms per production Update plus View sample on the benchmark machine, even when the reader only needed one viewport.

This change keeps semantic messages authoritative while moving viewport navigation and disposable paint data into focused TUI owners. It does not change transcript storage, wire identity, or the remaining #2715 responsibilities.

Changes

  • Replace the global rendered-line offset with transcript-owned message slots and row anchors. Reconcile anchors across trim, suffix updates, same-epoch replacement, epoch changes, duplicate IDs, and zero IDs.
  • Add viewport traversal that visits only visible messages plus finite overscan. A row-range renderer keeps one large message from materializing its complete styled output.
  • Add a renderer-owned 32-row chunk cache with LRU eviction, one active width/theme generation, a four-viewport row cap, and a 1 MiB byte cap.
  • Bypass static cache entries for visible animation and invalidate only the affected content revision for streaming or collapse changes.
  • Add deterministic work counters, exact output comparisons against the bounded legacy oracle, temporal regression tests, production-path benchmarks, and raw benchmark receipts.

Verification

  • go test ./...
  • mix protocol.gen --check
  • mix conformance: 162 passed
  • make lint: Credo, Dialyzer, duplication, architecture policy, and fast lint passed
  • Focused bug review: found and fixed duplicate-ID anchor reassignment, quadratic zero-ID replacement matching, and a divergent legacy animation scanner; targeted re-review passed
  • Final acceptance review: passed with no blockers, warnings, or missing criteria

The reproducible benchmark source and all raw outputs are in docs/performance/issue-3309/.

Scenario Base mean Head mean Base p95 Head p95 Base allocations Head allocations
10,000 messages, reading older chat 731.045 ms 2.864 ms 786.460 ms 3.010 ms 7,684,079 28,709
10,000 messages, following bottom 4.278 ms 3.082 ms 6.665 ms 4.747 ms 30,048 28,711

The unpinned 10,000-message mean improved by 255x. Pinned p95 improved by 28.8%, and pinned allocations fell by 4.4%.

Acceptance Criteria Addressed

  1. Warm unchanged updates and local scrolling render only the viewport plus finite overscan, independent of resident transcript size. ✅
  2. Offscreen streaming preserves the reader's anchor without rerendering unchanged offscreen messages; visible streaming, animation, collapse, theme, and width changes remain exact. ✅
  3. Layout metadata remains proportional to resident messages, and retained styled output obeys explicit row and byte caps. ✅
  4. Trim, suffix replacement, same-epoch full replacement, epoch changes, duplicate and zero IDs, empty transcripts, and pin transitions preserve the specified behavior. ✅
  5. Production Update plus View benchmarks, deterministic counters, raw receipts, and exact oracle comparisons demonstrate the new bound. ✅

@breznknecht
breznknecht force-pushed the codex/issue-3309-bounded-transcript-render branch from b6bdfee to b7a046d Compare September 16, 2026 14:19
@breznknecht
breznknecht merged commit 8457484 into main Sep 16, 2026
11 checks passed
@breznknecht
breznknecht deleted the codex/issue-3309-bounded-transcript-render branch September 16, 2026 14:31
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.

Reading older TUI chat stays responsive as the transcript grows

2 participants