Skip to content

perf(web): pack terminal snapshot rows in WASM - #17188

Open
StiensWout wants to merge 1 commit into
pingdotgg:mainfrom
StiensWout:t3/terminal-packed-wasm-rows
Open

StiensWout wants to merge 1 commit into
pingdotgg:mainfrom
StiensWout:t3/terminal-packed-wasm-rows

Conversation

@StiensWout

Copy link
Copy Markdown
Contributor

Terminal snapshots cross the JS/WASM boundary once per cell, which makes large grids expensive. Pack each changed row in WASM and decode its cells and graphemes in one pass, retaining the existing row cache.

A 120×40 Node benchmark measured full snapshots at 7.15–7.95 ms on main, 4.05–4.53 ms with #17091, and 1.31–1.38 ms here. This measures snapshot work, not browser FPS. The binary grows by 1,037 bytes. #17091's navigation changes remain separate.

Verified 31 focused tests, web typecheck, scoped lint, differential parity, and two independent reviews. Mac Chrome checked ANSI, Unicode, wrapping, alternate screen, scrolling, selection, and split-pane resizing. Desktop shares this renderer; the Electron shell was not tested.

Before

Before

After

After

Scroll, selection, and split-pane verification is an action sequence, not a frame-rate recording.

Prepared for Wout by gpt-6.1-sol in the Codex harness, with delegated GPT and Claude reviews.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 8, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This change replaces the shipped terminal snapshot marshalling path with a new C/WASM packing ABI, updated build integration, and shared-memory allocation protocol. Its intended output is compatible and well tested, but the cross-language runtime refactor affects every terminal snapshot and warrants human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2fb6486c-4037-4c60-8fe3-217664f3b487
📥 Commits

Reviewing files that changed from the base of the PR and between a4c9494 and 96642fc.

⛔ Files ignored due to path filters (1)
  • apps/web/src/terminal/ghostty/vendor/ghostty-vt.wasm is excluded by !**/*.wasm
📒 Files selected for processing (4)
  • apps/web/scripts/build-libghostty-wasm.sh
  • apps/web/scripts/ghostty-pack-row.c
  • apps/web/src/terminal/ghostty/core.test.ts
  • apps/web/src/terminal/ghostty/core.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The browser WASM build now exports a Ghostty row-packing helper. The terminal core uses its packed output to decode rows. Tests cover graphemes, memory growth, resizing, and dirty-row behavior.

Changes

Packed Ghostty row decoding

Layer / File(s) Summary
Add and build the row-packing export
apps/web/scripts/ghostty-pack-row.c, apps/web/scripts/build-libghostty-wasm.sh
The C helper serializes row flags, cell records, and grapheme data. The build script adds the helper and export to a temporary Ghostty checkout, then copies the WASM output from its out/bin directory.
Decode packed rows in the terminal core
apps/web/src/terminal/ghostty/core.ts, apps/web/src/terminal/ghostty/core.test.ts
The core allocates packed-row storage, retries when the buffer is too small, and decodes cell and row data. Tests cover long graphemes, memory growth, resizing, and dirty-row updates.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant Core as GhosttyTerminalCore
  participant Pack as t3_ghostty_pack_row
  participant API as Ghostty API
  Core->>Pack: Pass row, cells, columns, and output buffer
  Pack->>API: Read row flags and cell data
  API-->>Pack: Return row and cell values
  Pack-->>Core: Return packed row data
Loading

Suggested reviewers: t3dotgg

Merge Risk: ⚪ Minimal · up to 96642

This change speeds up terminal snapshot decoding by packing rows in WASM. The review found no concrete defect, and the buffer retry and memory-growth paths are covered by tests.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 96642

The change is confined to terminal rendering and retains buffer ownership and size checks. The new row format requires the application and its binary to remain compatible. No introduced security concern was established, but deployed behavior was not independently verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — Terminal cores use a cached shared WASM runtime, but each core owns its packed-row allocation and cleanup. Consequently, buffer correctness matters within the shared client memory boundary, not just for an isolated row object.

Trust Boundaries and Controls

  • inferred — Attacker-influenced terminal text can affect grapheme content and packed size, but the existing terminal path does not let it choose output pointers, capacities, or serialized offsets directly. The producer writes records only when the required size fits capacity and checks grapheme arithmetic overflow. Unsigned 16-bit caller dimensions keep the initial cell-record calculation within range.

Resilience and Maintainability Implications

  • inferred — A packing, decoding, or allocation exception does not publish the current row or clear its dirty flag. Earlier successfully decoded rows may remain cached, while global dirty reset is skipped if the loop fails. Out-of-space handling retries using the producer-reported size and reacquires the row’s cell traversal.

Hardening Proposals

  • proposed — A versioned layout handshake or shared layout definition could make future producer/decoder drift fail explicitly before interpreting offsets into shared memory. This is preventive hardening, not an established PR vulnerability.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, conventional, and clearly identifies the main change: packing terminal snapshot rows in WASM for web performance.
Description check ✅ Passed The description clearly explains the problem, implementation, performance results, verification steps, test coverage, platform limits, and UI evidence. It does not explicitly provide the required scop…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant