Sashité for Developers
  1. Sashité for Developers
  2. Nostr
  3. NIPs
  4. Game Session

NIP-XX

Game Session

draft optional

Abstract

Defines kind: 3422, a regular event published by a player to found a session, and from which the session is playable. The Game Session carries the session’s two players, their seat assignments, their per-player variants, the game family, the rule system, the timing designation, and the initial position of play, and constitutes the signer’s explicit commitment to the session terms. The founding follows one of two paths that converge here — a Direct Challenge (kind 3420, fresh or rematch) accepted by the challenged player, or a matchmaking Pairing (kind 3419) founded by either of its players — each yielding exactly two players, seated first and second (the protocol’s seat vocabulary, kind 3420 §Match-terms tags); the variant vocabulary is the rule system’s. No Ply (kind 3423) is valid until a conforming Game Session is published.

On the directed path the Game Session is the acceptance: the challenged player accepts a Direct Challenge by founding the session on it, in one signed act.

Motivation

The lifecycle of a session has a transition between “proposed” (a challenge or a pairing exists) and “playable” (the players can submit Plies). Three concerns motivate making this transition one explicit, signed event:

  1. A single anchor. Every later event of the session — each Ply (kind 3423), the Conclusion (kind 3425), a rematch challenge (kind 3420 §Rematch challenge) — references the Game Session and nothing else. It is the event a consumer resolves first and the one by which a session is named.

  2. Self-containment for verifiers. The Game Session mirrors everything a verifier needs to replay the session from its events — players, seats, variants, rules, the timing designation, the initial position — so that no consumer has to walk the founding chain to know what the session is. Whatever a Direct Challenge left open (a variant, the seat) is settled here by the accepting player.

  3. t₀. The Game Session defines the session-start moment used for time-control accounting: its optional start_at tag when present, otherwise its canonical timing (§Canonical session start). Before t₀, no Ply is valid; at t₀, the clock of the player seated first starts running.

The suite designates no arbiter. What the Game Session states is not a third party’s ratification but a player’s commitment, and its correctness is not taken on trust: every term it carries is either mirrored from a founding event (and checked against it) or prescribed by the rule-system document named by rules (and checked against that). A Game Session that fails those checks founds nothing.

Specification

Event kind

kind: 3422

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

Signing party

The event MUST be signed by a player of the session, as its founding path determines:

A Game Session signed by any other pubkey is invalid and MUST be ignored by verifiers.

Tags

Founding reference

Tag Cardinality Value Description
e exactly one event id, optional relay hint, marker reference to the session’s founding event

The Game Session MUST reference, via exactly one e tag, the founding event the session is founded on. The marker (fourth element) names the founding event type:

The founding event carries the session’s timing designation (a timestamper-marked p tag in attested mode, or timing_relay tags in self-timed mode — Canonical Timing §Timing modes and mode selection), the rules term, and establishes the two players, so the Game Session’s signing-party and player rules apply uniformly regardless of path; seat and variant sourcing differ by path (see §Seats and §Variants). The relay hint (third element) is OPTIONAL but SHOULD be present.

Timing designation (mirrored)

