<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <updated>2026-10-03T01:25:05Z</updated>
  <generator>https://nostr.now</generator>

  <title>Nostr notes by fleetmesh</title>
  <author>
    <name>fleetmesh</name>
  </author>
  <link rel="self" type="application/atom+xml" href="https://nostr.now/npub1dxlsl0yzz9yglsephmjmlgrm4cvy4zqmpvtv87mwzwjtrhdzsyjq4xs7uy.rss" />
  <link href="https://nostr.now/npub1dxlsl0yzz9yglsephmjmlgrm4cvy4zqmpvtv87mwzwjtrhdzsyjq4xs7uy" />
  <id>https://nostr.now/npub1dxlsl0yzz9yglsephmjmlgrm4cvy4zqmpvtv87mwzwjtrhdzsyjq4xs7uy</id>
  <icon>https://www.fleetmesh.org/assets/android-chrome-512x512.png</icon>
  <logo>https://www.fleetmesh.org/assets/android-chrome-512x512.png</logo>




  <entry>
    <id>https://nostr.now/nevent1qqs0har3wrnfuzpdflcw7a6qq74kdkvdfn95ylt8kxz77j5y8kaz94gzyp5m7rausgg53r7ryxlwt0aq0whpsj5grv93dslmdcf6fvwa52qjg8nrmvg</id>
    
      <title type="html">meshstr: a permissionless relay mesh for nostr, published today ...</title>
    
    <link rel="alternate" href="https://nostr.now/nevent1qqs0har3wrnfuzpdflcw7a6qq74kdkvdfn95ylt8kxz77j5y8kaz94gzyp5m7rausgg53r7ryxlwt0aq0whpsj5grv93dslmdcf6fvwa52qjg8nrmvg" />
    <content type="html">
      In reply to &lt;a href=&#39;/naddr1qqrk6etndpehguspz4mhxue69uhkw6t59ehx7um5wf582c3wd9hsygrfhu8meqs3fz8uxgd7ukl6q7awrp9gsxctzmplkmsn5jcamg5pyspsgqqqw7vsw66dws&#39;&gt;naddr1qq…6dws&lt;/a&gt;&lt;br/&gt;_________________________&lt;br/&gt;&lt;br/&gt;meshstr: a permissionless relay mesh for nostr, published today as an alpha draft.&lt;br/&gt;&lt;br/&gt;Relay operators publish, signed, the budget they grant each peer; peers account for their own consumption in signed receipts; a finding against a peer counts only from a node that granted it, and is never imported as a ban. Nothing is implemented yet: this is a proposal, published so it can be argued with, all CC0.&lt;br/&gt;&lt;br/&gt;Spec: &lt;a href=&#34;https://www.meshstr.org/spec.html&#34;&gt;https://www.meshstr.org/spec.html&lt;/a&gt;&lt;br/&gt;NIP on NostrHub:&lt;blockquote class=&#34;border-l-05rem border-l-strongpink border-solid&#34;&gt;&lt;div class=&#34;-ml-4 bg-gradient-to-r from-gray-100 dark:from-zinc-800 to-transparent mr-0 mt-0 mb-4 pl-4 pr-2 py-2&#34;&gt;quoting  &lt;span itemprop=&#34;mentions&#34; itemscope itemtype=&#34;https://schema.org/Article&#34;&gt;&lt;a itemprop=&#34;url&#34; href=&#34;/naddr1qqdk6etndpehgu3dwfjkccte94kk2umg94c8ymm5da3k7mqpz4mhxue69uhhyetvv9ujuerfw36x7tnsw43qygrfhu8meqs3fz8uxgd7ukl6q7awrp9gsxctzmplkmsn5jcamg5pyspsgqqq0psst04w33&#34; class=&#34;bg-lavender dark:prose:text-neutral-50 dark:text-neutral-50 dark:bg-garnet px-1&#34;&gt;naddr1qq…4w33&lt;/a&gt;&lt;/span&gt;&lt;br/&gt; &lt;/div&gt; meshstr&lt;br/&gt;=======&lt;br/&gt;&lt;br/&gt;Permissionless relay mesh, bilateral rate accounting, and deterministic compute&lt;br/&gt;-------------------------------------------------------------------------------&lt;br/&gt;&lt;br/&gt;`draft` `optional`&lt;br/&gt;&lt;br/&gt;This document specifies **meshstr**: a permissionless mesh that nostr relay&lt;br/&gt;operators can join from a VPS, a Raspberry Pi, a laptop or a phone, in order to&lt;br/&gt;have what a solitary relay cannot — spam control derived from what other&lt;br/&gt;operators actually observed, rather than from a blocklist somebody else&lt;br/&gt;maintains.&lt;br/&gt;&lt;br/&gt;It is a proposal. One alpha implementation exists, and the numbers below are&lt;br/&gt;alpha-mutable. It is published here to fix the event kinds against collision&lt;br/&gt;and to let the design be argued with in public.&lt;br/&gt;&lt;br/&gt;The full specification, with the reasoning behind every choice, is at&lt;br/&gt;**&lt;a href=&#34;https://www.meshstr.org/spec.html&#34;&gt;https://www.meshstr.org/spec.html&lt;/a&gt;**. This document is the normative core of&lt;br/&gt;it: what an implementation must put on the wire, without the arguments.&lt;br/&gt;&lt;br/&gt;## Motivation&lt;br/&gt;&lt;br/&gt;A relay that wants to reject spam has three options today. It can write its own&lt;br/&gt;heuristics, which every relay then rewrites. It can import a blocklist, which&lt;br/&gt;means adopting somebody else&#39;s moderation and their mistakes. Or it can require&lt;br/&gt;payment, which prices out exactly the users least able to pay.&lt;br/&gt;&lt;br/&gt;None of those is the obvious fourth option: ask the operators who already saw&lt;br/&gt;the traffic. That is not possible today because relays have no way to say&lt;br/&gt;anything to each other, and no way to hold each other to what they said.&lt;br/&gt;&lt;br/&gt;meshstr is that channel, built so that saying something costs the speaker&lt;br/&gt;something. Every node publishes, signed, the budget it has granted each peer.&lt;br/&gt;Every peer accounts for its own consumption in signed receipts. A finding&lt;br/&gt;against a peer is admissible only if the reporter itself issued that peer a&lt;br/&gt;grant — so an accusation is always backed by a relationship the accuser&lt;br/&gt;publicly entered into, and nobody can report on a node they never carried&lt;br/&gt;traffic for.&lt;br/&gt;&lt;br/&gt;Three properties hold throughout:&lt;br/&gt;&lt;br/&gt;- **Joining costs a node no data it already had.** The mesh replicates&lt;br/&gt;  additively. Leaving is a flag.&lt;br/&gt;- **No private data crosses.** No IP addresses, no subscription contents, no&lt;br/&gt;  user identifiers. What crosses is events, budgets, receipts and adverse&lt;br/&gt;  findings.&lt;br/&gt;- **There is no authority.** No registry, no bootstrap host anyone must reach,&lt;br/&gt;  no release manager, and no key that can revoke a node it does not peer with.&lt;br/&gt;&lt;br/&gt;## Terminology&lt;br/&gt;&lt;br/&gt;The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT and MAY are to be&lt;br/&gt;interpreted as described in RFC 2119.&lt;br/&gt;&lt;br/&gt;A **node** is a relay that speaks this protocol. A **peering** is a pair of&lt;br/&gt;grants, one per direction. A **window** is the accounting period a grant names.&lt;br/&gt;An **issuer** grants capacity; a **subject** consumes it and accounts for it.&lt;br/&gt;&lt;br/&gt;Nodes take one of three classes, declared in the descriptor and not negotiable&lt;br/&gt;per peer:&lt;br/&gt;&lt;br/&gt;| Class | Runs on | Obligations |&lt;br/&gt;|---|---|---|&lt;br/&gt;| `leaf` | a phone or a laptop | one WebSocket, a bounded store, no p2p stack; MAY hold no coverage at all |&lt;br/&gt;| `edge` | a VPS or a home server | full transport ladder, holds coverage, serves range reconciliation |&lt;br/&gt;| `anchor` | a well-connected server | everything an edge does, plus mediation for leaves and long-lived descriptors |&lt;br/&gt;&lt;br/&gt;## Node identity&lt;br/&gt;&lt;br/&gt;A node is identified by a `did:nostr` DID whose subject is its nostr pubkey.&lt;br/&gt;&lt;br/&gt;### Keys&lt;br/&gt;&lt;br/&gt;DIDComm v2 requires X25519 for envelope encryption, and iroh and libp2p both&lt;br/&gt;identify hosts by Ed25519. No single key does all three, so a node holds three&lt;br/&gt;and binds the other two by listing them in a descriptor signed by the first.&lt;br/&gt;&lt;br/&gt;| Key | Curve / multicodec | Purpose | Rotation |&lt;br/&gt;|---|---|---|---|&lt;br/&gt;| node | secp256k1 x-only, `0xe7` | the DID subject; signs the descriptor, grants, reports, receipts and every event the node authors | never — rotating it creates a new node |&lt;br/&gt;| agreement | X25519, `0xec` | `keyAgreement`; DIDComm v2 ECDH-ES and ECDH-1PU | SHOULD rotate every 90 days, overlapping one window |&lt;br/&gt;| transport | Ed25519, `0xed` | iroh `NodeId` and libp2p `PeerId`; signs gossipsub under StrictSign | MAY rotate freely; a new descriptor is the only requirement |&lt;br/&gt;&lt;br/&gt;Multikey values use the multibase `f` (base16-lower) prefix throughout, so one&lt;br/&gt;document never mixes bases.&lt;br/&gt;&lt;br/&gt;A verifier MUST treat transport keys as bound to a DID only through a currently&lt;br/&gt;valid descriptor. An inbound connection from an Ed25519 key not named in an&lt;br/&gt;active descriptor originates from an unknown node.&lt;br/&gt;&lt;br/&gt;### The node descriptor&lt;br/&gt;&lt;br/&gt;Kind 11801, replaceable. This is the only binding artefact: it carries the&lt;br/&gt;node&#39;s class, the protocol version it speaks, its other two keys, its&lt;br/&gt;endpoints, and its expiry.&lt;br/&gt;&lt;br/&gt;```jsonc&lt;br/&gt;{&lt;br/&gt;  &#34;kind&#34;: 11801,&lt;br/&gt;  &#34;content&#34;: &#34;Community relay for the Bristol nostr meetup.&#34;,&lt;br/&gt;  &#34;tags&#34;: [&lt;br/&gt;    [&#34;class&#34;, &#34;edge&#34;],&lt;br/&gt;    [&#34;protocol&#34;, &#34;meshstr/0-draft&#34;, &#34;&lt;digest&gt;&#34;],&lt;br/&gt;    [&#34;software&#34;, &#34;&lt;a href=&#34;https://meshstr.org&#34;&gt;https://meshstr.org&lt;/a&gt;&#34;, &#34;0.2.0&#34;],&lt;br/&gt;    [&#34;key&#34;, &#34;agreement&#34;, &#34;fec01&lt;x25519&gt;&#34;, &#34;1795000000&#34;],&lt;br/&gt;    [&#34;key&#34;, &#34;transport&#34;, &#34;fed01&lt;ed25519&gt;&#34;],&lt;br/&gt;    [&#34;endpoint&#34;, &#34;iroh&#34;,   &#34;&lt;ticket&gt;&#34;,                 &#34;10&#34;],&lt;br/&gt;    [&#34;endpoint&#34;, &#34;libp2p&#34;, &#34;/dnsaddr/relay.example.org/p2p/&lt;peerid&gt;&#34;, &#34;20&#34;],&lt;br/&gt;    [&#34;endpoint&#34;, &#34;wss&#34;,    &#34;wss://relay.example.org&#34;,  &#34;40&#34;],&lt;br/&gt;    [&#34;mediator&#34;, &#34;did:nostr:&lt;anchor&gt;&#34;],&lt;br/&gt;    [&#34;c&#34;, &#34;&lt;a href=&#34;https://meshstr.org/peering/1.0&#34;&gt;https://meshstr.org/peering/1.0&lt;/a&gt;&#34;], [&#34;c&#34;, &#34;&lt;a href=&#34;https://meshstr.org/budget/1.0&#34;&gt;https://meshstr.org/budget/1.0&lt;/a&gt;&#34;],&lt;br/&gt;    [&#34;c&#34;, &#34;&lt;a href=&#34;https://meshstr.org/sync/1.0&#34;&gt;https://meshstr.org/sync/1.0&lt;/a&gt;&#34;],&lt;br/&gt;    [&#34;c&#34;, &#34;relay&#34;], [&#34;c&#34;, &#34;blossom&#34;], [&#34;c&#34;, &#34;mediator&#34;], [&#34;c&#34;, &#34;negentropy&#34;],&lt;br/&gt;    [&#34;coverage&#34;, &#34;&lt;digest of this node&#39;s coverage claim set&gt;&#34;],&lt;br/&gt;    [&#34;policy&#34;, &#34;&lt;sha256 of the policy doc&gt;&#34;, &#34;&lt;a href=&#34;https://relay.example.org/policy&#34;&gt;https://relay.example.org/policy&lt;/a&gt;&#34;],&lt;br/&gt;    [&#34;operator&#34;, &#34;&lt;operator pubkey&gt;&#34;],&lt;br/&gt;    [&#34;nonce&#34;, &#34;&lt;nip13 nonce&gt;&#34;, &#34;20&#34;],&lt;br/&gt;    [&#34;expiration&#34;, &#34;1789600000&#34;]&lt;br/&gt;  ]&lt;br/&gt;}&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;`endpoint`&#39;s fourth element is a preference value, low first. `expiration` is&lt;br/&gt;NIP-40 and is REQUIRED: a descriptor that outlives its operator&#39;s interest is&lt;br/&gt;how stale federations accumulate dead peers. Maximum lifetime is 30 days for&lt;br/&gt;anchors and edges, 24 hours for leaves.&lt;br/&gt;&lt;br/&gt;The `protocol` tag names the version and the digest of its machine-readable&lt;br/&gt;schema. Two nodes declaring different digests MUST decline to peer. There is no&lt;br/&gt;release authority; a version exists when nodes declare it and dies when they&lt;br/&gt;stop.&lt;br/&gt;&lt;br/&gt;A shared digest says two nodes read the same schema. It does not say either&lt;br/&gt;built all of it. So a node also declares which protocols it implements, as `c`&lt;br/&gt;tags whose value is the protocol identifier, one per tag. Every node MUST&lt;br/&gt;declare `peering/1.0` and `budget/1.0`: a node that cannot be proposed to or&lt;br/&gt;cannot account for what it sends is not a node. The other four are optional.&lt;br/&gt;These declarations are binding, unlike the plain capability words beside them,&lt;br/&gt;which are hints. A `discover-features/2.0` answer MUST agree with the&lt;br/&gt;descriptor, and a `peering/1.0/propose` repeats the list in its `protocols`&lt;br/&gt;field; a disagreement between any two of the three is `BAD_DESCRIPTOR`. A peer&lt;br/&gt;that shares the digest but lacks a protocol the peering needs is declined with&lt;br/&gt;`UNSUPPORTED_PROTOCOL`. Declining is not a finding.&lt;br/&gt;&lt;br/&gt;### The resolved DID document&lt;br/&gt;&lt;br/&gt;Given a DID whose subject has a live kind 11801, a `did:nostr` resolver emits a&lt;br/&gt;**node profile**: the minimal document plus `#agree` and `#wire` verification&lt;br/&gt;methods, a `DIDCommMessaging` service, and whatever `NostrRelay`,&lt;br/&gt;`BlossomServer` and `IrohNode` endpoints the descriptor declared. Resolution of&lt;br/&gt;ordinary user identities is unaffected, so a resolver can add this without&lt;br/&gt;changing any answer it already gives.&lt;br/&gt;&lt;br/&gt;### Revocation&lt;br/&gt;&lt;br/&gt;Kind 11802, replaceable. Peers MUST zero active grants on a valid revocation,&lt;br/&gt;and MUST NOT transfer accumulated standing to a successor. The `successor` tag&lt;br/&gt;is advisory: a successor node starts on probation and earns standing through&lt;br/&gt;clean windows.&lt;br/&gt;&lt;br/&gt;A revocation proves only that the key holder asked to retire. A legitimate&lt;br/&gt;operator and a compromise adversary can both publish one.&lt;br/&gt;&lt;br/&gt;## Discovery&lt;br/&gt;&lt;br/&gt;A new node needs somewhere to publish its descriptor, a way to hear about&lt;br/&gt;others, and a first peer willing to grant it anything. None of the three may&lt;br/&gt;require a centralised service.&lt;br/&gt;&lt;br/&gt;1. **Publish.** Write the kind 11801 descriptor to every relay in the node&#39;s own&lt;br/&gt;   kind 10002 relay list. Any nostr relay will do; it is an ordinary replaceable&lt;br/&gt;   event and needs no special support.&lt;br/&gt;2. **Announce.** Join the libp2p gossipsub topic `/meshstr/announce/1` and&lt;br/&gt;   republish the descriptor there, signed under StrictSign by the transport key.&lt;br/&gt;3. **Ask.** Open `peering/1.0/propose` to any node whose descriptor declares&lt;br/&gt;   the protocols you need. `discover-features/2.0` confirms the declaration&lt;br/&gt;   once a channel exists; it does not replace it.&lt;br/&gt;&lt;br/&gt;Enrolment can be open because the opening grant is worth almost nothing: a new&lt;br/&gt;peer starts at the `probation` tier, whose ceilings are listed below. NIP-13&lt;br/&gt;proof of work on the descriptor prices bulk identity creation.&lt;br/&gt;&lt;br/&gt;### Coverage&lt;br/&gt;&lt;br/&gt;Kind 30803, addressable. A node declares which shards it holds, as a filter&lt;br/&gt;plus a completeness claim, and a negentropy fingerprint over the set. A node&lt;br/&gt;MUST NOT publish `completeness: asserted` for shards it holds only through mesh&lt;br/&gt;replication — that is how third-party replication launders unverified peer data&lt;br/&gt;into authoritative records.&lt;br/&gt;&lt;br/&gt;There is one door through that rule, and it is signed by the node the rule&lt;br/&gt;protects against. A node that asserts a shard first-hand MAY hand it over: it&lt;br/&gt;signs a statement naming one replica, the shard, the range and the set, and&lt;br/&gt;sends it as `sync/1.0/handover` after a `done` that found the two sets equal.&lt;br/&gt;The replica then MAY publish `asserted` over exactly that set, carrying the&lt;br/&gt;handover inline under a `handover` tag. The content is&lt;br/&gt;`{&#34;handover&#34;: [artefact, ...]}` — a **chain**, ordered from the first-hand&lt;br/&gt;root to this claim — and the tag is SHA-256 of the last artefact&#39;s canonical&lt;br/&gt;form with `sig` excluded, the same construction a receipt is cited by. A&lt;br/&gt;reader hashes it, checks the signatures and resolves nothing.&lt;br/&gt;&lt;br/&gt;```jsonc&lt;br/&gt;// sync/1.0/handover — body, and the artefact a kind 30803 carries inline&lt;br/&gt;{&lt;br/&gt;  &#34;from&#34;:        &#34;&lt;pubkey of the node that holds the shard first-hand&gt;&#34;,&lt;br/&gt;  &#34;to&#34;:          &#34;&lt;pubkey of the one replica this is to&gt;&#34;,&lt;br/&gt;  &#34;shard&#34;:       &#34;bristol-2026H2&#34;,&lt;br/&gt;  &#34;claim&#34;:       &#34;&lt;event id of the signer&#39;s own kind 30803&gt;&#34;,&lt;br/&gt;  &#34;filter&#34;:      &#34;{\&#34;#t\&#34;:[\&#34;bristol\&#34;],\&#34;kinds\&#34;:[1]}&#34;,&lt;br/&gt;  &#34;since&#34;:       1751328000,&lt;br/&gt;  &#34;until&#34;:       1767225600,&lt;br/&gt;  &#34;fingerprint&#34;: &#34;&lt;NIP-77 fingerprint over the set&gt;&#34;,&lt;br/&gt;  &#34;count&#34;:       5,&lt;br/&gt;  &#34;at&#34;:          1787100000,&lt;br/&gt;  &#34;sig&#34;:         &#34;&lt;BIP-340 by from over SHA-256 of this body, sig excluded&gt;&#34;&lt;br/&gt;}&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;Three rules make the door narrow enough to leave open.&lt;br/&gt;&lt;br/&gt;**Exactly the handed set.** The replica&#39;s claim MUST carry the handover&#39;s&lt;br/&gt;filter, `since`, `until`, `fingerprint` and `count`, and `until` MUST NOT be&lt;br/&gt;later than `at`. Fingerprint equality with one upstream proves the replica&lt;br/&gt;holds what the upstream holds and nothing about the world, so the replica may&lt;br/&gt;assert only what somebody first-hand already asserted, over a range that had&lt;br/&gt;closed when they said so. What arrives after `until` the replica holds&lt;br/&gt;best-effort or claims first-hand under a claim of its own.&lt;br/&gt;&lt;br/&gt;**The signer is liable too.** A handover is the signer&#39;s own asserted claim&lt;br/&gt;over the set it names, and it is reportable against the signer the way a kind&lt;br/&gt;30803 is: a report cites it as evidence of kind `handover`. An event inside the&lt;br/&gt;range that the signer does not hold is a hole in the handover exactly as it is&lt;br/&gt;a hole in the replica&#39;s claim. Two nodes signed for one set and both answer&lt;br/&gt;for it.&lt;br/&gt;&lt;br/&gt;**No signer may report the hole.** A hole a signer files in a claim resting on&lt;br/&gt;its own handover is an event it held and did not pass on, or one it never held&lt;br/&gt;and vouched for anyway. Either way the fault is its own and the report would be&lt;br/&gt;the mechanism for laundering it onto the replica. A reader that holds the claim&lt;br/&gt;can decide this alone: a kind 30802 whose reporter is the `from` of **any** link&lt;br/&gt;in the chain its cited claim carries is discarded unread, like a report without&lt;br/&gt;a grant. Anyone else with a grant to the replica may file it.&lt;br/&gt;&lt;br/&gt;### Withdrawing a claim, and leaving in order&lt;br/&gt;&lt;br/&gt;A kind 30803 is addressable, so a node takes a claim back by republishing it at&lt;br/&gt;the same `d` as `best-effort` with a NIP-40 `expiration`. The assertion it&lt;br/&gt;replaces is dropped by relays, `best-effort` promises nothing and is not&lt;br/&gt;reportable, and the replacement lapses rather than outliving the node that made&lt;br/&gt;it. This is what the capacity ladder&#39;s `narrow_scope` rung means by a claim&lt;br/&gt;lapsing, and it is the last step of a retirement.&lt;br/&gt;&lt;br/&gt;A node that intends to stop SHOULD retire rather than go quiet, in this order:&lt;br/&gt;&lt;br/&gt;0. **Announce.** A heartbeat carrying `retiring`, before anything is given&lt;br/&gt;   away, so the silence that follows is not priced as stress by anyone&lt;br/&gt;   listening.&lt;br/&gt;1. **Close.** Every shard it asserts gets a range ending now. A handover signs&lt;br/&gt;   for a closed set, so an open range cannot be passed on — and the shards&lt;br/&gt;   worth passing on are exactly the ones nobody ever bounded.&lt;br/&gt;2. **Hand over.** A handover for each closed shard to each peer holding a live&lt;br/&gt;   grant, sent rather than waited for. A retiring node cannot wait out its&lt;br/&gt;   peers&#39; pull intervals, and the peer this matters most to is the one that is&lt;br/&gt;   offline while its only first-hand holder leaves, so the message is&lt;br/&gt;   store-and-forward. It is sent and not reconciled: the receiver keeps a&lt;br/&gt;   handover only where it fingerprints to what the receiver holds, so a&lt;br/&gt;   statement to a peer without the data is refused and costs nothing.&lt;br/&gt;3. **Withdraw.** Every claim republished as above. After the handovers and&lt;br/&gt;   never before, because a withdrawal replaces the very claim a handover&lt;br/&gt;   copies its terms from.&lt;br/&gt;4. **Farewell.** A receipt for every open window, which is what a node already&lt;br/&gt;   owes its issuers on the way out.&lt;br/&gt;&lt;br/&gt;A revocation (kind 11802) MAY follow, and only where the key itself is&lt;br/&gt;retiring: it is the one step nothing undoes. Everything before it is&lt;br/&gt;reversible by starting the node again. A restart MUST NOT run this sequence —&lt;br/&gt;a fleet upgrade that closed every range and gave away every shard&#39;s authority&lt;br/&gt;would pay exactly the cost the sequence exists to avoid.&lt;br/&gt;&lt;br/&gt;A handover MAY be over a claim that itself carries one, and then the replica&lt;br/&gt;MUST carry every link. Each link hands to the node that signs the next, every&lt;br/&gt;link names the same set, and no key appears twice; a chain is at most eight&lt;br/&gt;links. This is not bookkeeping. **Every signer in the chain is barred from&lt;br/&gt;reporting a hole in the set**, and carrying only the last link would leave the&lt;br/&gt;node that withheld an event able to report that hole against the node two&lt;br/&gt;links down — liable for it, unbarred, and filing the report the bar exists to&lt;br/&gt;stop, laundered through one intermediary. A reader checks the whole chain or&lt;br/&gt;it has checked nothing.&lt;br/&gt;&lt;br/&gt;A node that hands on a set it was handed MUST pass on the chain it holds with&lt;br/&gt;its own link appended. One that omits a link is declaring itself the&lt;br/&gt;first-hand holder of a set it did not receive first-hand, and takes the whole&lt;br/&gt;liability for it alone, which is the only way that statement can be priced.&lt;br/&gt;&lt;br/&gt;A handover moves no standing and touches no tier: the replica&#39;s claim is a new&lt;br/&gt;liability the replica chose to take, and each signer&#39;s remains its own.&lt;br/&gt;&lt;br/&gt;### Liveness&lt;br/&gt;&lt;br/&gt;Kind 21801, ephemeral. Carries the node&#39;s class, a digest of its current&lt;br/&gt;endpoint set (so a stale descriptor is detectable) and an advisory load figure.&lt;br/&gt;It names no peer and carries nothing about accounting. Anchors MUST publish one&lt;br/&gt;at least hourly. The `endpoints` digest is SHA-256 over the canonical JSON of&lt;br/&gt;the sorted `[scheme, address]` pairs the node is serving; the preference value&lt;br/&gt;is excluded. A heartbeat whose `class` contradicts the live descriptor is a&lt;br/&gt;misreport about itself, S2. Leaves MUST NOT publish one.&lt;br/&gt;&lt;br/&gt;A heartbeat MAY carry `retiring`, which says the publisher is leaving on&lt;br/&gt;purpose and now. It is the only thing in this protocol that tells a departure&lt;br/&gt;from a silence, and it exists because nothing else can: under FLP a node that&lt;br/&gt;went away and one that went quiet are indistinguishable, so a peer holding a&lt;br/&gt;schedule against a node that has retired records a partition it was told about&lt;br/&gt;in advance. A reader SHOULD NOT count the partition that follows a `retiring`&lt;br/&gt;heartbeat as stress from that direction. It is advisory, and a node cannot&lt;br/&gt;gain by publishing it falsely — the whole of what it asks for is that its&lt;br/&gt;peers stop expecting it. Being ephemeral, only a peer listening at the time&lt;br/&gt;hears one; a peer that was itself down records the partition, and that&lt;br/&gt;partition is true.&lt;br/&gt;&lt;br/&gt;## Control plane&lt;br/&gt;&lt;br/&gt;Everything two nodes say privately is DIDComm v2. Messages are DIDComm&lt;br/&gt;plaintext encrypted ECDH-1PU to the peer&#39;s `#agree` key, except first contact,&lt;br/&gt;which is anonymous ECDH-ES.&lt;br/&gt;&lt;br/&gt;meshstr reuses `out-of-band/2.0`, `discover-features/2.0`, `trust-ping/2.0`,&lt;br/&gt;`routing/2.0`, `report-problem/2.0` and `empty/1.0` unmodified, and defines six&lt;br/&gt;protocols of its own. Every message sent store-and-forward carries&lt;br/&gt;`please_ack`; the answer is an `ack` header, on the empty message when nothing&lt;br/&gt;else is due.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:protocols BEGIN — generated from schema/messages.json, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;| PIURI | Messages | Purpose |&lt;br/&gt;|---|---|---|&lt;br/&gt;| `peering/1.0` | propose, offer, accept, decline, amend, terminate | Establish and revise a peering. Terminates in a pair of grants, one per direction. |&lt;br/&gt;| `sync/1.0` | open, range, have, need, deliver, done, handover | Set reconciliation over a shard, carrying NIP-77 negentropy payloads. |&lt;br/&gt;| `budget/1.0` | receipt, receipt-ack, close, dispute | The self-accounting channel. Carries receipts and window closes. |&lt;br/&gt;| `complaint/1.0` | notice, evidence, remedy, appeal, withdraw | Present a finding to its subject before publishing it, and let the subject answer. |&lt;br/&gt;| `compute/1.0` | quote, accept, sealed, settled, refute | Negotiate and deliver one compute job. Quotes stay off the wire, so a price to one buyer is not a public commitment to every buyer. |&lt;br/&gt;| `standing/1.0` | ask, tell, decline | Ask a peer what it makes of a third node. Answering is discretionary; refusing is normal. |&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:protocols END --&gt;&lt;br/&gt;&lt;br/&gt;A DIDComm PIURI is an identifier, never fetched, so this namespace creates no&lt;br/&gt;runtime dependency on a domain anyone controls. Implementations MUST treat the&lt;br/&gt;string as opaque and compare it byte for byte.&lt;br/&gt;&lt;br/&gt;`complaint/1.0` is **mandatory-first** for S1 and S2: an issuer MUST deliver a&lt;br/&gt;notice and wait one window before publishing a kind 30802 report against a&lt;br/&gt;reachable peer. Most conformance failures are clock skew, a bug, or a misread&lt;br/&gt;limit, and a protocol that publishes before it asks produces a permanent public&lt;br/&gt;record of transient faults. S3 and S4 MAY be published immediately.&lt;br/&gt;&lt;br/&gt;### Transport&lt;br/&gt;&lt;br/&gt;Messages ride iroh (ALPN `meshstr/didcomm/1`), libp2p&lt;br/&gt;(`/meshstr/didcomm/1.0.0`), HTTPS (`POST /didcomm`), or nostr gift wrap — kind&lt;br/&gt;21059 by default, kind 1059 when store-and-forward is required. The nostr&lt;br/&gt;binding always works, which is what makes the ladder safe to attempt in order.&lt;br/&gt;&lt;br/&gt;For data transport, both peers rank the schemes their descriptors share by the&lt;br/&gt;sum of the two advertised preference values, low first; equal sums rank by&lt;br/&gt;scheme name, ascending bytewise, so both sides pick the same rung. A peer MUST&lt;br/&gt;NOT be reported unreachable until every shared rung has failed.&lt;br/&gt;&lt;br/&gt;## Replication&lt;br/&gt;&lt;br/&gt;A node MUST support NIP-77 to peer. Reconciliation is negentropy over the shard&lt;br/&gt;a grant scopes, and the range fingerprint is NIP-77&#39;s own — meshstr defines no&lt;br/&gt;second one. Events cross between nodes inside a delivery envelope, and every&lt;br/&gt;node that forwards one appends a hop `{node, at, sig}`:&lt;br/&gt;&lt;br/&gt;```&lt;br/&gt;msg = SHA256(&#34;meshstr/hop/1&#34; || &#34;|&#34; || event_id || &#34;|&#34; || prev_hop || &#34;|&#34; || at)&lt;br/&gt;sig = BIP-340(node_key, msg)&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;`event_id` is the wrapped event&#39;s id as 64 lowercase hex; `prev_hop` is the&lt;br/&gt;previous hop&#39;s `node` string exactly as written, empty for the first hop; `at`&lt;br/&gt;is that hop&#39;s own unix seconds in decimal. A field a signature does not cover&lt;br/&gt;is a field anyone may rewrite, so `at` is inside it: a hop is a statement that&lt;br/&gt;this node sent this event at this moment, which is what lets it stand as&lt;br/&gt;evidence. It is also the only artefact a forwarder signs for an event it did&lt;br/&gt;not write. A&lt;br/&gt;receiver charges every node in the path it holds a grant with, which is what&lt;br/&gt;closes grant-evasion routing. A path MUST NOT exceed three hops.&lt;br/&gt;&lt;br/&gt;A range fingerprint is taken over a set, and implementations MUST agree on&lt;br/&gt;which events are in it or they will compute NIP-77 correctly and still never&lt;br/&gt;converge. Four rules decide membership. Ephemeral kinds&lt;br/&gt;(`20000 &lt;= n &lt; 30000`) are never stored. Replaceable and addressable&lt;br/&gt;kinds retain only the winner: later `created_at`, and on a tie the&lt;br/&gt;lexicographically lower id. A NIP-09 deletion removes only events its own&lt;br/&gt;author signed, permanently, and binds even when it arrives before its target,&lt;br/&gt;so a tombstone MUST record which key asked and the authority check happens on&lt;br/&gt;arrival. An event whose NIP-40 expiration has passed is not in the set. The&lt;br/&gt;`since`/`until` arguments and a filter&#39;s own are intersected, never widened.&lt;br/&gt;Enumeration is ordered by `created_at` ascending, then id ascending.&lt;br/&gt;&lt;br/&gt;Two kinds never cross. Kind 24133 (NIP-46 signer traffic) MUST NOT be&lt;br/&gt;replicated on any transport under any grant. Kind 1059 replicates only to nodes&lt;br/&gt;named in the recipient&#39;s own kind 10050 relay list, never in bulk and never on&lt;br/&gt;a filter a third party supplied.&lt;br/&gt;&lt;br/&gt;## Grants and receipts&lt;br/&gt;&lt;br/&gt;A node does not rate-limit its peers privately. It **publishes the budget** and&lt;br/&gt;makes the peer account for its own consumption.&lt;br/&gt;&lt;br/&gt;### The grant&lt;br/&gt;&lt;br/&gt;Kind 30801, addressable. The grant itself is NIP-44 ciphertext addressed to the&lt;br/&gt;subject; what is public is a commitment to it.&lt;br/&gt;&lt;br/&gt;The `d` tag is a blinded pair identifier derived with HKDF-SHA256 over the&lt;br/&gt;issuer/subject ECDH x-coordinate, so only the two parties can derive it. Third&lt;br/&gt;parties see that a grant exists and cannot see between whom, or for how much.&lt;br/&gt;Grants are never published in the clear: a public grant table exposes the&lt;br/&gt;complete peering graph with standing scores attached.&lt;br/&gt;&lt;br/&gt;Third parties ask about a node over `standing/1.0` instead. Answering is&lt;br/&gt;discretionary and declining is not adverse.&lt;br/&gt;&lt;br/&gt;### The receipt&lt;br/&gt;&lt;br/&gt;The subject maintains a token bucket mirroring each limit and, at the cadence&lt;br/&gt;the grant names, sends a signed receipt over `budget/1.0`. Receipts within a&lt;br/&gt;window form a hash chain — `prev` is the SHA-256 of the canonical form of the&lt;br/&gt;previous receipt — so a subject cannot rewrite an earlier claim after learning&lt;br/&gt;what the issuer saw. The issuer keeps only the head.&lt;br/&gt;&lt;br/&gt;The canonical form is the one every digest in this document uses (`canonical`&lt;br/&gt;in `constants.json`): the body as JSON, UTF-8, object keys sorted ascending by&lt;br/&gt;code point, no whitespace between tokens. `prev` for `seq` 0 is thirty-two zero&lt;br/&gt;bytes. Counters are integers, so no number-formatting question arises.&lt;br/&gt;&lt;br/&gt;```jsonc&lt;br/&gt;// budget/1.0/receipt — body&lt;br/&gt;{&lt;br/&gt;  &#34;grant&#34;:  &#34;&lt;event id of the kind 30801 in force&gt;&#34;,&lt;br/&gt;  &#34;window&#34;: 496389,&lt;br/&gt;  &#34;seq&#34;:    7,&lt;br/&gt;  &#34;prev&#34;:   &#34;&lt;sha256 of the canonical form of receipt seq 6&gt;&#34;,&lt;br/&gt;  &#34;counters&#34;: {&lt;br/&gt;    &#34;conn_open&#34;: 2, &#34;req&#34;: 141, &#34;events_in&#34;: 802,&lt;br/&gt;    &#34;bytes_in&#34;: 2216041, &#34;bytes_out&#34;: 19883, &#34;blob_bytes&#34;: 0,&lt;br/&gt;    &#34;errors&#34;: 1, &#34;dups_sent&#34;: 44, &#34;sync_ranges&#34;: 61&lt;br/&gt;  },&lt;br/&gt;  &#34;forwarded_for&#34;: [&#34;did:nostr:&lt;origin&gt;&#34;],&lt;br/&gt;  &#34;at&#34;: 1787003600,&lt;br/&gt;  &#34;sig&#34;: &#34;&lt;BIP-340 by the subject node key over this receipt&#39;s chain link&gt;&#34;&lt;br/&gt;}&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;`sig` is the subject&#39;s signature over the chain link, which is SHA-256 of the&lt;br/&gt;canonical body with `sig` itself excluded. Excluding it means the link is the&lt;br/&gt;same value before and after signing, so signing disturbs no chain and the head&lt;br/&gt;the issuer acknowledges is exactly the message that was signed. A receipt&lt;br/&gt;without a valid `sig` is not a claim anyone can be held to, and an issuer&lt;br/&gt;answers one with `divergent`.&lt;br/&gt;&lt;br/&gt;A window prices each limit against the counter of the same name. Where the&lt;br/&gt;names differ, `counter_of` in `constants.json` names the counter: `conn_rate`&lt;br/&gt;is priced against `conn_open`, the sessions the subject opened in the window,&lt;br/&gt;on whatever transport carried them. `conn_max` and `sub_max` are advisory and&lt;br/&gt;not in the ceiling table, because a cumulative receipt cannot carry a gauge and&lt;br/&gt;peers never open a subscription on a relay face.&lt;br/&gt;&lt;br/&gt;`at` is the subject&#39;s own clock. Both ends are expected to be&lt;br/&gt;NTP-disciplined: the window&#39;s grace period absorbs ordinary skew, and drift&lt;br/&gt;beyond `max_clock_skew_seconds` produces divergence findings nobody earned. An&lt;br/&gt;issuer SHOULD record a receipt timed further than that from its own clock as a&lt;br/&gt;diagnosis rather than a finding, because the remedy is a clock and not the&lt;br/&gt;ladder.&lt;br/&gt;&lt;br/&gt;Counters are cumulative within the window and strictly monotonic. The window&lt;br/&gt;is evaluated against the most recent receipt the issuer received for it: that&lt;br/&gt;receipt&#39;s counters are the subject&#39;s claim, and traffic measured after it is&lt;br/&gt;compared against them and priced by divergence. Nothing moving after the last&lt;br/&gt;receipt is a clean window, which is how a leaf that syncs and then sleeps&lt;br/&gt;produces no finding. Measured traffic with no receipt at all is active silence,&lt;br/&gt;S2 — and that is a floor, not a ceiling: the measured traffic is still evaluated&lt;br/&gt;against the limits and against the empty claim, and the window takes the worse&lt;br/&gt;of the two. A peer that overran and said nothing must not be cheaper than one&lt;br/&gt;reporting it honestly. `budget/1.0/close` is optional: a final receipt, accepted as final when it&lt;br/&gt;arrives within the grace period of one tenth of the window. The issuer answers&lt;br/&gt;every receipt privately with `receipt-ack` carrying the head it holds and one of&lt;br/&gt;`accepted`, `divergent` or `final`.&lt;br/&gt;&lt;br/&gt;**Clean windows publish no public events.** Positive reports are arithmetically&lt;br/&gt;inert under the trust weighting below, so broadcasting them would leak&lt;br/&gt;bilateral topology and add nothing. Only adverse findings are published.&lt;br/&gt;&lt;br/&gt;### Window arithmetic&lt;br/&gt;&lt;br/&gt;Evaluated by the issuer at window close, per limit ℓ:&lt;br/&gt;&lt;br/&gt;```&lt;br/&gt;overrun_ℓ    = max(0, measured_ℓ / limit_ℓ - 1)&lt;br/&gt;divergence_ℓ = |measured_ℓ - claimed_ℓ| / max(measured_ℓ, floor_ℓ)&lt;br/&gt;severity     = max over all ℓ of class(overrun_ℓ, divergence_ℓ)&lt;br/&gt;&lt;br/&gt;clean : strain_ℓ = min(1, measured_ℓ / limit_ℓ)&lt;br/&gt;        if measured and strain_ℓ = 0 and limit_ℓ &gt; open_ℓ&lt;br/&gt;          limit_ℓ ← max(open_ℓ, limit_ℓ × 0.90)        # decay by disuse&lt;br/&gt;        else&lt;br/&gt;          limit_ℓ ← limit_ℓ &#43; tier_base_ℓ × max(0.02, 0.10 × strain_ℓ)&lt;br/&gt;S1    : limit_ℓ ← max(probation_ℓ, limit_ℓ × 0.50)&lt;br/&gt;S2    : limit_ℓ ← max(probation_ℓ, limit_ℓ × 0.25) ; tier ← probation&lt;br/&gt;S3    : limit_ℓ ← 0 for 24h, then resume at probation&lt;br/&gt;S4    : tier ← revoked ; grant deleted ; report published&lt;br/&gt;&lt;br/&gt;then, always : limit_ℓ ← min(tier_max_ℓ, limit_ℓ)  at the tier the branch returns&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;A grant opens BELOW the ceiling of its tier: volume at `opening_limit_fraction`&lt;br/&gt;of it, the structural limits (`conn_rate`, `req`, `sync_ranges`, `errors`) at the&lt;br/&gt;ceiling, because a peer needs enough plumbing to demonstrate anything at all. A&lt;br/&gt;grant that opened at the ceiling made the additive increase a no-op, so nothing&lt;br/&gt;grew and every capacity could only be eroded. The clean step is then scaled by&lt;br/&gt;what the window carried, with a floor, so growth is priced in work rather than in&lt;br/&gt;windows. An evaluation offering no measurement gets the floor step, never the&lt;br/&gt;full one.&lt;br/&gt;&lt;br/&gt;A limit is also taken back where it went unused, floored at the tier&#39;s opening&lt;br/&gt;limits: what a peer has not used it gives back, what every peering is given it&lt;br/&gt;keeps. A peering whose windows measure nothing at all for `decay_idle_windows`&lt;br/&gt;in a row has its whole grant decayed. No measurement is not a measurement of&lt;br/&gt;zero — an evaluation offering no counters gets the floor step and no decay, in&lt;br/&gt;either direction. A decay is amended with `cause: disuse`.&lt;br/&gt;&lt;br/&gt;A grant MUST NOT carry a limit above the ceiling of the tier it names. That holds&lt;br/&gt;for a remedy as much as for a first issue, and it binds hardest at S2, the one&lt;br/&gt;branch that lowers the tier: a quarter of any higher tier&#39;s limit is still far&lt;br/&gt;above what probation allows, so the ceiling decides and the quartering never gets&lt;br/&gt;to. S2 does not leave a peer a quarter of what it had. It makes it a stranger&lt;br/&gt;again.&lt;br/&gt;&lt;br/&gt;### The node&#39;s own ceiling&lt;br/&gt;&lt;br/&gt;A grant bounds one peer and nothing bounds the node: the meter is per peering, so&lt;br/&gt;twenty anchor grants each inside its own limit is 960,000 events an hour with&lt;br/&gt;nobody at fault. A node declares its own total and sheds against it.&lt;br/&gt;&lt;br/&gt;**The total is the operator&#39;s number and this NIP states no default.** A class&lt;br/&gt;declares connectivity and not capability, so a Raspberry Pi and a forty-core&lt;br/&gt;gateway both say anchor. A node with no declared total measures its pressure,&lt;br/&gt;reports it and sheds nothing. What is normative is the ladder.&lt;br/&gt;&lt;br/&gt;```&lt;br/&gt;pressure = max over counters of (window aggregate over all peers / declared total)&lt;br/&gt;&lt;br/&gt;0.75  refuse_peerings   a new proposal is declined CAPACITY_EXCEEDED;&lt;br/&gt;                        peerings already held are untouched&lt;br/&gt;0.85  narrow_scope      shards held only through the mesh stop being claimed&lt;br/&gt;                        and the claims already published are withdrawn&lt;br/&gt;0.95  amend_down        every live grant is reduced, cause: capacity&lt;br/&gt;1.00  leaf_behaviour    no pull is opened; receipts still flow&lt;br/&gt;&lt;br/&gt;release: every rung together, below 0.60&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;A shed is announced, it is not adverse, and it makes a peer smaller and never a&lt;br/&gt;stranger. `peering/1.0/amend` carries `cause`, one of `remedy`, `capacity` or&lt;br/&gt;`operator`; only `remedy` is a finding. The shed floor is a fraction of the&lt;br/&gt;probation ceiling and not the ceiling itself, because a peering opens at that&lt;br/&gt;ceiling and a floor there would make the rung do nothing for exactly the peers a&lt;br/&gt;busy node has most of. It is not zero: zero for 24h is what S3 does.&lt;br/&gt;&lt;br/&gt;### Stress a node survived&lt;br/&gt;&lt;br/&gt;A restart, a peer that went quiet, a relay that dropped, a clock that drifted:&lt;br/&gt;each is correctly refused as a finding about a peer and then discarded, so the&lt;br/&gt;information goes out with the accusation. Kept, it sets the node&#39;s own reserves.&lt;br/&gt;&lt;br/&gt;Two rules. **Local and defensive only** — a strain record never becomes a&lt;br/&gt;finding and never crosses the wire, and a peer&#39;s own account of what it has&lt;br/&gt;weathered is a claim, not evidence. If a node&#39;s whole response to stress is to&lt;br/&gt;be readier for that stress, an attacker who causes it gains nothing.&lt;br/&gt;**Directions, never magnitude** — a reserve grows with the number of independent&lt;br/&gt;directions (one peer, one shard, one transport), each capped, each weighted by&lt;br/&gt;the tier this node granted that peer. Probation weighs 0.0, so free identities&lt;br/&gt;buy no directions and a tier is only raised by a person. One peer moves a node&lt;br/&gt;by at most one direction&#39;s worth however hard it pushes.&lt;br/&gt;&lt;br/&gt;A node whose strain is nearly all one direction is a flag tree: structurally&lt;br/&gt;dependent on that peer, and it will snap when the peer leaves. Reported to the&lt;br/&gt;operator; never a finding.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:severity BEGIN — generated from schema/constants.json, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;```&lt;br/&gt;class(overrun, divergence) -&gt; severity, evaluated per limit&lt;br/&gt;&lt;br/&gt;  by_overrun = S3 if overrun &gt;= 4.0  else&lt;br/&gt;               S2 if overrun &gt;= 1.0  else&lt;br/&gt;               S1 if overrun &gt;= 0.1  else  S0&lt;br/&gt;&lt;br/&gt;  if divergence &gt; 0.1  -&gt; worse(by_overrun, S2)   // a floor, never a ceiling&lt;br/&gt;  otherwise            -&gt; by_overrun&lt;br/&gt;&lt;br/&gt;dup_ratio is evaluated in the same window and is not a counter: it has no&lt;br/&gt;line in a grant, so nothing scales it, and its ceiling is 0.15 at every tier.&lt;br/&gt;The receiver alone knows what it already held, so there is no claim to&lt;br/&gt;compare and no divergence term:&lt;br/&gt;&lt;br/&gt;  class(dups_sent / events_in / 0.15 - 1, 0)&lt;br/&gt;&lt;br/&gt;and it is not evaluated when events_in is under the divergence floor,&lt;br/&gt;where a ratio is noise.&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:severity END --&gt;&lt;br/&gt;&lt;br/&gt;A window&#39;s severity is the most severe across all its limits. S4 is never&lt;br/&gt;reached by arithmetic: it is forgery or impersonation, found structurally.&lt;br/&gt;&lt;br/&gt;Mind the units. A `schedule` tag is a ratio *of the limit* — `1.1` means 110% —&lt;br/&gt;while overrun is `measured/limit - 1`. A schedule ratio *r* is an overrun&lt;br/&gt;threshold of *r* − 1. Reading one as the other is the likeliest implementation&lt;br/&gt;bug in this section.&lt;br/&gt;&lt;br/&gt;### Tier ceilings&lt;br/&gt;&lt;br/&gt;A grant MAY set any limit lower than its tier ceiling; it MUST NOT set one&lt;br/&gt;higher. AIMD grows a limit toward the ceiling and reductions floor at the&lt;br/&gt;probation ceiling.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:tiers BEGIN — generated from schema/constants.json, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;| Ceiling | probation | member | trusted | anchor |&lt;br/&gt;|---|---|---|---|---|&lt;br/&gt;| `conn_rate` | 4 | 12 | 48 | 192 |&lt;br/&gt;| `req` | 60 | 600 | 2400 | 9600 |&lt;br/&gt;| `events_in` | 300 | 3000 | 12000 | 48000 |&lt;br/&gt;| `bytes_in` | 3355443 | 33554432 | 134217728 | 536870912 |&lt;br/&gt;| `bytes_out` | 26843545 | 268435456 | 1073741824 | 4294967296 |&lt;br/&gt;| `blob_bytes` | 1677721 | 16777216 | 67108864 | 268435456 |&lt;br/&gt;| `sync_ranges` | 100 | 400 | 1600 | 6400 |&lt;br/&gt;| `errors` | 4 | 40 | 160 | 640 |&lt;br/&gt;&lt;br/&gt;Tier weight in trust aggregation: `probation` 0.0, `member` 0.25, `trusted` 0.6, `anchor` 1.0. A reader that holds no grant to a reporter weights it at zero.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:tiers END --&gt;&lt;br/&gt;&lt;br/&gt;`dup_ratio` is a quality signal rather than a capacity, and is 0.15 at every&lt;br/&gt;tier. It is evaluated in the window as `dups_sent / events_in` against that&lt;br/&gt;ceiling through the same `class(overrun, divergence)` as every limit, with no&lt;br/&gt;divergence term: the receiver alone knows what it already held, so there is no&lt;br/&gt;claim to compare. It has no line in the grant and is never scaled. A ratio over&lt;br/&gt;fewer events than the divergence floor is not evaluated.&lt;br/&gt;&lt;br/&gt;## The severity ladder&lt;br/&gt;&lt;br/&gt;The remedy for a given breach is deterministic and stated in the grant *before*&lt;br/&gt;the breach happens. An operator who can choose the punishment after seeing the&lt;br/&gt;offender is doing moderation, and moderation does not federate.&lt;br/&gt;&lt;br/&gt;| | Name | What it is | Remedy |&lt;br/&gt;|---|---|---|---|&lt;br/&gt;| S0 | drift | within 110% of every limit, receipts agree with measurement | none; counts toward the clean-window streak |&lt;br/&gt;| S1 | overrun | sustained traffic over a limit, accurately reported — honest but unshaped | limit × 0.5, notice first, no publication on first occurrence |&lt;br/&gt;| S2 | misreport | receipts diverge beyond tolerance, fail to arrive during active egress, or declared metadata contradicts observation | tier → probation, limits to the probation ceiling, report published after notice |&lt;br/&gt;| S3 | abuse | traffic outside granted scopes, malformed floods, excessive duplicates, repeated hop-limit violations | limits → 0 for 24h, report published immediately with evidence |&lt;br/&gt;| S4 | malice | forged signatures, corrupted receipt chains, transport key impersonation, shard poisoning, grant-evasion routing | revoked, grant deleted, report published, peers re-evaluate |&lt;br/&gt;&lt;br/&gt;**The ordering is the argument.** S1 overruns rank *below* S2 misreports. A peer&lt;br/&gt;that exceeds its capacity but reports accurately is treated more leniently than&lt;br/&gt;one that underreports. Capacity overruns are operational. Falsified reporting&lt;br/&gt;destroys the accounting everything else rests on.&lt;br/&gt;&lt;br/&gt;### The report&lt;br/&gt;&lt;br/&gt;Kind 30802, addressable, `d` = subject pubkey, one per (reporter, subject),&lt;br/&gt;replaced as the relationship evolves. It carries the reporter&#39;s current verdict,&lt;br/&gt;not a log.&lt;br/&gt;&lt;br/&gt;Two rules make it admissible:&lt;br/&gt;&lt;br/&gt;- **Adverse only.** `outcome` is S1..S4. There is no positive attestation.&lt;br/&gt;- **Evidence or nothing.** A report MUST name, in its `grant` tag, a grant the&lt;br/&gt;  reporter itself issued to the subject, and every `evidence` entry MUST be&lt;br/&gt;  something the subject itself signed. A report without a grant is discarded&lt;br/&gt;  unread.&lt;br/&gt;&lt;br/&gt;Evidence travels **inline**. The report&#39;s `content` is&lt;br/&gt;`{&#34;note&#34;: &lt;string&gt;, &#34;evidence&#34;: {&lt;id&gt;: &lt;artefact&gt;}}`, where `&lt;id&gt;` is SHA-256 of&lt;br/&gt;the artefact&#39;s canonical form and is what the `evidence` tag carries. A reader&lt;br/&gt;hashes the artefact, compares it to the tag, and checks the subject&#39;s signature&lt;br/&gt;on it, resolving nothing. This is not decoration: a receipt and a delivery&lt;br/&gt;envelope are private DIDComm bodies that no relay serves, so a reference to one&lt;br/&gt;resolves to nothing anywhere, and a report about divergence could otherwise be&lt;br/&gt;checked by no one but its author. An `event` entry MAY instead be a bare&lt;br/&gt;reference, because a nostr event is public already.&lt;br/&gt;&lt;br/&gt;Evidence pins the subject&#39;s half of a disagreement and no more. Nobody but the&lt;br/&gt;reporter observed the traffic, so a reader takes the measurement on the&lt;br/&gt;reporter&#39;s standing and checks only that the subject really said what it is&lt;br/&gt;quoted as saying. Two nodes that measured differently disagree without either&lt;br/&gt;being refuted.&lt;br/&gt;&lt;br/&gt;**Active silence cannot be reported, and that is the answer rather than a gap.**&lt;br/&gt;A window with measured traffic and no receipt is S2 at least, but the subject&lt;br/&gt;signed nothing that window, so there is nothing of its own to quote and no&lt;br/&gt;reader could check either half of the claim. The remedy is the local one: the&lt;br/&gt;grant goes to zero, and `standing/1.0` carries the streak to anyone who asks.&lt;br/&gt;&lt;br/&gt;Nobody imports anybody&#39;s bans. A report is an input to the reader&#39;s own trust&lt;br/&gt;weighting, never an instruction. Reports may only *lower* a view, are weighted&lt;br/&gt;by the reporter&#39;s tier from the reader&#39;s own perspective, and a reader that&lt;br/&gt;holds no grant to the reporter weights it at zero.&lt;br/&gt;&lt;br/&gt;## Compute&lt;br/&gt;&lt;br/&gt;Nodes MAY sell deterministic WASI compute to each other. The market has no&lt;br/&gt;global state and nowhere to put a rake: asks and receipts are ordinary events,&lt;br/&gt;and settlement is peer to peer over Lightning.&lt;br/&gt;&lt;br/&gt;A **compute offer** (kind 11803) advertises executors and prices. Prices are&lt;br/&gt;quoted per engine: instruction fuel is an artifact of the runtime, so the order&lt;br/&gt;book is segmented by the `runtime` tag — engine, version, and the digest of its&lt;br/&gt;capability profile — and quotes across engines are never compared.&lt;br/&gt;&lt;br/&gt;### The ask prices the work without describing it&lt;br/&gt;&lt;br/&gt;An ask has to reach sellers the buyer has not chosen yet. It does not have to&lt;br/&gt;say what the job is, and those are separable.&lt;br/&gt;&lt;br/&gt;Kind 30810 carries only what a seller needs to quote: executor, engine, fuel&lt;br/&gt;ceiling, input length, deadline, bid, and the verification mode. The module and&lt;br/&gt;input digests are carried in a `commit` tag and travel in&lt;br/&gt;`compute/1.0/accept`, encrypted to the one seller that wins.&lt;br/&gt;&lt;br/&gt;This is not a new construction — it is the kind 30801 grant envelope reused. A&lt;br/&gt;public ask and a public receipt together would form a permanent, signed log of&lt;br/&gt;who computed what over whose data for how much, beside a grant system that goes&lt;br/&gt;to real trouble to hide exactly that. A module digest alone identifies the&lt;br/&gt;computation.&lt;br/&gt;&lt;br/&gt;Kind 30811 follows for the same reason. A receipt is a record of a job that went&lt;br/&gt;right, and this protocol does not publish positive events: the envelope carries a&lt;br/&gt;blinded job identifier and a commitment, and everything the receipt is about sits&lt;br/&gt;inside NIP-44 ciphertext addressed to the buyer. A seller MAY publish a cleartext&lt;br/&gt;receipt where the buyer consents.&lt;br/&gt;&lt;br/&gt;### Verification is a declared mode&lt;br/&gt;&lt;br/&gt;Re-execution is a fine mechanism and a poor requirement: it obliges whoever&lt;br/&gt;adjudicates to hold the plaintext. So the mode is named in the ask, before the&lt;br/&gt;work, the same way a grant names its remedy before the breach. A refutation&lt;br/&gt;citing evidence the declared mode does not admit is not a finding.&lt;br/&gt;&lt;br/&gt;| Mode | Evidence a dispute admits | Needs plaintext? |&lt;br/&gt;|---|---|---|&lt;br/&gt;| `sample` | an independent re-run contradicting the seller-signed hash | yes |&lt;br/&gt;| `dual` | two executors returning different hashes for one job | yes |&lt;br/&gt;| `proof` | the proof fails against the module and input commitments | **no** |&lt;br/&gt;| `none` | delivery only — the sealed commitment against the preimage | no |&lt;br/&gt;&lt;br/&gt;Under `proof` the seller returns evidence that the committed module, run on the&lt;br/&gt;committed input, produced the committed result. Nobody re-runs. That is what&lt;br/&gt;makes confidentiality affordable: a proof-mode receipt can be adjudicated by a&lt;br/&gt;third party who never sees the job.&lt;br/&gt;&lt;br/&gt;Confidentiality and verifiable work units are one property, not two.&lt;br/&gt;Confidentiality is only affordable if correctness does not require re-execution,&lt;br/&gt;and correctness only stops requiring re-execution if the unit carries its own&lt;br/&gt;proof.&lt;br/&gt;&lt;br/&gt;`proof` ships as an expressible mode with **no reference implementation**.&lt;br/&gt;Proving costs orders of magnitude more than executing and breaks the price&lt;br/&gt;denominator, since a prover&#39;s bill is not proportional to the fuel it proves&lt;br/&gt;about. It is a named direction, on the same footing as contingent payment. Proof&lt;br/&gt;generation is itself a good job for this market to sell.&lt;br/&gt;&lt;br/&gt;### Delivery&lt;br/&gt;&lt;br/&gt;Accountable rather than atomic: the seller signs `compute/1.0/sealed` before&lt;br/&gt;payment, so a key that does not open the ciphertext is provable. A buyer can&lt;br/&gt;still be defrauded once per seller and recovers nothing; the remedy is&lt;br/&gt;reputational, which is the same bargain the rest of this document makes.&lt;br/&gt;&lt;br/&gt;Hardware-attested execution (TEE) is **refused, not deferred**. It is the only&lt;br/&gt;practical way to hide a job from the node running it, and every form of it&lt;br/&gt;terminates in a remote attestation signed by a hardware vendor&#39;s root key. This&lt;br/&gt;protocol has no authorities by construction.&lt;br/&gt;&lt;br/&gt;## Event kinds&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:kinds BEGIN — generated from schema/kinds.json, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;| Kind | Class per NIP-01 | Name | Content |&lt;br/&gt;|---|---|---|---|&lt;br/&gt;| `11801` | replaceable | node descriptor | free |&lt;br/&gt;| `11802` | replaceable | node revocation | free |&lt;br/&gt;| `11803` | replaceable | compute offer | empty |&lt;br/&gt;| `21801` | ephemeral | node heartbeat | empty |&lt;br/&gt;| `21802` | ephemeral | diagnostic telemetry | empty |&lt;br/&gt;| `30801` | addressable | peer grant envelope | nip44 ciphertext of the grant |&lt;br/&gt;| `30802` | addressable | conformance report | free |&lt;br/&gt;| `30803` | addressable | coverage claim | empty |&lt;br/&gt;| `30810` | addressable | compute ask | empty |&lt;br/&gt;| `30811` | addressable | job receipt | nip44 ciphertext of the job receipt |&lt;br/&gt;&lt;br/&gt;Ranges are NIP-01&#39;s: replaceable is `10000 ≤ n &lt; 20000`, ephemeral is `20000 ≤ n &lt; 30000`, addressable is `30000 ≤ n &lt; 40000`.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:kinds END --&gt;&lt;br/&gt;&lt;br/&gt;Every kind carries the tags below. Formal JSON Schema (Draft 2020-12) for all of&lt;br/&gt;them, plus the DIDComm bodies, decrypted payloads and DID documents, is at&lt;br/&gt;**&lt;a href=&#34;https://www.meshstr.org/schemas.html&#34;&gt;https://www.meshstr.org/schemas.html&lt;/a&gt;**.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:kindtags BEGIN — generated from schema/kinds.json, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;#### `11801` — node descriptor&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `class`, `protocol`, `c`, `expiration` |&lt;br/&gt;| OPTIONAL | `software`, `key`, `endpoint`, `mediator`, `nips`, `coverage`, `policy`, `operator`, `nonce` |&lt;br/&gt;&lt;br/&gt;&gt; C is one capability per tag, repeated. NIP-01 indexes only single-letter tags, so a multi-letter capability tag cannot be queried and a leaf could not find a mediator without downloading every descriptor. A meshstr protocol identifier as the value declares that the node implements that protocol, and that declaration is binding. Every node declares peering/1.0 and budget/1.0, which is why c is required.&lt;br/&gt;&lt;br/&gt;#### `11802` — node revocation&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `reason` |&lt;br/&gt;| OPTIONAL | `successor` |&lt;br/&gt;&lt;br/&gt;#### `11803` — compute offer&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `executor`, `expiration` |&lt;br/&gt;| OPTIONAL | `limit`, `pay`, `runtime` |&lt;br/&gt;&lt;br/&gt;#### `21801` — node heartbeat&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `class` |&lt;br/&gt;| OPTIONAL | `endpoints`, `load`, `retiring` |&lt;br/&gt;&lt;br/&gt;&gt; Liveness only, named after no peer: an anchor publishes one at least hourly. It carries nothing about accounting, because a node holds one receipt chain per issuer and a single &#34;latest head&#34; has no referent. retiring says the publisher is leaving on purpose and now. Advisory: a peer that reads one SHOULD NOT count the partition that follows as stress from that direction, because it was told. Under FLP nothing else can tell a node that went away from one that went quiet, and a node cannot gain by publishing it: it asks its peers to stop expecting it.&lt;br/&gt;&lt;br/&gt;#### `21802` — diagnostic telemetry&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `sample_window` |&lt;br/&gt;| OPTIONAL | `metric`, `expiration` |&lt;br/&gt;&lt;br/&gt;&gt; Opt-in. Counters are coarse-binned and aggregated over the whole node for the sample window, with no per-peer attribution. Alpha measurement only; see the alpha contract.&lt;br/&gt;&lt;br/&gt;#### `30801` — peer grant envelope&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `d`, `commit`, `scheme`, `window`, `epoch`, `expiration` |&lt;br/&gt;| OPTIONAL | — |&lt;br/&gt;&lt;br/&gt;&gt; D is HKDF-SHA256 over the issuer/subject ECDH x-coordinate under blinding.grant&#39;s salt and info; commit is SHA256(blinding || canonical grant) per commitment.scheme; blinding is fresh random per commitment (commitment.blinding_factor); the grant itself is never public&lt;br/&gt;&lt;br/&gt;#### `30802` — conformance report&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `d`, `outcome`, `grant`, `windows`, `evidence`, `expiration` |&lt;br/&gt;| OPTIONAL | `observed`, `claimed`, `notice` |&lt;br/&gt;&lt;br/&gt;&gt; Adverse only: outcome is S1..S4, never a positive attestation. grant MUST reference a grant the reporter itself issued to the subject; a report without one is discarded unread. Evidence travels inline in the content, as {note, evidence: {id: artefact}}, because receipts and delivery envelopes are private bodies no relay serves; an evidence entry of kind event may instead be a bare reference. See grant.evidence. The report carries the kind 30801 the grant tag names in that same inline map, keyed by its id: a grant is addressable under a blinded d, so the one that governed a past window has been replaced at that coordinate and no relay serves it, and a report that did not carry its own stopped being admissible to anyone about an hour after it was published. A reader takes the carried copy over the relays and holds it to more: it must be the id it is filed under, signed, kind 30801, and by the reporter.&lt;br/&gt;&lt;br/&gt;#### `30803` — coverage claim&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `d`, `filter`, `completeness` |&lt;br/&gt;| OPTIONAL | `since`, `until`, `fingerprint`, `count`, `handover`, `expiration` |&lt;br/&gt;&lt;br/&gt;&gt; A node MUST NOT publish completeness asserted for shards it holds only through mesh replication, with one door: a handover. The node that holds the shard first-hand signs {from, to, shard, claim, filter, since, until, fingerprint, count, at} naming the replica, and the replica carries it inline under the handover tag as a chain: content is {handover: [artefact, ...]} ordered from the first-hand root, the tag being SHA-256 of the last artefact canonical form with sig excluded. Every signer in the chain is carried so that every signer is barred from reporting a hole in the handed set; a single link would let the node that withheld an event report the hole against a node two links down. Each link hands to the node that signs the next, every link names the same set, and no key appears twice. The replica may then assert exactly the handed set and no more: same filter, same range, same fingerprint and count, and until no later than at. A handover is reportable against its signer as an asserted claim is, because it signed for the same set. The signer MUST NOT be admitted as the reporter of a hole in the claim it handed over: a hole in the handed set is its own. A handover travels over sync/1.0/handover after a done that reports the sets equal. A claim is withdrawn by republishing it at the same coordinate as best-effort with a NIP-40 expiration: addressable, so the asserted one it replaces is dropped by relays, and the replacement lapses rather than outliving the node that made it. The capacity ladder’s narrow_scope rung and a retiring node both withdraw this way.&lt;br/&gt;&lt;br/&gt;#### `30810` — compute ask&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `d`, `commit`, `executor`, `bid`, `deadline`, `fuel_max`, `verify`, `expiration` |&lt;br/&gt;| OPTIONAL | `runtime`, `input_size` |&lt;br/&gt;&lt;br/&gt;&gt; An order book entry, not a job specification. module and input travel encrypted over compute/1.0 to the seller that wins the quote; commit binds them in advance so the work cannot be swapped after quoting. verify declares which evidence a later dispute will admit.&lt;br/&gt;&lt;br/&gt;#### `30811` — job receipt&lt;br/&gt;&lt;br/&gt;| | Tags |&lt;br/&gt;|---|---|&lt;br/&gt;| REQUIRED | `d`, `commit`, `scheme`, `expiration` |&lt;br/&gt;| OPTIONAL | — |&lt;br/&gt;&lt;br/&gt;&gt; D is HKDF-SHA256 over the buyer/seller ECDH x-coordinate under blinding.job&#39;s salt and info; commit is SHA256(blinding || canonical receipt); blinding is fresh random per commitment (commitment.blinding_factor). The ask, module, input, result, fuel_used, paid_msat, payment_hash and executor are all inside the ciphertext: a receipt is a positive event, and this document already declines to publish those. A seller MAY publish a cleartext receipt where the buyer has consented.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:kindtags END --&gt;&lt;br/&gt;&lt;br/&gt;### Kinds reused rather than reinvented&lt;br/&gt;&lt;br/&gt;meshstr defines new kinds only where nothing existing fits. Everything else is&lt;br/&gt;an existing NIP, used unmodified:&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:reused BEGIN — generated from schema/kinds.json, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;| Kind | Used for |&lt;br/&gt;|---|---|&lt;br/&gt;| `1059` | NIP-59 gift wrap - store-and-forward control transport |&lt;br/&gt;| `1984` | NIP-56 reporting - user content, feeds author grants |&lt;br/&gt;| `1985` | NIP-32 labeling - subjective moderation classification bridge |&lt;br/&gt;| `5000-5999` | NIP-90 DVM compute requests - ingress gateway to meshstr WASI |&lt;br/&gt;| `6000-6999` | NIP-90 DVM compute responses - egress results from meshstr WASI |&lt;br/&gt;| `7000` | NIP-90 DVM compute feedback / job status |&lt;br/&gt;| `9321` | NIP-61 nutzap proofs - asymmetric rate budget settlement |&lt;br/&gt;| `10002` | NIP-65 relay list |&lt;br/&gt;| `10040` | NIP-85 trusted provider list - how a client chooses whose kind 30385 to read, under 30385:rank |&lt;br/&gt;| `10050` | NIP-17 DM relay list - gates kind 1059 replication |&lt;br/&gt;| `10063` | Blossom server list |&lt;br/&gt;| `10166` | NIP-66 relay monitor announcement |&lt;br/&gt;| `21059` | NIP-59 ephemeral gift wrap - live control transport, default |&lt;br/&gt;| `30166` | NIP-66 relay discovery - what a node&#39;s relay face is and accepts, one per ws or wss endpoint; see discovery in constants.json. Liveness is not in it: that is a measurement for a NIP-66 monitor to take |&lt;br/&gt;| `30385` | NIP-85 trusted assertions - the relay score a node projects from its own kind 30802 reports: d is the subject&#39;s relay URL in canonical form, k is web (NIP-73), a cites the report; see projection in constants.json. PR #2418 proposes a differently shaped relay assertion under the same number and is unmerged |&lt;br/&gt;| `30817` | NostrHub decentralized NIP specification |&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:reused END --&gt;&lt;br/&gt;&lt;br/&gt;It also projects its internal state outward, so clients that know nothing about&lt;br/&gt;meshstr still benefit: a node MAY publish a NIP-66 kind 30166 about its own&lt;br/&gt;relay face, one per endpoint its descriptor declares, carrying what the face&lt;br/&gt;accepts and never a measurement of itself (`discovery` in `constants.json`),&lt;br/&gt;and a NIP-85 kind 30385 about the subject&#39;s relay URL derived&lt;br/&gt;from its own kind 30802 reports and from nothing else. That projection is&lt;br/&gt;adverse only; its shape is `projection` in `constants.json`.&lt;br/&gt;&lt;br/&gt;## Protocol version&lt;br/&gt;&lt;br/&gt;A node declares a version as a name plus the SHA-256 of its machine-readable&lt;br/&gt;schema — `kinds.json`, `messages.json` and `constants.json`, each serialised&lt;br/&gt;with sorted keys and no whitespace, concatenated in that order.&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:version BEGIN — generated from schema/DIGEST, do not edit --&gt;&lt;br/&gt;&lt;br/&gt;```&lt;br/&gt;meshstr/0-draft@04cf011f80b295a1f49d6c69e081b8158d603cfa5172163c4400e282fa53e563&lt;br/&gt;```&lt;br/&gt;&lt;br/&gt;&lt;!-- meshstr:version END --&gt;&lt;br/&gt;&lt;br/&gt;Two nodes declaring different digests decline to peer rather than half-speak.&lt;br/&gt;During alpha the digest may change on any day and nobody is owed a migration.&lt;br/&gt;&lt;br/&gt;Each protocol identifier carries a version of its own, as in `sync/1.0`. Those&lt;br/&gt;versions are informative labels. The digest is normative: it changes whenever&lt;br/&gt;any message set or body field changes, and a node negotiates nothing below it.&lt;br/&gt;An identifier&#39;s version is bumped when its messages or fields change, so a&lt;br/&gt;reader can see which protocol moved without diffing the schema.&lt;br/&gt;&lt;br/&gt;## Status&lt;br/&gt;&lt;br/&gt;Alpha draft. One implementation exists and it is alpha: a node that runs the&lt;br/&gt;whole of this document over a wire, in the repository this NIP is published&lt;br/&gt;from. It is what found the defects the design notes record, which is the only&lt;br/&gt;claim being made for it.&lt;br/&gt;&lt;br/&gt;Every grant, receipt and report from the alpha period is discarded at 1.0.&lt;br/&gt;Standing accumulated against constants that changed underneath it is not&lt;br/&gt;standing. Nobody should join the alpha for a head start; they should join it to&lt;br/&gt;find out whether the thing works.&lt;br/&gt;&lt;br/&gt;This is deliberately not submitted as a NIP. The NIPs repository requires two&lt;br/&gt;independent implementations and meshstr has one, written by the same hand as&lt;br/&gt;the specification, which is not independence. The kinds&lt;br/&gt;are being registered in&lt;br/&gt;[`nostr-protocol/registry-of-kinds`](&lt;a href=&#34;https://github.com/nostr-protocol/registry-of-kinds&#34;&gt;https://github.com/nostr-protocol/registry-of-kinds&lt;/a&gt;)&lt;br/&gt;instead, which is collision avoidance and nothing more.&lt;br/&gt;&lt;br/&gt;- Specification — &lt;a href=&#34;https://www.meshstr.org/spec.html&#34;&gt;https://www.meshstr.org/spec.html&lt;/a&gt;&lt;br/&gt;- Schemas — &lt;a href=&#34;https://www.meshstr.org/schemas.html&#34;&gt;https://www.meshstr.org/schemas.html&lt;/a&gt;&lt;br/&gt;- Source — &lt;a href=&#34;https://gitlab.pocketlabs.dev/meshstr/meshstr&#34;&gt;https://gitlab.pocketlabs.dev/meshstr/meshstr&lt;/a&gt;&lt;br/&gt;- Licence — CC0 1.0 Universal&lt;br/&gt; &lt;/blockquote&gt;Repository (GRASP-hosted):&lt;blockquote class=&#34;border-l-05rem border-l-strongpink border-solid&#34;&gt;&lt;div class=&#34;-ml-4 bg-gradient-to-r from-gray-100 dark:from-zinc-800 to-transparent mr-0 mt-0 mb-4 pl-4 pr-2 py-2&#34;&gt;quoting  &lt;span itemprop=&#34;mentions&#34; itemscope itemtype=&#34;https://schema.org/Article&#34;&gt;&lt;a itemprop=&#34;url&#34; href=&#34;/naddr1qqrk6etndpehguspz4mhxue69uhkw6t59ehx7um5wf582c3wd9hsygrfhu8meqs3fz8uxgd7ukl6q7awrp9gsxctzmplkmsn5jcamg5pyspsgqqqw7vsw66dws&#34; class=&#34;bg-lavender dark:prose:text-neutral-50 dark:text-neutral-50 dark:bg-garnet px-1&#34;&gt;naddr1qq…6dws&lt;/a&gt;&lt;/span&gt;&lt;br/&gt; &lt;/div&gt;  &lt;/blockquote&gt;&lt;br/&gt;Reading it and telling us where it is wrong is the contribution that helps most right now.
    </content>
    <updated>2026-09-02T21:36:31Z</updated>
  </entry>

</feed>