Kalah TDD study · Part 2 of 29 · Approach

Experimental design and approach

The study question, the task, the runs and arms, their caps and where the study sits in the course.

Source runs full-1, tcp-1-list2, rep-1, rep-2, pilot-1, pilot-2, tcp-1, tcp-1-list and rep-2/rebuild at tdd-experiment c3dd988

Contents

Study question

Classic greedy TDD writes the smallest failing test and then the smallest change that passes it. Do TDD variants that plan the class structure first, change the step size, try several starts or change how the tests check the code lead an AI coding agent to a better Kalah solution?

Run ended 2026-10-16. Model Claude Opus 5.5 (claude-opus-5-5). Runs: full-1 survey, tcp-1-list2 list reliability, rep-1 planned contrasts, rep-2 planned contrasts. 11 survey methods. 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.

Task and variants

The agent builds the course's Kalah assignment. The brief below is docs/SPEC.md at tdd-experiment c3dd988 verified.

Excerpt of the Assignment 2 brief ("Making Changes"), adapted for this experiment. The game rules and the output format are in README.md. Example specs are in examples/.

Task

Implement Kalah so that it supports all four variants below, and keep the implementation alterable. The variant is chosen by the two boolean parameters of play().

Restrictions

A significant amount of the assessment is based on an automatic marking system. If you ignore any of the following restrictions, your submission will not be marked.

  • No Java 9 (or later) features, including JDK. Java 8 is allowed.
  • No reference to any other files (e.g. use of configuration files).
  • No use of third-party libraries.
  • Do not use System.exit() under any circumstances.

The play() method

A test suite tests all variants together through this method:

    /**
     * Play a game of Kalah.
     * @param io Where to get input from and direct output to
     * @param clockwise If true, then sowing of seeds should be done in a clockwise direction,
     * otherwise if false sowing should be in an anti-clockwise direction.
     * @param sevenfive If true, then the game should have 7 houses per player, and start with 5 seeds in each house,
     * otherwise if false then it should have 6 houses per player starting with 4 seeds per house.
     */
    public void play(IO io, boolean clockwise, boolean sevenfive) {
      ....
    }

The Kalah.java stub runs the anti-clockwise 6-4 variant because of the parameters its main() passes to play(). To play another variant, change those values:

  public static void main(String[] args) {
      new Kalah().play(new MockIO(), false, false); // Change values of boolean parameters as needed
  }

So to change to the clockwise 6-4 variant, change the first parameter to true.

Variants

Your implementation must allow all 4 variants: 6 houses with 4 seeds both clockwise and anti-clockwise, and 7 houses with 5 seeds both clockwise and anti-clockwise. The specific variant being tested is given by how clockwise and sevenfive are set. The test cases are the same scenarios for each variant (4 sets of test cases). examples/EXAMPLES.md lists a sample of the test specifications.

The four variants that play() selects verified.

clockwisesevenfiveHouses per playerSeeds per houseSowing
falsefalse64anti-clockwise
truefalse64clockwise
falsetrue75anti-clockwise
truetrue75clockwise

Change cases

The implementation must allow all combinations of these two change cases.

Change Case 1: Sow seeds in an anti-clockwise direction

The game can be played with seeds sown in an anti-clockwise direction, the opposite of the clockwise sowing described in README.md.

Change Case 2: 7 houses with 5 seeds

The game can be played with 7 houses per player, each house starting with 5 seeds.

Harness pipeline

Every run goes through the same harness. Agents do the building, reviewing and rating. Harness scripts do the rest.

Figure 2.1

Harness pipeline of one run

Harness pipeline of one runargs.py writes the run's arguments. batch.js runs each method's stages in its own clone, then a blind review and a measure agent per method. after.py, collect.sh, three blind raters and render.py follow.HarnessAgentsHarnessAgentsargs.pyargs.json with model,effort and capsMethod stagesbatch.js, one cloneper methodBlind reviewbatch.js, one permethodMeasure agentMEASURE.md per methodafter.pyslugs.tsv andbatch.json for collectcollect.sh16 steps per clone, 7for a list runThree blind ratersrate.js, eight cqpprinciplesrender.pyreport pageper clonerepeat per unit
  1. args.py. args.json with model, effort and caps. Lane: Harness.

    Next: Method stages (per clone).

  2. Method stages. batch.js, one clone per method. Lane: Agents.

    Next: Blind review.

    Loop: repeat per unit, back to Method stages.

  3. Blind review. batch.js, one per method. Lane: Agents.

    Next: Measure agent.

  4. Measure agent. MEASURE.md per method. Lane: Agents.

    Next: after.py.

  5. after.py. slugs.tsv and batch.json for collect. Lane: Harness.

    Next: collect.sh.

  6. collect.sh. 16 steps per clone, 7 for a list run. Lane: Harness.

    Next: Three blind raters.

  7. Three blind raters. rate.js, eight cqp principles. Lane: Agents.

    Next: render.py.

  8. render.py. report page. Lane: Harness.

