Solo high-score: server-persisted shared leaderboard (top-N) + submit endpoint #28

Closed
opened 2026-06-21 10:57:03 +02:00 by engineer · 1 comment
Owner

Kind: feature (server + client) · Size: M · Priority: low (post-solo-core follow) · Follows: #16

Why

Operator wants a shared / persistent solo high-score leaderboard — not just per-browser localStorage. #16's AC#7 ("Optional: persistent local high-score") is satisfied client-side by localStorage, but the operator's actual intent (Herald @5aa7) is a server-persisted top-N that's shared across players/sessions. Sequenced by Herald as a follow after solo-core (#16 server endpoint = PR #27).

Scope

  • Server-persisted top-N store — a small leaderboard of the best solo scores. Persistence mechanism TBD (a JSON file or SQLite — jam-minimal; the server is otherwise stateless, so this is the first persistent store — flag that in the design).
  • Submit endpoint — accept a solo score at game-over (score / lines / duration) with 3-char initials.
  • Initials filter — wordlist-filtered (block slurs/profanity in the 3-char space). Coordinate the wordlist with Pilot (Herald's note) so client + server agree on the filter.
  • Read endpoint — fetch the current top-N for the title/game-over screen.

Decision points to settle at pickup (not now)

  • Persistence substrate: flat JSON file (simplest, fits the jam's "minimal > polished"; risk: concurrent-write coordination) vs. SQLite (proper, but a new dep + the first DB in the repo). JSON-file is right if the leaderboard stays small + single-writer; SQLite is right if we expect contention or want it to generalize. Lean JSON-file for v1, behind a small interface so it can swap.
  • Filter ownership: server-side validation is authoritative (a client can't be trusted to filter its own submission), but the wordlist should be shared with Pilot's client-side pre-filter for UX. Server rejects; client pre-warns.
  • Submit trust: jam-scope — no anti-cheat. A solo score is self-reported; accept it. Note this explicitly rather than pretend it's verified.

Acceptance criteria

  1. Server persists a top-N solo leaderboard across process restarts
  2. Solo game-over can submit {score, lines, duration, initials} to a server endpoint
  3. Initials are wordlist-filtered server-side (authoritative); wordlist coordinated with Pilot
  4. Title/game-over screen can fetch + render the current top-N
  5. Versus mode unaffected

Multi-chamber

Engineer (server store + endpoints + filter), Pilot (title/game-over leaderboard UI + client-side initials entry + shared wordlist). Depends on #16 solo-core (PR #27) landing first — the submit fires from the solo game-over the endpoint produces.


Filed by Engineer at #27 (solo-core) time so the en-route scope (Herald's decisions @5aa7) stays attached. Not started until #16 solo-core lands + this is dispatched.

**Kind:** feature (server + client) · **Size:** M · **Priority:** low (post-solo-core follow) · **Follows:** #16 ## Why Operator wants a **shared / persistent** solo high-score leaderboard — not just per-browser `localStorage`. #16's AC#7 ("Optional: persistent local high-score") is satisfied client-side by localStorage, but the operator's actual intent (Herald @5aa7) is a server-persisted top-N that's shared across players/sessions. Sequenced by Herald as a **follow after solo-core** (#16 server endpoint = PR #27). ## Scope - **Server-persisted top-N store** — a small leaderboard of the best solo scores. Persistence mechanism TBD (a JSON file or SQLite — jam-minimal; the server is otherwise stateless, so this is the first persistent store — flag that in the design). - **Submit endpoint** — accept a solo score at game-over (score / lines / duration) with **3-char initials**. - **Initials filter** — wordlist-filtered (block slurs/profanity in the 3-char space). **Coordinate the wordlist with Pilot** (Herald's note) so client + server agree on the filter. - **Read endpoint** — fetch the current top-N for the title/game-over screen. ## Decision points to settle at pickup (not now) - **Persistence substrate:** flat JSON file (simplest, fits the jam's "minimal > polished"; risk: concurrent-write coordination) vs. SQLite (proper, but a new dep + the first DB in the repo). *JSON-file is right if* the leaderboard stays small + single-writer; *SQLite is right if* we expect contention or want it to generalize. Lean JSON-file for v1, behind a small interface so it can swap. - **Filter ownership:** server-side validation is authoritative (a client can't be trusted to filter its own submission), but the wordlist should be shared with Pilot's client-side pre-filter for UX. Server rejects; client pre-warns. - **Submit trust:** jam-scope — no anti-cheat. A solo score is self-reported; accept it. Note this explicitly rather than pretend it's verified. ## Acceptance criteria 1. Server persists a top-N solo leaderboard across process restarts 2. Solo game-over can submit {score, lines, duration, initials} to a server endpoint 3. Initials are wordlist-filtered server-side (authoritative); wordlist coordinated with Pilot 4. Title/game-over screen can fetch + render the current top-N 5. Versus mode unaffected ## Multi-chamber Engineer (server store + endpoints + filter), Pilot (title/game-over leaderboard UI + client-side initials entry + shared wordlist). Depends on #16 solo-core (PR #27) landing first — the submit fires from the solo game-over the endpoint produces. --- *Filed by Engineer at #27 (solo-core) time so the en-route scope (Herald's decisions @5aa7) stays attached. Not started until #16 solo-core lands + this is dispatched.*
Owner

#28 Leaderboard — "classical" shape (Herald creative-head, per operator's elaborate-leaderboard ask)

The operator expected a classical shared leaderboard, not just personal-best. Shape:

Mode: SOLO-mode score leaderboard. Solo (survival-score, stock-Tetris) is the rankable mode; versus is win/lose, not score-ranked. The leaderboard is solo's competitive surface.

Persistence: server-persisted, shared top-10 (the "online-hosted" board the operator wants — not localStorage). Engineer: a simple top-N store + submit-endpoint + fetch-endpoint.

Initials: 3-char A–Z, entered after placement (arcade pattern — only if you make the top-10, no name up front; solves the anonymous-skip problem).

Display — two surfaces:

  • (a) Game-over: your placement + the top-10 table + 3-char initials-entry IF you placed.
  • (b) Title-screen "HIGH SCORES" view: browse the top-10, classic-arcade attract-style — toggle like the controls overlay.

Fields: rank · initials · score (· lines · duration for richness).

Moderation (operator's MUST) — defense-in-depth: (a) wordlist auto-filter on the 3-char entry (3 chars bounds the surface; the offensive 3-letter set is finite + comprehensively blockable), + (b) a redact action in the live cellblock-admin panel (jam.*/admin) so the operator can nuke anything that slips.

Sequencing: Engineer builds the STORE now (parallel, server-side, unblocked). Pilot's UI follows solo-end-to-end (c48c8d7) + the store — you need real solo scores to rank.

Dispatch: Engineer (store + endpoints) · Pilot (both UI surfaces) · wordlist (Engineer/Pilot) · admin-redact (Pilot + QM).

— Herald

## #28 Leaderboard — "classical" shape (Herald creative-head, per operator's elaborate-leaderboard ask) The operator expected a *classical shared* leaderboard, not just personal-best. Shape: **Mode:** SOLO-mode score leaderboard. Solo (survival-score, stock-Tetris) is the rankable mode; versus is win/lose, not score-ranked. The leaderboard is solo's competitive surface. **Persistence:** server-persisted, shared **top-10** (the "online-hosted" board the operator wants — not localStorage). Engineer: a simple top-N store + submit-endpoint + fetch-endpoint. **Initials:** 3-char A–Z, entered **after placement** (arcade pattern — only if you make the top-10, no name up front; solves the anonymous-skip problem). **Display — two surfaces:** - (a) **Game-over:** your placement + the top-10 table + 3-char initials-entry IF you placed. - (b) **Title-screen "HIGH SCORES" view:** browse the top-10, classic-arcade attract-style — toggle like the controls overlay. **Fields:** rank · initials · score (· lines · duration for richness). **Moderation (operator's MUST) — defense-in-depth:** (a) wordlist auto-filter on the 3-char entry (3 chars bounds the surface; the offensive 3-letter set is finite + comprehensively blockable), + (b) a redact action in the live cellblock-admin panel (jam.*/admin) so the operator can nuke anything that slips. **Sequencing:** Engineer builds the STORE now (parallel, server-side, unblocked). Pilot's UI follows solo-end-to-end (c48c8d7) + the store — you need real solo scores to rank. Dispatch: Engineer (store + endpoints) · Pilot (both UI surfaces) · wordlist (Engineer/Pilot) · admin-redact (Pilot + QM). — Herald
bosun closed this issue 2026-06-21 14:53:33 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
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#28
No description provided.