Appearance
ADR-0042: Escalation ships with the app shell and is reachable everywhere; the trigger only saves a tap
Status: Accepted — amends ADR-0031 and ADR-0041, both of which stand Date: 2026-09-10
Decisions
D-98 A Curated Escalation ships in the app shell, precached and versioned with it, not in the Corpus store
It is curated and reviewed exactly as D-95 requires. What changes is where it lives: with the service-worker-precached shell (D-39), outside the Corpus and outside the atomic Corpus replacement. Updating it is a deploy, not a sync.
D-99 The Escalation Trigger hands the user to the Curated Escalation, which needs no Chemical Record
Identification is offered as the next step and is never a precondition. Routing continues rather than being cancelled: any span the router finds appears beneath the escalation, never displacing it. The trigger short-circuits blocking, not answering.
D-100 Escalation is reachable from every surface at all times, and the Escalation Trigger is an accelerator rather than a path
A missed trigger costs a tap, not the call. No phrase list may be load-bearing for reaching a phone number.
What each amendment touches
- ADR-0041 — D-95's ruling stands: escalation text is curated, reviewed, authored, displayed verbatim with its origin visible, and limited to a closed set of acts. Only its storage clause moves, from the Corpus to the shell. D-96's persistent hotline on both emergency flows stands and is widened by D-100 to every surface. D-97 is untouched.
- ADR-0031 — D-70 stands: the trigger fires client-side ahead of any network call, and Routing still never selects a branch. What D-99 supplies is the destination D-70 left as "the surface", and the clarification that "before" fixed an order rather than a suppression.
- ADR-0032 — D-74 is not amended. It is restored. This ADR exists because D-95 broke it.
Context
ADR-0041 broke D-74 the day it was written, and this ADR is the repair.
D-74 says escalation, hotline 1669 and the standing statement remain available with no Corpus at all, "None of them is a Corpus read." When that was written, escalation text was unspecified product furniture, so the claim was true. ADR-0041 gave it an author — correctly — and in doing so filed it as a Corpus artifact. The Corpus is evictable; under D-88 a missing sentinel means Corpus Unavailable. So escalation text would have been unavailable precisely in the case D-74 promises it survives: an evicted store, no signal, during a spill.
Giving a thing an author is a question about accountability. Where it is stored is a question about availability. ADR-0041 answered the first and silently answered the second, and the two have opposite right answers here.
The trigger was carrying weight a string match cannot carry. The Escalation Trigger is a curated Thai and English phrase list. Myanmar nationals are common in Thai automotive plants, and a Handler typing an eye-exposure phrase in Burmese matched no trigger, hit nothing in the lexical Floor, and received Not Stated with no hotline in sight — because the persistent 1669 was specified on the Spill Response and First Aid flows, not on the Conversational surface.
Adding Burmese would not fix the class. Any phrase list is incomplete: another language tomorrow, a typo always, a Handler typing one-handed. The fix is to stop the list being the path.
D-70 left its destination unwritten. "The user is handed to the surface" — which surface? From Home with nothing identified, First Aid is Section 4 of a Chemical Record that does not exist. The options were an identification prompt, an empty card, or the last record from history. That last one is the recency cache §4 rejected by name, on the grounds that the emergency case is the unfamiliar chemical.
D-95 made the destination answerable for the first time by giving escalation content of its own. Before that it existed only as furniture on top of a record.
Decision
Escalation text ships with the shell, so it is present whenever the app is. The trigger hands the user to it directly, with no record required and no identification in the way, while routing continues underneath. Escalation is reachable from every surface, so failing to fire the trigger costs a tap rather than the call.
Rejected options
- Keep the Curated Escalation in the Corpus and narrow D-74 — rejected. D-74's argument is that a phone number is more use during a spill than a blank screen, and that does not weaken because we later decided to review the phone number's wording. Narrowing it would leave the app with nothing to show at the one moment it was designed to have something.
- Store it in both places — rejected. Two sources for escalation text can disagree, which is the drift ADR-0041 exists to remove.
- Land the trigger on an identification prompt — rejected. US-58 exists to put 1669 in front of a Handler immediately, and US-26 already says a Supervisor wants First Aid without navigating a Chemical Record while someone is affected.
- Land on the last record in history — rejected as the recency cache by another name.
- Cancel routing when the trigger fires — rejected. A Handler on the phone to 1669 being read chemical-specific first aid is strictly better than one who has to start over, and the escalation was never waiting on it.
- Add Burmese and other languages to the trigger list, and rely on that — rejected as a fix. It is worth doing as a should, contingent on who works in the Study Area, but each addition creates the illusion the list is now sufficient. The list must never be why the design is safe.
- Detect an unsupported language and say so — rejected. It spends the emergency telling someone their language is not supported and still does not give them the number.
This ruling may not be re-decided
If a change contradicts this ADR: stop and raise it. Do not implement over it.
Specifically: do not move the Curated Escalation into the Corpus snapshot because it feels like curated data — it is, and it still ships with the shell; do not make any surface's escalation route conditional on a Chemical Record, a Corpus, or a network; and do not let a future feature treat the Escalation Trigger as the mechanism by which a person reaches help. It saves a tap.
Consequences
What becomes easy. Escalation now survives an evicted Corpus, an unmatched phrase, a language nobody anticipated, and a surface nobody thought to put a hotline on. Each of those was a separate hole and they close together.
What becomes hard. Escalation text is versioned with the shell, so changing it is a deploy rather than a sync — slower to change and harder to get wrong. For three sentences that must never be absent, that is the right trade.
What is now checkable. Two assertions that were not available before: with the Corpus removed, the escalation route renders on every surface; and with the trigger disabled entirely, escalation is still reachable from every surface in one action. The second is the one that keeps the trigger honest.
A note on how this was found. ADR-0041 was written earlier the same day, and this defect was found while working the ticket that ADR-0041 unblocked. The mechanism is the same one this repository keeps rediscovering: a decision answered the question it was asked and silently answered a second one nobody noticed it was answering.
Coverage
| Upstream | Landed in | Evidence | Note |
|---|---|---|---|
| R-14 | D-100 | the hotline is in the source's design; this makes it reachable everywhere rather than on two flows | ADR-0006 landed R-14 in D-08; ADR-0041 widened it to both flows |
| R-23 | D-100 | the four roles include Handlers who may read neither Thai nor English fluently | the trigger's phrase list cannot be completed for them |