Alterability. Item: Change Case 1: sow seeds anti-clockwise. Score /5: 5.
Reason: Direction is handled only in BoardView. Board sowing works the same whatever the direction, so the change sits in one small file plus the flag passed through Kalah.
Kalah TDD study · Part 20 of 29 · Designs
State rules over input regions. Generators sample and shrink.
Source run full-1 at tdd-experiment c3dd988
Search and validation
What it changes: The check. One test covers an input region.
One method of the study, from runs full-1. The survey build is the method's single build in run full-1. 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.
The procedure supplied to the agents. Indented lines run under the line above them.
Family: Search and validation. Idea: State rules over input regions. Generators sample and shrink. What it changes in the search: The check. One test covers an input region.
repeat per requirement until none is open:1. Phrase the next requirement as an invariant, round trip or model comparison.2. Write a generator for a narrow slice of valid inputs.3. Run the property and watch it fail with a shrunk counterexample.4. Make the smallest change that makes the property pass.5. Widen the generator toward all valid inputs and repeat until green.6. Save each shrunk counterexample as a fixed example test.7. Refactor with the properties as the safety net.once:8. In CI log the seed and replay saved failures before fresh random cases.
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 20.1
Next: Once: step 8.
Loop: repeat per requirement, back to Steps 1 to 7.
2 stages from the run facts, each checked against its block of the steps above. Details and notes are in the stage table. Tag: recomputed.
Next: Once: step 8.
Loop: repeat per requirement, back to Steps 1 to 7.
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 7 | repeat per requirement until none is open: | 1. Phrase the next requirement as an invariant, round trip or model comparison. 2. Write a generator for a narrow slice of valid inputs. 3. Run the property and watch it fail with a shrunk counterexample. 4. Make the smallest change that makes the property pass. 5. Widen the generator toward all valid inputs and repeat until green. 6. Save each shrunk counterexample as a fixed example test. 7. Refactor with the properties as the safety net. | unit requirement | No property library is on the classpath. Write generators over java.util.Random with a logged seed. |
| Once: step 8 | once: | 8. In CI log the seed and replay saved failures before fresh random cases. | none | none |
One build in run full-1.
One survey build. It passed every hidden test with adjusted mutation 1.000, 4 classes and 5 PMD violations. It gained 52 of its 76 hidden tests in one step and rewrote 1 percent of the src lines it added. Tag: recomputed.
The report's class diagram for this design is identical to Figure 20.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 (5 violations) |
| Mutation score | 116/123, 0 not run, adjusted 116/116 (0 of 7 survivors fail hidden tests) |
| Classes | 4 |
| Simple Constructs /5 | 4 |
| Minimal Duplication /5 | 3 |
| Modular Structure /5 | 4 |
| Problem Alignment (tentative) /5 | 4 |
| Weighted tokens | 1,234,954 |
| Bench median ms | 553 |
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.
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.
| Build | property-based |
|---|---|
| Adjusted mutation | 1.000 |
| Classes | 4 |
| Cost to completion | 1,171,669 |
| Strict PMD violations | 5 |
Figure 20.2
4 classes and 6 links. 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.
Each clone's own report, as in its REPORT.md.
Branch method/property-based. 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.
| 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 |
| Metric | Value | Tag |
|---|---|---|
| Total lines | 1562 (src 234, own tests 1328) | recomputed |
| Lines of code | 1237 (src 175, own tests 1062) | recomputed |
| Classes | 4 | recomputed |
| Methods | 22 | recomputed |
| Fields | 5 | recomputed |
| Bench median ms | 553 | 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/.
| Metric | Value | Tag |
|---|---|---|
| Mutation score | 116/123, 0 not run, adjusted 116/116 (0 of 7 survivors fail hidden tests) | recomputed |
| PMD lines | 5 (5 violations) | recomputed |
| Dependency edges | 5 | recomputed |
| Review scores (superseded) | Alterability 5, Code quality principles 4.2, Test quality 4 | unchecked |
| Tokens | 7,851,434 (input 396, cache creation 554,603, cache read 7,260,782, output 35,653) | recomputed |
| Weighted tokens | 1,234,954 | recomputed |
| Wall time | 0:29:48 | recomputed |
| Agent time | 0:28:44 | recomputed |
| Agent calls | 12 | recomputed |
| Audit flags | 0 high, 8 low | recomputed |
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.
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.
Alterability. Item: Change Case 1: sow seeds anti-clockwise. Score /5: 5.
Reason: Direction is handled only in BoardView. Board sowing works the same whatever the direction, so the change sits in one small file plus the flag passed through Kalah.
Alterability. Item: Change Case 2: 7 houses with 5 seeds. Score /5: 5.
Reason: The variant appears only as two ternaries in play() that size the Board. Board, BoardView and Match all work from houseCount(), so no other code changes.
Code quality principles. Item: 1. Clear Presentation. Score /5: 4.
Reason: Classes and methods are short and laid out cleanly. The sow loop uses a pit = -1 reset and side/player index juggling that takes some effort to follow.
Code quality principles. Item: 2. Explanatory Language. Score /5: 4.
Reason: Names such as sow, capture, houseSeeds, score and isOver match the domain, and the Javadoc explains why. Arithmetic like 3 - player and 1 - side encodes the opponent without a named helper.
Code quality principles. Item: 3. Consistent Code. Score /5: 4.
Reason: Players are 1-based through the public API and 0-based inside, and that holds everywhere. Kalah.java mixes tab indentation from the starter with spaces in the new code.
Code quality principles. Item: 4. Used Content. Score /5: 4.
Reason: Nearly everything is used by play(). Board.total() exists only for the tests.
Code quality principles. Item: 5. Simple Constructs. Score /5: 4.
Reason: Plain arrays, loops and a null-returning message keep it simple. Returning a nullable String from move() as a signal and the sentinel-driven sow loop are slightly awkward.
Code quality principles. Item: 6. Minimal Duplication. Score /5: 4.
Reason: There is little repetition. total() repeats the house summing that houseSeeds() already does, and the sevenfive ternary is evaluated twice.
Code quality principles. Item: 7. Modular Structure. Score /5: 5.
Reason: Board (state and rules), Match (turn), BoardView (rendering) and Kalah (I/O loop) each have one clear job with narrow interfaces.
Code quality principles. Item: 8. Problem Alignment. Score /5: 5.
Reason: The structure follows the game's concepts of houses, stores, sowing, capture and turns. Treating direction as a matter of presentation reflects the symmetry of the board.
Test quality. Item: Test quality. Score /5: 4.
Reason: Property tests with independent reference models pin sowing, capture, rendering, game end and full spec replays across all four variants, with named regression cases. The suite is large and its files depend on each other's helpers (SowPropertyTest.Game). Comments record red-run history, and the prompt model reuses the production BoardView.
0 high and 8 low flags from agent tool calls and the method's commits. Only audit.json lists the low flags.
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.
2026-10-15T23:54:47Z. Step: L1-7 iteration 1. Unit: Initial board. Tests added: 4. Cycles: 1. Sha: 95ad92f. Agent: property-based:L1-7#1. Tokens: 634376. Seconds: 100.857.
Actions: Wrote UNITS.md (10 units). Added seeded property runner test/kalah/Property.java and Board. Narrow generator (6,4) went red with shrunk counterexample (houses=1, seeds=1), stub fixed, generator widened to houses 1-10 seeds 0-11 green, counterexample saved as fixed test, refactored Board to pit arrays under the property. Checks: ./run.sh test BoardPropertyTest only, as the step names no other check.
2026-10-15T23:56:28Z. Step: L1-7 iteration 2. Unit: Seed conservation. Tests added: 3. Cycles: 1. Sha: 987a997. Agent: property-based:L1-7#2. Tokens: 592947. Seconds: 103.491.
Actions: Added SowPropertyTest over replayed move sequences (illegal moves skipped) and Board.sow. Narrow generator (6-4, one move) went red against an emptying stub with shrunk counterexample (houses=1, seeds=1, P1:1). Implemented sowing along own houses, own store, opponent houses, skipping opponent store (direction affects rendering only, per the anticlockwise specs). Widened to 1-10 houses, 0-11 seeds, up to 40 moves, green. Saved counterexample plus a 13-seed full-lap case as fixed tests. No refactor needed. Checks: ./run.sh test SowPropertyTest only, as the step names no other check.
2026-10-15T23:58:16Z. Step: L1-7 iteration 3. Unit: Sowing order. Tests added: 4. Cycles: 1. Sha: 80c3010. Agent: property-based:L1-7#3. Tokens: 467867. Seconds: 102.89.
Actions: Added SowingOrderPropertyTest with a reference that walks the on-screen board ring per direction (layout from the example specs) and skips the opponent store. Narrow generator (6-4 and 7-5 single move, both directions) was green on the first run because Board.sow from iteration 2 already follows the cycle, so no production change was needed. To see step 3 fail, an opponent-store fault was injected into Board.sow: the widened property went red with shrunk counterexample clockwise (houses=2, seeds=4, P1:2), then git restore made it green. Narrow test folded into the widened property (1-10 houses, 0-11 seeds, up to 40 moves). Saved the counterexample plus the 7-5 clockwise simple_start move and a 13-seed anti-clockwise lap as fixed tests. Checks: ./run.sh test SowingOrderPropertyTest only, as the step names no other check.
2026-10-15T23:59:24Z. Step: L1-7 iteration 4. Unit: Extra turn. Tests added: 3. Cycles: 1. Sha: b5772b3. Agent: property-based:L1-7#4. Tokens: 422817. Seconds: 64.47.
Actions: Added ExtraTurnPropertyTest with an oracle that counts pits along the 2 x houses + 1 sowing cycle (store is houses - house + 1 pits after the chosen house). Board.sow now returns boolean, first as a false stub. Narrow generator (6-4 start, one move) went red with shrunk counterexample (houses=6, seeds=4, P1:3). Fixed by returning whether sowing ended at the store position. Widened to the shared game generator (1-10 houses, 0-11 seeds, up to 40 moves), green; narrow generator folded into it. Saved the counterexample plus a one-short and a 13-seed lap case as fixed tests. No refactor needed. Checks: ./run.sh test ExtraTurnPropertyTest only, as the step names no other check.
2026-10-16T00:08:50Z. Step: L1-7 iteration 5. Unit: Capture. Tests added: 3. Cycles: 2. Sha: bf2f3e5. Agent: property-based:L1-7#5. Tokens: 794533. Seconds: 565.752.
Actions: Added CapturePropertyTest with a ring reference (own houses, own store, opponent houses) that sows then captures when the last seed ends in an own house holding 1 seed and the facing house (houses + 1 - house) is non-empty. Narrow generator (6-4, up to 10 moves) went red with shrunk counterexample (houses=6, seeds=4, P1:6 P1:2), the README capture example. Added Board.capture after sowing, green. Widened to the shared game generator (1-10 houses, 0-11 seeds, up to 40 moves), green; narrow generator folded into it. Saved the counterexample and an empty-opposite no-capture case as fixed tests. Exact-lap capture checked against examples exactlapemptycapture.txt. Refactor safety-net run of ./run.sh test turned SowingOrderPropertyTest red because its reference had no capture (conflicting test), so its reference now applies the same capture step, all five property classes green; the six example tests stay red until play() exists. Checks: ./run.sh test CapturePropertyTest, then ./run.sh test for the property safety net.
2026-10-16T00:10:59Z. Step: L1-7 iteration 6. Unit: Empty house. Tests added: 3. Cycles: 1. Sha: 5d88a4a. Agent: property-based:L1-7#6. Tokens: 416422. Seconds: 125.738.
Actions: Added Match (board plus whose turn, P1 first) with move(house) returning the message to print, and EmptyHousePropertyTest asserting that choosing an empty house returns "House is empty. Move again." and leaves board snapshot and turn unchanged while legal moves return null. Stub that always sowed went red on the narrow generator (6-4, up to 6 choices) with shrunk counterexample (houses=5, seeds=4, P1:2 P1:2), an extra turn followed by the emptied house. Fixed with an empty-house check before sowing, green. Widened to the shared game generator (1-10 houses, 0-11 seeds, up to 40 moves), green; narrow generator folded into it. Saved the counterexample and the useempty.txt sequence as fixed tests. No refactor needed. Printing via IO waits for play(). Checks: ./run.sh test EmptyHousePropertyTest only, as the step names no other check.
2026-10-16T00:13:02Z. Step: L1-7 iteration 7. Unit: Board rendering. Tests added: 5. Cycles: 2. Sha: 34235c3. Agent: property-based:L1-7#7. Tokens: 871807. Seconds: 125.695.
Actions: Added BoardView.lines(board, clockwise) and RenderPropertyTest, whose parser reads each row's P1 or P2 label so it does not depend on direction, plus a layout check against the screen geometry of SowingOrderPropertyTest.ring. Narrow generator (anti-clockwise 6-4, up to 30 moves) went red against an empty stub with shrunk counterexample anti-clockwise (houses=1, seeds=0, no moves). Implemented the anti-clockwise layout, green. Widened to all four variants (6-4 and 7-5, both directions), red with shrunk counterexample clockwise (houses=1, seeds=0, no moves). Added the mirrored clockwise layout, green. Saved both counterexamples plus exact-text tests for the anti-clockwise 6-4 simple_start board after P1:1 and the clockwise 7-5 start board. Refactor was an Arrays import only. Checks: ./run.sh test RenderPropertyTest only, as the step names no other check.
2026-10-16T00:15:45Z. Step: L1-7 iteration 8. Unit: Prompt and quit. Tests added: 5. Cycles: 3. Sha: 696f171. Agent: property-based:L1-7#8. Tokens: 1131808. Seconds: 157.525.
Actions: Added PromptPropertyTest with a ScriptedIO (records prompts and printed lines, answers readInteger from a script ending in q) and a model built from Match plus BoardView in the example spec layout: start board, then per choice the mover's prompt, any message and the board, then prompt, "Game over" and the board. Choices stop before a move that would end the game, as game end is a later unit. Narrow generator (anti-clockwise 6-4, quit at once) went red against the stub with shrunk counterexample anti-clockwise (houses=6, seeds=4, no moves). Added board, one prompt and Game over, green. Widened to up to 30 choices, red with shrunk counterexample (houses=6, seeds=4, P1:1). Added the readInteger loop over Match.move, green. Widened to all four variants, red with shrunk counterexample anti-clockwise (houses=7, seeds=5, no moves). Sized the board from sevenfive, green. Saved the three counterexamples plus the useempty sequence as fixed tests. No refactor needed. Checks: ./run.sh test PromptPropertyTest, then ./run.sh test as the refactor safety net: all property classes green, quit, exactlapemptycapture, useempty and simple_start specs now pass, full_game2 and full_game_tie stay red at game end (later unit).
2026-10-16T00:17:20Z. Step: L1-7 iteration 9. Unit: Game end and scores. Tests added: 3. Cycles: 1. Sha: 7cff8f0. Agent: property-based:L1-7#9. Tokens: 572565. Seconds: 92.044.
Actions: Added GameEndPropertyTest: a case is a variant plus picks, each pick choosing among the mover's non-empty houses and the lowest one after the picks run out, so every case plays to the end (capped at 5000 moves). The invariant: scores (houses plus store) sum to the starting total, and play() output ends with the last board, then with no further prompt "Game over", the board, a tab-indented score line per player and "Player N wins!" or "A tie!" for the higher score. Narrow generator (anti-clockwise 6-4, up to 60 picks) went red with shrunk counterexample anti-clockwise 6-4 picks=[]. Added Board.houseSeeds and Board.score, Match.isOver and the result lines in play(), green. Widened to all four variants, green on first run. Saved the counterexample plus clockwise 7-5 lowest-house as fixed tests. Refactor merged the quit and game-end exits into one ending. Checks: ./run.sh test GameEndPropertyTest, then ./run.sh test as the refactor safety net: all 11 classes green, full_game2 and full_game_tie specs now pass.
2026-10-16T00:19:43Z. Step: L1-7 iteration 10. Unit: Full games. Tests added: 4. Cycles: 1. Sha: 6c2df1f. Agent: property-based:L1-7#10. Tokens: 1061181. Seconds: 147.799.
Actions: Added FullGamePropertyTest: a case is an example spec, a cut and a mirror flag. The derived spec keeps the spec's lines up to input number cut, turns that input into q and appends "Game over" and the last board (a cut past the last input keeps the whole spec). Mirroring reverses the cells of each house row, which draws the same counts in the other direction, so clockwise 7-5 simple_start also covers the anti-clockwise 7-5 variant that has no spec. play() runs on a ScriptedIO fed the derived inputs and its output must equal the derived output lines. Narrow generator (each spec in full) was green on the first run, then widened to any cut and then to mirroring, green each time, because play() already passed all six specs after iteration 9. Conflict with step 3 (watch it fail): no production change could be made smaller, so the red came from a temporary fault, capture disabled in Board, which went red with shrunk counterexample full_game2.txt cut=12 (quit just after the first capture); Board was restored with git restore, green. Saved that counterexample plus mirrored simple_start (anti-clockwise 7-5) and mirrored full_game_tie as fixed tests. No refactor needed. Checks: ./run.sh specs once at the start to see spec status (6 of 6 pass), then ./run.sh test FullGamePropertyTest for each run.
2026-10-16T00:21:15Z. Step: s8. Unit: CI seed logging and replay of saved failures. Tests added: 4. Cycles: 2. Sha: b38c93c. Agent: property-based:s8. Tokens: 596470. Seconds: 87.549.
Actions: The runner already printed one seed per property. Added test/kalah/property-failures.txt (lines of seed and property name) and Property.savedSeeds, and forAll now runs every saved seed for the property, logged as "replay seed=N", before the fresh run logged as "seed=N" (still overridable with -Dkalah.seed). A failure message names which seed failed, so its seed can be added to the file. Cycle 1: PropertyTest (saved seed read for its own property only, first case drawn from the saved seed, replay plus fresh run, no saved seeds means fresh only) red at compile, then green. Cycle 2: replay failure names "replay seed=42", red with "failed with seed=42", fixed, green. The file holds only the self-test seed 42 because earlier iterations did not record their failing seeds; their shrunk counterexamples are already fixed example tests. Checks: ./run.sh test PropertyTest per cycle, then ./run.sh test once as CI: 13 classes, 0 failed.
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: Property-based TDD. Sources: LOG.md, git log (95ad92f to 4eef089) and the test sources. GAP.md and ATTEMPTS.md do not exist in this clone. Credits and time are measured by the harness and are not recorded here.
## Properties per verb
Ten domain properties over five production verbs, plus one runner self-test property. Each property is one `Property.forAll` call. `recomputed` from the test sources.
| verb | properties | names |
|---|---|---|
| `new Board` | 1 | initial board |
| `Board.sow` | 4 | seed conservation, sowing order, extra turn, capture |
| `Match.move` | 1 | empty house |
| `BoardView.lines` | 1 | board rendering |
| `Kalah.play` | 3 | prompt and quit, game end and scores, full games |
| `Property.forAll` (runner) | 1 | runner self-test |
Mean 2.0 domain properties per verb. `Board.sow` carries the most because sowing, extra turn and capture all live in it. `Board.houseSeeds`, `Board.score` and `Match.isOver` have no property of their own. They are covered through the game end property.
## Defects caught that example tests missed
Zero recorded. `recomputed` from LOG.md.
| source of red | count | would the example specs also fail |
|---|---|---|
| red against a stub or missing feature (iterations 1, 2, 4 to 9) | 11 | yes. The specs stayed red until play() existed in iterations 8 and 9 |
| injected fault: sowing into the opponent store (iteration 3) | 1 | likely through the lap specs. `unchecked` |
| injected fault: capture disabled (iteration 10) | 1 | yes. full_game2 contains a capture |
| conflicting test: the sowing order reference lacked capture (iteration 5) | 1 | not a production defect |
Every property red came from a stub, a missing feature or a deliberate fault. None came from code that already passed the six example specs. The properties do reach inputs the specs never show, such as one-house boards, house counts 1 to 10, seed counts 0 to 11 and the anti-clockwise 7-5 variant, which has no spec. Iteration 8 first saw the sevenfive sizing gap on that variant. The clockwise 7-5 simple_start spec exercises the same gap, so it does not count as a miss.
## Failures that do not replay from their seed
Zero observed. `recomputed` from LOG.md and test/kalah/property-failures.txt.
- Iterations 1 to 10 logged shrunk counterexamples and saved each one as a fixed test. They did not record the failing seeds, so seed replay of those failures was never exercised.
- Step s8 added seed logging and replay of saved seeds. The only saved seed is the runner self-test seed 42, and its replay passed in PropertyTest.
- Replay determinism therefore rests on one checked seed.
See Methodology: measures and the Glossary for the terms and table columns this page uses.