01 β Measuring CK Match Quality
Why a new measurement was needed
Section titled βWhy a new measurement was neededββValidation is trashβ was the hypothesis; we needed a number. The existing
packages/eval/src/runners/auto-validation-runner.ts looked like the tool but is a
tautology: it feeds the WhereFour answer-key SKUs straight into the matcher, so it
measures βgiven the right SKU, can Typesense re-find itβ (~90%+, flattering), not
βgiven the document, do we find the right product.β Its scorer header even says it:
βthe dataset has no canonical expected erpProductId per line.β
Ground truth: history, not operator labels
Section titled βGround truth: history, not operator labelsβCK has effectively no operator-validated match labels (auto-submit is fail-closed;
only ~17 validated lines on conn 4f234677), so the webapp eval:match path (which keys
on 90-day operator-confirmed extracted_order_items.erp_item_id) is empty for CK.
Instead we reconstruct truth from history: CK Gmail emails matched to the actual
prod WhereFour sales orders. This pipeline already existed
(pull-ck-emails β enrich-ck-emails β compile-ck-golden) and produced
cleveland-kitchen-golden-dataset.json: 1,055 emails β 823 WhereFour orders β 5,541
line items with item_ids ([sku, upc]) + unit_price per line and _wherefourMatch
(customer, PO, method) per entry.
The harness: extract β match β align β score
Section titled βThe harness: extract β match β align β scoreβapps/webapp/scripts/run-ck-match-eval.ts:
- Corpus β golden entries that already had extracted document lines in the DB
(
extracted_order_items), joined to the WhereFour answer by PO number. - Match β run the real production matcher (
findProductMatchesBatch+ fuzzy) on the extracted document lines (never the answer-key SKUs), scoped to the WhereFour customer. - Two-pass align + score (
packages/eval/src/scorers/ck-match-scorer.ts):- Pass 1 (extraction layer): align each extracted line to an answer line on
document-side fields. A line with no confident answer partner =
extraction_miss, not a matcher miss. - Pass 2 (matcher layer): on aligned pairs, compare the matcherβs predicted product
to the answer by SKU β UPC β normalized-name β
correct/wrong/unmatched.
- Pass 1 (extraction layer): align each extracted line to an answer line on
document-side fields. A line with no confident answer partner =
- Aggregate β match recall / precision / wrong-match-among-matched + extraction-miss
- a reproducibility snapshot (connection, Typesense counts, dataset sha, git rev).
Metrics
Section titled βMetricsβ- Candidate coverage = % of aligned answer lines whose correct product is retrieved into the candidate set. This is the metric of record for the recall problem.
- Match recall = correct / aligned; precision = correct / matched; wrong-match-among-matched = wrong / matched (highest severity β confident wrong binds). NOT βfalse auto-submitβ (CK is fail-closed; nothing auto-ships).
Honest caveats
Section titled βHonest caveatsβ- Oracle customer. The harness resolves the WhereFour customer by name, so it
measures item matching, not customer resolution. Customer/retailer disambiguation
(the dominant production failure) is hidden here β see
05-wrong-retailer-and-email-context.md. - 66 of 699 golden POs had pre-extracted lines in the DB. Numbers are a real but partial slice; population-final numbers need extracting the rest.
- WhereFour-as-truth = the fulfilled order, which can differ from the email
(substitutions, standing-template qty-0 lines;
fix-ck-ground-truth.tsstrips some).