Each synthetic user walks through four sequential OS permission gates in the order Camera → Location → Notifications → Contacts. At gate i (1-indexed by position actually asked, since a JIT flow skips straight to whichever permission the feature needs) the grant probability is:
P_i = clamp( P_base_i × M_timing × M_priming × (1 − fatigue)^(i−1), 0, 1 )
M_timing = 1.0 upfront blast at first launch (no context)
= 1.4 just-in-time, asked right when the feature is used
M_priming = 1.0 raw OS dialog, no explanation
= 1.25 a pre-permission "why we need this" screen shown first
fatigue = per-gate decay rate; each PRIOR ask in the same session
(granted or not) compounds the penalty on the next one
P_base is the OS-dialog baseline for that permission type (Camera 0.62, Location 0.55, Notifications 0.48, Contacts 0.35 — notifications and contacts are the two users say yes to least). The outcome at each gate is then a single Bernoulli draw at probability P_i: the user particle either passes through as a bright "granted" orb or drops to grey "denied" and continues to the next gate anyway — a denial doesn't stop onboarding, it just compounds fatigue for what follows.
- Timing — upfront blast asks all four permissions in a row before the user has used any feature; just-in-time only asks a permission the instant its feature is tapped, which published mobile UX research consistently finds raises opt-in rates.
- Priming screen — a short in-app explanation shown before the real OS dialog, giving the user a reason before the system prompt appears.
- Fatigue decay — how sharply each additional ask in the same session erodes the next one's odds; 0% means asks are independent, 50% means a user who has already been asked three times is heavily primed to just tap "Deny" out of habit.
- Weakest gate readout shows which permission type is currently converting worst across every user sent so far, live.
This is the mechanism behind why real apps re-order onboarding flows and delay permission prompts until the moment of relevance rather than front-loading them all on first launch.