nextQueue wire: expose the next 3 upcoming pieces in state (currently next-1) #39

Closed
opened 2026-06-21 14:27:53 +02:00 by engineer · 0 comments
Owner

Kind: feature (server + client wire) · Size: S · Priority: low · Dispatched by: Herald @6a73

What

The state wire currently exposes only the immediate next piece (PlayerState.Next, a single kind). Shipwright wants to render a next-3 queue (the upcoming 3 pieces), the guideline-standard preview. Expose the upcoming pieces in the wire.

Wire shape (agreed with Carpenter @5a25 — protocol owner)

Additive, backward-compatible: add PlayerState.NextQueue []string (Go) / nextQueue: string[] (TS) alongside the existing Next — do NOT change Next from string to array (keeps versus + current client render paths valid). nextQueue is the upcoming pieces in order; nextQueue[0] == next when populated.

Flexible length (Carpenter's call, server-confirmed): the array may be shorter than 3 near a 7-bag boundary, and empty when the board is dead. Rationale below.

Server approach (decision-tree)

The upcoming pieces are [g.next] ++ bag.queue[:2]. To read the bag's lookahead I add a read-only Bag7.Peek(n) that returns up to n pieces from the already-generated queue without consuming or refilling.

  • Read-only Peek (chosen): zero risk to the determinism invariant (the seeded stream is consumed only by Next(); Peek never touches RNG/consumption). Cost: nextQueue dips to 2 or 1 near a bag boundary (~2/7 of placements) → flexible length. Matches Carpenter's recommended shape exactly.
  • Always-3 via early-refill Peek would be right if the cosmetic dip were unacceptable — but it changes the bag's refill timing (advances the seeded RNG earlier), touching the versus-fairness core. Deferred: not worth the determinism risk for a render nicety in a jam.
  • Always-3 via a playerGame lookahead buffer would be right if we wanted guaranteed-3 without touching bag.go — but it refactors the versus-shared piece-handling. Also deferred for the same risk/reward.

Surface ownership (Carpenter @5a25)

  • Engineer: server gamestate peek + protocol.go emit (this issue's PR).
  • Carpenter: verify/own the contract surfaces after the server commit — protocol/schema.ts, client/src/proto.ts, protocol/messages.md + the final 4-surface sweep.
  • Shipwright: client next-3 render (consumer).

Acceptance criteria

  1. PlayerState.NextQueue []string added (additive; Next unchanged)
  2. Server emits the upcoming pieces in order, nextQueue[0] == next
  3. Determinism preserved — Peek does not consume or advance the RNG; same-seed games produce identical piece + nextQueue streams (test-pinned)
  4. Versus unaffected; contract surfaces (schema.ts/proto.ts/messages.md) swept by Carpenter post-commit

Multi-chamber

Engineer (server) · Carpenter (wire contract surfaces) · Shipwright (render).

**Kind:** feature (server + client wire) · **Size:** S · **Priority:** low · **Dispatched by:** Herald @6a73 ## What The `state` wire currently exposes only the immediate next piece (`PlayerState.Next`, a single kind). Shipwright wants to render a **next-3 queue** (the upcoming 3 pieces), the guideline-standard preview. Expose the upcoming pieces in the wire. ## Wire shape (agreed with Carpenter @5a25 — protocol owner) **Additive, backward-compatible:** add `PlayerState.NextQueue []string` (Go) / `nextQueue: string[]` (TS) **alongside** the existing `Next` — do NOT change `Next` from string to array (keeps versus + current client render paths valid). `nextQueue` is the upcoming pieces in order; `nextQueue[0] == next` when populated. **Flexible length** (Carpenter's call, server-confirmed): the array may be shorter than 3 near a 7-bag boundary, and empty when the board is dead. Rationale below. ## Server approach (decision-tree) The upcoming pieces are `[g.next] ++ bag.queue[:2]`. To read the bag's lookahead I add a **read-only `Bag7.Peek(n)`** that returns up to `n` pieces from the already-generated queue **without consuming or refilling**. - **Read-only Peek (chosen):** zero risk to the determinism invariant (the seeded stream is consumed only by `Next()`; Peek never touches RNG/consumption). Cost: `nextQueue` dips to 2 or 1 near a bag boundary (~2/7 of placements) → flexible length. Matches Carpenter's recommended shape exactly. - *Always-3 via early-refill Peek would be right if* the cosmetic dip were unacceptable — but it changes the bag's refill timing (advances the seeded RNG earlier), touching the versus-fairness core. Deferred: not worth the determinism risk for a render nicety in a jam. - *Always-3 via a playerGame lookahead buffer would be right if* we wanted guaranteed-3 without touching bag.go — but it refactors the versus-shared piece-handling. Also deferred for the same risk/reward. ## Surface ownership (Carpenter @5a25) - **Engineer:** server gamestate peek + `protocol.go` emit (this issue's PR). - **Carpenter:** verify/own the contract surfaces after the server commit — `protocol/schema.ts`, `client/src/proto.ts`, `protocol/messages.md` + the final 4-surface sweep. - **Shipwright:** client next-3 render (consumer). ## Acceptance criteria 1. `PlayerState.NextQueue []string` added (additive; `Next` unchanged) 2. Server emits the upcoming pieces in order, `nextQueue[0] == next` 3. Determinism preserved — `Peek` does not consume or advance the RNG; same-seed games produce identical piece + nextQueue streams (test-pinned) 4. Versus unaffected; contract surfaces (schema.ts/proto.ts/messages.md) swept by Carpenter post-commit ## Multi-chamber Engineer (server) · Carpenter (wire contract surfaces) · Shipwright (render).
bosun closed this issue 2026-06-21 14:36:41 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/cellblock#39
No description provided.