≈ 25 minutes · hook → predict → explain → play → check

Split games,
not positions.

Every decision in this course — architecture, learning rate, data size — will be judged by one number: validation accuracy. This mission is about making sure that number tells the truth.

00 · Why this matters

A score that lies politely.

Our count-based baseline currently predicts the next human move in 22.4% of held-out positions. Suppose that next month a shiny new neural model reports 78% validation accuracy. Champagne? Not yet — because there is a boring way to reach 78% without learning any more chess: let the evaluation quietly reuse games the model already studied.

That failure mode is called data leakage, and it is not a beginner’s mistake — leaky evaluations regularly slip into published research. For us it is also the single most expensive mistake available, because every later experiment chooses between models by comparing validation numbers. If those numbers reward memorization, we will spend the tournament’s 100 MB and one exaFLOP optimizing for the wrong thing, and discover it on match night.

The plan: commit to a prediction, see the exact mechanism of the leak with rows you can point at, watch it inflate a score in a simulator, and then approve the split our real code uses.

01 · Predict before you read

Predict the direction of the error.

Here is the setup. We expand each game into overlapping next-move examples, shuffle all examples from every game together, then take 10% as validation. Positions from one game can land on both sides of the boundary.

Relative to genuinely unseen games, apparent validation accuracy will usually be…

Confidence in this prediction

02 · The mechanism

The exam answers are hiding in the study guide.

What a validation score is supposed to measure

Training accuracy answers an easy question: “how well did the model fit the games it studied?” With enough capacity, memorizing wins that contest without any understanding. The question we actually care about is different: “how will it move in a game nobody has played yet?” — because that is literally what the tournament is. A validation set is a stand-in for that future: games we possess but the model has never touched. The score it produces is trustworthy only while “never touched” stays literally true.

One game becomes many training rows

Language models don’t train on games; they train on (context → next move) rows. Here is a six-ply Ruy Lopez opening and every row it generates:

RowContext the model seesTarget it must predict
R1(game start)e4
R2e4e5
R3e4 e5Nf3
R4e4 e5 Nf3Nc6
R5e4 e5 Nf3 Nc6Bb5
R6e4 e5 Nf3 Nc6 Bb5a6

Notice the redundancy: R6’s context contains R2, R3, R4, and R5 in their entirety. These six rows are not six independent facts about chess — they are one game photographed from six angles.

Hold out one row, leak it through its neighbours

Say the shuffle sends R4 to validation and the other five rows to training. The exam question is: “after e4 e5 Nf3, what came next?” The answer is Nc6. Now look at what the model studied. Training row R5 begins e4 e5 Nf3 Nc6… — the exam’s answer is printed, verbatim, inside a study row. So is R6. A model with spare capacity doesn’t need to understand knight development; it can simply remember “that game where Nc6 followed Nf3” and recite it back.

The held-out question R4 is answered verbatim inside training rows R5 and R6: their contexts contain Nf3 Nc6, the exact transition validation is supposed to test.

To be fair: a different game that reached e4 e5 Nf3 and continued Nc6 would also “give away” this answer — but that is legitimate generalization, a pattern learned across many players. The leak is that this exact game answers its own exam. And the distinction we care about — pattern versus memory — is precisely the distinction the leaky split erases.

Randomness is not independence

The shuffle in the leaky protocol is genuinely random, and that is the trap: randomness controls which rows cross the boundary, not whether related rows may cross it. The fix is choosing the right split unit — the smallest thing that must stay whole. Rows from one game share information, so the unit is the game. The same reasoning appears everywhere in machine learning: split by patient in medical imaging, by speaker in audio, by day in market data. Whenever examples share a source, the source is the unit.

Three lines that keep the evidence honest

Our baseline decides each game’s fate with one tiny function:

def is_validation_game(site: str, seed: int, validation_percent: int) -> bool:
    digest = hashlib.blake2b(f"{seed}:{site}".encode(), digest_size=8).digest()
    return int.from_bytes(digest) % 100 < validation_percent
  • site is the game’s Lichess URL — a stable identity that never changes, no matter how the file is sorted or re-downloaded.
  • blake2b(...) turns seed + identity into a huge, effectively random — but perfectly deterministic — number.
  • % 100 drops that number into one of a hundred buckets; < validation_percent sends, say, buckets 0–9 to validation. That is a 10% split.

Four properties fall out of those three lines: the whole game lands on one side (assignment depends only on identity), the split is reproducible on any machine in any row order, no chronology bias can sneak in, and changing the seed deals a completely fresh split without touching the data. Read the real function — pinned to the exact commit, it is these same three lines.

What honesty costs

A game-level split scores lower — that is the point, it stopped grading memory — and its estimate wobbles more when validation holds only a few games, because whole games are coarser coins to flip. The rough rule: quadrupling the number of validation games halves the wobble. How much data to spend on a steadier estimate is a genuine trade-off, and it is Mission 4’s topic. You can feel it first, in the simulator below.

03 · See it happen

Watch the leak inflate a score.

