Page generated: 2026-08-27
Data (model runs) generated: 2026-07-23
Scoring inputs: ground truth 36c390d2, evaluate.py 5c52b890, rules 355f2e77
How a traveler name is scored, why two different similarity measures give different answers, and where models put the right value in the wrong field. Every figure on this page is computed from the run checkpoints and the ground-truth CSVs by build_scoring_doc.py; none of it is typed by hand.
The name is the matching key, not a scored field. It never appears in SCORED_FIELDS, so its accuracy contributes to no published figure directly. It enters the results in exactly one way:
1. A similarity is computed for each candidate (model row, GT row) pair.
2. Pairs below 0.7 are rejected; the rest are eligible to match.
3. Rows are paired, and then the similarity value is discarded.
4. Matched rows are counted: precision = matched / rows produced, recall = matched / GT travelers, F1 = 2PR/(P+R).
So a pair at 0.71 and a pair at 1.00 are indistinguishable in every published number, and a pair at 0.69 is counted twice against the model — once as a false positive and once as a missed traveler.
Both run on the reduced readings of the model name, not the raw string. evaluate.name_variants generates every reading the EQUIVALENCES.md §1 rules allow — the untouched name, the name with a leading article and title removed, the name with an appended place of origin removed — and the best-scoring one wins. The unreduced form is always among the candidates, so a reduction can reveal a name that was buried but never lower a score. The §1 removed column in the tables below reports which reduction won.
Gate (evaluate.name_match, applying name_similarity to each reading) — the larger of two candidates:
difflib.SequenceMatcher.ratio(), which is Ratcliff-Obershelp: 2·M / T, where T is the combined length of both strings and M counts characters matched by taking the longest contiguous block and recursing either side of it. It is not an edit distance: characters stranded across an anchor block cannot be matched.|A∩B| / max(|A|,|B|), requiring whole identical tokens.
CER-based (analyze_name_precision.pair_sim) — 1 − CER, where CER = levenshtein(gt, model) / len(gt), a true minimum edit distance normalized by the reference length. This is the measure already used for the eight scored fields, via evaluate.char_accuracy.
They agree on plain substitutions and diverge on length: the combined-length denominator absorbs appended text, the reference-length denominator does not.
gate, no §1 is the similarity on the untouched string — what this page reported before the §1 rules were wired into the scorer. gate is what evaluate.match_rows actually applies. The difference between the two columns is the rules doing their job. title score and origin score are the scorer's own per-field results for the same row.
Conflation no longer costs a match by itself: wherever §1 removed is non-empty, the added title, article or origin was taken off before the comparison, and what is left is the reading of the name. Two things the reduction does not fix are visible below — a short name misread is still rejected on its own merits, and a higher gate score lets some genuinely wrong readings clear 0.7 that previously fell short.
Page 39 — GT traveler Baissen. GPT reports title correctly as Barone and also prefixes it to the name. §1 takes the title back off, so the comparison is Bassa against Baissen: three wrong characters in a seven-character name. The row is rejected on the reading alone. This case used to be presented as conflation breaking the match; the title was never the reason it would fail today.
| Source | Runs | name | title | place_of_origin | gate, no §1 | gate | name CER | §1 removed | title score | origin score |
|---|---|---|---|---|---|---|---|---|---|---|
| Ground truth | — | Baissen | Barone | Sassonia | — | — | — | — | — | — |
| GPT A | 7 | Il Barone Bassa | Barone | Sassonia | 0.364 | 0.667 | 0.571 | title/article: il barone | 1.00 | 1.00 |
| GPT N | 3 | Il Barone Bassa di | Barone | Sassonia | 0.320 | 0.667 | 0.571 | title/article: il barone; origin: di | 1.00 | 1.00 |
| GPT N | 3 | Il barone Bassa di | Il barone | Sassonia | 0.320 | 0.667 | 0.571 | title/article: il barone; origin: di | 1.00 | 1.00 |
| GPT N | 3 | Il Barone Bassa di | Il Barone | Sassonia | 0.320 | 0.667 | 0.571 | title/article: il barone; origin: di | 1.00 | 1.00 |
| Gemini 3.1 N | 10 | Baissen | Il Barone | Sassonia | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
| Claude B | 10 | Baissen | Barone | Sassonia | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
Page 28 — GT traveler Israel Bassan. GPT fills place_of_origin correctly and also appends it to the name. The raw string falls below threshold; with the appended origin removed the same row matches. Nothing about the model's reading changed — only whether the scorer could see it.
| Source | Runs | name | title | place_of_origin | gate, no §1 | gate | name CER | §1 removed | title score | origin score |
|---|---|---|---|---|---|---|---|---|---|---|
| Ground truth | — | Israel Bassan | (blank) | Verona | — | — | — | — | — | — |
| GPT N | 6 | Israel Baysan di Verona | (blank) | Verona | 0.667 | 0.923 | 0.923 | origin: di verona | 1.00 | 1.00 |
| GPT A | 2 | Israel Baysan di Verona | (blank) | Verona | 0.667 | 0.923 | 0.923 | origin: di verona | 1.00 | 1.00 |
| GPT N | 1 | Israel | (blank) | Verona | 0.632 | 0.632 | 0.462 | (blank) | 1.00 | 1.00 |
| Claude N | 10 | Israel Bassan | (blank) | Verona | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
| Gemini 3.1 N | 10 | Israel Bassan | (blank) | Verona | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
Page 36 — GT traveler Tornielli. GT records only the surname, so before §1 almost every row here was rejected for carrying a title the model also filed correctly. With the title removed all but the worst misreading now clear the threshold — including Barone Donizelli, where the surname is simply wrong. That is the cost side of the reduction: it raises every score, not only the deserving ones.
| Source | Runs | name | title | place_of_origin | gate, no §1 | gate | name CER | §1 removed | title score | origin score |
|---|---|---|---|---|---|---|---|---|---|---|
| Ground truth | — | Tornielli | Barone | Milano | — | — | — | — | — | — |
| Claude Thinking N | 1 | Barone Bonnietti | Barone | di Milano | 0.400 | 0.556 | 0.556 | title/article: barone | 1.00 | 1.00 |
| Claude A | 7 | Barone Donizelli | Barone | Milano | 0.560 | 0.778 | 0.667 | title/article: barone | 1.00 | 1.00 |
| Claude N | 6 | Barone Donizelli | Barone | Milano | 0.560 | 0.778 | 0.667 | title/article: barone | 1.00 | 1.00 |
| GPT A | 5 | Barone Tonelli | Barone | di Milano | 0.609 | 0.875 | 0.778 | title/article: barone | 1.00 | 1.00 |
| Claude N | 4 | Barone Donzelli | Barone | Milano | 0.500 | 0.706 | 0.667 | title/article: barone | 1.00 | 1.00 |
| GPT N | 2 | Il Barone Tonelli | Barone | Ambasciatore di Milano | 0.538 | 0.875 | 0.778 | title/article: il barone | 1.00 | 0.00 |
| GPT N | 2 | Il Barone Tonelli | Barone | di Milano | 0.538 | 0.875 | 0.778 | title/article: il barone | 1.00 | 1.00 |
| Claude A | 2 | Barone Donnielli | Barone | Milano | 0.560 | 0.778 | 0.778 | title/article: barone | 1.00 | 1.00 |
| Gemini 3.1 N | 10 | Tornielli | Il Barone | Milano | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
| Claude B | 10 | Tornielli | Barone | Milano | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
Page 36 — GT traveler Francesco Mazuchelli. The document writes the three brothers on one line and GT expands them to three rows. A model that transcribes the line faithfully produces one row. §1 does not help here, and it hurts once: stripping Conte lifts Conte Francesco Alberti over the threshold, matching a traveler it is not.
| Source | Runs | name | title | place_of_origin | gate, no §1 | gate | name CER | §1 removed | title score | origin score |
|---|---|---|---|---|---|---|---|---|---|---|
| Ground truth | — | Francesco Mazuchelli | Conte | Brescia | — | — | — | — | — | — |
| GPT N | 1 | Conte Francesco Alberti | Conte | Savoia | 0.605 | 0.703 | 0.650 | title/article: conte | 1.00 | 0.00 |
| GPT N | 1 | Conte Francesco di ... Marchetti | Conte | S. ... / Grecia | 0.667 | 0.762 | 0.650 | title/article: conte | 1.00 | 0.00 |
| Gemini 2.5 A | 3 | Francesco Mariscotti | Conte | Bologna | 0.650 | 0.650 | 0.650 | (blank) | 1.00 | 0.00 |
| Claude Thinking N | 1 | Archiciato Malucelli | (blank) | Leccia | 0.650 | 0.650 | 0.550 | (blank) | 0.00 | 0.00 |
| Claude B | 10 | Francesco Mazuchelli | Conte | Brescia | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
| Claude Thinking B | 10 | Francesco Mazuchelli | Conte | Brescia | 1.000 | 1.000 | 1.000 | (blank) | 1.00 | 1.00 |
Page 39 — GT traveler Giovanni Battista Maffoni. Nothing is conflated here, so §1 removed is empty throughout and the two gate columns agree. Included to show what the same character error rate does to a long reference.
| Source | Runs | name | title | place_of_origin | gate, no §1 | gate | name CER | §1 removed | title score | origin score |
|---|---|---|---|---|---|---|---|---|---|---|
| Ground truth | — | Giovanni Battista Maffoni | (blank) | Brescia | — | — | — | — | — | — |
| Claude N | 10 | Giovanni Batta Maffoni | (blank) | Brescia | 0.936 | 0.936 | 0.880 | (blank) | 1.00 | 1.00 |
| Gemini 3.1 N | 10 | Giovanni Batta Massoni | (blank) | Brescia | 0.851 | 0.851 | 0.800 | (blank) | 1.00 | 1.00 |
The register writes family groups on a single line (f.lli = fratelli, brothers) and the ground truth expands them to one row per named traveler, which is what the prompt asks for. A model that transcribes the line as written produces one row where GT has two or three, so it is charged one false positive plus a missed traveler for each name it did in fact read.
| Page | Model | Cond | Runs | the single name produced | title | place_of_origin | GT travelers in that one row |
|---|---|---|---|---|---|---|---|
| 36 | Gemini 3.1 | N | 10 | Francesco Filippo e Federico f.lli Mazzuchelli | Li Co: | Brescia | 3 — Francesco Mazuchelli; Filippo Mazuchelli; Federico Mazuchelli |
| 36 | Gemini 2.5 | N | 3 | Giuseppe Palmarini, Girolamo Bouillino e Antonio Zivati | (blank) | di Genova | 2 — Giuseppe Palmarino; Girolamo Borellino |
Not conflation, but the same arithmetic. title is scored by character accuracy against a short reference, so writing the article the document uses costs half the score:
GT title | model title | characters wrong | reference length | title score |
|---|---|---|---|---|
| Barone | Il Barone | 0 | 6 | 1.00 |
| Conte | Signor Conte | 7 | 5 | 0.00 |
CER divides by the length of the GT name, so the same number of wrong characters produces opposite verdicts depending on how long the name is:
The verdict column is the gate's, not CER's. An earlier version of this table compared 1 − CER against the gate's 0.70 threshold, which is the wrong measure for that cutoff — the gate is Ratcliff-Obershelp. Both are shown so the divergence is visible.
| GT name | model reading | characters wrong | reference length | CER | gate | verdict |
|---|---|---|---|---|---|---|
| Baissen | Bassa | 3 | 7 | 0.571 | 0.667 | rejected |
| Giovanni Battista Maffoni | Giovanni Battesta Maffoni | 1 | 25 | 0.960 | 0.960 | matched |
The shortest names on a page are the easiest to read and the hardest to match.
How many per-traveler rows each model actually returned for a page, as the lowest–highest range across its 10 runs, with the median and its distance from the ground-truth count beneath. Matching is ignored here: a model returning 20 rows for an 18-row page is reported as 20 even if only 10 of those rows correspond to a real traveler. This separates over- and under-generation from reading accuracy — a model can return exactly the right number of rows and still have read none of them correctly.
| Model | Cond | Page 28 — GT 18 | Page 36 — GT 37 | Page 39 — GT 10 | All pages — GT 65 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| rows returned | matched | name CER | rows returned | matched | name CER | rows returned | matched | name CER | rows returned | matched | name CER | ||
| Claude | N | 18median 18 · +0 vs GT | 15.32.7 unmatched | 13.6%291 of 2145 chars | 34–35median 35 · -2 vs GT | 27.57.4 unmatched | 19.6%829 of 4227 chars | 10median 10 · +0 vs GT | 7.92.1 unmatched | 16.5%212 of 1285 chars | 62–63median 63 · -2 vs GT | 50.712.2 unmatched | 17.4%1332 of 7657 chars |
| A | 19median 19 · +1 vs GT | 181 unmatched | 14.6%374 of 2570 chars | 34–35median 34 · -3 vs GT | 24.69.6 unmatched | 18.9%722 of 3818 chars | 10median 10 · +0 vs GT | 82 unmatched | 16.2%210 of 1300 chars | 63–64median 63 · -2 vs GT | 50.612.6 unmatched | 17.0%1306 of 7688 chars | |
| B | 18median 18 · +0 vs GT | 171 unmatched | 3.9%92 of 2360 chars | 37median 37 · +0 vs GT | 370 unmatched | 0.2%10 of 5450 chars | 10median 10 · +0 vs GT | 100 unmatched | 0.6%10 of 1620 chars | 65median 65 · +0 vs GT | 641 unmatched | 1.2%112 of 9430 chars | |
| GPT | N | 16–23median 18 · +0 vs GT | 10.58.1 unmatched | 22.3%331 of 1484 chars | 26–34median 33 · -4 vs GT | 14.717.5 unmatched | 23.1%539 of 2337 chars | 9–10median 10 · +0 vs GT | 4.45.5 unmatched | 26.6%203 of 764 chars | 58–67median 60.5 · -4 vs GT | 29.631.1 unmatched | 23.4%1073 of 4585 chars |
| A | 24–29median 25 · +7 vs GT | 7.917.2 unmatched | 14.9%171 of 1148 chars | 31–34median 32.5 · -4 vs GT | 15.217.2 unmatched | 23.6%570 of 2418 chars | 10median 10 · +0 vs GT | 46 unmatched | 24.2%167 of 691 chars | 66–70median 67 · +2 vs GT | 27.140.4 unmatched | 21.3%908 of 4257 chars | |
| B | 18median 18 · +0 vs GT | 180 unmatched | 4.3%110 of 2570 chars | 37median 37 · +0 vs GT | 370 unmatched | 0.4%20 of 5450 chars | 10median 10 · +0 vs GT | 100 unmatched | 0.0%0 of 1620 chars | 65median 65 · +0 vs GT | 650 unmatched | 1.3%130 of 9640 chars | |
| Gemini 2.5 | N | 19–20median 20 · +2 vs GT | 163.6 unmatched | 11.5%269 of 2334 chars | 24–36median 32 · -5 vs GT | 16.913.8 unmatched | 19.6%456 of 2327 chars | 10median 10 · +0 vs GT | 6.73.3 unmatched | 25.9%284 of 1096 chars | 54–66median 61 · -4 vs GT | 39.620.7 unmatched | 17.5%1009 of 5757 chars |
| A | 20–21median 20.5 · +2 vs GT | 14.75.8 unmatched | 8.7%187 of 2160 chars | 35–37median 36 · -1 vs GT | 24.711.3 unmatched | 19.4%661 of 3403 chars | 10median 10 · +0 vs GT | 73 unmatched | 17.4%200 of 1150 chars | 66–68median 66 · +1 vs GT | 46.420.1 unmatched | 15.6%1048 of 6713 chars | |
| B | 18–19median 18 · +0 vs GT | 180.1 unmatched | 0.8%20 of 2570 chars | 37median 37 · +0 vs GT | 370 unmatched | 0.3%19 of 5450 chars | 10median 10 · +0 vs GT | 100 unmatched | 0.0%0 of 1620 chars | 65–66median 65 · +0 vs GT | 650.1 unmatched | 0.4%39 of 9640 chars | |
| Gemini 3.1 | N | 19median 19 · +1 vs GT | 181 unmatched | 10.2%262 of 2570 chars | 34median 34 · -3 vs GT | 295 unmatched | 11.3%460 of 4084 chars | 10median 10 · +0 vs GT | 100 unmatched | 12.3%200 of 1620 chars | 63median 63 · -2 vs GT | 576 unmatched | 11.1%922 of 8274 chars |
| A | 19median 19 · +1 vs GT | 181 unmatched | 7.4%191 of 2570 chars | 36median 36 · -1 vs GT | 324 unmatched | 15.5%736 of 4747 chars | 10median 10 · +0 vs GT | 9.60.4 unmatched | 13.2%206 of 1560 chars | 65median 65 · +0 vs GT | 59.65.4 unmatched | 12.8%1133 of 8877 chars | |
| B | 18–19median 18 · +0 vs GT | 180.2 unmatched | 0.8%20 of 2570 chars | 37median 37 · +0 vs GT | 370 unmatched | 0.4%20 of 5450 chars | 10median 10 · +0 vs GT | 100 unmatched | 0.0%0 of 1620 chars | 65–66median 65 · +0 vs GT | 650.2 unmatched | 0.4%40 of 9640 chars | |
| Claude Thinking | N | 17–19median 18 · +0 vs GT | 14.73.3 unmatched | 16.0%328 of 2053 chars | 30–35median 34 · -3 vs GT | 2310.4 unmatched | 21.2%754 of 3561 chars | 10median 10 · +0 vs GT | 8.51.5 unmatched | 19.5%268 of 1376 chars | 58–63median 62 · -3 vs GT | 46.215.2 unmatched | 19.3%1350 of 6990 chars |
| A | 18–19median 18 · +0 vs GT | 15.13 unmatched | 16.1%343 of 2131 chars | 34–36median 35 · -2 vs GT | 25.98.8 unmatched | 20.8%830 of 4000 chars | 10median 10 · +0 vs GT | 8.31.7 unmatched | 19.2%259 of 1351 chars | 62–64median 63 · -2 vs GT | 49.313.5 unmatched | 19.1%1432 of 7482 chars | |
| B | 18median 18 · +0 vs GT | 17.80.2 unmatched | 2.5%64 of 2528 chars | 37median 37 · +0 vs GT | 370 unmatched | 0.3%14 of 5450 chars | 10median 10 · +0 vs GT | 100 unmatched | 0.1%2 of 1620 chars | 65median 65 · +0 vs GT | 64.80.2 unmatched | 0.8%80 of 9598 chars | |
rows returned is the raw count of per-traveler rows the model produced, before any scoring — range across the 10 runs, with the median and its distance from the ground-truth count. matched is the mean number of those rows that paired with a real GT traveler, and unmatched the remainder. name CER is the character error rate of the traveler names on the matched rows, micro-averaged as total edits over total reference length so it composes across pages. Detection and transcription are separate questions, reported separately: a model can return the right number of rows, match all of them, and still have misread the names.
Counted over all rows a model produced, matched or not, and over the scorer's own pairing (evaluate.match_rows) rather than a separate one. also correct in its own field = the model filled that field correctly as well, so it duplicated the value rather than misfiling it. row lost = the name match failed, costing a false positive and a missed traveler.
Read row lost as a residue, not as the cost of conflation: §1 already removed the added title or origin before the match was attempted, so these are rows that failed on the reading of the name even after the reduction. The column stays because it is the honest denominator — a matched-only count cannot see the rows that never made it.
| Model | Cond | Rows | Title in name | Origin in name | value also correct in its own field | row still matched | row lost |
|---|---|---|---|---|---|---|---|
| Claude | N | 629 | 62 (9.9%) | 0 (0.0%) | 49 of 62 | 46 | 16 |
| Claude | A | 632 | 23 (3.6%) | 0 (0.0%) | 11 of 23 | 22 | 1 |
| GPT | N | 607 | 61 (10.0%) | 60 (9.9%) | 104 of 121 | 100 | 21 |
| GPT | A | 675 | 34 (5.0%) | 15 (2.2%) | 44 of 49 | 38 | 11 |
| GPT | B | 650 | 10 (1.5%) | 0 (0.0%) | 5 of 10 | 10 | 0 |
| Gemini 3.1 | N | 630 | 4 (0.6%) | 0 (0.0%) | 0 of 4 | 4 | 0 |
| Gemini 3.1 | A | 650 | 6 (0.9%) | 0 (0.0%) | 0 of 6 | 6 | 0 |
| Gemini 3.1 | B | 652 | 9 (1.4%) | 0 (0.0%) | 9 of 9 | 9 | 0 |
| Claude Thinking | N | 614 | 21 (3.4%) | 0 (0.0%) | 13 of 21 | 18 | 3 |
| Claude Thinking | A | 628 | 12 (1.9%) | 0 (0.0%) | 2 of 12 | 9 | 3 |
| Claude Thinking | B | 650 | 1 (0.2%) | 0 (0.0%) | 0 of 1 | 1 | 0 |
The title in name and origin in name counts are still worth reading on their own: they measure how often a model puts a value somewhere the schema did not ask for, which is a question about instruction-following rather than about transcription, and the §1 rules deliberately make it cost nothing.
Generated by build_scoring_doc.py from the phase N/A/B checkpoints. See eval_guidelines.html for the full scoring rules.