app: fixture-mode session screen and a "Run benchmark" control

BenchFixture.kt/BenchNetwork.kt fake the backend for the bench build: a
URLStreamHandlerFactory installed only under BuildConfig.FIXTURE_MODE
answers TranscriptSource/EventStream's requests from an in-memory copy of
the bundled fixture instead of opening a socket, so the fold, the paging
and uniqueItems under test are the screen's real ones rather than a
shortcut built for this. MainActivity opens straight onto that session
when FIXTURE_MODE is set, with no enrollment and no permission prompts.

BenchRun.kt drives the same scroll loop and streaming phase
transcript-bench.sh/stream-bench.sh drive over ui-trace, but in-process
(24 swipes through the real LazyListState, then 400 fixture events
appended at 20/s through the real live-fold path), and adds process CPU
time, peak RSS and battery current to the render report -- "unavailable"
rather than a fabricated number where the device can't answer.

"Run benchmark" sits beside the existing "Copy" in session settings,
found by that exact label the way every other control here is
(SessionSettingsDialog's onRunBenchmark, null on every build but bench).
debugReport gained an optional `extra` section for this; empty and
invisible on every other build's report.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-05 21:03:57 -04:00
1 parent a6cb9a9082
commit e6c884a0cd
7 files changed
+537 -1

No files matched your search

@@ -1191,7 +1191,12 @@ fun SessionScreen(
// the bench scripts keep working when this moves again. They pressed it at a hand-measured
// coordinate until 2026-09-03, and anything that moved the header made that tap land on
// whatever now sat there -- reporting a number that was never measured.
val copyRenderReport = {
// Shared by the ordinary "Copy" button and (bench build only) "Run benchmark": what differs
// between them is only whether there is a [extra] section, built by BenchRun.run beforehand --
// everything about assembling, copying and logging the report is exactly the same act either
// way, and a second copy of it beside `onRunBenchmark` below would be the two silently
// disagreeing about what "the report" contains the first time either one changed.
fun buildAndCopyReport(extra: List<String> = emptyList()) {
val report =
debugReport(
device =
@@ -1213,6 +1218,7 @@ fun SessionScreen(
accounting =
FrameStats.drawPhase().let { (nanos, count) -> drawAccounting(nanos, count) },
crash = lastCrash(context),
extra = extra,
)
context.copyToClipboard("ai-app render report", report)
// Also to the log, so a session driving the app over adb can read the same report the
@@ -1226,6 +1232,20 @@ fun SessionScreen(
DebugStats.reset()
Toast.makeText(context, "Copied render report", Toast.LENGTH_SHORT).show()
}
val copyRenderReport = { buildAndCopyReport() }
// Bench build only: P0's scripted scroll-and-stream benchmark (BenchRun.kt), against the
// fixture session opened below instead of a real server. Null everywhere else -- see
// [SessionSettingsDialog]'s onRunBenchmark.
val runBenchmark: (() -> Unit)? =
if (BuildConfig.FIXTURE_MODE) {
{
settingsOpen = false
scope.launch {
val extra = BenchRun.run(context, scope, listState)
buildAndCopyReport(extra)
}
}
} else null
Box(Modifier.fillMaxSize()) {
Column(Modifier.fillMaxSize()) {
Row(
@@ -1869,6 +1889,7 @@ fun SessionScreen(
},
onDismiss = { settingsOpen = false },
onCopyRenderReport = copyRenderReport,
onRunBenchmark = runBenchmark,
)
}
}