The alert detail screen now creates with a lifetime (1/3/7/14 days) and shows expiresAt, lists subscriber rows by their non-identifying fields, and renders each ending (delivered, expired, disarmed, deleted) as a terminal state instead of a stale alert. Settings configures the single instance origin and reports the real readiness/listening checklist; the trigger pad keeps its 1200ms hold, and time helpers format the deadline and last-seen values.
The service mints /api/alarm/a/{alertId}#{token} with no host, so the QR renders against the configured instance and keeps working when the instance moves or is reached by another name. The scanner now matches path shape and fragment and never the host, so legacy alarm.dcntrlized.org codes and other instances codes still join; error copy distinguishes a malformed code from a wrong-alert token.
The device id is the subscriber-only pseudonymous handle, used as the join idempotency key and to address this device in the delivery ledger. Use SecureRandom through the native bridge, validate it against the service limits, and keep hardware identifiers out of it entirely. Device labels describe the device role, never a slice of the id, and the subscriber list renders the wire id/created/lastSeenAt fields.
The blocking grants (exact alarms, full-screen intent, notifications) and the advisory battery exemption are surfaced as readiness, not as warnings that still allow arming. Listening state is read from the persisted native record on resume so a process-killed service cannot leave a stale armed claim on screen.