UI interaction baselines registry

SSOT for the latency of reusable UI interaction primitives (open a menu, create a tab, focus an input, …) across Koder surfaces, measured as request→painted and compared on the same run against the best-in-class external equivalent (Chrome, GNOME, Tilix, …).

Contract: meta/docs/stack/specs/testing/ui-interaction-perf.kmd. Ratified by meta/docs/stack/rfcs/stack-RFC-012-ui-interaction-perf-corpus.kmd.

This is NOT perf-baseline.md. That file is an append-only log of backend hot-path bench runs keyed by component. This file is a tiered-threshold table keyed by (sdk-component, primitive, surface, target), owner-seeded, ratio-primary, and (from stack-RFC-012 Phase 5) used as a gate. Do not merge the two.

How to read a row

  • ratio = koder_p99 / reference_p99 measured in the *ame run on the

    same machine*— the portable signal (spec R5). when no external equivalent (self-referential primitive).

  • koder p99 / ref p99 = raw tail latency, ms, hardware-tagged. Median

    (p50) lives in the per-run history, not here; this table holds the latest governing p99.

  • tier = ideal / acceptable / unacceptable (spec R6). seed in

    the authority column means the tier is the HCI-prior default, not yet an owner verdict.

  • authority = seed (HCI default), owner (owner verdict — overrides),

    or ref (derived from the measured reference).

  • reference = external software + version + capture date (spec R5).
  • A row with no measurement yet carries tier: seed from the defaults

    below and for the measured columns.

Tier seed defaults (HCI priors — spec R6)

Used to seed every primitive before any measurement or owner verdict, so the corpus is never empty at bootstrap:

Tier Default condition
ideal ratio ≤ 1.2 AND p99 ≤ 100 ms (RAIL "instant")
acceptable 100 ms < p99 ≤ 1 s (Doherty attention bound) → auto-opens perf-debt ticket
unacceptable p99 > 1 s OR ratio > 3

Schema

Column Meaning
date YYYY-MM-DD of the run (UTC).
sdk-component <area>/<sector> that owns the widget (spec R8). product:<path> if hand-rolled (promote-to-sdk finding).
primitive Name from the closed vocabulary (spec R9).
surface flutter-desktop / flutter-mobile / flutter-web / cef-desktop / web / tui.
target OS/runtime tag where relevant (e.g. linux-x11, android).
ratio koder_p99 / ref_p99, or .
koder p99 ms, tail.
ref p99 ms, tail, or .
tier ideal / acceptable / unacceptable.
authority seed / owner / ref.
reference external sw + version + date, or .
hardware one-line hardware tag (raw ms is hardware-bound; ratio is not).
notes perf-debt ticket ref, instrumentation status, follow-ups.

Entries

First real-engine row landed in stack-RFC-012 Phase 2 (KKIT-078): the koder_kit desktop integration harness. Phase 3 adds the Kruze slice.

enginessdkkoder_kit — IDEAL (owner verdict, 2026-06-08)

Measured via the KoderInteractionProbe integration test on the real Flutter Linux engine under xvfb. Self-referential (no external reference → ratio ).

Owner verdict: ideal (2026-06-08), data-backed by the KKIT-086 diagnostic. The koder p99 ms below is integration_test HARNESS OVERHEAD, not app latency. The diagnostic (single-frame pumps + frame count) showed the result paints in frames p501 / max1 — the very next frame after the input (~16 ms, as fast as physically possible). The ~95-150 ms wall-clock is the tester.tap() + live-binding pump cadence floor (~100 ms), NOT render. So the true request→painted latency is 1 frame → genuinely ideal (well under the 100 ms RAIL bar). See spec R4.1 (harness-floor caveat) + KKIT-086.

KKIT-087 (frames-to-paint, all 4 measured): open-menu / focus-input / open-dialog / open-dropdown ALL paint in frames p501 / p991 / max=1 on dev-linux-dek — every primitive responds on the next frame. This is the clean governing metric (R4.1); the ms column is kept only as harness-floor evidence.

