Skip to content

MOB-399: slim builds never strip an OTP lib the app needs - #124

Merged
GenericJam merged 1 commit into
masterfrom
fix/slim-keep-required-otp
Oct 6, 2026
Merged

GenericJam merged 1 commit into
masterfrom
fix/slim-keep-required-otp

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Fixes MOB-399.

mix mob.release --android (default slim) stripped inets from the bundled OTP tree regardless of the app. Operator's release then logged plugin :mob_ash: OTP application failed to start ... {:inets, {~c"no such file or directory", ~c"inets.app"}} (ash → igniter → inets). Debug deploys ship the full tree, so only release broke.

Rule: a slim pass never strips an OTP lib any shipped app lists in its .app applications/included_applications, transitively.

  • MobDev.OtpRequiredApps: closure of MobDev.HotPush.runtime_lib_names/0 through the bundled OTP tree's lib/*/ebin/*.app.
  • Android release: OtpAssetBundle.build/3 takes :required_apps (precedence: defaults − required + :strip_extra_prefixes − :keep_prefixes), returns :kept_required, which mix mob.release logs.
  • iOS release script: skips names in MOB_SLIM_KEEP_LIBS (set by Release.build_ipa/1).
  • mix mob.deploy --slim: OtpAudit.Slim.compute_strip_set/1 takes :required_libs (after baseline/audit, before :drop_libs/:keep_libs).
  • HotPush's _build traversal follows included_applications too (shared .app reader).

Tests: otp_asset_bundle_test (transitive + included_applications kept, unrelated libs still stripped), slim_test (:required_libs precedence).

Proof on Operator: see the comment below (slim release AAB → universal APK on an emulator).

The Android release's default slim pass dropped inets (and the rest of its
fixed list) regardless of the app, so Operator's release failed to start
mob_ash: {:inets, {~c"no such file or directory", ~c"inets.app"}}.

MobDev.OtpRequiredApps computes the closure of the runtime dependency set
(HotPush.runtime_lib_names/0) through the bundled OTP tree's .app files
(applications + included_applications). The Android release
(OtpAssetBundle :required_apps), the iOS release script (MOB_SLIM_KEEP_LIBS)
and mix mob.deploy --slim (OtpAudit.Slim :required_libs) subtract it from
their strip sets. HotPush's _build traversal follows included_applications.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@GenericJam

Copy link
Copy Markdown
Owner Author

Proof on Operator (scratch clone of ~/code/operator at 849a7a7, mob_dev via path to this branch):

mix mob.release --android (default slim):

kept OTP libs the app needs (not slimmed): inets
5929 files, 306MB → 55MB
AAB: .../android/app/build/outputs/bundle/release/app-release.aab

otp.zip contains lib/inets-9.7/ebin/inets.app. Universal APK via bundletool build-apks --mode=universal (release keystore): 125,901,777 bytes. Installed on emulator-5562 (sdk_gphone64_arm64), cold launch, logcat:

I Elixir  : [mob] plugin :mob_ash: OTP application started
I Elixir  : [dyn] boot: %{status: :proven, mode: :normal, ...}

24 plugin OTP apps started; 0 failed to start lines (before: plugin :mob_ash: OTP application failed to start ... {:inets, {~c"no such file or directory", ~c"inets.app"}}). The repeated erl_prim_loader ... eacces. Target: .. Function: list_dir lines are pre-existing noise also seen on debug deploys (on-device compiler code path), unrelated to slimming.

@GenericJam

Copy link
Copy Markdown
Owner Author

Review: reviewer subagent (Codex rate-limited until 2026-10-09 21:14): MERGE. No blocking or should-fix findings; nitpicks: no test of the HotPush included_applications traversal end to end; iOS keep set uses Mix.Project.build_path while the script ships _build/dev (pre-existing).

@GenericJam
GenericJam merged commit 871c727 into master Oct 6, 2026
6 checks passed
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