The nine shapes
A shape is declared, not inferred, and the checker only tests the claim. Inference was the alternative and it is worse in the way that matters: a heuristic that reads three rows and guesses is right almost always, and the almost is a silent mis-train rather than a refusal. There is nogeneric and no custom. A format that means nothing cannot be checked and would
only be a field to fill in; a corpus whose shape is not here simply declares none, and everything
else works as it always did.
messages — chat SFT. A non-empty list, each entry carrying a non-empty role and content.
prompt_completion — plain supervised text. Both keys non-empty strings.
preference — DPO and friends.
fim — fill-in-the-middle, which is how a code model learns to complete inside a file
rather than after it. Only middle has to be non-empty: prefix and suffix are context and
either may legitimately be empty at the edges of a file.
repo_context — a completion with the rest of the repository in front of it. files is a
non-empty list of {path, content} with no repeated path, plus a non-empty target. This is
the shape RTL-Repo and every repository-level code benchmark use, and the one that cannot be
flattened into a prompt string without losing which file is which.
spec_rtl — a natural-language specification and the module that implements it.
testbench — a design and the bench that exercises it. The direction matters and is not
symmetric with spec_rtl: here the model writes the bench, which is a verification engineer’s
job.
log_root_cause — a tool or regression log and what went wrong. The manufacturing-side shape
as much as the design-side one.
script — an EDA scripting task: Tcl, a Makefile, a constraint file. Kept apart from
prompt_completion because what makes it correct is that the script runs, not that the text reads
well.
repo_context is refused rather than tolerated: whichever copy the
framework keeps decides what the model sees, so the two entries would disagree about the same file
in the same example.
What the checker may look at
Shape, and nothing else. Which keys are present, that they hold strings rather than nested structures, that a pair has both halves. Nothing about content, quality, language or length — those belong to the quality report, and a format check that started judging content would be a second opinion about data you own.Conformance is a ratio, not a gate
conformance takes any iterable of rows, so the caller decides how much to read. It reports how
many rows it saw, how many conformed, the ratio, and at most ten complaints with their row
numbers — a corpus with a million broken rows has one problem, not a million.
Two deliberate refusals:
- It never becomes a verdict. A gate that fires on any finding is a gate somebody turns off in a week, and a real corpus has malformed rows in it that nobody wants to argue about. What you are owed is the number and the first few examples.
- An empty file has no ratio.
ratioisNoneover zero rows, never1.0. Nothing was checked, and “perfect” is the wrong way to say that.
parse returns None for an absent format — the ordinary case, and not an error — and raises
with the sorted list of known names for one it does not recognise.
Splitting an engineering corpus at random leaks
Every contamination check the platform already has compares text.tp dataset check matches
normalised 13-grams; the fingerprint comparison intersects sampled n-gram hashes. Both answer the
question they were built for, and neither can see the failure that costs an engineering team its
evaluation.
Engineering corpora are full of near-variants of one artefact: eight revisions of a UART, a module
and the wrapper that instantiates it, the same testbench parameterised four ways. Two revisions of
one module genuinely share almost no n-grams while being, for the purpose of measuring what a
model learned, the same problem.
Split those at random and the evaluation set holds siblings of the training set. Every row is
distinct. No duplicate ratio fires. The shingle overlap reads clean. The held-out score then
measures recall of something the model has already seen, the number goes up, and the model is no
better.
So the check compares identity instead of text: whatever group_key names — a design, a
repository, a case number — and the answer is the share of evaluation groups that also appear in
training.
- It is counted over distinct groups, not rows. One design appearing in a thousand evaluation rows is one leak. Counting it a thousand times would let a corpus’s row distribution decide how serious its leak looks.
ratioisNonewhen nothing is held out, never0.0, for the same reason an empty conformance report has no ratio.- It needs no text at all. Two sets and an intersection, so it can run on metadata before either side is read.
Declaring the group key
spec.data.quality is the JobSpec block that carries the ceilings on the training data — the dual
of the evaluation gates, which judge whether the model that came out is good enough. Two of its
fields are about lineage:
- A ratio outside
0–1. max_group_leak_ratiowithoutgroup_key— without it every row is its own group and the ceiling could never be exceeded, which is a line that never gets judged. The same rule already bindsmax_overlap_ratiotooverlap_with.
design for the two RTL ones, repo for the
script assistant, and case for log triage, where the same failure reported twice is one fact.
tp solution show prints it as split by; see solutions.
What is wired up, and what is not
Being exact about this matters more than the feature does.
So today the nine names are a vocabulary a Solution declares and a library check you can run over
your own rows — in a preprocessing script, or in CI before a push.
group_key is the same:
declaring it records the intent and refuses an inconsistent spec; computing the leak is
group_leak’s job and calling it is yours.
That is a smaller claim than “the platform stops a leaking split”, and it is the true one.