Skip to content

MOB-418: on-device self-test (MobWake.SelfTest) - #2

Merged
GenericJam merged 3 commits into
masterfrom
selftest
Oct 9, 2026
Merged

GenericJam merged 3 commits into
masterfrom
selftest

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Part of MOB-418 / epic MOB-410 (mob_ci nightly e2e).

Native call proving init

MobWake.SelfTest.run/1 makes one read-only call: :mob_wake_nif.platform_signal/0. No UI, nothing scheduled, no state left behind.

Platform Native path Answer Result
iOS ObjC NIF reads UIApplication.backgroundRefreshStatus (main thread) %{background_refresh_status: :available | :denied | :restricted} :pass (denied/restricted are the user's/MDM setting)
Android Zig NIF → JNI → MobWakeBridge.platformSignal() %{battery_optimized: bool, has_context: true} :pass (bridge registered + app context set)
Android same %{battery_optimized: bool, has_context: false} {:fail, "MobWakeBridge has no app context …"}
Android NIF, register() never ran / method-ID lookup failed {:error, :bridge_not_registered} {:fail, …}
Android NIF, no JNIEnv {:error, :no_jni_env} {:fail, …}
host .erl stub nif_not_loaded raised {:fail, "mob_wake_nif is not linked …"}
any other shape (empty map, other platform's map, …) {:fail, …}

No skip branch: nothing here needs hardware or the user.

Native fix (Android)

platform_signal/0 used to return %{} when the bridge wasn't registered or no JNIEnv was available — the same answer as a host without the NIF, so a broken host looked healthy. It now returns {:error, :bridge_not_registered} / {:error, :no_jni_env} (like the mob_location pilot, GenericJam/mob_location#8). Mob.Wake.status/1 folds those into platform_signal: %{}, so its public contract is unchanged. Compile-checked locally with zig build-obj -target aarch64-linux-android against mob 0.9.15's mob_erts.zig / mob_zig.zig.

Other

  • manifest: selftest: MobWake.SelfTest, mob_version: "~> 0.9"
  • mix.exs: {:mob, "~> 0.9 and >= 0.9.15"}, {:mob_dev, "~> 0.7.17", …}; mix.lock updated
  • tests: classifier classify/2 covers every branch, each asserted with Mob.Plugin.SelfTest.result?/1; host run/1 hits the stub → fail; manifest declares the self-test with no validator warning. 44 tests, 0 failures; format + credo --strict clean.
  • No version bump. Not to be merged until on-device verification (iOS sim + Android emulator).

One read-only :mob_wake_nif.platform_signal/0 call. iOS: any
background_refresh_status passes. Android: passes only with
has_context: true; the Zig NIF now answers {:error, :bridge_not_registered}
/ {:error, :no_jni_env} instead of %{} so an unregistered bridge can't look
healthy. Mob.Wake.status/1 folds those into %{} as before.
@GenericJam

Copy link
Copy Markdown
Owner Author

Review: reviewer agent (read-only claude -p, Codex rate-limited until 2026-10-09 02:54): MERGE.

  • Pass 1 (f6e5abf): MERGE, with 3 should-fix items: the ErlangError rescue was too broad; the status/1 fold was untested and had no catch-all; the manifest mob_version was coarse. Nitpicks: use erts.errorTuple, document map_build_failed, the bridge_not_registered message.
  • Fixes (9852971, e5d4673): catch only :error, :nif_not_loaded; Mob.Wake.normalize_platform_signal/1 (map as-is, anything else → %{}) with its own test; manifest comment says the real floor (>= 0.9.15) is enforced in mix.exs; uses erts.errorTuple; map_build_failed is documented in the NIF comment and the CHANGELOG; the message now names the bootstrap.
  • Pass 2 (9852971): MERGE. No regressions. The one remaining nitpick (the CHANGELOG map_build_failed line) is fixed in e5d4673.

CI tests is green on e5d4673 (run 37890356544). Local checks: 45 tests, 0 failures; format and credo --strict are clean; the Android NIF compiles with zig build-obj -target aarch64-linux-android against mob 0.9.15's erts/jni modules. Not merged: waiting for on-device verification.

@GenericJam

Copy link
Copy Markdown
Owner Author

Device verification (MOB-418 group B), blank host mix mob.new st_system --blank --local (mob/mob_dev master = 0.9.15 / 0.7.17), this branch as a path dep, mix mob.deploy --native + mix mob.selftest:

  • iOS simulator iPhone 17 (2CAF98B3): pass %{background_refresh_status: :available}
  • Android emulator Pixel_8_arm API (emulator-5554): pass %{has_context: true, battery_optimized: true}

Native call: :mob_wake_nif.platform_signal/0 (raw answer shown, captured over rpc on the same deployed app).

@GenericJam
GenericJam merged commit b889ff1 into master Oct 9, 2026
2 checks passed
@GenericJam
GenericJam deleted the selftest branch October 9, 2026 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant