Dataset
Two error detection guardrails on 368 proposed contact merges
96 deduplication runs already published here, five guardrails applied to every merge they proposed, and the 96 raw responses of the one that needed model calls. Test conducted on 2026-09-12.
This page describes one dataset, published in full. It is the raw material behind our test of two guardrails on a task with no arithmetic: 96 deduplication runs already published here, five guardrails applied to every merge they proposed, and the 96 raw responses of the guardrail that needed model calls.
Everything on this page comes from that one run. Nothing is estimated.
What it measures, and what it does not prove
It measures no model. It measures the checks you would put around one to catch a false merge before two people become one row.
The question it was built for is narrow and it is the whole point: on 2026-09-04 we measured four guardrails on invoice extractions, where a free arithmetic identity exists. A contact list has none. This dataset re-runs the two guardrails that held up there, on a task where nothing can be recomputed, and scores them the same way.
Each guardrail carries two quantities that are never read one without the other: the catch rate, the share of the wrong merges it flags, and the false alarm rate, the share of the correct merges it flags. A guardrail that flags everything scores 100 % on the first and is useless. One that flags nothing scores 0 % on the second and is useless too.
What it does not prove, stated plainly, because a dataset quoted without its limits does more harm than no dataset at all:
- The 0 % false alarm rate of the key rule is true by construction. The source corpus requires every duplicate pair to share an email or a phone. In a real address book, somebody who changed both would have their merge blocked. This is the most flattering number in the file and it is the one to distrust first.
- The partitions are 26 days old. They were produced on 2026-08-17. Nothing here says the same models make the same merges today.
- 97 wrong merges. Every catch rate rests on that. A percentage on 97 items has a wide margin: orders of magnitude, not constants.
- 2 of the 96 responses are not valid JSON, and 7 of the 366 submitted groups came back with no verdict. Those 7 merges leave the self-check population, which is scored on 96 wrong and 265 correct instead of 97 and 271. Declared, not repaired.
- One corpus, 96 constructed rows, fixed seed, declared as constructed in its own protocol. No real person, no real company. The trap families are designed features of that corpus and their frequency here is not their frequency in a CRM.
- Address books of 12 rows, entirely inside the model window: the most favourable case. A 5000 row list is a different problem, not measured here.
- The self-check prompt is one prompt. A different instruction would give
different numbers. The one that was run is published inside
verifications.json, rather than a flattering variant found afterwards. - The comparison with the invoice test puts two tasks and two corpora side by side. What changes is not only the presence of an arithmetic check, and this dataset cannot separate the two.
The partitions are reused, and here is what that means
Nothing was deduplicated for this test. The 96 partitions judged here are exactly
those published on 2026-08-18 under
the contact deduplication dataset: 8
script generated address books of 12 rows from seed 20260817, four levels of
formatting mess, three low cost models, and a ground truth partition settled then.
That is a deliberate trade and it cuts both ways. What it buys: all five guardrails judge an identical set of merges, so the comparison isolates the guardrails and nothing else. What it costs: rerunning the models on 2026-09-12 would have mixed their effect with 26 days of model drift, and this dataset says nothing about the models as they are today.
This dataset generates no corpus of its own. Its reproducibility rests on the seed
of the source corpus, 20260817. Regenerate it and you hold the same 8 address
books.
Test conducted on 2026-09-12. The calls were run by the automated testing pipeline of this site: the self-check pass and the analysis are scripts, and both are in the archive below.
The unit that is scored
Not an address book, not a call: a proposed merge, meaning a pair of rows a model put in the same group.
| Count | |
|---|---|
| Merges proposed across the 96 runs | 368 |
| Correct, two rows and one person | 271 |
| Wrong, two people and one row destroyed | 97 |
The guardrails
| What it does | Cost | |
|---|---|---|
| A0 | the model's own notes field, filled while deduplicating: does it name both rows? |
none |
| A1 | strong keys: refuse any merge whose rows share neither email nor phone | none |
| A3 | self-check: one extra call to the same model, given the list and its own groups | one call per run |
| A4 | agreement of three models: flag any merge the other two did not both propose | two extra runs |
| A5 | agreement with a single other model, computed for all three witnesses | one extra run |
The A3 instruction never hints that an error was found and gives no ground truth, and the verdict is asked group by group rather than on the whole partition.
Raw figures
368 merges judged, 97 wrong, 271 correct.
| Guardrail | Catch rate | False alarms | Precision | Wrong merges missed |
|---|---|---|---|---|
| A0 spontaneous note | 73.2 % | 55.4 % | 32.1 % | 26 |
| A1 strong keys | 72.2 % | 0.0 % | 100.0 % | 27 |
| A3 self-check | 76.0 % | 20.8 % | 57.0 % | 23 |
| A4 agreement of three models | 62.9 % | 9.2 % | 70.9 % | 36 |
A5 with gpt-4o-mini alone |
25.5 % | 8.7 % | 44.8 % | 38 |
A5 with gemini-2.5-flash-lite alone |
40.0 % | 3.9 % | 78.8 % | 39 |
A5 with claude-haiku-4.5 alone |
65.4 % | 2.8 % | 91.1 % | 27 |
| A1 and A4 together | 90.7 % | 9.2 % | 77.9 % | 9 |
| A1 and A3 together | 92.7 % | 20.8 % | 61.8 % | 7 |
| A3 and A4 together | 87.6 % | 27.4 % | 53.8 % | 12 |
The same guardrails on the invoice task
| Guardrail | Invoices, 2026-09-04 | Contacts, 2026-09-12 |
|---|---|---|
| Self-check | 97.6 % caught / 39.0 % false | 76.0 % caught / 20.8 % false |
| Agreement of three models | 92.9 % caught / 11.0 % false | 62.9 % caught / 9.2 % false |
| The free mechanical rule | 59.5 % caught / 22.0 % false | 72.2 % caught / 0.0 % false |
By model, on the agreement guardrail
| Model | Wrong merges proposed | A4 catch rate | A4 precision |
|---|---|---|---|
openai/gpt-4o-mini |
46 of 133 | 73.9 % | 87.2 % |
google/gemini-2.5-flash-lite |
32 of 124 | 62.5 % | 66.7 % |
anthropic/claude-haiku-4.5 |
19 of 111 | 36.8 % | 41.2 % |
By level of formatting mess
| Level | Merges proposed | Wrong | A1 caught | A3 caught | A4 caught | A4 false alarms |
|---|---|---|---|---|---|---|
| N1 clean | 82 | 18 | 66.7 % | 88.2 % | 83.3 % | 10.9 % |
| N2 case and spaces | 95 | 26 | 69.2 % | 65.4 % | 53.8 % | 8.7 % |
| N3 phone formats mixed | 104 | 33 | 72.7 % | 78.8 % | 63.6 % | 2.8 % |
| N4 columns merged | 87 | 20 | 80.0 % | 75.0 % | 55.0 % | 14.9 % |
Reading load per 1000 proposed merges
In a population where 264 of them are wrong, which is this corpus and not a real address book.
| Guardrail | To re-read | Wrong merges found | Missed | Reads per one found |
|---|---|---|---|---|
| A1 | 190 | 190 | 73 | 1.0 |
| A3 | 355 | 202 | 64 | 1.8 |
| A4 | 234 | 166 | 98 | 1.4 |
| A1 and A4 | 307 | 239 | 25 | 1.3 |
Costs
The self-check pass, 96 calls: 0.07469 USD, 96 read, 94 valid JSON, 359 verdicts
returned for 366 submitted groups. Per 1000 self-check calls: gpt-4o-mini 0.196
USD, gemini-2.5-flash-lite 0.161 USD, claude-haiku-4.5 1.977 USD.
Every verdict was matched to its group by equality of the row sets, 359 times out of
359, and never by position. A positional match would have been an assumption; it is
counted separately in chiffres.json and it is zero.
What the archive contains
Eight files, 492862 bytes uncompressed. The inventory is here so you know what you are downloading before you download it.
| File | What it holds | Size |
|---|---|---|
corpus.json |
the 8 address books, the ground truth and the explanation of each pair, seed 20260817 |
40.6 KiB |
degrader.py |
the four formatting levels, needed to hand the model the exact list it saw | 3.6 KiB |
resultats-bruts.json |
the 96 partitions being judged, published 2026-08-18 | 213.3 KiB |
auto-verifier.py |
the self-check pass, one call per partition | 7.5 KiB |
verifications.json |
the 96 raw self-check responses, with the instruction used | 172.8 KiB |
analyser.py |
the five guardrails, their combinations and the reading load | 15.6 KiB |
chiffres.json |
every computed figure | 14.4 KiB |
PROTOCOLE.md |
the protocol, the reading of the figures, and the limits | 13.5 KiB |
corpus.json, degrader.py and resultats-bruts.json are copied unchanged from the
2026-08-18 dataset, so this archive stands on its own without fetching another one.
The scripts and their comments are in French, which is the working language behind this site. The API key is read from an environment variable and appears in none of these files.
Rerun it
The analysis calls no model at all, so it replays at zero cost on the raw responses
shipped in the archive. Only auto-verifier.py spends anything.
unzip 2026-09-deduplication-guardrails.zip
python3 auto-verifier.py --resultats resultats-bruts.json --corpus corpus.json \
--sortie verifications.json
python3 analyser.py --resultats resultats-bruts.json \
--verifications verifications.json --sortie chiffres.jsonA guardrail rule you disagree with can be changed in analyser.py and rerun on the
same 96 responses without paying for a single call.
Each raw response is one entry of verifications.json, exactly as the model returned
it, before any scoring. This one holds both failure directions in a single answer:
the merge of two different people is confirmed, and the merge of two rows sharing one
email address is rejected.
{"modele": "openai/gpt-4o-mini", "carnet": "carnet-01", "niveau": 1,
"lu": true, "json_valide": true,
"groupes_soumis": [[4, 5], [3, 8], [6, 9], [1, 10]],
"verdicts": [{"rows": [4, 5], "same_person": true},
{"rows": [3, 8], "same_person": true},
{"rows": [6, 9], "same_person": false},
{"rows": [1, 10], "same_person": false}]}Verify what you downloaded before you trust it:
shasum -a 256 2026-09-deduplication-guardrails.zip
# 245aa5fb0be4b00f99793ec677118123d56c9a8669695f4e1d4f98cf0c9c407bHow to cite this dataset
Copy one of the two forms below. The reference points at this page, which is the stable address of this dataset; the archive is what that address serves.
Think AI First (2026). Two error detection guardrails on 368 proposed contact merges, 96 raw self-check responses.
Think AI First. Test conducted 2026-09-12, published 2026-09-12.
https://think-ai-first.com/datasets/deduplication-guardrails-2026-09. Licensed CC BY 4.0.@dataset{thinkaifirst2026dedupguardrails,
author = {{Think AI First}},
title = {Two error detection guardrails on 368 proposed contact merges, 96 raw self-check responses},
year = {2026},
publisher = {Think AI First},
url = {https://think-ai-first.com/datasets/deduplication-guardrails-2026-09},
note = {Test conducted 2026-09-12. Licensed CC BY 4.0. Archive SHA-256 245aa5fb0be4b00f99793ec677118123d56c9a8669695f4e1d4f98cf0c9c407b}
}Licence and reuse
Published under CC BY 4.0. Use it, quote it, contradict it. If you rerun this and get something different, tell us through the contact form: corrections are published on the article itself, dated.
Download the dataset (zip, 48.3 KiB, 8 files)
Other datasets published here
Each one is a separate test, with its own corpus, its own raw responses and its own archive. This one judges the merges of the second.
- Invoice extraction by three low cost LLMs, 288 raw responses, test conducted 2026-08-10.
- Contact list deduplication by three low cost LLMs, 96 raw responses, test conducted 2026-08-17.
- Meeting action item extraction by three low cost LLMs, 96 raw responses, test conducted 2026-08-18.
- Repeatability of an LLM step at temperature 0, 360 raw responses, test conducted 2026-08-25.
- Four error detection guardrails on 288 invoice extractions, 288 raw self-check responses, test conducted 2026-09-04.
- Price against accuracy on invoice extraction, six models, 864 raw responses with their billed cost, test conducted 2026-09-06.
- Invoice against purchase order matching by four LLMs, 672 raw decisions, test conducted 2026-09-14.