# Story 1.3: Play Again & Skill Tracking

Status: ready-for-dev

## Story

As a player,
I want to play additional rounds after the daily word, with words appropriate to my skill level,
So that I can keep playing and the challenge adapts to me.

## Acceptance Criteria

1. **Play Again button:** Given I am on Screen 3 after completing or failing a game, when I view the screen, then a Play Again button is visible. ✅ (button exists from 1.2, just needs wiring)

2. **Play Again request:** Given I tap Play Again, when the client sends POST /api/play-again `{ skillMetric: number }`, then the server selects a word from the target bank using weighted random selection (near skill level more likely). Response: `{ wordId }`. Client navigates to Screen 2 with empty grid.

3. **Skill from difficulty:** Given I complete any game, when the final guess response includes `difficulty`, then the client recalculates skill metric from lifetime statistics (average attempts weighted by word difficulty) and persists it.

4. **Skill sent on play-again:** Given I tap Play Again repeatedly, when I play multiple rounds, then each request sends the latest skill metric. No repeat-word prevention (target set is large enough).

5. **Default difficulty fallback:** Given the server has no solver-ranked word bank (all default 3.0), when Play Again selects a word, then selection is effectively random pending solver data from Epic 2.

## Tasks / Subtasks

- [ ] Task 1: Implement POST /api/play-again endpoint (AC: 2, 5)
  - [ ] Create `server/src/play-again.ts` — weighted random word selection near skill level
  - [ ] Create `server/src/routes/play-again.ts` — POST /api/play-again, returns `{ wordId }`
  - [ ] Register route in `server/src/index.ts`

- [ ] Task 2: Wire Play Again in client (AC: 1, 2, 4)
  - [ ] Wire `handlePlayAgain` in App.tsx — call POST /api/play-again, reset game state, navigate to Screen 2
  - [ ] Reset useGame state for new round

- [ ] Task 3: Implement skill metric calculation (AC: 3)
  - [ ] Update game-end effect to properly average difficulty into skill metric
  - [ ] Store updated skill metric in localStorage

## Dev Notes

### Building on Story 1.2

- POST /api/guess returns `difficulty` on final guess ✅
- Screen 3 has Play Again button (non-functional) ✅
- `lastDifficulty` exposed from useGame hook ✅
- `state.skillMetric` persisted in localStorage ✅

### Architecture Compliance

- **AD-8 Weighted random selection:** Words near player skill level more likely. Specific distribution is implementation detail. [Source: ARCHITECTURE-SPINE.md#AD-8]
- **AD-2 Deterministic daily word unaffected:** Play Again generates different words per player. [Source: ARCHITECTURE-SPINE.md#AD-2]

### Skill Metric Formula

```
skillMetric = (skillMetric * (gamesPlayed - 1) + difficulty) / gamesPlayed
```
Running average of all word difficulties the player has encountered. This converges to the player's true skill over time.

### Files to Create/Modify

**New:** `server/src/play-again.ts`, `server/src/routes/play-again.ts`
**Modify:** `server/src/index.ts`, `client/src/App.tsx`, `client/src/hooks/useGame.ts`, `client/src/api.ts`

### References

- [Source: _bmad-output/planning-artifacts/prds/prd-wordle-2026-07-07/prd.md#FR-11, FR-12, FR-15]
- [Source: _bmad-output/planning-artifacts/architecture/architecture-wordle-2026-07-07/ARCHITECTURE-SPINE.md]
- [Source: _bmad-output/planning-artifacts/epics.md#Story 1.3]
