mirror of
https://github.com/tiennm99/ai-coding-workflow-labs.git
synced 2026-08-13 13:22:58 +00:00
docs: complete Epic 1 review, create story 2.1 best score tracking
Epic 1 code review passed with 0 patches needed — all 6 stories marked done. 6 deferred items logged for Epics 2-5. Created story 2-1-best-score-tracking as ready-for-dev to begin Epic 2.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Story 1.1: Project Scaffold & Dev Environment
|
||||
|
||||
Status: review
|
||||
Status: done
|
||||
|
||||
## Story
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Story 1.2: Game Logic Module
|
||||
|
||||
Status: review
|
||||
Status: done
|
||||
|
||||
## Story
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Story 1.3: Game Board & Tile Rendering
|
||||
|
||||
Status: review
|
||||
Status: done
|
||||
|
||||
## Story
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
# Story 2.1: Best Score Tracking
|
||||
|
||||
Status: ready-for-dev
|
||||
|
||||
## Story
|
||||
|
||||
As a player,
|
||||
I want to see my best score alongside my current score,
|
||||
so that I have a motivational anchor and can track my all-time progress.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. When the current score exceeds the best score after a merge, the best score display updates immediately to match the current score
|
||||
2. When the player starts a new game, the best score remains unchanged (it persists across games within the session)
|
||||
|
||||
## Tasks / Subtasks
|
||||
|
||||
- [ ] Task 1: Add bestScore state to App.svelte (AC: #1, #2)
|
||||
- [ ] Add `let bestScore = $state(0);` as a new reactive state variable
|
||||
- [ ] Add `$effect` that watches `gameState.score` — when it exceeds `bestScore`, update `bestScore`
|
||||
- [ ] Replace hardcoded `bestScore={0}` with `bestScore={bestScore}` in the ScoreBoard prop
|
||||
|
||||
- [ ] Task 2: Preserve bestScore across New Game (AC: #2)
|
||||
- [ ] Verify that `handleNewGame()` resets `gameState` via `initGame()` but does NOT reset `bestScore`
|
||||
- [ ] `bestScore` is a separate `$state` variable, not part of `gameState` — it survives `initGame()` by design
|
||||
|
||||
- [ ] Task 3: Verify existing tests still pass
|
||||
- [ ] Run `npx vitest run` — all 38 existing tests must pass (no game-logic.js changes)
|
||||
|
||||
## Dev Notes
|
||||
|
||||
### Architecture Compliance
|
||||
|
||||
- **State ownership:** `bestScore` lives in `App.svelte` as a `$state` rune — NOT inside the game state object
|
||||
- **Props-down pattern:** `App.svelte` passes `bestScore` to `ScoreBoard` via prop (already wired, just hardcoded to 0)
|
||||
- **No game-logic.js changes:** Best score is a UI/session concern, not game logic. The game-logic module stays pure.
|
||||
- **No storage.js yet:** localStorage persistence is Story 2.2. This story is in-memory only — best score resets on page refresh.
|
||||
|
||||
### Critical Anti-Patterns (DO NOT)
|
||||
|
||||
- DO NOT add `bestScore` to the `gameState` object — it is NOT part of the canonical game state shape `{ grid, score, won, keepPlaying }`
|
||||
- DO NOT create a `storage.js` module yet — that is Story 2.2
|
||||
- DO NOT use `$derived` for bestScore — it needs to be a `$state` that persists across game resets (derived would reset when gameState resets)
|
||||
- DO NOT use Svelte stores (`writable`, `readable`) — this project uses Svelte 5 runes only
|
||||
|
||||
### Implementation Pattern
|
||||
|
||||
The correct pattern uses `$effect` to watch score changes:
|
||||
|
||||
```javascript
|
||||
let bestScore = $state(0);
|
||||
|
||||
$effect(() => {
|
||||
if (gameState.score > bestScore) {
|
||||
bestScore = gameState.score;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This works because:
|
||||
- `$effect` runs whenever `gameState.score` changes (reactive dependency)
|
||||
- `bestScore` is a separate `$state`, so `handleNewGame()` resetting `gameState = initGame()` (score=0) does NOT reset bestScore
|
||||
- When a new game starts, `gameState.score` becomes 0, which is NOT > bestScore, so bestScore stays
|
||||
|
||||
### ScoreBoard Component
|
||||
|
||||
`ScoreBoard.svelte` already accepts `score` and `bestScore` props — no changes needed to the component:
|
||||
|
||||
```svelte
|
||||
let { score = 0, bestScore = 0 } = $props();
|
||||
```
|
||||
|
||||
The only change is in `App.svelte` line 58: replace `bestScore={0}` with `bestScore={bestScore}`.
|
||||
|
||||
### Previous Story Intelligence
|
||||
|
||||
From Epic 1 implementation:
|
||||
- `App.svelte` owns all state via `$state` rune — `gameState` is the single game state object
|
||||
- `ScoreBoard` component at `src/components/ScoreBoard.svelte` — presentational, receives `score` and `bestScore` props
|
||||
- `handleNewGame()` calls `gameState = initGame()` which returns `{ grid, score: 0, won: false, keepPlaying: false }`
|
||||
- `getDirectionFromKey` is the export name from `input-handler.js` (not `mapKeyToDirection`)
|
||||
- `overlayType` is used instead of separate `gameOver`/`won` checks in the template
|
||||
- Existing test suite: 38 tests in `src/lib/game-logic.test.js` — all game logic, no UI tests
|
||||
|
||||
### Scope Boundary
|
||||
|
||||
This story is intentionally minimal:
|
||||
- **In scope:** In-memory best score tracking that survives New Game within a session
|
||||
- **Out of scope:** localStorage persistence (Story 2.2), game state persistence (Story 2.2), keep-playing mode changes (Story 2.3)
|
||||
|
||||
### References
|
||||
|
||||
- [Source: _bmad-output/planning-artifacts/epics.md#Story 2.1]
|
||||
- [Source: _bmad-output/planning-artifacts/architecture.md#Frontend Architecture - State Management]
|
||||
- [Source: _bmad-output/planning-artifacts/architecture.md#Implementation Patterns - Communication Patterns]
|
||||
|
||||
## Dev Agent Record
|
||||
|
||||
### Agent Model Used
|
||||
|
||||
### Debug Log References
|
||||
|
||||
### Completion Notes List
|
||||
|
||||
### File List
|
||||
@@ -0,0 +1,10 @@
|
||||
# Deferred Work
|
||||
|
||||
## Deferred from: code review of Epic 1 (2026-04-13)
|
||||
|
||||
- **Best score always 0, never tracked** — UI displays "BEST: 0" that never updates. Covered by Story 2-1 (Best Score Tracking).
|
||||
- **Tile keyed by position, not identity** — `Grid.svelte` keys tiles by `r-c` grid position instead of unique tile ID. Will break slide/merge animations. Address in Epic 3 (animations).
|
||||
- **No animation lock for rapid key input** — No debounce or move-in-progress guard in `handleKeydown`. Synchronous now but will need a lock when animations are added in Epic 3.
|
||||
- **Grid 500px overflow on narrow viewports** — `Grid.svelte` hardcodes `containerSize = 500`. Overflows on mobile. Covered by Story 4-3 (Responsive Layout).
|
||||
- **Tile font overflow for very large values** — 3-tier font sizing (55/45/35px) exists but values beyond 8192 (6+ digits) may overflow the 106px cell at 35px. Epic 5 polish.
|
||||
- **Overlay has no keyboard focus trap** — `GameMessage.svelte` does not trap focus or auto-focus the action button. Accessibility improvement for post-MVP.
|
||||
@@ -35,7 +35,7 @@
|
||||
# - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended)
|
||||
|
||||
generated: 2026-04-13
|
||||
last_updated: 2026-04-13T01:00:00
|
||||
last_updated: 2026-04-13T22:21:00
|
||||
project: try-bmad
|
||||
project_key: NOKEY
|
||||
tracking_system: file-system
|
||||
@@ -43,18 +43,18 @@ story_location: _bmad-output/implementation-artifacts
|
||||
|
||||
development_status:
|
||||
# Epic 1: Play a Complete Game (Desktop)
|
||||
epic-1: in-progress
|
||||
1-1-project-scaffold-and-dev-environment: review
|
||||
1-2-game-logic-module: review
|
||||
1-3-game-board-and-tile-rendering: review
|
||||
1-4-game-header-score-display-and-new-game-button: review
|
||||
1-5-keyboard-input-and-interactive-gameplay: review
|
||||
1-6-win-and-game-over-overlays: review
|
||||
epic-1: done
|
||||
1-1-project-scaffold-and-dev-environment: done
|
||||
1-2-game-logic-module: done
|
||||
1-3-game-board-and-tile-rendering: done
|
||||
1-4-game-header-score-display-and-new-game-button: done
|
||||
1-5-keyboard-input-and-interactive-gameplay: done
|
||||
1-6-win-and-game-over-overlays: done
|
||||
epic-1-retrospective: optional
|
||||
|
||||
# Epic 2: Save Progress & Keep Playing
|
||||
epic-2: backlog
|
||||
2-1-best-score-tracking: backlog
|
||||
epic-2: in-progress
|
||||
2-1-best-score-tracking: ready-for-dev
|
||||
2-2-game-state-persistence: backlog
|
||||
2-3-keep-playing-mode: backlog
|
||||
epic-2-retrospective: optional
|
||||
|
||||
Reference in New Issue
Block a user