Continue Android file manager implementation from typed APK baseline #69

Open
opened 2026-09-25 17:04:53 -04:00 by ober · 0 comments
Owner

Continuation handoff: complete the Android file manager implementation

Original user goal (still active)

Read ~/jdrive-for-android.md and implement all of it in jerboa-drive.
Use the local Android emulator to test every feature and every GUI function with
real assertions. Open a pull request only after 100% of the requirements and
tests are complete, with CI green. Do not redefine completion around the
currently working subset.

The authoritative source checkout /Users/user/mine/jerboa-drive must remain
untouched. Current implementation work is in the dedicated checkout
/Users/user/work/jerboa-drive-android-implementation, branch
feat/android-file-manager. There is no commit or pull request yet.

What is implemented in the current worktree

All of the following are uncommitted changes in the worktree:

  • VERSION bumped from 2.0.23 to 2.0.24.
  • Makefile targets/help for android, android-release, and android-smoke.
  • scripts/build-android.sh: compiler/runtime fetch, clean generated output,
    encrypted asset provisioning, safe staging cleanup, debug APK build, and
    checksum output.
  • scripts/sign-android.sh: release-signing path (requires an external
    keystore; do not treat debug APKs as releases).
  • support/fetch-android-compiler.sh: pinned jerboa-android acquisition.
  • tools/android-embed.ss: typed Jerboa host provisioner for the JDAE envelope
    (scrypt N=65536/r=8/p=2, AES-256-GCM, bounded payload, JSON validation).
  • android/app.ss: typed Jerboa Android app containing:
    • JDAE envelope validation/decryption and profile application.
    • password unlock, asynchronous KDF work, lock lifecycle, stale-session
      cleanup, device ID, biometric enrollment/removal/unlock wrapper using
      AndroidKeyStore, and recovery handling.
    • typed SigV4 S3 path/virtual-host addressing, session-token signing,
      LIST pagination, HEAD/GET/PUT, bounded multipart initiation/parts/complete/
      abort, retries, prefix handling, and v2 name/frame codecs.
    • v2 ChaCha20-Poly1305 component names, JDF2 framing/AAD, metadata checks,
      codec self-tests, malformed-frame safeguards, and transfer journals.
    • SAF tree/document pickers, persisted tree URI, local folder open/parent/
      filtering, local copy/rename/delete, downloads, backup/restore reports,
      cache cleanup, cancellation, Sharesheet/FileProvider, and locked-state
      gating.
    • ScrollView-based action UI with dynamic smoke-test-visible controls.
    • typed WorkManager dependency (androidx.work:work-runtime-ktx:2.11.2),
      generated BackupWorker, and generated BackupScheduler with a unique
      15-minute plan/cancel operation. The worker deliberately records
      waiting-for-unlock and exits successfully when no live session exists;
      it does not pretend to perform an authenticated background transfer.
    • UI actions “Schedule backup” and “Cancel scheduled backup”, calling the
      generated scheduler and persisting backup-plan-status as scheduled or
      cancelled.
  • test/android-smoke.sh: fresh uninstall/install smoke harness with ADB
    retries, dynamic UI node taps, password/picker race handling, secret-sentinel
    APK scan, SAF picker flows, backup/schedule/cancel state checks, biometric
    fallback, lock/cache/recovery checks, local operations, v2 upload terminal
    result, codec, inspect, filter, and Sharesheet assertions.
  • docs/android.md: build/use/recovery documentation and explicit statement of
    the remaining limitations; it must stay honest until the gates below pass.
  • Cookbook knowledge saved successfully via Jerboa MCP:
    typed-android-workmanager-periodic (typed Worker/scheduler syntax and the
    required getSharedPreferences(name, mode) extern arity).

