Why
The reason applied results do not survive contact with production is almost never the model, and treating it as a modelling problem is how teams spend months on the wrong thing. A leak is any path by which information that would not exist at prediction time reaches the estimator during training. It does not announce itself. It shows up as a validation score that is too good, which is the one signal nobody investigates, because a good number looks like success rather than like a bug.
Three leaks account for most of it, and they are structural rather than clever. The first is temporal: data with an order was split at random, so the model was allowed to see the future while predicting the past. The second is grouped: the same entity appears on both sides of the split — the same user, the same document, the same address — so the model memorises the entity rather than learning the pattern, and scores brilliantly on entities it has already met. The third is preprocessing: a scaler, an imputer, a target encoder or a vocabulary was fitted on the whole dataset before splitting, so statistics from the test set were baked into the training features. The third is the most common and the least discussed, because it hides inside code that looks like data preparation rather than like modelling.
On-chain data triggers the first two simultaneously, which is why this belongs in this catalogue rather than in a textbook. Every record has a block timestamp, so it is ordered; every record is attached to an address, so it is grouped. A random split violates both at once. And the labels here usually depend on a forward window — did this address get drained within thirty days, did this position get liquidated before expiry — which means a training label overlaps in time with the validation period even after a clean date cut. That is exactly the case purged cross-validation with an embargo exists for: drop the training samples whose label horizon reaches into the validation window, and leave a gap after it before training resumes.
The honest way to report any of this is a gap, not a score. A single number from a leaky split is unfalsifiable — nobody can tell from the outside whether it is skill or contamination. Two numbers from two splits are a measurement, and the distance between them is the only part of it that carries information. The gap is also the cheapest possible experiment, because it needs no new data, no new features and no tuning: the same estimator, evaluated twice, honestly.
And it is worth naming what the discipline buys beyond correctness. A pipeline that splits properly is a pipeline that can be re-run when the data changes, because the boundary between what is known and what is being predicted has been written down explicitly instead of assumed. That boundary is the same thing a backtest needs, the same thing an audit asks for, and the same thing that makes a result reproducible six months later by somebody who was not there.
How it works
Three leaks, and the split that closes each
| Leak | How it gets in | What the score looks like | The fix |
|---|---|---|---|
| Temporal | Random split on ordered data | Excellent, and it degrades the moment it goes live | Split by time; never shuffle |
| Grouped | The same entity on both sides | Excellent on seen entities, chance-level on new ones | Split by group (address, user, document) |
| Horizon overlap | Labels depend on a forward window that reaches past the cut | Slightly too good; survives a naive date split | Purge the overlapping training samples, then embargo a gap |
| Preprocessing | Scaler / imputer / encoder fitted before the split | Uniformly and mildly too good across all folds | Fit inside the fold, always |
The horizon overlap row is the one that survives the obvious fix, which is what makes it worth naming separately. A team that has already learned to split by date will still leak if the label looks thirty days ahead and the training data runs up to the cut — the last thirty days of training labels are partly about the validation period.
Why the answer is a gap and not a score
| Split | What it measures | Honest use |
|---|---|---|
| Random | An upper bound produced by contamination | Only as the top of the gap |
| Time-ordered | What the model knows about the future given the past | A real estimate, still optimistic if grouped |
| Time + group + embargo | What it would have scored deployed | The number to report |
Report all three. A single honest number invites the question "could a better model do more?"; three numbers answer a better question — how much of the apparent performance was never real. And in a portfolio or a write-up, the gap is more persuasive than the score, because it demonstrates the one thing a reader cannot verify from outside: that you went looking for your own contamination.
The step people skip, stated concretely
Anything fitted belongs inside the fold. Not just the model — the scaler's mean and variance, the imputer's median, a target encoder's per-category averages, a vocabulary or tokenizer built from the corpus, a feature-selection step that looked at the labels, and any resampling done to balance classes. The test for whether something belongs inside is simple: would this quantity be computable on the day of prediction, using only what existed then? If not, computing it once over the whole table has already leaked.
Where it lands in this project
The pairing is deliberate. the-70-has-to-be-wrong is about scoring a probabilistic output honestly; this card is about whether the scoreboard was contaminated before scoring began. The two failures compose badly — a leaked split produces a model that looks well-calibrated on data it has effectively already seen, and the calibration plot will look fine right up until deployment. Fix the split first, because a calibration measured on a leak is a measurement of nothing.
Where it lands in Jayverse
- Number: split any address-level dataset by time and group, always. If Number ever builds a labelled dataset from onchain data (e.g. did an address get drained within 30 days), use a time-ordered, address-grouped split with an embargo equal to the label horizon, and report the gap against a naive random split as the actual result.
- Auditor: require the gap, not a single score. When Auditor reviews an internal model or heuristic, make it show random-split performance next to honest-split performance; a single unqualified score should not pass review, since it is unfalsifiable on its own.
- DeFi/Verex: fit preprocessing inside the fold. Any risk score built for liquid-staking or market resolution must fit its scalers, encoders or thresholds only on training data, never on the full dataset before splitting — add this as a pre-ship checklist item.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| survive contact with production | 실전(프로덕션)에 부딪혀도 무너지지 않다 · 검증 결과가 실제 배포 후에도 유효한지 말할 때. "fail... at the split, not at the model" |
| announce itself | 스스로 티가 나다, 알아서 드러나다 · 문제(leak)가 눈에 띄지 않게 숨어있음을 말할 때. "It does not announce itself" |
| bake into | (계산·결과에) 녹아들다, 반영되어 굳어지다 · 테스트셋 정보가 학습 특성에 섞여 들어간 상황. "baked into the training features" |
| account for | ~을 설명하다, ~만큼을 차지하다 · 남은 차이 중 일부의 원인을 짚을 때. "that alone accounts for" |
| reach into | (시간·범위상) ~까지 걸쳐 들어가다 · 학습 라벨이 검증 구간까지 침범하는 상황. "reaches into the validation window" |
| purge | (겹치는 데이터를 검증 전에) 걸러내다 · 교차검증에서 겹치는 학습 샘플을 제거하는 절차. "purged cross-validation with an embargo" |
| embargo | (일정 기간) 사용을 유예·차단하는 구간 · 검증 이후 학습 재개 전 두는 간격. "embargo a gap" |
| chance-level | 우연 수준, 무작위와 다를 바 없는 · 처음 보는 대상에 대한 낮은 성능을 말할 때. "chance-level on new ones" |
| invite the question | (당연히) ~라는 의문을 불러일으키다 · 정직한 숫자 하나가 오히려 의심을 살 때. "invites the question" |
| the moment it goes live | 실제로 가동되는 바로 그 순간 · 배포 직후 성능이 무너지는 시점을 가리킬 때. "degrades the moment it goes live" |
| leak | (검증에 섞이면 안 될 정보가 새어 들어오는) 데이터 누수 · 예측 시점에 없어야 할 정보가 학습에 섞이는 문제를 가리킴. "A leak is any path by which information" |
| imputer | 결측치를 채워 넣는 전처리 도구(imputer) · 통계량을 분할 전에 학습해 버리면 안 되는 예시로 언급. "the imputer's median" |
| target encoder | 범주형 변수를 타깃 평균으로 인코딩하는 기법(target encoder) · 분할 전에 학습하면 누수가 되는 전처리 예시. "a target encoder's per-category averages" |
| calibration | 예측 확률이 실제 빈도와 얼마나 일치하는지 보는 지표(calibration) · 누수된 분할 위에서는 이 지표도 믿을 수 없다는 맥락. "looks well-calibrated on data it has effectively already seen" |
| label horizon | 라벨이 내다보는 미래 시점 범위(label horizon) · 검증 구간과 겹치면 누수가 발생하는 지점. "whose label horizon reaches into the validation window" |