05 — Multiplayer
This document specifies every way Every Last City is played with more than one human, and it specifies exactly one thing about each: how order records and observation streams travel. The turn itself — the Orders phase, the Cascade, the Reckoning — is owned entirely by 10-turn-model.md and is identical in every mode. What changes between hot seat, live play, correspondence play and file play is the schedule and the carrier, never the rules.
Covered here: the four transport modes and their seat model; the common event-sourced foundation; concurrent order submission and how a phase closes; the wire protocol; the two authority modes; hot seat; live play over the Internet and LAN; correspondence play, which this turn model suits far better than sequential turn-taking ever did; the signed turn-bundle file for players with no infrastructure at all; switching a game between modes; notifications; deadlines, absence and AI substitution; spectating and replay; fog enforcement and anti-cheat; and self-hosted servers.
Status: Draft v0.2 · Owner: unassigned · Depends on: docs/design/00-direction.md, docs/design/01-decision-turn-model.md, 01-game-rules.md, 03-architecture.md, 04-ui-ux.md, 06-ai.md, 07-modding-content.md, 08-services-platform.md, 10-turn-model.md, 13-command.md, 14-victory.md
What this document is not. It defines no rule that changes what the simulation computes. Every requirement below is about transport, scheduling, storage, trust, or presentation. Where a requirement here appears to describe game behaviour, it is restating an obligation 10-turn-model.md owns, and 10-turn-model.md governs.
1. Multiplayer modes and definitions
MP-010 The game MUST support the following transport modes, all operating on the same game entity (immutable initial state + append-only order log per 03-architecture.md AR-250):
| Mode | How orders travel | Cascade runs on |
|---|---|---|
| Hot seat | Two or more humans share one device; each takes the Orders phase in sequence behind an occlusion screen (10-turn-model.md TM-460) | The local client |
| Live | All players connected concurrently over LAN or the Internet; orders stream to the authority as they are made | The authority (server or designated host client) |
| Correspondence | Server-held game; each player opens it whenever they like during the Orders phase, submits, and leaves | The server |
| Turn-bundle | The game serialized to signed, portable files passed by any out-of-band channel — email, forum, USB stick, airgapped network | The turn's closer (§10.4) |
MP-020 A seat is a slot in the game's player roster, identified by the stable player index
01-game-rules.md GR-020 assigns at setup. Every seat has a controller binding: local-human (a
profile on this device), remote-human (an account, per 08-services-platform.md), bundle-human (a
signing key, §10), ai (an AI plugin reference, per 06-ai.md), or vacant. Transport mode is a
property of how seats are bound and carried — never of the game state itself, and never of the player
index, which does not change for any reason including AI substitution (GR-020).
MP-030 Any combination of seat controller types MUST be permitted in one game (for example two local humans, one remote human, and two AIs). Rationale: a seat is a slot in a roster and a controller is a way of filling it; there is no reason for the two to constrain each other, and every restriction of the form "the organizer must be local" or "email games may have only one connected player" is an artifact of a transport, not a property of a game.
MP-040 All modes MUST be cross-play across every supported platform (Windows, macOS, Linux, iOS, Android, and the browser), guaranteed by the deterministic core (03-architecture.md AR-070). A game started on any platform MUST be joinable and resumable from any other.
MP-050 Offline modes (hot seat, LAN live play, turn-bundle) MUST NOT require an account or any
network service. Correspondence and Internet live play through an @everylastcity/server instance
require an account on that instance (official or self-hosted); guest accounts scoped to a single
server instance MAY be offered by that instance.
MP-060 The rules computed in every mode MUST be identical: same core version, same seed, same order log ⇒ same result, regardless of mode, transport, or how many times the game switched modes (10-turn-model.md TM-2410).
2. Mode capability parity
MP-070 Every mode MUST provide the capabilities marked required below. A mode MUST NOT be shipped with a required capability missing, and no mode MAY offer a capability marked unavailable:
| Capability | Hot seat | Live | Correspondence | Turn-bundle |
|---|---|---|---|---|
| The three-phase turn of TM-020, unmodified | required | required | required | required |
| Concurrent Orders phase (no player blocks another) | by occlusion, sequentially | required | required | required (§10.4) |
| Persisted orders carry an absent player (TM-280, TM-530) | required | required | required | required |
| Orders deadline and reserve bank (§13) | optional | required | required | soft only (MP-1040) |
| Server-enforced fog | unavailable | mode-dependent (§6) | required by default (MP-380) | unavailable (MP-790) |
| Compacted post-Cascade observation stream (TM-2150) | required | required | required | required |
| In-game chat (MP-185) | local only | required | required | carried in the bundle |
| AI substitution for an absent seat (MP-1010) | optional | required | required | optional |
| Spectating (§14) | unavailable live | policy-dependent | policy-dependent | post-game replay only |
| Rated play (MP-1160) | unavailable | authoritative only | authoritative only | unavailable |
| Mode switching in any direction (§11) | required | required | required | required |
MP-080 The ability to play a complete game with zero central infrastructure — turn-bundle, LAN, and hot seat — is a permanent requirement and MUST NOT be traded away for any server-side convenience. Rationale: a game whose multiplayer depends on a service the publisher operates is a game with an expiry date, and the correspondence games this design is built for have a lifetime measured in years (MP-630). The file must outlive the service, and it must outlive us.
3. Common foundations
MP-090 Every multiplayer game MUST be represented as the event-sourced entity defined in 03-architecture.md: immutable initial state (setup, map or generator+seed, content hashes) plus an append-only, sequence-numbered order log. Saves, resume, reconnection, spectating, replays, mode switching, and desync detection MUST all be derived from that log. The Cascade and the Reckoning MUST NOT be logged (10-turn-model.md TM-310); they are recomputed on replay.
MP-100 Every game MUST carry a globally unique GameId (UUIDv7) assigned at creation, stable
across mode switches, exports, and imports.
MP-110 Every game MUST be pinned at creation to: a core EngineVersion, a RulesVersion, a
protocol/view schema version (03-architecture.md AR-880, AR-920), the content hashes of its unit set,
map/scenario or generator plugin, and any behavioural mods (07-modding-content.md), and every ruleset
value that changes what the Cascade computes — including the Initiative Tier of 10-turn-model.md
TM-1030, which is fixed for the life of the game (TM-1070). All participants MUST run the pinned core
version; clients MUST support side-by-side core versions so old games stay playable.
MP-120 Content auto-distribution: when a joining client lacks pinned content, the lobby/server MUST offer to fetch it — data content (unit sets, maps, scenarios, assets) automatically; sandboxed WASM plugins (AI, generators) after a one-time per-plugin consent prompt. Hash mismatch MUST block joining.
3.1 There is no active seat
MP-130 There is no active seat. At any instant the game is in exactly one phase (10-turn-model.md TM-090), and during an Orders phase every seat may append order records concurrently. What MUST be exclusive is the authority: exactly one node (server, designated host client, or the turn's bundle closer) owns the right to assign log sequence numbers and append. All modes MUST enforce single-authority append; concurrent divergent appends MUST be impossible by construction (server sequencing) or detected and rejected (bundle sequence check, §10.6).
MP-135 Concurrency MUST be safe without ordering guarantees between players, because an order record can only mutate state belonging to its issuing player and any two records from different players therefore commute (10-turn-model.md TM-240). The transport MUST NOT add an ordering constraint of its own, MUST NOT hold one player's submission until another's has arrived, and MUST NOT let arrival order be observable to any player.
Rationale: this is the single most important consequence of the turn model for this document, and it is why the old possession machinery is gone. Under sequential turns, transport had to enforce "one player at a time" because the rules required it; the file that vanished from the sender's game list and the server that refused out-of-turn orders were both implementations of that rule. Under Orders and the Cascade the rule does not exist. The authority still sequences the log — that is a storage property — but it sequences a set of records whose result does not depend on the sequence, and a test proves it (TM-2360 hazard 7). Nothing about a fast connection, an early submission, or a lucky arrival order can buy anything.
MP-140 Player identity in a game is the seat, not the transport: a seat's human controller MAY change device, platform, connection, or mode binding at any time without affecting game state, stats attribution, or colours. Per-seat display colours personalized by a player MUST be stored per player per game.
MP-150 Losing and leaving: 14-victory.md owns what it means to leave a game and what placing a
departing player receives (VC-080). This document owns notification and access: a player who
capitulates, concedes, or is eliminated MUST be notified in-game and, in correspondence games, via
notification (§12), and MUST be offered spectator access to the remainder of the game under the
game's spectating policy (§14). A Concede order (14-victory.md VC-320, VC-2840) MUST travel as an
ordinary logged order like any other.
MP-160 Auto-persistence: in every connected mode the authority MUST durably persist the log after
every accepted order record and at every CloseOrders. A crash MUST lose at most order records whose
results were never acknowledged (MP-290).
MP-170 Clean lifecycle: no client action (window close, crash, network drop, sleep) may hang or corrupt a game for other players. Leaving is always safe, resuming is always possible from the persisted log, and an absent player never blocks anyone (10-turn-model.md TM-560).
MP-180 The complete wire protocol, bundle format, and server API MUST be publicly documented and versioned, sufficient for third-party clients and self-hosted servers to interoperate.
3.2 Chat and presence
MP-185 All connected modes (live, correspondence, spectators) MUST provide in-game text chat: a
game-wide channel, plus optional private player-to-player messages. In correspondence games chat MUST
be persistent, turn-annotated, and delivered with turn notifications. Chat history is part of the
game record but MUST NOT enter the order log (it can never affect simulation state). Because it is
game record, in-game chat travels as the Chat / ChatRelay protocol messages of MP-270 and MUST
NOT ride a room framework's ephemeral state-sync channel (MP-265; 08-services-platform.md SVC-402
states the same boundary from the server side). Pre-launch lobby chat is the separate, expendable
capability of MP-465 and carries none of this requirement's obligations.
MP-186 Connected clients MUST see per-seat presence, and presence MUST consist of exactly:
whether the seat is connected; whether it has issued CommitOrders for the current Orders phase;
time remaining on the deadline and in that seat's reserve bank; and, in correspondence games, time
since the seat's last action. Presence MUST be ephemeral, MUST NOT contribute to any hash, and MUST
NOT carry any fact about the game world (10-turn-model.md TM-440, TM-2070).
4. Turn handling: Orders, the Cascade, the Reckoning
MP-190 Turn handling is the three-phase turn of 10-turn-model.md TM-020 — a concurrent Orders phase, an input-free Cascade, and an input-free Reckoning — in every mode, with no variants, no options, and no per-mode differences. There is no sequential turn-taking anywhere in this specification, no seat is prompted "when it is their turn", and no player waits on another player's units.
Rationale: this is the change that reshaped this document. The previous draft specified sequential turns as the model and treated concurrent play as a variant that would need sealed batches and reveal-after-commit machinery. The reality is the reverse: the model is concurrent by construction, the sealing machinery is unnecessary because no client is ever sent another client's orders (MP-230), and the transport's job shrank from enforcing possession to relaying two things — order records up, and one observation stream per player down.
MP-192 The phases, their ordering, what may happen in each, and every rule about deadlines, absence and substitution are owned by 10-turn-model.md. This document specifies only how the records that drive them are carried, measured, and stored. Where the two appear to conflict, 10-turn-model.md governs.
MP-195 Exactly one node MUST run the Cascade and the Reckoning for a given turn: the server in authoritative mode, the designated host client in relay-only mode, the local client in hot seat and solo play, and the turn's closer in bundle mode (§10.4). Every other node MUST obtain the turn's outcome by replaying the turn record locally (relay-only, LAN, bundle) or by receiving its own observation stream (authoritative). No node MAY treat a Cascade it did not compute or replay as authoritative.
4.1 Order submission
MP-200 During an Orders phase a connected client MUST receive no information about the game world at all. The board is stable (10-turn-model.md TM-340) and every player sees their knowledge view exactly as the previous Cascade left it (TM-2050, TM-2060). The only thing the transport MAY deliver during an Orders phase is presence (MP-186) and chat (MP-185).
Rationale: under sequential turns this document had to specify a live fog-filtered feed to the players who were waiting, because things were happening that they could legitimately see. Now nothing is happening. The Orders phase transmits nothing, which is simpler, cheaper, and closes a whole class of leak by having no channel to leak through.
MP-205 A client MUST be able to submit order records incrementally throughout the Orders phase, in whatever order the player works, batched or one at a time (MP-280). The authority MUST validate and append each accepted record immediately (MP-300) and MUST NOT hold records until the player commits.
MP-210 Order records for a unit and stack level MUST resolve last-write-wins by ascending log sequence number (10-turn-model.md TM-230). A client MUST be able to revise any order any number of times before the phase closes, at no cost and with no record beyond the log itself (TM-360).
MP-215 CommitOrders MUST mark the issuing seat ready without freezing its orders and without
conferring any advantage (10-turn-model.md TM-390). RevokeCommit MUST be accepted while the phase
is open and rejected after CloseOrders (TM-420). Neither MUST be required: a seat that submits
nothing at all has a well-defined turn (TM-290).
MP-220 The Orders phase MUST close by exactly one authority-issued CloseOrders record, after
every seat has committed, timed out, or been marked absent or substituted (10-turn-model.md TM-430).
It MUST close immediately when every seat expected to act has committed, without waiting for the
deadline (TM-400). No other mechanism MAY close a phase.
MP-225 The authority MUST reject, with a typed rejection (03-architecture.md AR-320), any order
record naming a turn other than the current one or arriving outside that turn's Orders phase
(10-turn-model.md TM-260) — PhaseForbidden is the rejection for the latter. A late record MUST NOT
be queued for the next phase.
4.2 What the transport must not carry
MP-230 The authority MUST NOT relay any order record, or any derivative of one, to any client other than its issuer. It MUST NOT disclose another seat's order count, order kinds, unit selection, camera position, edit activity, or the timing of any of these (10-turn-model.md TM-450). Presence (MP-186) is the complete list of what a player may learn about another player during an Orders phase.
Rationale: sealed-envelope cryptography is unnecessary here and would have been theatre. The protection is structural — the server simply never sends one player's orders to another — and it is stronger than a seal, because a seal protects a payload that was nonetheless transmitted. The one mode where the payload genuinely must travel past other seats is bundle play, and §10.4 handles that with a commitment rather than by pretending the file is private.
MP-235 No client MAY submit anything during the Cascade or the Reckoning, and the authority MUST reject anything that arrives (10-turn-model.md TM-050). The transport MUST NOT offer a mid-Cascade prompt, confirmation, or interrupt of any kind, in any mode.
4.3 Delivering the result
MP-240 After the Cascade completes and the Reckoning closes, the authority MUST deliver to each seat exactly one observation stream: the compacted, ordered list of events that seat observed (10-turn-model.md TM-2150), carrying no gaps, placeholders, activation indices, per-event timestamps, or any field whose value varies with unobserved activity (TM-2160).
MP-245 In a game with two or more human players the stream MUST be transmitted as a single payload after the Cascade has fully completed (10-turn-model.md TM-2170) and MUST NOT be streamed incrementally. In solo and hot seat games it MAY be delivered incrementally (TM-2180). Playback pacing is client state and MUST NOT reach the authority (TM-2330).
MP-247 Pre-Cascade agreement: every node holding full state MUST compute the activation-order
hash of 10-turn-model.md TM-2370 at CloseOrders and exchange it before the Cascade runs; the
authority MUST compare and MUST report any mismatch as a desync immediately (TM-2380, MP-1150). The
hash travels on its own channel and MUST NOT be folded into the canonical state hash (TM-2390).
Rationale: this is the cheapest desync check in the system and the only one that fires before any
state has diverged. A few hundred bytes exchanged between CloseOrders and the first activation
catches an initiative modifier applied in a different order, a tier term contributing on one build
and not another, or a sort without a comparator — and it names the bug, where the same divergence
found three turns later at the state hash names nothing.
4.4 Hot seat scheduling and rolling planning
MP-249 In hot seat play the Orders phases of the players sharing a machine MUST be taken in sequence with full occlusion between them (10-turn-model.md TM-460, §7 below), and the resulting turn record and every hash MUST be identical to the same orders submitted concurrently. Where consecutive seats are all resolved by the same client — local humans in hot seat, or AI seats resolved by the authority — there MUST be no artificial pause between them beyond the occlusion hand-off itself.
MP-251 Where the client offers rolling planning (10-turn-model.md TM-2550), orders staged for turn T+1 while turn T plays back MUST remain entirely client-side. The transport MUST NOT transmit them, and the authority MUST reject them, until the Orders phase for T+1 has opened (TM-2570). Rolling planning MUST NOT be enabled in a mode where a player could act on the current Cascade before another player has received the same stream; where MP-245 holds, that is satisfied by construction (TM-2600).
5. Wire protocol (conceptual)
MP-250 The wire protocol is the network projection of the core's order/event model (03-architecture.md): order records flow up from client to authority; validated results flow down from authority to clients. Clients MUST never exchange raw game state peer-to-peer. What a client may legitimately receive and reconstruct depends on the game's authority mode (§6):
| Relay-only (incl. direct-LAN host and peers) | Authoritative (fog-enforced) | |
|---|---|---|
| What flows down | The canonical order log | Only the seat's compacted observation stream (TM-2150) and its own view deltas |
| What the client rebuilds | Full game state by replaying the log | Its own PlayerView only (AR-410, AR-420) |
| Fast-start object | A full-state snapshot (AR-650), derived from and SHA-256-verified against the log (AR-570) | An AR-500 ViewCheckpoint over that seat's filtered view — never full state, never the log |
| Who computes the Cascade | The designated host client (MP-195) | The server |
Authoritative-mode clients MUST NOT receive the canonical order log, RefereeView data, or
full-state snapshots under any circumstance, including fast start and reconnection (MP-290), even on
explicit request. Rationale: "snapshot" in 03-architecture.md's vocabulary (AR-650) is the complete
canonical state; serving one to a fog-enforced client would hand it every opponent's hidden position,
defeating MP-1120 information starvation and violating AR-410/AR-590.
MP-260 Transport: the primary transport MUST be WebSocket over TLS (browser-compatible), carrying
a versioned, length-delimited binary or JSON message envelope. LAN play uses the identical message
protocol over a local socket. All messages carry GameId, protocol version, and a monotonically
increasing per-game sequence number for downstream messages.
MP-265 Room framework and the state-transport boundary. The live server MAY be built on a room
framework (the binding stack selects Colyseus) for rooms, matchmaking, lobby presence, connection
lifecycle, and reconnection. Such a framework's automatic state-synchronization — mutate server-side
objects, ship computed binary deltas — MUST NOT be used as the transport for game state. Order
records travel up and validated results travel down (MP-250); every bulk payload a client
legitimately receives is the log tail, a full-state snapshot, an AR-500 ViewCheckpoint, or the
observation stream of MP-240, and never a framework-computed delta over server-held state. Framework
state sync MAY carry only ephemeral, non-authoritative data that can neither affect simulation nor
reveal fog-hidden state: connection status, commit markers and clocks (MP-186), and pre-launch lobby
chat (MP-465). In-game chat is not such data, and neither is the observation stream, the
activation-order hash, or any order record. Whatever the sync channel does carry is additionally
bound by 08-services-platform.md SVC-402: it MUST be reconstructible from the durable store and the
log, and losing all of it at once MUST cost nothing but a reconnect. Where such a framework supplies
its own message framing, that framing is part of the protocol surface MP-180 requires to be
documented and versioned.
Rationale: three independent reasons, each sufficient. (1) Replays, spectating, mode switching, resume, and desync detection all derive from the append-only log (MP-090); a second, snapshot-shaped state channel would make the log stop being the truth — the same argument 03-architecture.md AR-500 makes from the core's side. (2) Such frameworks synchronize server state, not a per-seat filtered view — adopting one for game state would hand a fog-enforced client the referee's copy and silently defeat MP-1120. (3) The observation stream must arrive as one payload at one moment (MP-245); a delta-sync channel pushes changes as they are computed, which is precisely the timing channel 10-turn-model.md TM-2170 exists to close.
MP-270 Message families (conceptual; exact schemas in the protocol reference, MP-180):
| Direction | Message | Purpose |
|---|---|---|
| up | Hello / Auth |
Protocol + core version negotiation (AR-920); account token, guest token, or LAN identity |
| up | JoinGame, ClaimSeat, LeaveGame |
Enter a game/lobby; bind a seat; leave (never destructive) |
| up | Resume(lastMsgSeq) |
Reconnect and request what was missed — the seat's own accepted order records and any completed observation stream in authoritative mode, the raw log tail in relay-only mode (MP-290) |
| up | SubmitOrders(turn, seat, orders[], clientBatchId) |
A transport batch of AR-260 order records, each carrying its own ClientTag; clientBatchId correlates the reply only (MP-280) |
| up | CommitOrders(turn, seat) / RevokeCommit(turn, seat) |
Mark the seat ready for this turn; withdraw that mark (MP-215) |
| up | ActivationOrderHash(turn, hash) |
This node's TM-2370 activation-order hash, sent by every node holding full state, before the Cascade (MP-247) |
| up | TurnHash(turn, hash) |
The reporting node's own AR-130 TurnHash for the Reckoning just closed. Sent by every connected node that legitimately holds full state — the relay-only host client, direct-LAN peers, and any client entitled to the whole log — per MP-1150. Fog-filtered authoritative-mode clients never send this: they hold no canonical state and instead compare the ViewHash carried on ViewCheckpoint |
| up | RequestCheckpoint (authoritative) / RequestSnapshot (relay-only) |
Ask for an AR-500 ViewCheckpoint of this seat's view; or, for a client already entitled to the whole log, a full-state snapshot. A RequestSnapshot from an authoritative-mode client MUST be answered with a ViewCheckpoint, never a snapshot (MP-250) |
| up | Chat, Ping, Concede |
Ancillary; Concede is an ordinary logged order (14-victory.md VC-320) |
| down | GameInfo |
Roster, mode, authority mode (§6) and how it was set (MP-905/MP-906), pinned versions/hashes including Initiative Tier (MP-110), policies, spectating rules |
| down | PhaseBegin(turn, phase) |
The game entered Orders, Cascade, or Reckoning (TM-090). The only phase notification; there is no per-seat turn begin |
| down | OrdersClosed(turn, commitMarkers[]) |
The phase closed, with each seat's terminal marker — Committed, TimedOut, Absent or Substituted (TM-300) |
| down | Observations(turn, events[]) |
The seat's complete compacted observation stream for the Cascade just computed, as one payload (MP-240, MP-245) |
| down | ViewCheckpoint / ViewDelta (AR-500) |
The seat's fog-filtered view: periodic full checkpoint of its PlayerView plus deltas, carrying the ViewHash of MP-1150 |
| down | OrderResults(clientBatchId, results[]) |
One result per submitted ClientTag: the assigned log Seq, a typed AR-320 rejection, or NotAttempted (MP-285) |
| down | ActivationOrderHash(turn, hash) / TurnHash(turn, hash) |
The authority's digests for comparison (§15, AR-530). TurnHash is AR-130's 64-bit XXH3, explicitly not the SHA-256 StateHash, which is reserved for snapshots and manifests |
| down | Presence, ChatRelay, Control |
Presence and clocks (MP-186); chat; substitution / host-migration / mode-switch / rollback notices |
MP-280 Idempotency is per order, not per batch. A SubmitOrders batch is a transport grouping
only: each element is an AR-260 order envelope carrying its own ClientTag, and resubmitting a
ClientTag already present in the log MUST return that order's original result without re-applying
it (AR-340). clientBatchId is transport correlation — it names the OrderResults reply and makes
whole-batch retry safe — and MUST NOT be used as the idempotency key.
MP-285 Batch outcome semantics: a batch is not atomic. The authority applies its orders in
array order, each one atomically, and MUST stop at the first rejection — orders before it are applied
and enter the log with their assigned Seq; the rejected order carries its typed AR-320 reason;
every order after it MUST NOT be applied and is reported NotAttempted. OrderResults returns
exactly one entry per submitted ClientTag so the client can reconcile without guessing.
Rationale: prefix application matches the incremental flow of MP-205 — a batch is only a network
optimization over records the player made one at a time, so a late rejection must neither undo
earlier accepted revisions nor let later ones apply against a state the player never saw. Because
order records are revisions of the player's own plan and not moves in a shared world, a partially
applied batch leaves a perfectly coherent Orders phase that the player can inspect and finish.
MP-290 Reconnection. What resuming means depends on the phase the game is in when the client returns:
- Mid-Orders — the common case, and the one correspondence play depends on. The client MUST
recover every order record it had accepted, identified by
ClientTag(MP-280), and MUST be able to continue editing and commit normally. Uncommitted client-side staging is client state and is restored by the client where it offers staging (10-turn-model.md TM-470; 04-ui-ux.md owns staging). Records whose results were never received MAY be resubmitted with no risk of double application. - Mid-Cascade or mid-Reckoning — there is nothing to resume, because neither phase takes input (TM-050). The client MUST wait and MUST receive the complete observation stream when the Cascade finishes, exactly as a connected client would (MP-245).
- Gap too large to ship as a tail — the mode decides the fast-start object (MP-250).
Authoritative: an AR-500
ViewCheckpointof that seat'sPlayerViewplus the subsequent deltas and any observation streams it missed. A reconnecting client MUST NOT be sent a full-state snapshot or any segment of the canonical log, even if it asks (AR-410, AR-590, MP-1120). Relay-only / direct LAN: a full-state snapshot (AR-650) plus the log tail, verified by SHA-256 against the manifest (AR-570) — permissible only because such clients are already entitled to the whole log.
Reconnect MUST be automatic. Disconnection MUST NOT commit a seat, MUST NOT clear its orders, and MUST NOT close a phase; a seat that never returns before the deadline is handled by §13.
MP-300 Validation: the authority MUST validate every order record against the pinned core's legality rules for the submitting seat before appending it (10-turn-model.md TM-250). Rejected records never enter the log. Clients SHOULD pre-validate locally against the same core so rejections are rare and instant — which they can do completely for their own orders, because an Orders phase mutates only per-player state (TM-350).
MP-310 Randomness: all random draws are made by the authority's core PRNG (03-architecture.md). Clients in authoritative mode never draw randomness; in relay/host mode only the host's core draws.
MP-320 Timing targets. Order-record acknowledgment SHOULD be ≤ 250 ms server-side processing at the 95th percentile in live games. The Cascade itself is bounded by 10-turn-model.md TM-2480 (200 ms for 1,200 activations). Observation-stream dispatch MUST begin within 100 ms of the Reckoning closing and MUST satisfy the simultaneity requirement of MP-1125. Correspondence games have no latency requirement beyond notification delivery (§12).
Rationale: latency stopped being a fairness question under this model and became purely a comfort question. There is no race to submit (MP-135), so a 300 ms connection costs a player nothing but the delay before their own edit is confirmed. The number that now matters is the one in MP-1125 — whether every player receives the turn's result at the same moment — because that is the only remaining place where a timing difference could mean anything.
MP-330 The protocol MUST carry no client-authored derived state: no computed combat results, no visibility claims, no initiative values, no activation indices. Everything a client asserts is either an order record, a digest for comparison (MP-247, MP-1150), or ancillary metadata.
6. Authority modes: relay-only vs authoritative
MP-340 Every server-connected game runs in exactly one authority mode at any instant, chosen at
creation or — for a game that enters a server mode by conversion from hot seat, turn-bundle, or
drop-box play — at that conversion (§11, MP-905). The mode in force MUST be carried in GameInfo and
shown to all joiners:
| Relay-only | Authoritative | |
|---|---|---|
| Who runs the Cascade and Reckoning | One designated client (the host) runs the full core; the server relays and stores | @everylastcity/server runs the headless core |
| Server sees | The canonical order log and metadata (needed for persistence, resume, mode switching); it does not interpret it | Full game state (it computes it) |
| Server cannot see | Nothing is hidden from the server unless E2E encryption is enabled (MP-370) | n/a |
| Fog enforcement | Client-side only; the host client necessarily holds full state — trust-based among friends | Server-side: each seat receives only its own observation stream (§15) |
| Randomness | Host's core PRNG | Server's core PRNG |
| Order validation | Host core validates; server checks only log integrity and sequencing | Server core validates every record |
| Eligible for rated play | No | Yes (08-services-platform.md) |
| Cost profile | Near-zero server compute | Server compute per game |
MP-350 Default: casual games default to relay-only; rated, tournament, and "fog-enforced" flagged games MUST be authoritative. The lobby MUST display the mode and its trust implications in plain language before players join.
MP-360 In relay-only mode the server MUST still: sequence and durably store the log; verify
hash-chain integrity (§15); collect and cross-check per-node ActivationOrderHash (MP-247) and
TurnHash (AR-130) values and flag mismatches; and support resume, mode switch and spectate from the
stored log.
MP-370 Optional E2E-encrypted relay: a relay-only game MAY be created with end-to-end encryption (participants hold the key; server stores ciphertext). This forfeits every server-side feature that reads the log — server-rendered spectating, AI substitution, web replay, and server-side deadline enforcement beyond a wall-clock timer — and the creation UI MUST state these trade-offs. If it ships, it ships behind a feature flag (open question 2).
MP-380 Correspondence games SHOULD default to authoritative mode: fog enforcement matters most when an Orders phase sits open on a server for days and no other player is watching. Relay-style correspondence (server stores; the host client validates and runs the Cascade on its next connection) MAY be offered for mod content the server cannot execute, and MUST be labelled as unenforced.
7. Hot seat
MP-390 A game with two or more local-human seats on one device is a hot seat game. It MUST work
fully offline with no account; each local seat MAY be bound to a local profile (for options, keybinds
and stats) or played as an unnamed guest seat.
MP-400 Occlusion hand-off: between local humans' Orders phases the client MUST display a neutral hand-off screen showing the next player's name and colours, with the map and all reports hidden, requiring explicit confirmation ("I am <name>") before revealing that seat's fog-filtered view (10-turn-model.md TM-460). Design decision: blanking is mandatory and not configurable. A shared screen is the one place where fog has no technical enforcement at all, and the cost of the rule is one keypress per hand-off against the certainty that an accidental glance cannot happen. There is no case in which a player benefits from the option to skip it.
MP-410 Optional per-profile PIN: a local profile MAY set a PIN required at its hand-off. Default off.
MP-420 Everything rendered between hand-off confirmations MUST be restricted to the active seat's fog-filtered view and its own observation stream — including reports, graphs, chat, the Dispatch (13-command.md), and combat detail. In particular the client MUST NOT render, for the seat currently at the machine, any part of another seat's observation stream from the previous Cascade.
MP-430 Playback in hot seat: the Cascade playback belongs to no single seat, so the client MUST either play it once per seat behind the occlusion screen, each seat seeing only its own stream, or offer a combined post-Cascade summary restricted to the union of nothing — that is, no combined view at all. A single shared playback MUST NOT be offered in a game with two or more human seats.
Rationale: this is the one genuinely new problem the turn model creates for hot seat, and it needs saying rather than discovering. Under sequential turns each player watched their own turn and there was nothing to share. Now a single Cascade produces a different, incompatible truth for each seat, and the tempting shortcut — show everyone the whole thing on the shared screen — is a total fog collapse. Per-seat playback behind the occlusion screen costs a few seconds per turn and preserves the game.
MP-435 A hot seat game MUST be switchable to any other mode and vice versa (§11). A hot seat game on a device with a signed-in account MAY be uploaded to become a correspondence game, with the other local seats invited out to remote players.
8. Live play (Internet and LAN)
8.1 Session topologies
MP-440 Live play MUST support two topologies with the same protocol (§5):
(a) Server-relayed: all clients connect to an @everylastcity/server instance (official or
self-hosted); no player opens ports; the server is relay-only or authoritative per §6.
(b) Direct LAN: one client hosts on the local network; peers connect directly; the host is the
authority (relay-only semantics). Hosting in (b) requires a client build that can open a listening
socket — the desktop and mobile builds. A browser-tab client MAY join a direct-LAN game but MUST NOT
be required to host one, and the UI MUST NOT offer hosting on a build that cannot. Rationale: (a)
removes port forwarding and external-IP configuration, which is the single largest source of failure
in player-hosted networking. (b) preserves infrastructure-free play (MP-080). The hosting caveat is a
platform capability limit, not a rules or mode limit: a browser-tab participant plays the identical
game over the identical protocol.
MP-450 Direct hosting over the open Internet MUST remain possible for users who want it (manual
host:port entry, MP-500), but is never required and never the default.
8.2 Lobbies, invites, discovery
MP-460 Creating a live game opens a lobby: the creator configures setup (owned by 04-ui-ux.md and 01-game-rules.md), and the lobby displays the roster, pinned content, rules summary, Initiative Tier, deadline and reserve defaults (§13), authority mode, and policies. The creator holds the lobby admin role: assigning joiners to seats, reordering seats, setting AI seats, kicking, and launching.
MP-465 Lobby chat is a distinct, deliberately expendable capability: a lobby MUST provide a text
channel among its current occupants before launch, for arranging setup, seats, and start time. It is
not in-game chat (MP-185): it is not part of the game record, never enters the order log, and is
not retained past launch, so it MAY be carried on a room framework's ephemeral state-sync channel
(MP-265; 08-services-platform.md SVC-402). At Launch Game (MP-520) — or, for a correspondence game
created under these lobby semantics, at the deferred start of MP-660 — the lobby channel closes and
all further conversation is in-game chat over the MP-270 Chat / ChatRelay messages. The client
MUST make the distinction visible, so no player assumes a pre-launch message is preserved in the game
record.
MP-470 Private lobbies are joined by invite link or short join code, generated automatically and never empty. The admin MAY regenerate the code at any time.
MP-480 Public listing: the admin MAY list the lobby publicly under a game name. The listing MUST show name, ruleset, unit set, map size, seats free, deadline preset, authority mode, and host region, and MUST NOT expose the join code. A listed lobby MAY additionally be marked open (join without code).
MP-490 LAN discovery: client builds with access to link-local discovery — the desktop and mobile builds — MUST discover LAN lobbies on the same network automatically (mDNS/UDP broadcast). A browser-tab client has no access to mDNS or UDP broadcast and MUST fall back to manual connection (MP-500) or an invite link; the absence of discovery MUST be stated in the UI rather than presented as an empty lobby list.
MP-500 Manual connection: entering host:port (or an invite URL) directly MUST always work, for
VPNs, airgapped LANs, and direct Internet hosting (MP-450). A browser-tab client served over HTTPS
cannot open a plaintext ws:// connection to a LAN host, which constrains the supported LAN path for
that build (open question 8).
MP-510 Friends/invites: with an account, players MAY invite friends directly; invitees receive a push notification deep-linking into the lobby (08-services-platform.md).
8.3 Launch
MP-520 Launch requires every seat resolved: each human seat bound to a present, connected player
and each remaining seat set to AI or removed. The admin's Launch Game starts the game; map
generation (if procedural) occurs at launch on the authority; turn 1's Orders phase opens once every
starting unit has a complete order stack (10-turn-model.md TM-070).
MP-530 The admin need not occupy a playing seat; an adminless-seat game is the dedicated-server case.
MP-540 Seat assignment is by the admin or automatic. There MUST be no requirement that the host occupy any particular player index. Rationale: under this turn model the player index is a tie-break input to nothing a player can feel — activation order is Initiative with a creation-sequence tiebreak (TM-1150), not player order — so index carries no advantage and no rule may give it one.
8.4 Join, leave, and absence during play
MP-550 After launch, clients MAY disconnect and reconnect freely without affecting other players (MP-290). A disconnected seat does not stop the game: its persisted orders execute (10-turn-model.md TM-530, TM-610), the Orders phase closes on the deadline and reserve schedule of §13, and the Cascade runs. All connected clients MUST see which seats have not committed and how long remains (MP-186).
Rationale: this is the requirement that most visibly improves under the new model. Under sequential turns, an absent player froze the game at their seat and every other player sat and waited; the old draft's answer was "the game waits at that seat's turn". Now an absent player's army continues a coherent plan and the turn resolves on schedule. Absence degraded from a stall into a disadvantage borne by the absent player alone.
MP-560 Leaving is uniform and safe: a single "Leave game" action disconnects with no ceremony — the game state lives with the authority.
8.5 Resume and host migration
MP-570 Server-relayed games: resuming requires no clients present — any participant reopens the game from their game list; the server restores the session and notifies the roster. A correspondence game does not need resuming at all, because it was never suspended (MP-615).
MP-580 Server-relayed relay-only games: if the designated host client disconnects, the server
MUST migrate the host (authority) role to the next connected client by player index within 10
seconds, resuming from the canonical log; if none is connected, the game holds at the current phase
boundary and resumes when any participant returns. Migration MUST be announced via Control, MUST
occur only at a phase boundary, and MUST NOT be performed mid-Cascade or mid-Reckoning
(10-turn-model.md TM-620). No order record, digest, or PRNG state may be lost or replayed
differently.
MP-590 Direct LAN games: the canonical log lives on the host, and every client MUST retain its
received log prefix. Any machine holding the full log MAY restart the game as the new host: it opens
the game from its saved log, re-hosts, and other clients rejoin by discovery or address. Design
decision for a host lost mid-turn: the game resumes from the last completed Reckoning boundary
present on the recovering machine, with an explicit on-screen statement of which turn was lost, and
every seat's order records for the abandoned Orders phase are discarded rather than partially
replayed. A phase is not a resumable unit; a turn is. Rationale: an Orders phase is only meaningful
as a complete set of commitments closed by one CloseOrders, and replaying a fragment of one would
produce a turn nobody submitted. Rewinding one turn is a small, comprehensible loss; a
half-reconstructed turn is an incomprehensible one.
MP-600 A resumed live game MAY be resumed into a different mode instead (§11). The intended hybrid is explicit: play live for the first session, then continue as correspondence when people disperse, with no interruption to the game and no requirement that any particular seat be the one to convert it (MP-930).
9. Correspondence play
9.1 Model
MP-610 A correspondence game lives on an @everylastcity/server instance. The server holds the
log, opens each Orders phase, accepts each seat's order records whenever that player connects, closes
the phase when every seat has committed or the deadline and reserve schedule expires (§13), runs the
Cascade and the Reckoning, delivers every seat its observation stream (MP-240), opens the next Orders
phase, and notifies everyone (§12). There are no user-visible files, directories, position numbers,
mail settings, or polling screens.
MP-615 Correspondence play MUST NOT depend on a live session. The authority for a correspondence game is the durable service and its persisted log (MP-160); a live room, if the deployment uses one (MP-265), is materialized only while a participant is connected and disposed when the last one leaves — an event that MUST NOT end, pause, stall, or otherwise alter the game. Every correspondence operation MUST be performable with no room in existence and no other participant online: claiming a seat (MP-650); submitting order records and committing (MP-205, MP-215); closing the Orders phase, running the Cascade and the Reckoning, and dispatching every seat's observation stream (MP-220, MP-240); deadline and reserve expiry (§13, MP-1000); rollback (MP-740); and archival and revival (MP-720). No obligation of §12 or §13, and no phase transition, may be implemented as behaviour of a room object.
Rationale: rooms in the chosen framework are ephemeral and in-memory, while correspondence play is a primary mode with a design lifetime of months to years (MP-630). Binding a years-long game to a process-lifetime object would be an availability regression against plain file passing, where the turn outlives every machine that touches it. The Cascade is explicitly on this list because it is the one operation that must run for a game nobody is watching: the deadline expires at 03:00 and the turn resolves, or correspondence play does not work.
MP-620 A correspondence Orders phase MUST support multi-sitting work: the player connects from any device, revises some orders, leaves, returns, revises more, and commits when ready. Accepted records persist server-side across sittings (MP-290); uncommitted client staging is restored per device where the client offers it (10-turn-model.md TM-470).
MP-625 One submission per player per turn. A correspondence turn MUST cost each player exactly one round-trip — open the game, issue orders against a stable board, commit — regardless of how many units they own, and MUST NOT require any further exchange before the turn resolves.
Rationale: this is the property that made the turn model worth adopting and it belongs in the transport document as a requirement, not as an emergent hope. Under interactive per-unit activation a correspondence turn needs one round-trip per unit activation: six players with thirty units each is 180 sequential round-trips, potentially hours apart, which is not a slow game but a broken one. Under Orders and the Cascade the count is one per player per turn and it does not grow with army size — a player with 200 units submits once, exactly as a player with 20 does. Everything else in this section is bookkeeping around that single fact.
MP-630 Correspondence games are long-lived: the design lifetime is months to years. Server retention policy MUST NOT silently destroy games (MP-720).
9.2 Creation and joining
MP-640 Creation: any account holder creates the game (setup per §8.2 lobby semantics, minus live presence), marks human seats as invited (by account, contact link, or open code), and publishes it. The creator need not hold any particular player index (MP-540).
MP-650 Joining: invitees receive a link or code; opening it shows the game summary and lets them claim their designated seat (or pick a free seat if the invite is open). Seat claiming MUST be server-transacted, so a mistyped identifier cannot corrupt the roster.
MP-660 Deferred start: by default the game starts — map generated, turn 1's Orders phase opened — when all human seats are claimed. The creator MAY alternatively start immediately with unclaimed seats held by stand-in AI until claimed. All claimants MUST be notified at start.
9.3 Running the game
MP-670 Phase advance: when the last seat commits, or the deadline and reserve schedule expires
(§13), the server MUST issue CloseOrders, run the Cascade and the Reckoning, dispatch every seat's
observation stream under MP-245, open the next Orders phase, and notify every player — not only some
next player, because there is no next player.
MP-680 The player's game list MUST show, for every correspondence game: the turn number; whether you have committed; how many seats have committed out of how many; the deadline remaining and your reserve bank remaining; whether a Cascade result is waiting to be watched; and unread chat. An "open my next game awaiting orders" action MUST cycle the player through games where they have not yet committed.
Rationale: the old game list answered "is it my turn?", which was the only question sequential play allowed. The question now is "have I committed?", and it has a different shape: it is never exclusive, several games can want you at once, and the answer for a game you have committed to is "nothing, relax" rather than "wait for six other people in order".
MP-690 Multiple local humans MAY share one device within a correspondence game: each claims their seat from that device, and the occlusion hand-off of §7 applies between them.
MP-700 The server transactionally owns phase state and possession. There MUST be no user-visible retry, hold, re-upload, or registry-repair mechanism of any kind, and no user action may leave a game in a state requiring manual repair. A client crash mid-Orders loses at most unacknowledged order records (MP-290).
MP-710 Contact changes: a player changing accounts or notification addresses updates their own account (08-services-platform.md); a game admin MAY re-issue an invite to rebind an unclaimed or abandoned seat.
9.4 Retention
MP-720 Inactivity: a fully stalled correspondence game (no orders from anyone) is nudged per §12, then after a server-configurable dormancy period (default 180 days, minimum 90) archived — frozen, delisted from active lists, but retained and revivable by any participant with one action. Hard deletion only per the instance's data-retention policy (08-services-platform.md). A game MUST NEVER be destroyed by timeout.
MP-730 Personal backups, scoped by authority mode (§6). What a participant may export from a live game is bounded by what that participant is already entitled to hold:
- Games without fog enforcement (relay-only, bundle, drop-box, hot seat): every participant MAY at any time export the game as a turn-bundle (§10) or replay file. This adds no exposure — such participants already hold the full log by construction (MP-250, MP-790).
- Authoritative fog-enforced games (the MP-380 correspondence default): a participant's mid-game export MUST be limited to their own fog-filtered view cache — the AR-590 client artifact of view checkpoints, deltas and past observation streams for their seat. It restores that player's own view on a new device and is useless for continuing the game alone. A full bundle or replay of a live fog-enforced game MUST NOT be offered to any participant.
A participant obtains the full container of a fog-enforced game only (a) after the game ends, via the replay of MP-1100, or (b) through a consent-gated mode switch out of authoritative fog-enforced mode — server → bundle (MP-920), server → hot seat (MP-940), or any other such switch, all governed by the gate in MP-900 — which requires all active human participants' consent precisely because it relocates full state onto a player device. No notification-only or admin-unilateral path to that switch exists. Operator-side export is a separate right (MP-1230) and MUST NOT be exposed as a per-participant path around this rule.
9.5 Rollback as an audited admin action
MP-740 The server retains full turn history, so rollback is: the game admin proposes a rollback to
a named prior point — any Reckoning boundary, never a point inside a phase — all active human
participants are notified and MUST consent (default), or the game's pre-agreed policy allows
admin-only rollback (declared at creation); on execution the log is truncated to that boundary, a
RollbackExecuted record with actor, timestamp and reason is appended to the audit log
(03-architecture.md AR-563), and all clients resync. Rollbacks MUST be visible forever in the game's
history view.
Rationale: the boundary restriction is new and it is forced by the model. A turn's outcome is a pure
function of the state at CloseOrders and the records of that phase, so a rollback to any point
inside an Orders phase would truncate a set of commitments into a set nobody submitted, and replaying
forward from it would produce a Cascade that never happened. Reckoning boundaries are the only points
at which the log describes a state that actually existed.
10. Turn-bundle mode (signed file play)
10.1 Purpose and format
MP-750 A turn bundle is a single portable file containing everything needed to continue a game:
header (GameId, core/protocol versions, content hashes, seat roster with public keys, bundle
sequence number, lifecycle phase), the initial state, the full order log, chat history, and a
signature chain (03-architecture.md AR-565, AR-567). It preserves infrastructure-free play (MP-080)
for airgapped, forum and file-passing players.
MP-755 An order packet is the small companion file this mode needs under a concurrent Orders
phase: one seat's order records for exactly one turn, plus that seat's CommitOrders, signed by that
seat's key and naming the GameId, the turn number, and the bundleSeq of the turn-opening bundle it
answers. A packet MUST NOT contain game state, MUST NOT be applicable to any other turn, and MUST be
rejected if its bundleSeq does not match the open turn.
MP-760 Container: the bundle uses the documented save/replay container of 03-architecture.md,
compressed, with extension .elcturn; order packets use the same container framing with extension
.elcorders. Both formats MUST be fully documented (MP-180).
MP-770 Integrity and identity: each seat owns a keypair generated automatically at seat claim (invisible to the user; exportable for multi-device use). Every bundle hand-off and every order packet carries the sender's signature (AR-565). A tampered log, a forged hand-off, or a packet signed by a seat that does not own it MUST fail verification on import.
MP-780 Privacy: a bundle MAY additionally be encrypted with a game passphrase agreed out-of-band (for posting on public forums). Encryption is optional; signatures are not.
MP-790 Fog in bundle mode is trust-based: the file necessarily contains full game state, and a determined participant can extract hidden information. The client MUST still render only the importing seat's fog-filtered view and its own observation stream, and the UI MUST label bundle games "friendly trust level: fog is not cryptographically enforced". Rated play in bundle mode is prohibited (MP-350). The closer's additional sight (MP-845) is a disclosed part of this trust level, not an exception to it.
10.2 Creating and bootstrapping
MP-800 Creation: the organizer configures setup with human seats marked bundle-human,
optionally claims their own seat, and exports the initial bundle in the sign-in profile
(03-architecture.md AR-567). While seats remain unclaimed the game is in sign-in state: the bundle
circulates, each recipient imports it, claims a seat (name + auto-generated key), and re-exports for
the next player. When the last seat is claimed, the completing machine materializes the initial state
deterministically from the recorded seed and provenance, and turn 1's Orders phase opens.
MP-810 Bootstrap shortcut: if the organizer already holds every participant's public key (prior games, or key exchange via a server), they MAY pre-authorize all seats and export a ready-to-play bundle, skipping the round-robin — the sign-in cycle exists for key establishment, not ceremony.
10.3 Importing and playing
MP-820 Import: opening a bundle or packet (file association, drag-drop, or in-game "Import") verifies signatures, hashes and content availability (MP-120), then places or updates the game in the player's game list. There are no watched directories to pre-create; imported files are copied into managed storage and the source is left untouched.
MP-830 Any seat whose key is present on the importing device MAY issue order records for the open Orders phase and export an order packet for it. Only the turn's closer MAY close the phase and run the Cascade (MP-845). The client MUST refuse to produce a packet for a seat whose key it does not hold, and MUST refuse to close a turn for which this device is not the closer.
10.4 The turn cycle
MP-840 A bundle turn MUST proceed in exactly three steps:
- Open. The turn's closer exports a turn-opening bundle at the current Reckoning boundary and distributes it to every seat by any channel — a single broadcast, not a chain. It carries the closer's own sealed order packet and the commitment of MP-845.
- Order. Every other seat imports it, plays a full Orders phase offline against the stable board (10-turn-model.md TM-340), and returns a signed order packet (MP-755) to the closer. Seats work in parallel; no seat waits on any other, and no seat sees any other's packet.
- Close. When the closer holds a packet from every seat — or the game's soft deadline expires
(MP-1040) — the closer appends every packet to the log in ascending player index, appends
TurnTimeoutfor any missing seat, appendsCloseOrders, runs the Cascade and the Reckoning, and exports the turn-closing bundle, which is also the next turn's opening bundle if the closer role has not rotated.
MP-845 The closer is a per-turn role, MUST rotate to the next player index at each Reckoning (skipping seats that are not live), and MUST be recorded in the bundle header. Because the closer holds every other seat's packet before the Cascade runs, the closer MUST commit first: the turn-opening bundle MUST carry the closer's own order packet encrypted under a key the closer withholds, together with a hash commitment over the plaintext packet, and the closer MUST publish the key only in the turn-closing bundle. Every client MUST verify, on importing a turn-closing bundle, that the revealed packet matches the commitment, and MUST refuse the bundle and raise a tamper warning if it does not.
Rationale: this is the one place in the design where the concurrent Orders phase collides with a transport that has no simultaneous channel, and it deserves a real answer rather than a shrug at "friendly trust". The commitment costs one hash and one symmetric key, is verified automatically, and makes the closer's unavoidable early sight worthless — their own orders were fixed before anyone else's existed. Rotation keeps even that structural position from settling on one player. What remains is that a dishonest closer can stall or refuse to close, which is a social failure a file game cannot prevent and does not need to: any other seat can be made closer by agreement, and the whole mode is labelled friendly-trust (MP-790) for exactly this reason.
MP-847 The bundle mode's turn therefore costs one broadcast plus one packet per player, independent of army size, and every player's thinking happens in parallel. Rationale: this is the same one-submission-per-player-per-turn property as MP-625, achieved without any server at all, and it is a direct consequence of the Orders phase being stable and identical for everyone (TM-030, TM-2050). Under sequential turns a file game required a serial chain of N hand-offs per turn, each carrying a full interactive turn's thinking, with every player idle until the file reached them; the concurrent phase turns that chain into a fan-out and a fan-in.
MP-850 After sending its packet a seat enters committed, awaiting close state: it MUST NOT be
able to revise that turn's orders, and the client MUST say so plainly. "Re-send my packet" MUST
remain available for a lost transmission, and re-sending an identical packet MUST be idempotent at
the closer by ClientTag (MP-280).
10.5 Recovery and rollback
MP-860 Rollback by agreement: any participant MAY export a bundle from an earlier Reckoning
boundary of their retained history (MP-740's boundary restriction applies identically). Importing a
bundle whose sequence number is ≤ one already seen for that GameId MUST warn loudly ("this rewinds
the game to turn N; agreed with all players?") and record the divergence locally.
MP-870 Lost transmission: if a turn-opening or turn-closing bundle never arrives, the sender re-exports it. Bundles and packets are plain files and may be re-sent freely; there is no single-download constraint.
10.6 Relay drop-box (optional bridge)
MP-880 An @everylastcity/server instance MAY offer a drop-box for bundle games: participants
upload and download bundles and order packets by GameId, with server-tracked phase state and
notifications, while the game formally remains a bundle game (signatures, trust level, no server
simulation). A drop-box collapses the fan-out and fan-in of MP-840 into ordinary correspondence
ergonomics — each player submits once, whenever they like — without any server-side fog claim, and
one action converts such a game to full correspondence play (§11).
11. Switching a game between modes
MP-890 Any game MUST be convertible between hot seat, live, correspondence and turn-bundle modes, in any direction, any number of times. A switch rebinds seat transports (MP-020) and changes the authority; it MUST NOT touch game state, the log, the seed, or pinned versions (MP-060).
MP-900 Who may switch: the game admin in server modes, or the current closer in bundle mode, with
notification to all humans. Switches append a ModeSwitch record to the audit log
(03-architecture.md AR-563).
Notification alone suffices only for a switch that does not relocate full state onto a player
device. A switch that takes a live game out of authoritative fog-enforced mode — to turn-bundle
(MP-920), hot seat (MP-940), drop-box (MP-880), or relay-only, whose designated host client
necessarily holds full state (MP-340) — MUST additionally obtain the consent of all active human
participants before it executes, and MUST NOT be performable unilaterally by the admin or by any
other single participant. Consenting participants and any refusal MUST be recorded in the
ModeSwitch record and surfaced in the game's history view. Rationale: MP-730 permits a participant
to obtain the full container of a live fog-enforced game only through a consent-gated switch; a
notification-only admin path out of authoritative mode would reopen from the other end exactly the
leak MP-730 closes.
MP-903 A mode switch MUST take effect only at a Reckoning boundary, between the close of one turn and the opening of the next Orders phase. A switch proposed mid-Orders MUST be queued and applied at the next boundary, and a switch MUST NOT be applied during a Cascade or a Reckoning (10-turn-model.md TM-620). Rationale: a mode switch changes which node is the authority, and the authority is the node that closes the phase and runs the Cascade. Switching mid-phase would leave a set of order records addressed to a node that is no longer entitled to sequence them.
MP-905 Authority mode on conversion: a game entering a server mode by conversion — hot seat
uploaded to correspondence (MP-435), a drop-box bundle game converted (MP-880), or any later
re-switch (MP-890) — never chose an authority mode at creation, so the converting party (MP-900) MUST
select relay-only or authoritative as an explicit part of the switch. The selected mode MUST appear
in the ModeSwitch notice and in GameInfo (MP-340), and the switch UI MUST show the same trust
implications required of the lobby by MP-350. Absent an explicit choice the converted game MUST
default to relay-only. Rationale: authoritative is the stronger trust claim; defaulting to it
silently would advertise enforcement the game's own history cannot support.
The authority-mode choice MUST NOT be used to route around MP-900's consent gate. Selecting or defaulting to relay-only for a game that is currently authoritative and fog-enforced hands full state to the designated host client (MP-340) and is therefore itself a switch out of fog enforcement: it requires the consent of all active human participants exactly as a switch to bundle or hot seat does. The relay-only default above applies only where nothing is being taken away — a game that was never fog-enforced, or one already outside authoritative mode at the moment of the switch.
MP-906 Fog enforcement is never retroactive. When a game becomes authoritative after any phase in
which participants held full state — hot seat, turn-bundle, drop-box, or relay-only — the client MUST
state plainly, at the switch and in GameInfo, that every device that previously held the full
container (AR-590) still holds all opponents' history up to the switch point, and that enforcement
applies only from that point forward. Such a game MUST be permanently flagged
fog-enforced-from-turn-N and MUST remain ineligible for rated play (MP-1160), which requires
authoritative mode for a game's entire life.
MP-910 There MUST be no minimum-turns gate on switching: switching is legal from turn 1, subject only to the boundary restriction of MP-903.
MP-920 Correspondence → bundle: exporting a correspondence game to bundle mode suspends the
server copy (authority moves to the file); re-uploading the latest bundle (sequence-checked) resumes
it as a server game under the same GameId. Uploading a stale bundle follows rollback consent
(MP-740).
Consent gate: where the correspondence game is authoritative and fog-enforced, the export MUST NOT
proceed without the consent of all active human participants (MP-900), because the bundle is by
construction a full container (MP-750) and hands every participant who receives it all opponents'
hidden history. The consent prompt MUST state that fog enforcement ends at the switch and trust drops
to the friendly bundle level (MP-790), and consent MUST be recorded in the ModeSwitch record. A
correspondence game that is not fog-enforced needs no consent for this switch: it adds no exposure
(MP-730).
MP-930 Live ↔ correspondence on a server is a pure scheduling change — the same server, the same log, the same phases, and only the deadline configuration differs (§13). It MUST be achievable as a single admin toggle in both directions, applied at the next Reckoning boundary (MP-903).
Rationale: under this model the distinction between live and correspondence play is nothing but the value of one deadline. That is a real simplification and it is worth stating: the same game, the same protocol messages, and the same code path serve a ten-minute deadline and a forty-eight-hour one.
MP-940 Hot seat ↔ server modes: uploading binds local seats to accounts and invites (MP-435); downloading a server game for hot seat requires all active human participants' consent per MP-900, because full state will reside on one device and fog trust drops to the friendly level (MP-790).
12. Notifications
MP-950 When an Orders phase opens in a game a player is in, the service MUST notify them via their enabled channels: mobile/desktop push, in-client badge, and opt-in email with a deep link that opens directly into that game's Orders phase (channel infrastructure per 08-services-platform.md).
MP-960 Notification events MUST include: an Orders phase opened; your turn's result is ready to watch; deadline warnings at configurable fractions (default 50% and 90% elapsed); your reserve bank began drawing down; you were timed out; you were substituted or restored; a Verdict offer is open and closes in N turns (14-victory.md VC-2780); game started; you were invited; rollback or mode switch executed; game revived from archive; chat mentions (opt-in); game ended, with result.
Rationale: the notification set changed shape with the model. "It is your turn" was previously an exclusive, sequential fact about one player; the equivalent now — "an Orders phase is open" — goes to everyone at once and stops being urgent, so the urgency moved to the two facts that are genuinely time-bounded: the deadline and the reserve bank. Notifying a player that their reserve has started to drain is the single most useful message this system sends, because it is the only one that reports an irreversible cost accruing right now.
MP-970 Per-player controls MUST include: per-game mute, global quiet hours, digest batching ("one summary for my 12 games"), and channel selection. Channel defaults are owned by 08-services-platform.md SVC-530 and are not restated divergently here: phase-open → push + desktop, with email fallback only if the seat has not committed for 24 h; invites → push + email; security email always (SVC-180) and exempt from unsubscribe (SVC-540). Where this document and SVC-530 disagree about defaults, SVC-530 governs.
MP-980 Self-hosted instances MUST support notifications without proprietary dependencies: standard Web Push and SMTP relay configuration at minimum (§16); clients MUST fall back to polling their game list when push is unavailable.
13. Deadlines, absence, and substitution
MP-990 Every server-hosted game carries a stall policy, chosen at creation, displayed to all joiners, and changeable mid-game only with the consent of all active humans. The rules of deadlines, the reserve bank, and their consequences are owned by 10-turn-model.md §5; this table is the configuration surface and its defaults defer to TM-490:
| Policy element | Options (defaults bold) |
|---|---|
| Orders deadline | per TM-490 for the game's shape — None for solo, two-player and hot seat; 600 s live 3+; 90 s blitz; 172800 s (48 h) correspondence; or any custom whole-second value, or None |
| Reserve bank per player per game | per TM-490 — 1800 s live, 300 s blitz, 432000 s (5 days) correspondence; custom permitted; never refills (TM-510) |
| On reserve exhaustion | TurnTimeout and close (TM-520). There is no other option: persisted orders execute and the turn resolves |
| Escalation | after 3 consecutive missed turns (TM-570), AI substitute — by vote in casual play, automatically in rated play (TM-580) |
| Vacation | per-player pool of days/year (default 30) that suspends that player's deadline; announced to the game |
| Admin rollback without unanimous consent | off / on (MP-740) |
MP-995 The host MUST perform all deadline, reserve and vacation arithmetic outside the simulation
core, and MUST reach the core only through the TurnTimeout and CloseOrders records
(10-turn-model.md TM-190, TM-550). No wall-clock value may enter the core by any path, and a replay
MUST reproduce the turn from those two records alone without consulting any clock (TM-2430).
MP-1000 Timeout resolution. When a seat's reserve reaches zero without a CommitOrders, the
authority MUST issue TurnTimeout for that seat and proceed to CloseOrders (TM-520). The seat's
units then execute their persisted order stacks and Stances normally (TM-530), automated units
resolve normally, units with no Posture adopt their Fallback Posture for that turn only, and Dispatch
items persist to the player's next session rather than being consumed (13-command.md CM-2010,
CM-2020). There MUST be no rules-visible penalty for a timeout — no forfeited movement, no production
penalty, no initiative penalty (TM-540). Host-issued records MUST carry Issuer = Authority(AutoTurn)
per 03-architecture.md AR-260 so the log records who generated them, and the seat's commit marker in
the turn record MUST be TimedOut (TM-300). A timed-out turn MUST be visible to every player through
the commit markers of OrdersClosed.
Rationale: the previous draft specified an elaborate auto-turn resolver that had to decide, on the absent player's behalf, what unordered units should do and what unspent resources should become. None of that machinery survives, and its disappearance is the clearest single illustration of what the turn model bought. Orders persist (TM-280), so an absent player's army is not idle — it is executing the plan its owner last wrote, including every conditional in it. There is nothing left for a resolver to invent, and "the absent player's army continues its campaign" is a far better failure mode than "the absent player's army stands still".
MP-1010 AI substitution: a substituting seat uses an AI configured at creation (default per
06-ai.md) running under the authority — server-side in correspondence and server-authoritative games
(06-ai.md AI-480), on the host client in relay-only games. Substitution MUST take effect only at a
turn boundary, MUST be recorded as a SubstitutePlayer order, and MUST NOT alter any unit's order
stack (10-turn-model.md TM-590): the AI takes over the position's existing orders. A substituted
player MUST be able to reclaim their seat on reconnection, recorded as ResumePlayer and taking
effect at the next turn boundary, with their Dispatch items intact (TM-600, CM-2010). The substitute
MUST receive only that seat's fog-filtered view (06-ai.md AI-490) and MUST commit within the same
Orders phase as any human seat, with no extra time, information, or order kinds (TM-410). Tenure MUST
continue to accrue for a substituted seat (14-victory.md VC-3060, VC-3070).
MP-1020 Seat replacement: an opened seat is offered by invite link; a replacement human inherits the seat (player index, forces, colours) but not the predecessor's account stats. Rated games MUST record the substitution for rating integrity (08-services-platform.md SVC-648).
MP-1030 Live absence is not a special case: a disconnected seat in a live game is handled by exactly the schedule above at the live deadline defaults, and its units execute persisted orders (MP-550). No live game may stop for an absent seat.
MP-1040 Bundle games have no enforceable timers. The closer MAY apply a soft deadline: after
an agreed interval, close the turn with TurnTimeout for any seat whose packet has not arrived
(MP-840 step 3). The client MAY show local reminders. The drop-box bridge (MP-880) applies reminder
notifications only.
14. Spectating and replay
MP-1050 Spectating derives from the log: a spectator is a read-only subscriber to a stream built by the same observation rules as a player's (10-turn-model.md TM-2300). Per-game spectating policy is set at creation and changeable by the admin: disabled (default for private games), invited spectators, link-holders, or public.
MP-1055 A live spectator's stream MUST be built and transmitted under the same rules as a player's: compacted (TM-2150), free of activation indices and per-event timestamps (TM-2160), and delivered as a single payload after the Cascade completes (TM-2170, MP-245). Rationale: a spectator receiving events incrementally is a timing oracle for anyone in contact with them, which is precisely the channel TM-2170 closes for players. A spectator stream that leaks it would make the player-side protection worthless in any game with an audience.
MP-1060 Spectator view scopes: (a) omniscient — full map, available only when all active humans consent or the game has ended; (b) seat POV — one player's observation stream, requiring that player's consent; (c) delayed — omniscient or POV delayed by N turns (default 1) to blunt live coaching. Rated and tournament games SHOULD default to delayed omniscient.
MP-1070 Enforcement: in authoritative mode the server constructs the spectator stream server-side. In relay-only and bundle games, live spectating beyond seat-POV-with-consent MUST be unavailable (the data to filter trustworthily does not exist server-side); post-game replay is always available.
MP-1080 Detail withheld from players MUST be withheld from live spectators: a live spectator stream MUST NOT carry anything 10-turn-model.md TM-2120 denies a player — events in unobserved tiles, activation indices, roster size, any unit's orders or condition — nor exact enemy initiative beyond the coarse band of TM-1100, nor any Contact detail above the fidelity grade the viewed seat holds (01-game-rules.md GR-1260). Full detail unlocks for participants and spectators only after the game ends (MP-1100).
MP-1090 Players who have left the game (14-victory.md VC-080) become eligible spectators per MP-150; the admin MAY restrict them to a delayed view to prevent intelligence reaching remaining players.
MP-1100 Replay: any participant MAY export, and the server MUST retain, a full replay (initial state + log) of every finished game, viewable in the client with free camera, per-seat observation stream toggle, step-through of any Cascade, and full detail. A replay MUST reproduce every Cascade, every Reckoning, every hash and every player's observation stream bit-identically (10-turn-model.md TM-2410), MUST NOT invoke AI code (TM-2420, 06-ai.md AI-350), and MUST NOT consult any clock, deadline or reserve bank (TM-2430). Replays double as the bug-report artifact.
15. Fog enforcement, integrity, and anti-cheat
MP-1110 Threat model: clients are never trusted. Anti-cheat rests on (a) server authority and information starvation, (b) determinism and auditability, (c) log integrity — never on client-side scanning or kernel components (none SHALL exist).
MP-1120 Information starvation (authoritative mode). The server MUST send each client only:
- during an Orders phase, nothing about the game world — presence and chat only (MP-200);
- during the Cascade and the Reckoning, nothing at all;
- after the Reckoning, exactly one compacted observation stream for that seat (MP-240): the ordered list of events that seat observed under 10-turn-model.md TM-2100 and TM-2110, and nothing else. The stream MUST NOT contain gaps, placeholders, activation indices, per-event timestamps, or any field whose value varies with unobserved activity (TM-2160).
Content within the stream MUST honour every disclosure limit the rules impose: an observed enemy unit's initiative appears only as the coarse three-band estimate of TM-1100 (TM-2130), and a Contact reports only what its fidelity grade admits (01-game-rules.md GR-1260) — a Trace says a domain and nothing more, and only an Assessment carries strength, Stance and condition. What was never sent cannot be map-hacked.
Rationale: compaction is not an optimization, it is the fog rule. An uncompacted per-activation feed leaks by omission: a client that receives a slot for every activation can infer from an empty slot that something happened where it could not see, and by correlating those slots with the initiative bands it legitimately knows, deduce roughly what class of unit acted and when. Over a few turns that is a reasonable census of an opponent's army, assembled entirely from things the player never observed. Emitting only observable events, with no ordinal that maps back to the roster, closes it completely.
MP-1125 The timing channel. Because activation order is initiative order, when a client learns something would otherwise disclose what acted. The transport MUST therefore:
- transmit each player's stream as a single payload after the Cascade has fully completed, never incrementally (10-turn-model.md TM-2170), in every game with two or more human players;
- dispatch all players' streams for a turn together, so that no player learns the turn resolved measurably before another;
- not vary dispatch time with stream content or size — a player who observed nothing MUST receive an empty stream at the same moment as a player who observed a battle, and the transport MUST NOT skip or defer a dispatch because a stream is empty;
- send nothing at all between
CloseOrdersand that dispatch, so the interval carries no sub-structure to measure.
Rationale: this is the requirement the fog rules of 10-turn-model.md reach into this document to obtain, and every clause of it closes a channel that reopens the leak MP-1120 closed. Clause 3 is the subtle one: an implementation that treats "no observations" as "nothing to send" turns silence into a signal, and an empty payload costs nothing to send.
MP-1127 Orders-phase silence. The only thing the transport MAY deliver during an Orders phase is presence (MP-186) and chat, and presence MUST NOT vary with any player's order content (10-turn-model.md TM-450, TM-2070). The client MUST NOT emit network traffic whose timing or volume varies with the content of its Dispatch (13-command.md CM-1860) or of its order edits in any way an opponent could observe, and the authority MUST NOT relay any derived signal of another seat's activity beyond the commit marker itself.
MP-1130 Order legality: the authority validates every order record against the pinned core (MP-300, 10-turn-model.md TM-250); a record naming an entity the issuing player does not own or cannot observe is rejected and counted. Repeated impossible records from one client SHOULD be surfaced to the admin and the service as a tamper signal. An order that was legal when issued and merely unachievable at activation is not an error at any layer and MUST NOT be counted as one (TM-270).
MP-1140 Log integrity: the log is hash-chained per order record — each appended record's
ChainHash commits to its predecessor (03-architecture.md AR-260). That is the granularity AR-570(b)
verifies on import and that the AR-565 hand-off signature covers, so it is the only chaining rule;
this document adds none. A SubmitOrders batch is a transport grouping only (MP-280), is not atomic
(MP-285), and MUST NOT be treated as a chain unit. The log is additionally server-sequenced in server
modes (gapless Seq) and signature-chained in bundle mode (MP-770). Non-order control records —
rollbacks, mode switches, admin actions — live in the separate audit chain of AR-563.
MP-1150 Desync detection has two checkpoints per turn, and is scoped to what each node can legitimately compute — a fog-filtered client holds no canonical state and MUST NOT be sent any (MP-250), so it cannot be asked for a canonical digest:
- Before the Cascade. Every node holding full state MUST compute and exchange the activation-order hash of 10-turn-model.md TM-2370 (MP-247); the authority compares and reports any mismatch immediately, before any state has diverged.
- After the Reckoning, nodes holding full state — the authoritative server, the relay-only host
client, and any client entitled to the whole log — MUST compute AR-130's
TurnHash(64-bit XXH3) over the canonical state hash of TM-2400, and connected ones MUST report it (TurnHashmessage, §5; AR-530). - After the Reckoning, authoritative-mode clients report instead a per-seat
ViewHash: a digest computed independently by server and client over the canonical encoding (AR-620) of that seat'sPlayerView, carried on AR-500ViewCheckpointmessages. Contract: this obliges 03-architecture.md to defineViewHashas part of the AR-500 view-serialization contract; until it does, authoritative-mode clients report no digest and their desync exposure is covered only by the server's own snapshot verification (AR-670).
Per-turn digests MUST use the cheap XXH3 form; the SHA-256 StateHash is reserved for snapshots and
save manifests (AR-130). On mismatch the authority's log is truth: the mismatching client MUST resync
— from the log in relay-only mode, from a fresh ViewCheckpoint in authoritative mode (MP-290) — and
persistent mismatch is logged as a defect or tamper signal with the replay attached.
MP-1160 Rated integrity: rated games MUST run in authoritative mode on a server instance (MP-350), for the game's entire life (MP-906). Ratings, reporting and enforcement policy are specified in 08-services-platform.md. Relay-only and bundle games are unrated by construction and their UI says so. Where a rated game uses third-party AI seats, 06-ai.md AI-370's determinism and server-side-execution constraints apply.
MP-1170 Fair-visibility parity: any information the client UI derives — distance readouts, combat odds previews (13-command.md), a player's own units' initiative and relative activation order — MUST be computable from that seat's own view and committed state alone (10-turn-model.md TM-2080), so a modified client gains no information advantage, only convenience it already legitimately has. The client MUST NOT need, and the protocol MUST NOT supply, any value that would let a client reconstruct the global activation order (TM-1120).
MP-1180 Disputes: because every game is a deterministic replay from the order log, the dispute artifact is the log itself. The service MUST be able to re-simulate any rated game headlessly and verify the recorded result before it enters ratings (TM-2410).
16. Self-hosted servers
MP-1190 @everylastcity/server MUST be self-hostable as a single Docker image, providing the full
feature set of this document: lobbies, live relay and authoritative simulation, correspondence play,
drop-box, spectating, replays, notifications, and local accounts. The official hosted instance runs
the same software (08-services-platform.md).
MP-1200 Configuration surface (file/env, no GUI required): listen port and TLS, external URL, account policy (open/invite/guest), default stall policies (MP-990), dormancy period (MP-720), storage paths and quotas, Web Push keys, SMTP relay, content cache limits, and the scheduler that owns deadline expiry and Cascade execution for games with nobody connected (MP-615). Where an instance runs as more than one process or node, the configuration surface additionally covers the shared store used for room presence and matchmaking; a single-process instance MUST require no such store and MUST run against its database alone.
MP-1210 Instance independence: a self-hosted instance MUST function with zero connectivity to the official service — no license checks, no phone-home. Cross-instance identity and federation are NOT required in v1; a player uses per-instance accounts (open question 6).
MP-1220 Compatibility: server and client negotiate protocol and core versions (Hello, §5;
AR-920); an instance MUST advertise its supported version ranges, and games remain pinned (MP-110) so
a server upgrade never alters an in-flight game's rules. Self-hosted operators MUST be able to run
multiple core versions side by side.
MP-1230 Data portability: the instance operator MUST be able to export any game the instance
hosts as a bundle or replay, and an instance MUST support bulk export — no game is captive to an
instance (MP-080). Operator export carries no new exposure in authoritative mode, since the instance
already computes full state. Player export follows MP-730 exactly: unrestricted for games without
fog enforcement; limited mid-game to the player's own fog-filtered view cache (AR-590) in
authoritative fog-enforced games; full only after the game ends (MP-1100) or through the
consent-gated mode switch out of authoritative mode (MP-900, MP-905, MP-920, MP-940). Operator bulk
export MUST NOT be surfaced as a per-participant feature that circumvents MP-730, and an operator who
is also a participant in a live fog-enforced game on their own instance MUST be disclosed as such in
GameInfo — self-hosting is not a fog-enforcement claim.
MP-1240 WASM plugin execution: an instance MAY execute sandboxed WASM AI and generator plugins (07-modding-content.md) for authoritative games with modded content, subject to operator-set resource limits; instances that decline MUST still relay such games (MP-380).
17. Contracts on other documents
Obligations this specification places on subsystems it does not own, and the obligations it accepts.
MP-1250 This document accepts 10-turn-model.md TM-2700 in full and discharges it as follows:
transport of order records (§4.1, §5) and of observation streams (MP-240, MP-245); the presence
channel of TM-440 as ephemeral non-authoritative data (MP-186, MP-265); the deadline and reserve
clocks as host-side state reaching the core only as TurnTimeout and CloseOrders (MP-995,
MP-1000); the activation-order hash exchange of TM-2380 (MP-247, MP-1150); and the single-payload
transmission of TM-2170 (MP-245, MP-1125).
MP-1255 This document accepts 14-victory.md VC-3180 in full: AI substitution of a departed
seat without freezing its Tenure (MP-1010); transport of CastVerdictVote and Concede as ordinary
logged orders (MP-150, MP-270); and delivery of a Verdict offer within the VerdictWindow of VC-2780
in correspondence play (MP-960).
MP-1260 03-architecture.md MUST provide: the order envelope and its gapless server-assigned
Seq and per-record ChainHash (AR-260); the Issuer enum with an Authority(reason) form covering
host-issued phase records — this document uses AutoTurn for TurnTimeout (MP-1000) and requires a
reason value for the authority's CloseOrders, which the AR-260 set does not yet name; typed
rejections including PhaseForbidden (AR-320); idempotent resubmission by ClientTag (AR-340);
PlayerView/RefereeView separation (AR-410, AR-420); ViewCheckpoint/ViewDelta with a defined
ViewHash (AR-500, MP-1150); the audit log for non-order control records (AR-563); the turn-bundle
and sign-in container profiles (AR-565, AR-567); and the three version axes of AR-880 with the wire
schema version of AR-920.
MP-1265 06-ai.md MUST provide: AI seats that submit order records within the same Orders phase as human seats with no extra time, information, or order kinds (10-turn-model.md TM-410); server-side execution of AI seats for correspondence and server-authoritative games (AI-480); a substitute that takes over an absent seat's existing orders and sees only that seat's fog-filtered view (AI-490, MP-1010); and the single fault-and-fallback policy of AI-240, which this document cites rather than restating.
MP-1270 08-services-platform.md MUST provide: account, notification-channel and quiet-hours infrastructure (§12) with SVC-530 owning channel defaults; the room-framework scope boundary of SVC-402 matching MP-265; rating policy and substitution recording (SVC-648, MP-1020); and the durable scheduler that runs deadline expiry, Cascade execution and notification dispatch for correspondence games with nobody connected (MP-615, MP-1200).
MP-1275 04-ui-ux.md MUST provide: the client-side staging restored on reconnection (MP-290); the correspondence game list of MP-680; the occlusion hand-off and per-seat playback of §7; the presence and clock display of MP-186; and the trust-level labelling MP-350, MP-790 and MP-906 require in plain language.
Open questions
- Bundle closer stalling (MP-845). The commitment makes the closer's early sight harmless, but a closer who simply never closes still halts the game, and rotation does not help if the stalled turn is theirs. Should any seat be able to force a re-close after an agreed interval by assembling the packets themselves — which requires every seat to broadcast its packet to everyone rather than only to the closer, and therefore trades stall-resistance for the closer's exclusive sight becoming universal? Current draft keeps packets closer-only and treats the stall as social.
- E2E-encrypted relay (MP-370): is there real demand, given it forfeits server-side deadline enforcement, substitution, spectating and replay? Ship behind a flag or drop entirely.
- Hot seat playback cost (MP-430). Per-seat playback behind the occlusion screen is correct and it multiplies the least interesting part of the turn by the number of players. Is there an acceptable compressed form — a written per-seat after-action summary (TM-2280) with animation only on request — and does that change the feel enough to matter at a shared table?
- Reconnection during a very long Cascade (MP-290). The Cascade is bounded at 200 ms of computation (TM-2480) but the dispatch is bounded by MP-1125's simultaneity requirement across potentially slow links. What does a client see if it connects during that window — a "resolving" state that is honest but reveals nothing, or nothing at all?
- Vacation and the reserve bank (MP-990). Vacation suspends the deadline; the reserve bank is separate and never refills (TM-510). A player returning from vacation with an exhausted reserve is permanently on the clock for the rest of a multi-year game. Should the reserve refill on some schedule in correspondence play, or is a bank that only ever depletes the correct incentive?
- Federation between self-hosted instances (MP-1210): out of scope for v1 — revisit post-launch.
- Default dormancy period (MP-720): 180 days is a guess; tune against real correspondence cadence once games exist.
- LAN play from a browser tab (MP-440, MP-490, MP-500): the browser build can neither host, nor
discover by mDNS, nor reach a plaintext
ws://LAN host. Is LAN play formally a desktop/mobile feature, or do we invest in a locally trusted certificate or a loopback bridge? This is the one place the cross-platform goal and the zero-infrastructure goal do not overlap. - Unreachable-participant consent (MP-900): the gate out of fog-enforced mode needs consent from all active humans, but correspondence play is exactly where a participant may be unreachable for weeks. Does an unreachable seat block the switch indefinitely, does the §13 escalation ladder make it inactive first, or does a substituted seat drop out of the consent set? "Active human participants" is used throughout without a definition.
- Downgrading a live authoritative game to relay-only (MP-900, MP-905): the gate requires unanimous consent, but should the downgrade be offered at all? It permanently forfeits rated eligibility on any later re-upgrade (MP-906), so a simpler rule would be to forbid authoritative → relay-only outright and require the switch to go through bundle or hot seat.
ViewHashin the core view contract (MP-1150): does 03-architecture.md adopt a per-player view digest on AR-500ViewCheckpoint, or do we accept server-only desync detection for fog-filtered clients? This document asserts the obligation; 03 must accept or refuse it.- A reason value for authority-issued
CloseOrders(MP-1260): AR-260'sIssuerenum namesAutoTurn,AiSubstitutionandPluginFallback.CloseOrdersis always authority-issued and is not any of those. Proposed: addPhaseControl. 03-architecture.md owns the enum. - View-cache export and restore (MP-730): the fog-filtered view cache is the only mid-game backup a fog-enforced participant gets — is it re-importable on a second device, and does that require the seat key of MP-770 to stop a stolen cache from revealing a player's own view?
- Batch semantics for clients that want all-or-nothing (MP-285): prefix application is specified; do any UI flows — multi-unit orders issued as one gesture — need an opt-in atomic batch, or is per-order reconciliation always sufficient now that a batch only ever revises the issuer's own plan?
- Two presence sources (MP-265, MP-186): presence for connected clients MAY ride the room framework's ephemeral sync channel, but correspondence presence ("time since last action", commit markers) must be visible with no room running. Do we accept two implementations, and does the live channel ever expose a signal — "currently viewing" can imply attention on a map region — that MP-1127 would not otherwise permit?
- Lobby chat durability (MP-465): lobby chat is expendable by construction, so a late joiner sees none of the pre-launch conversation and nothing survives launch. Acceptable, or should the lobby channel be persisted for the lobby's lifetime — a durable write, never the sync channel — without becoming a second chat record competing with MP-185?
- Cross-platform digest agreement (MP-1150, MP-1180): the desync machinery compares
ActivationOrderHash,TurnHashandViewHashcomputed by a Node authority, a browser tab and a Tauri build of the same source. Agreement rests on the core's integer and iteration-order discipline, so a core defect surfaces here first as a false desync. Should rated play (MP-1160) be gated on a CI job proving digest agreement across all three runtimes? - Per-turn digest budget (MP-247, MP-1150): the authority plus every full-state node now
computes two digests per turn while authoritative-mode clients compute a per-seat
ViewHash. Has the aggregate been measured on a server carrying many concurrent games, or only for one game in isolation? - Rated-play substitution limits (MP-1020, MP-1160): how many timed-out turns or substitutions before a rated game is annulled rather than rated? The turn model makes a timed-out turn far less damaging than a skipped turn used to be, which may mean the threshold should be higher than instinct suggests.
- Bundle passphrase and key exchange (MP-780, MP-810): passphrase agreement is out-of-band. Do we want an optional key-exchange assist via the drop-box, and does that weaken the no-infrastructure guarantee by making the convenient path the connected one?