Why
When the Android driver misbehaves, its log says nothing. A CI run (#31603873289) lost all six scenarios to hierarchy calls that died on the action's context deadline, and the driver log offered exactly 11 lines, all from instrumentation startup:
INSTRUMENTATION_STATUS: class=org.taleslabs.tales.driver.TalesDriverTest
...
s_glBindAttribLocation: bind attrib 0 name position
No request ever appears, so there is no way to tell whether those calls reached the driver at all — and therefore no way to explain why they did not receive the retryable 503 that the 8s snapshot ceiling in Snapshot.kt should have produced. That question is still open.
The Apple driver already does this, and it is what made the iOS root cause readable: the request/response pairs showed a single POST /launch taking 245391ms, which located the failure precisely. Handlers.swift:
[tales-driver] request: POST /launch
[tales-driver] response: POST /launch status=200 elapsed=245391ms
The gap between a request: line and its missing response: is what identifies the call that wedged the driver. Android has no equivalent.
What
Mirror the Apple driver's logging in Router.kt:
- one
request: <METHOD> <path> line before dispatch,
- one
response: <METHOD> <path> status=<code> elapsed=<ms>ms line after,
- skip
GET /health, which Tales polls once a second and which would otherwise bury the log.
Match the [tales-driver] prefix so both platforms grep the same way.
Acceptance
- A failing Android run's
build/artifacts/mobile/driver/<target>/driver.log shows the sequence of calls with timings.
- A call that never completes is identifiable as a
request: line with no matching response:.
GET /health does not appear.
Notes
Touching the driver means rebuilding the committed APKs (make build-android-driver, needs JDK 17 + the Android SDK), refreshing the source.sha256 sentinel, and rebuilding the tales binary, which embeds them — an old binary keeps installing the previous driver. make check-android-driver-fresh guards the sentinel in CI.
Context: the ANR that triggered the investigation is handled separately by suppressing system error dialogs on the CI emulator; this issue is only about being able to diagnose the next occurrence.
Why
When the Android driver misbehaves, its log says nothing. A CI run (#31603873289) lost all six scenarios to hierarchy calls that died on the action's context deadline, and the driver log offered exactly 11 lines, all from instrumentation startup:
No request ever appears, so there is no way to tell whether those calls reached the driver at all — and therefore no way to explain why they did not receive the retryable
503that the 8s snapshot ceiling inSnapshot.ktshould have produced. That question is still open.The Apple driver already does this, and it is what made the iOS root cause readable: the request/response pairs showed a single
POST /launchtaking 245391ms, which located the failure precisely.Handlers.swift:The gap between a
request:line and its missingresponse:is what identifies the call that wedged the driver. Android has no equivalent.What
Mirror the Apple driver's logging in
Router.kt:request: <METHOD> <path>line before dispatch,response: <METHOD> <path> status=<code> elapsed=<ms>msline after,GET /health, which Tales polls once a second and which would otherwise bury the log.Match the
[tales-driver]prefix so both platforms grep the same way.Acceptance
build/artifacts/mobile/driver/<target>/driver.logshows the sequence of calls with timings.request:line with no matchingresponse:.GET /healthdoes not appear.Notes
Touching the driver means rebuilding the committed APKs (
make build-android-driver, needs JDK 17 + the Android SDK), refreshing thesource.sha256sentinel, and rebuilding thetalesbinary, which embeds them — an old binary keeps installing the previous driver.make check-android-driver-freshguards the sentinel in CI.Context: the ANR that triggered the investigation is handled separately by suppressing system error dialogs on the CI emulator; this issue is only about being able to diagnose the next occurrence.