The reported failures are one missing acknowledgement and one missing service
start.
- Alarms only fired with the app in focus: the armed WebSocket lives in the
native foreground service, and nothing started it — the only entries were a
button on one alert screen and a toggle in Settings. The provider now arms the
active subscription itself (asks for POST_NOTIFICATIONS, uses the device token
the service can hold, throttles a refused start to once per five minutes), and
Home says whether the background listener is really running instead of
presenting the on-screen socket as coverage.
- Dismissed alarms came back: the takeover never sent the ack. acknowledgeAlarm
existed and was never called, so the service still believed this device owed
the alarm and replayed it on every connect/poll. The acknowledge path now
persists the dismissal (durably, retried) and records it locally, so a status
report of the trigger it already dismissed cannot raise the takeover again.
The record tolerates a dismissal with no event id (the native launch carries
only the alert) and is pinned to the concrete event as soon as one is known.
- No way back from the takeover: acknowledge now shows a Back to alerts action,
hardware back works once the device is silent, and the screen leaves by itself
when the alert ends for this device.
- A destroyed alert answers 401 to its device token (the subscription went with
it). That is terminal: acknowledgements and the status poll stop retrying the
dead credential and mark the subscription ended instead of looping.
- Settings' start-listening button built the socket URL without the device
token, so it could never arm a subscriber's service.
tsc clean, 144 tests (15 new: dismissal memory, background arming, dead
credential, unnamed ack queue).