Tag Cardinality Value Description
p timestamper zero or one pubkey, optional relay hint, marker timestamper in attested mode, the designated timestamper, mirrored from the founding
timing_relay zero or more relay URL (wss://…) in self-timed mode, the designated timing relays, mirrored from the founding verbatim

The Game Session repeats the founding’s timing designation — exactly one of the two forms — so that it is self-contained for verifiers: a consumer holding only the Game Session knows the session’s timing mode and which parties (timestamper, or relays) establish canonical timing for every event of the session, without first resolving the founding chain.

Game

Tag Cardinality Value Description
game exactly one game-family identifier the game family of the session

The Game Session MUST carry exactly one game tag identifying the game family. The identifier MUST match the regular expression ^[a-z][a-z0-9]{0,31}$ and MUST equal the game declared in the referenced founding event.

Example values: chess, shogi, xiangqi, go, or — in this suite — sanki (a multi-game 8×8 platform).

Players

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

The Game Session carries one p tag per player, each with the marker player as its fourth element:

The set of player pubkeys MUST be the two players established by the referenced founding event — on the directed path the challenge’s signer and its opponent, on the matchmaking path the Pairing’s two player-marked pubkeys — and the signer is one of them. The p tags serve a dual purpose: semantic (identifying the players) AND structural (notification routing via standard Nostr #p filters, so the other player receives the Game Session without chained subscription logic).

Seats

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

The Game Session MUST carry exactly one seat tag per player. The second element is the player’s pubkey; the third is the seat-name, one of exactly two protocol-defined values: first (moves first) or second (moves second). The two players MUST hold the two distinct values. Seat-names are play-order indices, not game vocabulary; the traditional labels (white/black, sente/gote, red/black) are presentation, mapped by the rule system (kind 3420 §Match-terms tags).

The source of the seat assignment depends on the founding path:

Variants

Tag Cardinality Value Description
variant exactly two (one per player) pubkey, variant-name the player’s variant within the game family

The Game Session MUST carry exactly one variant tag per player. Each variant tag is structured ["variant", "<player_pubkey>", "<variant_name>"]. The second element is a player pubkey; the third is a variant identifier matching ^[a-z][a-z0-9]{0,31}$.

Each player’s variant MUST equal that player’s variant declared in the referenced founding event when it declares one. On the directed path, a variant the Direct Challenge left open — the challenged player’s own, or the challenger’s when the challenger delegated it by omission (kind 3420 §Match-terms tags) — is supplied here by the challenged player, and is authoritative from this event. On the matchmaking path the Pairing fixes both (kind 3419 §Match-terms tags).

The requiredness is unconditional — a deliberately structural rule, so that conformance is countable without knowing anything about the game: a game family with a single variant simply repeats its one style’s identifier (e.g., ["variant", "<pubkey>", "chess"] in a plain chess session). The identifiers’ meaning stays opaque to the protocol; the rule-system document named by rules interprets them (for sanki, each player’s variant — chess, ogi, xiongqi — determines their setup and movement rules on the shared board).

Rules

Tag Cardinality Value Description
rules exactly one digest + optional retrieval hint the rule-system document of the session, mirrored from the founding

The Game Session MUST carry exactly one rules tag, ["rules", "<digest>", "<hint>"] (kind 3420 §Match-terms tags), whose digest MUST equal the rules digest declared in the referenced founding event. The hint MAY differ from the founding’s (the signer MAY name a server of their own).

Mirroring rules is what makes the Game Session self-contained for verifiers on this axis too: a consumer holding only the Game Session knows which rule-system document to apply to every Ply of the session, and to its Conclusion, without resolving the founding chain. It is also the signer’s commitment to play under it: a client that cannot retrieve and execute the named document MUST NOT publish a Game Session for it (kind 3420 §Validation responsibility).

Scheduled start (optional)

Tag Cardinality Value Description
start_at zero or one unix seconds the scheduled session-start instant (t₀); overrides canonical timing

A Game Session MAY carry a start_at tag — a single unix-seconds instant declaring when the session’s clock starts:

When present, start_at MUST be the event’s created_at (a session cannot schedule a start before it exists — locally verifiable), and it becomes the session’s t₀: no Ply is valid before it, and the game cannot begin before that instant. When absent, t₀ is the session’s canonical timing (§Canonical session start) — so start_at is fully backward-compatible and optional on both founding paths.

Because t₀ is shared by both players, a start_at shifts both clocks identically and cannot create an asymmetric advantage. A session on either founding path MAY use it to schedule a start ahead of publication — including, on the directed path, to give the challenger notice before the clock of the player seated first starts running (§Client guidelines).

Content

The content field MUST be a non-empty string representing the initial position of the session. The encoding format is application-specific and determined by the consuming application based on the session’s game and variant tags; the position itself is the one the rule-system document named by rules prescribes for the session’s (game, variants) — the signer has no discretion over it, and a Game Session whose content is not the prescribed position is non-conforming (constraint 7). The suite supports no randomized-setup variant: no party is designated to draw one, and a rule-system document MUST prescribe a deterministic initial position for every pairing it defines (kind 3420 §Match-terms tags). Common encoding formats include:

The protocol does NOT prescribe any particular encoding and does NOT interpret it. Recognition of the encoding (from the declared game and variant), parsing, and the check against the rule system’s prescribed position are the responsibility of the consuming application.

Requiring an always-present initial position encoding — rather than allowing an implicit “default position” for deterministic variants — eliminates ambiguity. Every Game Session is self-describing: a consumer can reconstruct the session’s starting state from the event alone, given the declared encoding format, without depending on hardcoded conventions about what “the standard position of variant X” means. It also generalizes uniformly to game-specific setups (e.g., the reference sanki rule system, where the multi-style nature of the game makes a “default” hard to define).

The content field MUST consist of valid UTF-8, contain no C0/C1 control characters (except those explicitly permitted by the declared encoding), and contain no Unicode bidirectional override characters. The total length of the content field MUST NOT exceed 4096 bytes.

Semantic constraints

A conforming Game Session event MUST satisfy all of the following:

  1. The event contains exactly one e tag, marked direct_challenge or pairing, referencing a retrievable, signature-valid, conforming founding event (per that kind’s own constraints — kind 3420 §Semantic constraints, including §Rematch challenge for a rematch challenge; kind 3419 §Consent constraints, the Pairing being canonical).
  2. The event’s pubkey (the signer) is a player established by that founding event, as §Signing party requires for its path: the opponent of a Direct Challenge; either player of a Pairing.
  3. The event contains exactly one game tag, with a valid identifier per §Game, whose value equals the game declared in the referenced founding event.
  4. The event contains exactly two p tags carrying the marker player, with distinct pubkeys, equal as a set to the two players established by the founding event, and including the signer.
  5. The event contains exactly one seat tag per player. Each seat tag’s second element is a player pubkey (per constraint 4); the seat-names are first and second, one each (§Seats). On the directed path the assignment is consistent with the Direct Challenge’s seat tag when present (the challenger holds the declared value); when absent, any assignment satisfying the one-each rule conforms. On the matchmaking path the assignment equals the Pairing’s seat tags.
  6. The event contains exactly two variant tags, one per player pubkey (per constraint 4). Each variant’s third element equals that player’s variant declared in the referenced founding event when it declares one (§Variants); a variant the Direct Challenge left open is any valid identifier.
  7. The content field is a non-empty string per §Content, with length at most 4096 bytes, and — for a consumer able to interpret it — encodes the initial position the rule-system document named by rules prescribes for the session’s (game, variants).
  8. If a start_at tag is present, it is a single unix-seconds value the event’s created_at; t₀ is then the later of it and the canonical timing (§Canonical session start).
  9. The event’s timing designation mirrors the founding’s verbatim: the same timestamper-marked p tag (attested mode) or the same timing_relay set (self-timed mode), and exactly one of the two forms. The event’s canonical timing is at or before the founding event’s deadline: the Direct Challenge’s accept_until on the directed path, the Pairing’s found_until on the matchmaking path (kind 3419 §Lifecycle tags); a Game Session whose canonical timing exceeds it is non-conforming.
  10. Exactly one rules tag is present, whose digest (second element) matches ^[0-9a-f]{64}$ and equals the rules digest of the referenced founding event (§Rules).

Constraints 1–6, 9 and 10 require cross-event validation against the referenced founding event (directed: the Direct Challenge, and for a rematch challenge the concluded Game Session and Conclusion it references; matchmade: the Pairing, kind 3419, and the two Open Challenges it references). Constraint 7 requires the rule-system document; a consumer that does not hold it checks the field’s form only and treats the session as unverified rather than conforming. Constraint 8 is checkable from the event alone. The Game Session’s created_at is informational and is not subject to any cross-event semantic constraint beyond constraint 8; ordering is enforced structurally by the cross-event reference chain (the Game Session references the founding event by event ID, which proves it was signed after the founding event existed).

Idempotence and race resolution

A given session has exactly one canonical Game Session. The slot a Game Session occupies is:

If several Game Session events exist for the same slot — a player publishing twice, both players of a Pairing founding it, both players’ rematch challenges being accepted — the canonical event is determined per Canonical Timing §Meta-resolution: the candidate with the smallest canonical timing, with the smallest event ID as tiebreaker.

Non-canonical Game Sessions are ignored by verifiers. A player SHOULD publish only one Game Session per slot, and SHOULD NOT publish one once they observe a canonical Game Session for it; a single player publishing several is non-conforming behavior and may indicate misbehavior or implementation bugs, whereas the two players of a Pairing racing is the expected cost of letting either found, resolved here. In attested mode, the Game Session’s own created_at is informational and MUST NOT be used for canonicalization; in self-timed mode it IS the canonical timing (made non-backdatable by the designated timing relay).

Validation responsibility

Validation of a Game Session against the semantic constraints is the responsibility of the client (the other player’s client first — it is the acceptance it was waiting for — then downstream observers and rating verifiers). A Game Session that fails semantic constraints is structurally invalid and MUST be rejected: it founds nothing, and on the directed path it does not accept the challenge either, which stays open until its accept_until.

A session without a conforming Game Session remains in the “proposed but not playable” state. No Ply (kind 3423) can be valid for such a session: Ply validity requires t₀, and t₀ requires both a conforming Game Session and its canonical timing (§Canonical session start; kind 3423 §Time accounting). Plies whose canonical timing precedes t₀ MUST be treated as invalid.

Canonical session start

The session-start timestamp (t₀), used by time-control accounting (see kind 3423 §Time accounting), is:

t₀ = the later of the Game Session’s start_at tag value (when present) and the Game Session’s canonical timing (Canonical Timing §t₀).

With no start_at, t₀ is simply the canonical timing. With a future start_at, the session is scheduled and no clock runs before it. And if canonical timing is established only after start_at has passed, t₀ is that later moment — no player is ever charged for an interval during which no valid Ply existed.

The canonical timing is, always, the timing that orders the session and establishes its existence. In attested mode it is the created_at of the Event Timestamp Attestation (kind 3410) signed by the designated timestamper and referencing this Game Session via an attests-marked e tag (the Session Start Attestation). In self-timed mode it is the Game Session’s own created_at, once its acceptance by a designated timing relay is established. Whichever branch yields t₀, the result is authoritative for all time-control accounting — rule-system-defined; the reference sanki rule system specifies it in its supporting document (Time Accounting — Sanki).

In attested mode, the Game Session’s own created_at is informational and MUST NOT be used as the canonical timing or as input to any timing-dependent decision (a present start_at still defines t₀); in self-timed mode the created_at is the canonical timing — and t₀ when no start_at is present.

The structure of the Session Start Attestation is:

["e", "<game_session_event_id>", "<relay_hint>", "attests"]

Only the attests-marked e tag is required. NIP-26-delegated signatures from the timestamper are NOT accepted as authoritative; see kind 3420 §Security considerations.

Until the Game Session has canonical timing, it is pending (Canonical Timing §The pending state) and the session is in a founded but untimed state: distinct from proposed (before the Game Session) and from playable (after t₀ exists and has been reached). No Ply is valid in this window — operationally, a Ply is early or late by comparing its own canonical timing to t₀; no wall-clock observer is involved. In attested mode, the Game Session acquires canonical timing when the designated timestamper attests it — a window bounded only by the timestamper’s responsiveness (§Handling a silent timestamper below). In self-timed mode, canonical timing is established the moment a designated timing relay accepts the Game Session, so the window is only propagation delay — unless no designated relay accepts it (§Handling a silent timing relay below).

No founding event’s created_at defines t₀. On the directed path, the Direct Challenge constrains the lifecycle deadline (accept_until); on the matchmaking path, the Open Challenges constrain the pool deadline and the Pairing contributes ordering via its own canonical timing. None of these contributes to time-control accounting, which anchors on the Game Session’s start_at (when present) or else its canonical timing.

Examples

The examples below use placeholder pubkeys, event ids, and timestamps for illustration.

Example 1 — Accepting a Direct Challenge (FEN encoding)

Alice challenged Bob (kind 3420, Example 1 there: game="chess", both variant="chess", Alice first, attested mode with Dave as timestamper). Bob accepts by founding the session: the Game Session is signed by Bob, references the challenge, mirrors its terms, and carries the standard chess starting position, which is what the named rule system prescribes:

{
 "kind": 3422,
 "pubkey": "<bob_pubkey>",
 "created_at": 1700000400,
 "tags": [
  ["e", "<challenge_event_id>", "wss://relay.example.com", "direct_challenge"],
  ["p", "<dave_pubkey>", "wss://relay.example.com", "timestamper"],
  ["game", "chess"],
  ["rules", "3f6d1a0c9e4b2a7d5c8e1f0a9b3c7d2e4f6a8b0c1d3e5f7a9b2c4d6e8f0a1b3c", "https://blobs.example.com"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<alice_pubkey>", "first"],
  ["seat", "<bob_pubkey>", "second"],
  ["variant", "<alice_pubkey>", "chess"],
  ["variant", "<bob_pubkey>", "chess"]
 ],
 "content": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
 "id": "...",
 "sig": "..."
}

The content carries the standard chess starting position in FEN. Even though the position is conventionally well-known, the protocol requires it to be explicit: the Game Session is self-describing. The session becomes playable once this event has canonical timing — its Session Start Attestation in attested mode, or acceptance by a designated timing relay in self-timed mode — establishing t₀ per §Canonical session start; at that point, the player assigned to seat first (Alice in this example) submits the first Ply.

Example 2 — Accepting a challenge that left terms open (FEEN encoding)

Bob challenged Alice in the sanki context, self-timed, fixing neither variant nor the seat (kind 3420, Example 3 there). Alice accepts, supplying both variants (she plays chess, gives Bob ogi — the delegation Bob consented to) and choosing the seats (Bob first), and carries the multi-variant starting position the rule system prescribes for (sanki, chess, ogi):

{
 "kind": 3422,
 "pubkey": "<alice_pubkey>",
 "created_at": 1700000400,
 "tags": [
  ["e", "<challenge_event_id>", "wss://relay.example.com", "direct_challenge"],
  ["timing_relay", "wss://relay.example.com"],
  ["game", "sanki"],
  ["rules", "3f6d1a0c9e4b2a7d5c8e1f0a9b3c7d2e4f6a8b0c1d3e5f7a9b2c4d6e8f0a1b3c", "https://blobs.example.com"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<bob_pubkey>", "first"],
  ["seat", "<alice_pubkey>", "second"],
  ["variant", "<alice_pubkey>", "chess"],
  ["variant", "<bob_pubkey>", "ogi"]
 ],
 "content": "<FEEN string encoding Bob's ogi setup and Alice's chess setup on a shared 8×8 board; see Position Encoding — Sanki for the concrete encoding>",
 "id": "...",
 "sig": "..."
}

The content carries a FEEN representation of the multi-variant initial position. FEEN’s three-field structure (piece-placement, hands, style-turn) accommodates Sanki’s defining property: two players using different variants on a shared board (the exact profile is the rule system’s supporting document, Position Encoding — Sanki). A verifier holding the rule-system document checks that this is indeed the prescribed position for these variants and seats.

Example 3 — Matchmade session (Pairing founding)

The session was founded through the matchmaking pool: the canonical Pairing (kind 3419) matched Alice and Bob, fixed both variants (ogi), and drew the seats (Bob first). Either player may found; here Alice does, referencing the Pairing with the pairing marker and mirroring its seats:

{
 "kind": 3422,
 "pubkey": "<alice_pubkey>",
 "created_at": 1700000400,
 "tags": [
  ["e", "<pairing_event_id>", "wss://relay.example.com", "pairing"],
  ["timing_relay", "wss://relay.example.com"],
  ["game", "sanki"],
  ["rules", "3f6d1a0c9e4b2a7d5c8e1f0a9b3c7d2e4f6a8b0c1d3e5f7a9b2c4d6e8f0a1b3c", "https://blobs.example.com"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<alice_pubkey>", "second"],
  ["seat", "<bob_pubkey>", "first"],
  ["variant", "<alice_pubkey>", "ogi"],
  ["variant", "<bob_pubkey>", "ogi"]
 ],
 "content": "<FEEN string for the ōgi-vs-ōgi starting position>",
 "id": "...",
 "sig": "..."
}

Had Bob published his own Game Session for the Pairing at the same time, it would be identical in every tag and in content; the one with the smaller canonical timing (then the smaller id) is canonical, the other ignored. Everything downstream of this event is identical to a directed session.

Example 4 — Rematch (accepting a rematch challenge)

Alice proposed the rematch of a concluded session (kind 3420, Example 6 there: seats swapped, every other term inherited). Bob accepts exactly as he would any Direct Challenge; the slot this Game Session occupies is (rematch, <concluded_session_id>):

{
 "kind": 3422,
 "pubkey": "<bob_pubkey>",
 "created_at": 1700009100,
 "tags": [
  ["e", "<rematch_challenge_id>", "wss://relay.example.com", "direct_challenge"],
  ["timing_relay", "wss://relay.example.com"],
  ["game", "sanki"],
  ["rules", "3f6d1a0c9e4b2a7d5c8e1f0a9b3c7d2e4f6a8b0c1d3e5f7a9b2c4d6e8f0a1b3c", "https://blobs.example.com"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<bob_pubkey>", "first"],
  ["seat", "<alice_pubkey>", "second"],
  ["variant", "<alice_pubkey>", "ogi"],
  ["variant", "<bob_pubkey>", "chess"]
 ],
 "content": "<FEEN string for the swapped-seat starting position>",
 "id": "...",
 "sig": "..."
}

Nothing here is Bob’s choice: the rematch challenge fixed the seats and both variants, and the content is the position the rule system prescribes for them.

Client guidelines

Clients implementing kind: 3422 SHOULD:

  1. For the accepting player’s client (directed path): before publishing, retrieve and verify the rule-system document, compute the prescribed initial position, mirror every term the challenge fixed, and supply — with the user’s input or a deterministic default — every term it left open. Consider carrying a start_at a short interval ahead when the challenge is old, so that the challenger’s client has time to notice the acceptance before the clock of the player seated first starts running.
  2. For the founding player’s client (matchmaking path): publish the Game Session as soon as the canonical Pairing is observed; the content is fully determined, so no user input is needed. Do not publish if a canonical Game Session for the Pairing is already observed.
  3. For players’ clients: do NOT allow the user to submit a Ply (kind 3423) until t₀ is established (see §Canonical session start). This requires a conforming Game Session with canonical timing — in attested mode, the Session Start Attestation from the designated timestamper; in self-timed mode, acceptance by a designated timing relay. Display distinct indicators for the two pre-playable states:
    • Awaiting acceptance / founding (a challenge or a canonical Pairing exists, no Game Session yet).
    • Awaiting authoritative timing (Game Session received but not yet canonically timed — in attested mode, no Session Start Attestation yet): “founded; waiting for authoritative timing”.
  4. For all clients: validate a received Game Session against the semantic constraints — including, when the rule-system document is held, the prescribed initial position — before treating the session as founded; parse the content per the variant’s encoding conventions to display the initial position. Recognition of the encoding is by the declared game and variant; common encodings include FEN, SFEN, and FEEN.
  5. For rating verifiers and observers: a session without a conforming Game Session has no effect on ratings (no Ply is valid, no contributing Conclusion can be produced).

Handling an unaccepted challenge or an unfounded Pairing

If the challenged player never publishes a Game Session, the Direct Challenge expires at its accept_until without effect (kind 3420 §Security considerations, Decline by silence). If neither player of a canonical Pairing founds the session before the Pairing’s deadline, the Pairing lapses likewise (kind 3419 §Lifecycle tags), and the players re-enter the pool. In both cases the dormant events remain on Nostr indefinitely but carry no protocol-level consequence; there is no void mechanism and none is needed, since no clock has started.

Handling a silent timestamper (attested mode)

This applies in attested mode. After the Game Session has been published, the designated timestamper is expected to publish the Session Start Attestation. If they never do, t₀ is never established and the session remains in the “founded but untimed” state indefinitely: the session is dormant, no Ply is valid, no Conclusion can produce a contributing verdict for rating purposes (Plies are required for any non-trivial verdict context, and Plies require t₀).

Players SHOULD treat the absence of a Session Start Attestation within a clock-reasonable interval as a strong signal that the timestamper is unavailable. To formally close this dormant state, the players’ clients SHOULD display the session as “timestamper unavailable” and offer the players the option to start a fresh session (a new Direct Challenge) with a different timestamper. The dormant Game Session remains on Nostr indefinitely but carries no protocol-level consequence.

The principal mitigation is selection: players SHOULD only accept challenges whose designated timestamper they trust to be operational. A timestamper that goes silent after play has begun is a distinct case with no specified recovery — a known limitation of attested mode; a recovery path must be specified before a deployment activates the mode.

Handling a silent timing relay (self-timed mode)

In self-timed mode t₀ is established as soon as one of the designated timing relays accepts the Game Session, so there is normally no separate wait. The analogue of a silent timestamper is a designated set none of whose relays will accept the Game Session — because they are unreachable, or reject the event (for example, a created_at their clocks deem in the past). Until a designated relay accepts it, the Game Session is pending and t₀ is undefined — exactly the founded but untimed state above. Players SHOULD treat persistent rejection or unavailability as a signal that the designated relays are unusable, and offer to start a fresh session designating working relays. The mitigation is the same as for every designated party: designate relays you trust to be operational and correctly configured (Canonical Timing §Security).

Security considerations

References