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

NIP-XX

Pairing

draft optional

This NIP defines a Nostr event kind by which a designated matchmaker pairs two compatible Open Challenges (kind 3418) into a declared session for a turn-based, two-player abstract strategy board game of the chess family. The Pairing is the founding event of the matchmaking path: it stands in the same position as the Accepted Challenge (kind 3421) does for the directed path, and the resulting session is ratified, played, and adjudicated by the same downstream NIPs.

Abstract

Defines kind: 3419, a regular event signed by a matchmaker that references two Open Challenges (kind 3418) and binds them into a session. The Pairing names the two players, fixes the concrete arbiter (and, in attested mode, the timestamper) authorized by both Open Challenges, resolves each player’s variant, and carries the agreed time control. The arbiter then ratifies the session and assigns the seat by publishing a Game Session (kind 3422) that references the Pairing.

Neither player signs the Pairing. Their consent is pre-committed in their Open Challenges: a Pairing is conforming only if it respects the terms both referenced Open Challenges declared (§Consent constraints). This bounds the matchmaker’s authority to selecting which compatible pair to match, when, and which concrete values to choose within each Open Challenge’s authorization.

Motivation

A symmetric matchmaking pool needs an event that turns two independent “I am available” authorizations into one session, signed by a party neither player is. The Pairing is that event. The matchmaker observes the pool of Open Challenges (kind 3418) that authorize it, finds two that are mutually compatible, and publishes a Pairing referencing both.

The design separates pool entry (kind 3418, signed by each player) from pairing (this NIP, signed by the matchmaker) so that:

The Pairing declares the session. Whether and when it becomes playable depends on the arbiter publishing the Game Session (kind 3422); time-control accounting anchors at t₀, established by the Game Session’s canonical timing. See §From Pairing to Game Session.

Specification

Event kind

kind: 3419

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

Signing party

The event MUST be signed by the pubkey designated as matchmaker by both referenced Open Challenges (kind 3418). Any other signer’s event is not a conforming Pairing for those Open Challenges and MUST be ignored. The matchmaker is identified by signature; it is not carried as a p tag.

NIP-26-delegated signatures from the matchmaker are NOT accepted as authoritative, consistent with the suite’s delegation policy for designated parties (kind 3420 §Security considerations).

Attestation by the designated timestamper (attested mode)

This section applies in attested mode only (a timestamper is designated by both Open Challenges). In self-timed mode the Pairing’s canonical timing is its own created_at, established by acceptance at a designated timing relay (Canonical Timing §Canonical timing of an event); it then serves the same roles — greedy matching and the accept-deadline check — without an attestation.

The designated timestamper publishes an Event Timestamp Attestation (kind 3410) referencing this Pairing via the required attests-marked e tag. The attestation’s created_at is then the Pairing’s canonical timing for greedy matching (§Race resolution) and for the accept-deadline check against each Open Challenge’s accept_until (§Consent constraints).

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

Only the attests-marked e tag is required; like the attestation of the Accepted Challenge (kind 3421), it carries no discovery marker, because the Game Session does not yet exist when the Pairing is attested. Until the Pairing has canonical timing (an attestation in attested mode, or established acceptance by a designated timing relay in self-timed mode), it is pending (Canonical Timing §The pending state): it has no position in greedy matching and cannot yet be ratified. NIP-26-delegated signatures from the timestamper are NOT accepted as authoritative.

In attested mode, the Pairing’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’s ingestion window. See Canonical Timing.

Tags

Reference tags

Tag Cardinality Value Description
e open_challenge exactly two event id, optional relay hint, marker the two Open Challenges (kind 3418) being paired

Each reference is ["e", "<open_challenge_event_id>", "<relay_hint>", "open_challenge"]. The two referenced Open Challenges MUST have distinct signers (the two players). The relay hint is OPTIONAL but SHOULD be present.

Player and authority tags

Tag Cardinality Value Description
p three or four pubkey, optional relay hint, role marker exactly two player; exactly one arbiter; and, in attested mode, exactly one timestamper (absent in self-timed mode, the default)