date sdk-component primitive surface target ratio koder p99 (ms; harness-floored) frames-to-paint tier authority reference hardware notes
2026-06-08 enginessdkkoder_kit open-menu flutter-desktop linux-x11 113.7 1 ideal owner dev-linux-dek (xvfb) KKIT-079/086. Paints in 1 frame; the 113.7 ms is harness overhead (the earlier 507 ms was the settle-animation, dropped).
2026-06-08 enginessdkkoder_kit focus-input flutter-desktop linux-x11 113.0 1 (measured) ideal owner dev-linux-dek (xvfb) KKIT-084086. Diagnostic measured frames p50=1max=1 — the representative proof the band is harness floor, not latency.
2026-06-08 enginessdkkoder_kit open-dialog flutter-desktop linux-x11 105.8 1 ideal owner dev-linux-dek (xvfb) KKIT-085086. Overlayroute primitive; same 1-frame paint + harness floor.
2026-06-08 enginessdkkoder_kit open-dropdown flutter-desktop linux-x11 133.2 1 ideal owner dev-linux-dek (xvfb) KKIT-085086. Overlayroute primitive; same 1-frame paint + harness floor.
2026-06-08 enginessdkkoder_kit switch-tab flutter-desktop linux-x11 2 ideal seed dev-linux-dek (xvfb) KKIT-088 (Phase 6). Route-push primitive (build incoming page + paint) → 2 frames ≈33ms, well under the 100ms RAIL bar. Measured in an ISOLATED host (the shared corpus Column overflowed the fixed linux window and broke neighbouring overlay primitives). frames p502/p992/max=2 over 20 samples. seed tier pending an owner verdict.
2026-06-08 enginessdkkoder_kit open-popover flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-090 (Phase 6, vocab completion slice 1). MenuAnchor opened by a PRIMARY-tap trigger button (real tap→paint path). frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit open-drawer flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-090. Scaffold drawer via ScaffoldState.openDrawer(). frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit expand-tree-node flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-090. ExpansionTile expand → child first-paint. frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit type-into-input flutter-desktop linux-x11 0 ideal seed dev-linux-dek (xvfb) KKIT-091 (Phase 6, vocab slice 2). TextField reflects input. 0 = tester.enterText pumps once internally so the glyph is painted within the intent (≤1 frame, instant).
2026-06-08 enginessdkkoder_kit open-submenu flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-091. SubmenuButton inside an open MenuAnchor → nested item first-paint. frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit select-dropdown-item flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-091. Picking an item updates the bound value → repaint. frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit close-dialog flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-092. First DISMISSAL primitive. RESPONSIVENESS = structural removal with exit transition OFF: frames p501/p991max=1 (gated). The exit ANIMATION is a separate NON-GATED settle reference: `close-dialogsettle` = p508/p999/max=9 (~150ms designed fade). R2.1 first-response vs settled; D1 don't gate the animation.
2026-06-08 enginessdkkoder_kit new-tab flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-093 (vocab COMPLETE). Stateful tab-manager host; adding a tab paints its view. frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit close-tab flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-093. Dismissal (R2.2); a tab strip has no exit animation so first-response =settle. frames p501/p991/max=1.
2026-06-08 enginessdkkoder_kit tab-switch-view flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-093. IndexedStack swap; find skips offstage so the inactive view "appears" once switched onstage. frames p501/p991max=1. *616 closed vocab now measured on flutter-desktop.*
2026-06-08 enginessdkkoder_kit open-context-menu flutter-desktop linux-x11 1 ideal seed dev-linux-dek (xvfb) KKIT-088 (Phase 6). MenuAnchor opened via MenuController.open() — 1-frame paint = instant. Trigger is programmatic, NOT a synthesised right-click: flutter_test -d linux does not deliver secondary-tap gestures, and the primitive's budget (R8) is the menu RENDER, not gesture recognition (a framework concern). frames p501/p991/max=1 over 20 samples. seed tier pending an owner verdict.

enginessdkkoder_kit — flutter-web (cross-surface, Phase 6 — KKIT-089)

First cross-surface validation (stack-RFC-012 Phase 6's core premise: does the corpus generalise beyond one surface?). The SAME phase6_primitives_perf_test.dart runs on flutter-web (real Chromium 148 browser, flutter drive headless via chromedriver on dev-linux-dek). For flutter-web the metric is still frames-to-paint (the Flutter framework scheduler runs in the browser; the spec's PerformanceObserver is for the NON-Flutter web surface, R3).

Result: All tests passed. on flutter-web — both primitives' perf-golden gates (frames p99 ≤ 3) PASS in the browser, AND the exact frames-to-paint are captured (KKIT-089 closed the precise-measurement gap). The numbers are identical to flutter-desktop: switch-tab = 2 frames, open-context-menu = 1 frame — the same SDK widgets paint in the same frame budget on the browser as on the desktop engine. The corpus generalises with equal numbers, not just an equal verdict.

