Engineering story · Inference Fabric

An index you can rebuild from its receipt

Approximate-nearest-neighbour indexes are usually irreproducible, so a different result cannot be told from a bug; three hashes, a hash-seeded sample, fixed iterations and a byte-identical rebuild test make mine reproducible

Rust · CUDA C++Approximate nearest-neighbour indexNVIDIA GPUs
An index rebuilt from its receipt
Build receipt
Configuration
Training set
Artifact
seed · sample cap · fixed iterations
First build
Rebuild, rows reordered
header and timestamp, outside the hash
body bytes, identical in both builds
  • 100Krows, the default cap on the training sample
  • 4,096cells at most; a configuration outside the bounds is refused
  • 32vectors at least in every cell

An approximate index trades exactness for speed, and most implementations trade reproducibility away with it: random seeds from the clock, training samples that depend on traversal order, floating-point reductions whose result depends on which thread finished first. When such an index returns different neighbours after a rebuild, nobody can say whether the data changed, the build changed, or something broke.

I wanted an index whose receipt is enough to rebuild it byte for byte.

Three hashes

Every build produces three hashes. The configuration hash is over a canonical binary encoding of the parameters, so two builds with the same settings have the same hash regardless of how the settings were written. The training-set hash is over the length-prefixed, sorted list of shard and row identifiers that were sampled, so it does not depend on the order in which the shards were walked. The artifact hash is over the body bytes of the index file, excluding the header, which carries a wall-clock timestamp that would otherwise make every build unique. A build is checked by recomputing the artifact hash from the written bytes before it is catalogued.

Configuration hashThe parameters, canonically encoded
setting a, setting bsetting b, setting a
two spellings, one encoding
Training-set hashSampled shard and row ids, sorted
shard cshard ashard b
shard ashard bshard c
walk order drops out
Artifact hashThe index file's body bytes header with its timestamp left out

A sample that does not depend on order

The training sample is a reservoir sample over the shard set, seeded by a hash of the build seed, the sorted shard set, the sample cap and each shard's row count. The shard set is canonicalised first, sorted and de-duplicated, and the selections are sorted before hashing, so the same data in a different order yields the same sample and the same hash.

Walk one
Walk two
Canonical set
Sample
Illustrative. Each colour is one shard; the sample is the same rows whichever walk produced it.

Fixed arithmetic

The seeding of k-means++ splits its work: the GPU computes each row's squared distance to the centroids chosen so far, and the host draws the next seed with a seeded generator, so the random step happens outside any floating-point reduction. Lloyd's algorithm then runs a fixed count of iterations with no early exit, with its reduction order fixed by the launch geometry of one block per centroid. Everything is single precision; half precision, bfloat16, FP8 and tensor-core paths are banned by a check in the build.

k-means++ seeding, split in two
GPU
squared distance from each row to the chosen centroids
Hosta seeded draw picks the next centroid, outside any reduction
Lloyd's algorithm · 25 iterations, every build

No early exit; one block per centroid fixes the reduction order.

Single precision only; half, bfloat16, FP8 and tensor-core paths fail a check in the build.

The test that proves it

An integration test builds the index twice and asserts a byte-identical artifact hash, then builds it again from the same data in a different order and asserts the same. A second test fixes a recall floor: the index must find a fixed share of what exact search finds.

Same data, three builds
First build Second build Rows in a different order

One artifact hash, byte for byte.

Recall at ten neighbours · against exact search
0floor 85%

On clustered fixtures; recall must also rise as more cells are probed.

What this demonstrates

Treating reproducibility as a property to be engineered into an approximate algorithm, with the receipt, the sample, the arithmetic and the test each closed against a source of variation, so that a changed result is always a question with an answer.

The determinism contract was my design; AI coding agents, a mix of frontier and open-source models, implemented and tested it under my governance system.