The step order follows the harness sources at tdd-experiment c3dd988 verified. One step has no source check. render.py draws the report again once the ratings land unchecked.

Text version: Harness pipeline of one run
  1. args.py. args.json with model, effort and caps. Lane: Harness.

    Next: Method stages (per clone).

  2. Method stages. batch.js, one clone per method. Lane: Agents.

    Next: Blind review.

    Loop: repeat per unit, back to Method stages.

  3. Blind review. batch.js, one per method. Lane: Agents.

    Next: Measure agent.

  4. Measure agent. MEASURE.md per method. Lane: Agents.

    Next: after.py.

  5. after.py. slugs.tsv and batch.json for collect. Lane: Harness.

    Next: collect.sh.

  6. collect.sh. 16 steps per clone, 7 for a list run. Lane: Harness.

    Next: Three blind raters.

  7. Three blind raters. rate.js, eight cqp principles. Lane: Agents.

    Next: render.py.

  8. render.py. report page. Lane: Harness.

collect.sh runs collectOne for each clone and collectList for a list-only run. A step marked yes is skipped when fetchBack fails recomputed.

ModeOrderStepSkipped on failed fetchBack
collectOne1fetchBackno
collectOne2exportyes
collectOne3logsyes
collectOne4gradeyes
collectOne5measureyes
collectOne6survivorsyes
collectOne7benchyes
collectOne8metricsyes
collectOne9diagramyes
collectOne10costsno
collectOne11curveyes
collectOne12apfdyes
collectOne13auditno
collectOne14adherenceyes
collectOne15reviewno
collectOne16reportno
collectList1fetchBackno
collectList2pinyes
collectList3exportyes
collectList4listyes
collectList5costsno
collectList6auditno
collectList7ordersno

Runs and arms

An arm is a design or a test-list order. A run builds one or more arms under fixed caps.

Figure 2.2

Builds per arm and run

Builds per arm and runOne row per arm and one column per build run. Each mark's area grows with its build count, which stands beside it. A ring marks rebuilt replicates.pilot-1pilot-2full-1tcp-1rep-1rep-2Classic greedy TDDClassic greedy TDD, pilot-1: 1 build1Classic greedy TDD, full-1: 1 build1Classic greedy TDD, rep-1: 5 builds5Classic greedy TDD, rep-2: 5 builds5Noun-verb mapNoun-verb map, full-1: 1 build1Noun-verb map, rep-1: 5 builds5Mapped-path TDDMapped-path TDD, full-1: 1 build1Functions first, classes laterFunctions first, classes later, full-1: 1 build1Functions first, classes later, rep-1: 5 builds5Transformation Priority Premise TDDTransformation Priority Premise TDD, full-1: 1 build1Coarse-to-fine TDDCoarse-to-fine TDD, full-1: 1 build1Coarse-to-fine TDD, rep-2: 5 builds5Annealed refactoringAnnealed refactoring, full-1: 1 build1Multi-start TDDMulti-start TDD, pilot-1: 1 build1Multi-start TDD, pilot-2: 1 build1Multi-start TDD, full-1: 1 build1Most informative next testMost informative next test, pilot-2: 1 build1Most informative next test, full-1: 1 build1Most informative next test, rep-2: 5 builds5Property-based TDDProperty-based TDD, full-1: 1 build1Held-out TDDHeld-out TDD, pilot-1: 1 build1Held-out TDD, pilot-2: 1 build1Held-out TDD, full-1: 1 build1Held-out TDD, rep-2: 5 builds, 5 rebuilt5Anchor EngineeringAnchor Engineering, rep-1: 5 builds5Test-list order: randomTest-list order: random, tcp-1: 1 build1Test-list order: coverageTest-list order: coverage, tcp-1: 1 build1Test-list order: costTest-list order: cost, tcp-1: 1 build1Test-list order: riskTest-list order: risk, tcp-1: 1 build1Test-list order: usageTest-list order: usage, tcp-1: 1 build1

Each mark's area grows with its build count. The ring marks the rep-2 replicates rebuilt at a later harness. Counts come from facts.json recomputed.

