commit 41e20a14d30416d13d9864ed2cc2f415d9a8e6ea
parent 9e60a154c607ee31bd108f751e1bb1fe64259314
Author: triesap <tyson@radroots.org>
Date: Fri, 12 Jun 2026 02:33:24 -0700
spec: add social event contract
- define the public social event substrate and approved event families
- record strict comment, reaction, file metadata, listing draft, and relay-list decisions
- document social conformance requirements for future codec vectors
- keep curated social operations deferred until implementation-backed vectors exist
Diffstat:
4 files changed, 145 insertions(+), 0 deletions(-)
diff --git a/spec/README.md b/spec/README.md
@@ -46,6 +46,22 @@ envelope. They are outside the `rr-rs` event-contract boundary unless a future
contract slice explicitly promotes them into a curated SDK operation surface with
matching conformance vectors and language export mappings.
+## Public Social Event Substrate
+
+Public social events are represented as event and codec substrate in
+`radroots_events`, `radroots_events_codec`, and `radroots_events_codec_wasm`.
+
+The active social-event contract is defined in `spec/social-events.md`. It covers
+ordinary posts, comments, reactions, articles, public generic file metadata,
+calendar events, reposts, reports, listing drafts through `RadrootsListing`, and
+NIP-65 relay lists through `RadrootsList`.
+
+The social surface is substrate-first. MVP social builders and parsers may be
+promoted into curated SDK operation metadata only after their Rust models,
+codecs, wasm helpers where needed, and deterministic conformance vectors exist.
+Production-v1 repost, report, calendar collection, and RSVP behavior remains
+available through event and codec APIs by default.
+
## Rust Crate Tiers
The public Rust story is tiered explicitly.
diff --git a/spec/conformance/README.md b/spec/conformance/README.md
@@ -16,3 +16,18 @@ Each fixture must be deterministic and machine-readable.
- vectors are generated from canonical rust implementations.
- every contract behavior change must update vectors in the same change.
- language sdk test harnesses must validate vectors without local overrides.
+
+## social event vectors
+
+Social event vectors are required for every new social codec and every existing
+codec whose public behavior changes under `spec/social-events.md`.
+
+The social vector set must cover valid, invalid, and round-trip behavior for the
+approved public social event families. It must include strict NIP-22 comment
+targets, empty-content NIP-25 reactions, public NIP-94 generic file metadata,
+NIP-99 listing `published_at`, NIP-65 relay-list `r` tags, and private Field
+business-document isolation.
+
+Social event vectors must be deterministic, synthetic, and repo-owned. They must
+not depend on relay databases, application runtime state, external services, or
+fixture roots outside this repository.
diff --git a/spec/operations.toml b/spec/operations.toml
@@ -6,6 +6,10 @@ source = "rust"
[public]
domains = ["profile", "farm", "listing", "trade"]
+# Public social events are substrate-first during the active social refactor.
+# Curated social operations are intentionally added only after their models,
+# codecs, wasm helpers, and conformance vectors exist.
+
[shared_types]
public = [
"WireEventParts",
diff --git a/spec/social-events.md b/spec/social-events.md
@@ -0,0 +1,110 @@
+# Public Social Event Substrate
+
+Status: active implementation contract
+
+Scope: public Radroots social Nostr event models, codecs, wasm builders, and deterministic
+conformance vectors in this repository.
+
+## Purpose
+
+The public social event substrate extends the Radroots event family beyond profile, farm, listing,
+and trade workflows while keeping relay runtime behavior, application projections, moderation
+services, and private Field business documents outside this repository's event-contract boundary.
+
+The target implementation is standards-first and Radroots-named. Event models live in
+`radroots_events`, canonical encode/decode behavior lives in `radroots_events_codec`, optional JSON
+to tags helpers live in `radroots_events_codec_wasm`, and deterministic fixtures live under
+`spec/conformance`.
+
+## Source Inventory
+
+The current repository already contains partial public social support for kind `1`
+`RadrootsPost`, kind `1111` `RadrootsComment`, kind `7` `RadrootsReaction`, generic
+`RadrootsList` entries, and listing draft kind `30403` through `RadrootsListing`.
+
+The current gaps before the social refactor are:
+
+- missing model and codec coverage for articles, public generic file metadata, calendar date events,
+ calendar time events, reposts, generic reposts, calendar collections, RSVP events, and reports
+- incomplete kind and tag constants for the approved NIP surface
+- `RadrootsPost` does not yet preserve optional social metadata
+- `RadrootsComment` still accepts legacy `e_root` and `e_prev` fallback tags in canonical decode
+- `RadrootsReaction` currently rejects empty content even though empty content is a valid NIP-25 like
+- `RadrootsListing` needs explicit optional `published_at` metadata for NIP-99 parity
+- NIP-65 relay-list behavior needs explicit validation evidence through `RadrootsList`
+- conformance vectors and canonical-event witnesses do not yet cover every new or upgraded social
+ event family
+
+## Approved Event Families
+
+The MVP public social substrate includes:
+
+- `RadrootsPost` for ordinary NIP-01 kind `1` notes plus optional Radroots social metadata
+- `RadrootsArticle` for NIP-23 kind `30023` long-form content
+- generic public `RadrootsFileMetadata` for NIP-94 kind `1063`
+- `RadrootsCalendarDateEvent` for NIP-52 kind `31922`
+- `RadrootsCalendarTimeEvent` for NIP-52 kind `31923`
+
+The production-v1 public social substrate includes:
+
+- `RadrootsRepost` for NIP-18 kind `6`
+- `RadrootsGenericRepost` for NIP-18 kind `16`
+- `RadrootsCalendar` for NIP-52 kind `31924`
+- `RadrootsCalendarEventRsvp` for NIP-52 kind `31925`
+- `RadrootsReport` for NIP-56 kind `1984`
+- listing draft kind `30403` validation through `RadrootsListing`
+- relay-list kind `10002` validation through `RadrootsList`
+
+## Contract Decisions
+
+`RadrootsPost` remains compatible with ordinary kind `1` text notes. Content-only notes must remain
+valid. Optional farm or address references, media metadata, geohash, topics, and quote references
+must be preserved when present and must use serde defaults so existing simple JSON fixtures remain
+valid.
+
+`RadrootsComment` uses strict NIP-22 semantics. The target and scope model must support event-id,
+address, and external roots or parents through `E`/`e`, `A`/`a`, and `I`/`i` tags with matching
+`K`/`k` kind metadata. Canonical decode must reject legacy `e_root` and `e_prev` fallback tags.
+
+`RadrootsReaction` uses strict NIP-25 semantics. Empty content, `+`, `-`, emoji, and custom reaction
+content are valid when the target tags are valid. Missing targets remain invalid.
+
+`RadrootsReport` intentionally tightens NIP-56 for the Radroots type: a reported pubkey `p` tag is
+required for a valid report, including event and file or blob reports.
+
+Generic public `RadrootsFileMetadata` remains separate from private `RadrootsFarmFileMetadata` even
+though both use kind `1063`. The public generic model must cover the current simple NIP-94 tags,
+including URL, MIME type, SHA-256 hash, original hash, size, dimensions, blurhash, thumbnail, image,
+summary, alt text, fallback, `magnet`, `i`, and `service`.
+
+`RadrootsListingDraft` and `RadrootsRelayList` are not separate model types in the target contract.
+Listing draft kind `30403` is represented through `RadrootsListing`, and NIP-65 relay metadata kind
+`10002` is represented through `RadrootsList`.
+
+## Exclusions
+
+This substrate does not include `RadrootsFeedItem`, `RadrootsMapPin`, NIP-72 community events,
+checkout or payment events, or public task, harvest, work-session, approval, or other Field business
+document event types.
+
+Task records, work sessions, harvest records, approvals, and similar Field business objects remain
+CRDT document semantics carried inside the CRDT change envelope unless a later contract explicitly
+promotes them.
+
+## SDK Boundary
+
+The public social surface is event and codec substrate first. Curated SDK operation metadata may
+promote MVP social builders and parsers only after the corresponding Rust models, codecs, wasm
+helpers where needed, and conformance vectors exist. Production-v1 repost, report, calendar
+collection, and RSVP behavior remains substrate-visible by default unless a consumer proves that it
+should be promoted into the curated operation surface.
+
+## Conformance Boundary
+
+Every new social codec and every upgraded existing social codec must have deterministic valid and
+invalid conformance vectors before closeout. Upgraded vectors must include the strict comment,
+reaction, listing, farm, list, and list-set behavior whose public contract changes during the
+refactor.
+
+Social vectors are repo-owned and synthetic. They must not depend on application relay state, local
+databases, external services, root fixture catalogs, or ambient machine state.