Compare commits

...

6 Commits

Author SHA1 Message Date
claude (duplicate_chess) 294a786336 docs: session handoff — deployed under chess.sethpc.xyz/duplicate/ 2026-05-19 18:14:45 -04:00
claude (duplicate_chess) cab556ede4 docs: record live deploy under chess.sethpc.xyz/duplicate/
CLAUDE.md: phase moves from "local sandbox" to deployed; adds the
operations recipe (tar pipe to /var/www/duplicate-chess on Caddy CT 600).
DECISIONS.md: supersedes the "Deployment deferred" entry with the
chosen architecture — Caddy handle_path serving the static build under
the chess.sethpc.xyz origin, rather than a separate subdomain or a
Fastify static mount.
2026-05-19 18:11:53 -04:00
claude (duplicate_chess) a58139345d fix: page title (was leftover Vite scaffold 'vite-tmp') 2026-05-19 18:09:58 -04:00
claude (duplicate_chess) 8039a8b364 build: set vite base to /duplicate/ for sub-path hosting
Hosted under chess.sethpc.xyz/duplicate/ as a third game-mode card on
blind_chess. With base='/', Vite emitted absolute /assets/... URLs that
would fall through the Caddy /duplicate/* handler and 404 against the
blind_chess Fastify backend. Setting base='/duplicate/' keeps every asset
fetch inside the static handler.
2026-05-19 18:07:23 -04:00
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
6 changed files with 517 additions and 7 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.
@@ -0,0 +1,272 @@
# Handoff: Duplicate Chess deployed under chess.sethpc.xyz/duplicate/
## Session Metadata
- Created: 2026-05-19 18:12:12
- Project: /home/claude/bin/duplicate_chess
- Branch: main (all work committed + pushed)
- Session duration: ~30 minutes (after a fresh-session handoff load + a course
correction — the user's "deploy the new game mode" originally read like a
blind_chess deploy; clarified mid-session to mean duplicate_chess as a 3rd
game-mode card on chess.sethpc.xyz).
### Recent Commits (for context)
- `cab556e` docs: record live deploy under chess.sethpc.xyz/duplicate/
- `a581393` fix: page title (was leftover Vite scaffold 'vite-tmp')
- `8039a8b` build: set vite base to /duplicate/ for sub-path hosting
- `d2adf7f` docs: session handoff — duplicate chess v1 built and merged
- `5047ad7` docs: update CLAUDE.md — v1 implemented and merged
Companion change in the sibling repo: `blind_chess @ fef6dcf`
("feat(client): third landing card linking to duplicate chess") + `33a7cef`
(docs note in blind_chess CLAUDE.md).
## Handoff Chain
- **Continues from**: [2026-05-19-060141-duplicate-chess-v1-built.md](./2026-05-19-060141-duplicate-chess-v1-built.md)
— v1 was code-complete and merged but local-only.
- **Supersedes**: None.
## Current State Summary
`duplicate_chess` v1 is **live at https://chess.sethpc.xyz/duplicate/** as of
2026-05-19. It is served as a static sub-app from `/var/www/duplicate-chess/` on
Caddy CT 600 (192.168.0.185), via a `handle_path /duplicate/*` block inside the
existing `chess.sethpc.xyz` Caddy site. Vite is built with `base: '/duplicate/'`
so every asset URL carries the `/duplicate/` prefix and stays inside the static
handler instead of falling through to the blind_chess Fastify backend on CT 690.
In the sibling `blind_chess` repo, the landing page (`Landing.svelte`) now shows
a 3rd card — "Duplicate Chess (under development)" — beneath the existing
friend/AI cards, linking to `/duplicate/`. That client was rebuilt and rsynced
to CT 690; `blind-chess.service` was restarted to pick up the new bundle.
End-to-end curl evidence:
- `https://chess.sethpc.xyz/duplicate/` → 200, served `index.html` (title now
`duplicate chess`, no longer `vite-tmp`).
- `https://chess.sethpc.xyz/duplicate/assets/index-Cu-6IMcr.js` → 200, 87103 b.
- `https://chess.sethpc.xyz/duplicate/assets/index-p72E9BrX.css` → 200, 4291 b.
- `https://chess.sethpc.xyz/` → 200, blind_chess landing; the JS bundle contains
the strings "Duplicate Chess", "under development", "/duplicate/" and the new
CSS classes `.card-link`, `.badge`, `.open-cue`.
- `https://chess.sethpc.xyz/api/health``{"ok":true,"activeGames":0,"uptime":...}`.
**Not yet verified by a human in a real browser** — Andrew (Seth's dad, the
inventor) is the intended remote tester. v1 interactive testing was already
pending from the prior handoff.
## Codebase Understanding
### Architecture Overview
Three independent deploy units share the `chess.sethpc.xyz` origin:
```
chess.sethpc.xyz {
encode gzip zstd
handle_path /duplicate/* { # ← new, this session
root * /var/www/duplicate-chess # CT 600 (Caddy)
try_files {path} /index.html
file_server
}
handle {
reverse_proxy 192.168.0.245:3000 # CT 690 (blind_chess Fastify)
}
}
```
`handle_path` strips the `/duplicate` prefix before serving, so the on-disk
layout under `/var/www/duplicate-chess/` is at the root (`/index.html`,
`/assets/...`, `/favicon.svg`, `/icons.svg`). With `vite base='/duplicate/'`,
in-bundle asset URLs are `/duplicate/assets/...` — they re-enter the
`handle_path`, get stripped, and resolve. Symmetric and audit-friendly.
### Critical Files
| File | Purpose | Relevance |
|------|---------|-----------|
| `vite.config.ts` | Sets `base: '/duplicate/'` | Required for sub-path hosting; default `/` would 404 on assets |
| `index.html` | Page title fix — `<title>duplicate chess</title>` | Was `vite-tmp` from the Vite scaffold |
| `CLAUDE.md` | Operations + Live URL | Resume-time reference |
| `DECISIONS.md` | Architectural decision recorded (supersedes the "deferred" entry) | The "why" for sub-path over subdomain or Fastify static mount |
| Sibling: `blind_chess/packages/client/src/lib/Landing.svelte` | 3rd card + `.card-link`/`.badge`/`.open-cue` CSS | The visible entry point on chess.sethpc.xyz |
| Caddy: `/etc/caddy/Caddyfile` (lines ~11121124) on CT 600 | `handle_path /duplicate/*` sub-block | Backup at `/etc/caddy/Caddyfile.bak.duplicate-chess-1779228542` |
### Key Patterns Discovered
- **Vite `base` is build-time**, not runtime. It is baked into `index.html` and
bundled asset URLs. Switching it requires a rebuild.
- **CT 600 has no rsync.** Used `tar -cf - . | ssh ... 'cd ... && tar -xf -'`
to push the dist. Could `apt install rsync` later for ergonomics.
- **Caddy `handle_path` vs `handle`**: `handle_path` strips the matched prefix
before downstream directives; `handle` does not. With `base='/duplicate/'` in
Vite, both forms work, but `handle_path` lets the on-disk layout live at the
root of its own dir — cleaner than mirroring the prefix in the filesystem.
## Work Completed
### Tasks Finished
- [x] `vite.config.ts` set to `base: '/duplicate/'`, rebuilt, committed.
- [x] `index.html` title fixed from `vite-tmp` to `duplicate chess`, rebuilt.
- [x] blind_chess Landing.svelte: added 3rd "Duplicate Chess (under development)"
card with `.card-link`, `.badge`, `.open-cue` styles. Built, typechecked
clean (0 errors / 0 warnings), committed, pushed.
- [x] Provisioned `/var/www/duplicate-chess/` on CT 600; tar-piped both builds.
- [x] Backed up Caddyfile, added `handle_path /duplicate/*` sub-block via an
idempotent Python `text.replace` script (failed if the old block was
missing or the new block was already present). `caddy validate`
`Valid configuration`. `systemctl reload caddy` → active.
- [x] Rsynced blind_chess client dist to `/opt/blind-chess/client/dist/` on
CT 690, chowned to `blindchess:blindchess`, restarted the service. The
restart dropped 1 in-memory game (per pre-accepted MVP policy).
- [x] Documentation:
- `~/bin/CLAUDE.md` projects table updated with the live URL.
- `duplicate_chess/CLAUDE.md` got the Operations section + new phase line.
- `duplicate_chess/DECISIONS.md` "deployment deferred" entry superseded.
- `blind_chess/CLAUDE.md` deploy line notes the `/duplicate/*` Caddy block.
### Files Modified
| File | Changes | Rationale |
|------|---------|-----------|
| `vite.config.ts` | `base: '/duplicate/'` + 3-line comment | Sub-path hosting |
| `index.html` | title → `duplicate chess` | Vite scaffold leftover |
| `CLAUDE.md` | live URL, Operations section | Resume-time reference |
| `DECISIONS.md` | supersede the deferred-deploy decision | Architectural record |
| `~/bin/CLAUDE.md` | projects-table row updated | Loaded every session |
| `blind_chess/packages/client/src/lib/Landing.svelte` | 3rd card + CSS | Entry point |
| `blind_chess/CLAUDE.md` | deploy line mentions /duplicate/* | Resume-time reference |
| `/etc/caddy/Caddyfile` on CT 600 | added `handle_path /duplicate/*` block | Routing |
### Decisions Made
| Decision | Options Considered | Rationale |
|----------|-------------------|-----------|
| Serve duplicate as `chess.sethpc.xyz/duplicate/` sub-path | (a) separate subdomain like `duplicate.sethpc.xyz` (b) Fastify static mount on CT 690 | Sub-path keeps the user's mental model "one site, three modes"; Caddy file_server is the right tool; isolation from blind_chess server means redeploys don't drop blind games. |
| Built with Vite `base: '/duplicate/'` | (a) `base: '/'` with Caddy stripping prefix + serving | Building with the right base is simpler and survives any matcher refactor. |
| 3rd landing card as a plain `<a href="/duplicate/">` (not a button calling an API) | (a) iframe inside the SPA (b) source-merge duplicate's components into blind_chess client | Plain anchor is honest about the architecture, no cross-origin/iframe pitfalls; source-merge is excessive for "under development". |
| Landing card visibly tagged "under development" | (a) silent/equivalent | Sets expectations for Andrew; signals it's not at parity with blind/vanilla. |
## Pending Work
## Immediate Next Steps
1. **Send Andrew the URL: https://chess.sethpc.xyz/duplicate/** — and the
blind_chess landing https://chess.sethpc.xyz/ where he can see both as
"modes". Wait for his feedback on the duplicate sandbox UX.
2. **Manual browser test** of both the new 3rd landing card AND duplicate's
interactive flow (still pending from the prior handoff): play a real game,
click a piece, confirm green/grey triple-highlight, move applies to both of
the player's boards, etc.
3. (If Andrew's testing surfaces issues) The known v1 open items in the prior
handoff still apply — scrub semantics, provisional endgame rules. Andrew's
ruling matters for those.
### Blockers/Open Questions
- [ ] **Was the right model chosen for "under development" framing?** Seth said
"incorporate as a 3rd game mode 'under development'." I interpreted that
as a 3rd top-level card on the existing two-card landing (since "mode"
currently means a radio inside each card, and duplicate is 4-player so
can't fit that radio). The card is a plain link out to `/duplicate/`,
not embedded. If Seth wanted an iframe or a deeper integration, redo.
- [ ] All open items from the prior handoff remain open (scrub semantics, the
PROVISIONAL endgame rules, the trust-on-`player` deserialize, …).
### Deferred Items
- **`apt install rsync` on CT 600** — would let future deploys use `rsync`
instead of `tar -cf - | ssh tar -xf -`. The tar idiom worked but is uglier.
- **Caddyfile cleanup** — `caddy validate` warned about pre-existing
`Unnecessary header_up X-Forwarded-For/Host` in *other* blocks (not ours)
and an `unformatted` notice. Not introduced this session; safe to ignore.
- **Visual polish** on the 3rd landing card — only verified via curl + JS/CSS
string grep; not yet eyeballed in a real browser.
- **Open the duplicate sub-app from a deeper path** like `/duplicate/foo`
Caddy's `try_files {path} /index.html` falls back to index.html for any
unmatched path, so any future client-side routing works without changes.
## Context for Resuming Agent
## Important Context
- **Two repos were touched.** `duplicate_chess` got the vite base + title +
docs. `blind_chess` got the new landing card. Both pushed to `main` on
`git.sethpc.xyz/Seth/...`.
- **Two services were touched** at deploy time:
- Caddy on CT 600 (192.168.0.185) — reloaded after Caddyfile edit (graceful).
- blind-chess on CT 690 (192.168.0.245) — full restart, dropped 1 in-memory
game per pre-accepted MVP policy.
- **`chess.local` (the LAN-only blind_chess instance on VDJ-RIG) was NOT
updated** this session. It still serves the previous blind_chess client (no
3rd landing card) and has no `/duplicate/` route. The Caddy edit was on
CT 600 only. If Seth wants parity on chess.local, redeploy the blind_chess
client there and decide whether duplicate is reachable from the LAN at all
(no Caddy block currently exists for `chess.local/duplicate/*`).
- **The phrase "new game mode" caused initial confusion.** I (mistakenly)
spent the opening few tool calls trying to figure out what new thing in
`blind_chess` should be deployed before asking — none of the recent
blind_chess commits described a new mode. Seth clarified the target was
`duplicate_chess`. Future sessions: if a deploy ask seems to mismatch the
current repo's state, look at the sibling `duplicate_chess` repo too.
### Assumptions Made
- That "3rd game mode under development" meant a third top-level landing card,
not an in-blind_chess radio addition (duplicate is 4-player — wouldn't fit
the existing 2-player radio without a much bigger rework).
- That a plain anchor link to `/duplicate/` was the right shape (vs iframe).
- That dropping the 1 active in-memory blind_chess game on restart was OK
(matches the pre-accepted MVP policy in DECISIONS.md).
### Potential Gotchas
- **`vite-tmp` was the page title** at first deploy (`a581393` fixed it, but
there was a ~2-minute window where it shipped). If Andrew tests during a
redeploy window, mention it.
- **Caddy `handle_path` strips the prefix** — anyone reading `/var/www/duplicate-chess/`
layout might expect a `duplicate/` subdir; there isn't one (files live at
the root of that dir).
- **Files in `/var/www/duplicate-chess/` are owned by uid/gid 1001**
(the `claude` uid on steel141, passed through via tar), readable to all.
Worked because Caddy needs only read; chown to `caddy:caddy` or `root:root`
would be tidier.
- **`localhost` on VDJ-RIG (where chess.local lives) hits a Caddy 502** —
documented in the prior handoff. Doesn't affect this deploy (we touched CT
600's Caddy, not the rig's).
## Environment State
### Tools/Services Used
- `gitea` CLI for pushes (both repos).
- `ssh root@192.168.0.185` (Caddy CT 600) — Caddyfile edit + Caddy reload.
- `ssh root@192.168.0.245` (CT 690) — client dist rsync + systemctl restart.
- `tar -cf - | ssh ... tar -xf -` for content transfer (no rsync on CT 600).
- `pnpm` (workspace in blind_chess, single-pkg in duplicate_chess).
### Active Processes
- `caddy.service` on CT 600 — reloaded.
- `blind-chess.service` on CT 690 — restarted (1 active game dropped).
- No dev servers left running locally.
### Environment Variables
- None added or required.
## Related Resources
- Caddyfile backup: `/etc/caddy/Caddyfile.bak.duplicate-chess-1779228542` on CT 600.
- Local backups: `duplicate_chess/.backup/vite.config.ts.*.bak` and
`blind_chess/packages/client/src/lib/.backup/Landing.svelte.*.bak`.
- Live URLs:
- https://chess.sethpc.xyz/ — blind_chess landing (3rd card visible).
- https://chess.sethpc.xyz/duplicate/ — duplicate_chess sandbox.
- https://chess.sethpc.xyz/api/health — blind_chess API health.
- Sibling-repo companion commit: `blind_chess @ fef6dcf` (landing card)
+ `33a7cef` (CLAUDE.md doc note).
---
**Security Reminder**: No credentials or secrets in this handoff.
+30 -5
View File
@@ -27,12 +27,37 @@ 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, merged, and deployed** (2026-05-19) as a third
game-mode card ("under development") on `chess.sethpc.xyz`. The engine and the
compass UI are complete; not yet manually browser-tested by Seth.
- **Repo:** `git.sethpc.xyz/Seth/duplicate_chess` (`main`).
- **Live URL:** https://chess.sethpc.xyz/duplicate/ — static bundle on Caddy CT 600
at `/var/www/duplicate-chess/`. Independent of the blind_chess server (CT 690);
duplicate redeploys never restart blind_chess. Vite is built with
`base: '/duplicate/'`; the Caddy `chess.sethpc.xyz` block has a
`handle_path /duplicate/*` that strips the prefix and serves static files.
- **Local dev:** `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/`.
## Operations
- **Health:** `curl https://chess.sethpc.xyz/duplicate/` returns the served `index.html`.
- **Redeploy** (after a `pnpm build`):
```
cd dist && tar -cf - . | ssh root@192.168.0.185 \
'cd /var/www/duplicate-chess && rm -rf assets favicon.svg icons.svg index.html && tar -xf -'
```
No Caddy reload needed for content changes; `file_server` serves live from disk.
- **Caddy config:** the `chess.sethpc.xyz` block in `/etc/caddy/Caddyfile` on CT 600
(192.168.0.185). The `handle_path /duplicate/*` sub-block governs this app.
## Conventions
+1 -1
View File
@@ -27,5 +27,5 @@ Format: `YYYY-MM-DD: <decision> — <why>`
2026-05-19: AI opponents — deferred; the sandbox is operator-driven.
2026-05-19: Free position editor — rejected for v1; play-from-start + history scrubbing keeps every shown position reachable by legal play, preserving the "every board is real chess" invariant.
2026-05-19: Counter-rotating pieces upright on the diamonds — rejected; pieces rotate with their board so each player's army faces their seat (the point of the compass).
2026-05-19: Deployment behind Caddy — deferred; v1 runs locally, the static build can be hosted later trivially.
2026-05-19: Deployment behind Caddy — deferred; v1 runs locally, the static build can be hosted later trivially. **Superseded 2026-05-19 (later same day):** deployed under `chess.sethpc.xyz/duplicate/` as a 3rd "under development" card on the blind_chess landing. Vite built with `base: '/duplicate/'`; Caddy `handle_path /duplicate/*` strips the prefix and serves `/var/www/duplicate-chess/` on CT 600. Chosen over a separate subdomain so Andrew sees both games from one URL, and over a Fastify static mount so duplicate redeploys never restart blind_chess.
2026-05-19: A separate "dual view" of the on-move player's two boards — rejected; the compass is the whole UI, with the triple-highlight happening directly on it.
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vite-tmp</title>
<title>duplicate chess</title>
</head>
<body>
<div id="app"></div>
+4
View File
@@ -3,5 +3,9 @@ import { svelte } from '@sveltejs/vite-plugin-svelte'
// https://vite.dev/config/
export default defineConfig({
// Hosted as a sub-app under chess.sethpc.xyz/duplicate/ alongside blind_chess.
// Setting `base` makes Vite emit asset URLs with the /duplicate/ prefix so they
// stay inside the Caddy static handler instead of falling through to blind_chess.
base: '/duplicate/',
plugins: [svelte()],
})