Write the test that rules out the most wrong implementations.
Source runs full-1, rep-2 and rep-1 at tdd-experiment c3dd988
Contents
Search and validation
What it changes: The check. Next test kills surviving mutants.
BronzeBest overallrank sum 14.5
SilverMost cost effectiveM 477,347, M_io 448,873
BronzeCheapest708,760 weighted tokens
BronzeMost consistent designC 0.38, p 0.464
One method of the study, from runs full-1 and rep-2. The survey build is the method's single build in run full-1. A replicate is one of its builds in run rep-2, which ran in a different batch. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
How it builds code
The procedure supplied to the agents. Indented lines run under the line above them.
Family: Search and validation. Idea: Write the test that rules out the most wrong implementations. What it changes in the search: The check. Next test kills surviving mutants.
repeat per requirement until none is open:1. Finish one requirement with red-green-refactor cycles as usual.2. Run PIT or mutmut on the code that requirement touched.3. List surviving mutants. Set aside those no input could tell apart.4. Keep survivors that change an output a requirement names.5. Write the smallest requirement-level test that kills the most kept survivors.6. Take expected values from the requirement. Never from the current code's output.7. If the test fails on real code treat it as red and fix the code.8. Rerun mutation until no kept survivor remains. Then take the next requirement.
Once means one agent runs the steps. Repeat per unit means one agent per unit until no unit is open. Throughout means the rule joins every prompt. For up to n starts means separate attempts with the best kept. The harness does means the harness runs the step without an agent. If names the event that starts a stage, and with adds a rule borrowed from another method. Steps are quoted from args.json with their numbers. Tag: verified.
Figure 19.1
Stage flow of Most informative next test
Steps 1 to 8.Lane: Agent.
Loop: repeat per requirement, back to Steps 1 to 8.
1 stages from the run facts, each checked against its block of the steps above. Details and notes are in the stage table. Tag: recomputed.
Text version: Stage flow of Most informative next test
Steps 1 to 8.Lane: Agent.
Loop: repeat per requirement, back to Steps 1 to 8.
Stages
Each stage as the run facts list it. Runs as and Note are quoted verbatim and Steps repeats the steps above. Tag: verified.
Stage
Runs as
Steps
Details
Note
Steps 1 to 8
repeat per requirement until none is open:
1. Finish one requirement with red-green-refactor cycles as usual. 2. Run PIT or mutmut on the code that requirement touched. 3. List surviving mutants. Set aside those no input could tell apart. 4. Keep survivors that change an output a requirement names. 5. Write the smallest requirement-level test that kills the most kept survivors. 6. Take expected values from the requirement. Never from the current code's output. 7. If the test fails on real code treat it as red and fix the code. 8. Rerun mutation until no kept survivor remains. Then take the next requirement.
unit requirement
Mutation testing is ./run.sh mutate. It mutates all of src/, newest file first. It runs the method's own tests without the starter's Example tests.
Survey build
One build in run full-1.
15/15Functional mark
9E
708,760Cost to completion
477,347M
448,873M_io
9PMD findings
noAlignment
Replicates
Repeat builds: 5 in run rep-2.
1.000Median adjusted mutation, over 5 replicates in rep-2
3Median classes, over 5 replicates in rep-2
1,068,727Median cost to completion, over 5 replicates in rep-2
16Median CQP, over 5 replicates in rep-2
M against Classic greedy TDD: U 17, Holm p 1.000; adjusted mutation against Classic greedy TDD: U 15, Holm p 1.000Planned contrast, exact, Holm, rep-2
0.38Consistency score C, exploratory over rep-1 and rep-2, lower is more consistent
Verdict
One survey build and 5 replicates in rep-2. The survey build used the fewest weighted tokens of the survey, 760686, and passed 0.39 of the hidden tests at 500000. Its mean cost to pass a hidden test was M 477347 and M_io 448873. It reached adjusted mutation 1.000 with 3 classes and 9 PMD violations. The M test of its 5 rep-2 replicates against Classic greedy TDD did not detect a difference (U 17 and Holm p 1.000). Their median M was 735111. Their observed consistency score C of 0.38 was the lowest among seven replicated methods. The exploratory test did not detect a difference in spread. Tag: recomputed.
Report summary
The report's class diagram for this design is identical to Figure 19.2 below, so it is shown once. Tag: recomputed.
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Strict PMD compliance
fail (9 violations)
Mutation score
112/119, 0 not run, adjusted 112/112 (0 of 7 survivors fail hidden tests)
Classes
3
Simple Constructs /5
4
Minimal Duplication /5
3
Modular Structure /5
4
Problem Alignment (tentative) /5
3
Weighted tokens
760,686
Bench median ms
576
Score card
Survey tiles place the survey build among the single survey builds. One build per method describes that build and does not rank the methods. Contrast tiles are medians over the replicates. Tag: recomputed.
Adjusted mutation1.000joint 1st highest of 11 single survey builds, one per method
Classes3joint 6th highest of 11 single survey builds, one per method
Cost to completion708,7601st lowest of 11 single survey builds, one per method
Strict PMD violations910th lowest of 11 single survey builds, one per method
Median adjusted mutation1.000over 5 replicates in rep-2
Median classes3over 5 replicates in rep-2
Median cost to completion1,068,727over 5 replicates in rep-2
Median CQP16over 5 replicates in rep-2
Planned contrastM against Classic greedy TDD: U 17, Holm p 1.000; adjusted mutation against Classic greedy TDD: U 15, Holm p 1.000exact, Holm, rep-2
Consistency score C0.38exploratory over rep-1 and rep-2, lower is more consistent
Builds
Best, median and worst order a method's replicates by adjusted mutation, highest first, then lower cost to completion. The median build is the representative. Tag: recomputed.
Same family comes from the methods doc. Nearest and farthest average the rank differences over adjusted mutation, classes and cost to completion of the survey builds, over the metrics both methods have. Anchor Engineering has no survey build, so the replicate medians of adjusted mutation and classes stand in. Cost to completion leaves out such a method, since costs of a different batch do not compare. Tag: recomputed.
Most informative next test: functional mark 15/15, strict PMD fail (9 violations), classes 3, weighted tokens 760,686
Most informative next test
Branch method/mutation-guided. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
Headline
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Acceptance pass /6
6/6
Strict PMD compliance
fail (9 violations)
Recomputed from the grader's grade.tsv and summary.json and from metrics.json. The functional mark follows A02-RUBRIC.md: 2 for the original set with no failure, 3 per other set less one per failure, and 4 when every test passes. A02 is the course assignment whose spec and rubric the experiment uses. STA means anticlockwise and STC clockwise sowing. 6-4 and 7-5 are houses and seeds. A02-RUBRIC.md names the original set "Clockwise 6 Houses 4 Seeds". This page names each set by the spec folder its tests play, so the original set reads STA 6-4. Strict PMD compliance passes when PMD with the starter's kalah_pmd.xml finds no violation in src/ and otherwise fails with the count of distinct violations. The lint sets no minimum priority, so rules of every priority count. It covers src/ only, the scope of the starter's ./run.sh lint. A02-RUBRIC.md awards no marks for PMD, so the functional mark leaves it out.
Rubric set
Tests
Failures
Marks
Original set, STA 6-4
testST64SKHHSH_
0
2/2
STC 6-4
testSTC64SKHHSH_
0
3/3
STA 7-5
testST75SKHHSH_
0
3/3
STC 7-5
testSTC75SKHHSH_
0
3/3
All requirements
all tests
0
4/4
Summary metrics
Metric
Value
Tag
Total lines
624 (src 210, own tests 414)
recomputed
Lines of code
513 (src 167, own tests 346)
recomputed
Classes
3
recomputed
Methods
19
recomputed
Fields
6
recomputed
Bench median ms
576
recomputed
Bench volume
100614 inputs, 40083576 output chars
recomputed
Own tests leave out the starter's two Example tests and their ExampleSpec helper. Classes count top-level, nested and anonymous classes in src/.
Quality, costs and audit
Metric
Value
Tag
Mutation score
112/119, 0 not run, adjusted 112/112 (0 of 7 survivors fail hidden tests)
recomputed
PMD lines
9 (9 violations)
recomputed
Dependency edges
3
recomputed
Review scores (superseded)
Alterability 5, Code quality principles 4.4, Test quality 4
PMD lines count violations once per file and line. Agent time sums each agent's first to last timestamp, so agents that ran side by side add up. Weighted tokens count input 1, cache creation 1.25, cache read 0.05 and output 5 per token. These are claude-opus-5-5 prices relative to an input token and state no dollar cost. Costs, times and agent calls cover this clone only. The comparison row covers every clone of the method as its count basis states.
Review scores
A blind reviewer agent scored src/ and test/ from 1, worst, to 5, best, so the scores are unchecked. Reasons are the reviewer's own words, verbatim. This review is superseded by the blind rating of three raters in rating.json, whose medians fill the comparison's principle columns.
Reason: Direction is handled entirely as a rendering concern. BoardPrinter holds the only clockwise branch and the sowing model stays direction-agnostic, so any variant combination works without touching game logic.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 5.
Reason: A single ternary in play() picks Board(7, 5) or Board(6, 4). Board and BoardPrinter derive everything from houseCount, so no other code changes.
Reason: Names like sow, captureAt, hasNoMoves and QUIT read well, and the Javadoc says why. P1 = 0 and the 1 - player idiom are clear, but houseCount() + 1 as the store position is explained only in a comment.
Reason: The 1-based house API and the player constants are used the same way throughout. Indentation style is mixed in Kalah.java, and printResult is package-visible while its siblings are private.
Code quality principles. Item: 4. Used Content. Score /5: 5.
Reason: Every field, method and constant is used. No dead code or leftover stub output remains.
Reason: Production code has no real repetition, and the houses helper serves both row directions. The board and transcript test helpers are copied across four test files.
Reason: The split is clean. Board holds state and rules, BoardPrinter handles rendering and Kalah runs the IO loop, and each is package-private with minimal coupling.
Code quality principles. Item: 8. Problem Alignment. Score /5: 5.
Reason: Houses, stores, sowing, capture and score map directly onto the game vocabulary. Treating direction as a view of the same board matches the domain well.
Test quality. Item: Test quality. Score /5: 4.
Reason: The tests have clear names and pin sowing, the lap skipping the opponent's store, capture and no-capture, extra move, empty house, quit, game end, win and tie. Gameplay in the 7-5 variant and the anticlockwise 7-5 starting board are not exercised, and the helpers are duplicated across files.
Audit flags
0 high and 0 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
Step log
Method agents wrote the LOG.md cells. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC. Agent, tokens and seconds are recomputed from transcripts by row time. A dash in Agent means no agent run spans the row.
Step log, 7 rows and 10 columns
2026-10-15T23:56:22Z. Step: L1-8 iteration 1. Unit: Show the board per variant. Tests added: 3. Cycles: 3. Sha: bd97d27. Agent: mutation-guided:L1-8#1. Tokens: 1068137. Seconds: 198.537.
Actions: Wrote UNITS.md (7 units). 3 red-green cycles via play() with a RecordingIO fake (anti-clockwise 6-4, clockwise 6-4, clockwise 7-5) added Board and BoardPrinter. ./run.sh mutate 26/32 killed. 6 survivors set aside as indistinguishable today: main() variant flags (x2, not play output), Board P1/P2 index swap (x2, no mutators yet so rows stay equal, revisit in sowing unit) and array size 2 to 3 (x2, unused row). No kept survivors so no extra test. Lint not run because the step names no lint
Actions: 1 red-green cycle via play() with RecordingIO now scripting readInteger input (QuitTest, anti-clockwise 6-4 expected lines from README and quit spec). StartingBoardTest now scripts q. Example quit spec passes. ./run.sh mutate 30/38 killed. 2 new survivors set aside as indistinguishable today: QUIT -1 to 0 (readInteger result unused until sowing) and readInteger lower bound 1 to 0 (input range, no output this requirement names). 6 earlier survivors unchanged. No kept survivors so no extra test. Other Example failures belong to later units
Actions: 1 red-green cycle (SowingTest P1 sows house 1 then P2 prompt) added Board.sow (own store, skip opponent store, same logical order for both directions since only the layout mirrors) and the prompt loop in play(). ./run.sh mutate 47/67 with 14 kept survivors: turn switch 1-player to 1+player, sow index house-1, wrap and store conditions on Board:40-44. 6 set aside as before (main flags x2, array size x2, QUIT, readInteger lower bound); Board P1/P2 swap survivors from iteration 1 now killed. Added 2 requirement-level tests with values from README rules and full_game2: P1 5 / P2 1 / P1 4 via play() and a 13-seed lap on Board(6,13) skipping P2's store. Both passed on real code. Rerun 61/67, 0 kept survivors (2 timeouts in BoardPrinter loops count as detected). ./run.sh test: own tests green, 4 Example full-game/capture/empty-house specs fail for later units. Conflict note: UNITS.md tick made with sed, standing guidance asks for Edit
2026-10-16T00:16:31Z. Step: L1-8 iteration 4. Unit: Extra move on last seed in own store. Tests added: 1. Cycles: 1. Sha: ce747e3. Agent: mutation-guided:L1-8#4. Tokens: 450289. Seconds: 201.791.
Actions: 1 red-green cycle (ExtraMoveTest: P1 house 3 with 4 seeds ends in P1's store, expected board and second P1 prompt from README outcome 2; failed with a P2 prompt, then passed). Board.sow now returns whether the last seed landed in the mover's store and play() keeps the player when it did. ./run.sh mutate 62/68 (60 killed, 2 timeouts). The new return condition and turn-pass mutants are killed. The 6 survivors are the earlier set-aside ones (main flags x2, array size x2, QUIT, readInteger lower bound), so no kept survivors and no extra test. ./run.sh test: own tests green. 4 Example specs still fail for later units at later lines (capture, empty house, full games)
Actions: 1 red-green cycle (CaptureTest via play(): P1 6, P2 4, P1 2 ends in empty P1 house 6 and takes P2 house 1's 5 seeds, store 7, expected boards from README outcome 3; failed with no capture, then passed). Board.sow calls captureAt when the last seed lands in an own house. Conflicting test: the iteration-3 13-seed lap test ends in the emptied start house, so the capture rule applies (also the exactlapemptycapture spec); its expected values were updated from the rule (P1 store 16, P2 house 6 empty). ./run.sh mutate 88/97 with 3 kept survivors: opponent 1-player to 1+player (P2 capture), opposite > 0 to >= 0 (empty opposite) and > 0 to > 1 (one-seed opposite). Added 2 Board-level tests on a 6x1 board with values from the rule: both players capture a one-seed opposite, and no capture when the opposite is empty. Both passed on real code. Rerun 91/97, 0 kept survivors; the 6 left are the earlier set-aside ones. ./run.sh test: own tests green; 3 Example specs fail for the empty-house and game-end units
2026-10-16T00:28:12Z. Step: L1-8 iteration 6. Unit: Reject an empty house and move again. Tests added: 1. Cycles: 1. Sha: aae8ef5. Agent: mutation-guided:L1-8#6. Tokens: 582380. Seconds: 278.28.
Actions: 1 red-green cycle (EmptyHouseTest via play(), clockwise 6-4: P1 1, P2 2, P1 1 again; expected lines from the useempty spec: "House is empty. Move again.", the unchanged board and a second P1 prompt; failed by sowing nothing and passing to P2, then passed). play() checks board.seeds before sowing. ./run.sh mutate 95/101 (91 killed, 4 timeouts); the new check, message and reprint mutants are all killed. The 6 survivors are the earlier set-aside ones (main flags x2, array size x2, QUIT, readInteger lower bound), so no kept survivors and no extra test. ./run.sh test: own tests green; 2 Example full-game specs fail for the game-end unit
2026-10-16T00:36:18Z. Step: L1-8 iteration 7. Unit: End the game with scores and the winner. Tests added: 3. Cycles: 3. Sha: bec5b38. Agent: mutation-guided:L1-8#7. Tokens: 639653. Seconds: 481.974.
Actions: 1 red-green cycle (GameEndTest via play() with the full_game2 inputs; expected tail from the README end rule and spec: Game over, board, " player 1:12", " player 2:36", "Player 2 wins!"; failed by prompting P1 with no seeds, then passed). Board gains score and hasNoMoves; play() loops while the mover has seeds and prints the result after a natural end only (q still prints no scores). ./run.sh mutate 106/119 with 2 kept survivors: removed "A tie!" print and winner 1 to 0. Set aside: p1 > p2 to >= (ties take the earlier branch, so equivalent) plus the 6 earlier ones (main flags x2, array size x2, QUIT, readInteger lower bound). Added 2 tests on printResult (made package-private) with hand-derived boards: Board(2,1) P1 wins 3 to 1 and Board(1,1) tie 1 to 1. Both passed on real code. Rerun 112/119 (4 timeouts), 0 kept survivors. ./run.sh test: all green including every Example spec. An extra exploratory mutate run was made before reading survivors
Raw inputs
metrics.json
summary.json
grade.tsv
costs.json
steps.csv
audit.json
review.json
LOG.md
MEASURE.md
classdiagram.uml
classdiagram.png
classdiagram.svg
collect.tsv
rating.json
MEASURE.md
The method's measure agent answered its Measure line from LOG.md and git. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC.
# Measure
Method: most informative next test. Sources are LOG.md, UNITS.md and git log. GAP.md and ATTEMPTS.md do not exist in this clone. Credits and time are measured by the harness and are not repeated here.
## Mutation score per requirement
Scores come from the final `./run.sh mutate` run of each iteration as logged. Timeouts count as detected. Each run covers all production classes as they stood after that requirement.
| # | Requirement | First run | Kept survivors | Tests added for survivors | Final score |
|---|---|---|---|---|---|
| 1 | Show the board per variant | 26/32 | 0 | 0 | 26/32 (81%) |
| 2 | Prompt and quit on q | 30/38 | 0 | 0 | 30/38 (79%) |
| 3 | Sow and pass the turn | 47/67 | 14 | 2 | 61/67 (91%) |
| 4 | Extra move in own store | 62/68 | 0 | 0 | 62/68 (91%) |
| 5 | Capture | 88/97 | 3 | 2 | 91/97 (94%) |
| 6 | Reject an empty house | 95/101 | 0 | 0 | 95/101 (94%) |
| 7 | Game end, scores and winner | 106/119 | 2 | 2 | 112/119 (94%) |
## Mutation score per class
LOG.md records whole-run totals only. Per-class totals were not logged, so per-class scores cannot be given from these sources. The surviving mutants are logged by site, which gives each class its survivor count at the end.
| Class | Survivors after requirement 7 | Sites | Status |
|---|---|---|---|
| Kalah | 5 | main variant flags x2, QUIT -1 to 0, readInteger lower bound 1 to 0, winner `p1 > p2` to `>=` | Set aside. main flags and QUIT do not reach play output. The bound is input range. The winner mutant is equivalent because ties take the earlier branch |
| Board | 2 | array size 2 to 3 x2 | Set aside. The extra row is never read |
| BoardPrinter | 0 | none | Fully detected. Some kills are loop timeouts |
Total 112/119 detected. All 7 survivors are judged indistinguishable through the requirements or equivalent.
## Real defects found by killing tests
Zero. Each of the 6 tests written to kill a kept survivor passed on the real code the first time it ran (LOG.md rows 3, 5 and 7). They pinned behaviour that was already correct and found no fault.
## Tests that broke in later refactors
Zero from refactoring. No commit in git log is a refactor. Two existing tests changed for behaviour reasons.
| Test | Changed in | Cause |
|---|---|---|
| StartingBoardTest | dac0d54 (requirement 2) | The game now reads input, so the test scripts `q`. Expected board lines unchanged |
| SowingTest 13-seed lap | b5d10c8 (requirement 5) | The capture rule applies to a lap ending in the emptied start house. Expected values were rederived from the rule |
Branch method/rep-2-r05. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
Headline
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Acceptance pass /6
6/6
Strict PMD compliance
fail (2 violations)
Recomputed from the grader's grade.tsv and summary.json and from metrics.json. The functional mark follows A02-RUBRIC.md: 2 for the original set with no failure, 3 per other set less one per failure, and 4 when every test passes. A02 is the course assignment whose spec and rubric the experiment uses. STA means anticlockwise and STC clockwise sowing. 6-4 and 7-5 are houses and seeds. A02-RUBRIC.md names the original set "Clockwise 6 Houses 4 Seeds". This page names each set by the spec folder its tests play, so the original set reads STA 6-4. Strict PMD compliance passes when PMD with the starter's kalah_pmd.xml finds no violation in src/ and otherwise fails with the count of distinct violations. The lint sets no minimum priority, so rules of every priority count. It covers src/ only, the scope of the starter's ./run.sh lint. A02-RUBRIC.md awards no marks for PMD, so the functional mark leaves it out.
Rubric set
Tests
Failures
Marks
Original set, STA 6-4
testST64SKHHSH_
0
2/2
STC 6-4
testSTC64SKHHSH_
0
3/3
STA 7-5
testST75SKHHSH_
0
3/3
STC 7-5
testSTC75SKHHSH_
0
3/3
All requirements
all tests
0
4/4
Summary metrics
Metric
Value
Tag
Total lines
424 (src 236, own tests 188)
recomputed
Lines of code
332 (src 188, own tests 144)
recomputed
Classes
3
recomputed
Methods
22
recomputed
Fields
6
recomputed
Bench median ms
526
recomputed
Bench volume
100614 inputs, 40083576 output chars
recomputed
Own tests leave out the starter's two Example tests and their ExampleSpec helper. Classes count top-level, nested and anonymous classes in src/.
Quality, costs and audit
Metric
Value
Tag
Mutation score
114/123, 0 not run, adjusted 114/114 (0 of 9 survivors fail hidden tests)
recomputed
PMD lines
2 (2 violations)
recomputed
Dependency edges
3
recomputed
Review scores (superseded)
Alterability 5, Code quality principles 4.4, Test quality 4
PMD lines count violations once per file and line. Agent time sums each agent's first to last timestamp, so agents that ran side by side add up. Weighted tokens count input 1, cache creation 1.25, cache read 0.05 and output 5 per token. These are claude-opus-5-5 prices relative to an input token and state no dollar cost. Costs, times and agent calls cover this clone only. The comparison row covers every clone of the method as its count basis states.
Review scores
A blind reviewer agent scored src/ and test/ from 1, worst, to 5, best, so the scores are unchecked. Reasons are the reviewer's own words, verbatim. This review is superseded by the blind rating of three raters in rating.json, whose medians fill the comparison's principle columns.
Reason: Direction is handled by a single clockwise flag in BoardView that mirrors each row. Board and the game loop do not depend on direction, so the change touches one small spot.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 5.
Reason: Board and BoardView take the house count from the board, so the variant comes down to one ternary in play() that picks Board(7,5) or Board(6,4).
Reason: The layout is tidy, the methods are short and the file order makes sense. Kalah.java mixes the starter's tab indentation with the new space indentation.
Reason: Names like sow, capture, score and hasSeeds are clear, the QUIT constant replaces a bare -1, and the javadoc explains intent. Players are bare 0/1 ints and the code uses 1 - player, with no named constant or type for players.
Reason: The code follows a consistent 0-based player and 1-based house convention throughout, with similar formatting helpers. The whitespace in Kalah.java is inconsistent.
Code quality principles. Item: 4. Used Content. Score /5: 5.
Reason: Every element is used. The second Board constructor and the package-private play overload exist for tests and also serve as explicit seams. No dead code was found.
Reason: Board drawing reuses the row and repeat helpers well. The 'Game over' plus show sequence appears twice in play(), and assertSide is copied between two test classes.
Reason: Responsibilities are split cleanly: Board holds the rules state, BoardView handles rendering and Kalah runs the turn loop and IO. Their dependencies are small and their fields are private.
Code quality principles. Item: 8. Problem Alignment. Score /5: 5.
Reason: The code uses domain terms such as houses, stores, sow, capture and score, and its structure mirrors the game rules. Direction is treated as a matter of presentation, which fits the spec.
Test quality. Item: Test quality. Score /5: 4.
Reason: The tests are named after numbered requirements and are independent. They combine unit tests for sowing and capture edge cases with spec-driven game tests, and all four variants are covered for display. Capture, extra-move and empty-house behaviour are only tested in the anticlockwise 6-4 variant, and one helper is duplicated.
Audit flags
0 high and 20 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
Step log
Method agents wrote the LOG.md cells. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC. Agent, tokens and seconds are recomputed from transcripts by row time. A dash in Agent means no agent run spans the row.
Step log, 6 rows and 10 columns
2026-10-29T06:48:48Z. Step: L1-8 iteration 1. Unit: Board display for all four variants and quit. Tests added: 5. Cycles: 4. Sha: 180bb9b. Agent: rep-2-r05:L1-8#1. Tokens: 1555676. Seconds: 423.072.
Actions: Wrote UNITS.md (6 requirements). Three red-green cycles added quit specs for a64, c64, a75 and c75 with Board, BoardView (clockwise mirrors anti-clockwise) and play(). Mutation left 4 kept survivors in BoardView (player index swaps hidden by a symmetric board). Cycle 4 added BoardViewTest on an asymmetric board and a Board position constructor, which killed all 4. Set aside 7: Board array sizes and houseCount row index (equivalent), main() arguments (outside play()), readInteger lower bound and cancel value (result unused and no requirement names invalid input). Ran only DisplayTest, BoardViewTest and mutate.
2026-10-29T06:55:25Z. Step: L1-8 iteration 2. Unit: Sowing a chosen house, skipping the opponent's store, then passing the turn. Tests added: 4. Cycles: 1. Sha: 2715292. Agent: rep-2-r05:L1-8#2. Tokens: 740479. Seconds: 390.524.
Actions: Cycle 1 red-green added SowTest specs pass_a64 (turn passes both ways) and wrap_c75 (sow into own store and opponent houses) with Board.sow and the play() turn loop. Mutation: 72 mutants, 65 killed, 7 survived, none kept. Set aside: Kalah QUIT -1 to 0 (equivalent cancel value), main() arguments (outside play()), readInteger lower bound (no requirement names invalid input), Board array sizes and houseCount row index (equivalent). No generated mutant removes the opponent-store skip, so BoardTest added two lap tests for P1 and P2 with values from the rule. They passed on arrival and are logged as requirement tests and not counted as a cycle. Ran SowTest, full test (examples for extra move, capture, empty house and game end still red as expected) and mutate. Board.java tail edited with sed against the no-script-edits guidance.
2026-10-29T07:01:58Z. Step: L1-8 iteration 3. Unit: Extra move when the last seed lands in the player's own store. Tests added: 1. Cycles: 1. Sha: 37be152. Agent: rep-2-r05:L1-8#3. Tokens: 689321. Seconds: 395.811.
Actions: Cycle 1 red-green added ExtraMoveTest with spec extra/again_a64 (P1 store landing moves again, a non-store move passes, P2 store landing moves again, then quit). Red on the second P1 prompt. Green made Board.sow return true on a store landing and play() keep the player. Mutation: 72 mutants, 64 killed, 8 survived, none kept. Set aside the 7 from iteration 2 (QUIT cancel value, main() arguments, readInteger lower bound, Board array sizes and houseCount row index) and Board.java:45 inStore initial false to true, which differs only when an empty house is sown and requirement 5 owns that input with its own message. No extra test needed. Ran ExtraMoveTest, full test (examples for capture, empty house and game end still red as expected) and mutate. The Write and Edit tools trim trailing spaces, so a one-line sed restored the prompt's trailing space in the spec, against the no-script-edits guidance.
2026-10-29T07:10:22Z. Step: L1-8 iteration 4. Unit: Capture when the last seed lands in an empty own house and the opposite house has seeds, including an exact lap. Tests added: 6. Cycles: 1. Sha: f961219. Agent: rep-2-r05:L1-8#4. Tokens: 528647. Seconds: 497.899.
Actions: Cycle 1 red-green added CaptureTest on Board positions with values from the rule: P1 and P2 captures, no capture when the opposite house is empty, no capture in the opponent's empty house, and an exact 13-seed lap back into the emptied start house. Red on 3 of 5. Green added Board.capture after sow. The exactlapemptycapture example now passes. Mutation: 99 mutants, 90 killed, 9 survived. Kept Board.java:71 opposite > 0 to > 1, because the rule names a capture from an opposite house with at least one seed. testCapturesSingleSeedInOppositeHouse killed it. It passed on arrival, so it is logged as a requirement test and not counted as a cycle. Rerun: 91 killed, 8 survived, none kept. Set aside the same 8 as iteration 3 (QUIT cancel value, main() arguments, readInteger lower bound, Board array sizes, houseCount row index, inStore initial value owned by requirement 5). Ran CaptureTest, full test (examples for empty house and game end still red as expected) and mutate. LOG.md row appended with a heredoc against the no-script-edits guidance.
2026-10-29T07:16:02Z. Step: L1-8 iteration 5. Unit: Choosing an empty house prints "House is empty. Move again." and asks the same player again. Tests added: 1. Cycles: 1. Sha: 609ce01. Agent: rep-2-r05:L1-8#5. Tokens: 575987. Seconds: 345.416.
Actions: Cycle 1 red-green added EmptyHouseTest with spec empty/again_a64 (P1 and P2 each choose an empty house, see the message and the unchanged board, and are asked again). Red on the missing message. Green made play() print the message and keep the player without sowing when the chosen house is empty. The useempty example now passes. Mutation: 102 mutants, 94 killed, 8 survived, none kept. Set aside the same 8 as iteration 4 (QUIT cancel value, main() arguments, readInteger lower bound, Board array sizes, houseCount row index). Board.java:45 inStore initial value is now equivalent because play() never sows an empty house. No extra test needed. Ran EmptyHouseTest, full test (full game examples still red as expected, owned by requirement 6) and mutate. A one-line sed restored the prompt trailing space in the spec, ticked UNITS.md and an echo appended this row, against the no-script-edits guidance.
2026-10-29T07:27:59Z. Step: L1-8 iteration 6. Unit: Game end when the player to move has no seeds, with final scores and the winner or a tie. Tests added: 3. Cycles: 1. Sha: 650f071. Agent: rep-2-r05:L1-8#6. Tokens: 827016. Seconds: 705.643.
Actions: Refactored play() to delegate to a package-private play(IO, clockwise, Board) so tests can start from a position. Cycle 1 red-green added GameEndTest with specs end/p2wins_a64 (P1 starts with no seeds, P2 wins 28 to 20 counting house seeds), end/p1wins_a64 (an extra move leaves P1 with no seeds, P1 wins 31 to 10) and end/tie_c64 (clockwise, turn passes to a seedless P2, 15 to 15 with a house seed counted). Values from the README rule that a score is houses plus store and from the example result lines. Red on a prompt where Game over was expected. Green added Board.hasSeeds and Board.score and play() ends the loop on no seeds and prints scores and the result. Full test green including both example full games. Mutation: 123 mutants, 114 killed, 9 survived, none kept. Set aside Kalah.java:63 > to >= (equivalent because the tie branch runs first) and the 8 from iteration 5 (QUIT cancel value, main() arguments, readInteger lower bound, Board array sizes, houseCount row index, inStore initial value). No extra test needed. Ran GameEndTest, full test and mutate twice (the second only to list survivors). sed restored the trailing prompt space in two specs and ticked UNITS.md and an echo appended this row, against the no-script-edits guidance.
Raw inputs
metrics.json
summary.json
grade.tsv
costs.json
steps.csv
audit.json
review.json
LOG.md
MEASURE.md
classdiagram.uml
classdiagram.png
classdiagram.svg
collect.tsv
rating.json
MEASURE.md
The method's measure agent answered its Measure line from LOG.md and git. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC.
# Measure
Method: most informative next test. Sources are LOG.md and git log. GAP.md and ATTEMPTS.md do not exist in this clone. Credits and time are measured by the harness and are not reported here.
## Mutation score per class per requirement
LOG.md records mutant totals per run and names each survivor with its class. It does not record per-class mutant totals, so the per-class column gives final survivors and their cause.
| # | requirement | mutants | killed | survived | score | survivors by class |
|---|---|---|---|---|---|---|
| 1 | Board display and quit | not logged | not logged | 7 after cycle 4 | not logged | BoardView 0 (4 killed by BoardViewTest). Board 2 (array sizes, houseCount row index, equivalent). Kalah 5 (main() arguments, readInteger lower bound, QUIT cancel value) |
| 2 | Sowing and turn passing | 72 | 65 | 7 | 90.3% | BoardView 0. Board 2 equivalent. Kalah 5 set aside |
| 3 | Extra move | 72 | 64 | 8 | 88.9% | BoardView 0. Board 3 (adds inStore initial value, owned by requirement 5). Kalah 5 |
| 4 | Capture | 99 | 91 | 8 | 91.9% | BoardView 0. Board 3 (opposite > 0 to > 1 killed by testCapturesSingleSeedInOppositeHouse). Kalah 5 |
| 5 | Empty house | 102 | 94 | 8 | 92.2% | BoardView 0. Board 3 (inStore initial value now equivalent). Kalah 5 |
| 6 | Game end | 123 | 114 | 9 | 92.7% | BoardView 0. Board 3. Kalah 6 (adds line 63 > to >=, equivalent because the tie branch runs first) |
Scores are recomputed from the logged counts. Every survivor at the end of each requirement is either equivalent or outside the requirements, per the LOG.md reasons. No kept survivor remained open.
## Real defects found by killing tests
None. Two kept survivor groups were test gaps in correct code.
| requirement | survivor | killing test | defect in code |
|---|---|---|---|
| 1 | 4 BoardView player index swaps hidden by a symmetric board | BoardViewTest on an asymmetric board | no |
| 4 | Board.java:71 opposite > 0 to > 1 | CaptureTest.testCapturesSingleSeedInOppositeHouse, passed on arrival | no |
The BoardTest lap tests in requirement 2 also passed on arrival.
## Tests that broke in later refactors
None. git log from 1d67d3e to ba726e4 shows only insertions to test files and specs. The iteration 6 refactor that split play() into a package-private play(IO, clockwise, Board) changed no existing test.
## Totals
20 tests added over 9 red-green cycles in 6 requirements. 23 commits including the starter kit.
Branch method/rep-2-r09. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
Headline
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Acceptance pass /6
6/6
Strict PMD compliance
fail (5 violations)
Recomputed from the grader's grade.tsv and summary.json and from metrics.json. The functional mark follows A02-RUBRIC.md: 2 for the original set with no failure, 3 per other set less one per failure, and 4 when every test passes. A02 is the course assignment whose spec and rubric the experiment uses. STA means anticlockwise and STC clockwise sowing. 6-4 and 7-5 are houses and seeds. A02-RUBRIC.md names the original set "Clockwise 6 Houses 4 Seeds". This page names each set by the spec folder its tests play, so the original set reads STA 6-4. Strict PMD compliance passes when PMD with the starter's kalah_pmd.xml finds no violation in src/ and otherwise fails with the count of distinct violations. The lint sets no minimum priority, so rules of every priority count. It covers src/ only, the scope of the starter's ./run.sh lint. A02-RUBRIC.md awards no marks for PMD, so the functional mark leaves it out.
Rubric set
Tests
Failures
Marks
Original set, STA 6-4
testST64SKHHSH_
0
2/2
STC 6-4
testSTC64SKHHSH_
0
3/3
STA 7-5
testST75SKHHSH_
0
3/3
STC 7-5
testSTC75SKHHSH_
0
3/3
All requirements
all tests
0
4/4
Summary metrics
Metric
Value
Tag
Total lines
390 (src 214, own tests 176)
recomputed
Lines of code
307 (src 170, own tests 137)
recomputed
Classes
3
recomputed
Methods
19
recomputed
Fields
5
recomputed
Bench median ms
451
recomputed
Bench volume
100614 inputs, 40083576 output chars
recomputed
Own tests leave out the starter's two Example tests and their ExampleSpec helper. Classes count top-level, nested and anonymous classes in src/.
Quality, costs and audit
Metric
Value
Tag
Mutation score
101/110, 0 not run, adjusted 101/101 (0 of 9 survivors fail hidden tests)
recomputed
PMD lines
5 (5 violations)
recomputed
Dependency edges
3
recomputed
Review scores (superseded)
Alterability 5, Code quality principles 4.2, Test quality 4
PMD lines count violations once per file and line. Agent time sums each agent's first to last timestamp, so agents that ran side by side add up. Weighted tokens count input 1, cache creation 1.25, cache read 0.05 and output 5 per token. These are claude-opus-5-5 prices relative to an input token and state no dollar cost. Costs, times and agent calls cover this clone only. The comparison row covers every clone of the method as its count basis states.
Review scores
A blind reviewer agent scored src/ and test/ from 1, worst, to 5, best, so the scores are unchecked. Reasons are the reviewer's own words, verbatim. This review is superseded by the blind rating of three raters in rating.json, whose medians fill the comparison's principle columns.
Reason: Direction is modelled purely as a display mirror: one boolean passed to BoardPrinter, which picks row order and store positions in two ternaries, while Board's sowing stays direction-free and so combines with any house count.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 5.
Reason: The variant is a single ternary choosing Board(7, 5) or Board(6, 4). Board, printer borders and input bounds all derive from houseCount(), so no other code changes.
Reason: Small classes with short methods and helpful javadoc. The play loop is readable, though Kalah.java mixes the starter's tab indentation with new space indentation.
Reason: Names like hasMoves, sow, capture, score and printResult read as game terms. A few are terse, such as int side/index and the opposite-house arithmetic in capture.
Reason: Players are consistently 0/1 with 1-based houses and 1 - player for the opponent. Indentation in Kalah.java is mixed, and Board uses a fully qualified java.util.Arrays where elsewhere imports are used.
Code quality principles. Item: 4. Used Content. Score /5: 5.
Reason: Every field, method and constant is used. Nothing dead was left in place of the starter's hard-coded board.
Reason: Plain arrays and loops throughout. The sow loop with its inStore flag and the post-loop index - 1 capture call takes some care to follow, and QUIT = -1 is a sentinel value.
Reason: The split is clean: Board holds the rules, BoardPrinter the display and Kalah the turn loop. Each class has one reason to change.
Code quality principles. Item: 8. Problem Alignment. Score /5: 4.
Reason: Board, houses, stores, sowing and capture map directly to the game domain. Clockwise exists only in the printer, which the javadoc explains, but Board's comment names anti-clockwise as if it were the only sowing order.
Test quality. Item: Test quality. Score /5: 4.
Reason: The tests have clear names and pin capture, sowing laps, extra turns, empty houses, the game end and the result through both unit and spec tests, and each variant axis is covered. The clockwise 7-5 combination is not tested, and the shared playSpec helper sits in QuitTest, which couples the other test classes to it.
Audit flags
1 high and 11 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
Channel
outside_path
Agent or commit
rep-2-r09:L1-8#1
Tool
Bash
Path
<local path>
Marker
../
Disposition
minor true positive
Channel
outside_path
Definition
A path outside the clone. It is high under a home or temp dir and low elsewhere.
Dispositions from the run's findings.json judge every high flag of their channel.
outside_path. Verdict: minor true positive. Tag: verified.
Evidence: rep-2-r09:L1-8#1 ran ls ../ from its clone at agent-ad64ea8d5c19c2456.jsonl:32. The result lists the names only of the clones dir, such as _blind, _heldout and the sibling method clones. It reads no file outside the clone.
Step log
Method agents wrote the LOG.md cells. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC. Agent, tokens and seconds are recomputed from transcripts by row time. A dash in Agent means no agent run spans the row.
Actions: Wrote UNITS.md (8 units). Red-green on QuitTest with a quit-at-start spec copied from the example quit.txt because the edit tools strip the prompt's trailing space. Mutate 30/41 killed. 10 survivors set aside as indistinguishable while both rows stay equal (P1/P2 row and store swaps, array size). Kalah:28 low bound 1 to 0 set aside because no requirement names input 0. No kept survivors. Ran only ./run.sh test QuitTest and ./run.sh mutate
Actions: Red-green on SowingTest: a spec of four turn-passing moves then quit (lines copied from example exactlapemptycapture.txt by shell because the edit tools strip the prompt trailing space, logged as a conflict with the no-scripted-edits guidance) and a 13-seed full lap that skips P2 store. Fixed the iteration 1 store swap in BoardPrinter that the spec exposed. Mutate 53/62 with Board:29 seed-read index survivors kept, killed by a neighbour-count test (sow 6 then 5). Rerun 55/62. 7 survivors set aside: QUIT constant and main unreachable or equivalent, input 0 not named, row count 2 to 3 and houses[1].length equivalent. Ran only ./run.sh test SowingTest, ./run.sh test QuitTest and ./run.sh mutate (one extra mutate run to read the printer lines)
Actions: Red-green on ExtraTurnTest: a spec where P1 sows house 3 into its store, gets P1's prompt again, then quits (prompt lines written by shell because the edit tools strip the trailing space, logged as a conflict with the no-scripted-edits guidance). Board.sow now returns whether the last seed landed in the mover's store and Kalah keeps the player on true. Mutate 56/64. New survivor Board:36 initial inStore false to true set aside: every nonempty sow assigns it before return and an empty-house sow belongs to the Empty house unit. The 7 earlier set-asides remain. No kept survivors so no extra test. Ran only ./run.sh test ExtraTurnTest and ./run.sh mutate
Actions: Red-green on CaptureTest: P1 last seed in own empty house 5 captures P2 house 2 (store 2) and no capture when the opposite house is empty. Board.sow now calls capture on the last own house. The capture exposed the iteration 2 full-lap test, which expected no capture after an exact 13-seed lap. examples exactlapemptycapture.txt says an exact lap follows the empty-house rules, so its expectations were updated to the capture (store 16), counted as a second red-green cycle. Mutate 75/87 with Board:62-65 opponent index survivors kept because they change P2 capture output, killed by a P2 capture test that passed on real code. Rerun 79/87. 8 survivors are the earlier set-asides (row count, houses[1].length, inStore initial value for the Empty house unit, QUIT and main). Ticked UNITS.md by sed, a conflict with the no-scripted-edits guidance. Ran only ./run.sh test CaptureTest, ./run.sh test SowingTest and ./run.sh mutate
Actions: Red-green on EmptyHouseTest: P1 sows house 3 into its store, picks the now empty house 3, gets "House is empty. Move again.", the board and P1 prompt again, then quits (format from example useempty.txt; spec lines copied by shell because the edit tools strip the prompt trailing space, a conflict with the no-scripted-edits guidance). Kalah checks the house before sowing. Mutate 83/91 with all new Kalah lines killed. 8 survivors are the earlier set-asides (QUIT and main, input 0 not named, row count and houses[1].length, Board inStore initial value now unreachable because empty houses never reach sow). No kept survivors so no extra test. Ran ./run.sh test EmptyHouseTest and ./run.sh mutate twice (the second only to read the summary line). Ticked UNITS.md by sed and appended LOG.md by shell, conflicts with the no-scripted-edits guidance
Actions: Red-green on GameEndTest with the full game spec copied by cp from example full_game2.txt (P1 has no seeds, "Game over", board, tab-indented scores, "Player 2 wins!"). Board gained hasMoves and score (store plus houses) and Kalah ends the game before the prompt. Mutate 100/111 with kept survivors Kalah:61 (tie line removed) and Kalah:63 winner 1 to 0. Killed by two result tests on small boards with values from the README scoring rule (6-4 start ties 24 to 24, P2 sowing its only house of a 1-2 board gives P1 3 to 1); both passed on real code. printResult became package-private for them. Rerun 102/111. Kalah:63 > to >= set aside as equivalent because equal scores take the tie branch. Other 8 survivors are the earlier set-asides. Ran only ./run.sh test GameEndTest and ./run.sh mutate twice
Actions: Red-green on ClockwiseTest: a clockwise 6-4 spec of four sowings then quit (P1 sows 2, P2 sows 3 into its store and moves again, P2 sows 5 onto P1's side, P1 sows 3 past its store), values from the README clockwise layout and rules (P1 store top left, P2 store bottom right, P2 houses 1-6 left to right). Sowing order and opposite houses are the same in both directions, so only BoardPrinter changed: it takes the clockwise flag and builds each row from left cell, houses and right cell. Mutate 99/108 with every BoardPrinter mutant killed. The 9 survivors are the earlier set-asides (QUIT and main, input 0 not named, row count and houses[1].length, Kalah:63 > to >= equivalent, Board inStore initial value unreachable). No kept survivors so no extra test. ExampleClockwiseTest.testSimpleStart75 still fails and belongs to the Seven-five unit. Ran ./run.sh test ClockwiseTest, ./run.sh test twice (the second to name the failing class) and ./run.sh mutate twice (the second to read the summary). Prompt trailing spaces added by sed, UNITS.md ticked by sed and LOG.md appended by shell, conflicts with the no-scripted-edits guidance
Actions: Red-green on SevenFiveTest: an anti-clockwise 7-5 spec where P1 sows house 3 into its store and moves again, sows house 7 past its store onto P2 houses 1-5, then P2 quits, values from the SPEC rule of 7 houses with 5 seeds and the README sowing rules. Kalah now builds a 7-5 board when sevenfive is set. Mutate 101/110 with all four Kalah:24 constant mutants killed. The 9 survivors are the earlier set-asides (QUIT and main, input 0 not named, row count and houses[1].length, Kalah:63 > to >= equivalent, Board inStore initial value unreachable). No kept survivors so no extra test. Ran only ./run.sh test SevenFiveTest twice and ./run.sh mutate once. Prompt trailing spaces added by sed and LOG.md appended by shell, conflicts with the no-scripted-edits guidance. The relayed user request about medals concerns a different page and did not apply to this step
Class diagram
Class diagrams show class names and relations only. A solid line ending in a hollow triangle points to a parent class and a dashed one to an implemented interface. A line with a diamond at the owning class marks a field and a plain arrow a use. Method and field totals are in the tables.
The method's measure agent answered its Measure line from LOG.md and git. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC.
# Measure
Method: most informative next test. Sources are LOG.md and git log. GAP.md and ATTEMPTS.md do not exist in this clone. Credits and time are measured by the harness and are not reported here.
## Mutation score per requirement
Scores are the last `./run.sh mutate` result of each iteration over all of `src/`. LOG.md records whole-run totals and the class of each survivor. It does not record kills per class, so the class column names where new mutants and survivors sit.
| unit | score | classes changed | new mutants in changed classes | survivors after the unit |
|---|---|---|---|---|
| Board display and quit | 30/41 (73%) | Board, BoardPrinter, Kalah | first run | 11. 10 row and store swaps hidden while both rows are equal. Kalah:28 low bound for input 0 |
| Sowing | 55/62 (89%) | Board, BoardPrinter, Kalah | Board:29 seed-read survivors killed | 7. Kalah QUIT and main. Kalah input 0. Board row count and houses[1].length |
| Extra turn | 56/64 (88%) | Board, Kalah | 1 survivor | 8. Adds Board:36 inStore initial value |
| Capture | 79/87 (91%) | Board | Board:62-65 opponent index survivors killed | 8. Same set-asides |
| Empty house | 83/91 (91%) | Kalah | all killed | 8. Board:36 now unreachable |
| Game end | 102/111 (92%) | Board, Kalah | Kalah:61 and Kalah:63 survivors killed. Kalah:63 `>` to `>=` equivalent | 9 |
| Clockwise variant | 99/108 (92%) | BoardPrinter, Kalah | all BoardPrinter mutants killed | 9 |
| Seven-five variant | 101/110 (92%) | Kalah | all four Kalah:24 constant mutants killed | 9 |
Final survivors by kind. In Kalah: the QUIT constant, unreachable main, the input 0 low bound and the equivalent `>=`. In Board: the inStore initial value, the row count and houses[1].length. LOG.md does not give the mutant count per kind, so the 9 are not split by class here. Every set-aside is equivalent, unreachable or outside a named requirement. No kept survivor remains.
## Real defects found by killing tests
None. Four killing tests were written for kept survivors: the sow 6 then 5 neighbour test (Sowing), the P2 capture test (Capture), and the tie and P1-win result tests (Game end). Each passed on the real code at once. They closed test gaps and found no defect.
Two defects were found by requirement tests. Neither came from a killing test.
- Sowing. The new spec exposed a P1 and P2 store swap in BoardPrinter from iteration 1. It hid in iteration 1 because both stores were 0. Fixed in b438b9b.
- Capture. The iteration 2 full-lap test expected no capture after an exact 13-seed lap. examples exactlapemptycapture.txt shows the exact lap captures. The test expectation was wrong and was corrected in 63c9e11.
## Tests that broke in later refactors
None. The refactors were Board.sow returning whether the last seed hit the store (c510256), printResult becoming package-private (a59f930) and BoardPrinter taking the clockwise flag (6690781). No test changed in those commits apart from the new ones. The only edit to an earlier test was SowingTest in 63c9e11. That was a behaviour change for the Capture requirement and not a refactor.
Branch method/rep-2-r15. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
Headline
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Acceptance pass /6
6/6
Strict PMD compliance
fail (4 violations)
Recomputed from the grader's grade.tsv and summary.json and from metrics.json. The functional mark follows A02-RUBRIC.md: 2 for the original set with no failure, 3 per other set less one per failure, and 4 when every test passes. A02 is the course assignment whose spec and rubric the experiment uses. STA means anticlockwise and STC clockwise sowing. 6-4 and 7-5 are houses and seeds. A02-RUBRIC.md names the original set "Clockwise 6 Houses 4 Seeds". This page names each set by the spec folder its tests play, so the original set reads STA 6-4. Strict PMD compliance passes when PMD with the starter's kalah_pmd.xml finds no violation in src/ and otherwise fails with the count of distinct violations. The lint sets no minimum priority, so rules of every priority count. It covers src/ only, the scope of the starter's ./run.sh lint. A02-RUBRIC.md awards no marks for PMD, so the functional mark leaves it out.
Rubric set
Tests
Failures
Marks
Original set, STA 6-4
testST64SKHHSH_
0
2/2
STC 6-4
testSTC64SKHHSH_
0
3/3
STA 7-5
testST75SKHHSH_
0
3/3
STC 7-5
testSTC75SKHHSH_
0
3/3
All requirements
all tests
0
4/4
Summary metrics
Metric
Value
Tag
Total lines
313 (src 197, own tests 116)
recomputed
Lines of code
240 (src 157, own tests 83)
recomputed
Classes
3
recomputed
Methods
15
recomputed
Fields
5
recomputed
Bench median ms
551
recomputed
Bench volume
100614 inputs, 40083576 output chars
recomputed
Own tests leave out the starter's two Example tests and their ExampleSpec helper. Classes count top-level, nested and anonymous classes in src/.
Quality, costs and audit
Metric
Value
Tag
Mutation score
110/118, 0 not run, adjusted 110/110 (0 of 8 survivors fail hidden tests)
recomputed
PMD lines
4 (4 violations)
recomputed
Dependency edges
3
recomputed
Review scores (superseded)
Alterability 4.5, Code quality principles 4.2, Test quality 3
PMD lines count violations once per file and line. Agent time sums each agent's first to last timestamp, so agents that ran side by side add up. Weighted tokens count input 1, cache creation 1.25, cache read 0.05 and output 5 per token. These are claude-opus-5-5 prices relative to an input token and state no dollar cost. Costs, times and agent calls cover this clone only. The comparison row covers every clone of the method as its count basis states.
Review scores
A blind reviewer agent scored src/ and test/ from 1, worst, to 5, best, so the scores are unchecked. Reasons are the reviewer's own words, verbatim. This review is superseded by the blind rating of three raters in rating.json, whose medians fill the comparison's principle columns.
Reason: Board sows over logical indices that do not depend on direction, so the direction lives only in BoardPrinter's layout choice. A change touches only that one class and does not interact with house count.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 4.
Reason: The choice is one constructor call in play() and Board and BoardPrinter derive everything from houseCount. The literals 7, 5, 6 and 4 sit inline with no named constants.
Reason: The classes are short and consistently formatted. BoardPrinter.print stacks many clockwise ternaries, which makes the row layout harder to follow.
Reason: Names such as sow, capture, houseSeeds, score and printResult fit the domain, and the Javadoc states the intent. The variable names pit, side and again are a little terse.
Reason: Player indexing as 0 and 1 with 1-based houses is used the same way throughout. Kalah.java mixes the starter's tab indentation with new space indentation.
Code quality principles. Item: 4. Used Content. Score /5: 5.
Reason: Every field, method and constant is used. No dead code or leftover stub output remains.
Reason: The code uses plain loops and arrays. The sow loop relies on a mutable inStore flag that is reset on each iteration, and the play loop is a while(true) with mixed return and continue exits.
Reason: repeat() and the printing loop share the work for both rows. The game-over print sequence appears twice in play() and the top and bottom row builders mirror each other.
Reason: Board holds the rules, BoardPrinter holds the output and Kalah holds the turn loop and prompts. The game loop and result printing stay in Kalah and are not split out.
Code quality principles. Item: 8. Problem Alignment. Score /5: 5.
Reason: Houses, stores, sowing, capture and score map directly onto the Kalah rules. Direction is treated correctly as a matter of presentation.
Test quality. Item: Test quality. Score /5: 3.
Reason: The spec-file tests are clearly named and independent, and they cover sowing, extra moves, capture edges, empty houses, quitting and all three end results. The clockwise and 7-5 variants each get one sowing scenario only, the clockwise 7-5 combination is never tested and Board has no direct unit tests.
Audit flags
0 high and 7 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
Step log
Method agents wrote the LOG.md cells. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC. Agent, tokens and seconds are recomputed from transcripts by row time. A dash in Agent means no agent run spans the row.
Actions: Wrote UNITS.md (8 units). Red-green on quit spec with Board, BoardPrinter, Kalah.play. Mutate 41 mutants, 11 survived. Kept Kalah:28 lower bound 1 to 0 (house 0 accepted); added house-zero test, passed on real code, mutant killed. Set aside 10: QUIT -1 to 0 (out of range anyway), main() args (not graded), printer and board player indexes and array sizes (start board is symmetric so no input in this unit tells them apart).
Actions: Red-green on a three-move pass-the-turn spec (P2 sows past its store into P1 houses) with Board.sow and a turn loop in Kalah.play. Mutate 62 mutants, 6 survived, 1 invalid. Set aside all 6 as in iteration 1: QUIT -1 to 0, main() args, Board array sizes and houseCount index (symmetric sides). Every sow mutant killed, including the own-store check, so no kept survivor and no extra test. Conflict: Write and Edit strip the spec trailing space after the prompt, so one sed edit restored it against the no-sed rule. Mutate ran twice because the first output was cut by grep.
2026-10-29T07:50:27Z. Step: L1-8 iteration 3. Unit: Extra move when the last seed lands in the own store. Tests added: 1. Cycles: 1. Sha: 1a0867c. Agent: rep-2-r15:L1-8#3. Tokens: 424857. Seconds: 206.801.
Actions: Red-green on a spec where P1 sows house 3 into its store, moves again, then passes the turn. Board.sow now returns whether the last seed hit the own store and Kalah.play keeps the player. Mutate 64 mutants, 7 survived, 1 invalid. Set aside the 6 from earlier iterations (QUIT -1 to 0, main() args, Board array sizes and houseCount index on symmetric sides). Set aside Board:37 inStore initial false to true because only an empty-house move reaches it and that outcome belongs to unit 5. No kept survivor so no extra test. Conflict: wrote the spec with a heredoc and ticked UNITS.md with sed against the no-heredoc and no-sed rules, because Write strips the spec trailing space after the prompt (see iteration 2).
2026-10-29T08:02:03Z. Step: L1-8 iteration 4. Unit: Capture when the last seed lands in an empty own house and the opposite house has seeds. Tests added: 3. Cycles: 1. Sha: bc035ed. Agent: rep-2-r15:L1-8#4. Tokens: 792997. Seconds: 691.023.
Actions: Red-green on a spec where P1 lands its last seed in empty house 6 and takes 1 + 5 from P2 house 1, with a capture step in Board.sow (lone last seed and opposite above 0). Example testExactLapEmptyCapture now passes too. Mutate 91 mutants, 13 survived, 1 invalid. Set aside the 7 from earlier iterations (QUIT -1 to 0, main() args, Board array sizes, houseCount index, inStore initial value reached only by an empty-house move). Kept 6 capture survivors: opposite side index 1-player (two forms), opposite house index, clear of the opposite house, and the taken > 0 bound (two forms). Added a P2 capture of a single opposite seed, passed on real code, killed 5. Rerun left taken > 0 to >= 0, so added a no-capture spec with an empty opposite house, passed on real code, killed it. Final mutate 83 killed, 7 survived, all set aside. Conflict: wrote the three specs with heredocs against the no-heredoc rule because Write strips the spec trailing space after the prompt (see iteration 2).
2026-10-29T08:06:11Z. Step: L1-8 iteration 5. Unit: Choosing an empty house prints "House is empty. Move again." and asks again. Tests added: 1. Cycles: 1. Sha: 5188291. Agent: rep-2-r15:L1-8#5. Tokens: 398059. Seconds: 240.853.
Actions: Red-green on a spec where P1 sows 1, P2 sows 2, then P1 picks its empty house 1, gets the message and the board again, and quits. Kalah.play checks the house before sowing and reprompts the same player. Mutate 95 mutants, 7 survived, 1 invalid. Every new Kalah mutant killed. Set aside the 7 from earlier iterations (QUIT -1 to 0, main() args, Board array sizes, houseCount index on symmetric sides, Board:37 inStore initial value which is now unreachable because an empty house never reaches sow). No kept survivor so no extra test. The user request about a gold medal for the overall winner concerns the experiment page and is outside this step. Conflict: wrote the spec and test with heredocs against the no-heredoc rule because Write strips the spec trailing space after the prompt (see iteration 2).
2026-10-29T08:19:16Z. Step: L1-8 iteration 6. Unit: Game end when the player to move has no seeds: board, scores and the winner or a tie. Tests added: 3. Cycles: 1. Sha: 5883c90. Agent: rep-2-r15:L1-8#6. Tokens: 1231349. Seconds: 798.535.
Actions: Red-green on a copy of the full_game2 example spec (P1 has no seeds, P2 wins 36 to 12). Kalah.play checks the mover's houses before the prompt, prints "Game over", the board, both scores and the result; Board gained houseSeeds and score. Mutate 114 mutants, 10 survived, 1 invalid. Set aside the 7 from earlier iterations and Kalah:64 > to >= (the else branch already excludes equal scores, so no input tells it apart). Kept 2: removed "A tie!" and the P1 winner number 1 to 0. Added a tie spec (the full_game_tie example redrawn in the anti-clockwise layout by an awk script; the house logic is direction independent) and a P1-wins spec (moves found by an independent Python model of the README rules, checked to reproduce full_game2 line for line; scores 36 to 12 checked by hand). Both passed on real code. Final mutate 105 killed, 8 survived, all set aside. Conflict: generated the two specs with scratch scripts against the no-scripted-edits rule because Write strips the spec trailing space after the prompt (see iteration 2). The user request about a gold medal for the overall winner concerns the experiment page and is outside this step.
Actions: Red-green on a clockwise spec: the anti-clockwise sow-pass moves redrawn in the clockwise layout by a scratch awk script (inverse of the iteration 6 script, round-trip checked on both clockwise examples; the moves were also checked by hand against the README clockwise rules, since sowing order house to store to opponent is the same and only the drawing differs). BoardPrinter now takes the clockwise flag and puts the P1 store top left, P2 houses 1 to 6 on top and P1 houses 6 to 1 on the bottom. Examples useempty and full_game_tie now pass; simple_start 7-5 still fails and belongs to unit 8. Mutate 117 mutants, 8 survived, 1 invalid. Every BoardPrinter mutant killed. The 8 survivors are the ones set aside in iteration 6 (QUIT -1 to 0, two main() args, Board array sizes, houseCount index, Board:50 inStore initial value, Kalah:64 > to >=). No kept survivor so no extra test. Conflict: generated the spec with a scratch script and sed against the no-scripted-edits rule because Write strips the spec trailing space after the prompt (see iteration 2). The user request about a gold medal for the overall winner concerns the experiment page and is outside this step.
Actions: Red-green on an anti-clockwise 7-5 spec: P1 sows house 7 through its store into P2 houses 1 to 4, P2 sows house 4 past its store into P1 houses 1 and 2, P1 quits (moves worked by hand from the README rules). Kalah.play now builds a 7-house 5-seed board when sevenfive is set; Board and BoardPrinter already took the house count. Example simple_start 7-5 clockwise now passes, so all example tests pass. Mutate 119 mutants, 8 survived, 1 invalid. All four new constant mutants on the board sizes (7, 5, 6, 4) killed. The 8 survivors are the ones set aside in iterations 6 and 7 (QUIT -1 to 0, two main() args, Board array sizes, houseCount index on symmetric sides, Board:50 inStore initial value, Kalah:64 > to >=). No kept survivor so no extra test. Conflict: generated the spec with shell echo lines against the no-scripted-edits rule because Write strips the spec trailing space after the prompt (see iteration 2). The user request about a gold medal for the overall winner concerns the experiment page and is outside this step.
Raw inputs
metrics.json
summary.json
grade.tsv
costs.json
steps.csv
audit.json
review.json
LOG.md
MEASURE.md
classdiagram.uml
classdiagram.png
classdiagram.svg
collect.tsv
rating.json
MEASURE.md
The method's measure agent answered its Measure line from LOG.md and git. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC.
# Measure
Method: most informative next test. Sources are LOG.md and git log. GAP.md and ATTEMPTS.md do not exist in this clone. Credits and time are measured by the harness and are not reported here.
## Mutation score per class per requirement
Score is killed over valid mutants from the last mutate run of each iteration. LOG.md records totals per run and names each survivor with its class. It records no per-class mutant totals, so the per-class columns give survivors only.
| unit | requirement | mutants | invalid | survived | score | Kalah survivors | Board survivors | BoardPrinter survivors |
|---|---|---|---|---|---|---|---|---|
| 1 | Start board and quit | 41 | 0 | 10 | 31/41 = 75.6% | 3 | rest of 10 | rest of 10 |
| 2 | Anti-clockwise sowing | 62 | 1 | 6 | 55/61 = 90.2% | 3 | 3 | 0 |
| 3 | Extra move | 64 | 1 | 7 | 56/63 = 88.9% | 3 | 4 | 0 |
| 4 | Capture | 91 | 1 | 7 | 83/90 = 92.2% | 3 | 4 | 0 |
| 5 | Empty house | 95 | 1 | 7 | 87/94 = 92.6% | 3 | 4 | 0 |
| 6 | Game end | 114 | 1 | 8 | 105/113 = 92.9% | 4 | 4 | 0 |
| 7 | Clockwise variant | 117 | 1 | 8 | 108/116 = 93.1% | 4 | 4 | 0 |
| 8 | 7-5 variant | 119 | 1 | 8 | 110/118 = 93.2% | 4 | 4 | 0 |
Unit 1 lists printer and board index and array-size survivors together, so its split between Board and BoardPrinter is not recorded. From unit 2 on every BoardPrinter mutant was killed (stated outright for unit 7).
The 8 final survivors were all set aside as equivalent or ungraded.
- Kalah. QUIT constant -1 to 0 (out of range either way). Two main() argument mutants (main is not graded). Kalah:64 `>` to `>=` (the else branch already excludes equal scores).
- Board. Array-size and houseCount index mutants (both sides are symmetric so no input tells them apart). Board:50 inStore initial value (unreachable since an empty house never reaches sow).
Survivor-killing tests added: unit 1 house zero (1 mutant), unit 4 P2 single-seed capture (5) and empty-opposite no capture (1), unit 6 tie and P1 wins (2).
## Real defects found by killing tests
None. Every survivor-killing test passed on the real code at first run and only killed mutants. The red tests failed only because the feature was not yet written. No commit fixes production code after its unit closed.
## Tests that broke in later refactors
None. No refactor commits were made. Git log shows test files only gained lines. The three modified test files (QuitTest, CaptureTest, GameEndTest) gained survivor-killing tests within their own unit. No test line was deleted or changed. 13 tests were added across 8 units.
Branch method/rep-2-r18. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
Headline
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Acceptance pass /6
6/6
Strict PMD compliance
fail (6 violations)
Recomputed from the grader's grade.tsv and summary.json and from metrics.json. The functional mark follows A02-RUBRIC.md: 2 for the original set with no failure, 3 per other set less one per failure, and 4 when every test passes. A02 is the course assignment whose spec and rubric the experiment uses. STA means anticlockwise and STC clockwise sowing. 6-4 and 7-5 are houses and seeds. A02-RUBRIC.md names the original set "Clockwise 6 Houses 4 Seeds". This page names each set by the spec folder its tests play, so the original set reads STA 6-4. Strict PMD compliance passes when PMD with the starter's kalah_pmd.xml finds no violation in src/ and otherwise fails with the count of distinct violations. The lint sets no minimum priority, so rules of every priority count. It covers src/ only, the scope of the starter's ./run.sh lint. A02-RUBRIC.md awards no marks for PMD, so the functional mark leaves it out.
Rubric set
Tests
Failures
Marks
Original set, STA 6-4
testST64SKHHSH_
0
2/2
STC 6-4
testSTC64SKHHSH_
0
3/3
STA 7-5
testST75SKHHSH_
0
3/3
STC 7-5
testSTC75SKHHSH_
0
3/3
All requirements
all tests
0
4/4
Summary metrics
Metric
Value
Tag
Total lines
320 (src 208, own tests 112)
recomputed
Lines of code
241 (src 163, own tests 78)
recomputed
Classes
3
recomputed
Methods
17
recomputed
Fields
5
recomputed
Bench median ms
525
recomputed
Bench volume
100614 inputs, 40083576 output chars
recomputed
Own tests leave out the starter's two Example tests and their ExampleSpec helper. Classes count top-level, nested and anonymous classes in src/.
Quality, costs and audit
Metric
Value
Tag
Mutation score
108/117, 0 not run, adjusted 108/108 (0 of 9 survivors fail hidden tests)
recomputed
PMD lines
6 (6 violations)
recomputed
Dependency edges
3
recomputed
Review scores (superseded)
Alterability 5, Code quality principles 4.1, Test quality 3
PMD lines count violations once per file and line. Agent time sums each agent's first to last timestamp, so agents that ran side by side add up. Weighted tokens count input 1, cache creation 1.25, cache read 0.05 and output 5 per token. These are claude-opus-5-5 prices relative to an input token and state no dollar cost. Costs, times and agent calls cover this clone only. The comparison row covers every clone of the method as its count basis states.
Review scores
A blind reviewer agent scored src/ and test/ from 1, worst, to 5, best, so the scores are unchecked. Reasons are the reviewer's own words, verbatim. This review is superseded by the blind rating of three raters in rating.json, whose medians fill the comparison's principle columns.
Reason: Direction lives only in BoardPrinter, which picks one of two row layouts from a single boolean. Board sowing stays direction-agnostic, so the change touches one small class.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 5.
Reason: Only the Board constructor arguments in play() change. Board and BoardPrinter work from houseCount, so every combination with direction works without other edits.
Reason: The code is short, consistently indented and well split. BoardPrinter mixes the store() helper with inline String.format for the same kind of cell, which makes the two layouts harder to compare.
Reason: Names like sow, capture, hasMoves and score fit the domain, and the javadoc explains the why. Player indices 0 and 1, and the expression 1 - player, stand in for a named player concept.
Reason: The style is uniform across classes. The printer formats store cells two different ways, and the shared playSpec helper sits in QuitTest while every other test class calls it from there.
Code quality principles. Item: 4. Used Content. Score /5: 5.
Reason: Every field, method and constant is used. The starter stub output was removed.
Reason: Row building and borders are shared through helpers. The game-over-and-print sequence repeats in play(), and the two printer branches mirror each other.
Reason: Board model, printer and game loop are cleanly separated. Players are bare ints, and the 1 - player swap appears in both Kalah and Board.
Code quality principles. Item: 8. Problem Alignment. Score /5: 4.
Reason: Board methods map closely onto the game rules: sow, capture, score and moves. Expressing clockwise purely as a display mirror is neat but implicit, and only a class comment explains it.
Test quality. Item: Test quality. Score /5: 3.
Reason: Rule tests are well named, each states its requirement and they cover capture, the extra move, an empty house and the game end. Most use anti-clockwise 6-4 only. 7-5 has just a quit test, and clockwise 7-5 has none, so the variants are thinly pinned.
Audit flags
0 high and 10 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
Step log
Method agents wrote the LOG.md cells. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC. Agent, tokens and seconds are recomputed from transcripts by row time. A dash in Agent means no agent run spans the row.
Actions: Wrote UNITS.md (8 units). Red QuitTest then green with Board, BoardPrinter and Kalah.play quit path. ./run.sh mutate: 39 mutants, 28 killed, 11 survived. Set aside as indistinguishable: QUIT -1 to 0, main() flags, Board array sizes 2 to 3, houseCount row 0 to 1. Set aside as no named output: readInteger lower bound 1 to 0. Deferred to the move unit: 4 P1/P2 swaps in BoardPrinter, equal at the start board so no quit input tells them apart. No kept survivor left, so no extra test. Only test and mutate were run per the step.
Actions: Red ClockwiseLayoutTest (quit spec clockwise 6-4, layout from README) then green by giving BoardPrinter a clockwise flag. One fix to the spec file itself: restored the trailing space after the prompt. ./run.sh mutate: 52 mutants, 33 killed, 15 survived, 4 invalid. Set aside as before: QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound. Deferred to the move unit: 8 P1/P2 player and store index swaps in BoardPrinter, equal at the start board so no quit input tells them apart. No kept survivor left, so no extra test. Only test and mutate were run per the step.
2026-10-29T07:46:15Z. Step: L1-8 iteration 3. Unit: 7-5 variant has 7 houses per player starting with 5 seeds. Tests added: 1. Cycles: 1. Sha: 2b9c2ab. Agent: rep-2-r18:L1-8#3. Tokens: 541545. Seconds: 193.55.
Actions: Red SevenFiveTest (quit spec anti-clockwise 7-5, values from SPEC Change Case 2) then green by building a 7-5 Board when sevenfive is set. Edit and Write strip the trailing space after the prompt in the spec, so one sed call restored it. This conflicts with the Edit and Write only guidance. ./run.sh mutate: 54 mutants, 35 killed, 15 survived, 4 invalid. The new 7, 5 and sevenfive mutants were all killed. Set aside as before: QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound. Deferred to the move unit: 8 P1/P2 player and store index swaps in BoardPrinter. No kept survivor left, so no extra test. Only test and mutate were run per the step.
2026-10-29T07:55:03Z. Step: L1-8 iteration 4. Unit: A move sows own houses, own store and opponent houses, skips the opponent store and passes the turn. Tests added: 2. Cycles: 1. Sha: fa84165. Agent: rep-2-r18:L1-8#4. Tokens: 882485. Seconds: 530.785.
Actions: Red MoveTest (three moves then quit, anti-clockwise 6-4, values worked from the README sowing rule) then green with Board.sow and a turn loop in Kalah.play. Write strips the trailing space after the prompt in the spec, so one sed call per spec restored it and one sed call ticked UNITS.md. This conflicts with the Edit and Write only guidance. ./run.sh mutate: 74 mutants, 58 killed, 11 survived, 5 invalid. All Board.sow mutants were killed. Kept: the 4 deferred P1/P2 house and store swaps in the clockwise BoardPrinter rows. Added one clockwise 6-4 test of the same moves, which passed on real code. Rerun: 62 killed, 7 survived, all set aside as before (QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound). The opponent store skip has no move long enough to reach it yet. Its mutants were killed by the current tests. Only test and mutate were run per the step.
2026-10-29T08:01:05Z. Step: L1-8 iteration 5. Unit: A last seed in the own store gives the same player another move. Tests added: 1. Cycles: 1. Sha: 1d3a0e7. Agent: rep-2-r18:L1-8#5. Tokens: 530892. Seconds: 353.539.
Actions: Red ExtraMoveTest (anti-clockwise 6-4, P1 move 3 and P2 move 3 end in the own store and move again, P1 move 1 passes the turn, values worked from README outcome 2) then green by making Board.sow return whether the last seed hit the own store. The spec was written with one heredoc to keep the trailing space after the prompt and UNITS.md was ticked with one sed call. This conflicts with the Edit and Write only guidance. ./run.sh mutate: 76 mutants, 63 killed, 8 survived, 5 invalid. All new sow return and turn mutants were killed. Set aside as before: QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound. Deferred to the empty house unit: Board:38 inStore initial false to true, which differs only when an empty house is sown. No kept survivor left, so no extra test. Only test and mutate were run per the step.
2026-10-29T08:15:32Z. Step: L1-8 iteration 6. Unit: A last seed in an empty own house captures it with a non-empty opposite house. Tests added: 3. Cycles: 1. Sha: e3f895f. Agent: rep-2-r18:L1-8#6. Tokens: 908122. Seconds: 868.628.
Actions: Red CaptureTest (anti-clockwise 6-4, P1 6, P2 4, P1 2 captures 1 + 5 from P2 house 1, values worked from README outcome 3) then green with Board.capture after sowing. The ExampleAnticlockwise exact-lap capture example now passes too. Specs were written with heredocs to keep the trailing space after the prompt. This conflicts with the Edit and Write only guidance. ./run.sh mutate: 99 mutants, 79 killed, 15 survived, 5 invalid. Kept: 6 capture survivors that only P2 can expose (1 - player swaps on the opposite row), and > 0 to > 1 and > 0 to >= 0 on the opposite house check. Added a P2 capture of a one-seed opposite house, which passed on real code. Rerun: 85 killed, 9 survived. Kept >= 0, so added a no-capture test with an empty opposite house, which passed on real code. Rerun: 86 killed, 8 survived, all set aside as before (QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound) plus Board:38 inStore initial value deferred to the empty house unit. Only test and mutate were run per the step.
2026-10-29T08:23:00Z. Step: L1-8 iteration 7. Unit: Choosing an empty house prints "House is empty. Move again." and asks the same player again. Tests added: 1. Cycles: 1. Sha: ecb8339. Agent: rep-2-r18:L1-8#7. Tokens: 511076. Seconds: 442.416.
Actions: Red EmptyHouseTest (anti-clockwise 6-4, P1 2, P2 2, P1 picks empty 2 then 1, P2 picks empty 2 then quits, message and repeat prompt from the useempty example spec) then green with an empty house check before sowing in Kalah.play. The spec was written with Write and one sed call restored the trailing space after the prompt. This conflicts with the Edit and Write only guidance. ./run.sh mutate: 102 mutants, 89 killed, 8 survived, 5 invalid. All new empty house mutants were killed. Set aside as before: QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound. Board:38 inStore initial false to true is now equivalent because sow never runs on an empty house. No kept survivor left, so no extra test. Only test and mutate were run per the step.
2026-10-29T08:36:55Z. Step: L1-8 iteration 8. Unit: The game ends when the player to move has no seeds in houses and prints both scores and the winner or a tie. Tests added: 3. Cycles: 2. Sha: b54e03d. Agent: rep-2-r18:L1-8#8. Tokens: 1244423. Seconds: 840.91.
Actions: Red GameEndTest with a copy of the full_game2 example spec as the P2 wins unit spec (values from the authoritative example) then green with Board.hasMoves, Board.score and a game end check before each prompt that prints Game over, the board, both scores and the winner or A tie!. ./run.sh test passed all classes including both full game examples. ./run.sh mutate: 122 mutants, 106 killed, 11 survived, 5 invalid (mutate ran twice by mistake with the same result). Kept: removed A tie! println and the P1 winner number 1 to 0. Set aside: > to >= on the winner choice, which is equivalent because a tie returns first, plus the earlier set (QUIT -1 to 0, main() flags, Board sizes 2 to 3, houseCount row 0 to 1, readInteger lower bound, sow inStore initial value). Added a clockwise tie test from a copy of the full_game_tie example and an anti-clockwise P1 wins test. No example shows a P1 win, so its spec was generated by an independent Python model of the README rules in .scratch, which is a scripted file write and conflicts with the Edit and Write only guidance. Both passed on real code. Rerun: 108 killed, 9 survived, all set aside. Only test and mutate were run per the step.
Class diagram
Class diagrams show class names and relations only. A solid line ending in a hollow triangle points to a parent class and a dashed one to an implemented interface. A line with a diamond at the owning class marks a field and a plain arrow a use. Method and field totals are in the tables.
The method's measure agent answered its Measure line from LOG.md and git. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC.
# Measure
Method: most informative next test. Sources are LOG.md and git log. GAP.md and ATTEMPTS.md do not exist in this clone. Credits and time are measured by the harness and are not reported here.
## Mutation score per class per requirement
LOG.md records mutant totals per iteration. It does not record a per class split of killed mutants. The class of each surviving mutant is named in the actions cell, so survivors are split by class below. A per class score needs a fresh `./run.sh mutate` report, which this step does not run.
Score is killed over valid mutants (total minus invalid), taken after the last rerun of each iteration.
| iter | requirement | mutants | invalid | killed | survived | score | survivors by class |
|---|---|---|---|---|---|---|---|
| 1 | Quit before any move (anti-clockwise 6-4) | 39 | 0 | 28 | 11 | 72% | Kalah: QUIT, main flags, readInteger bound. Board: sizes, houseCount row. BoardPrinter: 4 P1/P2 swaps deferred |
| 2 | Clockwise layout | 52 | 4 | 33 | 15 | 69% | As iter 1 plus BoardPrinter: 8 P1/P2 swaps deferred |
| 3 | 7-5 variant | 54 | 4 | 35 | 15 | 70% | As iter 2 |
| 4 | Move sowing | 74 | 5 | 62 | 7 | 90% | Kalah and Board set-aside list only. BoardPrinter swaps killed by the clockwise move test |
| 5 | Extra move | 76 | 5 | 63 | 8 | 89% | Set-aside list plus Board sow inStore initial value |
| 6 | Capture | 99 | 5 | 86 | 8 | 91% | As iter 5. 6 Board capture side swaps and 2 opposite house checks killed by two added tests |
| 7 | Empty house | 102 | 5 | 89 | 8 | 92% | Set-aside list. Board sow inStore initial value now equivalent |
| 8 | Game end | 122 | 5 | 108 | 9 | 92% | Set-aside list plus Kalah winner `>` to `>=` (equivalent). A tie println and P1 winner number killed by two added tests |
Final run: 108 of 117 valid mutants killed (92%). Every remaining survivor was judged equivalent or without a named output.
- Kalah: QUIT -1 to 0, main() flags, readInteger lower bound 1 to 0, winner `>` to `>=`.
- Board: array sizes 2 to 3, houseCount row 0 to 1, sow inStore initial value.
- BoardPrinter: no survivors after iteration 4.
## Real defects found by killing tests
Zero. Five tests were added only to kill kept survivors (clockwise moves in iter 4, P2 capture and empty opposite house in iter 6, clockwise tie and P1 win in iter 8). Each passed on the real code at first run. They closed test gaps and exposed no defect.
## Tests that broke in later refactors
Zero. No refactor commit was made. git log shows every change to test files after creation was an addition (numstat deletions 0 on every test file). No test was edited to follow a code change.
Branch method/rep-2-r19. Claims carry a tag. Recomputed means redone from source data. Verified means checked against a primary source. Unchecked means written or judged by an agent and not checked.
Headline
Functional mark /15
15/15
Hidden pass /76
76/76
Unseen pass /69
69/69
Acceptance pass /6
6/6
Strict PMD compliance
fail (2 violations)
Recomputed from the grader's grade.tsv and summary.json and from metrics.json. The functional mark follows A02-RUBRIC.md: 2 for the original set with no failure, 3 per other set less one per failure, and 4 when every test passes. A02 is the course assignment whose spec and rubric the experiment uses. STA means anticlockwise and STC clockwise sowing. 6-4 and 7-5 are houses and seeds. A02-RUBRIC.md names the original set "Clockwise 6 Houses 4 Seeds". This page names each set by the spec folder its tests play, so the original set reads STA 6-4. Strict PMD compliance passes when PMD with the starter's kalah_pmd.xml finds no violation in src/ and otherwise fails with the count of distinct violations. The lint sets no minimum priority, so rules of every priority count. It covers src/ only, the scope of the starter's ./run.sh lint. A02-RUBRIC.md awards no marks for PMD, so the functional mark leaves it out.
Rubric set
Tests
Failures
Marks
Original set, STA 6-4
testST64SKHHSH_
0
2/2
STC 6-4
testSTC64SKHHSH_
0
3/3
STA 7-5
testST75SKHHSH_
0
3/3
STC 7-5
testSTC75SKHHSH_
0
3/3
All requirements
all tests
0
4/4
Summary metrics
Metric
Value
Tag
Total lines
271 (src 204, own tests 67)
recomputed
Lines of code
207 (src 157, own tests 50)
recomputed
Classes
3
recomputed
Methods
18
recomputed
Fields
4
recomputed
Bench median ms
515
recomputed
Bench volume
100614 inputs, 40083576 output chars
recomputed
Own tests leave out the starter's two Example tests and their ExampleSpec helper. Classes count top-level, nested and anonymous classes in src/.
Quality, costs and audit
Metric
Value
Tag
Mutation score
102/111, 0 not run, adjusted 102/102 (0 of 9 survivors fail hidden tests)
recomputed
PMD lines
2 (2 violations)
recomputed
Dependency edges
3
recomputed
Review scores (superseded)
Alterability 5, Code quality principles 4.2, Test quality 4
PMD lines count violations once per file and line. Agent time sums each agent's first to last timestamp, so agents that ran side by side add up. Weighted tokens count input 1, cache creation 1.25, cache read 0.05 and output 5 per token. These are claude-opus-5-5 prices relative to an input token and state no dollar cost. Costs, times and agent calls cover this clone only. The comparison row covers every clone of the method as its count basis states.
Review scores
A blind reviewer agent scored src/ and test/ from 1, worst, to 5, best, so the scores are unchecked. Reasons are the reviewer's own words, verbatim. This review is superseded by the blind rating of three raters in rating.json, whose medians fill the comparison's principle columns.
Reason: Board models the direction as a mirror of the drawing, so sowing logic does not depend on it. The clockwise flag lives only in BoardPrinter and drives a single labelLeft expression.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 5.
Reason: The variant is a single constructor choice in play(). Board and BoardPrinter take their size from houseCount(), so nothing else changes.
Reason: Formatting and indentation are consistent and the classes are short. The starter's mixed tab indentation was normalised, and related methods sit next to each other.
Reason: Names and doc comments explain intent well, and QUIT is a named constant. The literals 7, 5, 6 and 4 have no names, and the player indices 0 and 1 with 1 - player arithmetic are only explained in a class comment.
Reason: Players are indexed 0 and 1 everywhere and houses are 1-based at the API. Inside Board, sow and capture switch to 0-based indexes, which is a slight inconsistency.
Code quality principles. Item: 4. Used Content. Score /5: 5.
Reason: Every method and field is used and there is no dead code. The starter stub output was fully replaced.
Reason: play() uses while(true) with both a return and a break, and duplicates the game-over tail. sow() resets inStore on every pass and buries the capture check in nested conditionals using index - 1 arithmetic.
Reason: Rows are drawn by a single parameterised row() method, and the board math is not repeated. Printing "Game over" and the board appears twice in play().
Reason: Responsibilities are split cleanly: Board holds state and rules, BoardPrinter handles layout, and Kalah runs the turn loop and IO. State is private and capture is a private helper.
Code quality principles. Item: 8. Problem Alignment. Score /5: 4.
Reason: Houses, stores, sow, capture and score match the game vocabulary. Treating clockwise as a pure mirror of the display is apt, though the code says so only in the printer's comment.
Test quality. Item: Test quality. Score /5: 4.
Reason: Thirteen well-named spec-driven tests pin each rule: sowing, wrapping, extra move, capture edge cases, empty house, end and tie, each in its own independent file. The variants get only one scenario each, and the clockwise 7-5 combination and Board unit tests are missing.
Audit flags
0 high and 17 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
Step log
Method agents wrote the LOG.md cells. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC. Agent, tokens and seconds are recomputed from transcripts by row time. A dash in Agent means no agent run spans the row.
Actions: Wrote UNITS.md (9 units). One red-green cycle with spec test GameTest.testQuitAtStartShowsBoardAndGameOver, then a printer store-cell refactor. Mutation 28/39 killed. All 11 survivors set aside as indistinguishable within this unit: P1/P2 row and store index swaps (all pits equal at start, killed once sowing lands), QUIT constant (consistent both sides), main() flags (unreached), lower bound 0 (no requirement names the output for input 0), Board row count and houses[0] vs [1] length (equivalent). No kept survivor so no extra test.
2026-10-29T06:49:10Z. Step: L1-8 iteration 2. Unit: Sow chosen house into following pits and pass the turn. Tests added: 2. Cycles: 2. Sha: 8bae5da. Agent: rep-2-r19:L1-8#2. Tokens: 580694. Seconds: 275.281.
Actions: Red-green cycle 1 with spec test GameTest.testSowIntoFollowingHousesThenPassTurn: added Board.sow (own row only) and a turn loop in Kalah.play. Mutation 42/53 killed. Kept survivors: Board.java:30 seed count read from row[house] or row[house+1] (changes the sown board). Cycle 2 added GameTest.testSowTakesOnlyTheChosenHousesSeeds with values from the rules; it passed on real code and killed both. Rerun 44/53 with 9 survivors set aside: input lower bound 0 (no requirement names its output), store index swaps in the printer (stores stay 0 until the store unit), main() flags and QUIT constant (unreached or consistent), Board array sizes and houses[0] length (equivalent). Edits to UNITS.md made with sed per the step tooling; shell heredocs used for spec files which conflicts with the standing Edit/Write guidance.
Actions: Red-green cycle 1 with spec test GameTest.testSowIntoOwnStoreSkipOpponentsStoreAndWrap (8 moves, each passing the turn, ending with P2 sowing house 6 past P1's store back onto P2 house 1). Expected values came from a rule model of the README in .scratch (gitignored), checked against the existing sow spec and by hand for the last two moves. It failed with an index error. Board.sow then walked both rows and the mover's store and the test passed. Mutation 52/59 killed with every Board.sow mutant killed. 7 survivors set aside as in earlier units: Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0 (no requirement names its output). No kept survivor so no extra test. Python was used only for scratch search and spec generation. Code edits used Edit.
2026-10-29T06:59:52Z. Step: L1-8 iteration 4. Unit: Extra move when the last seed lands in the mover's store. Tests added: 1. Cycles: 1. Sha: 42da51f. Agent: rep-2-r19:L1-8#4. Tokens: 553928. Seconds: 300.05.
Actions: Red-green cycle 1 with spec test GameTest.testLastSeedInOwnStoreGivesAnotherMove (P1 house 3 ends in store and P1 moves again, then P2 house 3 likewise, expected values hand-derived from the README rules). It failed red, then Board.sow returned whether the last seed hit the store and Kalah.play kept the turn on true. Mutation 53/61 killed with one invalid. 8 survivors set aside: Board.java:37 inStore initial value (differs only for an empty-house sow whose output belongs to the empty-house unit), Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0 (no requirement names its output). No kept survivor so no extra test. The Write tool trimmed trailing prompt spaces in the spec so sed restored them, and sed ticked UNITS.md, which conflicts with the standing Edit/Write guidance.
2026-10-29T07:06:31Z. Step: L1-8 iteration 5. Unit: Capture the last seed and the non-empty opposite house. Tests added: 2. Cycles: 2. Sha: 500bcc2. Agent: rep-2-r19:L1-8#5. Tokens: 741612. Seconds: 398.915.
Actions: Red-green cycle 1 with spec test GameTest.testLastSeedInOwnEmptyHouseCapturesOppositeSeeds (P2 then P1 capture, expected values from a README rule model in .scratch, gitignored, and checked by hand). It failed red, then Board.sow called a new Board.capture when the last seed lands in an own house that was empty. Mutation 74/84 killed. Kept survivors: Board.java:64 opposite count > to >= (captures from an empty opposite house) and 0 to 1 (no capture of a single opposite seed), both outputs the requirement names. Cycle 2 added GameTest.testCaptureNeedsOnlyOneOppositeSeedAndNoneWhenOppositeIsEmpty with values from the rules. It passed on real code and killed both. Rerun 76/84 with 8 survivors set aside as in iteration 4: Board.java:37 inStore initial value, Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0. Python used only for the scratch model and spec generation and sed only to set the spec comment line, which conflicts with the standing Edit/Write guidance. Code and UNITS.md edits used Edit.
2026-10-29T07:10:12Z. Step: L1-8 iteration 6. Unit: Reject an empty house and prompt the same player again. Tests added: 1. Cycles: 1. Sha: 7e162ee. Agent: rep-2-r19:L1-8#6. Tokens: 469756. Seconds: 222.15.
Actions: Red-green cycle 1 with spec test GameTest.testEmptyHouseIsRejectedAndSamePlayerMovesAgain (P1 then P2 choose an emptied house, see "House is empty. Move again.", the board and their own prompt again; expected values hand-derived from the README and the clockwise useempty example format). It failed red on the missing message, then Kalah.play checked Board.seeds before sowing. Mutation 79/87 killed with one invalid, and every new empty-house mutant in Kalah.java:36-37 was killed. 8 survivors set aside: Board.java:37 inStore initial value (now equivalent because sow is never called on an empty house), Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0 (no requirement names its output). No kept survivor so no extra test. The Write tool trimmed trailing prompt spaces in the spec so sed restored them, which conflicts with the standing Edit/Write guidance.
2026-10-29T07:20:19Z. Step: L1-8 iteration 7. Unit: End the game when the mover has no seeds, print scores and the winner or a tie. Tests added: 3. Cycles: 3. Sha: afdd2d8. Agent: rep-2-r19:L1-8#7. Tokens: 1349351. Seconds: 600.292.
Actions: Red-green cycle 1 with spec test GameTest.testGameEndsWhenMoverHasNoSeedsAndHigherScoreWins (P2 has no seeds on their turn, P1 wins 44-4). Expected values came from a README rule model in .scratch (gitignored) that reproduces examples full_game2.txt exactly, plus hand sums of houses and stores. It failed red, then Board gained hasMove and score and Kalah.play printed Game over, the board, both scores and the result. Mutation 95/107 killed with one invalid. Kept survivors: Kalah.java:58 removed "A tie!", Kalah.java:60 winner 2 to 3 (P2 win), Board.java:29 hasMove seeds > 0 to > 1 (game ends while only single-seed houses remain). Cycle 2 added GameTest.testSingleSeedHousesStillMoveAndEqualScoresTie (24-24 with a single-seed turn) and cycle 3 added GameTest.testGameEndsWhenP1HasNoSeedsAndP2Wins (11-37). Both passed on real code. Rerun 98/107 with 9 survivors set aside: Kalah.java:60 > to >= (equivalent since equal scores take the tie branch), Board.java:55 inStore initial value, Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0 (no requirement names its output). Python used for the scratch model and spec generation and a heredoc for this row, which conflicts with the standing Edit/Write guidance. Code, test and UNITS.md edits used Edit.
Actions: Red-green cycle 1 with spec test GameTest.testClockwiseLayoutShowsP2HousesOnTopAndP1StoreTopLeft (clockwise 6-4, extra moves for P1 then P2 so both stores differ, then quit). Expected values hand-derived from the README layout and the clockwise useempty example format. It failed red on the anti-clockwise top row. AnticlockwisePrinter became BoardPrinter with a clockwise flag that mirrors each row, and Kalah.play passes clockwise. Mutation 100/110 killed with one invalid and every BoardPrinter mutant killed. 9 survivors set aside as in iteration 7: Kalah.java:60 > to >= (equivalent), Board.java:55 inStore initial value, Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0 (no requirement names its output). No kept survivor so no extra test. CI 26 tests with only ExampleClockwiseTest.testSimpleStart75 failing, which needs the 7-5 unit. The Write tool trimmed trailing prompt spaces in the spec so sed restored them, which conflicts with the standing Edit/Write guidance.
2026-10-29T07:32:27Z. Step: L1-8 iteration 9. Unit: Play with 7 houses per player and 5 seeds per house (sevenfive = true). Tests added: 1. Cycles: 1. Sha: 7bf76b0. Agent: rep-2-r19:L1-8#9. Tokens: 566313. Seconds: 257.42.
Actions: Red-green cycle 1 with spec test GameTest.testSevenFivePlaysSevenHousesOfFiveSeeds (anti-clockwise 7-5: P1 house 3 ends in the store after house 7 for another move, P1 house 7 sows into P2 houses 1-5, P2 house 7 sows into P1 houses 1-4, then quit). Expected values hand-derived from the SPEC change case and the README rules. It failed red on the 6-house board, then Kalah.play built Board(7, 5) when sevenfive is true. Mutation 102/111 killed with one invalid and all four Kalah.java:26 board-size mutants killed. 9 survivors set aside as in iteration 8: Kalah.java:60 > to >= (equivalent), Board.java:55 inStore initial value, Board array sizes and houses[0] length (equivalent), QUIT constant, main() flags (unreached), input lower bound 0 (no requirement names its output). No kept survivor so no extra test. CI 19 tests all pass, ExampleClockwiseTest.testSimpleStart75 included. The Write tool trimmed trailing prompt spaces in the spec so sed restored them, which conflicts with the standing Edit/Write guidance.
Raw inputs
metrics.json
summary.json
grade.tsv
costs.json
steps.csv
audit.json
review.json
LOG.md
MEASURE.md
classdiagram.uml
classdiagram.png
classdiagram.svg
collect.tsv
rating.json
MEASURE.md
The method's measure agent answered its Measure line from LOG.md and git. Agent-written text is shown verbatim and unchecked. Words such as recomputed inside it are the agent's own and are not tags of this page. Its Measure lines describe measurement during the run. Harness scores were measured separately after the run. Agent text may quote git commit times in the host's local zone. Harness times are UTC.
# Measure
Method: most informative next test. Sources: LOG.md, git log. GAP.md and ATTEMPTS.md do not exist in this clone.
Credits and time are measured by the harness and are not recorded here.
## Mutation score per requirement
LOG.md records one `./run.sh mutate` total per iteration over all of `src/`. It names surviving mutants by file and line but gives no per-class totals. The table gives the final total per requirement and attributes the survivors to classes from the LOG.md notes.
| iteration | requirement | first run | final run | final score | survivors by class |
|---|---|---|---|---|---|
| 1 | Anti-clockwise 6-4 starting board and quit | 28/39 | 28/39 | 72% | 11 across Kalah, Board and the printer. Row and store index swaps (equal at start), QUIT constant, main() flags, input lower bound 0, Board array sizes |
| 2 | Sow chosen house and pass the turn | 42/53 | 44/53 | 83% | Printer store index swaps. Kalah QUIT, main() flags, lower bound 0. Board array sizes and houses[0] length |
| 3 | Sow into own store, skip opponent's store, wrap | 52/59 | 52/59 | 88% | Board.sow none. Board array sizes. Kalah QUIT, main() flags, lower bound 0 |
| 4 | Extra move on last seed in own store | 53/61 | 53/61 | 87% | Board inStore initial value plus array sizes. Kalah QUIT, main() flags, lower bound 0 |
| 5 | Capture into own empty house | 74/84 | 76/84 | 90% | Board inStore initial value plus array sizes. Kalah QUIT, main() flags, lower bound 0 |
| 6 | Reject an empty house | 79/87 | 79/87 | 91% | Board inStore initial value (now equivalent) plus array sizes. Kalah QUIT, main() flags, lower bound 0 |
| 7 | End of game, scores and winner or tie | 95/107 | 98/107 | 92% | Kalah `>` to `>=` at line 60 (equivalent), QUIT, main() flags, lower bound 0. Board inStore initial value plus array sizes |
| 8 | Clockwise layout | 100/110 | 100/110 | 91% | BoardPrinter none. Kalah and Board as in iteration 7 |
| 9 | 7 houses of 5 seeds | 102/111 | 102/111 | 92% | BoardPrinter none. Kalah and Board as in iteration 7 |
Invalid mutants are excluded from the totals as LOG.md reports them. Every survivor left at the final run of each iteration was set aside as equivalent or outside the requirement. The recurring set is Board array sizes, the Board inStore initial value, the Kalah QUIT constant, the main() flags, the input lower bound 0 and from iteration 7 the Kalah `>=` tie branch.
## Real defects found by killing tests
None. Four requirements kept survivors and each got one or two killing tests. All of them passed on the real code at once. They pinned behaviour the code already had and found no defect.
| iteration | survivor | killing test |
|---|---|---|
| 2 | Board.java:30 seed count read from `row[house+1]` | GameTest.testSowTakesOnlyTheChosenHousesSeeds |
| 5 | Board.java:64 capture from an empty opposite house and no capture of one seed | GameTest.testCaptureNeedsOnlyOneOppositeSeedAndNoneWhenOppositeIsEmpty |
| 7 | Kalah.java:58 tie message removed. Board.java:29 hasMove `> 0` to `> 1` | GameTest.testSingleSeedHousesStillMoveAndEqualScoresTie |
| 7 | Kalah.java:60 winner 2 to 3 | GameTest.testGameEndsWhenP1HasNoSeedsAndP2Wins |
## Tests that broke in later refactors
None. git log shows only additions to test/ after each test was written. No commit deletes or changes a line of an existing test or spec file. The two refactors were the printer store-cell change in iteration 1 and the AnticlockwisePrinter to BoardPrinter change in iteration 8. Neither needed a test change.
## Totals
| item | value |
|---|---|
| requirements done | 9 of 9 |
| tests added (GameTest) | 13 |
| red-green cycles | 13 |
| final mutation score | 102/111 (92%) |
| real defects found | 0 |
| tests broken by refactors | 0 |