habitat
frontier · quantitative research · backtests

Did the backtest’s state ever see the future?

Look-ahead is the quiet killer of quantitative research: an accumulated state — a covariance, a risk model, a factor history — conditioned, anywhere, on information not yet available at the time being simulated. Everyone in the chain owes the same claim: at every date, the state used only what was known by that date — and here is proof.

the pain

Today that claim is an assertion backed by procedure — point-in-time databases, code review, methodology documents — and allocators discount backtests wholesale precisely because the assertion is uncheckable. The fund owes it to its allocator; the model developer owes it to model validation under SR 26-2; the index and risk-model vendor owes it to licensees; the researcher owes it to the journal. None of them can currently hand over anything a skeptic can recompute.

the process today

Every existing tool answers a different question. Point-in-time and bitemporal databases attest availability, not use: a pipeline can consult a PIT store and still peek — a normalization fitted on the full sample, a covariance estimated once over the whole window, a survivorship-filtered universe. Lineage and workflow logs attest events, not effect: a state influenced by an unlogged look-ahead still has clean lineage. And re-deriving the state to compare within a tolerance runs into the no-universal-tolerance wall — benign recomputation noise and a real look-ahead can be the same size, so the ε is an exploitable window.

the cost

A backtest that peeked is a track record that never existed. The allocator prices that risk into every allocation; the validator signs off on a soundness claim no one can check; the licensee inherits the vendor’s self-attestation. The field’s response — discount everything — taxes the honest researcher hardest, because an honest backtest and a peeked one currently produce the same kind of evidence: a document.

the exhibit — recompute it yourself

corpus: real pinned data — Ken French Data Library, daily research factors (mkt_rf, smb, hml, rf) · 1,259 trading days, 2018-01-02 → 2022-12-30 · the vendor archive ships inside the kit, sha256-pinned (af8aec07…), fetched 2026-07-08 — the vendor restates monthly; this pin is the record · dates gated strictly increasing: the history was ingested in order. Register: detection — the argmax cell (mkt_rf×mkt_rf) is measured, not a claim about which row peeked.

GREEN — every prefix, byte-exact
every consumed state replayed from its own past alone — all 1,258 indices
prefix digests reproduced1,258 / 1,258
final state digest (v3)be07f371…
tolerancenone — byte-equality

The state at each date is a pure function of the trace prefix V[:i+1] — recomputed on your machine, byte-for-byte, at every index. A backtest reading these states read only what was known at each date.

RED — the peek, deliberately committed
the 2020-03-16 row — the worst future market day, mkt_rf −12.01 — folded into the 2019-12-31 state (index 502)
digests divergedindex 502 + all 757 after
max|Δg|0.2808
duplicate floor · the corpus’s own0.1657
ratio past floor1.69×

This red is a deliberate fold-in we run as a brake test. Had the history peeked, the GREEN match was impossible: byte-divergence at the peek and every index after, ringing past the N-matched worst-case cost of re-ingesting a row the state already held.

Declared honestly, beside the headline: a statistically unremarkable future row (the median control, 2022-10-20) also breaks byte-equality at every subsequent index — detection is byte-level — but lands at ~0.032× the duplicate floor, within the corpus’s own null: an uninformative future row changes bytes, not materiality. And a survivorship forge — the 5 worst pre-peek days dropped retroactively — fails to reproduce the digest chain from index 23, the first dropped row, onward. A cleaned-up history cannot forge this receipt.

recompute fingerprint — the final chain digest the kit’s verify step reproduces from the pinned vendor archive alone, byte-for-byte on any engine that follows the kit’s published canonicalization · v3 = be07f3713ccc406cfd6e880a6b92dadedf6950f503e326ebc2bdfd9f897b2472
kit fingerprint · sha256 = 982ec9f9ca86bc70c9a93f7056f6a67c4e4e05dea39015d511bb9c739db4aeaf
The verifier re-derives the trace from the raw vendor zip, replays all 1,258 prefixes, and runs the peek, median, and survivorship controls — in a clean environment (numpy only).

the relief

On a substrate where the accumulated state is an exact function of an append-only, temporally sealed record, the point-in-time claim stops being an attestation: the state at i either is the byte-exact functional of the record up to i, or it is not. Timestamps are monotonic and future-rejecting at write — by the substrate’s design a future-conditioned row is unrepresentable; the shipped kit demonstrates the detection, byte-for-byte on your bench. “Trust our PIT discipline” becomes a receipt the allocator, the validator, or the licensee recomputes on their own bench.

what this does not prove

The receipt covers the substrate’s derived state — the covariance/metric layer a strategy reads — not arbitrary downstream code: a signal computed outside the substrate can still peek, and this certificate says exactly which state it certifies. It is a frontier receipt: the accumulation must run on the substrate from the start — you cannot retro-certify a history assembled elsewhere; the buyer adopts the substrate to get the receipt. RED is detection, not localization: the argmax cell is measured, and which row peeked is a separate claim this kit does not make. Vendor restatements complicate “the record up to i” — that is the revision-materiality case, and the two compose. And it is a snapshot: this trace, these pins — not the strategy’s future conduct.

A backtest’s honesty is currently a document. This receipt is the same claim as byte-equality at every index — recomputed on your bench, from the vendor’s own pinned record.

The longer read — the landscape of recomputable data boundaries these receipts extend — is in the docs.

verify this receipt in your browser

This case's receipt records its verdict and both digests above, and carries its own SHA-256. Recompute it here — WebCrypto, in your tab, nothing sent — and it matches; alter one character of a copy and it fails. It is the smallest version of the whole move: recompute, don't trust. The kit below lets you recompute the geometry digest itself on your bench.

published fingerprint ·

or download this receipt and check it on your bench: receipt-point-in-time.jsonshasum -a 256 prints the same number. Every receipt is on the ledger.

request the kit

The point-in-time receipt kit — pinned vendor archive, trace, manifest, verify.py. A person sends it: the kit and its verification steps arrive by reply, usually within a business day.

← Receipts · Docs · Ledger

Rating plate — what this digest sees, and what it cannot

Measured 2026-07-16 by two independent runs, per column, on this receipt’s pinned corpus. A material single-entry edit moved the digest on 4 of 4 columns — every column. What it cannot see:

Check it: the kit’s check-pair runs this digest and a sorted-rows hash on any table — add 0.5 to one cell and both move; relabel a constant column and only one does. Nothing on this plate says anything about any person or institution: detection, not adjudication.