Repository navigation
Description
Describe the bug
We run Buzz internally as a human + agent workspace on the hosted community twelfth-ai.communities.buzz.xyz, desktop + mobile, on 0.5.23. Nobody gets pinged, on either platform, and we could not work out why from inside the app. We had to read Dart, Swift and Rust to find out.
This is deliberately not "please add push". Android transport is #6092 / #7482 and hosted-relay enablement is #7415 — both open, both correct, and this issue does not restate them. The gap neither of them covers is that push delivery on mobile is gated on four independent conditions, three of which fail silently, and the Notifications settings screen affirmatively reports success regardless of any of them.
Verified against main at 312cf67.
The four gates
| # | Gate | Where | What the user is told |
|---|---|---|---|
| 1 | Platform has a push transport | Android has none | nothing — the settings card is not rendered at all on Android |
| 2 | Build has BUZZ_PUSH_GATEWAY_URL baked in |
relay_provider.dart:79 |
"Unavailable in this build" — iOS only |
| 3 | Relay advertises nip-pl + a push descriptor |
push_relay_capability_provider.dart:22-55 |
nothing — a debugPrint |
| 4 | iOS permission + per-community toggle | notifications_section.dart:27-50 |
correctly surfaced |
Gate 1. mobile/android/app/src/main/AndroidManifest.xml declares no POST_NOTIFICATIONS. There is no FCM service, no UnifiedPush receiver, and no firebase_messaging / flutter_local_notifications in mobile/pubspec.yaml. The only Android-side push code is build-time validation of the gateway URL define (mobile/android/app/build.gradle.kts:26-56). Expected, per #6092 — but the app never says so, because _NotificationsSection early-returns SizedBox.shrink() on non-iOS (notifications_section.dart:7-10) and it is the only notifications UI in mobile settings. Filed separately as #7824.
Gate 2. static const pushGatewayConfigured = pushGatewayUrl != '' — a compile-time define. False short-circuits every push path (push_relay_capability_provider.dart:24, push_bootstrap.dart:92, push_bridge.dart:143,194). Surfaced, but as one four-word subtitle that doesn't say which build would work.
Gate 3 — the one that actually caught us. Discovery fails closed, by documented design:
/// An unconfigured artifact has no capability and never starts discovery.
/// Discovery fails closed. An absent, malformed, or unreachable NIP-11 push
/// descriptor is represented as no capability, so no notification permission,
/// APNs registration, gateway enrollment, or relay lease can begin.and the failure path is:
} catch (error, stackTrace) {
debugPrint('Current relay does not advertise valid push: $error');
debugPrintStack(stackTrace: stackTrace);
return null;
}Fail-closed is right for a capability probe. The problem is what happens next. currentRelayPushDescriptorProvider is watched in exactly two places — app.dart:352, which declines to start pushSubscriptionSyncProvider, and push_bootstrap.dart:173. notifications_section.dart never watches it.
So the user-visible failure is a false affirmative. With the toggle on and iOS permission granted, against a relay that advertises no push at all, the Notifications card renders:
Push notifications
Receive message notifications from this community
That statement is untrue and there is no way, from any screen in the app, to discover that it is untrue.
We can confirm this is live, not theoretical. Our own hosted community, fetched 2026-09-23 (AEST):
$ curl -sS -H 'Accept: application/nostr+json' https://twelfth-ai.communities.buzz.xyz | jq '{version, supported_extensions, push}'
{
"version": "0.2.1",
"supported_extensions": [
"nip-er",
"buzz-gif"
],
"push": null
}No nip-pl, no push descriptor, so discoverBuzzPushRelayCapability returns null and pushSubscriptionSyncProvider never starts. This is the same state #7415 verified on sunnn.communities.buzz.xyz on 2026-09-06 — a second hosted community, seventeen days later, unchanged. Meanwhile the app tells our operators they will receive message notifications from this community.
And past all four gates, it's still silent
crates/buzz-push-gateway/src/model.rs:15-16:
pub const APNS_RECONNECT_PAYLOAD: &[u8] =
br#"{"aps":{"alert":{"body":"Reconnect to your relay now"},"mutable-content":1}}"#;No sound key (#7186, open), and mobile/ios/NotificationService/NotificationService.swift sets title/body/subtitle and never .sound. A locked phone that clears all four gates still doesn't make a noise — which is indistinguishable, to the person holding it, from gates 1–3 being shut.
Steps to reproduce
- iOS, 0.5.23, joined to a hosted community (ours is
twelfth-ai.communities.buzz.xyz). - Settings → Notifications → toggle on. Grant iOS notification permission.
- Observe the subtitle: "Receive message notifications from this community".
- Lock the phone. Have a teammate or agent @mention you.
- Nothing arrives. Nothing in the app indicates why, or that anything is wrong.
- On Android, repeat from step 2 — there is no Notifications card to toggle.
Expected behavior
The Notifications screen tells the truth about whether this install can deliver a notification, and says which gate is shut when it can't:
- Android: "Push notifications are not yet supported on Android" (link feat(mobile/android): end-to-end push notifications — FCM registration, POST_NOTIFICATIONS, and banner display #6092).
- No gateway define: name it as a build limitation, not a mystery.
- Relay advertises no
nip-pl: "This relay does not support push notifications" — this is the missing one, and it is a one-lineref.watchaway. - All gates open: the current success copy, which would then be accurate.
Actual behavior
Three of four gates are invisible, and the screen reports success across all of them.
Suggested fix
_NotificationsSection already has the right shape for this — it has an unavailable-row branch for gate 2. Extend it to watch currentRelayPushDescriptorProvider and to render on non-iOS, so each gate gets its own row and its own reason. That turns "I'm not getting pinged" from a three-language code read into a screenshot.
Beyond the copy fix, the thing we'd most want is one diagnostics row an operator can screenshot into an issue: surface, build, relay capability, permission, lease state, last successful wake. Reproducing any push bug today requires reading Rust, Dart and Swift, which is why we suspect these reports are thin.
Version and platform
- Buzz version: 0.5.23
- Mobile: iOS and Android, both affected, for the two different reasons above
- Relay: hosted
twelfth-ai.communities.buzz.xyz, relay software 0.2.1 - Code references verified at
block/buzz@312cf67
Happy to test on real devices on both platforms and report back, and happy to open the _NotificationsSection PR if the copy is agreed.
Also filed from this investigation
- Android: the Notifications settings card is not rendered at all, so there is no way to learn that push doesn't exist #7824 — Android renders no Notifications settings card at all (gate 1 has no UI)
- Push wakes the phone for messages the app itself refuses to mark unread — the push lease subscribes to every channel message, the unread rule excludes untouched thread replies #7825 — the push lease is broader than the in-app unread rule, so once push does work the phone wakes for events the app won't badge
Related
#6092 (Android transport) · #7482 (UnifiedPush) · #7415 (hosted enablement) · #5206 (self-host gateway) · #7186 (APNs sound) · #4657 (registration) · #5091 (badge clearing) · #5007 (delivery consistency) · #7305 (Android vibration) · #7447 (mention classes) · #7779 (agent replies in inbox)
Activity
fix(mobile): hide notification settings without relay push capability (…
fix(mobile): hide notification settings without relay push capability (…
fix(mobile): simplify notification settings (#8199)
chore(sync): merge upstream desktop-v0.5.28 (#35)