This simulator runs the whole story as a repeatable experiment: 200 synthetic games of 30 positions each, played by a model whose true skill on new games is 30%, but which recalls about 80% of the lines it studied. Each dot is one complete experiment — a fresh split, then an evaluation.

0%25%50%75%100%measured validation accuracytrue skill ≈ 30%Split by position — the leaky protocolExperiment 1: measured 76.7%Experiment 2: measured 74.4%Experiment 3: measured 75.0%Experiment 4: measured 74.2%Experiment 5: measured 75.0%Experiment 6: measured 71.9%Experiment 7: measured 72.2%Experiment 8: measured 70.6%Experiment 9: measured 72.8%Experiment 10: measured 71.3%Experiment 11: measured 71.2%Experiment 12: measured 73.4%Experiment 13: measured 72.7%Experiment 14: measured 77.3%Experiment 15: measured 72.6%Experiment 16: measured 75.7%Experiment 17: measured 74.8%Experiment 18: measured 71.0%Experiment 19: measured 75.2%Experiment 20: measured 72.1%Experiment 21: measured 72.8%Experiment 22: measured 75.0%Experiment 23: measured 73.4%Experiment 24: measured 73.2%Experiment 25: measured 70.3%Experiment 26: measured 73.4%Experiment 27: measured 75.2%Experiment 28: measured 74.1%Experiment 29: measured 74.2%Experiment 30: measured 72.5%Experiment 31: measured 72.2%Experiment 32: measured 72.8%Experiment 33: measured 71.6%Experiment 34: measured 72.7%Experiment 35: measured 68.9%Experiment 36: measured 73.5%Experiment 37: measured 72.1%Experiment 38: measured 70.1%Experiment 39: measured 72.8%Experiment 40: measured 72.5%mean 73%Split by game — the honest protocolExperiment 1: measured 29.2%Experiment 2: measured 27.7%Experiment 3: measured 29.5%Experiment 4: measured 31.2%Experiment 5: measured 33.7%Experiment 6: measured 30.3%Experiment 7: measured 33.0%Experiment 8: measured 30.8%Experiment 9: measured 32.8%Experiment 10: measured 29.3%Experiment 11: measured 29.2%Experiment 12: measured 29.3%Experiment 13: measured 25.8%Experiment 14: measured 31.3%Experiment 15: measured 30.2%Experiment 16: measured 27.2%Experiment 17: measured 30.5%Experiment 18: measured 26.7%Experiment 19: measured 32.2%Experiment 20: measured 31.7%Experiment 21: measured 30.7%Experiment 22: measured 32.0%Experiment 23: measured 30.5%Experiment 24: measured 30.2%Experiment 25: measured 33.2%Experiment 26: measured 31.0%Experiment 27: measured 31.7%Experiment 28: measured 30.8%Experiment 29: measured 32.0%Experiment 30: measured 26.0%Experiment 31: measured 30.0%Experiment 32: measured 31.7%Experiment 33: measured 30.8%Experiment 34: measured 27.3%Experiment 35: measured 29.8%Experiment 36: measured 29.0%Experiment 37: measured 31.0%Experiment 38: measured 29.0%Experiment 39: measured 29.0%Experiment 40: measured 33.2%mean 30%
Leaky split reports73.1%+43 points of pure illusion
Honest split reports30.3%± 1.9 points across redraws
Training games180of 200 available
Validation games20600 positions

Four things to notice while you play:

  • The amber cloud sits far above the truth at every setting — it reports the model’s memory, not its chess. It drifts down as you hold out more of each game, because partial memorization leaks partially. Diluted leakage is still leakage.
  • The green cloud brackets the dashed truth line. Lower, honest, useful.
  • Drag validation share down to 5%: the green dots scatter, because a handful of validation games makes a noisy estimate. Push it to 50%: steadier — but watch the training-games counter fall.
  • The leak is not noise, it is bias: no amount of redrawing pulls the amber cloud toward the truth.

The toy’s assumptions (skill 30%, recall 80%, uniform games) are made up, but the shape survives any reasonable numbers. The Chapter 1 experiment measures the real effect on the real baseline.

04 · Implementation comparison

Which split would you approve?

You are reviewing three pull requests. Each claims to split games 90/10. Choose the one that keeps the evidence trustworthy for our current dataset — and know why the other two fail.

05 · Retrieval checkpoint

Close the loop without looking back.

All three must be correct at the same time. Wrong answers unlock hints — retry as often as you like; there is no penalty.

R1

What is the split unit for our current evaluation?

R2

Why hash the stable game ID with a seed?

R3

On a fixed dataset, what does a larger validation split usually buy and cost?

Mission handoff

The code is still sealed.

Commit the forecast, approve the trustworthy implementation, and answer all three retrieval questions correctly.

06 · Go deeper · pick what you need

The trail beyond this page.

The source assignment for this mission (20–40 minutes): read the real split function and the pinned dataset manifest, then answer — what identity must remain stable for our split to remain reproducible? The rest of the list is optional depth, each entry labelled with what it gives you.