A model in stages, a product in integers, and v0.0.20

Qwen3 splits into stages that reproduce the whole model bit for bit, matmul_fixed accumulates in integers so every backend gives the same bits, the kernels build reproducibly, and v0.0.20 ships.

Every quantized test until then compared ZIPP with ZIPP. e8053573 compares the whole chain with transformers reading the same GGUF, an implementation that shares nothing with it: the worst of 455,808 logits differs by 7.4e-5. 50ec6a98 then ran Qwen3 as two stages with a hidden state crossing between them and got the whole model's logits bit for bit, and d7fe124e put the stages in worker threads and killed one, measuring that a restarted stage is not recovery: it differs in 151,936 of 151,936 logits and predicts " the" where the model says " Paris".

c4409b6f adds matmul_fixed: both sides quantized to int16 against their own row's maximum and summed as integers, so the answer is the same bits on every backend by construction rather than by agreeing on rounding order, which is what a proof system over a prime field needs. WebGPU and WebGL2 have no 64-bit integer to accumulate in, so they refuse the graph; before this, an operation a backend had no kernel for returned a buffer of zeros. 435ea899 runs a prompt 16 positions at a time into the same caches, 65 ms a token against 182, bit for bit. fdc639c5 made kernels.wasm build to the same bytes on Windows and Linux and has CI rebuild and compare it, and v0.0.20 was published with the plugins source only.