0.8.2
Added
-
Post-mortem collection —
Mob.PostMortem+
Mob.PostMortem.BeamCrashDump(MOB-158, phase 1). The framework
now picks up the crash dumps the BEAM leaves behind on disk and turns
each into aMob.Defect.CapsuleonMob.Defect.Bus(kind:
:beam_crash, owner::mob).Mob.PostMortem.sweep/0andMob.PostMortem.sweep/1do a one-shot
scan of default and caller-supplied paths. Nothing runs
automatically — an app opts in from itson_start; a developer or CI
can call it from IEx. Same discipline the rest ofMob.Defect
follows: mob owns the format and the bus, never becomes the
collector.Mob.PostMortem.BeamCrashDumpscans forerl_crash.dumpfiles,
reads a bounded 8 KB header (slogan / system version / taints /
atoms / dump version), computes a sha256 for artifact identity, and
never touches the dump body. Dumps stay on disk for offline
inspection withcrashdump_viewer.Mob.PostMortem.Registry
records emitted ids in a public ETS table so a re-sweep is a no-op;
registry state is intentionally not persisted across BEAM restarts,
because a fresh BEAM sweeps back into a fresh bus.Fingerprint is the normalized slogan: binary literals (including
ones truncated by the 8 KB header cut-off) and long numeric runs
that are the printable form of the same are stripped, so two
{badarg, ...}crashes onio:put_chars/2with different embedded
payloads share a triage row instead of each opening one.Severity is picked from the slogan: allocator panics
(eheap_alloc,binary_alloc,ets_alloc,sl_alloc,
driver_alloc,fix_alloc,std_alloc) and boot-time crashes
(Kernel pid terminated,Runtime terminating during boot) are
:fatal; a literalnormalexit is:info; anything else is
:critical. -
iOS MetricKit ingest for
Mob.PostMortem.IOS(MOB-179). Replaces
the phase 1 scaffold.Mob.PostMortem.sweep/0on iOS now attaches an
MXMetricManagerSubscriberon first call (lazy — no work for apps
that never opt in), buffers OS-delivered payloads in a bounded native
queue (32 entries, oldest-dropped on overflow), and drains them into
Mob.Defect.Capsules on each subsequent call. Ships in release —
MetricKit is the whole reason MOB-158 exists.Payload → kind mapping:
MXCrashDiagnostic→:native_crash/
:fatal;MXHangDiagnostic→:anr/:critical;
MXCPUExceptionDiagnosticandMXDiskWriteExceptionDiagnostic→
:perf_regression/:warning. (These are the individual
diagnostics; theMXDiagnosticPayloadcontainer that carries them
is what MetricKit hands the delegate.)Fingerprint groups a crash by (kind + top-frame binary + top-frame
offset) so the same crash across launches becomes one triage row.
Redaction: MetricKit call-stack payloads carry only mangled symbols,
binary UUIDs and image names — safe identifiers, no user data. The
fullMXDiagnosticPayload.JSONRepresentationrides on evidence,
bounded by the capsule's existing truncation.iOS 14+ required (
didReceiveDiagnosticPayloads:is iOS 14+). Older
builds hit the fallback path and return[]. Android's stub NIF also
returns[]—ApplicationExitInfois a separate ticket (MOB-180). -
Android ApplicationExitInfo ingest for
Mob.PostMortem.Android
(MOB-180). Replaces the phase 1 scaffold.Mob.PostMortem.sweep/0
on Android now pulls the OS-held history of process exits via
ActivityManager.getHistoricalProcessExitReasons(API 30+), filters
against a persistent marker at
<filesDir>/mob_post_mortem_appexit_marker.txtso each exit emits
exactly once across boots, and turns each new entry into a
Mob.Defect.CapsuleonMob.Defect.Bus.Reason code → kind mapping:
REASON_CRASH/REASON_CRASH_NATIVE
/REASON_SIGNALED→:native_crash/:fatal;REASON_ANR→
:anr/:critical;REASON_LOW_MEMORY/
REASON_EXCESSIVE_RESOURCE_USAGE→:oom/:fatal;
REASON_USER_STOPPED/REASON_USER_REQUESTED/REASON_EXIT_SELF
/REASON_DEPENDENCY_DIED/REASON_OTHER/REASON_FREEZER→
:user_kill/:info.Fingerprint groups by
(kind + process_name + reason_code)— the
same class of exit for the same process across boots becomes one
triage row. The emitted capsule carries reason code, pid,
timestamp, process name, and the OS-generated description string.
Trace file contents (an ANR's stack text) are NOT included this
phase — they can carry app strings and need the same discipline the
receipt module documents before they can safely reach the bus.Implementation is pure Zig JNI in
android/jni/mob_nif.zigrather
than aMobBridge.kt.eextemplate addition. Every existing mob
app gets the feature the moment they bump mob, with no template
refresh dance. See
decisions/2026-09-11-appexit-native-jni-not-bridge.md. iOS
registers a stubnif_post_mortem_android_drainreturning[]so
the sharedmob_nif.erlNIF list resolves on both platforms.