Sashité for Developers
  1. Sashité for Developers
  2. Nostr
  3. NIPs
  4. Conclusion

NIP-XX

Conclusion

draft optional

This NIP defines a Nostr event kind by which a player of a chess-family session concludes it: a verdict that terminates the session, signed by one of its two players and binding by correctness — it is valid if and only if it states the outcome that the session’s rule system yields for the session’s public events at the moment of its publication, which any consumer holding the rule-system document can recompute.

Abstract

Defines kind: 3425, a regular event by which either of the two players of a chess-family session publishes its verdict. The event references the Game Session (kind 3422), assigns a numeric result to each player via tags, and identifies the termination cause via the content field. Its own canonical timing is the cutoff at which the session’s natural state is evaluated.

A conforming Conclusion terminates the session. No further events can alter the outcome.

Until the suite’s 2026-09-04 revision this kind was the Adjudication, signed by a designated arbiter in response to an Adjudication Request (kind 3424, retired). The two events are merged here, and the arbiter is gone: the cutoff is the Conclusion’s own timing, and the verdict is verified rather than believed.

Motivation

Every rule question a chess-family session raises — which candidate Ply of a slot is legal, what the position then is, whether it is terminal, how the clocks are charged, what the outcome is at a given instant — is a function of the session’s public events and of the rule-system document the session was founded on (kind 3420 §Match-terms tags, the rules term). Two conforming implementations of that document reach the same answer. A verdict therefore needs no authority to be correct; what it needs is a signed, public, timed event that fixes the instant at which the session is evaluated and anchors its outcome for consumers that do not recompute it on every read: rematches (kind 3420 §Rematch challenge), rating authorities (kinds 3426/3427), indexers. The Conclusion is that event:

The Conclusion is signed by a player, not by a third party, and it asserts nothing the player is free to choose: the outcome it carries MUST be the one the rule system yields at its cutoff, and a Conclusion carrying any other outcome is structurally invalid — it does not terminate the session, exactly as a Ply that fails legality does not move a piece. A player who concludes while no objective cause stands — no termination on the board, no expired opponent clock, no draw offer to accept — does not thereby get a favourable verdict; they get the rule system’s residual reading of an invocation with no cause, which for the reference rule system is their own resignation (Statuses — Sanki §Implicit resignation). The Conclusion is thus also the suite’s resignation and draw-acceptance mechanism, without dedicated event kinds.