Extraction seam (the architectural win): flutter drive does NOT relay the browser-side print(), so the harness exports measurements via IntegrationTestWidgetsFlutterBinding.reportData, which the default integrationDriver(responseDataCallback: writeResponseData) writes to build/integration_response_data.json on every surface uniformly — replacing fragile, surface-dependent print-scraping. This seam is reusable by every future driven surface (mobile/tv).

date sdk-component primitive surface target ratio koder p99 frames-to-paint tier authority reference hardware notes
2026-06-08 enginessdkkoder_kit switch-tab flutter-web chromium-148 2 ideal seed dev-linux-dek (chromium headless) KKIT-089. Exact via reportData JSON: p502/p992/max=2 (20 samples). IDENTICAL to flutter-desktop. Gate p99≤3 PASSED.
2026-06-08 enginessdkkoder_kit open-context-menu flutter-web chromium-148 1 ideal seed dev-linux-dek (chromium headless) KKIT-089. Exact via reportData JSON: p501/p991/max=1 (20 samples). IDENTICAL to flutter-desktop. Gate p99≤3 PASSED.

productshorizontalkruze — pending Phase 3 (advisory)

Planned first rows (instrumentation unverified until the CEF OnPaint probe lands — spec R3):

date sdk-component primitive surface target ratio koder p99 ref p99 tier authority reference hardware notes
2026-06-08 product:productshorizontalkruze new-tab cef-desktop linux-x11 ~110-180 ms (coarse) acceptable seed dev-linux-kruze optkruze-seat (cage headless, grim+wtype) kruze#239e MEASURED. Latency ~110-180ms for 2-6 light tabs (grim-coarse, not seconds), then CRASH at ~7 tabs (webview_cef instability). Light tabs UNDERESTIMATE real pain. Root cause = webview/CEF contention under N tabs (eager init), not the new-tab render → fix kruze#240 (lazy webview init).
2026-06-09 enginessdkkoder_kit open-menu flutter-desktop linux-x11 1.0 113.7 1 ideal seed tilix 1f (headless XTEST) dev-linux-dek (xvfb) KKIT-095 /k-mirror D5. Tilix reference via XTEST synth + ffmpeg 60fps frames-to-paint: open-menu p991f over 5 samples. kterm=tilix, both ideal.
2026-06-09 enginessdkkoder_kit new-tab flutter-desktop linux-x11 0.5 1 ideal seed tilix 2f (headless XTEST) dev-linux-dek (xvfb) KKIT-095. Tilix new-tab p99=2f (samples 2,1,1,2,2); kterm 1f → kterm 2x faster. Both ideal (<<100ms RAIL).
2026-06-10 product:productshorizontalkruze new-tab cef-desktop linux-wayland — (self-ref) 192 ms acceptable owner-pending Chromium 1.x measured 2026-06-10 (NOT a meaningful equivalent — see note) dev-linux-kruze optkruze-seat kruze#239c. Self-referential per spec R5 (no meaningful external equivalent): the 239c paired run EMPIRICALLY PROVED Kruze-new-tab and Chromium-new-tab are not equivalent primitives — Chromium’s Ctrl+T paints its full New Tab Page (Google logosearchshortcuts, a heavy web doc) while Kruze paints a light blank tab, so a ratio would compare different work. Raw same-methodsame-host numbers kept as context only: Kruze p50=141p99192 (n19 clean cycles, no crash), Chromium p50479/p99648 (n=20). Honest signal: Kruze’s new-tab primitive is fast (~141ms) AND stable across 19 clean Ctrl+TCtrl+W cycles — the 3rd converging confirmation (after the #239e load curve + crash finding) that the Owner’s “seconds” pain is NOT the new-tab act but webviewCEF contention under N tabs. R6 perf-debt obligation (acceptable tier → must open a fix ticket) is ALREADY DISCHARGED by kruze#240 (hard live-browser ceiling, DONE). Tier acceptable is the seed; owner verdict pending (R6 owner-override). The real-page degradation (heavy tabs UNDERESTIMATED by blank tabs here) + open-context-menu are tracked as the #239 residual, gated_by: evidence-soak on the #227 AV-seat.
product:productshorizontalkruze open-context-menu cef-desktop linux-x11 seed seed Chrome (CDP, version TBD) kruze#239 residual — needs mouse input (Button3); cage seat only has wtype (keyboard), XTEST kills Kruze under sw-XWayland, no network for ydotool/uinput → blocked-by: kruze#227 (AV-seat with mouse).