What
Give the project one authenticated way to reach people already running the app — "2.1 is out and fixes X", "the node is down for maintenance tonight", "this relay is being retired" — without a backend, an account, or a push token.
Announcements are signed Nostr events (kind 38387) published from a small allowlist of project keys compiled into the app. The signature is the whole trust model: a hostile relay can withhold or stale an announcement, but cannot forge one. They render in the notification surface that already exists — no new screen, no new bell.
Full specification
specs/006-announcement-channel/spec.md — event contract, trust model, freshness and expiry rules, severity levels, consent, publishing, and the test cases each phase owes. Read it before starting; the details below are only the shape of the work.
Wire contract: MostroP2P/protocol#56 (registers the kind — should land before the reader ships).
Shape of the work
Almost all of it is Rust: parsing, allowlist, verification, freshness and storage are protocol work. Dart only renders what Rust hands it.
Build order from §10 — one PR per step, and the off switch ships before the surface:
- §3 parsing and validation + the §4.1 allowlist, as pure functions — no relay, no DB, no UI
- Fetch, verify, freshness, expiry, the
announcements table (SCHEMA_VERSION 3 → 4)
- Bridge surface + the Announcements toggle, then
./scripts/frb-generate.sh
- Rendering into the existing notification surface, five locales of chrome
rust/src/bin/announce.rs — the publisher validator
- Add the real npubs — one line, its own PR
Steps 1–5 all merge without the channel existing in production: the allowlist ships empty, and an empty allowlist opens no subscription. Step 6 is the only commit that makes it live.
Blocked on a decision, not on code
Where the announcement key lives. §4.1 requires a dedicated key, kept offline, that is neither a maintainer's personal key nor a Mostro node key. Nothing can be published until that exists — but it blocks step 6 only, not steps 1–5.
Not in scope
Real push (FCM), background relay subscriptions, targeted messages to a particular user or node operator, any inbound path, and node-authored announcements. §11 says why for each.
What
Give the project one authenticated way to reach people already running the app — "2.1 is out and fixes X", "the node is down for maintenance tonight", "this relay is being retired" — without a backend, an account, or a push token.
Announcements are signed Nostr events (kind
38387) published from a small allowlist of project keys compiled into the app. The signature is the whole trust model: a hostile relay can withhold or stale an announcement, but cannot forge one. They render in the notification surface that already exists — no new screen, no new bell.Full specification
specs/006-announcement-channel/spec.md— event contract, trust model, freshness and expiry rules, severity levels, consent, publishing, and the test cases each phase owes. Read it before starting; the details below are only the shape of the work.Wire contract: MostroP2P/protocol#56 (registers the kind — should land before the reader ships).
Shape of the work
Almost all of it is Rust: parsing, allowlist, verification, freshness and storage are protocol work. Dart only renders what Rust hands it.
Build order from §10 — one PR per step, and the off switch ships before the surface:
announcementstable (SCHEMA_VERSION3 → 4)./scripts/frb-generate.shrust/src/bin/announce.rs— the publisher validatorSteps 1–5 all merge without the channel existing in production: the allowlist ships empty, and an empty allowlist opens no subscription. Step 6 is the only commit that makes it live.
Blocked on a decision, not on code
Where the announcement key lives. §4.1 requires a dedicated key, kept offline, that is neither a maintainer's personal key nor a Mostro node key. Nothing can be published until that exists — but it blocks step 6 only, not steps 1–5.
Not in scope
Real push (FCM), background relay subscriptions, targeted messages to a particular user or node operator, any inbound path, and node-authored announcements. §11 says why for each.