0145 — An emergency always escalates, whatever we know about the location
- Status: Accepted (Gera, 2026-10-19). Fede to acknowledge the reversal of his 2026-10-09 ruling; if he objects, this returns to Proposed until he and Gera settle it. Amended by ADR-0149 (Gera, 2026-10-29): the 2026-10-20 amendment below ("every emergency on a call pages on-call after the call") is superseded — the chain now starts mid-call at the moment of confidence with an interim notice, the work order follows after the call, and a caller can cancel. Decisions 1–7 stand.
- Date: 2026-10-19
- Deciders: Gera (rulings, 2026-10-19, in chat: always escalate; confirm the unit, never ask; same on-call chain; any active leak is an emergency). Fede to acknowledge, because this reverses his 2026-10-09 ruling.
- Supersedes: Fede's 2026-10-09 ruling, "with no home we cannot call people or do an emergency", as encoded in the maintenance voice prompt (
agents/clara/lib/voice-agents/maintenance-tenant.ts:163,191,218,223,232), the server refusal for calls with no building (handle-escalate-to-human.ts:371-389), the after-call refusal (voice-postcall-intake.ts:503-510) and the header ofmatch-home-answer.ts. - Plan: ws-emergency-rearchitecture, workstream A
Context
On 2026-10-18 a Western Slope resident called about a garbage disposal leaking a lot of water. The
address she gave was a real unit in one of the company's buildings, but the unit's street differs from the building's,
and the voice address lookup read only building addresses (fixed for that one lookup by #20946). With
no confirmed home, the prompt allowed only a callback note. The emergency tool was never called, no
on-call call, text or email went out, and the team got a plain "
Production logs (2026-10-19) show the after-call chain never ran because the classifier did not return "emergency". Why is unknown. Replaying the exact production input with Western Slope's emergency list gives "emergency" 20 out of 20, and the list loads correctly against production with the same arguments, so an earlier theory that the list never reached the classifier was retracted. What is left is model variance or something unobserved, and it cannot be settled because the verdict was never recorded. That is why decision 5 (a server-side content check that does not depend on the cause) comes right after the after-call start, and why decisions 6 and 7 require the verdict, the list lookup and every failed read to be recorded and alarmed.
The location gate made one failure (an address we could not place) silence a second, unrelated one (a leak nobody was told about). Western Slope's property manager expected an emergency response.
Decision
- Location is a field on the alert, not a gate. If the content is an emergency (the company's
list, or the built-in life-safety rules), the emergency path runs: the on-call chain starts and the
emergency notices go out, whether the location is confirmed, a best guess, or unknown.
The chain must be startable from the company and the dialled line's phone number alone, with
no property id. Today three places require one (
voice-postcall-intake.ts:508,handle-escalate-to-human.ts:371, and the hunt ticket'spropertyIdinemergency-alert-chain.ts:667); each is changed to fall back to the line's company. - Recognized callers are confirmed, never asked. When the caller's unit is known (from the phone,
or the line's building has one unit), Clara confirms it (
This is at your unit, <unit>?) and does not ask for an address. If the caller names a different place, nothing is blocked. The work order goes to the unit on file with a note, "caller said it's at X", and the alert carries both the unit on file and the place the caller named, so the technician is never sent to only one of two doors. - Unrecognized callers are asked once, then given a best guess. Order: phone match, name plus street, closest home from the address index (ADR-0147), the line's building. A best guess is never a reason to wait. A "likely" result with two candidate homes never files a work order on its own: the alert carries both, and the work order waits for a person or a confirmed answer.
- Every alert states its location confidence. Each alert carries
locationConfirmed, the unit as "probably, not confirmed" when unconfirmed, the address as the caller said it, and why we think so. The SMS, email, call script and #emergency post all render it. The alert goes to the same on-call chain as any emergency (live on-call first where the company has it, then the saved list). An unconfirmed location adds no extra recipients and removes none. - The server checks content, not only the voice model's rating. Note text from calls, texts and emails runs through the classifier's emergency rules (the classifier, never a keyword list: a keyword rule paged on a water bill), and an emergency verdict starts the chain even when the model chose a lower urgency.
- Every fail-closed read on the chain path alarms. The company-switch read
(
company-switch.ts:57-66) and the will-it-ring check (emergency-alert-chain.ts:155) fail closed with only a log warning. The emergency-list read (emergency-definition-read.ts) has three branches: its catch at :114 warns; the success path where no list resolves (:112, returning null) logs nothing; and the outlook catch at :118 is swallowed. The quiet branches are the ones to cover. Each read that stops or weakens a chain must raise the same ops alarm as "nobody was called" (alertOpsNobodyCalled), and the verdict and whether the company's list resolved are recorded on the dispatch log. A quiet failure on this path is a missed emergency. - A missed-emergency detector runs continuously. An emergency verdict, or a note marked urgent, with no chain start within a few minutes raises an alarm. Zero emergency notices across every real company for 60 days should have been red; this makes it red.
- Any active leak is an emergency. An active leak is water escaping from plumbing, a fixture, an appliance or the roof that is still running, or is pooling or spreading onto a floor, ceiling or wall, or that the caller can't stop. It is routine only when both hold: the water is fully caught (a bucket, a pan) and is not spreading, or the supply is shut off and it has stopped. A caller who says "a lot of water" is never asked to justify it before the chain starts.
- Team emails say how urgent it is and what was already done, in the plain staff-email shape
(the subject names the person and the thing, no banner prefix). For example:
<name>: emergency leak at <street> #<unit>, forwarded to your answering service (address not confirmed). The word "emergency" is part of the thing being named, not a banner. The bare "— callback" subject is retired.
A piece of code violates this ADR if it refuses, defers or downgrades an emergency because a home, unit or building could not be confirmed.
Consequences
- On-call staff will sometimes be called for a location we got wrong. The alert says so, and the callback number is always present. We accept a wrong-unit page over a missed emergency.
- A line with no building needs a number to dial out from. The company line does this (Situs's line was attached as its company line on 2026-10-19).
- Open PR #20742 narrows what counts as a "major leak" in the same prompt. Its "drip caught in a container" exclusion is compatible with decision 8 only when the water is also not spreading, and its dataset case that treats a pooling sink drip as routine contradicts decision 8 (pooling is spreading). #20742 must be amended to this definition before either change merges; otherwise its nightly goes red on this rule, or this rule is silently undone.
- False pages are measured before the gate loosens further: one chain per conversation (the dedupe key exists), and a tracked budget of false pages that wake someone at night.
- The 2026-10-18 call is the golden case for both the call script and the after-call sweep, alongside two false-positive controls (a contained drip, and a water-bill question).
- Work order creation for routine reports changes too (
handle-create-work-order.ts:965-973): a different stated place becomes a note, not a refusal.
Alternatives considered
- Keep the gate and fix the address lookup only. Rejected: the next address we cannot place silences the next emergency the same way. Two of the last 30 days' leak calls gave addresses we do not hold at all.
- Escalate only after the call. Rejected: the after-call path missed on 2026-10-18, and an emergency should not wait for the call to end.
Amendment 2026-10-20 — every emergency on a call pages on-call after the call, gas, fire and police included
- Decider: Gera, 2026-10-20, in chat: "I think all of them should go after the call to get as much context 'cause it wouldn't make sense to call right away but we don't have all the information in, right? So I would say everything should wait till after the call. 'Cause I mean it's gonna be an extra twenty seconds at most for valuable information."
- Supersedes: the founder ruling of 2026-10-08 ("write the work order and call them at the same
time") and Gera's 2026-10-09 "Police, fire, gas → ring on-call people until someone answers" as to
timing, and Fede's 2026-10-09 split that encoded them: a gas, fire or police emergency
(
gas_emergency,active_emergency) rang the on-call list during the call and a leak or flood (high) rang it from the work order written after the call.
Decision. On a live call at a confirmed building, a gas, fire or police emergency no longer rings the
on-call list mid-call. escalate_to_human still fires at once, still stamps the conversation, and still
answers Clara right away; the chain's start is held with the office notice
(Conversation.heldOfficeNotice.chain, office-notice-hold.ts) and started when the call ends, from the
call-ended route, the end of the after-call sweep, or the durable 10-minute fallback if the call-ended
webhook never arrives. A chain that takes the emergency is the office's one email; a chain that refuses
(switch off, nobody on the list, no line) pages the office, as the mid-call refusal did.
What this reverses, and what it does not. "Escalate only after the call" was rejected above for two
reasons. The second, "an emergency should not wait for the call to end", is reversed outright by this
amendment: the founders now judge the extra seconds worth the context. The first, that the after-call
path on 2026-10-18 depended on the classifier, which did not return "emergency", still stands, and this
design keeps it: the held chain does not depend on the classifier: it is Clara's own confirmed escalation, written during the call,
and it starts whatever the classifier, the content check or the work-order sweep decide. The classifier
path (liftMissedEmergency, the missed-emergency detector) still runs on top of it and is unchanged. The
emergency still always escalates; only the moment the on-call list is rung moves, by the length of the
rest of the call.
What does not change.
- Every spoken safety instruction ("leave your unit right now and call 911", "get out and call 911 now", stay outside) is word for word as before. Only the timing of the page moved.
- The tiers themselves: Clara still files gas at
gas_emergencyand fire, smoke, sparks or police atactive_emergency. - Text and email: no call to wait for, so those tiers still ring at once.
- An unconfirmed location (decision 1 above): the chain still rings during the call for every tier, leaks included, because no after-call work order can be filed for a home we could not place.
- The after-hours emergency conference (
transfer_to_numberto the property's emergency line) is a live transfer, tier-agnostic, and already withheld wherever the chain will ring; it is untouched. - If the hold cannot be written (no Temporal client, the fallback will not arm, the row will not save), the chain rings during the call exactly as before. Failing toward the old timing is safe; failing toward no page is not.
Consequences. The on-call person hears about a gas leak at the end of the call, later than before by the rest of the call plus, when the work-order sweep runs, the classifier's run before the release. The chain's name and spoken-address rows are read from the conversation when the chain starts, so what the caller said after the escalation reaches on-call. A later, weaker escalation on the same call never drops a held chain: the chain and its tier are carried forward. A call still going ten minutes after the escalation is rung by the fallback at the ten-minute mark, mid-call. A lost call-ended webhook costs up to ten minutes, where the mid-call start cost nothing; the fallback is armed before the hold is recorded, so a held chain with no timer cannot exist.
A piece of code violates this amendment if a confirmed gas, fire or police emergency on a call ends with neither the on-call chain started nor the office paged.