Verified evidence

  • Latest generated debug APK built successfully with SHA-256:
    414ac4ad49270cdcaab283d538519fadd53049d8a8f462bc0c2a138ba0541dd2.

  • Build command used:

    JDRIVE_ANDROID_PROVISION=1 \
      JDRIVE_ANDROID_INPUT_JSON=/tmp/jdrive-android-profile.json \
      JDRIVE_ANDROID_PASSWORD_FILE=/tmp/jdrive-android-password \
      scripts/build-android.sh
    

    The synthetic profile/password are disposable local test inputs only; do not
    print or commit them. The build compiled generated DriveActivity.kt,
    BackupWorker.kt, and BackupScheduler.kt successfully.

  • make security passed (package_security_status=pass,
    secret_scan_status=pass). git diff --check passed. Shell syntax checks
    passed for the scripts.

  • A complete pre-WorkManager full emulator run passed all existing GUI checks,
    including unlock/wrong-password/biometric fallback, background lock,
    encrypted backup marker, SAF folder/upload pickers, local operations, v2
    upload terminal result, transfer cancellation/journal/cache, codec, inspect,
    restart/recovery/device-ID/tree persistence, local filter, and Sharesheet.

  • After adding scheduler UI, a later emulator run reached and passed the new
    backup-scheduled and backup-cancelled assertions. That run later failed
    at a flaky post-picker “Unlocked” assertion; a one-second keyboard-dismiss
    delay was added to the harness afterward, but the entire updated run was not
    re-run before handoff. Re-run it before relying on the latest smoke result:

    sh -n test/android-smoke.sh
    sh test/android-smoke.sh build/android/app/build/outputs/apk/debug/app-debug.apk
    
  • jerboa_verify could not run because the MCP server points at stale
    /Users/user/mine/jerboa/bin/jerboa and a missing Chez cache. This is a
    tooling/runtime issue, not a source verification success; the Android build
    itself is the current compile evidence.

