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:
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
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)
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
mainat312cf67.The four gates
BUZZ_PUSH_GATEWAY_URLbaked inrelay_provider.dart:79nip-pl+ apushdescriptorpush_relay_capability_provider.dart:22-55debugPrintnotifications_section.dart:27-50Gate 1.
mobile/android/app/src/main/AndroidManifest.xmldeclares noPOST_NOTIFICATIONS. There is no FCM service, no UnifiedPush receiver, and nofirebase_messaging/flutter_local_notificationsinmobile/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_NotificationsSectionearly-returnsSizedBox.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:
and the failure path is:
Fail-closed is right for a capability probe. The problem is what happens next.
currentRelayPushDescriptorProvideris watched in exactly two places —app.dart:352, which declines to startpushSubscriptionSyncProvider, andpush_bootstrap.dart:173.notifications_section.dartnever 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:
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):
No
nip-pl, nopushdescriptor, sodiscoverBuzzPushRelayCapabilityreturns null andpushSubscriptionSyncProvidernever starts. This is the same state #7415 verified onsunnn.communities.buzz.xyzon 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:No
soundkey (#7186, open), andmobile/ios/NotificationService/NotificationService.swiftsetstitle/body/subtitleand 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
twelfth-ai.communities.buzz.xyz).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:
nip-pl: "This relay does not support push notifications" — this is the missing one, and it is a one-lineref.watchaway.Actual behavior
Three of four gates are invisible, and the screen reports success across all of them.
Suggested fix
_NotificationsSectionalready has the right shape for this — it has an unavailable-row branch for gate 2. Extend it to watchcurrentRelayPushDescriptorProviderand 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
twelfth-ai.communities.buzz.xyz, relay software 0.2.1block/buzz@312cf67Happy to test on real devices on both platforms and report back, and happy to open the
_NotificationsSectionPR if the copy is agreed.Also filed from this investigation
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)