mlx-bun 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/README.md +66 -21
  2. package/THIRD_PARTY_LICENSES.md +1 -0
  3. package/docs/archive/mlx-bun-lab-report.html +275 -0
  4. package/docs/archive/wwdc-mlx-bun.html +848 -0
  5. package/docs/design/audio-input-plan.md +356 -0
  6. package/docs/design/batching-perf-path.md +58 -35
  7. package/docs/design/batching-v2-plan.md +23 -9
  8. package/docs/design/bucketing-stage.md +2 -1
  9. package/docs/design/compat-cli-surface-design.md +4 -3
  10. package/docs/design/decode-speed-program.md +172 -0
  11. package/docs/design/docs-reorg-plan.md +1 -1
  12. package/docs/design/dspark-serving-program.md +371 -0
  13. package/docs/design/dspark-speculative-decoding.md +167 -5
  14. package/docs/design/faithful-l1-consolidation.md +310 -0
  15. package/docs/design/generic-model-support.md +8 -5
  16. package/docs/design/grammar-spec-batching-integration.md +301 -0
  17. package/docs/design/minicpm5-decode-megakernel.md +16 -11
  18. package/docs/design/mlx-lm-tool-parity-plan.md +11 -1
  19. package/docs/design/omlx-adoption-map.md +14 -6
  20. package/docs/design/orpo-training.md +34 -30
  21. package/docs/design/paged-kv-cache.md +214 -0
  22. package/docs/design/parallel-slots.md +82 -49
  23. package/docs/design/parity-tier-dag.md +43 -33
  24. package/docs/design/repo-cleanup-plan.md +189 -0
  25. package/docs/design/runtime-isolation.md +19 -3
  26. package/docs/design/segmented-backward-training.md +3 -2
  27. package/docs/design/ssd-kv-cold-tier.md +130 -0
  28. package/docs/design/structured-output.md +484 -0
  29. package/docs/design/the-dreaming-master-plan.md +2 -3
  30. package/docs/design/turboquant-kv.md +235 -0
  31. package/docs/design/unified-engine-frontier-plan.md +774 -0
  32. package/docs/design/web-chat-beat-matrix.md +315 -0
  33. package/docs/design/web-chat-redesign.md +1112 -0
  34. package/docs/investigations/dspark-handoff.md +182 -16
  35. package/docs/investigations/lab-build-journal.md +2 -2
  36. package/docs/investigations/openwiki-evaluation.md +249 -0
  37. package/docs/planning/IDEAS.md +14 -0
  38. package/docs/planning/PRODUCT_ROADMAP.md +2 -3
  39. package/docs/planning/chat-ui-vision-memory-first.md +199 -0
  40. package/docs/planning/chat-ui-vision.md +50 -0
  41. package/docs/planning/memory-docs-and-dag-plan.md +15 -6
  42. package/docs/planning/release-notes-v0.0.11.md +239 -0
  43. package/docs/reference/cli.md +35 -16
  44. package/docs/reference/distribution.md +13 -6
  45. package/docs/reference/embedding.md +35 -14
  46. package/docs/reference/features-matrix.md +97 -0
  47. package/docs/reference/library-api.md +30 -9
  48. package/docs/reference/memory.md +26 -6
  49. package/docs/reference/models.md +11 -1
  50. package/docs/reference/orpo-quickstart.md +3 -4
  51. package/docs/reference/server-api.md +634 -22
  52. package/docs/reference/server-config.md +250 -121
  53. package/docs/reference/training.md +14 -15
  54. package/package.json +5 -3
  55. package/src/anthropic.ts +13 -0
  56. package/src/audio/conformer.ts +647 -0
  57. package/src/audio/decode.ts +133 -0
  58. package/src/audio/features.ts +202 -0
  59. package/src/audio/transcode.ts +67 -0
  60. package/src/cli.ts +356 -105
  61. package/src/config.ts +49 -2
  62. package/src/download.ts +40 -0
  63. package/src/eval/README.md +7 -6
  64. package/src/eval/kl.ts +59 -3
  65. package/src/eval/quality-db.ts +2 -2
  66. package/src/eval/runner.ts +3 -3
  67. package/src/expert-offload.ts +15 -2
  68. package/src/flags.ts +13 -0
  69. package/src/generate.ts +330 -24
  70. package/src/grammar.ts +585 -0
  71. package/src/hub-rest.ts +242 -0
  72. package/src/kv-store.ts +442 -88
  73. package/src/lora.ts +8 -0
  74. package/src/md-modules.d.ts +42 -0
  75. package/src/media-fetch.ts +284 -0
  76. package/src/memory/rest.ts +245 -0
  77. package/src/memory/vault.ts +74 -0
  78. package/src/mlx/array.ts +106 -19
  79. package/src/mlx/autograd.ts +2 -2
  80. package/src/mlx/ffi.ts +27 -3
  81. package/src/mlx/metal-kernel.ts +7 -4
  82. package/src/mlx/ops.ts +153 -23
  83. package/src/mlx/turboquant-ops.ts +831 -0
  84. package/src/mlx/turboquant-tables.ts +237 -0
  85. package/src/model/batched-mask.ts +62 -1
  86. package/src/model/batched-quant.ts +206 -0
  87. package/src/model/batched-rotating-quant.ts +346 -0
  88. package/src/model/batched-rotating.ts +46 -1
  89. package/src/model/compiled-decode.ts +4 -15
  90. package/src/model/factory.ts +10 -4
  91. package/src/model/gemma4-base.ts +363 -39
  92. package/src/model/gemma4.ts +122 -33
  93. package/src/model/generated/gemma4-12b.ts +9 -13
  94. package/src/model/generated/gemma4-26b.ts +10 -5
  95. package/src/model/generated/gemma4-e4b.ts +14 -9
  96. package/src/model/minicpm5.ts +58 -102
  97. package/src/model/paged-kv.ts +253 -0
  98. package/src/model/qwen3-delta.ts +76 -15
  99. package/src/model/qwen3-moe.ts +404 -0
  100. package/src/model/qwen3.ts +9 -8
  101. package/src/model/qwen3_5.ts +88 -23
  102. package/src/model/support.ts +12 -1
  103. package/src/model/universal/dense.ts +40 -5
  104. package/src/model/universal/rope.ts +36 -21
  105. package/src/pi-web.ts +1299 -82
  106. package/src/preflight.ts +27 -8
  107. package/src/prompt-cache.ts +293 -33
  108. package/src/quantize/quantizer.ts +16 -1
  109. package/src/registry.ts +57 -2
  110. package/src/serve/batch-scheduler.ts +965 -72
  111. package/src/serve/generation-gateway.ts +214 -11
  112. package/src/serve/isolate.ts +417 -0
  113. package/src/serve/lane-registry.ts +44 -0
  114. package/src/serve/session-search.ts +326 -0
  115. package/src/server.ts +1380 -135
  116. package/src/spec/assistant-source.ts +150 -0
  117. package/src/spec/deepspec-source.ts +143 -0
  118. package/src/spec/dflash-source.ts +124 -0
  119. package/src/spec/dspark/ab-stats.ts +136 -0
  120. package/src/spec/dspark/calibration.ts +112 -0
  121. package/src/spec/dspark/deepspec-module.ts +801 -0
  122. package/src/spec/dspark/generate-dflash.ts +72 -20
  123. package/src/spec/dspark/loader.ts +23 -0
  124. package/src/spec/dspark/module-dflash.ts +278 -36
  125. package/src/spec/dspark/quantize-drafter.ts +91 -0
  126. package/src/spec/generate.ts +59 -25
  127. package/src/spec/ngram-source.ts +132 -0
  128. package/src/spec/serve-loop.ts +536 -0
  129. package/src/spec/source.ts +93 -0
  130. package/src/spec/two-model.ts +171 -0
  131. package/src/ssd-cache.ts +107 -35
  132. package/src/tokenizer.ts +288 -2
  133. package/src/tool-approvals.ts +131 -0
  134. package/src/tool-call.ts +408 -20
  135. package/src/train/flash-cce.ts +2 -2
  136. package/src/train/job.ts +0 -2
  137. package/src/train/trainer.ts +1 -4
  138. package/src/vision/prompt.ts +217 -48
  139. package/src/web/app.html +1184 -1789
  140. package/src/web/app.js +5667 -0
  141. package/src/web/icon.svg +13 -0
  142. package/src/web/manifest.webmanifest +24 -0
  143. package/src/web/src/adapters-panel.ts +288 -0
  144. package/src/web/src/api.ts +57 -0
  145. package/src/web/src/assistant.ts +485 -0
  146. package/src/web/src/chat.ts +1050 -0
  147. package/src/web/src/composer.ts +959 -0
  148. package/src/web/src/dataset.ts +132 -0
  149. package/src/web/src/finetune.ts +267 -0
  150. package/src/web/src/hub.ts +428 -0
  151. package/src/web/src/main.ts +98 -0
  152. package/src/web/src/markdown.ts +0 -0
  153. package/src/web/src/memory-panel.ts +572 -0
  154. package/src/web/src/model-picker.ts +159 -0
  155. package/src/web/src/palette.ts +346 -0
  156. package/src/web/src/protocol.ts +62 -0
  157. package/src/web/src/quantize.ts +167 -0
  158. package/src/web/src/rag.ts +274 -0
  159. package/src/web/src/sessions.ts +469 -0
  160. package/src/web/src/shell.ts +804 -0
  161. package/src/web/src/status.ts +252 -0
  162. package/src/web/src/ui-catalog.ts +92 -0
  163. package/src/web/sw.js +71 -0
  164. package/src/web/vendor/README.md +61 -0
  165. package/src/web/vendor/hljs-LICENSE +29 -0
  166. package/src/web/vendor/hljs-theme.css +59 -0
  167. package/src/web/vendor/hljs.js +26 -0
  168. package/src/model/fused-decode-kernel.ts +0 -312
  169. package/src/model/fused-geglu-kernel.ts +0 -198
  170. package/src/model/fused-mlp-kernel.ts +0 -169
  171. package/src/model/fused-swiglu-kernel.ts +0 -240
  172. package/src/model/steel-linear-kernel.ts +0 -96
  173. package/src/status-page.html +0 -497