Important implementation lessons

  • Never edit .ss/.sls with shell editors, Python, sed, or apply_patch. All
    .ss edits were made with jerboa_balanced_replace/jerboa_balanced_insert,
    followed by jerboa_check_balance. Continue this rule.
  • A ScrollView child LinearLayout needs explicit typed
    LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); otherwise later
    action buttons are clipped on the emulator.
  • The typed Worker fixture pattern is in the vendored jerboa-android tests:
    separate typed-kotlin-file forms, Worker subclass with doWork, and a
    scheduler using PeriodicWorkRequest.Builder, WorkManager, and
    enqueueUniquePeriodicWork.
  • Generated top-level Jerboa function names preserve underscores. The
    scheduler generated backup_schedule/backup_cancel; cross-file calls from
    DriveActivity must import/call those generated names, not assume a
    BackupSchedulerKt class symbol.
  • getSharedPreferences requires explicit (name, mode) parameters in the
    typed extern; omitting them gives a Kotlin arity error.
  • Dynamic UI node bounds are much more reliable than fixed coordinates. When a
    button is tapped and only its status is being asserted, do not tap an old
    coordinate again (the old helper accidentally invoked “Backup now” twice).
  • adb shell run-as ... cat shared_prefs/*.xml does not reliably expand the
    wildcard; enumerate files with find and read each one.
  • The MCP combined verifier is unavailable until its configured Jerboa/ Chez
    runtime is repaired. Do not “fix” this by editing the authoritative checkout.

Remaining work: do not open the PR until all of this is complete

The current app is explicitly not 100% complete. The next agent must use
~/jdrive-for-android.md as the authority and close every gate, not merely make
the synthetic smoke green.

  1. Provisioning/build hardening: implement the documented ~/.embed/
    allowlisted profile/AWS mapping and profile selector, confined regular-file
    and symlink/path checks, expired-token handling, separate vault/YubiKey
    export path, independent envelope vectors (including Unicode, duplicate
    JSON keys, malformed/oversized inputs), normal release signing/key setup,
    provenance artifacts, and default make android behavior without relying
    on a hand-created normalized JSON file.
  2. Byte-for-byte compatibility: export public synthetic desktop vectors and
    compare desktop↔Android names, headers, frames, empty/boundary/Unicode
    files, tamper/truncation/reordering/wrong-path rejection, and >4 GiB
    streaming. Preserve the exact desktop v2 contract.
  3. Real streaming transport: remove whole-file/whole-object buffering and
    the 16 MiB source limit (readBytes/readNBytes currently bound upload and
    download bodies). Implement 64-bit offsets, bounded frame/part buffers,
    multipart sizing up to 10,000 parts, range GET validation, ETag/version
    preconditions, cancellation/deadlines/backoff, ambiguous completion
    reconciliation, orphan cleanup, non-seekable/unknown-size staging, and
    measured heap evidence. Current multipart still accepts one Bytes body.
  4. Real S3 integration: exercise a disposable S3-compatible service with
    desktop-created data, >1000-object pagination, custom HTTPS/path/virtual
    host, session tokens, redirects/TLS/errors, concurrent modification, and
    desktop readback of Android uploads. The current synthetic endpoint is empty,
    so network actions only prove terminal failure handling.
  5. File manager UI: implement actual Local/Drive screens with directory/file
    rows, breadcrumb/back, size/type/date, sort, scoped search, multi-select,
    responsive/cancellable loading, upload/download/open/share, conflict choices
    (skip/replace/keep-both), path-safe recursive moves with re-encryption,
    partial move reporting, and foreign-object preservation. Current UI is a
    linear action list with limited selected-object behavior.
  6. Transfers/foreground execution: add per-file/overall progress and
    queued/running/waiting/failed/completed states, retry/partial details,
    foreground long-transfer service/notification/cancel path, notification
    permission denial handling, Doze/network/low-storage/reboot/process-kill,
    Android 15 service timeout/checkpoint handling, and proper structured
    manifest service types/permissions. Current Worker only records
    waiting-for-unlock and performs no backup transfer.
  7. Backup/restore engine: implement persisted named plans (sources/grants,
    labels, exclusions, destination plan IDs, schedule/constraints/conflict
    policy/history), hashed encrypted manifests, additive deletion semantics,
    honest completed/skipped/failed/unreadable/cancelled totals, source mutation,
    resume/recovery, fresh-unlock handoff, verified file/subtree/full restore,
    conflict/free-space handling, temp destination publication, and interruption
    safety. Current backup is a marker/report workspace, not a complete engine.
  8. Settings/platform: add biometric/lock/network/charging/cache/profile
    settings and redacted diagnostics UI; test rotation, screen-off authorized
    transfer, Doze, notification denial, service timeout, current API and min
    SDK emulator, physical arm64 device, upgrade/reinstall/enrollment-change,
    stale callbacks, and all release-signature checks.
  9. Full test matrix: add documented android-test/android-integration
    targets and run the complete provisioning, secret containment, envelope,
    v2, S3, file-manager, biometric, backup, restore, platform/build matrix in
    section 11 of the handoff. Every visible action must have a real emulator
    assertion and real operations must be byte/hash verified.
  10. Repository handoff: run required desktop make test, security, native
    build/smoke gates plus Android build/smoke; create a feature commit in this
    worktree, push it, open a Forgejo PR targeting the default branch, poll CI
    with fj -H git.jerboa.sh pr status ober/jerboa-drive#<number>, fix all red
    checks, and report the direct PR URL. Never self-approve or self-merge.

Suggested continuation sequence

cd /Users/user/work/jerboa-drive-android-implementation
git status --short
sed -n '1,260p' ~/jdrive-for-android.md
sh -n test/android-smoke.sh
JDRIVE_ANDROID_PROVISION=1 \
  JDRIVE_ANDROID_INPUT_JSON=/tmp/jdrive-android-profile.json \
  JDRIVE_ANDROID_PASSWORD_FILE=/tmp/jdrive-android-password \
  scripts/build-android.sh
sh test/android-smoke.sh build/android/app/build/outputs/apk/debug/app-debug.apk

Use disposable synthetic credentials and a disposable prefix. Never inspect,
print, commit, or publish real secrets. Keep all feature work under ~/work/;
leave /Users/user/mine/jerboa-drive unchanged. Only after the remaining gates
are actually implemented and tested should the continuation agent commit,
push, open the PR, and wait for human review.

## Continuation handoff: complete the Android file manager implementation ### Original user goal (still active) Read `~/jdrive-for-android.md` and implement **all** of it in `jerboa-drive`. Use the local Android emulator to test every feature and every GUI function with real assertions. Open a pull request only after 100% of the requirements and tests are complete, with CI green. Do not redefine completion around the currently working subset. The authoritative source checkout `/Users/user/mine/jerboa-drive` must remain untouched. Current implementation work is in the dedicated checkout `/Users/user/work/jerboa-drive-android-implementation`, branch `feat/android-file-manager`. There is no commit or pull request yet. ### What is implemented in the current worktree All of the following are uncommitted changes in the worktree: - `VERSION` bumped from `2.0.23` to `2.0.24`. - `Makefile` targets/help for `android`, `android-release`, and `android-smoke`. - `scripts/build-android.sh`: compiler/runtime fetch, clean generated output, encrypted asset provisioning, safe staging cleanup, debug APK build, and checksum output. - `scripts/sign-android.sh`: release-signing path (requires an external keystore; do not treat debug APKs as releases). - `support/fetch-android-compiler.sh`: pinned jerboa-android acquisition. - `tools/android-embed.ss`: typed Jerboa host provisioner for the JDAE envelope (scrypt N=65536/r=8/p=2, AES-256-GCM, bounded payload, JSON validation). - `android/app.ss`: typed Jerboa Android app containing: - JDAE envelope validation/decryption and profile application. - password unlock, asynchronous KDF work, lock lifecycle, stale-session cleanup, device ID, biometric enrollment/removal/unlock wrapper using AndroidKeyStore, and recovery handling. - typed SigV4 S3 path/virtual-host addressing, session-token signing, LIST pagination, HEAD/GET/PUT, bounded multipart initiation/parts/complete/ abort, retries, prefix handling, and v2 name/frame codecs. - v2 ChaCha20-Poly1305 component names, JDF2 framing/AAD, metadata checks, codec self-tests, malformed-frame safeguards, and transfer journals. - SAF tree/document pickers, persisted tree URI, local folder open/parent/ filtering, local copy/rename/delete, downloads, backup/restore reports, cache cleanup, cancellation, Sharesheet/FileProvider, and locked-state gating. - ScrollView-based action UI with dynamic smoke-test-visible controls. - typed WorkManager dependency (`androidx.work:work-runtime-ktx:2.11.2`), generated `BackupWorker`, and generated `BackupScheduler` with a unique 15-minute plan/cancel operation. The worker deliberately records `waiting-for-unlock` and exits successfully when no live session exists; it does not pretend to perform an authenticated background transfer. - UI actions “Schedule backup” and “Cancel scheduled backup”, calling the generated scheduler and persisting `backup-plan-status` as `scheduled` or `cancelled`. - `test/android-smoke.sh`: fresh uninstall/install smoke harness with ADB retries, dynamic UI node taps, password/picker race handling, secret-sentinel APK scan, SAF picker flows, backup/schedule/cancel state checks, biometric fallback, lock/cache/recovery checks, local operations, v2 upload terminal result, codec, inspect, filter, and Sharesheet assertions. - `docs/android.md`: build/use/recovery documentation and explicit statement of the remaining limitations; it must stay honest until the gates below pass. - Cookbook knowledge saved successfully via Jerboa MCP: `typed-android-workmanager-periodic` (typed Worker/scheduler syntax and the required `getSharedPreferences(name, mode)` extern arity). ### Verified evidence - Latest generated debug APK built successfully with SHA-256: `414ac4ad49270cdcaab283d538519fadd53049d8a8f462bc0c2a138ba0541dd2`. - Build command used: ```sh JDRIVE_ANDROID_PROVISION=1 \ JDRIVE_ANDROID_INPUT_JSON=/tmp/jdrive-android-profile.json \ JDRIVE_ANDROID_PASSWORD_FILE=/tmp/jdrive-android-password \ scripts/build-android.sh ``` The synthetic profile/password are disposable local test inputs only; do not print or commit them. The build compiled generated `DriveActivity.kt`, `BackupWorker.kt`, and `BackupScheduler.kt` successfully. - `make security` passed (`package_security_status=pass`, `secret_scan_status=pass`). `git diff --check` passed. Shell syntax checks passed for the scripts. - A complete pre-WorkManager full emulator run passed all existing GUI checks, including unlock/wrong-password/biometric fallback, background lock, encrypted backup marker, SAF folder/upload pickers, local operations, v2 upload terminal result, transfer cancellation/journal/cache, codec, inspect, restart/recovery/device-ID/tree persistence, local filter, and Sharesheet. - After adding scheduler UI, a later emulator run reached and passed the new `backup-scheduled` and `backup-cancelled` assertions. That run later failed at a flaky post-picker “Unlocked” assertion; a one-second keyboard-dismiss delay was added to the harness afterward, but the entire updated run was not re-run before handoff. Re-run it before relying on the latest smoke result: ```sh sh -n test/android-smoke.sh sh test/android-smoke.sh build/android/app/build/outputs/apk/debug/app-debug.apk ``` - `jerboa_verify` could not run because the MCP server points at stale `/Users/user/mine/jerboa/bin/jerboa` and a missing Chez cache. This is a tooling/runtime issue, not a source verification success; the Android build itself is the current compile evidence. ### Important implementation lessons - Never edit `.ss`/`.sls` with shell editors, Python, sed, or apply_patch. All `.ss` edits were made with `jerboa_balanced_replace`/`jerboa_balanced_insert`, followed by `jerboa_check_balance`. Continue this rule. - A ScrollView child LinearLayout needs explicit typed `LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)`; otherwise later action buttons are clipped on the emulator. - The typed Worker fixture pattern is in the vendored jerboa-android tests: separate `typed-kotlin-file` forms, `Worker` subclass with `doWork`, and a scheduler using `PeriodicWorkRequest.Builder`, `WorkManager`, and `enqueueUniquePeriodicWork`. - Generated top-level Jerboa function names preserve underscores. The scheduler generated `backup_schedule`/`backup_cancel`; cross-file calls from `DriveActivity` must import/call those generated names, not assume a `BackupSchedulerKt` class symbol. - `getSharedPreferences` requires explicit `(name, mode)` parameters in the typed extern; omitting them gives a Kotlin arity error. - Dynamic UI node bounds are much more reliable than fixed coordinates. When a button is tapped and only its status is being asserted, do not tap an old coordinate again (the old helper accidentally invoked “Backup now” twice). - `adb shell run-as ... cat shared_prefs/*.xml` does not reliably expand the wildcard; enumerate files with `find` and read each one. - The MCP combined verifier is unavailable until its configured Jerboa/ Chez runtime is repaired. Do not “fix” this by editing the authoritative checkout. ### Remaining work: do not open the PR until all of this is complete The current app is explicitly **not** 100% complete. The next agent must use `~/jdrive-for-android.md` as the authority and close every gate, not merely make the synthetic smoke green. 1. **Provisioning/build hardening**: implement the documented `~/.embed/` allowlisted profile/AWS mapping and profile selector, confined regular-file and symlink/path checks, expired-token handling, separate vault/YubiKey export path, independent envelope vectors (including Unicode, duplicate JSON keys, malformed/oversized inputs), normal release signing/key setup, provenance artifacts, and default `make android` behavior without relying on a hand-created normalized JSON file. 2. **Byte-for-byte compatibility**: export public synthetic desktop vectors and compare desktop↔Android names, headers, frames, empty/boundary/Unicode files, tamper/truncation/reordering/wrong-path rejection, and >4 GiB streaming. Preserve the exact desktop v2 contract. 3. **Real streaming transport**: remove whole-file/whole-object buffering and the 16 MiB source limit (`readBytes`/`readNBytes` currently bound upload and download bodies). Implement 64-bit offsets, bounded frame/part buffers, multipart sizing up to 10,000 parts, range GET validation, ETag/version preconditions, cancellation/deadlines/backoff, ambiguous completion reconciliation, orphan cleanup, non-seekable/unknown-size staging, and measured heap evidence. Current multipart still accepts one `Bytes` body. 4. **Real S3 integration**: exercise a disposable S3-compatible service with desktop-created data, >1000-object pagination, custom HTTPS/path/virtual host, session tokens, redirects/TLS/errors, concurrent modification, and desktop readback of Android uploads. The current synthetic endpoint is empty, so network actions only prove terminal failure handling. 5. **File manager UI**: implement actual Local/Drive screens with directory/file rows, breadcrumb/back, size/type/date, sort, scoped search, multi-select, responsive/cancellable loading, upload/download/open/share, conflict choices (skip/replace/keep-both), path-safe recursive moves with re-encryption, partial move reporting, and foreign-object preservation. Current UI is a linear action list with limited selected-object behavior. 6. **Transfers/foreground execution**: add per-file/overall progress and queued/running/waiting/failed/completed states, retry/partial details, foreground long-transfer service/notification/cancel path, notification permission denial handling, Doze/network/low-storage/reboot/process-kill, Android 15 service timeout/checkpoint handling, and proper structured manifest service types/permissions. Current Worker only records `waiting-for-unlock` and performs no backup transfer. 7. **Backup/restore engine**: implement persisted named plans (sources/grants, labels, exclusions, destination plan IDs, schedule/constraints/conflict policy/history), hashed encrypted manifests, additive deletion semantics, honest completed/skipped/failed/unreadable/cancelled totals, source mutation, resume/recovery, fresh-unlock handoff, verified file/subtree/full restore, conflict/free-space handling, temp destination publication, and interruption safety. Current backup is a marker/report workspace, not a complete engine. 8. **Settings/platform**: add biometric/lock/network/charging/cache/profile settings and redacted diagnostics UI; test rotation, screen-off authorized transfer, Doze, notification denial, service timeout, current API and min SDK emulator, physical arm64 device, upgrade/reinstall/enrollment-change, stale callbacks, and all release-signature checks. 9. **Full test matrix**: add documented `android-test`/`android-integration` targets and run the complete provisioning, secret containment, envelope, v2, S3, file-manager, biometric, backup, restore, platform/build matrix in section 11 of the handoff. Every visible action must have a real emulator assertion and real operations must be byte/hash verified. 10. **Repository handoff**: run required desktop `make test`, security, native build/smoke gates plus Android build/smoke; create a feature commit in this worktree, push it, open a Forgejo PR targeting the default branch, poll CI with `fj -H git.jerboa.sh pr status ober/jerboa-drive#<number>`, fix all red checks, and report the direct PR URL. Never self-approve or self-merge. ### Suggested continuation sequence ```sh cd /Users/user/work/jerboa-drive-android-implementation git status --short sed -n '1,260p' ~/jdrive-for-android.md sh -n test/android-smoke.sh JDRIVE_ANDROID_PROVISION=1 \ JDRIVE_ANDROID_INPUT_JSON=/tmp/jdrive-android-profile.json \ JDRIVE_ANDROID_PASSWORD_FILE=/tmp/jdrive-android-password \ scripts/build-android.sh sh test/android-smoke.sh build/android/app/build/outputs/apk/debug/app-debug.apk ``` Use disposable synthetic credentials and a disposable prefix. Never inspect, print, commit, or publish real secrets. Keep all feature work under `~/work/`; leave `/Users/user/mine/jerboa-drive` unchanged. Only after the remaining gates are actually implemented and tested should the continuation agent commit, push, open the PR, and wait for human review.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ober/jerboa-drive#69
No description provided.