The numeric result is carried as tags because it is structured, per-player data that consumers extract without parsing the content. Note that relays index only single-letter tag names for filtering (NIP-01), so result tags are read client-side after fetching (by #e/#p), not used as relay-side filters. The termination status, by contrast, is a single opaque token and is therefore carried as the content payload rather than as a tag.

This NIP fixes the format and the protocol-level guarantees of the verdict (correctness as a conformance condition, idempotence, finality). It does not define rule-system-specific evaluation logic or a fixed vocabulary of termination statuses; those remain the responsibility of the rule-system document the session names and of its supporting documents. Whatever the vocabulary, it MUST be decidable from published events alone: a verdict is a function of the natural state and the session’s public events, never of unpublished claims.

Specification

Event kind

kind: 3425

Conclusion events are regular events per NIP-01: immutable once signed and broadcast.

Signing party

The event MUST be signed by one of the two players of the session — the player-marked pubkeys of the referenced Game Session (kind 3422 §Players). Either player may conclude, at any moment after t₀, whether or not it is their turn to move. A Conclusion signed by any other pubkey is invalid and MUST be ignored.

Attestation by the designated timestamper (attested mode)

This section applies in attested mode. In self-timed mode the Conclusion’s canonical timing is its own created_at, established by acceptance at one of the session’s designated timing relays (Canonical Timing §Canonical timing of an event).

The designated timestamper publishes an Event Timestamp Attestation (kind 3410) referencing this Conclusion via the required attests-marked e tag. Its created_at is then the Conclusion’s canonical timing — the cutoff, and the timing for race resolution.

The structure of the Conclusion Attestation is:

["e", "<conclusion_event_id>", "<relay_hint>", "attests"]
["e", "<game_session_event_id>", "<relay_hint>", "<app>:session"]

The second e tag carries an application-namespaced discovery marker <app>:session referencing the Game Session (the reference timestamper uses sashite:session), following the same discovery pattern as per-Ply attestations — and, as there, the designated timestamper MUST include it (kind 3423 §Time accounting). NIP-26-delegated signatures from the timestamper are NOT accepted as authoritative.

In attested mode, the Conclusion’s own created_at is informational and MUST NOT be used for any timing-dependent decision; in self-timed mode it IS the canonical timing, made non-backdatable by the designated timing relay. See Canonical Timing.

Natural state of events at the cutoff

The verdict a Conclusion carries MUST be the outcome of the natural state of events at the cutoff: the Conclusion’s own canonical timing.

Specifically, the natural state consists of the longest consecutive chain of Plies following the session’s play order from its first half-move, where the Ply at each position satisfies all of the following:

  1. The Ply occupies the next slot in the play order. A Ply’s slot is (session, signer, step), where step is the signer’s own move ordinal (kind 3423 §Step semantics and play order); the mapping from slots to the play order — where each player’s step k falls — is defined by the rule system for the session’s (game, variant). For many games the two players’ sequences strictly alternate within each step value, but a rule system MAY define a different interleaving, including turn structures where a player moves more than once in a row.
  2. The Ply is canonical for its slot per Canonical Timing §Meta-resolution (or per the rule system’s selection among a slot’s candidates, where it defines one — kind 3423 §Multiple Plies for the same step).
  3. The Ply’s canonical timing is less than or equal to the cutoff.
  4. The Ply’s canonical timing is greater than or equal to t₀ (kind 3422 §Canonical session start: the later of the Game Session’s start_at tag, when present, and its canonical timing). A Ply whose canonical timing precedes t₀ is invalid (kind 3423 §Time accounting: no Ply is valid before t₀) and MUST NOT enter the natural state.

Every rule-system question the chain raises — which candidate of a slot is legal, what the position is after a Ply, whether it is terminal, how the clocks are charged — and the resolution of the invocation when the chain ends in an ongoing position (who concluded, at what cutoff — the rule system’s post-chain conventions, such as an agreed draw, an abandonment timeout, or the residual resignation) are answered under the rule-system document the session was founded on, named by the Game Session’s rules tag (kind 3422 §Rules), and under no other. The concluding player has no latitude here: the natural state is a function of the public events, the signer, the cutoff and that document, which any party holding them can recompute — and constraint 8 makes agreement with that computation a condition of the Conclusion’s validity.

The chain stops at the first position in the play order for which no Ply satisfying all four conditions exists. Plies timed after the cutoff — canonical timing strictly greater than the cutoff — are excluded from the natural state. They MAY exist on Nostr and MAY become relevant for a later Conclusion with a later cutoff, but they do not contribute to this verdict.

Implications

Until the Conclusion has canonical timing

While the Conclusion has no canonical timing — in attested mode, not yet attested by the designated timestamper; in self-timed mode, not yet accepted by a designated timing relay — its cutoff is undefined and its verdict cannot be checked. Verifiers MUST treat such a Conclusion as pending — not yet effective as the session’s outcome, and not yet known to be conforming — until it acquires canonical timing (Canonical Timing §The pending state).

Tags

Reference tag

Tag Cardinality Value Description
e game_session exactly one event id, optional relay hint, marker reference to the Game Session (kind 3422) for this session

The relay hint (third element) is OPTIONAL but SHOULD be present.

Players

Tag Cardinality Value Description
p exactly two pubkey, optional relay hint, marker player a session player

The two p tags identify the two session players, each with the marker player as its fourth element:

The set of player pubkeys MUST match the players (the player-marked p tags) in the referenced Game Session (kind 3422); the signer is one of them. The p tags serve a dual purpose: semantic (identifying the two players) and structural (notification routing via standard Nostr #p filters — the opponent learns of the Conclusion through their own #p subscription).

Seats

Tag Cardinality Value Description
seat exactly one per player pubkey, seat-name the player’s seat assignment

The Conclusion MUST carry exactly one seat tag per player:

The seat-names are the protocol’s two values, first and second (kind 3420 §Match-terms tags), one per player. The set of seat tags MUST mirror those of the referenced Game Session: same player→seat mapping.

Outcome tags

Tag Cardinality Value Description
result exactly two pubkey + integer result assigned to a player

A result tag is structured ["result", "<pubkey>", "<integer>"]:

^(100|[1-9]?[0-9])$

This regex admits values from 0 through 99 (no leading zeros) and exactly 100. Values such as 00, 001, 101, or negative values are invalid.

The two result tags MUST reference the two different players. Their integer values MUST sum exactly to 100.

Common configurations:

Lifecycle tag

Tag Cardinality Value Description
nonce exactly one nonce + difficulty NIP-13 proof of work

The nonce tag follows NIP-13. Like the Ply, the Conclusion is a player-signed, clock-relevant event: the difficulty relays require for it SHOULD be kept low, since mining latency delays the cutoff and is borne by the signer.

Content

The content field MUST contain a termination status string identifying the cause of session termination, taken from the vocabulary defined by the application layer for the session’s rule system (e.g., Statuses — Sanki for the reference sanki rule system).

The content field MUST satisfy:

^[a-z]{1,32}$

That is: one to thirty-two lowercase ASCII letters (az), with no digits, no uppercase, no separators, no surrounding whitespace, and no JSON wrapping.

The content field MUST NOT carry any other data. A Conclusion carries no narrative payload: it states the rule system’s verdict, not the signer’s opinion of it. If a player wishes to publish commentary, they SHOULD use a separate event (e.g., a kind 1 note) referencing this Conclusion via an e tag.

Semantic constraints

A conforming Conclusion event MUST satisfy all of the following:

  1. The event contains exactly one game_session-marked e tag and no other e tag.
  2. The game_session e tag references a retrievable, signature-valid, conforming Game Session event (kind 3422, per its §Semantic constraints) that is the canonical Game Session for its slot (kind 3422 §Idempotence and race resolution).
  3. The event’s pubkey (the signer) MUST be one of the player-marked pubkeys of the referenced Game Session.
  4. The event contains exactly two p tags, each marked player, with distinct pubkeys, matching those of the player-marked p tags in the referenced Game Session.
  5. The event contains exactly one seat tag per p tag, with pubkey matching one of the players and seat-name first or second (one each). The seat assignments MUST mirror the seat tags of the referenced Game Session.
  6. The event contains exactly two result tags. Their second elements are the two different players’ pubkeys (as identified in the p tags). Their third elements are non-negative integers matching ^(100|[1-9]?[0-9])$, summing exactly to 100.
  7. The content field is a non-empty string of one to thirty-two lowercase ASCII letters matching ^[a-z]{1,32}$, with no surrounding whitespace and no additional data; and exactly one nonce tag is present, 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).
  8. Correctness. The event has canonical timing, and its result tags and content equal the outcome that the rule-system document named by the Game Session’s rules tag yields for the natural state of the session at the cutoff (§Natural state of events at the cutoff), with the event’s signer as the invoker. A Conclusion stating any other outcome is non-conforming.

Constraints 1, 6 and 7 are checkable from the event alone. Constraints 2–5 require cross-event validation against the referenced Game Session. Constraint 8 requires the session’s Plies, their canonical timings, and the rule-system document: a consumer that does not hold the document can check constraints 1–7 only and MUST treat the Conclusion as unverified, never as conforming.

Validation responsibility

Validation of a Conclusion against the semantic constraints (§Semantic constraints) is the responsibility of every consumer that acts on it: the opponent’s client, observers, rating verifiers, and any client founding a rematch on it.

A Conclusion that fails any constraint — constraint 8 included — is invalid and does not terminate the session. The session remains open, and either player MAY publish a new Conclusion, at a new cutoff, stating the outcome the rule system then yields. A client SHOULD compute the verdict with a conforming implementation of the rule system before publishing, so that its Conclusions are never invalid.

The rule-system document being public and content-addressed, no party is trusted on the rules axis: a Conclusion is checked, not believed. What remains trusted is the timing authority whose acceptance or attestation confers the cutoff (Canonical Timing §Security). The fuller trust model belongs to the consuming application’s documentation (this suite’s application layer maintains one).

Idempotence and finality

A given session has exactly one canonical Conclusion — a per-session slot: because every conforming Conclusion must reference the session’s canonical Game Session (constraint 2), all of a session’s conforming Conclusions share one game_session reference, and competing ones land in one slot. The canonical event is the conforming candidate with the smallest canonical timing, with the smallest event ID as tiebreaker (Canonical Timing §Meta-resolution), whichever player signed it. Two conforming Conclusions with different cutoffs MAY carry different verdicts — a premature claim resolving to the claimant’s resignation at one cutoff, a timeout against the opponent at a later one — and the earliest one rules, at its signer’s risk. A non-conforming Conclusion does not occupy the slot: it has no effect, whatever its timing.

Non-canonical Conclusions MUST be ignored by clients as the session’s outcome. They are not retracted from relays; they are simply not effective. They are not thereby void as evidence: any conforming Conclusion of a session witnesses that the session is over, canonical or not — which is why a rematch challenge (kind 3420 §Rematch challenge) may name any of them in its concluded_by reference, while the outcome it implies remains the canonical Conclusion’s alone. In attested mode, the Conclusion’s own created_at MUST NOT be used for canonicalization; in self-timed mode it IS the canonical timing.

Once a canonical Conclusion is established (a conforming Conclusion with canonical timing — attested by the designated timestamper in attested mode, or accepted by a designated timing relay in self-timed mode), the session is terminated. No further events — including subsequent Plies or later Conclusions — can alter the outcome. Until a Conclusion has canonical timing, it is pending and the session is not yet formally terminated.

Examples

The examples below use placeholder pubkeys, event IDs, relay URLs, and timestamps for illustration.

Example 1 — Decisive verdict, published by the winner

Bob (seat second) has checkmated Alice; his client computes the verdict and he publishes:

{
 "kind": 3425,
 "pubkey": "<bob_pubkey>",
 "created_at": 1700005100,
 "tags": [
  ["e", "<game_session_event_id>", "wss://relay.example.com", "game_session"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<alice_pubkey>", "first"],
  ["seat", "<bob_pubkey>", "second"],
  ["result", "<alice_pubkey>", "0"],
  ["result", "<bob_pubkey>", "100"],
  ["nonce", "18211", "8"]
 ],
 "content": "checkmate",
 "id": "...",
 "sig": "..."
}

Alice’s client, replaying the session under the rule system to cutoff 1700005100, reaches the same checkmate and the same result: the Conclusion is conforming and canonical. Had Alice published it herself — the loser concluding — the event would be identical but for its signer and would be equally valid.

Example 2 — Resignation

Alice, in a lost but not yet terminated position, resigns: she publishes a Conclusion whose verdict is the rule system’s residual reading of an invocation with no objective cause — her own loss (Statuses — Sanki §Implicit resignation):

{
 "kind": 3425,
 "pubkey": "<alice_pubkey>",
 "created_at": 1700005100,
 "tags": [
  ["e", "<game_session_event_id>", "wss://relay.example.com", "game_session"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<alice_pubkey>", "first"],
  ["seat", "<bob_pubkey>", "second"],
  ["result", "<alice_pubkey>", "0"],
  ["result", "<bob_pubkey>", "100"],
  ["nonce", "18211", "8"]
 ],
 "content": "resignation",
 "id": "...",
 "sig": "..."
}

Had Alice’s client instead written ["result", "<alice_pubkey>", "100"] with content "timeout" while Bob’s clock had not expired, the Conclusion would fail constraint 8 and have no effect.

Example 3 — Draw

Bob offered a draw with the draw flag on his last Ply; Alice accepts by concluding — the rule system reads the offeree’s invocation, while the offer is the last move of the chain, as an agreement:

{
 "kind": 3425,
 "pubkey": "<alice_pubkey>",
 "created_at": 1700005100,
 "tags": [
  ["e", "<game_session_event_id>", "wss://relay.example.com", "game_session"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<alice_pubkey>", "first"],
  ["seat", "<bob_pubkey>", "second"],
  ["result", "<alice_pubkey>", "50"],
  ["result", "<bob_pubkey>", "50"],
  ["nonce", "18211", "8"]
 ],
 "content": "agreement",
 "id": "...",
 "sig": "..."
}

Client guidelines

Clients implementing kind: 3425 SHOULD:

  1. Subscribe to kind 3425 events with a #p filter on the user’s pubkey to receive Conclusions of the user’s own sessions.
  2. Subscribe to kind 3425 events with an #e filter on Game Session event IDs to follow Conclusions of sessions of interest.
  3. Validate received Conclusion events against all semantic constraints (§Semantic constraints) — constraint 8 with a conforming implementation of the session’s rule system — before treating them as binding; display an unverifiable Conclusion (rule-system document not held) as such.
  4. Apply the canonical resolution rule (§Idempotence and finality) when multiple Conclusions reference the same session.
  5. Treat a canonical Conclusion as final; ignore any subsequent events (Plies, later Conclusions) for the same session.
  6. Read user-visible session results from the result tags, not the content field: the content carries the cause of termination; the result tags carry the outcome distribution. Relays index only single-letter tag names (NIP-01), so result is not usable as a relay-side filter — fetch Conclusions by #e (session) or #p (player) and extract the outcome client-side.
  7. Before publishing, compute the verdict at the intended cutoff with a conforming implementation, and surface the consequence to the user: the only unconditional “conclude” affordance SHOULD be resign; claim-style affordances (win on time, draw on the board, accept the draw) SHOULD be offered only when the client itself predicts the corresponding verdict from the same public events. When the board itself is terminal (checkmate, stalemate, a background draw), the client SHOULD publish the Conclusion on the user’s behalf, whichever player it serves — the winner has every reason to, and the loser loses nothing by it.

Security considerations

References