clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

spec baseline + requested change

Dami committed acf8a8d
commit
acf8a8da2f2dc698c41ab4119250ce8275326b2d
parent
33947d643339b67e7e2d7157e305d3bad2811efb
author
Dami <dami.etoile@gmail.com>
31 files changed, +1220 -0
Aopenspec/changes/archive/.gitkeep1+
Aopenspec/changes/refactor-root-tui-model/.openspec.yaml2+
Aopenspec/changes/refactor-root-tui-model/design.md119++++++++++++++++++++++++++++++
Aopenspec/changes/refactor-root-tui-model/proposal.md27+++++++
Aopenspec/changes/refactor-root-tui-model/specs/root-tui-architecture/spec.md72++++++++++++++++++
Aopenspec/changes/refactor-root-tui-model/tasks.md41++++++++++
Aopenspec/config.yaml20+++++
Aopenspec/specs/catalog-and-registry/spec.md32++++++++
Aopenspec/specs/cli-and-session-flow/spec.md33++++++++
Aopenspec/specs/create-and-seeded-play/spec.md29+++++++
Aopenspec/specs/daily-and-weekly/spec.md29+++++++
Aopenspec/specs/fillomino/spec.md46++++++++++++
Aopenspec/specs/hashiwokakero/spec.md46++++++++++++
Aopenspec/specs/hitori/spec.md46++++++++++++
Aopenspec/specs/jsonl-export/spec.md25++++++
Aopenspec/specs/lightsout/spec.md46++++++++++++
Aopenspec/specs/netwalk/spec.md46++++++++++++
Aopenspec/specs/nonogram/spec.md46++++++++++++
Aopenspec/specs/nurikabe/spec.md46++++++++++++
Aopenspec/specs/pdf-export/spec.md25++++++
Aopenspec/specs/persistence-and-stats/spec.md25++++++
Aopenspec/specs/rippleeffect/spec.md46++++++++++++
Aopenspec/specs/shared-game-runtime/spec.md25++++++
Aopenspec/specs/shikaku/spec.md46++++++++++++
Aopenspec/specs/spellpuzzle/spec.md46++++++++++++
Aopenspec/specs/sudoku/spec.md46++++++++++++
Aopenspec/specs/sudokurgb/spec.md46++++++++++++
Aopenspec/specs/takuzu/spec.md46++++++++++++
Aopenspec/specs/takuzuplus/spec.md46++++++++++++
Aopenspec/specs/themes-and-ui/spec.md25++++++
Aopenspec/specs/wordsearch/spec.md46++++++++++++
A openspec/changes/archive/.gitkeep +1 -0
@@ -0,0 +1 @@
1+
A openspec/changes/refactor-root-tui-model/.openspec.yaml +2 -0
A openspec/changes/refactor-root-tui-model/design.md +119 -0
@@ -0,0 +1,119 @@
1+## Context2+3+The `app` package contains the root Bubble Tea model for PuzzleTea. It already uses a useful `screenModel` and `screenAction` pattern: menu-like screens update local component state and return actions that the root model applies. However, the root model still owns several distinct concerns at once:4+5+- The current route and cached screen instances.6+- Window sizing and active screen resizing.7+- Global key behavior for normal screens, active puzzles, pending generation, and pending export.8+- Active puzzle lifecycle, including spawn start/completion, save/load, completion persistence, and read-only weekly review.9+- Workflow setup for create, normal mode selection, daily, seeded, weekly, export, help, stats, and theme flows.10+- Shell state such as notices, debug rendering, theme/help toggles, store/config dependencies, and the shared spinner.11+12+The refactor should keep the public Bubble Tea surface stable while making those ownership boundaries explicit enough that future UI flows can be added without expanding `model.Update` or scattering session persistence rules.13+14+## Goals / Non-Goals15+16+**Goals:**17+18+- Keep `model.Update` focused on top-level dispatch: async messages, global shell keys, active game delegation, screen updates, and action application.19+- Make route/screen management responsible for current route, cached screen models, window sizing, active screen lookup, initialization, and resize behavior.20+- Make session lifecycle code the single owner of game spawning, spawn cancellation, spawn completion, saved-record import, active game update, completion persistence, and save-on-exit.21+- Keep screen models dependency-light: screens should continue to emit typed actions instead of directly reaching into the store, config, session controller, or root model internals.22+- Preserve current behavior for all app flows.23+- Add focused tests around routing/session behavior that could regress during the refactor.24+25+**Non-Goals:**26+27+- No changes to game package APIs, `game.Gamer`, registry/catalog behavior, persistence schema, or CLI flags.28+- No visual redesign of menus, screens, exports, or puzzle views.29+- No replacement of Bubble Tea or Bubbles components.30+- No broad package split unless a smaller `app`-internal type cannot express the boundary cleanly.31+32+## Decisions33+34+### Keep One Bubble Tea Root Model35+36+The app should continue exposing a single root Bubble Tea model. Internally, the root can delegate to smaller app-owned types, but it should remain the integration point for Bubble Tea messages and views.37+38+Alternative considered: make every app screen a full independent Bubble Tea model with store/config/session dependencies. That would reduce the root's visible size, but it would scatter persistence and lifecycle behavior across many screens. The current `screenAction` pattern is better: screens own component interaction, while app-level behavior stays centralized.39+40+### Introduce an App-Internal Route/Screen Manager41+42+Route and screen mechanics should be isolated from workflow behavior. A route/screen manager can own:43+44+- Current `viewState`.45+- Cached `map[viewState]screenModel`.46+- Active screen lookup.47+- Screen initialization through the existing registry.48+- Window dimensions and active-screen resize.49+- Route transitions that only change display state.50+51+The manager should not know how to create puzzles, save games, export packs, or apply theme changes. It should receive enough shell state to construct screens, then return updated screen state to the root.52+53+Alternative considered: leave these methods on `model` but move them into more files. That would make files shorter without changing ownership, so it would not materially improve reasoning.54+55+### Keep Screens as Intent Emitters56+57+Screens should continue returning `screenAction` values from `Update`. Actions should remain typed app intents, not generic strings. This keeps screen tests focused on interaction and allows root/controller tests to cover app behavior.58+59+Where actions currently perform substantial workflow setup, the action should become a small adapter into the appropriate controller. For example, mode selection should delegate session start details instead of constructing all spawn metadata inline.60+61+Alternative considered: have screens call controller methods directly. That would make individual actions smaller but would require injecting app dependencies into screens and would weaken the current separation.62+63+### Make Session Lifecycle the Owner of Active Game State64+65+The session controller should own:66+67+- Starting normal, Elo, and seeded generation.68+- Cancelling pending generation.69+- Ignoring stale spawn completions.70+- Activating generated or imported games.71+- Applying help/window-size messages to newly activated games.72+- Updating active games.73+- Persisting completed puzzles.74+- Saving or clearing games on escape/quit.75+- Handling read-only game opens.76+77+Workflow handlers may decide *which* puzzle to open or generate, but once that decision is made they should enter session code through higher-level methods rather than duplicating spawn request construction and save/resume rules.78+79+Alternative considered: keep workflow-specific spawn setup in handler files. That keeps local context near each flow, but the duplicated pattern of "check record, maybe resume, otherwise spawn, then persist" makes session behavior harder to audit.80+81+### Split Global Key Handling by Route Ownership82+83+Global key handling should route to the domain that owns the current state:84+85+- Pending generation: session controller handles escape/quit behavior and spawn cancellation.86+- Pending export: export controller/handler handles escape/quit behavior and export cancellation.87+- Active game: session controller handles save-on-escape, abandon-on-quit, reset, help toggle propagation, debug update, and weekly advancement entry points.88+- Normal screens: shell/global keys handle quit, debug toggle, and full-help toggle.89+90+This keeps `handleGlobalKey` from accumulating per-route workflow details.91+92+Alternative considered: keep a single root `handleGlobalKey` switch. It is straightforward today, but it is already mixing shell, export, session, and weekly behavior.93+94+### Preserve Behavior Before Improving Shape Further95+96+The refactor should be incremental and behavior-preserving. It is acceptable to leave some workflow-specific logic on the root temporarily if moving it would enlarge the diff or weaken tests. The important outcome is clearer ownership for the root update loop and session lifecycle.97+98+## Risks / Trade-offs99+100+- **Risk: Moving state between structs can accidentally drop screen component state.** → Keep the existing screen cache behavior and add tests around returning to screens after resize/navigation where practical.101+- **Risk: Session controller methods can become another large object.** → Limit it to active game/spawn/save/load lifecycle. Keep create/daily/seed/weekly selection logic outside unless it directly affects session invariants.102+- **Risk: Behavior-preserving refactors can hide regressions in keyboard handling.** → Add focused tests for escape/quit/reset/help/debug paths in generating, export-running, active-game, and normal-screen states.103+- **Risk: Export remains large and may not fit the same controller shape immediately.** → Treat export as a separate workflow boundary and avoid mixing it into session lifecycle.104+- **Risk: Over-abstracting routes could obscure simple app flows.** → Prefer small concrete types and typed methods over generic event buses or reflection-based routing.105+106+## Migration Plan107+108+1. Add tests that pin the current high-risk behavior before moving ownership.109+2. Extract route/screen management with no behavior changes.110+3. Move pending generation and active game key behavior into session-oriented methods.111+4. Move duplicated spawn/open/resume behavior behind session-oriented entry points where the call sites become clearer.112+5. Re-run `just fmt`, `just lint`, and `just test-short`.113+114+Rollback is straightforward because there are no data migrations or public API changes: revert the refactor commits if behavior diverges.115+116+## Open Questions117+118+- Should create/daily/seed/weekly decision logic live in one deterministic-play workflow helper, or remain in their current files while calling improved session APIs?119+- Should export get a small controller in this change, or only enough cleanup to remove export-running special cases from root global key handling?
A openspec/changes/refactor-root-tui-model/proposal.md +27 -0
@@ -0,0 +1,27 @@
1+## Why2+3+The root Bubble Tea model has accumulated several responsibilities: route dispatch, screen caching, global key handling, active game lifecycle, spawn/export cancellation, persistence, and workflow-specific setup for create/daily/seeded/weekly play. This makes changes to TUI flow harder to reason about and raises the risk of regressions when adding new screens or session behavior.4+5+## What Changes6+7+- Reorganize the root TUI model so `Update` remains a thin dispatcher rather than the owner of every workflow.8+- Clarify ownership boundaries for route/screen management, global shell state, active game/session lifecycle, and workflow-specific orchestration.9+- Consolidate active game opening, spawning, resuming, saving, and completion persistence behind session-oriented APIs.10+- Preserve existing user-facing behavior for menus, create flow, seeded play, daily/weekly play, export, help, debug, theme selection, persistence, and active puzzle controls.11+- Add focused tests around the refactored routing/session behavior where current coverage depends on root model internals.12+13+## Capabilities14+15+### New Capabilities16+- `root-tui-architecture`: Internal architecture requirements for the root Bubble Tea model, screen routing, workflow ownership, and behavior-preserving refactors.17+18+### Modified Capabilities19+20+None. This change is intended to preserve existing spec-level behavior.21+22+## Impact23+24+- Affected code: `app/model.go`, `app/update.go`, `app/view.go`, `app/screen_core.go`, `app/session_controller.go`, and workflow files such as `app/handle_create.go`, `app/handle_seed.go`, `app/handle_daily.go`, `app/weekly.go`, and `app/export.go`.25+- Affected tests: focused `app` package tests for update routing, screen actions, session lifecycle, spawn cancellation/completion, save-on-exit, and weekly advancement.26+- APIs: no public CLI, game registry, persistence schema, or game package API changes are planned.27+- Dependencies: no new runtime dependencies are planned.
A openspec/changes/refactor-root-tui-model/specs/root-tui-architecture/spec.md +72 -0
@@ -0,0 +1,72 @@
1+## ADDED Requirements2+3+### Requirement: Root update dispatch remains behavior-preserving4+The root TUI model SHALL preserve existing user-facing behavior while organizing `Update` as a top-level dispatcher for app messages, global shortcuts, active game updates, screen updates, and screen actions.5+6+#### Scenario: Existing app flows remain available7+- **WHEN** a user navigates through main menu, play menu, create, continue, daily, weekly, seeded play, export, options, help, stats, theme selection, or an active puzzle8+- **THEN** the app SHALL expose the same commands, navigation outcomes, persistence behavior, and view transitions as before the refactor9+10+#### Scenario: Root update delegates by message category11+- **WHEN** the root model receives async completion messages, window-size messages, key messages, screen messages, or active game messages12+- **THEN** dispatch SHALL route each message to the component that owns the relevant behavior without requiring screens to mutate root model internals directly13+14+### Requirement: Route and screen management is isolated15+The app SHALL isolate route and screen mechanics from workflow behavior so current route, cached screens, screen initialization, active screen lookup, window dimensions, and active-screen resizing are managed through a dedicated app-internal boundary.16+17+#### Scenario: Screen cache survives refactor18+- **WHEN** a screen is updated, resized, left, or re-entered according to the existing app flow19+- **THEN** the app SHALL preserve the same screen state retention or reinitialization behavior that existed before the refactor20+21+#### Scenario: Route management does not own workflows22+- **WHEN** a route transition requires creating, resuming, spawning, exporting, saving, applying a theme, or updating persistent state23+- **THEN** the route/screen management boundary SHALL delegate that workflow behavior to the owning controller or handler24+25+### Requirement: Screens emit typed app intents26+App screens SHALL remain dependency-light interaction models that update local component state and emit typed app intents for root-level behavior.27+28+#### Scenario: Screen action applies app behavior29+- **WHEN** a screen interaction requires opening another route, starting generation, submitting export, changing theme, opening help, or loading a record30+- **THEN** the screen SHALL return a typed action or command that is applied by the root app layer or its controllers31+32+#### Scenario: Screens avoid direct app dependency ownership33+- **WHEN** a screen is constructed or updated34+- **THEN** it SHALL NOT require direct ownership of store, config, session lifecycle, or persistence dependencies unless an existing behavior cannot be preserved otherwise35+36+### Requirement: Session lifecycle has a single owner37+The app SHALL centralize active game lifecycle behavior behind session-oriented code.38+39+#### Scenario: Starting a generated game40+- **WHEN** normal mode selection, create flow, seeded play, daily play, or weekly play starts puzzle generation41+- **THEN** session lifecycle code SHALL own generation state, cancellation, stale completion handling, game activation, save record creation, and transition into game view42+43+#### Scenario: Resuming or reviewing a saved game44+- **WHEN** the user resumes a saved game or opens a read-only weekly review45+- **THEN** session lifecycle code SHALL own import, read-only handling, active game ID setup, completion-saved state, help/window-size propagation, and transition into game view46+47+#### Scenario: Leaving an active game48+- **WHEN** the user exits or quits an active game49+- **THEN** session lifecycle code SHALL own save-state persistence, status updates, active game cleanup, and return-state behavior50+51+#### Scenario: Completing an active game52+- **WHEN** an active game becomes solved53+- **THEN** session lifecycle code SHALL persist final save data and completed status once, preserving existing error notice behavior when persistence fails54+55+### Requirement: Global key behavior is owned by active domain56+Global keyboard behavior SHALL be routed to the app domain that owns the current state.57+58+#### Scenario: Pending generation keys59+- **WHEN** the app is showing pending puzzle generation and the user presses escape or quit60+- **THEN** session lifecycle code SHALL preserve existing cancellation, return-route, and quit behavior61+62+#### Scenario: Pending export keys63+- **WHEN** the app is showing pending export and the user presses escape or quit64+- **THEN** export workflow code SHALL preserve existing cancellation, return-route, and quit behavior65+66+#### Scenario: Active game keys67+- **WHEN** the app is showing an active puzzle and the user presses escape, quit, reset, full-help, debug, or enter on a solved weekly puzzle68+- **THEN** active game/session handling SHALL preserve existing save, abandon, reset, help propagation, debug, and weekly advancement behavior69+70+#### Scenario: Normal screen keys71+- **WHEN** the app is showing a non-game, non-pending screen and the user presses global quit, debug, or full-help keys72+- **THEN** shell-level handling SHALL preserve existing quit, debug toggle, and full-help toggle behavior
A openspec/changes/refactor-root-tui-model/tasks.md +41 -0
@@ -0,0 +1,41 @@
1+## 1. Baseline Behavior Coverage2+3+- [ ] 1.1 Add or update focused tests for root `Update` dispatch of async spawn/export completion, window resize, active game messages, screen messages, and screen actions.4+- [ ] 1.2 Add or update tests for global key behavior in normal screens, pending generation, pending export, and active game states.5+- [ ] 1.3 Add or update tests for session lifecycle behavior: spawn cancellation, stale spawn completion, generated game activation, saved-record import, read-only review, save-on-exit, and solved-game completion persistence.6+- [ ] 1.4 Add or update tests that pin existing screen cache and resize behavior across representative route transitions.7+8+## 2. Route and Screen Boundary9+10+- [ ] 2.1 Introduce an app-internal route/screen management boundary for current `viewState`, cached screens, active screen lookup, screen initialization, window dimensions, and resize behavior.11+- [ ] 2.2 Move `activeScreen`, `initScreen`, `resizeActiveScreen`, and window-size handling behind the route/screen boundary without changing behavior.12+- [ ] 2.3 Update root model initialization to construct and use the route/screen boundary while preserving initial main-menu and initial-game behavior.13+- [ ] 2.4 Keep `screenModel` and `screenAction` semantics intact and verify existing screen tests still exercise typed app intents.14+15+## 3. Session Lifecycle Boundary16+17+- [ ] 3.1 Expand session-oriented methods so generated game start, pending generation state, cancellation, stale completion handling, and activation are owned by session lifecycle code.18+- [ ] 3.2 Move saved-record import, read-only review setup, active game ID setup, help/window-size propagation, and completion-saved state behind session lifecycle code.19+- [ ] 3.3 Move save-on-exit, abandon-on-quit, active game cleanup, and solved-game completion persistence behind session lifecycle code.20+- [ ] 3.4 Update create, mode-select, seed, daily, and weekly call sites to use the clarified session lifecycle entry points where doing so reduces duplicated spawn/open/resume rules.21+22+## 4. Global Key and Workflow Dispatch23+24+- [ ] 4.1 Refactor root global key handling so pending generation keys delegate to session lifecycle behavior.25+- [ ] 4.2 Refactor root global key handling so pending export keys delegate to export workflow behavior.26+- [ ] 4.3 Refactor active-game key behavior so save, quit, reset, help propagation, debug updates, and weekly advancement route through the owning session/workflow code.27+- [ ] 4.4 Keep normal-screen shell keys for quit, debug toggle, and full-help toggle behavior-preserving and easy to audit.28+29+## 5. Root Model Cleanup30+31+- [ ] 5.1 Reduce `model.Update` to a clear top-level dispatch flow: app-level messages, global keys, active game delegation, screen update, action application.32+- [ ] 5.2 Move state type definitions or helper methods into files that match their ownership boundary, avoiding file-only churn that does not clarify responsibilities.33+- [ ] 5.3 Remove obsolete wrappers or duplicated helper paths created during the refactor.34+- [ ] 5.4 Review `app/model.go`, `app/update.go`, `app/screen_core.go`, and `app/session_controller.go` for remaining responsibility leaks and document any intentionally deferred cleanup.35+36+## 6. Validation37+38+- [ ] 6.1 Run `just fmt`.39+- [ ] 6.2 Run `just lint`.40+- [ ] 6.3 Run `just test-short`.41+- [ ] 6.4 Manually review the change against `root-tui-architecture` requirements and confirm there are no user-facing behavior changes.
A openspec/config.yaml +20 -0
A openspec/specs/catalog-and-registry/spec.md +32 -0
@@ -0,0 +1,32 @@
1+## Purpose2+Define the separation between pure catalog metadata and concrete built-in game runtime registration.3+4+## Requirements5+6+### Requirement: Pure Catalog Index7+The catalog package SHALL index puzzle definitions, aliases, daily metadata, variants, and legacy modes without importing concrete game implementations.8+9+#### Scenario: Build catalog10+- **WHEN** definitions are passed to the catalog builder11+- **THEN** duplicate canonical names, duplicate aliases, invalid Elo values, missing daily modes, and invalid legacy mode targets are rejected12+13+### Requirement: Concrete Runtime Registry14+The registry package MUST compose built-in game entries, imports, help text, print adapters, variants, and legacy mode spawners.15+16+#### Scenario: Resolve game name17+- **WHEN** a canonical game name or alias is supplied18+- **THEN** the registry returns the concrete entry for that built-in game19+20+### Requirement: Variant First Creation21+Puzzle creation SHALL prefer registered variants with target Elo, while preserving legacy named modes as compatibility aliases to variant Elo presets.22+23+#### Scenario: Resolve legacy mode24+- **WHEN** a legacy mode title is supplied to CLI creation25+- **THEN** PuzzleTea resolves it to the target variant and preset Elo rather than treating modes as the primary creation model26+27+### Requirement: Daily Eligibility28+The registry SHALL expose daily-capable entries from metadata and skip duplicate game IDs so daily selection has at most one concrete spawner per game.29+30+#### Scenario: Build daily entries31+- **WHEN** daily entries are requested32+- **THEN** the registry returns seeded spawners tied to registered daily mode metadata
A openspec/specs/cli-and-session-flow/spec.md +33 -0
@@ -0,0 +1,33 @@
1+## Purpose2+Describe PuzzleTea command entry points and session lifecycle behavior.3+4+## Requirements5+6+### Requirement: Root Command And Direct Launch7+The CLI SHALL load active configuration, resolve root-level aliases, and either launch the interactive menu or dispatch to the requested command.8+9+#### Scenario: Launch menu without arguments10+- **WHEN** the user runs `puzzletea`11+- **THEN** PuzzleTea starts the interactive Bubble Tea application using the configured store and theme12+13+#### Scenario: Use root aliases14+- **WHEN** the user supplies root aliases such as `--new` or `--continue`15+- **THEN** PuzzleTea routes to the equivalent command flow16+17+### Requirement: New Continue List And Test Commands18+The CLI MUST expose `new`, `continue`, `list`, and `test` command flows for creating games, resuming named saves, listing saves, and running smokeable game startup checks.19+20+#### Scenario: Resume by name21+- **WHEN** the user runs `puzzletea continue <name>`22+- **THEN** PuzzleTea imports the saved game record and opens the session with completion state preserved23+24+#### Scenario: List saved games25+- **WHEN** the user runs `puzzletea list`26+- **THEN** PuzzleTea lists resumable saved games and includes abandoned games only when requested27+28+### Requirement: Session Lifecycle29+Interactive sessions SHALL autosave game state to SQLite, update status on completion or abandonment, and return to the configured application state after spawn or import failures.30+31+#### Scenario: Complete a puzzle32+- **WHEN** a game reports solved during an active session33+- **THEN** PuzzleTea records completion, preserves the save payload, and applies progression metadata
A openspec/specs/create-and-seeded-play/spec.md +29 -0
@@ -0,0 +1,29 @@
1+## Purpose2+Describe the interactive Create workflow, variant selection, Elo targeting, and deterministic seed behavior.3+4+## Requirements5+6+### Requirement: Create Uses Variants And Elo7+The Create screen SHALL present selectable variant leaves, require a valid target Elo from 0 through 3000, and spawn the selected variant using Elo generation.8+9+#### Scenario: Generate from one checked variant10+- **WHEN** exactly one variant leaf is checked and the user generates11+- **THEN** PuzzleTea uses that variant, the entered Elo, and the optional seed if supplied12+13+#### Scenario: Generate from multiple checked variants14+- **WHEN** multiple variant leaves are checked15+- **THEN** PuzzleTea chooses one checked leaf uniformly and disables deterministic seed entry for that intentionally random selection16+17+### Requirement: Seeded Create Resume18+The Create workflow MUST resume an existing deterministic save when the same seed, game, variant, and Elo identify a prior record.19+20+#### Scenario: Reuse create seed21+- **WHEN** a single selected variant has a nonblank seed matching an existing deterministic record22+- **THEN** PuzzleTea imports and resumes that record instead of creating a duplicate23+24+### Requirement: Global Seed Selection25+The `--set-seed` flow SHALL deterministically select game, legacy seeded mode, name, and puzzle content from a seed string.26+27+#### Scenario: Launch by global seed28+- **WHEN** the user runs `puzzletea new --set-seed <seed>`29+- **THEN** PuzzleTea rejects explicit game arguments and resumes or creates the deterministic puzzle for that seed
A openspec/specs/daily-and-weekly/spec.md +29 -0
A openspec/specs/fillomino/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Fillomino built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Fillomino SHALL be registered as a built-in game with canonical description "Grow the numbered regions to their exact sizes.", aliases `polyomino, regions`, variants `Fillomino (default 1300 Elo)`, and daily legacy modes `easy 6x6, medium 8x8, hard 10x10`.8+9+#### Scenario: Resolve Fillomino10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Fillomino entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Fillomino MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Fillomino by Elo17+- **WHEN** the user selects the Fillomino variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Fillomino puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Fillomino SHALL preserve legacy named modes as compatibility presets that map to the Fillomino variant and preset Elo values: Mini 5x5 (300 Elo), Easy 6x6 (700 Elo), Medium 8x8 (1300 Elo), Hard 10x10 (2000 Elo), Expert 12x12 (2600 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Fillomino mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Fillomino variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Fillomino runtime MUST let players grow numbered regions so every connected region has area equal to its number, with matching adjacent regions merged and contradictory region sizes rejected by solved-state checks.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Fillomino reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Fillomino SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard cursor entry is required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Fillomino38+- **WHEN** a saved Fillomino payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Fillomino print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Fillomino45+- **WHEN** Fillomino is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/hashiwokakero/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Hashiwokakero built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Hashiwokakero SHALL be registered as a built-in game with canonical description "Connect the islands with bridges.", aliases `hashi, bridges`, variants `Hashiwokakero (default 1300 Elo)`, and daily legacy modes `easy 9x9, medium 7x7`.8+9+#### Scenario: Resolve Hashiwokakero10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Hashiwokakero entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Hashiwokakero MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Hashiwokakero by Elo17+- **WHEN** the user selects the Hashiwokakero variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Hashiwokakero puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Hashiwokakero SHALL preserve legacy named modes as compatibility presets that map to the Hashiwokakero variant and preset Elo values: Easy 7x7 (250 Elo), Medium 7x7 (500 Elo), Hard 7x7 (800 Elo), Easy 9x9 (700 Elo), Medium 9x9 (1100 Elo), Hard 9x9 (1500 Elo), Easy 11x11 (1300 Elo), Medium 11x11 (1700 Elo), Hard 11x11 (2100 Elo), Easy 13x13 (1900 Elo), Medium 13x13 (2400 Elo), Hard 13x13 (2900 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Hashiwokakero mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Hashiwokakero variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Hashiwokakero runtime MUST let players connect islands with horizontal or vertical bridges so each island reaches its required bridge count, bridges never cross, at most two bridges connect a pair, and the final bridge graph is connected.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Hashiwokakero reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Hashiwokakero SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard bridge editing is required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Hashiwokakero38+- **WHEN** a saved Hashiwokakero payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Hashiwokakero print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Hashiwokakero45+- **WHEN** Hashiwokakero is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/hitori/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Hitori built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Hitori SHALL be registered as a built-in game with canonical description "Shade the cells to eliminate duplicates.", aliases `none`, variants `Hitori (default 1800 Elo)`, and daily legacy modes `easy, medium`.8+9+#### Scenario: Resolve Hitori10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Hitori entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Hitori MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Hitori by Elo17+- **WHEN** the user selects the Hitori variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Hitori puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Hitori SHALL preserve legacy named modes as compatibility presets that map to the Hitori variant and preset Elo values: Mini (300 Elo), Easy (700 Elo), Medium (1300 Elo), Tricky (1800 Elo), Hard (2300 Elo), Expert (2800 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Hitori mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Hitori variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Hitori runtime MUST let players shade cells so each row and column has no duplicate unshaded numbers, shaded cells are never orthogonally adjacent, and all unshaded cells remain connected.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Hitori reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Hitori SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard shading controls are required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Hitori38+- **WHEN** a saved Hitori payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Hitori print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Hitori45+- **WHEN** Hitori is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/jsonl-export/spec.md +25 -0
A openspec/specs/lightsout/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Lights Out built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Lights Out SHALL be registered as a built-in game with canonical description "Turn the lights off.", aliases `lights`, variants `Lights Out (default 2000 Elo)`, and daily legacy modes `medium, hard`.8+9+#### Scenario: Resolve Lights Out10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Lights Out entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Lights Out MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Lights Out by Elo17+- **WHEN** the user selects the Lights Out variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Lights Out puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Lights Out SHALL preserve legacy named modes as compatibility presets that map to the Lights Out variant and preset Elo values: Easy (0 Elo), Medium (1000 Elo), Hard (2000 Elo), Extreme (3000 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Lights Out mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Lights Out variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Lights Out runtime MUST let players toggle a selected light and its orthogonal neighbors, and the puzzle is solved only when every light is off.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Lights Out reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Lights Out SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard toggling is required, and mouse click-to-toggle support MUST be available.36+37+#### Scenario: Resume saved Lights Out38+- **WHEN** a saved Lights Out payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+Lights Out MUST remain excluded from printable export until a print adapter is provided.43+44+#### Scenario: Export Lights Out45+- **WHEN** Lights Out is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/netwalk/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Netwalk built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Netwalk SHALL be registered as a built-in game with canonical description "Rotate network tiles until every computer connects to the server.", aliases `network`, variants `Netwalk (default 1500 Elo)`, and daily legacy modes `easy 7x7, medium 9x9`.8+9+#### Scenario: Resolve Netwalk10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Netwalk entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Netwalk MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Netwalk by Elo17+- **WHEN** the user selects the Netwalk variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Netwalk puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Netwalk SHALL preserve legacy named modes as compatibility presets that map to the Netwalk variant and preset Elo values: Mini 5x5 (400 Elo), Easy 7x7 (900 Elo), Medium 9x9 (1500 Elo), Hard 11x11 (2200 Elo), Expert 13x13 (2800 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Netwalk mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Netwalk variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Netwalk runtime MUST let players rotate network tiles until every computer is connected to the server through matching pipe edges and there are no dangling required connections in the solved network.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Netwalk reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Netwalk SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard rotation is required, and mouse click-to-rotate support MUST be available.36+37+#### Scenario: Resume saved Netwalk38+- **WHEN** a saved Netwalk payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Netwalk print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Netwalk45+- **WHEN** Netwalk is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/nonogram/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Nonogram built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Nonogram SHALL be registered as a built-in game with canonical description "Fill the cells to match tomographic hints.", aliases `none`, variants `Nonogram (default 1600 Elo)`, and daily legacy modes `standard, classic`.8+9+#### Scenario: Resolve Nonogram10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Nonogram entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Nonogram MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Nonogram by Elo17+- **WHEN** the user selects the Nonogram variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Nonogram puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Nonogram SHALL preserve legacy named modes as compatibility presets that map to the Nonogram variant and preset Elo values: Mini (100 Elo), Pocket (450 Elo), Teaser (800 Elo), Standard (1000 Elo), Classic (1300 Elo), Tricky (1600 Elo), Large (1900 Elo), Grand (2200 Elo), Epic (2600 Elo), Massive (2900 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Nonogram mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Nonogram variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Nonogram runtime MUST let players mark filled and empty cells so every row and column exactly matches its tomographic run-length hints.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Nonogram reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Nonogram SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard marking is required, and mouse drag support MUST be available.36+37+#### Scenario: Resume saved Nonogram38+- **WHEN** a saved Nonogram payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Nonogram print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Nonogram45+- **WHEN** Nonogram is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/nurikabe/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Nurikabe built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Nurikabe SHALL be registered as a built-in game with canonical description "Split the land while keeping one connected sea.", aliases `islands, sea`, variants `Nurikabe (default 1400 Elo)`, and daily legacy modes `easy, medium`.8+9+#### Scenario: Resolve Nurikabe10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Nurikabe entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Nurikabe MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Nurikabe by Elo17+- **WHEN** the user selects the Nurikabe variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Nurikabe puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Nurikabe SHALL preserve legacy named modes as compatibility presets that map to the Nurikabe variant and preset Elo values: Mini (300 Elo), Easy (800 Elo), Medium (1400 Elo), Hard (2100 Elo), Expert (2700 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Nurikabe mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Nurikabe variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Nurikabe runtime MUST let players build numbered islands with exact island sizes, keep islands separated orthogonally, avoid 2x2 sea blocks, and maintain one connected sea.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Nurikabe reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Nurikabe SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard cell editing is required, and mouse drag support MUST be available.36+37+#### Scenario: Resume saved Nurikabe38+- **WHEN** a saved Nurikabe payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Nurikabe print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Nurikabe45+- **WHEN** Nurikabe is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/pdf-export/spec.md +25 -0
A openspec/specs/persistence-and-stats/spec.md +25 -0
A openspec/specs/rippleeffect/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Ripple Effect built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Ripple Effect SHALL be registered as a built-in game with canonical description "Fill the cages with sequential numbers without violating ripple distance.", aliases `ripple`, variants `Ripple Effect (default 1500 Elo)`, and daily legacy modes `easy 6x6, medium 7x7, hard 8x8`.8+9+#### Scenario: Resolve Ripple Effect10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Ripple Effect entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Ripple Effect MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Ripple Effect by Elo17+- **WHEN** the user selects the Ripple Effect variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Ripple Effect puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Ripple Effect SHALL preserve legacy named modes as compatibility presets that map to the Ripple Effect variant and preset Elo values: Mini 5x5 (400 Elo), Easy 6x6 (900 Elo), Medium 7x7 (1500 Elo), Hard 8x8 (2200 Elo), Expert 9x9 (2800 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Ripple Effect mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Ripple Effect variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Ripple Effect runtime MUST let players place digits in rooms so each room contains each digit once and matching digits in any row or column are separated by more cells than the digit value.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Ripple Effect reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Ripple Effect SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard digit entry is required for rooms and cursor movement.36+37+#### Scenario: Resume saved Ripple Effect38+- **WHEN** a saved Ripple Effect payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Ripple Effect print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Ripple Effect45+- **WHEN** Ripple Effect is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/shared-game-runtime/spec.md +25 -0
A openspec/specs/shikaku/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Shikaku built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Shikaku SHALL be registered as a built-in game with canonical description "Divide the grid into rectangles with set sizes.", aliases `rectangles`, variants `Shikaku (default 1400 Elo)`, and daily legacy modes `easy 7x7, medium 8x8`.8+9+#### Scenario: Resolve Shikaku10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Shikaku entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Shikaku MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Shikaku by Elo17+- **WHEN** the user selects the Shikaku variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Shikaku puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Shikaku SHALL preserve legacy named modes as compatibility presets that map to the Shikaku variant and preset Elo values: Mini 5x5 (300 Elo), Easy 7x7 (800 Elo), Medium 8x8 (1400 Elo), Hard 10x10 (2100 Elo), Expert 12x12 (2700 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Shikaku mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Shikaku variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Shikaku runtime MUST let players partition the grid into rectangles, each rectangle containing exactly one clue and having area equal to that clue.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Shikaku reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Shikaku SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard rectangle editing is required, and mouse drag support MUST be available.36+37+#### Scenario: Resume saved Shikaku38+- **WHEN** a saved Shikaku payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Shikaku print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Shikaku45+- **WHEN** Shikaku is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/spellpuzzle/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Spell Puzzle built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Spell Puzzle SHALL be registered as a built-in game with canonical description "Connect letters to fill a crossword with bonus anagrams.", aliases `spell, spellpuzzle`, variants `Spell Puzzle (default 1500 Elo)`, and daily legacy modes `beginner`.8+9+#### Scenario: Resolve Spell Puzzle10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Spell Puzzle entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Spell Puzzle MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Spell Puzzle by Elo17+- **WHEN** the user selects the Spell Puzzle variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Spell Puzzle puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Spell Puzzle SHALL preserve legacy named modes as compatibility presets that map to the Spell Puzzle variant and preset Elo values: Beginner (0 Elo), Easy (600 Elo), Medium (1500 Elo), Hard (2400 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Spell Puzzle mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Spell Puzzle variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Spell Puzzle runtime MUST let players connect wheel letters to fill crossword board words and track valid bonus anagrams without requiring bonus words for puzzle completion.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Spell Puzzle reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Spell Puzzle SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard word entry is required, and mouse drag support MUST be available.36+37+#### Scenario: Resume saved Spell Puzzle38+- **WHEN** a saved Spell Puzzle payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Spell Puzzle print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Spell Puzzle45+- **WHEN** Spell Puzzle is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/sudoku/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Sudoku built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Sudoku SHALL be registered as a built-in game with canonical description "Fill the 9x9 grid following sudoku rules.", aliases `none`, variants `Sudoku (default 1800 Elo)`, and daily legacy modes `easy, medium`.8+9+#### Scenario: Resolve Sudoku10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Sudoku entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Sudoku MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Sudoku by Elo17+- **WHEN** the user selects the Sudoku variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Sudoku puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Sudoku SHALL preserve legacy named modes as compatibility presets that map to the Sudoku variant and preset Elo values: Beginner (0 Elo), Easy (600 Elo), Medium (1200 Elo), Hard (1800 Elo), Expert (2400 Elo), Diabolical (3000 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Sudoku mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Sudoku variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Sudoku runtime MUST let players fill a 9x9 grid so every row, column, and 3x3 box contains digits 1 through 9 exactly once while preserving givens.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Sudoku reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Sudoku SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard digit entry is required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Sudoku38+- **WHEN** a saved Sudoku payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Sudoku print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Sudoku45+- **WHEN** Sudoku is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/sudokurgb/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Sudoku RGB built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Sudoku RGB SHALL be registered as a built-in game with canonical description "Fill the board with RGB symbols so each row, column, and 3x3 box contains {1,1,1,2,2,2,3,3,3}. [1,2,3] maps to [triangle,square,filled]. Inspired by Sudoku Ripeto.", aliases `rgb sudoku, ripeto, sudoku ripeto`, variants `Sudoku RGB (default 1800 Elo)`, and daily legacy modes `easy, medium`.8+9+#### Scenario: Resolve Sudoku RGB10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Sudoku RGB entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Sudoku RGB MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Sudoku RGB by Elo17+- **WHEN** the user selects the Sudoku RGB variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Sudoku RGB puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Sudoku RGB SHALL preserve legacy named modes as compatibility presets that map to the Sudoku RGB variant and preset Elo values: Beginner (0 Elo), Easy (600 Elo), Medium (1200 Elo), Hard (1800 Elo), Expert (2400 Elo), Diabolical (3000 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Sudoku RGB mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Sudoku RGB variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Sudoku RGB runtime MUST let players fill a 9x9 grid with the three RGB symbols so each row, column, and 3x3 box contains exactly three of each symbol while preserving givens.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Sudoku RGB reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Sudoku RGB SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard symbol entry is required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Sudoku RGB38+- **WHEN** a saved Sudoku RGB payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Sudoku RGB print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Sudoku RGB45+- **WHEN** Sudoku RGB is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/takuzu/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Takuzu built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Takuzu SHALL be registered as a built-in game with canonical description "Fill the grid with filled and empty. No 3 in a row.", aliases `binairo, binary`, variants `Takuzu (default 1600 Elo)`, and daily legacy modes `medium, tricky`.8+9+#### Scenario: Resolve Takuzu10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Takuzu entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Takuzu MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Takuzu by Elo17+- **WHEN** the user selects the Takuzu variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Takuzu puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Takuzu SHALL preserve legacy named modes as compatibility presets that map to the Takuzu variant and preset Elo values: Beginner (300 Elo), Easy (700 Elo), Medium (1100 Elo), Tricky (1600 Elo), Hard (2100 Elo), Very Hard (2500 Elo), Extreme (2900 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Takuzu mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Takuzu variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Takuzu runtime MUST let players fill an even-sized grid with two symbols, avoid three identical symbols in a row or column, balance each row and column, and avoid duplicate completed rows or columns.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Takuzu reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Takuzu SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard symbol entry is required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Takuzu38+- **WHEN** a saved Takuzu payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Takuzu print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Takuzu45+- **WHEN** Takuzu is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/takuzuplus/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Takuzu+ built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Takuzu+ SHALL be registered as a built-in game with canonical description "Fill the grid with filled and empty using some relational clues. No 3 in a row.", aliases `takuzu plus, binario+, binario plus`, variants `Takuzu+ (default 1600 Elo)`, and daily legacy modes `medium, tricky`.8+9+#### Scenario: Resolve Takuzu+10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Takuzu+ entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Takuzu+ MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Takuzu+ by Elo17+- **WHEN** the user selects the Takuzu+ variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Takuzu+ puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Takuzu+ SHALL preserve legacy named modes as compatibility presets that map to the Takuzu+ variant and preset Elo values: Beginner (300 Elo), Easy (700 Elo), Medium (1100 Elo), Tricky (1600 Elo), Hard (2100 Elo), Very Hard (2500 Elo), Extreme (2900 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Takuzu+ mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Takuzu+ variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Takuzu+ runtime MUST enforce Takuzu rules plus relation clues, where equals clues require adjacent cells to match and x clues require adjacent cells to differ.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Takuzu+ reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Takuzu+ SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard symbol entry is required, and mouse click-to-focus support MUST be available.36+37+#### Scenario: Resume saved Takuzu+38+- **WHEN** a saved Takuzu+ payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Takuzu+ print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Takuzu+45+- **WHEN** Takuzu+ is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game
A openspec/specs/themes-and-ui/spec.md +25 -0
A openspec/specs/wordsearch/spec.md +46 -0
@@ -0,0 +1,46 @@
1+## Purpose2+Document the shipped Word Search built-in game behavior.3+4+## Requirements5+6+### Requirement: Registry Metadata7+Word Search SHALL be registered as a built-in game with canonical description "Find the hidden words in a letter grid.", aliases `words, wordsearch, ws`, variants `Word Search (default 1500 Elo)`, and daily legacy modes `easy 10x10`.8+9+#### Scenario: Resolve Word Search10+- **WHEN** the registry resolves the canonical name or any alias11+- **THEN** it returns the Word Search entry with help text, import behavior, variant metadata, and legacy mode compatibility12+13+### Requirement: Variant Elo Creation14+Word Search MUST support the current variant plus target Elo creation path, using the variant default Elo when no explicit target is supplied.15+16+#### Scenario: Spawn Word Search by Elo17+- **WHEN** the user selects the Word Search variant and a target Elo from 0 through 300018+- **THEN** PuzzleTea spawns a deterministic Word Search puzzle and records target, actual, and confidence metadata when generation reports it19+20+### Requirement: Legacy Mode Compatibility21+Word Search SHALL preserve legacy named modes as compatibility presets that map to the Word Search variant and preset Elo values: Easy 10x10 (600 Elo), Medium 15x15 (1500 Elo), Hard 20x20 (2400 Elo).22+23+#### Scenario: Use legacy mode title24+- **WHEN** the user supplies a legacy Word Search mode title through CLI or deterministic daily metadata25+- **THEN** PuzzleTea resolves it to the Word Search variant and the registered preset Elo26+27+### Requirement: Puzzle Rules28+The Word Search runtime MUST let players select hidden dictionary words in straight lines on the grid and solve only when all listed words have been found.29+30+#### Scenario: Check solved state31+- **WHEN** the player fills the board or word state32+- **THEN** Word Search reports solved only when all rule constraints are satisfied33+34+### Requirement: Save Load And Interaction35+Word Search SHALL serialize enough state for resume/import, reset to its initial puzzle, expose debug and full-help data, and support its shipped interaction model. Keyboard selection is required, and mouse drag support MUST be available.36+37+#### Scenario: Resume saved Word Search38+- **WHEN** a saved Word Search payload is imported39+- **THEN** the restored game preserves givens, player entries, cursor/selection state where applicable, and solved-state behavior40+41+### Requirement: Print Export Support42+The Word Search print adapter SHALL render puzzle and solution data for JSONL-to-PDF workflows.43+44+#### Scenario: Export Word Search45+- **WHEN** Word Search is included in a JSONL or PDF export flow46+- **THEN** PuzzleTea follows the registered print support behavior for that game