The plan marked A34 (instrumented E2E against a real host) and A35
(macrobenchmark) DONE. Neither had a single line of code — :app had no
androidTest source set at all, and `testInstrumentationRunner` named a
HiltTestRunner class that did not exist. They had been converted into checklist
bullets. This adds 67 instrumented tests and 3 macrobenchmarks, and every one
of them has actually been executed on an emulator against this repo's own
server — not merely compiled.
Why this layer had to exist: four crash-on-first-interaction defects shipped
behind a green 900-test suite, for one structural reason — no JVM test
instantiates an android.view.View, creates an InputConnection, dispatches a
MotionEvent or runs a layout pass. So the rig builds the REAL RemoteTerminalView
in a REAL Activity and drives it through the REAL framework entry points,
faking only the wire so assertions can be about BYTES rather than "did not
crash". That distinction matters: a no-crash-only test would have passed against
the silent-black-hole variant of the IME bug, which was arguably the worse half
of it.
The four crash regressions (28 tests):
keys — Enter is \r not \n, Ctrl+C is 0x03, Backspace 0x7f, and arrows in BOTH
DECCKM modes driven off the live emulator bit, so ESC[A vs ESC OA is
asserted rather than assumed; BACK falls through and emits nothing; soft
keyboard commitText/sendKeyEvent/deleteSurroundingText and a CJK
composition pass through verbatim.
alternate-screen scroll — every test feeds ESC[?1049h FIRST and asserts the
buffer is active before touching anything, because that is the branch that
used to crash. Real dispatchTouchEvent drags both directions, the DECCKM
form, the mouse-tracking branch emitting a wheel report and NO arrows
(branch order), the wheel's 3-rows-per-notch, and the fling proven not to
start by 800 ms of silence after ACTION_UP.
autofill — the framework's own autofill-structure gate is closed on both the
frame and the stock child, before and after focus.
resize — including the draw-race counterpart of the AIOOBE fixed in 538c8eb.
A34 E2E against a live server (15 tests): attach → attached → output round
trip, ring-buffer replay on reconnect, spawn failure via a second server
deliberately configured with a bad SHELL_PATH, a held gate resolved through
POST /hook/decision, and CswshDefenceE2eTest — the F9 bad-Origin rejection,
which the checklist calls the one non-skippable defence and which had never
been executed anywhere.
A35 (3 macrobenchmarks): startup, and pair → attach → type → approve.
Reaching a host from the emulator needs ALLOWED_ORIGINS=http://10.0.2.2:<port>,
because the server derives allowed origins from host NIC IPs and 10.0.2.2 is
the emulator's alias for the host, not an interface address. Tests take the
host as an instrumentation argument and SKIP with a clear message when it is
absent, so "passed" can never be confused with "never ran".
Verified independently of the authoring agent, on emulator-5554 (webterm AVD,
android-35, arm64, software GPU), with both servers live:
Starting 67 tests on webterm(AVD) - 15
Finished 67 tests on webterm(AVD) - 15
tests="67" failures="0" skipped="0"
JVM gate unaffected: ./gradlew test :app:assembleDebug
:app:assembleDebugAndroidTest :macrobenchmark:assembleBenchmark koverVerify ->
BUILD SUCCESSFUL, 903 tests, 0 failures.