fix(deploy): verify iOS BEAM overrides - #50
Merged
Conversation
…gression Two adversarial passes plus a device session on a physical iPhone SE. The mechanism in this PR works — I deployed through it, pulled Documents/otp/ <app>/<app>.beam back off the device with an independent devicectl call and confirmed it byte-identical to the compile output, and the app booted clean. These are the fixes around it. BLOCKER 1 — every deploy, every platform. runtime_lib_names/0 stopped seeding the expansion with project_app, so the project's own .app was never read. A dep declared `runtime: false` and opted back in via `extra_applications:` — the documented idiom, where extra_applications deliberately overrides the flag — was silently dropped from the push. Reproduced against a real fixture project: master resolves ["lazy_lib", "proj"], this PR resolves ["proj"]. On device the app boots and dies with undef on first use — the same failure class this PR exists to eliminate, relocated from the bootstrap to a dependency. The removal was not gratuitous: seeding also leaked only: :dev deps into the runtime set, contradicting the moduledoc. So expand first, then subtract the deps we know are dev-only, keeping anything the project re-declares in extra_applications. Fixture now resolves ["lazy_lib", "proj"] again with mob_dev (only: :dev) correctly absent. Worth noting one trap in the fix itself: extra_applications lives on the project module's application/0 callback, NOT in Mix.Project.config/0. Reading it from config yields [] and silently subtracts the very libs being protected — which is what my first attempt did, caught by the fixture. BLOCKER 2 — the destructive copy has no rollback. --remove-existing-content makes a mid-transfer failure worse than the bug being fixed: mob_beam.m:317 prefers Documents/otp/<app> on directory EXISTENCE alone, so a partial override shadows the complete signed bundle and the next Springboard launch dies with undef, even though the deploy correctly skipped the restart. There is no clean repair — devicectl has no delete verb, and pushing an empty directory leaves it present and therefore still preferred, which is strictly worse. So the failure path now states the override is incomplete and names the two recoveries that do work. Verified mob_beam.m and the devicectl verb list directly. Also: - Mix.Project.compile_path/0 raises at an umbrella root, where the old _build/dev wildcard degraded. Now raises mob's own "umbrellas not supported" message. - The WiFi-only-device throw sat OUTSIDE the try, so it escaped deploy_ios/3 and deploy_all/1 (neither catches) and aborted the whole run with a raw ** (throw), losing the summary for devices that already succeeded. Returns now. - Staging dirs are PID-qualified; unique_integer restarts low in a fresh VM, so two concurrent deploys could collide and one's cleanup delete the other's. - validate_ios_override distinguishes a MISSING staged bootstrap from a MISMATCHED one; the old message wrapped enoent inside "does not match active compile output" and pointed at the wrong file. The test asserted that misleading string, so it was pinning the confusion. - runtime_lib_names/0 now has coverage. It is the function that decides the push set and had none — every existing test hand-builds the MapSet it produces, so this regression stayed green across 2146 tests. Verified: 2148 tests, format, compile --warnings-as-errors, credo --strict, and a real deploy to the physical iPhone that boots and renders. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GenericJam
added a commit
that referenced
this pull request
Aug 28, 2026
`mix test` writes an `android/` scaffold into the repo root — mob_dev's own generators run against cwd, and the suite doesn't redirect them to a tmp dir. Those 8 files (including a 63KB gradle-wrapper.jar and ~98KB of logo PNGs) were untracked-but-not-ignored, so #50 swept them in while adding nothing Android-related. They don't reach Hex (the package ships lib/priv only, verified with `mix hex.build --unpack`), and nothing in this repo reads them — every `android/...` path in lib/ resolves against a *target app's* root, not ours. Removed and ignored. The ignore stops recommits; it doesn't fix the leak. The suite should generate into a tmp dir instead of cwd — left for its own change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
GenericJam
added a commit
that referenced
this pull request
Aug 28, 2026
…eet wiring Deploy fixes (#50): BEAM discovery now follows Mix.Project.build_path/0 and compile_path/0 rather than a hardcoded _build/dev, so a non-dev MIX_ENV or custom :build_path is honoured — projects on build_per_environment: false previously pushed no dependency BEAMs at all. Physical-iOS overrides are replaced rather than merged and the transfer is verified before restart. Also restores traversal of the project's own .app so deps reachable only via extra_applications stop being silently dropped, plus umbrella, WiFi-device and concurrent-staging error handling. Doctor (#48): warns when a project still carries the pre-MOB-104 sheet dismissal wiring, which delivers {:tap, tag} where the contract and iOS deliver {:dismiss, tag}. Release review of v0.6.27..HEAD: 2148 tests pass, format/credo --strict/ warnings-as-errors clean. Security scan exits 0; its 2 HIGH findings are bundled-versions manifest drift in locally cached mob OTP tarballs, untouched by this diff and not owned by this repo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why
Physical iOS prefers Documents/otp/ over the complete signed bundle. An incomplete or stale override can therefore shadow a valid native install and fail at boot with undef for :start/0. A successful devicectl transfer previously had no completeness postcondition.
This change makes the active compiler output the source of truth and proves active bootstrap -> staging -> remote bootstrap identity. A failed or mismatched transfer returns an error and does not restart the app.
Verification
No Hex package was published and no device was used for this branch. Physical verification can be performed from the PR before release.