v2 · 45 printed rows · wrong on purpose · key committed
A print studio's lot list with errors planted in it, and an answer key that cannot be read until the clock says so. v1 shipped its key in the same directory as its data, under a guessable name. That made it open, not blind. This is the version where that is fixed and checkable.
A match is one lot number printed against two genuinely different colourways of the same product. Two SKUs under one colourway is a run surface: two widths, a spread, not a diversity. It is not a match and it must not be counted as one.
That sentence is the whole test. Everything below is dirt applied to it.
Three normalisations, named on purpose. A test where the caller has to guess the cleaner is a test of guessing, not of screening.
| normalisation | why |
|---|---|
| trim, collapse inner runs of whitespace, fold case | the same lot entered twice by two people is still one lot |
strip a trailing (cont.), with or without the full stop | a continued lot is the same lot, not a new one |
these tokens mean the field is missing, not that it holds a value: (empty), -, 0, n/a, na, none, null, tba, tbc, tbd, unknown | never join on them; report the row unplaced |
Case-insensitive. Missing is not a colourway, and two missing values are not two colourways.
feed.csv · sha256 da010fc974de8b7e20b893d6e85b76e92601b7bf9c2e2cc8f70d12af09d7985a
| column | what it holds |
|---|---|
page | the page of the source document this row was read from |
product_code | three products, P-201 to P-203 |
product_name | the same three, spelled out |
lot | the printed lot number, as printed |
colourway | the printed colourway, as printed |
sku | the printed SKU, as printed |
units | printed quantity; carry it, do not sum it |
“As printed” is load bearing. Nothing in that column has been cleaned.
Classes and counts, computed from the construction, not typed from memory. Not locations. Finding them is the test.
| class | size | what a screen must do |
|---|---|---|
| exact duplicate row, re-scraped on a later page | 1 row | collapse on content, not on page |
| one lot printed three ways (trailing space, clean, lower case) | 3 rows | trim and fold case before joining |
| one SKU printed three ways (case, surrounding spaces) | 3 rows | normalise before counting distinct SKUs |
| lot continuation, printed <code>(cont.)</code> on a later page | 1 row | join the continuation, do not cut the lot in half |
| placeholder lots: <code>(empty)</code>, <code>0</code>, <code>N/A</code>, <code>TBC</code> | 5 rows | never join on a placeholder; report those rows unplaced |
| colourway missing on every row of a lot | 2 lots | return unresolved, not resolved either way |
| one lot, two or more SKUs, one colourway | 6 lots | run surface; separate count from matches |
| lot number prefix collision | 2 rows | exact lot key; no truncation, no prefix match |
| colourway spelling one edit apart | 2 lots | flag for a human; do not decide |
| one SKU claimed by two colourways | 2 SKUs | conflict; exclude from both counts |
| one lot claimed by two products | 1 lot | conflict; a lot belongs to one product |
| one SKU printed under two lots (a reprint) | 4 SKUs | legal, and it must not merge the two lots |
Per lot, one line: the count, the fields that count was computed on written beside it, and the product it belongs to. A match count and a run count are two numbers, never one. Lots it cannot resolve come back as unresolved with the missing field named. Nothing comes back as a single figure a reader has to guess the meaning of.
commitment.txt carries a sha256 of the exact key file, taken when this data was built. The key itself goes up at 2026-10-28 18:00 UTC at /lab/run-register-fixture/v2/key.json, and not before.
key sha256 9e59c91d8603e9cf90a375cc96f6b3b0fb3b26a8fa9698d687672065ccda47b8
So: run your screen now, write down what it says, and only then read the key. Hash the released file against the number above and you know two things at once: what the answer was, and that I could not have moved it after seeing your count. A key released beside its data proves nothing about whether it was fitted to the first caller. This one is checkable in both directions.
If the hashes do not match, say so publicly and my fixture is finished as evidence. That is the cost of publishing a receipt, and it is cheaper than the v1 mistake.