@@ -0,0 +1,235 @@
1
+ # TurboQuant KV — design (Phase 13)
2
+
3
+ Status: v1 wired end-to-end (2026-07-06): codec + `TurboQuantKVCache` +
4
+ `--kv-quant turbo[:k<bits>v<bits>]` (cli.ts, serve/generate/bench) +
5
+ `maybeQuantizeKv` conversion + `GenerationGateway` solo-only refusal +
6
+ `kv-store.ts` persistence + `scripts/eval-turboquant-curve.ts` (KL/ppl curve
7
+ script; not yet RUN against a real model — that's the next stage's gate).
8
+ Owner seam: L2 cache format, L1-unmodified attention (dequantize-on-fetch),
9
+ eval-gated. Opt-in only — naked default stays L1.
10
+
11
+ ## What it is
12
+
13
+ Rotation-based KV-cache quantization: signed int8 affine keys + FWHT-rotated
14
+ 3-bit Lloyd-Max values, per-32-group fp16 scales. More usable context at the
15
+ same memory (2.56× KV compression at the k8/v3 default, head_dim 128), NOT a
16
+ weight quantizer. Composes with (is orthogonal to) the per-layer mixed-KV
17
+ allocation axis — TurboQuant is the QUANTIZER axis (frontier plan §7.2).
18
+
19
+ ## Oracle chain (decided 2026-07-06 from the research fan-out)
20
+
21
+ Two unrelated implementations share the name; do not conflate:
22
+
23
+ - **The paper** (arXiv:2504.19874, Google): dense QR random rotation, no
24
+ groups, no K/V asymmetry, optional QJL residual stage. It anchors the WHY
25
+ (rotate→Gaussian marginal→Lloyd-Max optimal; 4^-b distortion law) but not
26
+ the layout.
27
+ - **vllm-metal** (`vllm-project/vllm-metal`, `vllm_metal/attention/caches/
28
+ turboquant.py` + `kernels_v2/turboquant.metal`): the engineering variant.
29
+ optiq's `runtime/mtp/turboquant.py` config layer is lifted verbatim from it
30
+ (byte-identical `CENTROIDS_3BIT`, matching op signatures in optiq
31
+ `cache_state.py`). **This is our oracle** — "the oracle is whoever ships
32
+ it." Its Python reference functions are pure MLX; we vendor them and
33
+ generate bit-exact goldens with the oracle venv.
34
+ - mlx-vlm's 6.3k-line module is a THIRD design (whole-vector norms, MSE/Prod
35
+ codecs, keys rotated too) — noted, not our target. Its numeric test oracles
36
+ (MSE≈{0.36, 0.117, 0.03} at bits {1,2,3} on unit vectors) are still useful
37
+ sanity anchors for the rotation+Lloyd-Max math.
38
+ - vllm-metal's rendered docs page contradicts its own source (claims keys are
39
+ rotated; the code never rotates keys). Trust the source.
40
+
41
+ ## Algorithm (vllm-metal reference semantics, exact)
42
+
43
+ Per token, per kv-head, groups of 32 along head_dim (head_dim ∈ {64,128,256,
44
+ 512}, must divide by 32):
45
+
46
+ **Keys — NO rotation, asymmetric affine, per-32-group:**
47
+ - signed (q8_0/int8, bits=8): `max_val=127; scale=(max−min)/(2·max_val);
48
+ zero=round((max+min)/(2·scale)); idx=clip(round(x/scale − zero), −127, 127)`
49
+ stored as int8, one byte per element (no packing at 8 bits).
50
+ - unsigned (q5_0/q4_0/int2…): `max_val=2^bits−1; scale=(max−min)/max_val;
51
+ zero=round(min/scale); idx=clip(round(x/scale − zero), 0, max_val)`, packed.
52
+ - Dequant (both): `x̂=(idx+zero)·scale`. scale/zero fp16, one pair per group.
53
+ - Reference routes intermediates through fp16 (and deliberately drops the
54
+ +1e-8 scale epsilon because it underflows in fp16) — match the Python
55
+ reference's ACTUAL behavior, verified by goldens, not its comments.
56
+
57
+ **Values — FWHT + Lloyd-Max, per-32-group RMS scale:**
58
+ - `y = FWHT(x · signs)` where `signs ∈ {±1}^d` from `mx.random.randint(0,2,
59
+ (d,), key=mx.random.key(42))`, and FWHT normalizes by 1/√d.
60
+ - `scale = sqrt(mean(y²))` per 32-group (RMS, not min/max); `y_n = y/(scale+1e-8)`.
61
+ - `idx = searchsorted(BOUNDARIES, y_n)` — nearest centroid. 3-bit table:
62
+ centroids ±{0.24509, 0.75601, 1.34391, 2.15195}, boundaries ±{0.50055,
63
+ 1.04996, 1.74793}, 0. Other bit-widths (2/4/5/8): iterative Lloyd-Max on a
64
+ unit normal — we generate those tables ONCE from the vendored reference and
65
+ hardcode them (parity by construction; no runtime iteration).
66
+ - Pack: flat little-endian bitstream, element i at bits [i·b, i·b+b), values
67
+ may straddle two bytes (3-bit: 8 values → 3 bytes).
68
+ - Dequant: `x̂ = InvFWHT(centroids[idx] · scale · signs⁻¹)` (inverse = apply
69
+ FWHT then multiply signs; Hadamard is an involution up to normalization).
70
+
71
+ **Per-token-per-head bytes (k8v3, d=128):** 128 (K int8) + 8+8 (K scale/zero)
72
+ + 48 (V packed) + 8 (V scale) = 200 vs 512 bf16 → 2.56×. The centroid table is
73
+ a shared constant, not per-token. This reproduces optiq's `compression_ratio`.
74
+
75
+ **Sign vectors are hardcoded constants per head_dim** (64/128/256/512),
76
+ generated from the reference's key(42) — exactly what vllm-metal does in its
77
+ .metal source. Deterministic across machines and spill/restore.
78
+
79
+ ## v1 architecture in mlx-bun
80
+
81
+ Dequantize-on-fetch: `TurboQuantKVCache implements Cache` (does NOT subclass
82
+ KVCache — that keeps it auto-excluded from batching), `updateAndFetch(k,v)`
83
+ quantizes the new tokens into packed storage and returns the dequantized bf16
84
+ active window, so the standard `ops.sdpa` path runs unmodified — the same
85
+ pattern optiq's `runtime/kv/rotating.py` uses for its v1. No generated-file
86
+ changes: a novel cache class fails every `#matches()` guard and falls back to
87
+ the monolith by design. Quantization groups run along head_dim only —
88
+ token-axis slicing stays byte-safe (standing invariant).
89
+
90
+ Files (from the codebase-map seams):
91
+ - `src/mlx/turboquant-ops.ts` — NEW: fwht (bind `mlx_hadamard_transform`,
92
+ confirmed exported by libmlxc), encode/decode keys + values, pack/unpack.
93
+ - `src/mlx/turboquant-tables.ts` — NEW, GENERATED by regen script: sign
94
+ vectors per head_dim + Lloyd-Max centroid/boundary tables per bit-width.
95
+ - `src/model/gemma4-base.ts` — NEW `TurboQuantKVCache` (full-attention only in
96
+ v1; rotating/sliding-window layers stay bf16 — documented limitation).
97
+ - `src/generate.ts` `maybeQuantizeKv()` — the single conversion chokepoint
98
+ (serve serial lane + generate + eval all flow through it); keep the
99
+ `offset===0` skip and `quantizedKvStart` semantics.
100
+ - `src/cli.ts` — `--kv-quant turbo[:k<bits>v<bits>]` (default k8v3).
101
+ - `src/serve/generation-gateway.ts` — explicit solo-only refusal (belt +
102
+ braces on top of the automatic instanceof exclusion).
103
+ - `src/kv-store.ts` — new `CacheKind "turboquant"`, branches in
104
+ snapshotCache/loadKvCache/cloneKvCaches; header carries kBits/vBits.
105
+ - `src/model/fingerprint.ts` — NOT touched, by design symmetry: uniform
106
+ `--kv-quant 4|8` is a CLI-only runtime lever that never feeds
107
+ `configFingerprint()` either (only the per-layer `kv_config.json` scheme
108
+ does); TurboQuant is the same class of lever, so it gets the same
109
+ non-treatment. The SSD-cache compat key (`server.ts`'s `schemeKey`) DOES
110
+ fold in the TurboQuant scheme directly (`turbo-k<bits>v<bits>`), same as it
111
+ already does for uniform bits — that's the actual anti-collision mechanism
112
+ for this class of scheme, not the fingerprint.
113
+ - Docs same-commit: server-config.md, cli.md, features-matrix.md.
114
+ - Tests: `tests/turboquant-ops.test.ts` (golden bit-exactness vs vendored
115
+ reference + model-free math props), `tests/turboquant-cache.test.ts` (cache
116
+ invariants, growth/trim, persistence roundtrip — synthetic arrays, no
117
+ model/golden dependency), `scripts/regen-turboquant-goldens.ts`.
118
+ - `scripts/eval-turboquant-curve.ts` — the Gate 3 quality-vs-bpw curve script:
119
+ bf16 baseline + {k8v8,k8v4,k8v3,k8v2,k4v3,k4v2} sequentially, reusing
120
+ `src/eval/kl.ts`'s `evaluateKlKvArm` (teacher-forced serving-decode KL,
121
+ real `TurboQuantKVCache.fromKVCache` conversion) and
122
+ `src/eval/perplexity.ts`'s `evalPpl` (bf16-forward anchor column).
123
+ Typechecks + `--help`/arg-parsing verified; not yet RUN against a real
124
+ model — that run (and reading the resulting curve against the paper's law)
125
+ is the next stage's job.
126
+ - Vendored reference: `lab/repro/vllm-metal-turboquant/` (their Python file +
127
+ provenance note), driven only by the regen script via the oracle venv.
128
+
129
+ ## Gates — ALL PASSED 2026-07-06 (M1 Max 32 GB)
130
+
131
+ Gate 3 measured curve (MiniCPM5-1B, `scripts/eval-turboquant-curve.ts`,
132
+ teacher-forced serving-decode KL vs bf16, 8 prompts × 128 tokens, 32 decode
133
+ steps; affine baselines via the same `evaluateKlKvArm` harness):
134
+
135
+ | scheme | effective KV bits | mean KL vs bf16 |
136
+ |---|---|---|
137
+ | bf16 | 16.00 | 0 (control) |
138
+ | uniform kv8 (affine g64) | 8.50 | 0.00246 |
139
+ | turbo k8v8 | 8.75 | 0.00214 |
140
+ | turbo k8v4 | 6.75 | 0.00936 |
141
+ | **turbo k8v3 (default)** | **6.25** | **0.0325** |
142
+ | turbo k8v2 | 5.75 | 0.175 |
143
+ | uniform kv4 (affine g64) | 4.50 | 0.0516 |
144
+ | turbo k4v3 | 4.25 | 0.0622 |
145
+ | turbo k4v2 | 3.75 | 0.205 |
146
+
147
+ Shape reproduces the paper's law: value bits dominate, ~4^-b decay, cliff at
148
+ v2. Headline: turbo adds operating points between affine kv8/kv4 — the k8v3
149
+ default (2.56× KV compression) beats uniform kv4's KL with room to spare.
150
+ Live smokes: cpm5 + e4b generation coherent under turbo:k8v3 (e4b emits the
151
+ one-time rotating-layers-stay-bf16 warning). The paper's own LongBench
152
+ numbers were NOT rerun (different benchmark harness) — the reproduction is
153
+ shape-level plus the codec-level D_mse≈0.03 anchor, which our 3-bit
154
+ roundtrip test hits.
155
+
156
+ 1. **Quantizer parity (bit-exact, the hard gate):** our encode indices,
157
+ scales, zeros, packed bytes, and dequant outputs match the vendored
158
+ vllm-metal Python reference on golden vectors (head_dim 64/128; configs
159
+ k8v3/k4v3/k4v2/k8v4/k2v5/k5v8 — spanning every kBits/vBits value the CLI
160
+ accepts, per the 2026-07-06 integration review). This is an oracle-backed
161
+ scheme at the codec level.
162
+ 2. **Math sanity (model-free):** FWHT involution/orthogonality; roundtrip MSE
163
+ at 3-bit on unit-normal data ≈ paper's D_mse≈0.03 band.
164
+ 3. **Quality-vs-bpw curve (Phase 13 exit criterion):** teacher-forced KL
165
+ (src/eval/kl.ts) + perplexity vs bf16 KV on MiniCPM5-1B (head_dim 128,
166
+ pure full-attention) across {k8v8, k8v4, k8v3, k8v2, k4v3, k4v2}; curve
167
+ shape must match the paper's law (≈quality-neutral ≥3.5 effective bits,
168
+ marginal degradation at 2.5, cliff below). e4b spot check second. Model
169
+ runs SEQUENTIAL (32 GB box rule).
170
+ 4. Whole-repo `tsc --noEmit` = 0; fast suite green; no batching regression
171
+ (turbo requests route serial with a clear reason).
172
+
173
+ ## Deferred inverse FWHT (LANDED 2026-07-06, post-v1, Josh-directed)
174
+
175
+ Attention is linear in V, so `InvFWHT(Σᵢ wᵢ·v̂ᵢ) = Σᵢ wᵢ·InvFWHT(v̂ᵢ)`:
176
+ `updateAndFetchDeferredV` returns the V window still in the rotated domain
177
+ and the attention site un-rotates the OUTPUT once per query row
178
+ (`tq.unrotateValues`) — O(q·d log d) per step instead of O(T·d log d).
179
+ Opt-in per attention site via `SharedKv.vRotated` (monolith gemma4.ts —
180
+ KV-shared consumer layers inherit the flag through sharedIn — and
181
+ minicpm5.ts); every other consumer keeps calling `updateAndFetch` (eager)
182
+ and stays correct. Not bit-identical to eager (bf16 rounding in the rotated
183
+ domain before the transform); measured k8v3 KL 0.0338 vs eager 0.0325 —
184
+ same quality. Paired fetch-path A/B on a LOADED M1 Max: never slower,
185
+ ~10-20% off fetch cost at 4k ctx, noise-level at 8k (dequant gather
186
+ dominates both paths) — no speed claim until a quiet-machine benchmark.sh
187
+ run; the win is removing the O(T) transform, which matters more once the
188
+ gather itself is fused.
189
+
190
+ ## Future: rotation-based WEIGHT quantization (noted 2026-07-06, Josh)
191
+
192
+ The same rotate-then-quantize mechanism applies to weights, and we already
193
+ ship a quantization tool (`convert`/`fuse` verbs) to hang it on — as a
194
+ further optimization of quantization itself, the quantizer leg of the §7.1
195
+ mixed-precision program (allocation × quantizer, same orthogonality as KV):
196
+
197
+ - Rotation smears outlier channels so a low-bit codebook covers the signal
198
+ mass — the QuaRot/SpinQuant family (both cited by the TurboQuant paper).
199
+ - Weights beat KV on one axis: the rotation FOLDS into adjacent weight
200
+ matrices offline (R into one layer, Rᵀ into the next) → zero runtime
201
+ cost, no online transform at all.
202
+ - Weights lose on the other: they're static, so calibration-aware methods
203
+ (GPTQ/AWQ/imatrix, optiq sensitivity maps) are admissible and set a
204
+ higher baseline than any calibration-free scheme — the win to chase is
205
+ rotation COMPOSED WITH calibration/allocation, not instead of it.
206
+ - A Lloyd-Max weight FORMAT needs custom quantized-matmul kernels — the
207
+ 26B gather-qmv shelving (dispatch fixed-cost ate the prize) is the
208
+ cautionary precedent. Rotation-folding into mlx's EXISTING affine format
209
+ needs no new kernels and is the cheap first experiment.
210
+ - Activations (W4A4/QuaRot act-quant): more involved (online rotation,
211
+ fused kernels) and mispriced for this hardware — no int4 tensor cores,
212
+ decode is weight-bandwidth-bound. See w4a16-compute-precision-spike.md.
213
+ Not queued.
214
+
215
+ Gate when picked up: perplexity + frozen 6-task eval at equal bpw vs the
216
+ plain affine convert output (the §7.1 gate, eval DB rows).
217
+
218
+ ## Non-goals for v1 (recorded so they don't creep)
219
+
220
+ - Fused quantized-SDPA Metal kernel (the remaining fetch cost is the
221
+ unpack+gather; deferred InvFWHT — see above — already landed).
222
+ - Rotating/sliding-window TurboQuant cache; batched TurboQuant; QJL residual
223
+ stage (Q_prod); entropy coding (paper explicitly declined it too).
224
+ - TurboQuant on the speculative lane: `--kv-quant turbo` + `--draft-model`
225
+ keeps the KV scheme — those requests decode serially WITHOUT speculation
226
+ (the spec loop is bf16-KV-only; excluded in the server's spec-eligibility
227
+ gate with a startup warning, 2026-07-07 review fix — turbo was previously
228
+ routed into the spec lane and silently dropped).
229
+ - Head dims beyond {64,128,256,512}: REFUSED AT SERVER START (2026-07-07
230
+ review fix — validation was lazy on the first cache append, so an
231
+ unsupported model 500'd every request mid-prefill; createServer now
232
+ checks the config's full-attention head dim against
233
+ TURBOQUANT_HEAD_DIMS, and the cache-level check stays as the backstop).
234
+ - Speed claims of any kind — v1 dequant-on-fetch is expected slower per-step
235
+ at long context; this ships as a memory/context feature like uniform KV.