Skip to content

docs: reserve kind 38387 for announcement events - #56

Open
grunch wants to merge 2 commits into
mainfrom
docs/reserve-kind-38387-announcements
Open

docs: reserve kind 38387 for announcement events#56
grunch wants to merge 2 commits into
mainfrom
docs/reserve-kind-38387-announcements

Conversation

@grunch

@grunch grunch commented Aug 26, 2026

Copy link
Copy Markdown
Member

What

Registers kind 38387 — announcements in the 3838x block, and adds src/announcement_event.md describing the event.

Event Type Kind z
Orders 38383 order
Ratings 38384 rating
Info 38385 info
Disputes 38386 dispute
Announcements 38387 announcement

Why

A project that ships a Mostro client has no way to say anything to the people already running it. A store release note reaches them once, at update time, if they read it — and on web and desktop there is not even that. So none of these can be said today:

  • "2.1 is out and it fixes the invoice bug you are hitting."
  • "The public node is down for maintenance tonight."
  • "This default relay is being retired."

Every conventional answer wants a server, an account, an email address, or a push token — which is exactly the set of things these clients deliberately do not have. But a client that speaks Nostr already has what a broadcast channel needs: a signed event. The publisher's key is the whole trust model, so a hostile relay can withhold an announcement or serve a stale one, but cannot forge one.

The odd one in the block

38387 is the only kind here that is not published by a Mostro daemon. A node neither publishes nor reads it — it is published by the keys of the project that ships a client, and read by that client.

So why register it here at all? Because a number reserved only inside one client's repository is not reserved. The registry is what stops two Mostro clients from picking 38387 for two different things. The document describes the event shape for the same reason: the shape is worth agreeing on even where the trust anchor is not.

The allowlist of publisher keys is deliberately per-project. Each project trusts its own keys, compiled into its own client; this document does not define a global one, and says so.

The shape

  • Addressable, so correcting a typo in a live announcement is a republish under the same d rather than a second announcement.
  • expiration (NIP-40) required, so a publisher cannot accidentally create something permanent.
  • min_version / max_version, semver, so "2.1 is out" is not shown to someone on 2.1. The upper bound is exclusive for exactly that reason; build metadata is rejected, since semver excludes it from precedence and honouring such a bound would silently ignore part of what the publisher wrote.
  • Every translation in one event. One event per language would turn a single publish into several, let a user's relay set deliver two languages and not the others, and leave the client deciding whether three events are one announcement or three.
  • Plain text only, url the single actionable element. The publisher is trusted with authorship, not with rendering arbitrary content inside a Bitcoin exchange client.

Severity

Added after review of the client spec: a release note and "a bug can leak your trade key, update now" are not the same message, and a client rendering them identically makes the second look like the first. Three levels — info, warning, critical.

The constraints are the interesting part:

  • A publisher declares a severity, never a colour, an icon, or any other presentation value. The mapping belongs to the client — palettes differ between themes, contrast pairs are something a design system has checked and an arbitrary hex is not, and the publisher is trusted with authorship rather than with rendering. A client MUST NOT accept presentation instructions from this event.
  • A client that does not recognise a value MUST still render the announcement, as warning. The one field where the "unknown means ignore" rule of v does not apply: v and the locale set decide whether a message is intelligible, severity only decides how it is presented, and dropping a security notice because a later revision of this document added a level is the worst outcome available. warning rather than critical, because a client cannot know which direction an unknown token sits in, and "any unrecognised string renders as the loudest level" is an escalation path a compromised publisher would use.
  • Severity decays with misuse, and the document says so without pretending it can enforce it.

What the document asks of a reader

The signature is the trust model, so the obligations are spelled out rather than implied: a compiled-in allowlist that is never updatable over the wire, explicit verification at the point of use, a freshness window, expiry re-checked against the clock rather than the network (an offline client receives nothing to displace what it holds), and addressing by (kind, pubkey, d) rather than d alone, since the allowlist is a list and two publishers can pick the same d.

Notes for review

  • Which locales are required is left to the publishing project, not fixed here — it depends on what its client ships. The document says a client SHOULD require every locale it supports rather than falling back to English, because a silent fallback is a bug the publisher never finds out about.
  • The reference implementation is specified in docs: specify an authenticated announcement channel + fix the app version it targets app#318 (Mostro Mobile v2), which requires exactly the five locales it ships.
  • No daemon change: nothing in this PR asks mostrod to publish or read anything.

Registers the next slot in the 3838x block for announcements: a signed,
one-way notice from a project to the people already running its client
— "2.1 is out", "the node is down tonight", "this relay is retiring".

It is the only kind in the block not published by a Mostro daemon. A
node neither publishes nor reads it; it is published by the keys of the
project that ships a client, and read by that client. The number is
registered here rather than defined here, so that two Mostro clients
cannot pick 38387 for two different things.

The document describes the event because the shape is worth agreeing on
even though the trust anchor is not: the allowlist of publisher keys is
per-project, compiled into each client, and this document deliberately
does not define a global one.
grunch added a commit to MostroP2P/app that referenced this pull request Aug 26, 2026
Adds the `z` / `y` tags the 3838x block conventions ask for, as an
obligation on the publisher rather than a filter on the reader: they
carry no trust, so validating them would only add a way for a correct
announcement to be dropped.

Also says which document wins where the two overlap — the protocol one
is the wire contract, this one is how this app implements it, and the
five-locale rule is this app's policy, which the protocol document
leaves to each project.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3dbfcaf2e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/announcement_event.md
Comment on lines +34 to +38
"created_at": 1756200000,
"kind": 38387,
"tags": [
["d", "2026-08-release-2-1"],
["expiration", "1758792000"],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the example timestamps to the announced year

At this commit's 2026-08-26 publication date, 1756200000 is 2025-08-26 and the expiration value is 2025-09-25, despite the announcement ID identifying an August 2026 release. A reader implementing the required 30-day freshness and expiration checks will therefore always reject this canonical example, making it unusable for interoperability testing; use timestamps consistent with the 2026 announcement.

Useful? React with 👍 / 👎.

Comment thread src/order_event.md
| Ratings | 38384 | `rating` |
| Info | 38385 | `info` |
| Disputes | 38386 | `dispute` |
| Announcements | 38387 | `announcement` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add the reserved kind to the overview registry

Registering kind 38387 only in this secondary table leaves the homepage registry in src/overview.md listing exactly the four pre-existing event kinds. Because the purpose of this change is to reserve the number and prevent clients from assigning it differently, developers consulting the primary overview can still miss the reservation; update that registry and link it to the new document as well.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 6 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9060843e-a9c2-4220-8dd0-325201032f75

📥 Commits

Reviewing files that changed from the base of the PR and between 893e008 and 2f2c921.

📒 Files selected for processing (3)
  • src/SUMMARY.md
  • src/announcement_event.md
  • src/order_event.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

A release announcement and "a bug can leak your trade key, update now"
are not the same message, and a client that renders them identically
makes the second look like the first. Three levels: info, warning,
critical.

The publisher declares a severity and never a colour: palettes differ
between themes, contrast pairs are something a design system has checked
and an arbitrary hex is not, and the publisher is trusted with
authorship rather than with rendering.

An unrecognised value must still render, as warning. It is the one field
where the unknown-means-ignore rule does not apply — severity decides
how a message is painted, not whether it is intelligible, and dropping a
security notice because a later revision added a level is the worst
outcome available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant