Split the newest reply once its turn ends, and make the UI harness reusable

The transcript's remaining lag was the newest assistant reply: transcriptUnits
kept the last row whole -- right while it streams (splitting a changing text
is a parse per delta), wrong forever after, so a session that ends on a long
reply drew it as one lazy-list item with every node alive. On a Pixel 9 Pro
XL that was 13.8ms of draw phase a frame, 79% of it the framework's own
per-node bookkeeping, against a 34,996px item.

An AssistantMsg now carries `settled`, folded from the status event that ends
its turn (status changes are transcript events with seqs, so replay settles
the same way), and cleared if a delta ever grows the message again. A settled
newest reply splits like every other. Folding it -- rather than reading the
screen's status -- routes the resplit through the held-events gate, so it can
only happen at the newest end while pinned, never under a reader. The
"session is working" predicate now lives once, in sessionWorking().

Measured on the emulator, same session and gestures, a 43KB reply as the
last row: draw phase 3.92ms -> 1.20ms per frame, framework share 3.07ms
(78%) -> 0.54ms (45%), worst single measure 82.5ms -> 9.1ms. The report's
"on screen" line went from one 60,674px AssistantMsg to five blocks of
95-846px. A live streamed turn settles and splits the moment it goes idle.

The harness half, asked for by Bryan: ui-sandbox.sh now derives its port and
root from the checkout name (two checkouts' sandboxes cannot reach each
other), keeps its token in ~/.config/ai-app/sandbox-token and salvages
enrolled device tokens across restarts (enrol the emulator once, ever), and
gained the driving verbs every UI session was re-inventing in /tmp: spawn,
send (text or @file), api. transcript-bench.sh is the standard
scroll-and-report measurement. AGENTS.md documents all of it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5 committed 2026-09-01 17:19:19 -04:00
1 parent 917eb9a7b3
commit 7a48f8ff1f
8 files changed
+250 -23

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
#!/bin/sh
# Scrolls the transcript and prints the app's own render report -- the
# standard measurement for "is the transcript smooth", so a perf session
# starts from a number instead of re-inventing this loop in /tmp.
#
# ./transcript-bench.sh restart the app, open the first
# session, scroll, report
# ./transcript-bench.sh -k keep whatever screen is open now
# ./transcript-bench.sh -n 4 swipe cycles (default 6; one cycle is
# two swipes back and two forward)
#
# What it prints is the report the in-app copy button produces, plus any
# duplicate-key warnings the flatten logged. Absolute frame times from the
# emulator are worthless (it renders in software); what transfers is the
# report's own accounting -- what was on screen, and where the draw phase
# went. Compare two runs of this with the same gestures, not one run
# against a phone.
#
# Coordinates are the ai-app AVD's 1080x2400 screen: the report button in
# the session top bar, and the first row of the session list.
set -eu
cd "$(dirname "$0")"
. ./android-env.sh >/dev/null 2>&1
keep=""
cycles=6
while getopts kn: flag; do
case $flag in
k) keep=1 ;;
n) cycles=$OPTARG ;;
*) exit 2 ;;
esac
done
if [ -z "$keep" ]; then
adb shell am force-stop com.example.aiapp
adb shell am start -n com.example.aiapp/.MainActivity >/dev/null
sleep 5
ui-trace record -d 3000 --do 'tap 500 545' -o /tmp/bench-open.txt >/dev/null 2>&1
sleep 3
fi
# First tap resets the report's "work since last copied" window, so the
# numbers cover exactly the swipes between the two taps.
ui-trace record -d 2000 --do 'tap 723 205' -o /tmp/bench-reset.txt >/dev/null 2>&1
adb logcat -c
DO=""
i=0
while [ "$i" -lt "$cycles" ]; do
DO="$DO --do 'swipe 540 700 540 1600 200' --do 'wait 500'"
DO="$DO --do 'swipe 540 700 540 1600 200' --do 'wait 500'"
DO="$DO --do 'swipe 540 1600 540 700 200' --do 'wait 500'"
DO="$DO --do 'swipe 540 1600 540 700 200' --do 'wait 500'"
i=$((i + 1))
done
eval ui-trace record -d $((cycles * 4400 + 2000)) $DO -o /tmp/bench-scroll.txt >/dev/null 2>&1
ui-trace record -d 2000 --do 'tap 723 205' -o /tmp/bench-report.txt >/dev/null 2>&1
sleep 1
adb logcat -d -s ai-app:I | sed -n '/ai-app render report/,$p' | sed 's/^.*ai-app : //'
adb logcat -d 2>/dev/null | grep -i "duplicate unit key" | head -3 || true