The p tags serve a dual purpose: semantic (the participants and the concrete third parties) and structural (routing via standard #p filters, so each player and the arbiter receive the Pairing). The arbiter and the timing designation (timestamper, or timing_relay tags) are carried explicitly so the Game Session (kind 3422) can verify them by the same logic it uses for the directed path.

Match-terms tags

Tag Cardinality Value Description
game exactly one game identifier the game context (equal to both Open Challenges’)
variant exactly two (one per player) pubkey + variant identifier each player’s resolved variant
time_control one or more duration + optional increment + optional plies the agreed time-control configuration

The game tag is ["game", "<game_id>"] and MUST equal the game of both referenced Open Challenges.

Each variant tag is ["variant", "<player_pubkey>", "<variant_id>"]pubkey-based, now that both players are known (the role→pubkey transition described in kind 3418 §Role-based ownership). Exactly one per player, unconditionally: the Pairing resolves every preference left open by the Open Challenges, so both players’ variants are fixed here — a single-variant game simply repeats its one style’s identifier. The resolved variants MUST satisfy both Open Challenges’ role preferences (§Consent constraints). The identifiers’ meaning stays opaque to the protocol (the arbiter’s rule system interprets them), mirroring kind 3422 §Variants.

The time_control tag uses the format and multi-period semantics of the Direct Challenge (kind 3420 §Match-terms tags) and MUST be identical to the time-control configuration of both referenced Open Challenges. Identity is compared on the parsed period sequence: the same number of periods in the same order, each pair equal in duration, in increment presence and value, and in plies presence and value. No normalization is applied: a period with no increment and a period with an explicit increment of 0 are not identical (kind 3420 §Match-terms tags).

No seat tag is carried. The seat assignment is performed by the arbiter in the Game Session (kind 3422), which assigns each player a seat at ratification time. See §From Pairing to Game Session.

There is no nonce tag: like the Game Session (kind 3422) and the Adjudication (kind 3425), a Pairing is signed by a designated third party, not subjected to proof of work. Spam resistance for the founding path is carried by the proof of work on the Open Challenges (kind 3418).

Content

The content field MUST be the empty string (""). A Pairing carries no narrative payload; its semantics are fully expressed by its tags.

A conforming Pairing event MUST satisfy all of the following. Constraints 11 and 12 are checkable from the event alone; the rest require the two referenced Open Challenges (and, for constraints 9 and 10, external data: the Pairing’s canonical timing, the filtering players’ contact lists, and the pinned rating attestations).

  1. Exactly two open_challenge-marked e tags, referencing retrievable, signature-valid, conforming Open Challenge events (kind 3418, per its §Semantic constraints) whose signers are distinct.
  2. The event’s pubkey (the matchmaker) equals the matchmaker-marked pubkey of both referenced Open Challenges.
  3. Exactly two player-marked p tags, whose pubkeys equal the signers of the two referenced Open Challenges (one each).
  4. Exactly one arbiter-marked p tag whose pubkey equals the arbiter-marked pubkey of both Open Challenges.
  5. Timing designation matches both Open Challenges (Canonical Timing §Timing modes and mode selection): in attested mode (both designate the same timestamper), exactly one timestamper-marked p tag whose pubkey equals that designation, and no timing_relay tag; in self-timed mode (both designate the same timing_relay set), timing_relay tags equal to that set (as a set), and no timestamper-marked p tag. A Pairing whose timing designation disagrees with either Open Challenge — or two Open Challenges whose designations differ from each other — cannot found a session; such a Pairing is non-conforming.
  6. Exactly one game tag whose value equals the game of both Open Challenges.
  7. Exactly two variant tags are present, one per player pubkey, and the resolved per-player variants satisfy, for each player P with resolved variant vP: (a) if P’s own Open Challenge carries a self variant, vP equals it; and (b) if the other player’s Open Challenge carries an opponent variant, vP equals it. A player whose variant is constrained by neither (a) nor (b) MAY be assigned any variant by the matchmaker — but the assignment is always written: the Pairing carries one resolved variant per player, unconditionally.
  8. The time_control configuration is identical to that of both Open Challenges.
  9. Each player satisfies the other player’s Open Challenge filter, evaluated at the Pairing’s canonical timing:
    • for everyone (or an absent filter): trivially;
    • for following: the filtering player follows the other, per the filtering player’s most recent NIP-02 contact list (kind 3) whose created_at is less than or equal to the Pairing’s canonical timing — the suite’s uniform at-or-before anchoring for consulting a replaceable list. The contact list being a replaceable event, this leg is fully verifiable only by consumers who observed the list at the relevant time (the matchmaker, the players, live observers); a late verifier who can no longer reconstruct the list state SHOULD treat the matchmaker’s pairing and the arbiter’s ratification as evidence of satisfaction rather than presume non-conformance;
    • for rating: both players’ ratings come from the pinned rating source carried by the filter (the rating-authority pubkey, attestation kind, and declared pool scope — kind 3418 §Match-terms tags). Each player’s rating is the most recent conforming attestation by that authority for that player in the scope the filter declarespergame: attestations carrying the session’s game, regardless of variant tags; pervariant: attestations whose game and single variant tag match that player’s resolved variant in this Pairing — with created_at less than or equal to the Pairing’s canonical timing; the other player’s rating MUST be within max_delta of the filtering player’s. A player with no such attestation is unrated and the filter is NOT satisfied. Under a pervariant scope, a rating filter is satisfiable only when the Pairing resolves the same variant for both players (a multi-variant session has no shared (game, variant) pool to compare in); under a pergame scope, the single game pool is shared regardless of the resolved variants, and the filter binds across any variant combination. This leg is objective and retroactively verifiable from public data alone: rating attestations are regular, persistent events, and the scope is written in the filter.
  10. The Pairing’s canonical timing is less than or equal to the smaller of the two Open Challenges’ accept_until values. A Pairing whose canonical timing exceeds either deadline (or whose referenced Open Challenge has none) is non-conforming.
  11. The matchmaker pubkey is distinct from both player pubkeys.
  12. The content field is the empty string ("").

A Pairing violating any constraint is non-conforming and MUST be ignored by all consumers (clients, the arbiter, rating verifiers). Non-conforming Pairings are not retracted from relays; they simply have no effect. This is the mechanism that bounds the matchmaker: it may choose the pair, the timing, and any value left free by both Open Challenges, but it cannot bind a player to an arbiter, timestamper, opponent, variant, time control, or counterparty outside that player’s signed authorization.

Race resolution — greedy matching

A given Open Challenge participates in at most one canonical Pairing. Because a Pairing references two Open Challenges, canonicalization is a matching problem rather than a single-slot selection; it is resolved deterministically and anchored, like the rest of the suite, on canonical timing (Canonical Timing §Meta-resolution):

  1. Consider all conforming Pairings that have canonical timing. Order them by their canonical timing (ascending), with the smallest Pairing event id as tiebreaker.
  2. Process them in that order, maintaining a set of “consumed” Open Challenges (initially empty). A Pairing is canonical iff both of its referenced Open Challenges are still free; on acceptance, mark both as consumed. A Pairing referencing an already-consumed Open Challenge is non-canonical and is skipped.

This greedy procedure yields the same matching for every consumer from the public events alone. If an Open Challenge appears in two conforming Pairings, the earlier-attested Pairing wins it; the later Pairing is void, and the other player it named remains free to be matched by a subsequent Pairing (in practice, their client re-enters the pool). A Pairing with no canonical timing does not participate.

From Pairing to Game Session

The Pairing declares the session; it does not make it playable. The designated arbiter ratifies by publishing a Game Session (kind 3422) whose founding-reference e tag points to the canonical Pairing (marker pairing) and whose signer is the arbiter named by the Pairing. The Game Session:

From the Game Session onward the lifecycle is identical to the directed path: Ply (kind 3423), Adjudication Request (kind 3424), Adjudication (kind 3425), and optional rating attestations (kinds 3426/3427) all apply unchanged. A matchmade session contributes to ratings exactly as a directed one does, subject to the pool scope in effect (a pervariant scope excludes multi-variant sessions from rating filters; a pergame scope rates them together).

Validation responsibility

Validation of a Pairing against the consent constraints is the responsibility of the client, the arbiter (which MUST validate before ratifying), and rating verifiers. A non-conforming Pairing does not declare a session; the arbiter SHOULD decline to publish a Game Session for it.

Examples

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

Example 1 — Same-variant pairing

The matchmaker pairs Alice’s and Bob’s sanki ōgi 5+3 Open Challenges:

{
 "kind": 3419,
 "pubkey": "<matchmaker_pubkey>",
 "created_at": 1700000100,
 "tags": [
 ["e", "<alice_open_challenge_id>", "wss://relay.example.com", "open_challenge"],
 ["e", "<bob_open_challenge_id>", "wss://relay.example.com", "open_challenge"],
 ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
 ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
 ["p", "<arbiter_pubkey>", "wss://relay.example.com", "arbiter"],
 ["timing_relay", "wss://relay.example.com"],
 ["game", "sanki"],
 ["variant", "<alice_pubkey>", "ogi"],
 ["variant", "<bob_pubkey>", "ogi"],
 ["time_control", "300", "3"]
 ],
 "content": "",
 "id": "...",
 "sig": "..."
}

The arbiter then publishes a Game Session (kind 3422) referencing this Pairing (marker pairing) and assigns Alice and Bob their seats.

Example 2 — Resolved multi-variant pairing

Bob’s Open Challenge fixed self = ogi and left opponent open; Dana’s fixed self = chess and left opponent open. The matchmaker resolves a multi-variant session (Bob ōgi vs Dana chess), valid because neither Open Challenge constrained the other’s variant:

{
 "kind": 3419,
 "pubkey": "<matchmaker_pubkey>",
 "created_at": 1700000100,
 "tags": [
 ["e", "<bob_open_challenge_id>", "wss://relay.example.com", "open_challenge"],
 ["e", "<dana_open_challenge_id>", "wss://relay.example.com", "open_challenge"],
 ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
 ["p", "<dana_pubkey>", "wss://relay.example.com", "player"],
 ["p", "<arbiter_pubkey>", "wss://relay.example.com", "arbiter"],
 ["timing_relay", "wss://relay.example.com"],
 ["game", "sanki"],
 ["variant", "<bob_pubkey>", "ogi"],
 ["variant", "<dana_pubkey>", "chess"],
 ["time_control", "300", "3"]
 ],
 "content": "",
 "id": "...",
 "sig": "..."
}

This is a multi-variant session; a rating filter declaring the pergame scope binds across it, while a pervariant declaration would have excluded it (constraint 9). Had Bob’s Open Challenge fixed opponent = ogi, this Pairing would be non-conforming (constraint 7) and ignored.

Client guidelines

Clients implementing kind: 3419 SHOULD:

  1. Subscribe to kind 3419 with a #p filter on the user’s pubkey to receive Pairings naming the user as player (and, for arbiter implementations, as arbiter).
  2. Validate a received Pairing against all consent constraints (§Consent constraints), retrieving both referenced Open Challenges, before treating the user as matched.
  3. Apply the greedy matching rule (§Race resolution) when an Open Challenge is referenced by more than one Pairing; act only on the canonical Pairing.
  4. After the canonical Pairing, display “matched; awaiting arbiter” and follow the Game Session (kind 3422); do not allow Ply submission until t₀ is established.

Arbiter implementations SHOULD, on observing a canonical Pairing naming them, validate it, assign seats (fairly, e.g. at random), and publish a Game Session (kind 3422) within a reasonable time, or decline by silence if the terms cannot be honored.

Security considerations

References