What's inside AI training data?

Ingot shows you which exact words — yours, or a benchmark's — are inside the data an AI learned from. The words themselves, not a score.

nothing is uploaded · press F12 and watch the network stay empty

Drop training data here

JSONL — one {"text": …} record per line. Plain or gzipped — any size, it streams.

What is this?

One mountain of text, two questions

An AI learns from a mountain of text scraped from the web — its training data. Two questions follow. Did your words end up in the mountain? And were the exam questions the AI is graded on — its benchmarks — in there too, so the score measures memory rather than ability (that is contamination)? Ingot answers both the same way: it finds the exact overlapping words and shows them to you.

  • Pick the exam. Three public benchmarks live in the menu — maths, code, general knowledge.
  • Drop the study material. Read here, in this tab — nothing is uploaded anywhere.
  • Read the overlaps. Every match shown with the words around it. Some overlap is innocent — that is why you see the words, not a score.

The scan that ran when you arrived was real — the built-in sample, read in this tab. Watch it work replays it step by step, or press play for the film.

37 seconds, voiced. Nothing plays or downloads until you press play.
six words this page keeps using
termplain meaning
benchmarka standard exam for AI models
training data · corpusthe pile of text a model studied
tokenroughly one word
n = 10ten identical words in a row is what counts as a match
contaminationexam questions found inside the study pile
canonicalfamous text the whole world quotes — it matches, but it is not leakage
Why the answer is trustworthy

Your corpus never leaves the machine

Not a policy — an architecture. There is no upload path: your file is read, hashed and scanned inside this tab. Open the network panel and watch it stay empty.

0bytes of your corpus sent anywhere. There is no server to send them to.
same codeas the command line runs, so a scan here and a scan in CI give the same numbers for the same bytes. A test asserts it.
hashes onlyin the published benchmark indexes — one-way hashes and item ids, never benchmark text.
enforcedthe page ships connect-src 'self' — the browser itself refuses to send data anywhere else. Check the response headers. Or pick the exam, go offline, and scan.

Never dropping a confidential corpus in a browser? Same scanner, same numbers, on your terminal: npx ingot-scan contaminate --index gsm8k --corpus your-corpus.jsonl

Method

Index the benchmark, stream the corpus once

Ingot memorises the exam — every ten-word run it contains — then reads your file once, checking each ten-word run that streams past. One pass, no matter how many questions. lm-evaluation-harness indexes the corpus instead, and reports nine days on the Pile.

  7.0 MB/sec single-threaded, end to end  →  20 GB in about 48 minutes

  21.4 GB of gzipped C4 shards on disk · GSM8K at n=10 · 51 minutes wall clock
  decompression, JSON.parse, hashing and match bookkeeping all included
  reproduce with: node scripts/pretraining-scan.ts
Why this number replaced a faster one

This said 37.1 MB/sec, 20 GB in 9.0 minutes until we scanned a real corpus. That figure is the scan kernel — tokenize, roll, look up — over text already read and already parsed, and quoting it as a scanning rate dropped most of the actual work. The kernel number is still the right one for judging optimisation; it was the wrong one to put here.

The field's 13-gram default is wrong

How many identical words in a row should count as a match? Everyone uses 13, because GPT-3 did in 2020 — and we could find no re-derivation since. So we ran 8 through 13 over a 1,000-item benchmark with 300 planted copies:

nverbatimedited copiesfalse positivesunscannable
8100%90.9%5 / 10002 / 1000
9100%85.9%3 / 10002 / 1000
10100%81.5%2 / 10003 / 1000
11100%79.7%1 / 100031 / 1000
12100%75.0%057 / 1000
13100%69.6%068 / 1000

n=13 leaves 6.8% of the benchmark unscannable — items shorter than 13 tokens can never match at all. At n=10 that is 0.3%, edited copies are caught at 81.5% against 69.6%, and the cost is two false positives per thousand that you can read and dismiss in a second.

The standard error, a retraction, and the caveats

The 81.5% against 69.6% gap is real at 300 planted items, where the standard error is about 2.3 points. An earlier version of this table claimed 100% against 3.5% — an artifact of a test fixture that deleted words on a fixed lattice, which decided in advance which values of n could survive. It is written up in docs/measurements.md, because a tool that audits other people's numbers cannot quietly restate its own.

Caveats: one corpus pair, both 2023-era, and edited copies simulated by random word dropping rather than a model rewriting text. Real paraphrase will be harder.

The registry

Three benchmarks against 21 GB of C4

We ran the scanner ourselves: three public exams against C4, a public snapshot of web text. Every shard's URL and SHA-256 is published, so every number reproduces.

Corpus
c4-en26 shards, Common Crawl
Size
21.33 GB9,264,249 documents
Tokens
3,418,685,530one pass, streamed
Method
n = 10exact, ingot-0.1.0
benchmarkflaggedratematchesdiscardedunscannable
gsm8k2 / 13190.152%200
humaneval6 / 1643.659%151150
mmlu342 / 140422.436%86564228

"2.4% of MMLU is contaminated in C4" is wrong, and that is the finding. We inspected 200 retained matches and found no contamination — we found NATO Article 5, Patrick Henry, the Fifth Amendment: canonical text, the famous passages the whole world quotes. MMLU quotes famous documents; web text contains them. The overlap is exact, reproducible and evidentially worthless.

Found mmlu-5951 c4-en · doc5541 n=10 · exact
…NATO’s founding treaty states in Article 5 that NATO members “agree that an armed attack against one or more of them in Europe or North America shall be considered an attack against them all” and that “if such an armed attack occurs, each of them, in exercise…

A false positive you can see is a judgment you make in one second; as a rate, it is one you cannot evaluate at all. The full write-up, including the two published numbers this project had to retract, is in three ways contamination scanning silently fails.

How we ruled contamination out — two tests

The standard defence does not save you. Document-frequency filtering discarded 757 matches at this scale and 0 at 356,317 documents — same filter, same threshold, so it only engages once the corpus is enormous. Even then the survivors are canonical, because a famous passage's exact ten-gram is rare: Patrick Henry's most quoted sentence appears in one document out of nine million, as give me liberty or give me death!?- Patrick Henry.

Tested properly against a corpus of different provenance — The Pile with every web-crawl subset removed, 251,488 documents of court opinions, patents, abstracts and digitised books — 67 of the 342 are confirmed canonical, 46 of them by court opinions. The other 275 are undetermined, not leaked: a control of nine unmistakably canonical items scored 1 of 9 against that reference, so absence from it carries no information. Presence is evidence; absence is a lead.

Discipline

What Ingot refuses to do

Each of these was a defect first, caught by reading the output instead of trusting it. All eleven are written up in docs/measurements.md.

  • No silent clean result. Every report names the items nothing could ever match.
  • No verdict without the text. Ingot reports what overlaps; whether that is leakage is your call.
  • No paraphrase in the headline. Weaker evidence sits in its own labelled section, outside the count.
  • No unmeasured claims. The false-positive rate prints beside the detection rate, from the same run.