Goal
Give every push somewhere to land, or record why it has nowhere to go.
Current behaviour
CivilDisorderSpec and CivilDisorderRecoverySpec return None from get_link(). game_deleted is emitted without a game, so render sets both link and data to None.
Both tap handlers read a link and no-op without one: the service worker reads data.FCM_MSG.data.link, and the native handler reads data.link. Tapping any of these three notifications does nothing.
Expected behaviour
Tapping a notification opens something relevant to it. Where there is genuinely nowhere to go — game_deleted names a game that no longer exists — that is recorded as a deliberate exception rather than left as an unset default.
Where
service/notification/registry.py — CivilDisorderSpec.get_link, CivilDisorderRecoverySpec.get_link, and the context.game is None branch in NotificationSpec.render; tap handling in packages/web/public/firebase-messaging-sw.js and packages/web/src/messaging-native.ts.
Goal
Give every push somewhere to land, or record why it has nowhere to go.
Current behaviour
CivilDisorderSpecandCivilDisorderRecoverySpecreturnNonefromget_link().game_deletedis emitted without a game, sorendersets bothlinkanddatatoNone.Both tap handlers read a link and no-op without one: the service worker reads
data.FCM_MSG.data.link, and the native handler readsdata.link. Tapping any of these three notifications does nothing.Expected behaviour
Tapping a notification opens something relevant to it. Where there is genuinely nowhere to go —
game_deletednames a game that no longer exists — that is recorded as a deliberate exception rather than left as an unset default.Where
service/notification/registry.py—CivilDisorderSpec.get_link,CivilDisorderRecoverySpec.get_link, and thecontext.game is Nonebranch inNotificationSpec.render; tap handling inpackages/web/public/firebase-messaging-sw.jsandpackages/web/src/messaging-native.ts.