fabro/test/attractor/green_test_vague.dot
2026-04-30 06:48:47 -04:00

473 lines
14 KiB
Text

digraph solitaire {
graph [
goal="Build a terminal-based Klondike Solitaire game in Go with TUI",
rankdir=LR,
default_max_retries=3,
retry_target="impl_setup",
model_stylesheet="
* { model: gpt-5.2-codex;reasoning_effort: medium; }
.hard { model: gpt-5.2-codex;reasoning_effort: high; }
.verify { model: gpt-5.2-codex;reasoning_effort: medium; }
.review { model: gpt-5.2-codex;reasoning_effort: high; }
"
]
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
// Project setup
impl_setup [
shape=box,
timeout=600,
prompt="Read .ai/spec.md. Create Go project structure for solitaire game.
Create:
- go.mod with module name 'solitaire'
- cmd/solitaire/main.go (stub with hello world)
- pkg/game/ directory
- pkg/ui/ directory
- pkg/storage/ directory
- README.md with brief description
Run: go build ./...
Write status.json: outcome=succeeded if project builds, outcome=failed with failure_reason otherwise."
]
verify_setup [
shape=box,
class="verify",
timeout=300,
prompt="Verify project setup was completed correctly.
Run:
1. go build ./...
2. go vet ./...
3. Check that all required directories exist
Write results to .ai/verify_setup.md.
Write status.json: outcome=succeeded if ALL pass, outcome=failed with details."
]
check_setup [shape=diamond, label="Setup OK?"]
// Core types (cards and deck)
impl_core_types [
shape=box,
timeout=1200,
max_retries=2,
prompt="Read .ai/spec.md sections on Game Logic and Package Structure.
Implement card and deck types in pkg/game/:
Create pkg/game/card.go with:
- Card type (Rank, Suit)
- Suit constants (Spades, Hearts, Diamonds, Clubs) with Unicode symbols
- Rank constants (Ace through King)
- String() method for card display
- NewDeck() function that creates standard 52-card deck
- Shuffle() method using crypto/rand for secure shuffling
Create pkg/game/card_test.go with tests for:
- Card string representation
- Deck creation (52 unique cards)
- Shuffle produces different order
Acceptance:
- go build ./...
- go test ./pkg/game/
Write status.json: outcome=succeeded if all criteria pass, outcome=failed with failure_reason otherwise."
]
verify_core_types [
shape=box,
class="verify",
timeout=300,
prompt="Verify core card types implementation.
Run:
1. go build ./...
2. go vet ./...
3. go test ./pkg/game/ -v
4. Check test coverage: go test -cover ./pkg/game/
Write results to .ai/verify_core_types.md.
Write status.json: outcome=succeeded if ALL pass and coverage >70%, outcome=failed with details."
]
check_core_types [shape=diamond, label="Types OK?"]
// Game logic
impl_game_logic [
shape=box,
class="hard",
timeout=1200,
max_retries=2,
prompt="Read .ai/spec.md sections on Game Logic and Core Features.
Read pkg/game/card.go for Card and Deck types.
Implement Klondike Solitaire game logic:
Create pkg/game/game.go with:
- Game struct with:
- Tableau (7 piles, [][]Card)
- Foundation (4 piles, [][]Card)
- Stock pile ([]Card)
- Waste pile ([]Card)
- Move history for undo
- NewGame() initializes properly (7 tableau piles with 1-7 cards, stock gets rest)
- IsWon() checks if all cards in foundations
- GetValidMoves() returns legal moves from current state
Create pkg/game/move.go with:
- Move type (source, destination, card count)
- MoveType constants (TableauToTableau, TableauToFoundation, WasteToTableau, etc.)
- ValidateMove() checks Klondike rules:
- Tableau: descending rank, alternating colors
- Foundation: ascending rank, same suit, starts with Ace
- Kings only to empty tableau
- ExecuteMove() applies move and updates game state
- UndoMove() reverts last move
Create pkg/game/game_test.go with tests for:
- Game initialization (correct card distribution)
- Move validation (legal and illegal moves)
- Move execution and undo
- Win detection
Acceptance:
- go build ./...
- go test ./pkg/game/ -v (all tests pass)
Write status.json: outcome=succeeded if all criteria pass, outcome=failed with failure_reason otherwise."
]
verify_game_logic [
shape=box,
class="verify",
timeout=300,
prompt="Verify game logic implementation.
Run:
1. go build ./...
2. go vet ./...
3. go test ./pkg/game/ -v
4. go test -cover ./pkg/game/ (check for >80% coverage)
Write results to .ai/verify_game_logic.md.
Write status.json: outcome=succeeded if ALL pass with good coverage, outcome=failed with details."
]
check_game_logic [shape=diamond, label="Logic OK?"]
// UI Rendering
impl_ui_render [
shape=box,
timeout=1200,
max_retries=2,
prompt="Read .ai/spec.md sections on User Interface and Input/Output.
Read pkg/game/game.go and pkg/game/card.go for game state types.
Implement TUI rendering using bubbletea framework:
First, add dependencies:
- go get github.com/charmbracelet/bubbletea
- go get github.com/charmbracelet/lipgloss
Create pkg/ui/render.go with:
- RenderGame() function that takes Game state and returns formatted string
- Display layout: foundations (top), tableau (middle), stock/waste (bottom)
- Card display: face-up shows rank+suit, face-down shows \"##\"
- Highlight selected pile/card
- Status line showing move count and messages
Create pkg/ui/tui.go with:
- model struct embedding Game and UI state (selected pile, cursor position)
- Init() bubbletea init function
- Update() stub (minimal, just quit on 'q')
- View() calls RenderGame()
Create basic test in pkg/ui/render_test.go for RenderGame output format.
Acceptance:
- go build ./...
- go test ./pkg/ui/
Write status.json: outcome=succeeded if all criteria pass, outcome=failed with failure_reason otherwise."
]
verify_ui_render [
shape=box,
class="verify",
timeout=300,
prompt="Verify UI rendering implementation.
Run:
1. go build ./...
2. go vet ./...
3. go test ./pkg/ui/ -v
4. Check that bubbletea dependency is properly added to go.mod
Write results to .ai/verify_ui_render.md.
Write status.json: outcome=succeeded if ALL pass, outcome=failed with details."
]
check_ui_render [shape=diamond, label="Render OK?"]
// UI Input
impl_ui_input [
shape=box,
class="hard",
timeout=1200,
max_retries=2,
prompt="Read .ai/spec.md section on User Interface keyboard navigation.
Read pkg/game/game.go, pkg/game/move.go for game operations.
Read pkg/ui/tui.go for existing model struct.
Implement keyboard input handling:
Update pkg/ui/tui.go:
- Extend model with:
- selectedPile (which pile is selected)
- selectedCardIndex (which card in pile)
- message (for feedback)
- Update() handles:
- Arrow keys / hjkl for navigation
- Space/Enter to select source, then destination (execute move)
- 'd' to draw from stock
- 'u' to undo
- 'n' for new game
- 'q' to quit
- Call game.ValidateMove() before executing
- Show feedback messages for invalid moves
- Detect and display win condition
Create pkg/ui/input.go with helper functions for input processing.
Update cmd/solitaire/main.go to:
- Create new game
- Initialize bubbletea program with TUI model
- Run program
Acceptance:
- go build ./cmd/solitaire
- Binary runs and displays game (manual check)
- All keyboard controls work (manual check)
Write status.json: outcome=succeeded if builds and runs, outcome=failed with failure_reason otherwise."
]
verify_ui_input [
shape=box,
class="verify",
timeout=300,
prompt="Verify UI input handling.
Run:
1. go build ./...
2. go vet ./...
3. go test ./...
4. go build ./cmd/solitaire
5. Check that binary exists at ./cmd/solitaire/solitaire
Write results to .ai/verify_ui_input.md.
Write status.json: outcome=succeeded if ALL pass and binary exists, outcome=failed with details."
]
check_ui_input [shape=diamond, label="Input OK?"]
// Persistence
impl_persistence [
shape=box,
timeout=1200,
max_retries=2,
prompt="Read .ai/spec.md section on Game State Management and Input/Output.
Read pkg/game/game.go for Game struct.
Implement save/load functionality:
Create pkg/storage/save.go with:
- SaveGame(game *Game, filename string) error
- Serialize game state to JSON
- Write to file
- LoadGame(filename string) (*Game, error)
- Read from file
- Deserialize JSON to Game struct
- Validate loaded state
- Make sure Game struct fields are exported for JSON marshaling
Update cmd/solitaire/main.go to:
- Add --load flag
- Add 's' key to save game
- Auto-save on quit (to .solitaire-save.json)
- Load on startup if save exists
Create pkg/storage/save_test.go with:
- Test save/load cycle
- Test invalid file handling
Acceptance:
- go build ./...
- go test ./pkg/storage/
- Manual test: save game, quit, restart with --load
Write status.json: outcome=succeeded if all criteria pass, outcome=failed with failure_reason otherwise."
]
verify_persistence [
shape=box,
class="verify",
timeout=300,
prompt="Verify persistence implementation.
Run:
1. go build ./...
2. go vet ./...
3. go test ./pkg/storage/ -v
4. go test ./... (all tests)
Write results to .ai/verify_persistence.md.
Write status.json: outcome=succeeded if ALL pass, outcome=failed with details."
]
check_persistence [shape=diamond, label="Persist OK?"]
// Integration and polish
impl_integration [
shape=box,
timeout=1200,
max_retries=2,
prompt="Read .ai/spec.md for full acceptance criteria.
Read all existing code to understand current state.
Polish and integrate the complete solitaire game:
Tasks:
1. Add command-line flags:
- --draw (1 or 3 cards, default 3)
- --seed (for reproducible games)
- --load (load saved game)
2. Add statistics display on quit (moves, time)
3. Improve error messages and user feedback
4. Add help screen ('h' or '?' key)
5. Ensure all tests pass
6. Update README.md with build instructions and how to play
Create integration test that:
- Initializes game
- Executes a sequence of moves
- Verifies game state
- Tests save/load cycle
Acceptance:
- go build ./...
- go test ./...
- go vet ./...
- ./cmd/solitaire/solitaire runs successfully
- All keyboard commands work
- Game is winnable
Write status.json: outcome=succeeded if all criteria pass, outcome=failed with failure_reason otherwise."
]
verify_integration [
shape=box,
class="verify",
timeout=300,
prompt="Verify integration and completeness.
Run:
1. go build ./...
2. go vet ./...
3. go test ./... -v
4. go test -cover ./...
5. go build ./cmd/solitaire
6. Test all command-line flags work
7. Verify README exists and has instructions
Write results to .ai/verify_integration.md.
Write status.json: outcome=succeeded if ALL pass, outcome=failed with details."
]
check_integration [shape=diamond, label="Integration OK?"]
// Final review
review [
shape=box,
class="review",
timeout=600,
goal_gate=true,
prompt="Read .ai/spec.md in full.
Review the complete solitaire implementation against all requirements.
Verify:
1. Core Gameplay:
- Game initializes correctly (proper card distribution)
- All legal moves accepted
- All illegal moves rejected
- Win condition works
2. User Experience:
- Full keyboard control
- Clear display
- Undo works
- Save/load works
3. Code Quality:
- go build ./... succeeds
- go test ./... succeeds
- go vet ./... clean
- Test coverage >80% for pkg/game/
4. Binary Works:
- Runs with ./cmd/solitaire/solitaire
- All features functional
- Can complete a game
Run full test suite and manual gameplay check.
Write comprehensive review to .ai/final_review.md.
Write status.json: outcome=succeeded if COMPLETE per spec, outcome=failed with specific missing items."
]
check_review [shape=diamond, label="Review OK?"]
// Wire up the graph
start -> impl_setup
impl_setup -> verify_setup
verify_setup -> check_setup
check_setup -> impl_core_types [condition="outcome=succeeded"]
check_setup -> impl_setup [condition="outcome=failed", label="retry"]
impl_core_types -> verify_core_types
verify_core_types -> check_core_types
check_core_types -> impl_game_logic [condition="outcome=succeeded"]
check_core_types -> impl_core_types [condition="outcome=failed", label="retry"]
impl_game_logic -> verify_game_logic
verify_game_logic -> check_game_logic
check_game_logic -> impl_ui_render [condition="outcome=succeeded"]
check_game_logic -> impl_game_logic [condition="outcome=failed", label="retry"]
impl_ui_render -> verify_ui_render
verify_ui_render -> check_ui_render
check_ui_render -> impl_ui_input [condition="outcome=succeeded"]
check_ui_render -> impl_ui_render [condition="outcome=failed", label="retry"]
impl_ui_input -> verify_ui_input
verify_ui_input -> check_ui_input
check_ui_input -> impl_persistence [condition="outcome=succeeded"]
check_ui_input -> impl_ui_input [condition="outcome=failed", label="retry"]
impl_persistence -> verify_persistence
verify_persistence -> check_persistence
check_persistence -> impl_integration [condition="outcome=succeeded"]
check_persistence -> impl_persistence [condition="outcome=failed", label="retry"]
impl_integration -> verify_integration
verify_integration -> check_integration
check_integration -> review [condition="outcome=succeeded"]
check_integration -> impl_integration [condition="outcome=failed", label="retry"]
review -> check_review
check_review -> exit [condition="outcome=succeeded"]
check_review -> impl_integration [condition="outcome=failed", label="fix"]
}