Build core Scribble gameplay loop: rooms, drawing, scoring, and round results#140
Open
sudevkrishnan wants to merge 32 commits into
Open
Build core Scribble gameplay loop: rooms, drawing, scoring, and round results#140sudevkrishnan wants to merge 32 commits into
sudevkrishnan wants to merge 32 commits into
Conversation
Covers room creation/host assignment, join validation (empty/invalid format/not-found), room isolation, ~2s lobby polling, and host-gated start with a 2-player minimum. Clarified the invalid-format vs not-found code boundary and required client-side identity persistence across browser reload, while reaffirming no server-side database/persistence project-wide. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds host/canStart fields to the room snapshot, a POST /:code/start gating endpoint, sessionStorage-based identity reattachment (tab-scoped to preserve two-tab testing), and ~2s lobby polling — all additive within the existing api/services/models and state/services/pages layering, per the plan's Constitution Check. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
35 tasks across setup, foundational (shared model/snapshot fields + sessionStorage identity helper), and the four user stories (host creation, join validation, lobby polling, host-gated start), plus a polish phase for reload reattachment and final quickstart/test validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Room creator is auto-assigned host; isHost/canStart exposed on snapshots
- Join validates empty/invalid-format/not-found codes with distinct
400/400/404 responses
- Lobby auto-polls every ~2s, replacing the manual refresh button
- POST /rooms/:code/start gates on host + 2-player minimum (403/409),
flipping room status to active (gameplay logic deferred to next phase)
- Client participant identity persists in sessionStorage so a tab reload
reattaches to the same room/role; stale identities are cleared and
surfaced as a clear error on the Start screen
19 backend tests / 16 frontend tests passing; both packages build clean.
Verified end-to-end via curl against a live server and manually in two
browser tabs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lity Covers trimming/rejecting blank names on create and join, assigning the host as drawer at round start, deterministic room-code-derived secret word selection, and drawer-only visibility of both the secret word and the candidate word list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tightens create/join name validation to trim+reject blank via Zod; assigns drawer (always the host) and a room-code-derived secret word once at successful start; redacts secretWord/availableWords from non-drawer snapshots server-side, while isDrawer stays public per participant so everyone can see who's drawing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PyYAML is now installed, so the agent-context extension's update-agent-context.sh can run; minor rewording of the CLAUDE.md pointer line, same target file as the manual edit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ment 22 tasks across setup, foundational (model fields + word-hash helper), and four P1 user stories (name validation, drawer assignment, word selection, drawer-only visibility), plus a polish phase for final quickstart/test validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/speckit-analyze (run after tasks, before implement) found a CRITICAL coverage gap: nothing routed non-host participants to the game screen when the round started, since LobbyPage only navigated the host explicitly in handleStart(). A guesser would be stuck on the Lobby screen indefinitely. Adds FR-012/SC-006/an edge case/an acceptance scenario to spec.md, a research.md decision documenting the fix (LobbyPage watches room.status via existing polling, navigates everyone once active) and why it's verified manually rather than via a new component-test dependency, a LobbyPage.tsx task (T014) in tasks.md, and updates plan.md/quickstart.md accordingly. Also rewords the "Round" Key Entity in spec.md to match data-model.md (flat fields on Room, not a separate stored object) per a LOW-severity finding from the same analysis pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements all four user stories from spec 002-drawer-word-assignment: - createRoomSchema/joinRoomSchema reject blank/whitespace playerName with "Player name is required"; removes the old "Player" fallback - startGame() assigns the host as drawer and a room-code-derived secret word (selectSecretWord, deterministic, no RNG) the first time a room goes active; repeated starts don't reassign either - toRoomSnapshot() redacts secretWord/availableWords for non-drawers; isDrawer is public per participant so everyone sees who's drawing - LobbyPage now navigates every participant (not only the host) to /game once room.status becomes active, closing a gap /speckit-analyze found before implementation; GamePage shows a Players list with Drawer/Guesser labels and the secret word when present 35 backend tests / 18 frontend tests passing; both packages build clean. Verified end-to-end via curl against a live server (blank-name rejection, drawer/word assignment, drawer-only redaction, determinism and idempotency across repeated starts/fetches). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds spec for User Stories 1-5 covering the drawer's interactive canvas/clear action, validated guess submission, polling-synced guess history, and deterministic 100/0 scoring. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds research, data model, API contract, and quickstart for the new canvas/clear, guess validation, redacted guess-history sync, and deterministic scoring mechanics. Also folds in the guess-text visibility clarification from the clarify session. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Breaks phase 3 into 43 tasks across Setup, Foundational, and five user-story phases (US1-US5) per spec.md priorities, plus a polish phase for end-to-end quickstart validation and the full test suite. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/speckit-analyze flagged that toRoomSnapshot() didn't actually emit strokes until the US4 redaction task, breaking US1/US2's own quickstart scenarios (guesser-side canvas sync) at their checkpoint. Moves that wiring into a new Foundational task (T006) since strokes carry no redaction rule. Also tightens US5's test coverage for FR-014 (post-correct incorrect guesses) and SC-006 (repeat-trial determinism). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements phase 3 (003-drawing-canvas-guessing): drawer-only freehand canvas with clear, validated guess submission (trim, case-insensitive, drawer rejected), per-viewer redacted guess history (incorrect guesses hidden from other guessers until correct), and atomic +100/+0 scoring. Backend gains addStroke, clearCanvas, submitGuess plus POST /:code/strokes, /:code/clear, /:code/guesses; toRoomSnapshot now redacts guess text per viewer. Frontend gains DrawingCanvas (with an isolated, unit-tested pointer-to-stroke builder), and wires GuessForm/ResultPanel/ Scoreboard to live room state. Also fixes a polling gap found during manual verification: GamePage never started polling (only LobbyPage did, and it stopped on navigating away), so a participant's view only updated on their own actions. GamePage now polls on mount like LobbyPage, so canvas/guess/ score updates from other participants sync within one cycle. 68 backend tests, 23 frontend tests, all passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a 24-item requirements-quality checklist covering core gameplay logic, polling sync, UX clarity, and security/input-integrity for phase 3. Resolves the three highest-value findings directly in spec.md: - Edge Cases: replaced unquantified "continuous-looking line" with a verifiable per-pointermove-event rendering rule. - SC-005: clarified that "one polling cycle" is the pass/fail threshold and "~2s" is descriptive context only. - New FR-020: sets a minimum display bar for redacted guess-history entries (guesser identity + incorrect indicator), closing a gap between the data contract (FR-018) and UI requirements. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…list gaps Resolves all 24 items in the gameplay-review checklist. Most were already satisfied by the existing spec; a few real spec gaps are fixed directly: - FR-003a + new US1 scenario: a zero-movement pointer-down/up is now an explicit, valid single-point stroke (a dot). - New Edge Case bullet: drawer/guesser role checks are explicitly a server-side guarantee, not a UI-only restriction, mirroring phase 2's non-UI-path guarantee for secret-word redaction. - New FR-005a: clear and guess controls must be hidden or visibly disabled for the role that can't use them. Also surfaced and fixed a real bug while resolving CHK021: submitGuess() only checked participantId against the drawer's ID, never against the room's actual participant list, so a fabricated participantId could still get a guess recorded and broadcast to everyone. Adds FR-009a, a not_participant failure reason (403, "participantId is not a member of this room"), and regression tests at both the service and route level. contracts/rooms-api.md updated to document the new error case. 70 backend tests passing (up from 68). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 4 of the gameplay loop: shared unredacted result state (word, scores, full guess history) visible to all players, plus host-triggered restart that returns everyone to the lobby with players preserved and all round state cleared. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolves the key ambiguity in the result/restart spec: rounds end only via an explicit host-triggered "End Round" action, never a timer or auto-detection, consistent with the project's no-timer constraint and the host's existing sole authority over game start/restart. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a "result" Room.status entered only via a host-only "End Round" action, with toRoomSnapshot revealing the secret word and full guess text to every viewer while in that state; restart returns the room to "lobby" preserving participants and clearing all round-specific fields. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two P1 user stories (shared result reveal, host restart to clean lobby), gated behind a shared RoomStatus widening in the Foundational phase, with tests at every layer per the constitution's discipline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
F1 (HIGH): ResultPage must poll, or a participant already on /result never observes the host's restart. F2: GamePage needs a symmetric lobby-skip safety net to match LobbyPage's result-skip one. F3: add a restart-then-startGame-again test so FR-012/SC-005 has automated coverage, not just manual quickstart. F4: clarify in Assumptions that restart-then-replay is the lab's explicit Scenario 4 deliverable, not the constitution's prohibited automatic multi-round/drawer-rotation mechanic. F5: pin down FR-003's score visibility with an explicit result-state assertion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds RoomStatus "result", host-only endRound/restartRoom in roomStore, their routes/schemas, and a toRoomSnapshot bypass that reveals the secret word and every guess's text to all viewers once a room is in the result state. Restart resets drawer/word/strokes/ guesses/scores while preserving the participant roster. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GamePage gains a host-only "End Round" button and navigates to the new ResultPage once the room enters the result state (with a lobby-skip safety net for a missed transition). ResultPage shows the revealed word/scores/history and a host-only "Restart" button, polling so it observes the host's later restart; LobbyPage gains a matching result-skip safety net for reconnecting clients. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Confirmed via curl: guess text/secretWord redacted during the active round and fully revealed to every viewer after End Round; End Round and Restart both reject non-host callers and wrong room states; Restart resets all round state and preserves the participant roster; a restarted room starts an independent second round cleanly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New review.md checklist tests requirements quality across state- transition correctness, edge cases, UX clarity, and cross-phase consistency. It surfaced three real spec gaps, all already satisfied by the implementation (closing documentation only, no code changes): FR-013 requires host-only End Round/Restart controls to be hidden for non-host viewers; FR-010 now states the restart reset is atomic; a new Edge Cases bullet confirms drawing/guessing is rejected once a round has ended, reusing the existing active-round gate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
21d6c6d to
131780b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the full multiplayer drawing-and-guessing game loop, delivered in four spec-driven phases:
auto-polling lobby (~2s), session-persisted participant identity (reattaches on reload), host-gated start (403
non-host, 409 under 2 players).
only.
from unknown participantId are rejected.
begin a new round; verified end-to-end against a live backend.
Each phase followed spec → plan → tasks → implement, with dedicated review/analyze passes closing gaps (e.g.
non-host navigation, round-end as a manual host action, unknown-participant guess rejection).
Contributor