docs: reserve kind 38387 for announcement events - #56
Conversation
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.
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.
There was a problem hiding this comment.
💡 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".
| "created_at": 1756200000, | ||
| "kind": 38387, | ||
| "tags": [ | ||
| ["d", "2026-08-release-2-1"], | ||
| ["expiration", "1758792000"], |
There was a problem hiding this comment.
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 👍 / 👎.
| | Ratings | 38384 | `rating` | | ||
| | Info | 38385 | `info` | | ||
| | Disputes | 38386 | `dispute` | | ||
| | Announcements | 38387 | `announcement` | |
There was a problem hiding this comment.
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 👍 / 👎.
|
Warning Review limit reachedNext included review available in 6 minutes. View limit detailsLimit 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. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
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. Comment |
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.
What
Registers kind
38387— announcements in the3838xblock, and addssrc/announcement_event.mddescribing the event.zorderratinginfodisputeannouncementWhy
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:
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
38387is 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
38387for 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
drather 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.urlthe 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:
warning. The one field where the "unknown means ignore" rule ofvdoes not apply:vand 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.warningrather thancritical, 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.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 thandalone, since the allowlist is a list and two publishers can pick the samed.Notes for review