Runtime diagnostics that run inside a Mob app's BEAM. Designed to be invoked via Erlang RPC from a developer's machine to inspect the actual state of a deployed app.
Pairs with mob_dev's tooling — mix mob.verify_strip calls into
verify_loaded_modules/0. Kept in the mob library (not mob_dev)
so the functions are present in every shipped app, not just at build
time on the developer's machine.
Don't expand the API surface here without thinking — anything added is permanently shipped to every Mob app and a permanent target for remote-execution if dist credentials leak.
Summary
Functions
Snapshot of what's currently loaded in the running BEAM, plus what's shipped-but-never-loaded (the empirical strip candidates).
Force-load every .beam file under the running app's OTP tree and
report any that fail. Used by mix mob.verify_strip to validate
that an aggressive strip didn't remove a module something else
needed.
Types
@type load_report() :: %{ total: non_neg_integer(), loaded: non_neg_integer(), failed: [load_failure()], elapsed_us: non_neg_integer(), otp_root: String.t() | nil }
@type loaded_snapshot() :: %{ loaded: [module()], loaded_count: non_neg_integer(), shipped_count: non_neg_integer(), unloaded_in_bundle: [module()], otp_root: String.t() | nil, captured_at: DateTime.t() }
Functions
@spec loaded_snapshot() :: loaded_snapshot()
Snapshot of what's currently loaded in the running BEAM, plus what's shipped-but-never-loaded (the empirical strip candidates).
In interactive mode (Mob's default), a module is loaded only when something calls into it. So the loaded set after a representative user session is "what the app actually needs." Anything in the bundle but not in the loaded set is a strong strip candidate.
Better than tracing for our purposes: zero overhead, no rate-limit worries, no risk of mailbox-overflowing a busy app.
Workflow:
- Deploy the app
- User exercises every flow they care about
- RPC
Mob.Diag.loaded_snapshot/0from a Mix task - Cross-reference
:unloaded_in_bundlewith the static audit: shipped + statically-reachable + never-loaded = high-confidence strip candidates.
Caveats: a flow that wasn't exercised won't show up. Run after a thorough session, not after just opening the app.
@spec verify_loaded_modules() :: load_report()
Force-load every .beam file under the running app's OTP tree and
report any that fail. Used by mix mob.verify_strip to validate
that an aggressive strip didn't remove a module something else
needed.
Walks all entries in :code.get_path/0, finds the OTP root from
the first matching .../otp/lib/... path, and enumerates .beam
files under it.
Returns load_report/0. Failures usually mean a stripped lib
contained a transitive dependency of a kept module.