2ada69a40f689bfeafba6878fdf94ed1760e4eaf
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0bfa2136be |
feat(dev): ask the phone instead of looking at it
The device tier could only take a screenshot and read what Go chose to log, and a screenshot cannot tell a dropped CSS declaration from a missing asset. This adds the third thing: the page's own answer, from the engine that is really rendering it. `make android-screenshot` grabs the screen, `make android-inspect` forwards the WebView's devtools socket, and `make android-eval EXPR=...` evaluates in the real page. Four details are load-bearing. Only a `debuggable` build opens that socket, so the debug build type takes `applicationIdSuffix ".dev"` and installs *beside* the release app -- the two carry different signing certificates, and Android's only remedy for a changed certificate is an uninstall, which takes the user's library with it. Playwright cannot drive a WebView (`connectOverCDP` calls `Browser.setDownloadBehavior`, which it answers "Browser context management is not supported"), so the eval is raw CDP over Node's built-in WebSocket. The socket name carries the pid, so it is resolved per launch rather than written down. And `exec-out`, not `shell`, for the screenshot: a pty translates LF and corrupts the PNG. What it immediately established is why it was worth having. The phone renders in Chrome 113 at 424x439 CSS px -- two years behind every browser the other tiers use, with no Popover API and no relaxed CSS nesting -- so a spec passing at that viewport says nothing about the device, and two conclusions drawn from version numbers alone were wrong. Both are corrected in NOTES.md and the plan. |
||
|
|
b1cdef8769 |
docs: record what a phone said that no tier could
The first device run of the published APK, and the first runtime evidence any of the Android work has ever had -- A4 shipped entirely reasoned from source. It confirms A4 whole: playback survives the screen locking, and the transport notification appears with cover art, which settles four open questions at once (the service starts, the permission was granted and the notification is visible, the lock screen picks up the session, and art decoded from a MANAGE_EXTERNAL_STORAGE path by a service is readable -- the one nobody could argue from documentation). It also found the two faults fixed in the preceding commits, and the lesson worth keeping is why *those two*: both are things the platform adds rather than things the app draws. So the skill's Android tier now says to ask a device about system bars, the back gesture, focus and audio interruptions, permissions and the keyboard -- and not about layout, which the other five tiers already cover. |
||
|
|
df2e9ea777 |
docs: record what the Android work established and disproved
Section A of plan 016 is closed and B1 is decided, so the three tenses move together: CLAUDE.md for what mediacontrols now is, the skill for what to run, NOTES.md for what was measured and when. The entry worth reading is the one that disproves a claim written here earlier in the same session. Dropping x86_64 was expected to make make android-install fail with INSTALL_FAILED_NO_MATCHING_ABIS. Measured, it installs and launches: Google's google_apis x86_64 images carry arm64 translation (abilist = x86_64,arm64-v8a), so the loader maps lib/arm64/libwails.so and runs it. It dies before any of our code with SIGILL, and the disassembly names the reason exactly -- `mrs x0, ID_AA64ISAR0_EL1`, Go's internal/cpu reading the arm64 feature register at runtime init, which the translator does not implement. So no Go binary starts under it, and that is not a property of this app. Which closes the last plausible shortcut. There are now three distinct ways this app fails on an x86_64 Android -- seccomp on the x86_64 build, an unimplemented system register on the translated arm64 one, and a real device still unverified -- and none of them is a bug in it. A phone remains the only verification path. Plan 016 also carries the B2 scope, now decided rather than recommended: option 1's data model with option 2's surface. The phone gets home, library browse, now-playing-as-a-view, the queue, search and playlists; it does not get autotag, downloads, Explore or the 93-control Settings page, and each of those has a reason written beside it. One rule for the work: no view forks, because a phone template that copies a view's is two templates to fix every bug in. |
||
|
|
f7dc76c955 |
docs(android): an arm64 image will not run on an x86_64 host
Build & publish Arch package / arch-package (push) Successful in 2m32s
Search index maintenance / maintain-index (push) Successful in 7s
CI / e2e (push) Successful in 5m42s
CI / check (push) Successful in 2m22s
Sync Homebrew formula / sync-formula (push) Successful in 6s
Build & publish the Android APK / apk (push) Failing after 50s
Emulator 37 refuses cross-architecture emulation outright -- "Avd's CPU Architecture 'arm64' is not supported by the QEMU2 emulator on x86_64 host" -- and there is no flag for it. Google dropped it. That matters because the previous commit's finding points at arm64 as the ABI that works, so the obvious next move is to boot an arm64 AVD, and the obvious next move costs a 3.8 GB download before it fails. Written down so the next session does not spend it. The consequence is stated rather than hidden: the claim that arm64 avoids the seccomp trap rests on reading modernc's two code paths, not on having run it. Verifying it needs an arm64 host, a physical device or adb connect. |
||
|
|
ed975019dc |
fix(dev): the smoke target died silently on a genuinely dead app
Two harness bugs and the finding that exposed them. **`pidof` exits 1 when it finds nothing**, and under `set -e` a failing command substitution killed the script before it could print anything -- rc=1, no output. That was invisible for as long as the app crash-*looped*, because there is always some pid in that state. It appeared the moment the app died for good and ActivityManager stopped respawning it, which is precisely the run you most want output from. **And an install failure said nothing useful.** Both ways it fails are about identity rather than the build: INSTALL_FAILED_VERSION_DOWNGRADE when a bare `make android` (versionCode 1) meets something a versioned build left behind, and a signature mismatch when a debug-signed local build meets a release-signed one. Both were hit in one session, and both are fixed by uninstalling. The target says so now instead of leaving someone to read the constant name. The finding: with the startup bug fixed the app reaches the database and takes SIGSYS on the x86_64 emulator, because modernc.org/libc's Xlstat64 issues a raw lstat syscall on linux/amd64 and Android's seccomp filter forbids it -- bionic never issues it. arm64 has no lstat syscall at all, so ccgo_linux_arm64.go routes Xlstat through fstatat and is structurally unaffected; Go's own syscall package already used fstatat on both. So the default emulator cannot verify this app, and the skill says so rather than letting the next session read a tombstone as a regression. |
||
|
|
68468e5378 |
feat(dev): an Android failure looks exactly like a success
The APK installs and launches. It also dies six milliseconds later, and finding that out cost a cycle for three reasons that have nothing to do with the bug itself: **Go's stdout does not reach logcat.** An Android app's fd 1 and 2 go to /dev/null, so every slog line -- including the one naming the error the app is about to exit on -- is discarded. `setprop log.redirect-stdio true` does not help: that redirects the Java runtime's System.out, and our code is a c-shared native library. **os.Exit leaves no evidence.** No panic, no AndroidRuntime stack, nothing in /data/tombstones, nothing in `logcat -b crash` or dropbox. All three places anyone would look are empty, and the one signal that is present -- "Zygote: exited due to signal 9" -- reads as "the system killed it" and sends you after the low-memory killer. **ActivityManager restarts it faster than you can observe.** pidof always answers and `am start` always reports Status: ok, so a crash-looping app looks alive. "Did it start" is the wrong question; `make android-smoke` asks whether it is the *same pid* N seconds later, and prints the filtered logcat plus how to read it when it is not. The tell, once known: "I/WailsBridge: Wails bridge initialized" followed immediately by a new pid doing the same thing. scripts/android-emulator.sh follows dev-headless.sh's shape -- background start, saved-PID stop, filtered log tail, never pkill -f. Two scaffold tasks are deliberately not wrapped: `android:logs` greps logcat for (Wails|yellowjacket), which catches the WailsBridge tag but misses the app's own process tag (app.yellowjacket is lowercase) and misses ActivityManager's "has died" line, which is the one that says it crashed; and `ensure-emulator` boots whatever `-list-avds | tail -1` returns, with no pidfile and no boot wait, so it cannot be sequenced. One environment note that is not obvious on Arch: Gradle needs a platform and /opt/android-sdk has none, so ANDROID_SDK defaults to ~/Android/Sdk while ANDROID_NDK points at /opt/android-ndk. Two SDKs, one for each half of the build. |