Table view: Builds per arm and run, 17 rows and 7 columns
Armpilot-1pilot-2full-1tcp-1rep-1rep-2
Classic greedy TDD1 build1 build5 builds5 builds
Noun-verb map1 build5 builds
Mapped-path TDD1 build
Functions first, classes later1 build5 builds
Transformation Priority Premise TDD1 build
Coarse-to-fine TDD1 build5 builds
Annealed refactoring1 build
Multi-start TDD1 build1 build1 build
Most informative next test1 build1 build5 builds
Property-based TDD1 build
Held-out TDD1 build1 build1 build5 builds, 5 rebuilt
Anchor Engineering5 builds
Test-list order: random1 build
Test-list order: coverage1 build
Test-list order: cost1 build
Test-list order: risk1 build
Test-list order: usage1 build

A build is one final clone of a method or arm. Start clones and rebuilds are not builds. Multi-start TDD runs each start in a clone of its own, up to the starts cap, so pilot-1 makes 3 builds in up to 6 clones recomputed, pilot-2 makes 3 builds in up to 6 clones recomputed and full-1 makes 11 builds in 14 clones verified. The runs make 62 builds, the counts in Figure 2.2, and 5 rebuilds recomputed. Figure 2.2 rings the rebuilt replicates.

Every run of the study recomputed. Every run used model opus at medium effort with caps of 15 cycles per call and 3 starts. Methods doc is the short sha256 of the methods doc each run was built under. The methods text quoted on the study pages is doc 12f026f6.

RunKindBuildsArmsWavesIterations capMethods docHarness commit
pilot-1Pilot33one batch264606950not recorded
pilot-2Pilot33one batch264606950not recorded
full-1Survey1111one batch1564606950not recorded
tcp-1-listTest list00none151f11dd37not recorded
tcp-1Test-list order55one batch151f11dd37not recorded
tcp-1-list2List reliability00none1512f026f6not recorded
rep-1Planned contrasts2042 waves of 101512f026f6not recorded
rep-2Planned contrasts2042 waves of 101512f026f6809589d
rep-2/rebuildRebuild5 rebuilds11 wave of 51512f026f6cc8c8cb
  • tcp-1-list. Writes the test list of 19 clauses and 12 candidates with lister tcp-1-list-lister, seed 20261020.
  • tcp-1. Builds the tcp-1-list list in 5 orders.
  • tcp-1-list2. Rates the tcp-1-list test list again with lister tcp-1-list2-lister, seed 20261020.
  • rep-2/rebuild. Rebuilds r04 r08 r14 r17 r20 of rep-2 at a later harness. Analysis and validity covers why.

Replicate protocol

rep-1 and rep-2 test planned contrasts between arms. Both follow one protocol, and the build refuses to run if their shapes differ.

Figure 2.3

Replicate protocol of rep-1 and rep-2

Replicate protocol of rep-1 and rep-24 arms of 5 replicates each launch in a rotated order, cut into 2 waves of 10 that build in turn. collect.sh, three blind raters, an exact Mann-Whitney U test per planned pair and a Holm step-down follow.Pick arms4 arms, 5 replicateseachRotate launch orderreplicate k rotated byk - 1Cut into waves2 waves of 10Build, review, measurefresh clone, caps 15iterations, 15 cycles,3 startscollect.shevery build after thebatchThree blind ratersone rating per finalExact Mann-Whitney Uper planned arm pairHolm step-downover each family ofpairsrepeat per wave
  1. Pick arms. 4 arms, 5 replicates each.

    Next: Rotate launch order.

  2. Rotate launch order. replicate k rotated by k - 1.

    Next: Cut into waves.

  3. Cut into waves. 2 waves of 10.

    Next: Build, review, measure.

  4. Build, review, measure. fresh clone, caps 15 iterations, 15 cycles, 3 starts.

    Next: collect.sh.

    Loop: repeat per wave, back to Cut into waves.

  5. collect.sh. every build after the batch.

    Next: Three blind raters.

  6. Three blind raters. one rating per final.

    Next: Exact Mann-Whitney U.

  7. Exact Mann-Whitney U. per planned arm pair.

    Next: Holm step-down.

  8. Holm step-down. over each family of pairs.

Arm, replicate, wave and cap counts come from facts.json recomputed. The test and its correction follow contrast.py verified. Planned contrasts has the results.

Text version: Replicate protocol of rep-1 and rep-2
  1. Pick arms. 4 arms, 5 replicates each.

    Next: Rotate launch order.

  2. Rotate launch order. replicate k rotated by k - 1.

    Next: Cut into waves.

  3. Cut into waves. 2 waves of 10.

    Next: Build, review, measure.

  4. Build, review, measure. fresh clone, caps 15 iterations, 15 cycles, 3 starts.

    Next: collect.sh.

    Loop: repeat per wave, back to Cut into waves.

  5. collect.sh. every build after the batch.

    Next: Three blind raters.

  6. Three blind raters. one rating per final.

    Next: Exact Mann-Whitney U.

  7. Exact Mann-Whitney U. per planned arm pair.

    Next: Holm step-down.

  8. Holm step-down. over each family of pairs.

