Alarm fatigue
Escalation is budgeted rather than judged screen by screen. This page sets the ceiling, names who owns it, and says what an interface loses by overspending it.
What this means
Alarm fatigue is the best-documented failure mode in clinical technology. In hospitals, monitors generate enough alarms that competent, trained and motivated staff stop responding to them, silence them pre-emptively, or tune them out entirely. Each alarm is individually reasonable and the aggregate is noise, and people have been harmed by alarms that fired correctly into a room where nobody was listening any more. The evidence for alarm fatigue as a documented problem, and the limits of its transfer to a consumer app, are set out under "Why (evidence)" below.
Consumer health apps reproduce the pattern at lower stakes, until the stakes are not low. A ring closes, a streak breaks, a weekly report is ready, a device needs charging, a reading is a little high, a subscription is expiring, and each of these arrives with the same visual weight and the same buzz. The reader learns from the repetition that this app's notifications do not require action, and that is the expectation they bring to the alert that does. How many low-value alerts that learning takes is something we have not measured.
Each individual decision to escalate is defensible on its own terms, and fatigue is a property of the aggregate rather than of any one decision. No single screen's review can detect it, which is why opsinjs governs escalation with a budget rather than with a per-screen judgement.
The rule
Escalation is a finite, explicitly budgeted resource. Every surface that escalates must be spent against a stated budget, and the budget is enforced at the screen and at the session rather than at the component.
Escalation budgets by scope
The budget sets five ceilings across four scopes, two of them at the screen.
| Scope | Ceiling | Failure mode it prevents | Basis |
|---|---|---|---|
| One screen | At most one urgent surface | Two urgent surfaces on one screen ask the reader to decide which of them to act on first, and a lay reader has no basis on which to rank two urgent claims. | Follows from the triage argument; chosen rather than derived. |
| One screen | At most two attention surfaces | Past two, the reader's scan is divided across the set, and we expect each surface to be read less closely than it would have been alone. | A judgement about scanning rather than a measurement. |
| One session | At most one interruptive modal that the reader did not initiate | An interruption the reader did not ask for stops the task they opened the app to do, and it is the most expensive item in this budget. | A judgement about goodwill. |
| One day | At most one non-clinical push notification | A push arrives at a moment the reader did not choose, so a low-value one spends the attention that the next clinical one will need. | |
| Any surface | urgent is reserved for clinical urgency | A commercial or product problem rendered as urgent is indistinguishable from a clinical one at the moment the reader sees it. |
Two of the five ceilings carry no entry under Basis. The daily limit on
non-clinical push is administered by
Notifications and off-screen alerts,
which owns scheduling and grouping, and the reservation of urgent for clinical
urgency is fixed by the status vocabulary on
Clinical status semantics rather than chosen
here.
The escalation ladder
The ladder has five rungs in a normative order, and a surface moves up a rung only when the rung below it has been used and has proved insufficient, never because a rung looks more important.
| Rung | Surface | Addressed to | Blocks the reader | Condition for using it |
|---|---|---|---|---|
| 1. Ambient | A StatusPill on the value itself | Nobody in particular; it is a property of the value | No | The default rung, available wherever a status is shown |
| 2. In-place | A CareCard in the flow of the screen, next to the value it is about, carrying a named action | The reader of that value, at the point it appears | No | Rung 1 is in use and the value needs a named action travelling with it |
| 3. Screen-level | An AlertBanner at the top of the screen | The reader of the screen | No | Rung 2 is in use and has proved insufficient |
| 4. Interruptive | A modal or a sheet the reader must dismiss | The reader, at the moment they arrive | Yes, until it is dismissed | The message is time-critical and cannot wait for the reader to reach it |
| 5. Off-screen | A push notification | The reader while the app is closed | It interrupts outside the app rather than blocking inside it | Rung 4 is in use and has proved insufficient, and the message is never a first attempt; it is the most expensive rung on the ladder, and its delivery is governed by Notifications and off-screen alerts |
Rules that close the routes around the budget
Every ceiling above can hold while escalation is still overspent, and three further rules cover those cases: one fact carried on several rungs at once, a surface that is never withdrawn, and a surface re-raised on a timer.
- No parallel escalation. The same fact does not get a pill and a card and a banner at once. One fact occupies the highest rung it justifies, and the surfaces below that rung are suppressed.
- De-escalation and its announcement. When a value returns to
steady, the surface that escalated it is removed, and the reader is told once that it has gone. - The re-raise condition. Repeating an unchanged
attentionbanner on successive opens does not increase the chance of action, and it reduces the response rate to later banners. A surface re-raises on a change of state rather than on a timer.
Why (evidence)
Applying it
Do
Suppress the lower rungs when a higher one fires. If an AlertBanner is
already telling the reader their blood pressure needs checking, the tile
below shows a watch pill rather than a second banner.
Don’t
Let every component decide its own urgency independently. No component-level review sees the aggregate of the screen, so a set of individually reasonable decisions produces an unreadable screen that passes every one of those reviews, which is why enforcement sits at the screen and at the session.
Do
Track alert volume per user as a product metric with a target ceiling, the way you track error rate. A stated ceiling is what makes the aggregate reviewable after release, where a screen-level review cannot reach.
Don’t
Measure alerts by click-through alone. Click-through on a newly introduced alert measures its novelty as much as its value, and it does not show what happens to the response rate as the same alert repeats unchanged.
Do
Tell the reader when something has resolved: "Your blood pressure readings are back in your usual range." The sentence states both that the surface has gone and why it has gone, and the de-escalation rule above requires it to be said once rather than repeated.
Don’t
Remove the banner without saying anything. A reader who cannot tell whether
the value returned to steady or the app dropped the surface has no reason
to treat the next banner as reliable.
Do
Give engagement, retention and commercial messages their own quiet channel that is visually and structurally separate from the clinical one, so that a reader can tell which channel a message arrived on before reading it.
Don’t
Borrow the clinical channel for a streak reminder because it gets noticed. The attention it borrows is the attention the next clinical alert on that channel will need, and the reader has no way to tell the two apart in advance.
Sound and haptics carry their own budget, and it is smaller than the visual one because a sound or a vibration cannot be skimmed past and reaches whoever is nearby as well as the reader. See Sound and haptics and Motion in health UI.
Components that implement this
AlertBanner is specified to expose the budget rather than hide it: a screen
that mounts a second urgent banner should fail loudly in development instead of
rendering two. That behaviour is a specification and not shipped code. The
component itself ships and does warn in development about several
things, including a missing heading level and an attention or urgent banner
with no action, but nothing counts banners across a screen, because a component
cannot see its siblings. The budget is enforced by review today, and the
specified behaviour is what the component will be held to when something can
enforce it.
What this does not cover
Four topics fall outside this page. Three of them are covered elsewhere in the corpus, and continuous clinical monitoring is outside opsinjs altogether.
| Excluded topic | Why it is out of scope | Where it is covered |
|---|---|---|
| Which readings deserve to escalate at all | The decision is a clinical threshold, and opsinjs does not set clinical thresholds | Clinical status semantics |
| Notification scheduling, quiet hours and OS-level grouping | Delivery mechanics are governed separately from the ceilings this page sets | Notifications and off-screen alerts |
| The interaction pattern for staged escalation | This page fixes the ceilings and the ladder, while the sequence, the wording and the components belong to a pattern | Alert escalation |
| Clinical monitoring systems | Continuous monitoring with alarms is a regulated domain with its own standards, and it requires an analysis this page does not attempt |
Updates to this page
Last read through against the system on 2026-09-02. Due for review every 6 months; expiry is reported by pnpm run check:freshness.
Category identity
The six metric families, the four roles each one exposes, and the meanings a category colour is forbidden to carry.
Motion in health UI
Motion may confirm an action, orient a reader and soften a transition. It may never carry urgency, meaning or a value, because a reader can miss it entirely.