Mob.Defect (mob v0.8.1)

Copy Markdown View Source

Entry points that convert what the framework's detectors produce into capsules on the defect bus.

The framework's detectors have their own shapes — an invariant violation is a Mob.Invariant.Violation, a divergence is the {:divergence, %{...}} a comparator returns. Rather than teach each detector to build a capsule, those detectors call the appropriate function here and this module supplies the fingerprint key, the owner, and the evidence shape.

Centralising the mapping is what keeps owner: :mob from being copied into five places, and what makes the fingerprint key for the same kind of defect identical across detectors — the whole point of a fingerprint is that a divergence detected on iOS from mob_dev and the same divergence detected on-device from a fallback path land on the same triage item.

Nothing propagates on the return path

Every function here returns the capsule it built, but the emit is a side-effect on the bus and the caller does not need to do anything with the return value. That matches the shape of Mob.Agent.Receipts.record/1 and lets a caller drop the emit onto an existing pipeline without restructuring around a result.

Summary

Functions

Emit a defect for a differential-comparator divergence.

Emit a defect for a confirmed invariant violation.

Functions

emit_divergence(map, opts \\ [])

@spec emit_divergence(map(), keyword() | map()) :: Mob.Defect.Capsule.t()

Emit a defect for a differential-comparator divergence.

Real entrypoint, pending an in-tree caller. Mob.Differential.compare/3 is a pure comparator; the caller that runs it — currently mob_dev, via MobDev.Differential.run/3 — invokes this after a :divergence result to put the class onto the bus. A follow-up mob_dev change wires that up after this ships to Hex; nothing in mob itself calls this yet.

Owner is :mob — the differential comparator asserts one design, both platforms, which is a framework-level promise. kind: :divergence.

The fingerprint key includes the fixture (so the same divergence in two fixtures reports separately), the reason (:type, :label, :frame, :child_count), and the path to the diverging node. The ios and android values are on evidence, not on the fingerprint key — a fixture's divergence in kind (say, always :type at [0, 2]) is the same class even if the tree values change slightly across releases.

emit_invariant_violation(v)

@spec emit_invariant_violation(Mob.Invariant.Violation.t()) :: Mob.Defect.Capsule.t()

Emit a defect for a confirmed invariant violation.

Owner is :mob — invariants are checks the framework makes about itself, and by construction they cannot fail for the app. kind: :invariant.

The fingerprint key is %{invariant: name, screen: screen_module}, so a violation of the same invariant on the same screen groups across occurrences, and the same invariant on a different screen — a leak class that appears in two places — reports separately.