Study stage and course context

Both parts below come from the full-1 report that these study pages are built from. "This page" in them means that report.

Study stage

Each run of the study and its state. Complete means its folder holds its comparison page. Listed means it holds the test list and orders of a list-only run. Pending means it holds its launch arguments in args.json and neither page.

pilot-1. State: complete. Tag: verified.

Summary: Pilot of Classic greedy TDD, Multi-start TDD and Held-out TDD at 2 iterations per loop. Its page leads with a dated superseded banner.

pilot-2. State: complete. Tag: verified.

Summary: Pilot of Multi-start TDD, Most informative next test and Held-out TDD at 2 iterations per loop. Its page leads with a dated superseded banner.

full-1. State: complete. Tag: verified.

Summary: This page. Eleven methods in 14 clones at up to 15 iterations per loop, 15 cycles per call and 3 starts.

tcp-1-list. State: listed. Tag: verified.

Summary: A lister agent wrote one test list of 12 candidate tests and the harness derived 7 orders of it.

tcp-1. State: complete. Tag: verified.

Summary: Five arms with one test-list order each for random, coverage, cost, risk and usage at seed 20261020.

tcp-1-list2. State: listed. Tag: verified.

Summary: A second blind lister rated the 19 clauses and 12 candidate tests of the tcp-1-list list to measure how far the ratings depend on the lister.

rep-1. State: complete. Tag: verified.

Summary: Two planned contrasts. Five replicates each of Functions first, classes later, Noun-verb map, Anchor Engineering and Classic greedy TDD in one batch of 20 builds, each rated blind for code quality.

rep-2. State: complete. Tag: verified.

Summary: Three planned contrasts. Five replicates each of Held-out TDD, Coarse-to-fine TDD, Most informative next test and Classic greedy TDD in one batch of 20 builds, each rated blind for code quality.

Course context

The COMPSCI 701 course items this study bears on.

Course context, 12 rows and 3 columns

Syllabus. Tag: verified.

Relevance: The course evaluates practices partly through research on their effectiveness. This study is a small empirical probe of TDD variants in that sense.

Lecture 11.2. Tag: verified.

Relevance: Calls TDD a development practice and a greedy algorithm for coding. It asks whether test order shapes the design and whether greedy design rules out good designs. Classic greedy TDD, its variants and the test-list order arms probe those questions.

Lecture 11.2 evidence. Tag: verified.

Relevance: Reports that TDD teams wrote smaller classes and methods with lower complexity and coupling and showed no clear cohesion trend. This page measures size but not complexity, coupling or cohesion.

Lecture 11.1. Tag: verified.

Relevance: Says design must be testable for TDD to work and defines testability as controllability and observability. No column of this page measures testability in that sense.

Lecture 2.1. Tag: verified.

Relevance: Splits maintainability into comprehensibility, alterability and testability. The rated cqp.html principles stand in for comprehensibility. Alterability is not measured here.

Lecture 2.3. Tag: verified.

Relevance: Defines a test case and a test criterion. The hidden, unseen and acceptance columns count passes of the course test suite. Mutation score adds a fault-based check alongside the course's coverage example.

Lecture 7.1. Tag: verified.

Relevance: Measures alterability as classes changed over classes in the design against the impact of a change case. This study carries out no change case, so it computes no such ratio and leaves alterability unmeasured.

Lecture 1.2. Tag: verified.

Relevance: Applies noun and verb analysis to the Kalah description. Noun-verb map extends it with project rules from an A02 attempt, so those added rules are not course content.

Lecture 5.1. Tag: verified.

Relevance: Says many small functions can aid comprehension and that refactoring in several steps may first go backwards. Functions first, classes later and Annealed refactoring probe those two points.

Lecture 4.1. Tag: verified.

Relevance: Stresses that metric thresholds give false positives and false negatives. Strict PMD compliance reports conformance to the course ruleset and alone does not show maintainability.

A02 rubric. Tag: verified.

Relevance: Functionality is 15 of 20 marks and maps to Functional mark /15. The 5 report marks are not scored here. The assignment judges alterability from a change actually made. This study builds all four variants at once and does not measure alterability.

A01 rubric. Tag: recomputed.

Relevance: Used the course PMD ruleset for maintainability marks and asks for at least 4 classes besides Kalah and enums. Seven of the 11 methods have 4 classes or fewer in total with Kalah included.