testsAndMisc/docs/superpowers/contracts/billsplit-apk-buildable-2026-08-03.json
Krzysztof Rudnicki 4d9f486176 billsplit: build a real APK by dropping file_picker for file_selector
billsplit had never produced an Android APK. file_picker 11.0.3 — the latest
release on pub.dev — is wedged under AGP 9 in both directions: it skips
applying the Kotlin Gradle Plugin when AGP >= 9, so with built-in Kotlin off
its own Kotlin never compiles (`cannot find symbol: FilePickerPlugin`), and
with built-in Kotlin on its buildscript leaks KGP onto the global classpath
via rootProject.allprojects, which AGP then rejects for every module.

The app's Gradle config was never at fault: android/app/build.gradle.kts and
settings.gradle.kts are byte-identical to habit_stack, home_inventory and
diet_guard_app, which all build. Only the dependency differed, so the fix is
the dependency — the toolchain stays on the house-standard AGP 9.

Ported both call sites to the official file_selector. Its save flow returns a
destination and leaves the write to the caller, where file_picker wrote the
bytes inside the plugin; that write now goes through an injectable seam
because a real dart:io future never completes inside testWidgets' fake-async
zone, so a widget test could otherwise never observe the resulting snackbar.
The test double moves from a MethodChannel mock to a FileSelectorPlatform fake
(file_selector speaks Pigeon, so a channel mock would not intercept it), and a
plain non-widget test covers the real on-disk writer to hold 100% coverage
without an ignore.

The launcher icon is now verified from the built artifact: the ic_launcher
assets unzipped from the APK render as the charcoal + gold perforated receipt,
not the stock Flutter beach. Peak build footprint is 1.86 GiB, inside budget.

Also rewrites ci_mirror.sh to run its gates in a disposable worktree at HEAD.
`pre-commit run --all-files` stashes the live tree, and in a shared checkout
that made an unrelated agent's uncommitted work collide with hook auto-fixes,
failing the push while blaming an innocent hook — and putting that work inside
a stash window, which memories/git-rules.md forbids. A clean worktree needs no
stash and is a truer mirror of CI, which never sees a dirty file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 14:15:40 +02:00

20 lines
2.1 KiB
JSON

{
"title": "Make billsplit's APK buildable and stop the CI mirror fighting a dirty tree",
"objective": "billsplit had never produced an Android APK: file_picker 11.0.3, the latest release, cannot compile under AGP 9 in either built-in-Kotlin mode. Replace it with the official file_selector so the app builds, verify the launcher icon from the built artifact rather than from a preview, keep the build inside this machine's 2 GB memory budget, and make the pre-push CI mirror stop failing whenever the shared checkout has uncommitted work.",
"acceptance_criteria": [
"flutter build apk --debug succeeds",
"The launcher icon extracted from the APK is the charcoal + gold perforated-receipt glyph and does not match the stock Flutter beach icon",
"Peak PSS across the build's JVM and Dart processes stays under 2 GiB, measured from /proc/<pid>/smaps_rollup",
"flutter analyze is clean, all tests pass, and billsplit holds 100% line coverage with no coverage ignores",
"meta/scripts/ci_mirror.sh passes while the working tree is dirty, leaves every uncommitted file byte-identical, and removes its temporary worktree",
"billsplit's Gradle and AGP versions stay identical to the sibling Flutter apps"
],
"out_of_scope": [
"Pinning AGP 8 or otherwise diverging billsplit's Android toolchain from habit_stack, home_inventory, todo and diet_guard_app",
"Installing or running the APK on the phone; the icon is verified from the artifact, not from a device launcher",
"Any change to the split engine, xlsx export format, or e-paragon parsing",
"Upgrading the other dependencies pub reports as outdated"
],
"verifier": "flutter analyze, flutter test --no-pub --coverage and python3 -m python_pkg.billsplit_coverage inside billsplit; flutter build apk --debug followed by unzipping the APK and rendering its ic_launcher assets; a PSS sampler over the build's processes; bash meta/scripts/ci_mirror.sh run deliberately against a dirty tree with before/after md5 of an uncommitted file; shellcheck on the rewritten script; and pre-commit run --files on the staged set inside a 2G cgroup"
}