docs blog library
github

UI performance qualification

bench/qualify-ui.ts requalifies the exact failing Ink workloads from the 2026-10-01 UI ownership qualification without relaxing any budget or discarding any observation. It exists because the full matched pipeline run and the focused alternating reproduction both fail Ink latency gates, and the focused failures still need tracked phase reproduction before a production fix.

What it measures

  • pipeline mode mounts each checkout’s own Ink fixture (bench/ui-pipeline-fixture.ts + packages/cli/src/ui/store.ts) and measures the two failing shapes — unicode and unbroken 1k chars over 20 seeded turns at 120x40 — with the production renderer scheduling of that checkout. Each delta case reports the first painted delta (one frame) and all 32 steady frames separately. No frame is discarded as warmup, and each row’s summary statistics (total, mean, p50, p95) are derived from the published durations, so a row can never disagree with its own observations.
  • memory mode runs each checkout’s untouched bench/conversation-memory.bench.ts worker with ink 30 short-paragraphs. The unchanged legacy conversation-memory worker keeps its GC, lifetime, source-retention and teardown costs inside the measured child wall time. The legacy checkout keeps its own fixture, so no production compatibility shim is inserted into the comparison.

Both modes run three alternating fresh-process base/head pairs, base first in each pair. Every reported number is the median of the three fresh processes; the report preserves every original observation.

Reproduce

Prepare a matched benchmark baseline for the base checkout with scripts/prepare-benchmark-baseline.ts, which copies the head’s benchmark suites and shared bench helpers into the base revision so both sides measure the same workloads (keeping the base’s original implementation where its source APIs changed). Install the locked dependencies in each checkout, then run the tool from the head checkout:

bun scripts/prepare-benchmark-baseline.ts /path/to/base-checkout /path/to/head-checkout
bun install --frozen-lockfile
(cd /path/to/base-checkout && bun install --frozen-lockfile)
bun bench/qualify-ui.ts pipeline --base /path/to/base-checkout --head /path/to/head-checkout --output /tmp/focused-pipeline
bun bench/qualify-ui.ts memory --base /path/to/base-checkout --head /path/to/head-checkout --output /tmp/focused-memory

The tool writes one report per side, /tmp/focused-pipeline.base.json and /tmp/focused-pipeline.head.json (same for memory), and prints a per-pair summary line. Both sides are validated before either report is written, so a mismatch discovered on one side never publishes a partial report for the other. Each report carries version, samples, mode, side, the runtime identity (platform, arch, bun) and the per-side results rows that feed the existing relative gates:

bun scripts/performance-check.ts /tmp/focused-pipeline.base.json /tmp/focused-pipeline.head.json
bun scripts/performance-check.ts /tmp/focused-memory.base.json /tmp/focused-memory.head.json

base and head must be different directories containing the mode’s fixture files. The tool rejects missing or unknown arguments, non-directory checkouts, missing fixture files, malformed or partial worker JSON, pipeline rows with a wrong name or iteration count, summary statistics that contradict the row’s own published durations, rows whose metrics do not measure the pinned 1k-char, 20-turn workload, mismatched metric key sets across the three samples, and nonzero worker exit statuses before writing any report. Child processes run through argument arrays (no shell interpolation) inside a fresh temporary JAZZ_HOME passed as that variable, with a pinned styled offline environment (FORCE_COLOR=3, NO_COLOR='', JAZZ_OFFLINE=1, JAZZ_DISABLE_KEYRING=1, JAZZ_UI_GLYPHS=unicode) that is released on success and failure.

Partial-workload limits

The tool measures only the four focused pipeline rows (unicode and unbroken, first and steady) and the single focused memory row. It is a focused reproduction, not the full suite: it does not cover the 10k/50k pipeline cases, prose shapes, OpenTUI, buffer/pacing/resize rows, or the full conversation-memory matrix. Absolute budgets for those remain enforced by bun scripts/performance-check.ts --absolute over a complete bench/run.ts report. The focused reports therefore establish relative behavior of the failing workloads only; they do not establish that CI passes or that the original user freeze persists.

Original failing qualification evidence

The 2026-10-01 run (macOS ARM64, Bun 1.4.2, offline synthetic fixtures, styled output) is preserved at bench/results/ui-ownership-2026-10-01/ (the write-up is tracked at bench/reports/ui-ownership-2026-10-01/qualification.md; the raw per-run JSONs stay local), which records the corrected pipeline comparison (fail, 3 metric gates), the earlier memory lifetime comparison (fail, Ink30 p50/p95) and the focused Ink30 lifetime comparison (pass), with links to every archived base/head report.

Tests and checks

The tool’s pure surface — CLI parsing, malformed or partial worker payloads, incoherent summary statistics, misnamed or miscounted pipeline rows, and unequal, duplicated or missing result samples — is covered by bench/qualify-ui.test.ts, which needs no checkout directory and spawns no worker process. The real parent CLI and worker dispatch are covered by bench/qualify-ui.integration.test.ts, which runs the actual runner against synthetic checkouts for three alternating pairs and asserts the complete four-row protocol, forced styled environment, isolated temporary JAZZ_HOME values, cleanup and failure behavior:

bun test bench/qualify-ui.test.ts bench/qualify-ui.integration.test.ts

The owned benchmark files lint under the shared bench/** configuration:

bun eslint bench/qualify-ui.ts bench/qualify-ui.test.ts --no-error-on-unmatched-pattern

This guide’s format is checked by the repo markdownlint configuration:

bunx markdownlint-cli2 docs/maintainers/ui-performance-qualification.md

machine-readable: /docs/maintainers/ui-performance-qualification.md · /llms.txt · /llms-full.txt