Compare commits

...

2 Commits

Author SHA1 Message Date
claude (duplicate_chess) d2adf7f321 docs: session handoff — duplicate chess v1 built and merged
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 06:04:16 -04:00
claude (duplicate_chess) 5047ad7786 docs: update CLAUDE.md — v1 implemented and merged
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 06:01:26 -04:00
2 changed files with 221 additions and 5 deletions
@@ -0,0 +1,209 @@
# Handoff: Duplicate Chess v1 — built, tested, merged to main
## Session Metadata
- Created: 2026-05-19 06:01:41
- Project: /home/claude/bin/duplicate_chess
- Branch: main (all work merged and pushed to `git.sethpc.xyz/Seth/duplicate_chess`)
- Session duration: one long session — brainstorm → spec → plan → full 14-task implementation → merge.
### Recent Commits (for context)
- 5047ad7 docs: update CLAUDE.md — v1 implemented and merged
- fae9f8d docs: correct Task 4 test move data in the plan
- 5db0410 fix: real project README and save-file version validation
- ead4839 feat(ui): assemble the duplicate chess sandbox app
- bedb5a0 feat(ui): promotion dialog
- Full implementation range: `9611c0a` (scaffold + spec) → `5047ad7`. 18 commits.
## Handoff Chain
- **Continues from**: None (first handoff — this is a brand-new project).
- **Supersedes**: None.
## Current State Summary
`duplicate_chess` is a **brand-new project created this session** — a local browser
sandbox for "duplicate chess", a four-player chess variant invented by Andrew
Freiberg (Seth's father; also the inventor behind the sibling `blind_chess`
project). The session ran the full superpowers pipeline: brainstorming → design
spec → implementation plan → subagent-driven execution of all 14 plan tasks → final
review → merge. **v1 is code-complete, all 27 engine tests pass, the build and
typecheck are clean, and it is merged to `main` and pushed.** The one thing not
done: a human interactive browser test (clicking through a real game). The app
mounts and renders correctly (verified via a headless smoke render).
## Codebase Understanding
### Architecture Overview
Single Vite + Svelte 5 + TypeScript app, **no server** (duplicate chess is
perfect-information, so everything runs client-side — this is the key difference
from `blind_chess`, which needs a server as its trusted view boundary).
- **Engine** (`src/engine/`, pure TypeScript, DOM-free, vitest-tested): four
`chess.js` games (NW/NE/SW/SE). A player's legal moves = the **intersection** of
the moves legal on their two boards, keyed by `(from,to,promotion)`. Ghost
immobility, the synchronized-checkmate definition, and en-passant/castling
divergence all fall out of the intersection — no special-case code.
- **UI** (`src/lib/`): a reactive store wraps the engine; the compass renders the
four boards as a 45°-rotated pinwheel; the triple-highlight (green = playable on
both boards, grey = legal on one only) is the teaching feature.
### Critical Files
| File | Purpose | Relevance |
|------|---------|-----------|
| `docs/superpowers/specs/2026-05-19-duplicate-chess-design.md` | The full design spec | Read first — variant rules, engine model, provisional rules |
| `docs/superpowers/plans/2026-05-19-duplicate-chess-sandbox.md` | The 14-task implementation plan | What was built, task by task |
| `src/engine/legality.ts` | `legalSyncedMoves` + `selectionHighlight` | The intersection — the heart of the variant |
| `src/engine/game.ts` | `DuplicateGame` — 4 chess.js, history, undo, draw clocks | The single source of truth for game state |
| `src/engine/ghosts.ts` | Ghost derivation by cross-board comparison | |
| `src/engine/endgame.ts` | checkmate/stalemate/threefold/fifty-move; **PROVISIONAL rules** | Andrew can revise the provisional rulings — grep `PROVISIONAL` |
| `src/lib/stores/game.svelte.ts` | Reactive store wrapping the engine | `#game` is plain (non-reactive); `view` is the `$state` snapshot |
| `src/lib/Compass.svelte` | The four-board pinwheel + click-to-move wiring | |
### Key Patterns Discovered
- **The engine is DOM-free and the single source of truth.** The UI never computes
legality; it calls the engine and renders the result.
- **Store reactivity:** `chess.js` objects must NOT be wrapped in a Svelte `$state`
proxy. The store keeps `DuplicateGame` in a plain private `#game` field and
exposes a plain-data `view` snapshot in `$state`, rebuilt after every change.
- **The pinwheel rotations** (NW 225°, NE 135°, SW 315°, SE 45°) put each player's
army on the board edge facing their seat. Confirmed against Andrew's sketch.
- **Tests reach real positions** via `playSymmetric` (test-helpers.ts): when all
four players move symmetrically the four boards stay identical, so each board is
an ordinary chess game — that is how the checkmate/stalemate/threefold tests
reach real terminal positions.
## Work Completed
### Tasks Finished
- [x] All 14 tasks of the implementation plan, executed via subagent-driven
development (fresh implementer subagent per task + a combined spec/quality review
per task + a final whole-implementation review by an opus reviewer).
- [x] Engine: `types, boards, game, legality, ghosts, endgame, notation` + an
integration test. 27 vitest tests, all passing.
- [x] UI: the reactive store + `Board`, `Compass`, `Panel`, `PromotionDialog`,
`App` components.
- [x] Two post-review fixes: a real project README, and save-file `version`
validation in `deserialize`.
- [x] Merged `build-sandbox``main`, pushed, feature branch deleted.
### Files Modified
The whole project was created this session. See `git log` on `main`. New trees:
`src/engine/` (7 modules + 6 test files), `src/lib/` (store + 4 components),
`src/App.svelte`, `src/app.css`, plus the Vite scaffold and project docs.
### Decisions Made
All recorded in `DECISIONS.md`. Key ones: local sandbox first (not networked);
single Vite app, no server; engine = 4× chess.js + intersection; compass UI as a
pinwheel of diamonds; coordinate notation; provisional endgame rules picked by
Claude and marked `PROVISIONAL`. One decision surfaced during the build and is NOT
yet in DECISIONS.md — see "Blockers/Open Questions".
## Pending Work
## Immediate Next Steps
1. **Manual interactive browser test.** Run `pnpm install && pnpm dev`, open the
URL, and play a real game: click a piece on a glowing board → confirm the
green/grey triple-highlight → click a green square → move applies to both that
player's boards → turn advances. Verify ghosts appear after a one-sided capture,
promotion dialog fires, undo / Prev / Next / Live work, Save downloads JSON and
Load restores it. The engine is well-tested; the UI interaction is verified only
by `svelte-check` + a headless smoke render so far.
2. **Decide the scrubbing semantics** (see Open Questions) and reconcile spec §4.3.
3. (Optional) The remaining minor follow-ups below, if they matter.
### Blockers/Open Questions
- [ ] **Scrub semantics — spec vs shipped code disagree.** Spec §4.3 says "making a
new move while scrubbed truncates history." The shipped code instead makes
scrubbing **view-only** (you must click "● Live" before moving). The final review
flagged this; the view-only behaviour is arguably cleaner. Seth to confirm which
to keep; then update spec §4.3 (or the code) to match.
- [ ] **The provisional endgame rules** (spec §6) are Claude's defaults, not
Andrew's rulings — double-board-mate = two winners, any stalemate ends the game
all-draw, threefold/50-move tracked on the whole system. Andrew should confirm.
### Deferred Items
- `deserialize` trusts the `player` field in a save file rather than recomputing it
from turn order — a corrupt/hand-edited save could desync. App-written saves are
always consistent, so this is robustness-only. Fix: have `DuplicateGame`'s
constructor ignore `entry.player` and use the turn-order default.
- Move log has no round-number column (within spec, but a nicety).
- Spec §4.3 names a `replayTo(n)` primitive; the code uses
`new DuplicateGame(history.slice(0,n))` instead — functionally equivalent,
cosmetic naming mismatch only.
- Networking / AI / position editor — explicitly out of v1 scope (spec §7).
## Context for Resuming Agent
## Important Context
- **The project is DONE for v1 and merged to `main`.** There is nothing half-built.
A resuming agent's job is the manual browser test (#1 above) and then deciding
whether to ship/deploy or extend.
- **`blind_chess` is the sibling project** (`~/bin/blind_chess`) — same inventor,
same homelab conventions, similar shared-engine + view-filter shape. The original
inventor conversation that defines duplicate chess is
`~/bin/blind_chess/USERFILES/4-person-chess.txt`, and Andrew's compass sketch is
`~/bin/blind_chess/USERFILES/4personchess.png`.
- **Provisional rules** are isolated in `src/engine/endgame.ts` and commented
`PROVISIONAL (spec §6)` — grep for it to find every spot a future ruling lands.
- v1 is **local only** — no deploy. Hosting the static `pnpm build` output behind
Caddy is a trivial later option (it is just static files), not done.
### Assumptions Made
- The interactive browser test passing is assumed but unverified — the headless
smoke render confirmed the app mounts and renders all four boards with no console
errors, but no clicks were exercised.
- 27 is the expected test count (all in `src/engine/`; the UI has no test harness
by design — `svelte-check` + manual, same as `blind_chess`).
### Potential Gotchas
- `pnpm test` uses `--passWithNoTests` (vitest 4.x exits 1 on no test files) — a
deliberate scaffold choice; harmless now that tests exist.
- A `.secrets.baseline` file exists for the global `detect-secrets` pre-commit hook
(it flags `pnpm-lock.yaml` SHA-512 integrity hashes as false positives).
- `svelte-check` reports **5 warnings** — all pre-existing Vite-template `tsconfig`
warnings (deprecated `moduleResolution`, missing `composite`). 0 errors. The
warnings are not defects; ignore them or fix the template tsconfig if desired.
- The brainstorming visual-companion mockups for the compass live under
`~/bin/blind_chess/.superpowers/brainstorm/.../content/` (`layout-v6.html` is the
approved layout) — they are in the `blind_chess` repo, not this one.
## Environment State
### Tools/Services Used
- pnpm workspace tooling (Node 22, pnpm 10). `gitea` CLI for push.
- Subagent-driven development for the build (sonnet implementers/reviewers, an opus
final reviewer).
### Active Processes
- None. No dev server left running.
### Environment Variables
- None added or required.
## Related Resources
- Spec: `docs/superpowers/specs/2026-05-19-duplicate-chess-design.md`
- Plan: `docs/superpowers/plans/2026-05-19-duplicate-chess-sandbox.md`
- `DECISIONS.md`, `IDEA.md`
- Repo: https://git.sethpc.xyz/Seth/duplicate_chess (`main` at `5047ad7`)
- Inventor conversation + sketch: `~/bin/blind_chess/USERFILES/4-person-chess.txt`,
`~/bin/blind_chess/USERFILES/4personchess.png`
---
**Security Reminder**: No credentials or secrets are included in this handoff.
+12 -5
View File
@@ -27,12 +27,19 @@ inventor's own point is that it cannot be understood from prose alone.
## Current State
- **Phase:** spec complete; implementation not started.
- **Repo:** `git.sethpc.xyz/Seth/duplicate_chess`.
- **Deploy target:** n/a — runs locally (`pnpm dev`).
- **Phase:** v1 **implemented and merged to `main`** — the engine and the compass
UI are complete. Not yet manually browser-tested.
- **Repo:** `git.sethpc.xyz/Seth/duplicate_chess` (`main`).
- **Deploy target:** n/a — runs locally (`pnpm install && pnpm dev`).
- **Stack:** Vite + Svelte 5 + TypeScript, `chess.js`. Single package; engine in
`src/engine/` (pure, DOM-free, vitest-tested), UI in `src/lib/`.
- **Next:** implementation plan via the writing-plans skill, then build.
`src/engine/` (pure, DOM-free; 27 vitest tests passing), UI in `src/lib/`.
- **Commands:** `pnpm dev` (run) · `pnpm build` · `pnpm test` (engine) ·
`pnpm exec svelte-check --tsconfig ./tsconfig.json` (typecheck).
- **Known follow-ups (not blocking):** interactive browser test still pending (a
human task — `svelte-check` + manual is the design, see spec §8); history scrubbing
is view-only whereas spec §4.3 says truncate-on-move (deviation — confirm which to
keep); `deserialize` trusts the `player` field on replay; move log has no round
numbers. See the latest handoff in `.claude/handoffs/`.
## Conventions