- Sashité for Developers
- Nostr
- NIPs
- Composition
NIP-XX
Composition
draft optional
This NIP defines a Nostr event kind by which anyone publishes a complete composed puzzle as a single, self-signed artifact: a board position under a stipulation — the problemists’ “White to play and mate in two” — together with the proof that the stipulation holds, a forcing-strategy certificate answering every legal defence. The exercise and its proof are one event because they are one act: to compose a puzzle is to pose an exercise one has already solved. A Validation (kind 3441) attests, in time linear in the certificate’s size, that the proof realizes the stipulation; until such a Validation exists from a validator the consumer trusts, a Composition is a claim nobody believes.
Abstract
Defines kind: 3440, a regular event by which any pubkey — the composer — publishes, under one signature, a position and a strategy certificate for it: at each solver turn the solver’s move, then one branch per legal opponent reply, down to leaves the game classifies as achieved. The stipulation is carried in tags — exactly one objective, completed by a required moves bound, the problemists’ “mate in N” spoken whole — and is asserted, not verified, at publication: nothing downstream believes it, and a Composition whose certificate does not realize its stipulation simply never acquires a valid Validation.
Verifying a Composition — every move legal, every opponent node exhaustive, every leaf achieved, then the derived outcome equal to the stipulated objective and the derived depth equal to the moves bound — requires no search. Producing it is where the work lives, and that work is the composer’s, performed once at the edge by an engine that had to run anyway.
Because the artifact is signed by its author, it rides the social graph natively — no authority’s key stands between a composer and their audience. It becomes activity once it is validated: activity surfaces render it when a trusted validator’s valid Validation exists — “a mate in two by X”, the stipulation realized — and until then it is reachable, not broadcast-visible (§Client guidelines). The event MAY carry an optional provenance reference to the Game Session the position arose from, and an optional routing reference to a validator.
Motivation
Two inversions produced this kind, and both are worth stating because each removed a whole apparatus.
The first was the proof. The withdrawn v1 funnel (kinds 6416/6417/30421) put correctness in the right place — nothing submitted was believed — but made the authority search, and a forced-objective search is exponential in depth. The authority therefore needed a search bound (Dmax), a triviality minimum, and a spam-hardened examination pipeline; and the resulting artifact was signed by the authority, so a composer’s puzzle never appeared under their own key. Carrying a certificate inverts the expensive step: the composer searches, the validator checks. A certificate is a proof — it covers every defence — and checking a proof is linear in its size. The bounds fall away mechanically: nothing is searched, so nothing needs a Dmax; a mate in one is a one-node certificate, so nothing needs a floor; and the natural ceiling becomes the relay’s event-size policy, an operator matter rather than a protocol constant.
The second was the merge. An intermediate revision split the artifact in two — a Problem (the stipulated position) and a Solution (the certificate), joined by an event reference — so that a position could be posed by one pubkey and proved by another. The split bought a community-solving layer, and priced it in machinery: a pool of competing Solutions, a canonical-solution fold to pick one, race resolution over that pool, a solver credit distinct from the composer’s, a transient decline for an unretrievable Problem, and a non-atomic paired publish — Nostr offers no multi-event atomicity, so a crash or a relay rejection between the two legs left a stipulated position standing with no proof in sight. Carrying both in one event deletes all six at once: there is one artifact, one signature, one proof of work, one failure mode, and nothing left to arbitrate. What it gives up — a position posed without a solution, and a proof attached by a third party — is recorded, with the loss accepted, in this suite’s design notes (application layer: Design Notes — Puzzles §The merged composition).
What the event keeps from the composition tradition is the stipulation. A position does not determine an exercise: the same diagram may hold a draw in 2 and a mate in 6, two different puzzles with different solutions and very different difficulty, and stipulating which one is being posed is what makes a puzzle a puzzle rather than an invitation to analyse. The required moves bound completes it — “mate in two” is the tradition’s whole sentence — and an objective without a distance is a study, not a problem statement: a genre this family deliberately does not pose.
Specification
Event kind
kind: 3440 — a regular event per NIP-01: immutable once signed and broadcast. A composer who wants to amend a Composition publishes a new one; the old one stands, and its Validation stands with it.
Signer — the composer
Any pubkey whatsoever. No role designates a composer and publishing confers no standing. The composer is credited as such wherever the Composition is rendered (kind 3441 §Credit); credit is attribution, not authority.
Timing
Not part of any session’s lifecycle, never attested; canonical timing is the event’s own created_at. Nothing in this family depends on Composition ordering.
Tags
| Tag | Cardinality | Value | Description |
|---|---|---|---|
game |
exactly one | identifier matching ^[a-z][a-z0-9]{0,31}$ |
the game whose rules the position and the certificate are read in; determines both encodings (reference: sanki) |
objective |
exactly one | mate, draw, advantage, or a game-defined token (§The stipulated objective) |
the stipulation: the outcome the solver is asked to force |
moves |
exactly one | positive integer, decimal, no leading zero | the stipulation’s bound: the exact number of solver moves the exercise is posed in (§The moves bound) |
L |
exactly one | a NIP-32 namespace token | the label namespace all l tags carry (§Index labels) |
l |
exactly three | the three prefixes of <game>:<objective>:<moves>, each with the same namespace as its third element |
NIP-32 labels: the relay-indexable projection of the stipulation (§Index labels) |
p validator |
0 or more | pubkey, optional relay hint, role marker validator |
OPTIONAL routing hints, one tag per validator: the validators whose verdicts the composer is seeking (§Addressing validators) |
e game_session |
0 or 1 | event id, optional relay hint, marker game_session |
OPTIONAL provenance: the Game Session (kind 3422) the position arose from; absent for a hand-composed position |
nonce |
exactly one | nonce + committed difficulty | NIP-13 proof of work |
alt |
0 or 1 | human-readable string | NIP-31 fallback (e.g. "A Sanki puzzle: mate in 2.") |
The game tag is the one discriminant a reader needs: a position whose encoding is not named is unreadable (the transport interprets nothing — a suite-wide principle — and game is how a consumer knows what not to interpret). The encoding itself — FEEN and the sanki half-move triple for sanki, FEN or SFEN or anything else for another game — is the game’s own definition, exactly as on every other kind of the suite.
The nonce tag follows NIP-13, with the committed difficulty required as its third element: this is an open-authorship kind and inherits the suite’s two spam defences, per-event proof of work and consumer author-scoping.
There are deliberately no claim tags beyond the stipulation: no depth, no outcome, no soundness. The certificate is the answer to the stipulation, and what it achieves is derived from it at validation and compared with the stipulation there (kind 3441 §The stipulation check, §The depth check). A value that is a pure function of the certificate is redundancy — restating derivable data only creates a second copy that can drift from the first.
The stipulated objective
The objective tag holds a single lowercase token, the stipulation. Three values are reserved by this NIP and carry a fixed meaning in every game:
| Value | The solver forces… | Guaranteed outcome |
|---|---|---|
mate |
a terminal state the rule system scores maximally in the solver’s favour | decisive, for the solver |
draw |
a terminal state the rule system scores as a draw | drawn |
advantage |
a non-terminal state the game deems decisively better for the solver | none |
The three are stated in terms of outcomes, not mechanisms, which is what keeps them rule-system-agnostic: nothing here presumes a board, a piece set, or a check — mate is the tradition’s name for the maximal-terminal class, not a mechanism requirement, and a game whose maximal terminal is not literally a checkmate still binds the class to it. Which of a game’s states realize a leaf of each class is the game’s own binding, in its supporting document (kind 3441 §Leaf classification; for the reference sanki rule system: Puzzle Specification — Sanki).
The vocabulary is open beyond the three: a game MAY define further objectives — the composition traditions contain stipulations no outcome class expresses, helpmates and selfmates among them. A token MUST match ^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)*$ and be at most 32 characters — no colon; namespacing uses a dot — and a game-defined token SHOULD be namespaced with the defining application’s prefix (sashite.helpmate), keeping the reserved/extension boundary legible at a glance. The colon is reserved as the index labels’ separator (§Index labels), which is what keeps a label unambiguously decomposable. A validator that does not serve a stipulated objective declines unsupported (kind 3441 §Content): an unrecognized stipulation makes a Composition unservable by that validator, never non-conforming.
The stipulation is asserted, not verified: no conformance condition, no relay, and no reader is asked to believe it. Its verification lives at validation, where the certificate’s derived outcome MUST equal the stipulated objective exactly — a certificate deriving anything else, weaker or stronger, is declined objective_mismatch (kind 3441 §The stipulation check).
The moves bound
The REQUIRED moves tag holds a positive decimal integer with no leading zero: the exact number of solver moves the exercise is posed in, counted as the certificate’s derived depth counts them — the maximum solver moves along any branch (§Content). The stipulation is the pair, outcome and distance — “mate in two”, the tradition’s whole sentence — and an objective without a distance is a study, “White wins, find how”: a genre this family deliberately does not pose. The exclusion is recorded, with the loss it accepts, in this suite’s design notes (Design Notes — Puzzles §The mandatory bound); it is smaller than it reads — a certificate is a finite tree and always derives a depth, so a composer, who by construction holds the certificate, always holds the bound to state.
The bound shares the stipulation’s whole discipline. It is asserted, not verified, at publication, and checked where the objective is checked — post-walk, at validation — and exactly: a sound certificate whose derived depth is anything other than the bound, deeper or shallower, is declined depth_mismatch (kind 3441 §The depth check). The shallow direction is deliberate: a “mate in 2” that admits a mate in 1 is a cooked problem — the tradition’s own verdict — and the family declines it by design rather than silently crediting the stronger answer. The bound adds no parameter to verification: it is read off the event exactly as the objective is, and the check stays linear.
Index labels
Relays index only single-letter tag names (NIP-01), so objective and moves are invisible to every filter. The stipulation is nevertheless the one axis on which a solver selects work — a mate in two, in sanki — so the event carries a relay-indexable projection of it, in the two label tags NIP-32 already defines. The letters are not taken from the ecosystem: L and l already mean label namespace and label, so no future NIP can reclaim them, and no query built on them can silently widen.
A conforming Composition carries exactly one L tag — a well-formed NIP-32 namespace token, echoed by every l tag — and exactly three l tags, each with that namespace as its third element, holding the three prefixes of the exercise facet <game>:<objective>:<moves>. Which namespace to use is a deployment convention, not a conformance condition: each consuming deployment fixes one for its puzzle corpus and filters by it (#L), rather than declaring other namespaces non-conforming (the reference deployment uses sashite.puzzle). With that namespace:
["L", "sashite.puzzle"],
["l", "sanki", "sashite.puzzle"],
["l", "sanki:mate", "sashite.puzzle"],
["l", "sanki:mate:2", "sashite.puzzle"]
Three properties earn the shape:
- The facet is hierarchical, not orthogonal. A projection of n independent dimensions would have to materialize 2ⁿ wildcard combinations, because a filter matches by equality; a projection of nested prefixes materializes n. Three values, some forty bytes, and a query is simply “the longest prefix I care about”.
- All three, or the index under-returns. A Composition carrying only
sanki:mate:2would be invisible to a query forsanki:mate. Partial projections fail silently, which is the one failure mode an index must not have; the cardinality is therefore exactly three, and it is a conformance condition. - It asserts nothing. The three values are a pure function of
game,objectiveandmoves— all present in the same event — so the projection is checkable from the event alone and adds no claim to the one the stipulation already makes. This is what makes it a REQUIRED tag rather than an optional courtesy: it costs nothing to verify, and an optional index is an index that under-returns by construction.
A consumer queries with the namespace scoped, which is what makes the label values collision-proof across the ecosystem:
{"kinds": [3440], "#L": ["sashite.puzzle"], "#l": ["sanki:mate:2"]}
Two limits are inherent to NIP-01 filters and belong in any client’s expectations. Filters compare by equality only: moves <= 3 is not expressible in any encoding, and difficulty ranges must be materialized by a curator or resolved consumer-side. And validation state is not filterable: a valid Validation lives on kind 3441, one hop away, so “validated mate-in-two puzzles” is a join no relay performs. Consumers resolve it themselves, or read a curated set published by an indexer they trust — an application-layer service this NIP does not define and does not need to.
Addressing validators
Each OPTIONAL validator-marked p tag names a validator whose verdict the composer is seeking. A Composition MAY carry none, one, or several: a composer serving two audiences — an application’s own validator and a third party’s — addresses both in the one event and receives, in time, one verdict from each.
They are routing hints and nothing more: each lets a validator subscribe to its own work queue with one #p filter instead of watching the whole kind, and lets a client render “submitted to X and Y” while a verdict is outstanding.
They bind no one, in either direction. A named validator owes no answer — an unjudged Composition is unjudged, not invalid (kind 3441 §Validator discretion) — and any validator MAY judge the Composition, named or not, since a Validation is reactive and unaddressed. Consumers select verdicts by their own trusted set, never by the composer’s address list, and that is what makes the plurality harmless: naming ten validators buys a composer ten chances of a verdict and not one reader’s trust. Divergent verdicts on one Composition are the expected consequence of addressing several, not a fault — they are public, attributable and replayable, and a consumer resolves them against its own trusted set exactly as it resolves unsolicited ones.
The list says where a composer went looking for a verdict; it never says which verdicts count. Its absence is equally conforming: a validator that watches the kind finds the work anyway.
Provenance
The OPTIONAL game_session-marked e tag records where the position came from — a game the composer played or watched — and is absent for a hand-composed position. It is a display reference first: clients offer navigation to the source game. It is nevertheless verifiable in principle — the position occurs in the session’s canonically replayed chain or it does not — and a consumer holding an engine MAY check that and treat a reference that fails it as spoofed. Validators are NOT required to verify provenance: it bears on no certificate’s soundness, and a Validation attests the proof, never the origin story.
A consumer that makes no use of provenance MUST still accept the tag and validate its shape (§Semantic constraints, constraint 7). Ignoring a tag’s meaning and rejecting the event that carries it are different things, and the second would decline a conforming Composition for a reason this NIP does not authorize.
Content — the position and the certificate
The content field carries a JSON object (serialized per NIP-01) with two REQUIRED members:
{
"position": <string>, the position, in the game's encoding
"certificate": <certificate> the forcing-strategy proof
}
Members this NIP does not define are ignored, as everywhere in Nostr. The envelope is protocol-defined; both values are game-defined, and the transport interprets neither.
position — a non-empty string of at most 512 characters, encoded per the game tag, which a game’s supporting document MAY tighten. Commentary belongs in ordinary notes referencing this event, never here. Whether the string parses, and whether it denotes a legal position, are game-specific questions settled at validation — not transport-level conformance conditions.
certificate — the proof, recursively:
certificate = [ move, replies ]
replies = [ [opponentMove, certificate], … ] # possibly empty
move = a half-move in the game's encoding — the same encoding the
game's Plies use (for sanki: the [source, destination, actor] triple)
Reading: from the current node’s position, the solver plays move; if the resulting position is achieved (a terminal the game scores for the solver, or a non-terminal state meeting a game-defined objective criterion — kind 3441 §Leaf classification), replies MUST be empty and the branch ends; otherwise replies MUST contain exactly one entry per legal opponent reply in that position, each continuing with the certificate for the position after that reply.
The exhaustiveness is on the defence side and there alone: at each solver node the certificate names one move, at each opponent node it answers every legal one. That asymmetry is the whole proof. A certificate closes the universal quantifier a puzzle’s statement contains — forces the outcome against every defence — where a solution line closes nothing: the opponent’s replies in a line are the proposer’s own choice, so a checked line witnesses only that a cooperative opponent can be mated. A single line is nevertheless the degenerate certificate in which every opponent node happens to have exactly one legal reply — a forced mate in 200 by perpetual constraint is a 400-half-move certificate, a few kilobytes. There is no minimum: a mate in one is [move, []].
Two quantities are derived by any checker and stated by nobody:
- depth — the maximum number of solver moves along any root-to-leaf path: the guarantee achieved in at most
depthsolver moves against every defence. Compared with themovestag at validation, and required to equal it exactly (kind3441§The depth check). - outcome — the weakest leaf class under the game’s outcome order (for the reserved classes:
mateoveradvantageoverdraw): what the strategy actually guarantees. A certificate mixing mating leaves with stalemating leaves guarantees only the draw. Compared with theobjectivetag at validation, and required to equal it exactly (kind3441§The stipulation check).
A third quantity is derived for display, by a rule this NIP fixes so that every client shows the same thing:
- the canonical line — from the root, descend at each opponent node into the subtree of greatest depth; on a tie, into the reply whose encoded move is smallest under the game’s own move ordering (for
sanki, lexicographic on the[source, destination, actor]triple). The result is a single root-to-leaf line — the principal variation, the defender’s longest resistance as the certificate bounds it — and it is what a client renders as “the solution”. The certificate stays exhaustive; the line is a view, computed identically by every consumer, never published.
Whether the JSON parses, whether the tree is well-shaped, and whether it survives the mechanical check are validation questions, answered with an informative verdict (kind 3441) — not conformance conditions. A malformed event earns silence; a well-formed event carrying a broken certificate earns an answer that helps the composer fix it.
Semantic constraints
A conforming Composition event MUST satisfy all of the following:
- The
contentfield is a non-empty string. (Whether it parses as the two-member envelope, whether thepositionrespects the game’s length limit, and whether thecertificateis well-shaped are validation questions — §Content — never conformance conditions: a conforming event can be recognized without a JSON parser, and a well-formed event carrying a broken payload earns an informative verdict rather than silence.) - The
gametag is present exactly once and matches^[a-z][a-z0-9]{0,31}$. - The
objectivetag is present exactly once and matches^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)*$, at most 32 characters. (Whether the objective is forceable, and whether any validator serves it, are validation questions — never conformance conditions.) - The
movestag is present exactly once and its value is a positive decimal integer with no leading zero. (Whether the certificate realizes the bound is a validation question — kind3441§The depth check — never a conformance condition.) - The
Ltag is present exactly once, carrying a well-formed NIP-32 namespace token; theltag is present exactly three times, each carrying that same namespace as its third element, and the three values are exactly<game>,<game>:<objective>and<game>:<objective>:<moves>, taken from the tags of constraints 2–4. (Checkable from the event alone — the labels are a pure function of the stipulation and the declared namespace. Which namespace a deployment consumes is a filtering convention, never a conformance condition.) - Every
ptag, if any are present, carries the markervalidatoras its fourth element and a 64-character lowercase hex pubkey as its value, and no pubkey appears in more than oneptag. (How many answer, and whether any does, are nobody’s conformance conditions.) - The
etag, if present, appears at most once, carries the markergame_sessionas its fourth element, and its value is a 64-character lowercase hex event id. (Whether it resolves, and whether the position really occurs in that game, are consumer verification questions — not conformance conditions.) - The
noncetag is present exactly once, carries its committed difficulty as its third element, and the event id satisfies NIP-13 against that committed difficulty — never against a relay’s advertised minimum (an ingestion policy, not conformance).
A non-conforming Composition MUST be ignored.
Duplication
Compositions are regular events, so the same exercise may exist under several event ids, by one composer or many — and, since the certificate travels with the exercise, two Compositions of one exercise may carry different proofs: the two keys of a dual, or two independent searches of the same strategy. This is accepted and is the family’s only remaining plurality. A consumer MAY merge displays by exact equality of the exercise tuple — game, objective, moves and the position member, which the l label’s longest prefix already carries but for the position — and nothing requires it to. Where the merge matters most is in play: a client that accepts a solver’s move against the union of the validated certificates sharing an exercise accepts every proved answer to it, not merely the one it happened to load (kind 3441 §Client guidelines).
Client guidelines
- Diffusion. Activity surfaces — the composer’s profile, their own timeline, their followers’ timelines, the feeds — SHOULD render a Composition only once a
validValidation from a validator in the consumer’s trusted set exists for it (kind3441§The validated state), the display carrying the realized stipulation and the composer’s credit. Until then the Composition is reachable, not broadcast-visible: a direct link, the composer’s own private listing. The gate is consumer-side because nothing else can be: kind3440is open-authorship, so an unsound or plainly spam Composition is always publishable, by any client whatsoever, and no emission convention binds the network’s writers; the validation overlay is the one signal a reader can trust without holding an engine, and gating the feed slot on it is the only robust defence against pollution. The same gate applies to anything that carries a Composition into a feed indirectly — a reaction, a repost, a curated set: an ungated relay would reopen the door the direct gate closes. - Composing. Offer publication from any board the user is looking at — the composition page, an analysis view, a finished game — with the stipulation, objective and bound, chosen explicitly. A composing client MUST verify the whole event against its own engine before broadcasting — the walk, both post-walk checks — and MUST NOT publish a certificate it has not checked itself: an unsound Composition costs its proof of work and earns a public decline. State
movesfrom a search carried to minimality: a bound the position beats by a move is a cooked problem, declineddepth_mismatch, never repaired downstream. Mine the proof of work before broadcasting. - Size before publish. Estimate the serialized size against the target relay’s event-size limit; a Composition that does not fit is not publishable there, and no protocol mechanism splits one. Narrower strategies — preferring checking, forcing continuations — shrink certificates.
- Publication reach. A client MAY publish a Composition to the addressed validators’ relays alone and rebroadcast the identical signed event to its outbox relays once a
validValidation lands. The event id, signature and proof of work are fixed at signature, so the rebroadcast is the same event, not a second one — and the same event reaches every ecosystem whose validator vouched for it, which is what lets one Composition circulate in several applications at once. This keeps declined compositions out of the public record and closes the front-running window; it is a relay-selection policy, not a protocol mechanism, and a client that broadcasts widely from the start is equally conforming. Two things this policy is NOT. It is not what makes a Composition appear anywhere: diffusion is the bullet above — a consumer rendering what its own trusted set has vouched for — and a rebroadcast changes which relays hold an event, never whether any application shows it. And it is not free: a client that defers the second broadcast owes itself a way to complete one it never sent, or avalidComposition ends up validated for consumers who cannot reach it. The composer’s own listing of their submissions is the natural place to notice and finish the job. - Tracking the verdict. Subscribe to kind
3441with#eon the Composition’s id, or#pon the user’s own pubkey for all their verdicts. - Provenance link. When the
game_sessionreference is present, offer navigation to the source game; mark the link unverified unless the client has checked the position against the game’s replay. - Appreciation. A reader may bookmark a Composition with a NIP-25 reaction (an application convention — this suite’s Stars), which names the composer in a
ptag and is the one signal that reaches them from outside the validation loop. A star is not a verdict and MUST NOT be displayed as one: it says a reader liked the puzzle, never that it holds.
Security considerations
- One claim, and a proof attached to it. A Composition asserts its stipulation, and carries in the same event the material that settles it. Nothing believes the claim at publication: an illegal position, a stipulation the certificate does not realize, or a
movesbound it misses, simply never acquires a valid Validation, never surfaces as activity, and stands as what it is — an unvouched claim. Its whole exposure is public silence, and the only way to lie is to publish a tree that fails its own mechanical check, which any engine-holding party detects in linear time. - Cooperative lines are structurally excluded. Exhaustive opponent nodes are the whole point: there is no encoding of a helpmate in this kind, because a certificate that omits a defence is invalid, mechanically. This is the property a line-based format cannot have at any price, and it is why the certificate is not negotiable.
- Spam. Open authorship, defended as everywhere in the suite: NIP-13 proof of work per event, and reader-side author scoping — plus the defence this family adds on top, validation-gated diffusion (§Client guidelines). Any client can publish any Composition, but none buys a feed slot until a trusted validator has vouched for it, so the noise open authorship admits stays where readers go looking, never where they merely read.
- Addressing fan-out. Each
validatorptag routes one event to one more pubkey, so an unbounded address list is a mild amplification: one proof of work, many notified parties. It is bounded by the forces that bound everything else here — bytes are priced by the proof of work, and no validator owes an answer — and clients SHOULD name the validators a composer actually wants a verdict from rather than every validator they can enumerate. Relays MAY bound the count by policy. - Size-based denial. A maliciously enormous certificate costs a validator time linear in its size, bounded by the relay’s event-size cap — the same cap that bounds every event. Validators MAY additionally bound the Compositions they examine by size, as policy.
- Provenance spoofing. A composer may reference a Game Session the position never arose in. The reference is checkable by replay, and it carries no weight anywhere — no validation, no credit, no ranking reads it — so the attack decorates a link, nothing more. Clients SHOULD present unverified provenance as such.
- Uncertified uniqueness. A Composition proves that its stipulation can be met, never that its key is unique: a certificate establishes sufficiency, and a second key at the same depth — a dual, a defect in the composition tradition — is invisible to the check. Refuting every alternative key requires a search exponential in the bound, which is the cost this family exists to avoid. Consumers that need soundness read it from an authority that searches, never from a certificate; the analysis is in this suite’s design notes (Design Notes — Puzzles §Why uniqueness is not certified).
- No secrecy. A Composition is public from broadcast, certificate included: publishing a puzzle publishes its solution. A composer who wants an audience to solve it unaided relies on clients not to reveal the certificate before the attempt, which is a client-quality property and not a protocol one.
References
- Validation (kind
3441) — the validator’s verdict on a Composition; defines the mechanical check, the stipulation and depth checks, the validated state and the credit. - NIP-13 — Proof of Work.
- NIP-32 — Labeling (the
Landltags).
