We trained real models on a 30,000-customer credit dataset, retrained them on accumulating data the way a bank does, and recalibrated cutoffs to hold a target decline rate. The 7,500 decisions of the first cohort are attested, then replayed. Then we asked what an auditor would conclude by re-running the current model to reconstruct an earlier decision. The population never changed. The answer still moved.
Fig. 00 — Replication on real lending data
of reconstructions report an outcome that was never the one taken — with the population held completely constant.
Same customers, same distribution, more training data. The only thing that changed is the model improving, from AUC 0.773 to 0.786. That alone was sufficient.
| Regime | AUC v1 → v3 | Reconstruction accuracy | Misreported |
|---|---|---|---|
| Real data — retraining only | 0.773 → 0.786 | 84.5% | 15.5% |
| Real data — with population drift | 0.651 → 0.757 | 78.7% | 21.3% |
| Simulated — high drift | 0.699 → 0.848 | 74.6% | 25.4% |
| With pinned receipts | — | 100% | 0% |
The error has a direction. Under population drift, 1,438 of 1,596 disagreements read stricter today than the customer was actually treated — manufacturing the appearance of a decision the bank never made.
Fig. 01 — The companion simulated study
of reconstructions report an outcome that was never the one taken.
Measured over attested decisions. The bank did nothing wrong: the model improved, the risk team recalibrated to hold its target decline rate, and the operating point moved underneath every historical decision.
The improvement is the cause, not a coincidence. A better model scores the same applicant differently, and a recalibrated cutoff sits somewhere new. The more diligently a risk team maintains its model, the less able the institution becomes to explain any single decision it already made.
Fig. 02 — Four real cases from that run
Drawn from the measured decisions above: the first instance of each transition type. Scores are the models' actual outputs.
| Decision | Then — score / cutoff | Decided | Today — score / cutoff | Reported |
|---|
Model at decision: · today:
Fig. 03 — The evidence
Three independent checks per receipt, all running locally in this page: the Ed25519 signature over the verdict, the SHA-256 receipt hash re-derived from the pinned inputs, and the hash-chain link to the previous receipt. There are no network calls on this page.
Fig. 04 — What this is
Fig. 05 — Selective disclosure
A supervisor asks about one customer. Handing over a chain means handing over the neighbours — disclosing other customers to answer a question about one. Instead, every receipt is committed to a Merkle root that can be published outside the bank; an inclusion proof then shows a single decision belongs to that committed set, using only log₂(n) sibling hashes.
The audit path is 17 hashes. Nothing in this bundle names, or is derived from, any other customer — which is what lets a bank answer a supervisor under data-minimisation obligations. The root is small enough to anchor outside the bank, so the commitment survives even loss of the store itself.