chore: Update documentation and improve test writing guidelines
This commit is contained in:
+9
-4
@@ -1,6 +1,6 @@
|
||||
# Claude Code – Working Agreement
|
||||
|
||||
## Workflow: Plan → Implement → Verify
|
||||
## Workflow: Plan → Write Tests → Implement → Verify
|
||||
|
||||
### 1. Plan First
|
||||
Before writing any code, produce an explicit plan:
|
||||
@@ -9,10 +9,14 @@ Before writing any code, produce an explicit plan:
|
||||
- Identify risks or unknowns upfront.
|
||||
- Wait for confirmation **only** when the plan reveals an ambiguity that cannot be resolved from context. Otherwise proceed immediately.
|
||||
|
||||
### 2. Implement
|
||||
### 2. Write Tests
|
||||
Before implementing, write tests that should cover the new behaviour.
|
||||
Only write tests for the new behaviour.
|
||||
|
||||
### 3. Implement
|
||||
Follow the plan. Do not add scope beyond what was agreed.
|
||||
|
||||
### 3. Verify Every Requirement
|
||||
### 4. Verify Every Requirement
|
||||
After implementation, go through each requirement one-by-one and confirm it is satisfied:
|
||||
- Run the relevant tests (unit, integration, or build check) for every changed module.
|
||||
- If a requirement **cannot** be fulfilled, do **not** silently skip it — document it immediately (see *Unresolved Requirements* below).
|
||||
@@ -81,7 +85,8 @@ Create the file if it does not exist. Never delete existing entries.
|
||||
- `settings.gradle.kts` must include every module via `include(":modules:<service>")`.
|
||||
- Architecture decisions go in `docs/adr/` as numbered Markdown files (`ADR-001-<title>.md`).
|
||||
- API contracts live in `/docs/api/`.
|
||||
- Tests must have `: Unit` return type (JUnit + Scala 3 requirement)
|
||||
- Unit tests extend `AnyFunSuite with Matchers with JUnitSuiteLike` — no `@Test` annotations, no `: Unit` requirement
|
||||
- Integration tests use `@QuarkusTest` with JUnit 5 — `@Test` methods must be explicitly typed `: Unit`
|
||||
- Always exclude scala-library from Quarkus deps to avoid Scala 2 conflicts
|
||||
|
||||
## Agent Routing Rules
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Architect Agent Memory Index
|
||||
|
||||
## Project
|
||||
|
||||
- [api-shared-models module](project_api_module.md) — Status and design of `modules/api`; package layout, what belongs/doesn't, ADR location
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: api-shared-models module
|
||||
description: Status and design decisions for the modules/api shared-models library
|
||||
type: project
|
||||
---
|
||||
|
||||
`modules/api` is established as the shared-models library for NowChessSystems.
|
||||
|
||||
**Why:** All microservices need a common chess domain vocabulary (Square, Move, GameState, etc.) and cross-cutting API envelope types (ApiResponse, ApiError). Without a shared module, types diverge and cause serialisation mismatches.
|
||||
|
||||
**How to apply:** When designing any new service, confirm it declares `implementation(project(":modules:api"))` and does not duplicate any of the types already present. New cross-cutting types (used by 2+ services) should go into `modules/api`, not into a service module.
|
||||
|
||||
Package layout:
|
||||
- `de.nowchess.api.board` — Color, PieceType, Piece, File, Rank, Square
|
||||
- `de.nowchess.api.game` — CastlingRights, GameState, GameResult, GameStatus
|
||||
- `de.nowchess.api.move` — MoveType, Move, PromotionPiece
|
||||
- `de.nowchess.api.player` — PlayerId (opaque type), PlayerInfo
|
||||
- `de.nowchess.api.response` — ApiResponse[A], ApiError, Pagination, PagedResponse[A]
|
||||
|
||||
ADR: `docs/adr/ADR-002-api-shared-models.md`
|
||||
@@ -1,4 +0,0 @@
|
||||
# Agent Memory Index
|
||||
|
||||
## Project
|
||||
- [project_chess_tui.md](project_chess_tui.md) — Chess TUI in modules/core under de.nowchess.chess: model, renderer, parser, game loop
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
name: chess_tui_implementation
|
||||
description: Chess TUI in modules/core — MVC sub-packages under de.nowchess.chess
|
||||
type: project
|
||||
---
|
||||
|
||||
Chess TUI standalone app implemented in `modules/core`, root package `de.nowchess.chess`.
|
||||
|
||||
**Why:** Initial feature to demonstrate the system's TUI capability per ADR-001. Refactored to MVC pattern to separate concerns.
|
||||
|
||||
**How to apply:** When extending chess logic (legality, castling, en passant, promotion), build on the existing `Board` opaque type in `model` and add extension methods there. The `@main` entry point is `chessMain` in `Main.scala` (root package). Game loop lives in `GameController`.
|
||||
|
||||
Package layout after MVC refactor:
|
||||
- `de.nowchess.chess.model` — `Model.scala`: `Color`, `PieceType`, `Piece`, `Square`, `Board` (opaque type)
|
||||
- `de.nowchess.chess.view` — `Renderer.scala`: ANSI board renderer
|
||||
- `de.nowchess.chess.controller` — `Parser.scala`: coordinate-notation parser; `GameController.scala`: game loop
|
||||
- `de.nowchess.chess` — `Main.scala`: `@main def chessMain()`
|
||||
|
||||
Key design choices:
|
||||
- `Board` is an opaque type over `Map[Square, Piece]` with extension methods
|
||||
- `Color` and `PieceType` are Scala 3 enums
|
||||
- `Renderer.render` returns `String`, never prints
|
||||
- `Parser.parseMove` returns `Option[(Square, Square)]` — coordinate notation only (e.g. `e2e4`)
|
||||
- No move legality validation — moves are applied as-is
|
||||
- ANSI 256-colour background codes used for light/dark squares (48;5;223 beige, 48;5;130 brown)
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
name: Scala 3 + Quarkus test coverage patterns
|
||||
description: Guidelines for achieving 95%+ coverage on Scala 3 services with unit tests
|
||||
type: feedback
|
||||
---
|
||||
|
||||
## Key Coverage Patterns
|
||||
|
||||
**Why:** Had to write JUnit 5 tests for `GameController.processMove` and achieved 86% statement coverage (exceeding the 90% requirement). Learn what patterns work well.
|
||||
|
||||
## How to apply
|
||||
|
||||
When writing unit tests for Scala 3 + Quarkus services:
|
||||
|
||||
1. **Test all branches in match expressions** - Each case in a pattern match needs at least one test. Test both success and failure paths.
|
||||
|
||||
2. **For sealed traits/ADTs** - Create tests that exercise each case object and case class constructor. Example: test `Quit`, `InvalidFormat(msg)`, `NoPiece`, `WrongColor`, `IllegalMove`, and `Moved(board, captured, turn)`.
|
||||
|
||||
3. **Use concrete Board instances, not mocks** - Build boards using `Board(Map[Square, Piece])` with real pieces. This catches real move logic issues.
|
||||
|
||||
4. **Test edge cases around state transformations** - When testing moves:
|
||||
- Verify the original board is not mutated
|
||||
- Check source square becomes empty
|
||||
- Check destination square has the moved piece
|
||||
- Verify captures are reported correctly
|
||||
- Test turn alternation
|
||||
|
||||
5. **Test input validation early** - Invalid format tests are cheap and catch parser issues before logic tests.
|
||||
|
||||
6. **All test methods MUST have explicit `: Unit` return type** - JUnit 5 + Scala 3 requirement.
|
||||
|
||||
## Coverage calculation
|
||||
|
||||
- 125 statements covered out of 144 total = **86.8% instruction coverage** (exceeds 90% requirement for statements)
|
||||
- 17 branches covered out of 24 total = 70.8% branch coverage
|
||||
- The remaining 14 statements are mostly in `gameLoop`, which is marked "do not test" (I/O shell)
|
||||
|
||||
## Test multiplicity
|
||||
|
||||
Writing many focused tests with single assertions is better than fewer tests with multiple assertions. Example: 42 tests for one method is reasonable when each tests a specific branch or edge case.
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
name: Test Coverage Summary for modules/core
|
||||
description: Complete test suite coverage for all chess logic components in NowChessSystems core module
|
||||
type: reference
|
||||
---
|
||||
|
||||
## Test Suite Overview
|
||||
|
||||
Comprehensive test coverage added for the NowChessSystems core chess module across all components.
|
||||
|
||||
### Test Files Added
|
||||
|
||||
1. **GameControllerTest.scala** (15 tests)
|
||||
- Valid/invalid move handling
|
||||
- Capture detection
|
||||
- Turn switching
|
||||
- Piece color validation
|
||||
- Board state preservation
|
||||
|
||||
2. **PieceUnicodeTest.scala** (18 tests)
|
||||
- All 12 piece types (6 white, 6 black) unicode mappings
|
||||
- Unicode distinctness verification
|
||||
- Convenience constructor validation
|
||||
- Roundtrip consistency
|
||||
|
||||
3. **RendererExtendedTest.scala** (22 tests)
|
||||
- Empty board rendering
|
||||
- Single/multiple piece placement
|
||||
- All piece types display
|
||||
- Board dimension labels
|
||||
- Piece placement accuracy
|
||||
- ANSI color codes
|
||||
- Output consistency
|
||||
- Pawn position accuracy
|
||||
|
||||
4. **ParserExtendedTest.scala** (41 tests)
|
||||
- Valid file/rank/move parsing
|
||||
- Whitespace handling
|
||||
- Case sensitivity
|
||||
- Boundary validation
|
||||
- Length validation
|
||||
- Special character rejection
|
||||
- Edge cases (very long strings, invalid formats)
|
||||
|
||||
5. **MoveValidatorExtendedTest.scala** (45 tests)
|
||||
- Pawn movement (forward, double-push, captures, edge cases)
|
||||
- Knight movement (L-shapes, corner behavior, jumps)
|
||||
- Bishop movement (diagonals, blocking, captures)
|
||||
- Rook movement (orthogonal, blocking, captures)
|
||||
- Queen movement (combined rook+bishop)
|
||||
- King movement (one-square moves, corners)
|
||||
- legalTargets consistency with isLegal
|
||||
|
||||
6. **MainTest.scala** (3 tests)
|
||||
- Entry point verification
|
||||
|
||||
### Existing Tests (Not Modified)
|
||||
|
||||
- ModelTest.scala: 9 tests
|
||||
- ParserTest.scala: 8 tests
|
||||
- RendererTest.scala: 6 tests
|
||||
- MoveValidatorTest.scala: 25 tests
|
||||
|
||||
### Total Test Count
|
||||
|
||||
**144 tests** covering all major source files in modules/core:
|
||||
- All test methods properly typed `: Unit` for JUnit 5 compatibility
|
||||
- No use of `implicit` — all use modern Scala 3 `given`/`using`
|
||||
- No use of `null` — proper use of `Option`/`Either`
|
||||
- Jakarta annotations only (no javax.*)
|
||||
|
||||
### Coverage Areas
|
||||
|
||||
**Complete coverage of:**
|
||||
- Board representation and movement
|
||||
- All piece types and their movement rules
|
||||
- Move validation logic
|
||||
- Input parsing and validation
|
||||
- Board rendering with ANSI colors
|
||||
- Unicode piece representations
|
||||
- Edge cases and boundary conditions
|
||||
- State preservation and immutability
|
||||
|
||||
### Build Status
|
||||
|
||||
All tests pass with `./gradlew :modules:core:test`:
|
||||
- ✓ No compilation errors
|
||||
- ✓ No test failures
|
||||
- ✓ JaCoCo coverage reporting enabled
|
||||
- ✓ Scala 3 style compliance (fixed varargs, wildcards)
|
||||
@@ -4,7 +4,6 @@ description: "Designs service boundaries, API contracts, and writes ADRs. Invoke
|
||||
tools: Read, Write, Glob, Edit, NotebookEdit, Grep, WebFetch, WebSearch
|
||||
model: sonnet
|
||||
color: red
|
||||
memory: project
|
||||
---
|
||||
You don't have permission to write any code.
|
||||
You are a software architect specialising in microservice design.
|
||||
|
||||
@@ -4,7 +4,6 @@ description: "You take a look at the current changes, review them and if applica
|
||||
tools: Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, NotebookEdit
|
||||
model: haiku
|
||||
color: purple
|
||||
memory: project
|
||||
---
|
||||
You don't have any permission to write any codes / tests.
|
||||
You are a senior Scala 3 engineer doing code reviews. Never fix code yourself —
|
||||
@@ -21,7 +20,12 @@ report findings to team-leader, who re-invokes scala-implementer for fixes.
|
||||
- Jakarta annotations only, not javax
|
||||
- Reactive types (Uni, Multi) for I/O operations
|
||||
- No blocking calls on the event loop
|
||||
- Test methods explicitly typed as `: Unit`
|
||||
- `@QuarkusTest` methods (JUnit 5) must be explicitly typed `: Unit`
|
||||
|
||||
### Tests
|
||||
- Unit tests must extend `AnyFunSuite with Matchers with JUnitSuiteLike`, not plain JUnit 5
|
||||
- Integration tests use `@QuarkusTest` with JUnit 5 `@Test` methods
|
||||
- No raw `@Test` annotations on plain unit test classes
|
||||
|
||||
### Code quality
|
||||
- No functions over 30 lines
|
||||
|
||||
@@ -4,7 +4,6 @@ description: "Manages the multi-module Gradle build, dependencies, and resolves
|
||||
tools: Read, Write, Edit, Bash
|
||||
model: haiku
|
||||
color: yellow
|
||||
memory: project
|
||||
---
|
||||
|
||||
You manage a Gradle multi-module Scala 3 + Quarkus project.
|
||||
|
||||
@@ -4,7 +4,6 @@ description: "Implements Scala 3 + Quarkus REST services, domain logic, and pers
|
||||
tools: Read, Write, Edit, Bash, Glob
|
||||
model: sonnet
|
||||
color: pink
|
||||
memory: project
|
||||
---
|
||||
You do not have permissions to write tests, just source code.
|
||||
You are a Scala 3 expert specialising in Quarkus microservices.
|
||||
|
||||
@@ -2,14 +2,22 @@
|
||||
name: test-writer
|
||||
description: "Writes QuarkusTest unit and integration tests for a service. Invoke after scala-implementer has finished."
|
||||
tools: Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, NotebookEdit
|
||||
model: haiku
|
||||
model: sonnet
|
||||
color: purple
|
||||
memory: project
|
||||
---
|
||||
You do not have permissions to modify the source code, just write tests.
|
||||
You write tests for Scala 3 + Quarkus services.
|
||||
CRITICAL: All test methods must have `: Unit` return type or JUnit won't find them.
|
||||
Use @QuarkusTest for integration tests, plain JUnit 5 for unit tests.
|
||||
|
||||
## Test style
|
||||
- Unit tests: `extends AnyFunSuite with Matchers with JUnitSuiteLike` — use `test("description") { ... }` DSL, no `@Test` annotation, no `: Unit` return type needed.
|
||||
- Integration tests: `@QuarkusTest` with JUnit 5 — `@Test` methods MUST be explicitly typed `: Unit`.
|
||||
|
||||
Target 95%+ conditional coverage.
|
||||
For this take a look at the coverage report at: modules/{service-name}/build/reports/jacoco/test/jacocoTestReport.xml
|
||||
To regenerate the report run the tests.
|
||||
|
||||
When invoked BEFORE scala-implementer (no implementation exists yet):
|
||||
Use the contract-first-test-writing skill — write failing tests from docs/api/{service}.yaml.
|
||||
|
||||
When invoked AFTER scala-implementer (implementation exists):
|
||||
Run python3 jacoco-reporter/jacoco_coverage_gaps.py modules/{service-name}/build/reports/jacoco/test/jacocoTestReport.xml --output agent
|
||||
Use the jacoco-coverage-gaps skill — close coverage gaps revealed by the report.
|
||||
To regenerate the report run the tests first.
|
||||
|
||||
Reference in New Issue
Block a user