lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

event_boundary_matrix.md (25751B)


      1 # Event boundary matrix
      2 
      3 Status: canonical
      4 Scope: public event domains, kinds, and RPC method ownership
      5 
      6 This matrix is the canonical open-source event-boundary source for the
      7 applications and services that expose public Radroots events. It retains the
      8 reviewed method and domain coverage while placing authority in this standalone
      9 contract package.
     10 
     11 ## Runtime key rule
     12 
     13 - Publish methods use the runtime-configured key as the author by default.
     14 - List and get methods may accept optional author filters, but default to the runtime key.
     15 - Multi-key publishing is out of scope until explicit key management is added.
     16 
     17 ## Method naming conventions
     18 
     19 - `events.<entity>.<action>`
     20 - `domains.<domain>.<subdomain>.<action>`
     21 - standard actions: `publish`, `get`, `list`, `validate`, `encode`, `decode`
     22 
     23 ## General verified admission rule
     24 
     25 `event.admit_verified` is the single trusted contract-admission boundary for a
     26 `RadrootsSignatureVerifiedEvent`. It never accepts a bare envelope or performs
     27 signature verification implicitly. Profile, root Post, Reply, Comment,
     28 DeletionRequest, and focused FoodAvailability candidates retain their exact
     29 typed admitted values. All other registered candidates must pass complete
     30 registry shape validation before returning `ContractValidated`.
     31 
     32 Kind `1` routing is ordered: root Post admission runs first, and only its exact
     33 thread-excluded candidate may proceed to NIP-10 Reply admission. A thread-shaped
     34 event that fails Reply admission is invalid rather than a generic root Post.
     35 Kind `30402` routing partitions raw marker names before validation. Focused Food
     36 is admitted through its typed profile; an excluded Operational Listing may
     37 fall back to complete registry validation; marker-free generic NIP-99 remains
     38 unsupported; mixed focused and operational markers remain an explicit
     39 ambiguity error.
     40 
     41 Unsupported kind/shape matching and contract/profile validation failures are
     42 distinct `RadrootsEventAdmissionError` variants with stable codes. Successful
     43 admission proves only the verified envelope and the selected product or
     44 registry contract. It does not sign, publish, upload media, select a NIP-01
     45 head, authorize a deletion, evaluate suppression, mutate storage, or establish
     46 reference existence or relay availability.
     47 
     48 ## Calendar boundary rule
     49 
     50 Calendar kinds `31922` through `31925` expose separate authored,
     51 baseline-parsed, and strict-admitted types. A structural
     52 `EventEnvelope` is not cryptographic verification, and neither the
     53 NIP-52 parser nor Radroots admission verifies the declared event id or Schnorr
     54 signature. A read-side runtime must keep the parsed or admitted value bound to
     55 an envelope whose id and signature it has independently verified and whose kind
     56 the corresponding parser accepted. Outbound authored models produce unsigned
     57 wire parts and require runtime signing and transport.
     58 
     59 ## Classified-listing profile boundary rule
     60 
     61 Kind `30402` is the standard NIP-99 classified-listing kind and
     62 `ClassifiedListingAddress` is the exact coordinate authority for that
     63 kind. `OperationalListing` is the richer
     64 `radroots.operational_listing.published.v1` profile accepted at the same kind;
     65 its typed codec, tags, and publication operations are exposed under the
     66 `operational_listing` domain. The standard kind identity does not by itself
     67 establish that an event satisfies the operational profile.
     68 
     69 Raw tag-name presence partitions the standard kind before profile tag-shape
     70 validation. `radroots:price_unit` and `radroots:quantity` are focused
     71 FoodAvailability markers. `radroots:primary_bin`, `radroots:bin`, and
     72 `radroots:price` are Operational Listing markers. Focused-only,
     73 operational-only, marker-free generic NIP-99, and mixed-marker inputs classify
     74 as `FocusedFoodAvailability`, `OperationalListing`, `GenericNip99`, and
     75 `Ambiguous`; malformed tags still contribute their first element, and names
     76 are case-sensitive. This central partition does not inspect kind, values, or
     77 arity and does not validate either profile.
     78 
     79 The focused `radroots.food.availability.v1` profile has four public operation
     80 boundaries. Strict authored details plus `created_at` produce deterministic
     81 unsigned kind-`30402` wire parts. Projection accepts only a
     82 `RadrootsSignatureVerifiedEvent`, returns focused data or an explicit
     83 Operational Listing or generic NIP-99 exclusion, rejects mixed markers as
     84 ambiguous, and applies focused validation only after partitioning. Combined
     85 admission performs NIP-01 id and signature verification before projection and
     86 keeps either result bound to its verified envelope.
     87 
     88 Strict authoring emits the exact ordered `d`, `title`, `summary`,
     89 `published_at`, `location`, `price`, `radroots:price_unit`, optional
     90 `radroots:quantity`, `status`, and repeated `image` tags. Inbound focused
     91 projection normalizes accepted decimal and currency spellings, ignores
     92 unowned optional NIP-99 tags, and preserves a bounded ordered image projection
     93 with stable diagnostics instead of treating malformed image metadata as a
     94 valid authored image. Focused capability tags for checkout, fulfillment,
     95 payments, provenance, and operational workflows are rejected; the profile
     96 does not gain those semantics by carrying an unknown tag.
     97 
     98 Revision validation re-applies strict authored wire semantics to both verified
     99 events. It requires stable kind, author, `d` coordinate, and `published_at`,
    100 then applies NIP-01 replacement order: later `created_at` wins, and the lower
    101 event id wins at equal time. Side-specific errors identify an invalid previous
    102 or current candidate before revision comparison.
    103 
    104 The `radroots_nostr` `events` feature seals strict FoodAvailability wire parts
    105 behind a builder whose timestamp cannot be mutated after validation. With the
    106 `signing` feature it supports local signing; generic authoring rejects focused
    107 and mixed kind-`30402` profiles. Signed-event relay remains transport-only.
    108 The non-default `legacy-ingest` replica feature verifies kind-`30402` NIP-01
    109 events first, selects the raw addressable head before profile decoding, and
    110 routes only Operational Listing into its trade-product projection. Selected
    111 focused or generic exclusions and invalid or ambiguous rejections remove an
    112 older operational projection and still advance the raw head. The head-only
    113 replica helper rejects kind `30402`; these events require profile-aware legacy
    114 ingestion so projection cleanup and head movement remain atomic. This
    115 bare-envelope module is absent from default builds and is not a Phase 1 product
    116 ingestion boundary. A future product replacement must accept only a
    117 store-produced verified, valid-stream-eligible, currently visible admission.
    118 
    119 A validated authored image proves local Blossom descriptor-to-byte agreement
    120 only. Successful BUD-02 upload completion and any raster, retrievability, or
    121 availability checks remain runtime responsibilities before signing or
    122 publication.
    123 
    124 ## Kind-1 post and Reply boundary rule
    125 
    126 Ordinary kind-1 events remain interoperable at the generic
    127 `radroots.social.post.v1` read boundary. Product projection first requires a
    128 `RadrootsSignatureVerifiedEvent`; any `e` tag excludes the event as a thread
    129 candidate without asserting NIP-10 Reply validity, then root-card precedence is
    130 Ask, PhotoUpdate, Update. The admission result keeps root product admission and
    131 thread-excluded candidates in distinct public variants. Exact subtype registry
    132 contracts are admission-only and cannot be selected by unsigned kind/tag
    133 matching. New root publication uses the strict authored types and a sealed
    134 Nostr builder with no raw tag/content mutation; generic builder publication
    135 rejects every kind `1` event before signing. The legacy mutable `Post`
    136 decoder is compatibility-only and has no authored encoder or tag-builder
    137 implementation.
    138 
    139 NIP-10 Reply is a separate typed kind-1 boundary. Strict direct authoring emits
    140 one marked `root` event reference and its referenced-author `p` tag. Strict
    141 nested authoring adds one distinct marked `reply` parent and its author,
    142 deduplicating equal authors. Inbound Reply projection requires NIP-01
    143 verification but tolerates both preferred marked and deprecated positional
    144 NIP-10 references. Valid supplemental unmarked `e` references remain citations;
    145 malformed supplemental references are ignored with ordered diagnostics.
    146 Empty marker slots remain absent for positional root, parent, and citation
    147 references even when a fifth-element author hint is present; malformed
    148 intermediate citations do not erase valid positional anchors.
    149 Advisory `p`, relay, and referenced-author metadata is projected best-effort
    150 rather than promoted to a validity gate. Positional replies remain thread
    151 enrichment, and a Reply carrying Ask or media metadata cannot be promoted as a
    152 root card.
    153 
    154 Authored and projected NIP-10 Reply and NIP-22 Comment relay hints share the
    155 portable `NostrRelayHint` profile:
    156 exact lowercase `ws://` or `wss://`, visible ASCII, canonical lowercase DNS or
    157 four-octet IPv4 or bracketed pure-hex RFC 5952 IPv6, optional canonical port
    158 `1..65535`, and RFC 3986 path-abempty/query syntax with uppercase `%HH`
    159 escapes. The profile rejects userinfo, fragments, backslashes, IDNA and
    160 percent-encoded hosts, legacy IPv4, and normalization-dependent spellings.
    161 Malformed inbound hints stay verbatim in ordered raw-tag diagnostics. Relay
    162 syntax validation is independent from the Reply boundary's 4,096-byte
    163 tag-element budget.
    164 
    165 Reply admission proves the Reply envelope's id, signature, and bounded NIP-10
    166 structure. It does not prove that a referenced event exists, has kind `1`, has
    167 a valid signature, was authored by the declared referenced author, or is
    168 available from a relay. Signed-event relay remains generic transport rather
    169 than a typed Reply-authoring boundary.
    170 
    171 ## NIP-22 Comment boundary rule
    172 
    173 The strict Radroots
    174 [NIP-22](https://github.com/nostr-protocol/nips/blob/bdfa7e62ef87fcfcb992b1a27aee49d36b0b4f91/22.md)
    175 profile is kind `1111`. Its root is exactly one `E` event id or `A`
    176 addressable coordinate, with matching singleton `K` root-kind and `P`
    177 root-author authority. Supported root kinds are only classified listings
    178 (`30402`), calendar date events (`31922`), and calendar time events (`31923`).
    179 External `I`/`i` roots and parents and ordinary kind-`1` roots are outside this
    180 profile.
    181 
    182 Strict authoring exposes `AuthoredNip22Comment` for top-level event,
    183 top-level address, and nested Comment positions. It emits exact ordered
    184 `E,K,P,e,k,p` for a top-level event, `A,K,P,a,e,k,p` for a top-level
    185 address, and `E,K,P,e,k,p` or `A,K,P,e,k,p` for a nested event or address
    186 root. Authored event references have four elements with an explicit relay slot
    187 and final author hint. Address and participant references have two elements
    188 plus an optional relay; the current-revision `e` reference on a top-level
    189 address Comment has no author hint. Direct `k` repeats the root kind, while
    190 nested `k` is `1111`.
    191 
    192 `RadrootsInboundNip22CommentProjection` accepts only an id-and-signature
    193 verified event. It resolves authority independently of tag order and enforces
    194 its cardinality, shape, canonical kind, coordinate-kind, author, and parent
    195 relationships. Unknown tags, `q` tags, distinct unselected `p` mentions, and
    196 the exact raw tags remain inspectable. Inbound NIP-22 reference event IDs,
    197 public keys, and coordinate-author hex accept either ASCII hex case; typed
    198 values normalize to lowercase while raw tags retain their original spelling.
    199 Malformed advisory relay or participant metadata is retained as ordered
    200 diagnostics, while valid hints that conflict with `P` or selected `p` authority
    201 are hard failures.
    202 `RadrootsAdmittedNip22CommentEvent` binds the result to the verified envelope;
    203 it does not prove reference existence, target signatures, target authorship, or
    204 relay availability.
    205 
    206 The event-contract registry v7 classifies `radroots.social.comment.v1` as
    207 `TypedOnly` for authoring and `AdmissionOnly` for matching. Registry versions
    208 `1` through `6` are stale. Generic kind-`1111` signing fails before signer
    209 access; publication remains transport-owned. The complete operation surface
    210 is exactly
    211 `social.comment.build_authored_draft`,
    212 `social.comment.project_verified_event`, and
    213 `social.comment.verify_and_admit_event`.
    214 
    215 Comment content is limited to 131072 UTF-8 bytes, a Comment to 1024 tags, all
    216 tags to 4096 elements including names, each element to 4096 UTF-8 bytes,
    217 aggregate tag bytes to 131072, and compact signed wire JSON to 262144 bytes.
    218 The canonical self-contained 114-case corpus is
    219 `contracts/conformance/vectors/comment/verified_profile.v1.json`.
    220 
    221 ## NIP-09 deletion-request boundary rule
    222 
    223 The strict Radroots
    224 [NIP-09](https://github.com/nostr-protocol/nips/blob/bdfa7e62ef87fcfcb992b1a27aee49d36b0b4f91/09.md)
    225 profile is kind `5` and requires at least one valid `e` event id or `a`
    226 replaceable/addressable coordinate. Strict authoring sorts normalized event
    227 targets and address targets independently, rejects duplicates, and emits all
    228 two-element `e` tags, then `a` tags, then the unique ascending target-kind
    229 advisories as two-element `k` tags. A caller-supplied event-target kind and
    230 every `k` tag are advisory metadata, not proof of the referenced event's kind.
    231 
    232 Inbound projection accepts only an id-and-signature-verified envelope. It
    233 preserves exact raw tags, tolerates unknown tags and trailing target elements,
    234 deduplicates normalized targets with first-seen provenance, and exposes sorted
    235 typed target views. A malformed `e` or `a` target is a hard failure.
    236 Malformed, noncanonical, duplicate, and address-only-conflicting `k` tags
    237 produce stable ordered diagnostics. An event target makes kind correspondence
    238 unprovable, so a differing `k` advisory is not promoted to a conflict.
    239 
    240 Admission proves only that the kind-`5` request envelope and bounded request
    241 profile are valid. It performs no target lookup, same-author authorization,
    242 address cutoff evaluation, replacement or suppression decision, store
    243 mutation, or deletion-request immunity evaluation.
    244 
    245 The separate pure evaluator accepts a signature-verified candidate and
    246 admitted deletion requests. It never mutates an event or store. Kind `5` is
    247 immune; every other suppression requires equal request and candidate authors.
    248 An exact `e` target is time-independent. An exact canonical `a` target applies
    249 through the inclusive maximum qualifying request timestamp, so a later
    250 replacement remains visible. Advisory `k` values are ignored. The decision and
    251 its canonical evidence are independent of request order and repeated
    252 qualifying inputs.
    253 
    254 The event-contract registry v7 classifies
    255 `radroots.social.deletion_request.v1` as `TypedOnly` for authoring and
    256 `AdmissionOnly` for matching. Generic kind-`5` signing fails before signer
    257 access; publication remains transport-owned.
    258 
    259 The complete operation surface is exactly
    260 `social.deletion_request.build_authored_draft`,
    261 `social.deletion_request.project_verified_event`,
    262 `social.deletion_request.verify_and_admit_event`, and
    263 `social.deletion_request.evaluate_suppression`. Content is limited to 131072
    264 UTF-8 bytes, a request to 1024 tags, all tags to 4096 elements including names,
    265 each element to 4096 UTF-8 bytes, aggregate tag bytes to 131072, and compact
    266 signed wire JSON to 262144 bytes. The canonical fixed 80-case request corpus is
    267 `contracts/conformance/vectors/deletion/verified_profile.v1.json`.
    268 Pure effect evaluation has the separate canonical
    269 `contracts/conformance/vectors/deletion/suppression.v1.json` corpus and does
    270 not weaken or add effect fields to the request corpus.
    271 
    272 ## Coverage matrix
    273 
    274 | Domain | Kind | Radroots Type | RPC Methods | Notes |
    275 | --- | --- | --- | --- | --- |
    276 | profile | 0 | AuthoredProfile / RadrootsInboundProfileMetadata | events.profile.publish, events.profile.list, events.profile.get | publish must use `profile.build_authored_draft`; inbound projection must use `profile.parse_inbound_metadata`; authored output is deterministic JSON with no marker tag |
    277 | follow | 3 | Follow | events.follow.publish, events.follow.list, events.follow.get | replaceable event |
    278 | post | 1 | AuthoredUpdate / AuthoredPhotoUpdate / AuthoredAsk / RadrootsInboundPostProjection | events.post.publish, events.post.list, events.post.get | ordinary kind-1 reads remain generic; exact root-card subtypes require verified admission; any `e` tag produces a thread-excluded candidate without a Reply claim |
    279 | reply | 1 | AuthoredNip10Reply / RadrootsInboundNip10ReplyProjection / RadrootsAdmittedNip10ReplyEvent / Nip10ReplyBuilder | social.reply.build_authored_draft, social.reply.project_verified_event, social.reply.verify_and_admit_event | strict marked direct/nested NIP-10 authoring; verified marked or positional inbound admission with advisory-metadata diagnostics; never a root card; target existence, kind, author, and relay availability are not proven |
    280 | comment | 1111 | AuthoredNip22Comment / RadrootsInboundNip22CommentProjection / RadrootsAdmittedNip22CommentEvent / Nip22CommentBuilder | social.comment.build_authored_draft, social.comment.project_verified_event, social.comment.verify_and_admit_event | strict NIP-22 event/address roots limited to kinds `30402`, `31922`, and `31923`; tolerant verified projection; registry-v7 typed-only authoring and admission-only matching |
    281 | deletion_request | 5 | AuthoredNip09DeletionRequest / RadrootsInboundNip09DeletionProjection / RadrootsAdmittedNip09DeletionRequestEvent / RadrootsNip09SuppressionDecision / Nip09DeletionRequestBuilder | social.deletion_request.build_authored_draft, social.deletion_request.project_verified_event, social.deletion_request.verify_and_admit_event, social.deletion_request.evaluate_suppression | effect-free NIP-09 request authoring and verified projection plus pure immutable suppression evaluation; same-author direct event targets and inclusive address cutoffs; kind-5 immunity; advisory kinds ignored; registry-v7 typed-only authoring and admission-only matching |
    282 | reaction | 7 | Reaction | events.reaction.publish, events.reaction.list, events.reaction.get | requires event, pubkey, or address tags |
    283 | repost | 6 | Repost | events.repost.publish, events.repost.list, events.repost.get | NIP-18 kind-1 repost surface |
    284 | generic_repost | 16 | GenericRepost | events.generic_repost.publish, events.generic_repost.list, events.generic_repost.get | NIP-18 generic repost surface |
    285 | seal | 13 | Seal | events.seal.encode, events.seal.decode | tags must be empty; used for NIP-59 transport |
    286 | message | 14 | Message | events.message.publish, events.message.list, events.message.get | rumor event; unsigned before wrapping |
    287 | message_file | 15 | MessageFile | events.message_file.publish, events.message_file.list, events.message_file.get | rumor event with file tags |
    288 | gift_wrap | 1059 | GiftWrap | events.gift_wrap.publish, events.gift_wrap.list, events.gift_wrap.get | requires `p` tag; optional expiration |
    289 | public_file_metadata | 1063 | FileMetadata | events.public_file_metadata.publish, events.public_file_metadata.list, events.public_file_metadata.get | public NIP-94 file metadata, distinct from private farm file metadata |
    290 | report | 1984 | Report | events.report.publish, events.report.list, events.report.get | NIP-56 report with required reported pubkey |
    291 | list | 10000..10102 | List | events.list.publish, events.list.list, events.list.get | replaceable NIP-51 list kinds excluding kind 3 |
    292 | relay_list | 10002 | List | events.relay_list.publish, events.relay_list.list, events.relay_list.get | NIP-65 relay list entries with `read` or `write` markers |
    293 | list_set | 30000..30007, 30015, 30030, 30063, 30267, 39089, 39092 | ListSet | events.list_set.publish, events.list_set.list, events.list_set.get | enumerated addressable NIP-51 list sets with `d` tag; NIP-52 kind `31924` is exclusively the calendar surface |
    294 | article | 30023 | Article | events.article.publish, events.article.list, events.article.get | NIP-23 long-form content |
    295 | knowledge | 818, 3460..3465, 30450..30451, 30818..30819 | RadrootsKnowledgeEvent | events.knowledge.publish, events.knowledge.list, events.knowledge.get | NIP-54 wiki plus Radroots knowledge source, claim, relation, review, field-report, bounty, proposal, and contribution contracts |
    296 | app_data | 30078 | AppData | events.app_data.publish, events.app_data.list, events.app_data.get | addressable app data with `d` tag |
    297 | app_handler | 31990 | KIND_APPLICATION_HANDLER | events.app_handler.publish, events.app_handler.list, events.app_handler.get | optional discoverability |
    298 | calendar_date | 31922 | AuthoredCalendarDateEvent / ParsedNip52CalendarDateEvent / AdmittedCalendarDateEvent | events.calendar_date.publish, events.calendar_date.list, events.calendar_date.get | registry-v7 typed-only NIP-52 date authoring through `CalendarEventBuilder`; baseline retains uppercase-`D` extensions, strict admission rejects them |
    299 | calendar_time | 31923 | AuthoredCalendarTimeEvent / ParsedNip52CalendarTimeEvent / AdmittedCalendarTimeEvent | events.calendar_time.publish, events.calendar_time.list, events.calendar_time.get | registry-v7 typed-only NIP-52 time authoring through `CalendarEventBuilder`; baseline applies required day anchoring, strict admission requires exact bounded UTC-day coverage |
    300 | calendar | 31924 | AuthoredCalendar / ParsedNip52Calendar / AdmittedCalendar | events.calendar.publish, events.calendar.list, events.calendar.get | NIP-52 calendar collection with separate authored, baseline parse, and strict Radroots admission boundaries |
    301 | calendar_rsvp | 31925 | AuthoredCalendarEventRsvp / ParsedNip52CalendarEventRsvp / AdmittedCalendarEventRsvp | events.calendar_rsvp.publish, events.calendar_rsvp.list, events.calendar_rsvp.get | NIP-52 calendar RSVP with separate authored, baseline parse, and strict Radroots admission boundaries |
    302 | farm | 30340 | Farm | events.farm.publish, events.farm.list, events.farm.get | addressable; canonical JSON; `g` tag only when a geohash exists |
    303 | plot | 30350 | Plot | events.plot.publish, events.plot.list, events.plot.get | requires address and pubkey tags; preserve self-tag |
    304 | coop | 30360 | Coop | events.coop.publish, events.coop.list, events.coop.get | addressable; canonical JSON; `g` tag from geohash |
    305 | document | 30361 | Document | events.document.publish, events.document.list, events.document.get | requires `d` and pubkey tags; optional address tag |
    306 | resource_area | 30370 | ResourceArea | events.resource_area.publish, events.resource_area.list, events.resource_area.get | addressable; GCS location and `g` tag required |
    307 | resource_cap | 30371 | ResourceHarvestCap | events.resource_cap.publish, events.resource_cap.list, events.resource_cap.get | addressable; required address, pubkey, key, start, and end tags |
    308 | food_availability | 30402 | FoodAvailabilityDetails / RadrootsInboundFoodAvailabilityProjection / RadrootsAdmittedFoodAvailabilityEvent / FoodAvailabilityBuilder | food_availability.build_authored_draft, food_availability.project_verified_event, food_availability.verify_and_admit_event, food_availability.validate_revision | focused `radroots.food.availability.v1` profile; strict deterministic authoring, verified projection/admission, stable-coordinate revision validation, sealed Nostr signing, transport-owned publication, generic-authoring reservation, and raw-head-first partitioning only behind the non-default `legacy-ingest` replica feature; BUD-02 upload evidence remains a runtime prerequisite |
    309 | operational_listing | 30402 | OperationalListing | events.operational_listing.publish, events.operational_listing.list, events.operational_listing.get | NIP-99 classified-listing kind with the richer Radroots operational profile; canonical Markdown content and tags; farm author required |
    310 | dvm_request | 5000-5999 | JobRequest | events.dvm_request.publish, events.dvm_request.list, events.dvm_request.get | generic DVM request surface |
    311 | dvm_result | 6000-6999 | JobResult | events.dvm_result.publish, events.dvm_result.list, events.dvm_result.get | generic DVM result surface |
    312 | dvm_feedback | 7000 | JobFeedback | events.dvm_feedback.publish, events.dvm_feedback.list, events.dvm_feedback.get | generic DVM feedback surface |
    313 | trade:proposal | 3470 | TradeMutationEnvelopeV1 | trade.get_trade, trade.list_trades, trade.submit_proposal | buyer-authored initial complete candidate mutation with canonical semantic identity |
    314 | trade:decision | 3471 | TradeMutationEnvelopeV1 | trade.decide_candidate, trade.get_trade, trade.list_trades | exact accept or decline mutation for a referenced candidate and proposal mutation |
    315 | trade:revision_proposal | 3472 | TradeMutationEnvelopeV1 | trade.get_trade, trade.list_trades, trade.propose_revision | buyer- or seller-authored complete replacement candidate referencing bounded parent heads |
    316 | trade:revision_decision | 3473 | TradeMutationEnvelopeV1 | trade.decide_candidate, trade.get_trade, trade.list_trades | exact accept or decline mutation for a referenced revision candidate and proposal mutation |
    317 | trade:cancellation | 3474 | TradeMutationEnvelopeV1 | trade.cancel_trade, trade.get_trade, trade.list_trades | policy-authorized cancellation mutation referencing the relevant candidate or current claim |
    318 | relay_doc | N/A | RelayDocument | system.relay_doc.get | HTTP NIP-11 info via relay fetch helper |
    319 
    320 ## Membership list sets and claims
    321 
    322 - Farm lists: kind `30001`, including `farm:<farm_d_tag>:members`, `members.owners`, `members.workers`, `plots`, and `listings`.
    323 - Coop lists: kind `30001`, including `coop:<coop_d_tag>:members`, `members.farms`, `members.owners`, `members.admins`, and `items`.
    324 - Resource area lists: kind `30001`, including `resource:<area_d_tag>:members.farms`, `members.plots`, and `members.stewards`.
    325 - Member-side claims: kind `30001`, including `member_of.farms` and `member_of.coops`.