Make the Rust client the sole app

This commit is contained in:
iris committed 2026-09-11 01:18:24 -04:00
1 parent a8602c1626
commit d8bb1699a8
230 files changed
+762 -27300

No files matched your search

+10 -14
View File
@@ -1,16 +1,13 @@
# The P0 benchmark fixture
`transcript.jsonl` is a synthetic transcript in the app's own event model (the JSON lines
`GET /sessions/{id}/transcript` returns; see `Events.kt`'s `parseSeqEvent` and
`server/src/session/driver.rs`) -- never a real one. It is what both the Compose `bench` build
and iris's bench build open with no server, so the two apps draw exactly the same content and a
frame-time comparison is measuring the renderer rather than the data.
`transcript.jsonl` is a synthetic transcript in the app's event model (the JSON lines
`GET /sessions/{id}/transcript` returns; see `event-model` and
`server/src/session/driver.rs`) -- never a real one. The `bench` build opens it without a
server so renderer measurements use deterministic data.
Generated by `./generate.py` (Python stdlib only, seeded -- `SEED = 20260905` -- so re-running it
reproduces the same file byte for byte). It writes into `assets/` -- a separate directory from this
script and README, because the Compose `bench` build type points its own asset source set straight
at `assets/` (`app/androidApp/build.gradle.kts`'s `sourceSets { getByName("bench") }`), and a Python
script and a markdown file have no business inside an APK:
reproduces the same file byte for byte). It writes into `assets/`; only those generated assets are
embedded in the benchmark APK.
- `transcript.jsonl` -- 3,603 events. The first 3,202 (`BACKLOG_COUNT`) are the scrolled-back
history the benchmark opens with: user turns, tool calls with kilobyte-scale input/output,
@@ -31,7 +28,7 @@ script and a markdown file have no business inside an APK:
**The run-on message is kept**, as the first two events of the backlog: 14,824 characters in a
single block, just under `text_cap`'s 16 KiB `MESSAGE_BYTES` so it draws in full rather than
behind a "Show all". It is deliberately *not* streamed -- the repeated-reshape pathology needs a
growing block, and that lives in `app-rust/tests/frame_profile.rs` where it can be iterated on
growing block, and that lives in the UI profiling rig where it can be iterated on
in a second rather than in a two-minute phone run. It is emitted with the random state saved and
restored around it, so adding it left every other backlog event byte-identical; that is what
keeps `phone_screen.rs`'s recorded gestures landing on the content they were recorded against.
@@ -39,10 +36,9 @@ script and a markdown file have no business inside an APK:
same way a real attachment is (`GET /sessions/{id}/files/{name}`), referenced by the two
`"type":"image"` events in the transcript.
`BACKLOG_COUNT` lives in three places and moves in all of them or none: here, `app-rust/src/ui/
fixture.rs` and `BenchFixture.kt`. The split is by line index, so a stale copy makes that app open
a different half of the file.
`BACKLOG_COUNT` lives here, in `generate.py`, and in `app/src/ui/fixture.rs`; change all three
together. The split is by line index.
Regenerate after changing the shape (a new event type, a different backlog/stream split) with
`./generate.py`, and commit the result -- it is checked in rather than generated at build time so
both apps' bench builds embed the identical bytes without needing this script at build time.
the benchmark embeds identical bytes without needing this script at build time.
+4 -5
View File
@@ -1,13 +1,12 @@
#!/usr/bin/env python3
"""Generates transcript.jsonl -- the synthetic fixture P0's benchmark opens in both apps.
"""Generates transcript.jsonl -- the synthetic fixture the benchmark opens.
Deterministic (fixed seed), so a Compose bench APK and an iris bench APK draw byte-identical
content: the point of the fixture is a like-for-like comparison, not a realistic one.
Deterministic (fixed seed), so runs draw byte-identical content.
Never a real transcript -- see AGENTS.md's ui-sandbox.sh, which this borrows its vocabulary
style from (headings, code fences, a table, a link) rather than reusing its Claude-Code JSONL
shape. This file's shape is the *app's own event model* instead: one JSON object per line,
matching what GET /sessions/{id}/transcript returns and what Events.kt's parseSeqEvent reads
matching what GET /sessions/{id}/transcript returns
(server/src/session/driver.rs is the source of truth for the field names).
./generate.py writes transcript.jsonl and bench1.png/bench2.png here
@@ -54,7 +53,7 @@ DELTAS_PER_BLOCK = (4, 12)
# stress for one-shot shaping and puts a row right on the cap boundary, where nothing else is.
#
# It is *not* streamed: the repeated-reshape pathology needs a growing block, and that lives in
# `app-rust/tests/frame_profile.rs`'s `what_reshaping_a_growing_message_costs`, where it can be
# the UI profiling rig's `what_reshaping_a_growing_message_costs`, where it can be
# iterated on in a second rather than in a two-minute phone run. Note that the cap would not save
# a real one anyway -- `row::build_row`'s `cap` is deliberately `false` for the live tail, because
# a row that grew while capped would appear to stop growing, so a streamed block's shaping cost