mlx-bun 0.5.0 → 1.0.0

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 (640) hide show
  1. package/README.md +1449 -109
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +7 -5
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -1,2225 +0,0 @@
1
- ---
2
- status: active
3
- axis: ON
4
- canonical-for: turboquant
5
- plan-anchor: "Phase: TurboQuant weights — rotation-folded quantization, Qwen3.8-27B target `[ ]` (opened 2026-08-17)"
6
- last-verified: 2026-08-23
7
- ---
8
-
9
- # TurboQuant — rotation-based quantization (KV leg landed, weights leg open)
10
-
11
- One canonical doc for both legs of the rotate-then-quantize program.
12
- Sources folded in: `docs/design/turboquant.md` (KV, landed 2026-07-06)
13
- and `docs/design/turboquant.md` (weights, open). Status/changelog
14
- prose lives in PLAN.md under the plan-anchor above (weights) and the closed
15
- Phase 13 entry (KV); this doc keeps mechanism, invariants, decisions with
16
- rationale, measured curves, and open items.
17
-
18
- ## Naming: TurboQuant is a KV method by origin
19
-
20
- TurboQuant (arXiv:2504.19874, Google) is a KV-cache quantizer: rotate the
21
- value vectors so their marginals are near-Gaussian, then Lloyd-Max quantize.
22
- That is the leg we ship under `--kv-quant turbo`. The **weights leg is this
23
- repo's extension** of the same mechanism to weight matrices — mechanically
24
- it is the QuaRot/SpinQuant family (rotation folded offline into adjacent
25
- weights, then quantized with mlx's stock formats), not anything the
26
- TurboQuant paper describes. The shared name records the shared idea
27
- (rotate → Gaussian marginal → better codebook coverage) and that both are
28
- the QUANTIZER axis of the mixed-precision program: they compose with, and
29
- never replace, per-layer allocation (OptiQ-style) and calibration.
30
-
31
- | leg | what is rotated | when | oracle | state |
32
- |---|---|---|---|---|
33
- | KV | value vectors (keys affine, unrotated) | online, per appended token | vllm-metal `turboquant.py` | landed 2026-07-06 |
34
- | weights | residual-stream basis of every linear | offline, folded into weights | QuaRot + SpinQuant fold code; mlx-lm GPTQ | open (PLAN "TurboQuant weights") |
35
-
36
- ---
37
-
38
- # Part A — KV leg (`--kv-quant turbo`)
39
-
40
- ## What it is
41
-
42
- Rotation-based KV-cache quantization: signed int8 affine keys + FWHT-rotated
43
- 3-bit Lloyd-Max values, per-32-group fp16 scales. More usable context at the
44
- same memory (2.56× KV compression at the k8/v3 default, head_dim 128). Owner
45
- seam: L2 cache format, L1-unmodified attention (dequantize-on-fetch), opt-in
46
- only — the naked default stays L1 (bf16 KV).
47
-
48
- ## Oracle chain (decided 2026-07-06)
49
-
50
- Two unrelated implementations share the name; do not conflate:
51
-
52
- - **The paper** (arXiv:2504.19874): dense QR random rotation, no groups, no
53
- K/V asymmetry, optional QJL residual stage. Anchors the WHY (rotate →
54
- Gaussian marginal → Lloyd-Max optimal; 4^-b distortion law), not the layout.
55
- - **vllm-metal** (`vllm-project/vllm-metal`,
56
- `vllm_metal/attention/caches/turboquant.py` + `kernels_v2/turboquant.metal`):
57
- the engineering variant. optiq's `runtime/mtp/turboquant.py` config layer is
58
- lifted verbatim from it (byte-identical `CENTROIDS_3BIT`, matching op
59
- signatures in optiq `cache_state.py`). **This is our oracle** — "the oracle
60
- is whoever ships it." Its Python reference is pure MLX; we vendor it at
61
- `lab/repro/vllm-metal-turboquant/turboquant_reference.py` (fetch provenance
62
- in `PROVENANCE.md` beside it) and generate bit-exact goldens through the
63
- oracle venv. Quirks are preserved on purpose: the port matches what the file
64
- computes, not what its comments say.
65
- - mlx-vlm's module is a THIRD design (whole-vector norms, MSE/Prod codecs,
66
- keys rotated too) — not our target; its unit-vector MSE anchors
67
- (≈{0.36, 0.117, 0.03} at bits {1,2,3}) remain useful sanity checks.
68
- - vllm-metal's rendered docs claim keys are rotated; the code never rotates
69
- keys. Trust the source.
70
-
71
- ## Algorithm (vllm-metal reference semantics, exact)
72
-
73
- Per token, per kv-head, groups of 32 along head_dim (head_dim ∈
74
- {64,128,256,512} — `TURBOQUANT_HEAD_DIMS` in `src/mlx/turboquant-tables.ts`).
75
-
76
- **Keys — NO rotation, asymmetric affine, per-32-group:**
77
- - signed (int8, bits=8): `max_val=127; scale=(max−min)/(2·max_val);
78
- zero=round((max+min)/(2·scale)); idx=clip(round(x/scale − zero), −127, 127)`,
79
- one byte per element (no packing at 8 bits).
80
- - unsigned (bits ∈ {2,4,5}): `max_val=2^bits−1; scale=(max−min)/max_val;
81
- zero=round(min/scale); idx=clip(round(x/scale − zero), 0, max_val)`, packed.
82
- - Dequant (both): `x̂=(idx+zero)·scale`; scale/zero fp16, one pair per group.
83
- - The reference routes intermediates through fp16 and deliberately drops the
84
- `+1e-8` scale epsilon (it underflows in fp16). Our port upcasts the affine
85
- arithmetic to fp32 (production feeds bf16 K; bf16 arithmetic shifted
86
- rounding-boundary indices vs the reference) and casts only scale/zero to
87
- fp16 at the end — reproducing the reference's real defect that a
88
- constant-valued block overflows zero_point to ±Inf. The golden test asserts
89
- it (`src/mlx/turboquant-ops.ts` header).
90
-
91
- **Values — FWHT + Lloyd-Max, per-32-group RMS scale:**
92
- - `y = FWHT(x · signs)`, `signs ∈ {±1}^d` from
93
- `mx.random.randint(0,2,(d,), key=mx.random.key(42))`; FWHT normalizes by 1/√d.
94
- - `scale = sqrt(mean(y²))` per 32-group (RMS, not min/max); `y_n = y/(scale+1e-8)`.
95
- - `idx = searchsorted(BOUNDARIES, y_n)`. 3-bit table: centroids
96
- ±{0.24509, 0.75601, 1.34391, 2.15195}, boundaries ±{0.50055, 1.04996,
97
- 1.74793}, 0. Other widths (2/4/5/8): the reference's iterative Lloyd-Max on
98
- a unit normal (key(0), 500 iterations), generated ONCE and hardcoded —
99
- parity by construction, no runtime iteration.
100
- - Pack: flat little-endian bitstream, element i at bits [i·b, i·b+b); values
101
- may straddle bytes (3-bit: 8 values → 3 bytes).
102
- - Dequant: `x̂ = InvFWHT(centroids[idx] · scale · signs⁻¹)`.
103
-
104
- **Bytes per token per head (k8v3, d=128):** 128 (K int8) + 8+8 (K
105
- scale/zero) + 48 (V packed) + 8 (V scale) = 200 vs 512 bf16 → 2.56×. This
106
- reproduces optiq's `compression_ratio`. Sign vectors are hardcoded constants
107
- per head_dim (what vllm-metal does in its .metal source) — deterministic
108
- across machines and spill/restore.
109
-
110
- ## Architecture in mlx-bun (verified 2026-08-23)
111
-
112
- Dequantize-on-fetch: `TurboQuantKVCache implements Cache`
113
- (`src/model/gemma4-base.ts`; does NOT subclass KVCache, which keeps it
114
- auto-excluded from batching). `updateAndFetch(k,v)` quantizes only the newly
115
- appended tokens into packed storage and returns the dequantized bf16 active
116
- window, so stock `ops.sdpa` runs unmodified — the pattern optiq's
117
- `runtime/kv/rotating.py` uses. A novel cache class fails every generated-file
118
- `#matches()` guard and falls back to the monolith by design. Quantization
119
- groups run along head_dim only — token-axis slicing stays byte-safe
120
- (standing invariant).
121
-
122
- Code map:
123
- - `src/mlx/turboquant-ops.ts` — fwht (binds `mlx_hadamard_transform`),
124
- encode/decode keys + values, pack/unpack, `unrotateValues`.
125
- - `src/mlx/turboquant-tables.ts` — GENERATED by `bun scripts/regen.ts
126
- turboquant` (job file `scripts/regen/turboquant.ts`, which shells out to
127
- `lab/repro/vllm-metal-turboquant/gen_goldens.py` under the oracle venv):
128
- sign vectors per head_dim + Lloyd-Max tables per bit-width; also writes
129
- `goldens/turboquant.json` (machine-independent, flat goldens set).
130
- - `src/config.ts` — `TurboQuantScheme {kBits, vBits}`,
131
- `parseTurboQuantScheme` (`turbo` = k8v3; `TURBOQUANT_VALID_KBITS`
132
- {2,4,5,8}, `TURBOQUANT_VALID_VBITS` {2,3,4,5,8}).
133
- - `src/cli.ts` — `--kv-quant turbo[:k<bits>v<bits>]` on serve/generate/bench.
134
- - `src/kv-scheme.ts` — `KvScheme` kind `"turbo"`; `cacheKey` =
135
- `turbo-k<k>v<v>` (the SSD-cache / prompt-cache anti-collision key);
136
- `bytesAt` bills bf16 (conservative — no projector for the packed layout
137
- yet); `fitOptions` is empty for turbo for the same reason.
138
- - `src/generate.ts` `maybeQuantizeKv()` → `maybeTurboQuantizeKv()` — the
139
- single conversion chokepoint (serve serial lane + generate + eval all flow
140
- through it); `TurboQuantKVCache.fromKVCache`; `RotatingKVCache` layers stay
141
- bf16 with a one-time warning; keeps the `quantizedKvStart` semantics.
142
- - `src/backends/mlx/kv-codec.ts` and `src/model/turboquant-codec.ts` separate
143
- encoding and existing fused kernel selection from storage membership.
144
- - `KvTensorRows` owns arbitrary encoded planes; `BatchedTurboQuantKVCache`
145
- binds the five TQ planes to shared positions and a rotated-value attention
146
- port. Gemma owns pre-write row positions across cache appends and releases
147
- shared positions with the shared attention state.
148
- - `src/backends/mlx/cache-layout.ts` supplies ordinary and target-transaction
149
- layouts. The gateway binds start-zero TQ and grouped Qwen MTP capabilities;
150
- the scheduler only chooses work. Server head-dimension validation remains.
151
- `turboQuant` and `kvQuant` are mutually exclusive.
152
- - `src/kv-store.ts` — `CacheKind "turboquant"`; header carries kBits/vBits
153
- + head_dim; snapshot/restore/clone branches.
154
- - `src/model/fingerprint.ts` — NOT touched, by symmetry: uniform
155
- `--kv-quant 4|8` is a CLI-only runtime lever that never feeds
156
- `configFingerprint()` either; the anti-collision mechanism for this class
157
- of lever is the scheme key above, not the fingerprint.
158
- - Tests: `tests/turboquant-ops.test.ts` (golden bit-exactness vs the
159
- vendored reference + model-free math props), `tests/turboquant-cache.test.ts`
160
- (cache invariants, growth/trim, persistence roundtrip; synthetic arrays).
161
- - Curve script: `scripts/turboquant/eval-turboquant-curve.ts` — bf16
162
- baseline + {k8v8,k8v4,k8v3,k8v2,k4v3,k4v2} sequentially, reusing
163
- `src/eval/kl.ts`'s `evaluateKlKvArm` (teacher-forced serving-decode KL,
164
- real `fromKVCache` conversion) and `src/eval/perplexity.ts`'s `evalPpl`.
165
- - Reference docs: server-config.md, cli.md, docs/reference/server-config.md carry the
166
- flag surface.
167
-
168
- ## Deferred inverse FWHT (landed 2026-07-06, post-v1)
169
-
170
- Attention is linear in V, so `InvFWHT(Σᵢ wᵢ·v̂ᵢ) = Σᵢ wᵢ·InvFWHT(v̂ᵢ)`:
171
- `updateAndFetchDeferredV` returns the V window still in the rotated domain
172
- and the attention site un-rotates the OUTPUT once per query row
173
- (`tq.unrotateValues`) — O(q·d log d) per step instead of O(T·d log d).
174
- Opt-in per attention site via `SharedKv.vRotated` (monolith `gemma4.ts` —
175
- KV-shared consumer layers inherit the flag through `sharedIn` — and
176
- `minicpm5.ts`); every other consumer keeps calling `updateAndFetch` (eager)
177
- and stays correct. Not bit-identical to eager (bf16 rounding in the rotated
178
- domain before the transform); measured k8v3 KL 0.0338 vs eager 0.0325 —
179
- same quality. Paired fetch-path A/B on a LOADED M1 Max: never slower,
180
- ~10-20% off fetch cost at 4k ctx, noise-level at 8k (dequant gather
181
- dominates both) — no speed claim until a quiet-machine
182
- `scripts/bench-serve.ts all` run; the win is removing the O(T) transform,
183
- which matters more once the gather itself is fused. (The class-level doc
184
- comment on `TurboQuantKVCache` still calls deferred-InvFWHT a non-goal; the
185
- method exists two screens below it — the comment is stale, the code is
186
- authoritative.)
187
-
188
- ## Packed-value decode fusion investigation
189
-
190
- The Mac-quant video follow-up in decode-speed-program §7.11 exposed an
191
- unpack/gather/scale chain that also exists in our shipped KV decoder. A
192
- research-only Metal prototype reads the byte-packed values and fp16 group
193
- scales directly from the active cache window, gathers the existing f32
194
- Lloyd-Max centroids and multiplies in f32. The eager path keeps the native
195
- inverse Hadamard, sign multiplication and bf16 cast. The deferred path casts
196
- the same f32 values to bf16. Keys and the quantized representation stay the
197
- same. The four-dimensional launch reads cache strides without copying its
198
- capacity slice; context length, capacity and head count remain runtime inputs.
199
- There is no specialization for each new token position.
200
-
201
- On the M4 Pro 24 GB, the initial 140 cases preserve 280 flat/grid comparisons
202
- across value bits 2/3/4/5/8, head dimensions 64/128/256/512, multiple batch/head
203
- counts, strided cache windows and both rotation paths. Three six-process
204
- repeats preserve another 1,440 candidate comparisons and every cross-process
205
- fixture/output hash. These add fp16 scales and the production 32-value group
206
- to the initial bf16/f32 and 64-value-group operation coverage. Every process
207
- returns to its primed native sign/centroid-cache allocation. The all-dimension
208
- screen retains 5,104 bytes; each D256 repeat retains 2,288 bytes. The generated
209
- kernel keys stay constant across the three tested context lengths.
210
-
211
- The last repeat uses synthetic [1,8,N,256] caches with fp16 scales and groups
212
- of 32. For eager V3 decode, paired median operation time falls 46.72% at N128,
213
- 77.43% at N2048 and 81.37% at N8192. V5 falls 54.66%, 82.12% and 84.93%. Every
214
- V3/V5 pair improves. At N8192, peak temporary allocation falls about 250 MiB
215
- for V3 and 282 MiB for V5. The repeat checks outputs before timing and after
216
- the last rep of each arm; the earlier screen read the output on the CPU
217
- between every rep, which changed the timing regime. Raw screens are retained.
218
- These are operation diagnostics on a loaded machine, not RSS or full-model
219
- speed claims. This Qwen artifact has four KV heads, so the next gate runs the
220
- actual model. The experimental full-model branch keeps V8 on its native path
221
- while the larger low-bit gain is assessed.
222
-
223
- Evidence in reports/qwen38-rd: tq-value-grid.json,
224
- tq-value-repeat{,-review}.json, tq-value-f16-repeat{,-review}.json and
225
- tq-value-production-repeat{,-review}.json. Full-model logits, live cache and
226
- recurrent state, seeded generation, actual HTTP timing, fallback/lifetime and
227
- quiet acceptance are required before production integration or a default.
228
-
229
- The first Qwen k8v3 full-model pair now preserves all 20 forward/state and
230
- continuation comparisons plus four greedy/seeded-sampled generations at
231
- 128/2048 input tokens. Both arms make 4,880 cache-value calls. The candidate
232
- uses one D256/V3/group32/fp16-scale specialization across every context length;
233
- final active allocation is identical at 1,016,898 bytes. Timing is mixed:
234
- single-token forwards improve, while three of four complete generations lose.
235
- During the candidate process, one-minute load rises from 2.80 to 7.57 and
236
- system swap grows about 323 MiB, so this pair cannot isolate the cause of the
237
- slowdown. It is retained in full, and no production/default decision follows.
238
- Evidence: tq-value-full{,-review}.json. Actual Bun HTTP comparisons follow.
239
-
240
- An additional 270 finite-scale-boundary cases preserve 540 comparisons,
241
- including zero, signed zero, fp16 subnormals and large scales at every head
242
- dimension, with the actual four-KV-head shape included. All allocations return
243
- to the primed 5,104-byte global cache. Evidence: tq-value-edge.json. The first
244
- actual HTTP pair preserves all five responses, call maps and final allocation.
245
- Measured complete time falls 0.77% for the 58-token code prompt and 1.38% for
246
- the 1,806-token inventory prompt. The latter improves decode throughput 7.57%
247
- but worsens TTFT 3.80%; it is a screening pair, not acceptance. Six alternating
248
- fresh-server pairs now preserve all 30 paired responses, call maps, source
249
- hashes and process exits. Each server ends with the same 11,936,577,410 active
250
- bytes, which includes the retained model. Paired median complete time falls
251
- 0.82% on the short prompt, all six pairs, and 2.87% on the long prompt, four of
252
- six pairs. Long-prompt decode throughput rises 7.33%, five of six pairs; TTFT
253
- worsens 0.75% in the paired median and is split three wins/three losses. Per-
254
- request sampled RSS differences are small and inconsistent, so this is not a
255
- physical-memory claim. Retain both losing long-prompt pairs. Evidence:
256
- tq-value-http-repeat{,-review}.json. Test decode-only eligibility to separate
257
- prefill scheduling from decode, then broader context/quant/cache and quiet
258
- acceptance. No production/default change yet.
259
-
260
- A separate decode-only V arm also preserves 20 forward/state cases and four
261
- generations. Exact call maps show 4,480 fused M1 reads and 400 native
262
- multi-token reads; active allocation remains 1,016,898 bytes. Evidence:
263
- tq-value-decode-full{,-review}.json. A first timing pair improves complete
264
- generation, but it is not the policy decision.
265
-
266
- The next prototype decodes packed K and V in one launch, retaining K's f32
267
- addition before multiplication and V's f32 centroid multiplication. It passes
268
- 720 initial pair comparisons. An expanded screen checks all 20 served K/V bit
269
- combinations with distinct key/value scales, including finite boundary values,
270
- and preserves all 2,400 comparisons. Equal scale values in the initial
271
- synthetic fixtures could not detect a swapped scale input; the expanded
272
- fixtures close that gap. Actual-model scales were already independent.
273
-
274
- Six fresh-process operation repeats preserve another 432 comparisons. With
275
- actual four-head D256 caches, fp16 scales and group32, joint k8v3 decoding is
276
- 9.60%, 22.80% and 43.19% faster than V-only fusion at N128/2048/8192 in the
277
- paired median, all six pairs at each context. These include the native inverse
278
- rotation. Peak temporary allocation falls another 0.53/8.5/34 MiB. The full
279
- Qwen pair preserves 20 forward/state comparisons and four generations, all
280
- 4,880 cache calls, one generated specialization and identical final active
281
- allocation. Source and raw evidence: tq-kv-screen.json,
282
- tq-kv-independent.json, tq-kv-repeat{,-review}.json and
283
- tq-kv-full{,-review}.json.
284
-
285
- The actual Bun HTTP follow-up completes all six arm orders across 18 fresh
286
- servers. Its 90 requests preserve all 60 candidate/control response comparisons,
287
- call and eligibility maps, process exits and source hashes. Every server retains
288
- the same 11,936,577,410 active bytes. Each candidate uses one shader specialization
289
- across both prompt lengths. These runs use the same R6 weights, k8v3 cache,
290
- serial execution, greedy seed42 and no prompt reuse or speculative draft.
291
-
292
- | Candidate versus original | 58-token prompt: complete time | 1,806-token prompt: complete time | Long-prompt decode throughput | Long-prompt TTFT |
293
- |---|---|---|---|---|
294
- | V fusion only on M1 appends | −0.81%, 6/6 wins | −3.42%, 5/6 wins | +7.53%, 5/6 wins | −0.14%, 5/6 wins |
295
- | Joint K/V at all append shapes | −0.76%, 5/6 wins | −4.57%, 6/6 wins | +10.35%, 6/6 wins | −0.17%, 5/6 wins |
296
-
297
- Values are medians of paired changes, not ratios of unpaired medians. Joint
298
- decoding also improves long-prompt complete time over decode-only V by 1.20%,
299
- all six pairs; its short-prompt median is 0.08% slower. The first joint short
300
- request loses 3.70%, and the first decode-only long request loses 2.30%; both
301
- remain in the report. TTFT is effectively flat. Observed RSS deltas remain
302
- small and do not establish physical-memory savings. Evidence:
303
- tq-kv-policy-http{,-review}.json. Extend the exact gates to 8,192 context tokens,
304
- RTN4 and deferred-rotation consumers, then check integrated lifetime/fallback
305
- behavior. These are M4 Pro diagnostics with existing system swap; quiet
306
- acceptance and a production/default decision remain open.
307
-
308
- The 8,192-token R6 gate also passes: six full forward/state/continuation cases
309
- at M1/4/128 and two 64-token greedy/sampled generations are exact. Both arms
310
- make 2,960 cache calls and finish at 1,016,898 active bytes; the candidate still
311
- uses one shader key. In this single pair, complete generation time falls 9.11%
312
- and 7.43%, and native peak allocation falls 126.97 MiB. The measured M1 forward
313
- falls from 200.84 to 118.87 ms. These are screening timings, not repeated HTTP
314
- acceptance or physical-memory savings. Evidence: tq-kv-long-full{,-review}.json.
315
-
316
- A further prototype folds inverse Hadamard, normalization, signs and bf16 cast
317
- into the joint decoder. It copies the exact radix-16 butterfly and indexing from
318
- MLX 0.31.2's MIT-licensed Metal Hadamard implementation. All 480 shape/bit/dtype/
319
- finite-boundary cases preserve both candidate comparisons. Six fresh processes
320
- then preserve all 36 performance cells, but the literal one-row threadgroup
321
- layout loses to joint decode plus native rotation: k8v3 paired median operation
322
- time rises 12.76%/20.11%/24.67% at N128/2048/8192. Lower temporary allocation
323
- alone does not justify this version. The follow-up tests independent rows in
324
- one threadgroup, preserving each row's arithmetic and participation in barriers
325
- at partial tails. Evidence: tq-kv-rotation-screen.json and
326
- tq-kv-rotation-repeat{,-review}.json. No full-model run is justified for the
327
- losing layout.
328
-
329
- Grouping independent rows into one threadgroup preserves the same 960 boundary
330
- comparisons, including partially occupied tail groups. Six fresh-process repeats
331
- preserve all 36 timing cells. At N8192, this version improves over joint decode
332
- plus native rotation by 22.28% for k8v3 and 23.20% for k4v3, all six pairs, while
333
- halving the operation's peak temporary allocation from 64 to 32 MiB. It remains
334
- slower at N128 and N2048; for k8v3 the paired medians are +4.08% and +20.43%.
335
- Only a long-context candidate is justified for full-model/request testing.
336
- Evidence: tq-kv-rotation-rows-screen.json and
337
- tq-kv-rotation-rows-repeat{,-review}.json. The baseline layout does not advance.
338
-
339
- Joint decoding also passes the RTN4 full-model counterpart: 18 forward/state/
340
- continuation cases at context128/2048/8192 and four generations are exact, with
341
- 5,536 matching cache calls, one specialization and 1,000,514 final active bytes
342
- per arm. Its first paired generation timings improve, but repeated RTN4 HTTP
343
- acceptance remains. A nonfinite follow-up preserves 960 additional comparisons
344
- across every served bit pair, all head dimensions and scale dtypes, including
345
- NaNs, infinities and arbitrary f32 zero-point fractions. This covers the
346
- reference codec's documented zero-scale/infinite-fp16-zero behavior.
347
-
348
- The MiniCPM5-1B counterpart exercises deferred V rotation: all 20 forward/state
349
- cases, four generations and 7,320 cache calls match. Both arms finish at 524,860
350
- active bytes; the candidate uses one D128 specialization. These are correctness
351
- and first-pair timing gates, not repeated cross-model serving claims. Evidence:
352
- tq-kv-rtn4-full{,-review}.json, tq-kv-nonfinite.json and
353
- tq-kv-minicpm-full{,-review}.json. Gemma D512 and integrated operation/fallback/
354
- lifetime checks follow.
355
-
356
- Gemma-4-e4b's D512 deferred consumer also passes: 20 forward/state cases, four
357
- generations and 1,220 matching cache reads, one specialization and 1,057,864
358
- final active bytes per arm. Evidence: tq-kv-gemma-e4b-full{,-review}.json.
359
-
360
- The joint decoder was initially integrated as an experimental opt-in. The environment
361
- setting and supported inputs are documented in server-config.md. A shared
362
- `src/mlx/turboquant-kv-decode.ts` owns only the packed Metal operation; the existing
363
- codec owns inverse rotation and the cache captures operation selection once.
364
- Request/execution interfaces, quantization and persistence remain unchanged.
365
- The original codec remains the fallback and correctness reference. Five new
366
- operation tests pass 1,102 assertions across served bit combinations, head
367
- dimensions, independent group sizes, nonfinite values, strided storage, fallback
368
- and shapeless-trace behavior, borrowing and exact post-disposal allocation.
369
- All three typechecks pass. With fusion enabled, the existing 26 codec/cache
370
- tests also pass, including growth, trim and mixed-cache persistence. Their
371
- snapshot helpers now release temporary casts and owned state views instead of
372
- letting test-only allocations obscure the lifecycle checks. The integrated
373
- model/HTTP evidence follows; prototype timings above are not automatically
374
- attributed to the production dispatch.
375
-
376
- The integrated R6 gate now preserves all 20 forward/state/continuation cases,
377
- four generations, 4,880 cache reads and 1,016,898 final active bytes per arm.
378
- Passive observation confirms that every enabled read reaches the production
379
- kernel, with one specialization. The full model-free tier passes 1,873 tests
380
- with 10 skips; typechecks and pure hygiene also pass. Evidence:
381
- tq-kv-integrated-full{,-review}.json and tq-kv-integrated-code-checks.json.
382
- The integrated RTN4 counterpart also preserves all 20 forward/state cases,
383
- four generations, 4,880 reads and 1,000,514 final active bytes. Its first-pair
384
- timings are mixed: three complete-generation cells regress 0.44–1.88%, while
385
- the 2,048-token sampled cell improves 4.33%. Exactness alone does not establish
386
- a speed gain. Evidence: tq-kv-integrated-rtn4-full{,-review}.json.
387
-
388
- Six integrated R6 HTTP pairs preserve all 30 response comparisons, call maps,
389
- one candidate specialization and equal post-exit active allocation. Paired
390
- medians for the 58-token prompt are −0.74% complete time and +0.75% decode,
391
- both six wins. At 1,806 prompt tokens they are −3.61% complete time, four wins,
392
- and +10.33% decode, five wins. Long-prompt TTFT is +1.81%, three wins. Both
393
- complete-time losses, +0.55% and +10.95%, remain in the result. This repeat is
394
- noisier than the prototype, with no established TTFT improvement.
395
-
396
- The same run stops after its first RTN4 pair on a 10,944-byte difference in
397
- post-exit active allocation, with less retained in the candidate. All five
398
- responses and the cache call maps match. The original run remains marked
399
- incomplete; the later allocation investigation and revised assessment appear
400
- below. Every child exits
401
- cleanly and all 547 recorded source hashes remain unchanged. Evidence:
402
- tq-kv-integrated-http{,-review}.json. A separate instrumented allocation/GC
403
- diagnostic follows; its timings cannot be compared with ordinary serving.
404
-
405
- The HTTP extension keeps the existing RSS collector and adds the calibrated
406
- native process reader. R6's whole-server sampled physical-footprint maximum
407
- falls in every pair, with a median difference of 2.04 GiB; this includes
408
- startup, warmups and both prompt shapes. Measured-request RSS is nearly flat.
409
- These observations do not identify per-request physical peaks or prove
410
- savings across models. Longer-context, pressure, repeated deferred-model
411
- serving and quiet acceptance remain before any default decision.
412
-
413
- A fresh six-pair RTN4 repeat completes all 60 requests with all 30 response
414
- comparisons and cache call maps exact. Both prompt shapes improve complete
415
- time and decode throughput in every pair. At 58 prompt tokens the paired
416
- medians are −3.07% complete time and +3.35% decode; at 1,806 they are −5.95%
417
- and +15.47%. TTFT medians are about −0.63% in both cells. These use k8v3 KV,
418
- serial execution and 128 generated tokens, without a speculative draft.
419
-
420
- The repeat still fails its exact process-exit allocation gate. The candidate
421
- retains 15,135,029,250 bytes in all six servers; four controls match, while
422
- the last two retain 18,624 and 6,976 fewer bytes. Together with the earlier
423
- smaller candidate observation, this varies in both arms. An array-tracked
424
- diagnostic preserves 1,851 live wrappers and identical allocation before and
425
- after explicit GC, but does not reproduce the variation. It establishes no
426
- GC fix or kernel leak. The lighter observation below resolves the acceptance
427
- metric, while preserving these failed reports. Evidence:
428
- tq-kv-integrated-rtn4-http{,-review}.json and tq-kv-memory{,-review}.json.
429
-
430
- The lighter array observer reproduces a 2,560-byte capacity difference while
431
- both servers retain exactly 1,851 wrappers with matching dtype/shape counts
432
- and logical bytes, before and after GC. This exposes a flaw in the exact-byte
433
- gate: MLX's Metal allocator counts `MTLBuffer.length`, and its cache can reuse
434
- a larger buffer for a smaller request. A controlled native reproduction gives
435
- identical 4,096-byte arrays with either 4,096 or 6,144 active bytes. Clearing
436
- unused buffers preserves that difference; disposing the live array releases
437
- it completely. See the pinned allocator.cpp and buffer_cache.h plus
438
- allocator-capacity-repro.json. The server's individual backing capacities were
439
- not enumerated, so reuse explains the metric's limitation without attributing
440
- every byte. Ownership acceptance uses the matching live-array inventory and
441
- the exact native/cache disposal gates; active capacity remains a reported
442
- measurement. Original failed reports remain unchanged. The revised assessment
443
- is tq-kv-integrated-rtn4-http-acceptance.json.
444
-
445
- The integrated 8K R6 gate also passes all six forward/state/continuation cases
446
- and both 64-token greedy/sampled generations, with 2,960 matching cache reads,
447
- one specialization and equal final allocation. In the first three-arm block,
448
- joint decoding improves complete generation by 8.63%/7.59% versus the original.
449
- Adding row-grouped inverse rotation only at N≥8192 preserves all results and
450
- improves a further 1.25%/0.90% over integrated joint decoding. Its 2,256 rotation
451
- calls exactly match eligibility, with 704 ordinary joint calls. The operation's
452
- lower temporary allocation does not reduce the whole generation's peak further.
453
- These are screening timings; the repeated long-context HTTP result follows. Evidence:
454
- tq-kv-rotation-long{,-review}.json.
455
-
456
- The six-block long-context HTTP repeat completes all 18 fresh servers and 54
457
- requests in all six arm orders. At 8,846 prompt tokens and 128 generated tokens,
458
- joint decoding versus the original codec improves paired-median decode by
459
- 83.87% and complete time by 12.77%. Adding row-grouped inverse rotation improves
460
- a further 5.39% decode and 1.05% complete time over the integrated joint decoder.
461
- Every paired complete-time and decode comparison improves. The incremental
462
- TTFT median is −0.24%, with four of six wins; sampled request RSS is slightly
463
- higher, so this establishes no RSS saving. All response text, usage, finish
464
- reasons, call/eligibility maps and retained capacity match; all children exit
465
- cleanly and all 547 recorded source hashes remain fixed. These are R6/k8v3,
466
- serial, greedy seed42 diagnostics on the M4 Pro, without a draft. They do not
467
- apply to bf16-cache rows. Evidence: tq-kv-rotation-long-http{,-review}.json.
468
-
469
- That result justifies integrating the inverse operation into the same opt-in.
470
- The numeric module `src/mlx/turboquant-kv-inverse.ts` owns a single D256 shader,
471
- with 16 rows per threadgroup, unrolled radix16 butterflies and exact 1/16
472
- normalization. The codec selects it only for the measured eager k8v3, B1/H4,
473
- fp16/group32 regime at N≥8192; other calls retain joint decoding or the original
474
- codec. Packed arrays and codec-table strides are explicit. N changes the grid,
475
- never the shader specialization, and padded rows participate in every barrier.
476
- The updated operation suite passes nine tests and 1,226 assertions, including
477
- threshold/partial-row, nonfinite, strided-table, fallback and ownership checks.
478
- Actual integrated model and serving acceptance against the saved prior joint
479
- codec remain separate from the prototype's timing evidence. The R6 native
480
- integration gate passes twelve forward/state/continuation cases and four
481
- 64-token greedy/sampled generations at contexts 2048/8192. Logits, tokens,
482
- logprobs, complete cache states, prefix snapshots and usage are identical.
483
- The candidate's 2,256 inverse calls match eligibility exactly, with 3,088 joint
484
- calls; both arms release to the same retained allocation. Source hashes remain
485
- fixed and both children exit cleanly. A brief concurrent CPU build prevents
486
- accepting this gate's timing. Evidence:
487
- tq-kv-inverse-integrated-r6-full{,-review}.json.
488
-
489
- The MLX 0.32.2 controls now pass the same integrated model gate on both R6 and
490
- RTN4. Every full logit/state/continuation case and greedy/sampled generation is
491
- exact, with matching call maps, equal final active allocation and clean exits.
492
- The version-specific records are mlx-upgrade-0.32.2/{r6,rtn4}-kv-inverse-full.json.
493
- The integrated serving repeat now completes six usable timing pairs per quant
494
- on the M4 Pro 24 GB, with the same 8,846-token prompt, k8v3, greedy seed42 and
495
- 128 generated tokens. Inverse rotation improves the paired-median HTTP decode
496
- rate by 4.69% on R6 and 5.98% on RTN4; every decode pair improves. Complete
497
- request time improves 0.79% on R6, with all six pairs improving. RTN4's complete
498
- time is inconclusive: its median improves 0.38%, but only three pairs improve
499
- and prefill variation exceeds the incremental saving. Neither result establishes
500
- a general RSS reduction. All 78 responses across the original and replacement
501
- runs match text, usage and finish reason. Call/eligibility maps match, all 26
502
- servers exit cleanly and source/library hashes stay fixed. One original R6
503
- timing pair was excluded after an MLX unit test overlapped its warmup; the
504
- predeclared replacement supplies that pair. These are loaded-machine
505
- diagnostics, not canonical acceptance. Evidence:
506
- mlx-upgrade-0.32.2/inverse-kv-http{,-replacement,-review,-isolation}.json.
507
- Combined pressure and quiet acceptance remain.
508
-
509
- The consolidated 0.32.2 runtime also passes six paired actual HTTP blocks per
510
- MiniCPM5-1B and Gemma4-e4b with the joint decoder off/on. Their deferred value
511
- paths use D128 and D512 respectively. All 120 responses, including warmups,
512
- match in text, usage and finish reason; every call map matches and all 24
513
- servers exit cleanly. Source and native-library hashes remain fixed. Both
514
- models improve complete request time in every measured pair. MiniCPM improves
515
- substantially at both tested prompt lengths; Gemma's benefit is larger on the
516
- longer prompt. Sampled RSS establishes no reduction. The server-exit observer
517
- still sees resident model arrays, so its active capacity is not a disposal-to-
518
- zero test. Native operation and full-model ownership gates remain separate.
519
- These are M4 Pro 24 GB diagnostics with k8v3, greedy seed 42 and 128 generated
520
- tokens. Those measurements used serial placement; shared integration is covered below.
521
- Evidence: mlx-upgrade-0.32.2/deferred-kv-http{,-review}.json. This closes
522
- the deferred-model serving comparison; broader pressure and quiet gates remain.
523
-
524
- Direct packed-key attention is closed as an additional speed candidate. A
525
- research port of MLX 0.31.2's two-pass vector attention replaces each K load
526
- with the existing signed-k8 zero/scale arithmetic and bf16 rounding. It keeps
527
- the native block selection, score reduction, online softmax, bf16 partial
528
- output and final reduction order. The dense source port and packed-key variant
529
- both match all 72 operation cases at D256, one query, GQA 6 and N1024 through
530
- 16384, including group32/64, fp16/bf16/f32 metadata and strided arrays. Every
531
- owned allocation is released. Scope is M4 Pro, no mask or sinks, with eager
532
- V already decoded; this does not cover arbitrary SDPA inputs.
533
-
534
- Six fresh-process repeats then measure the complete eager k8v3 decode plus
535
- attention using actual encoder output. All 72 cells preserve their inputs
536
- and both candidate outputs, with 3,888 timed operations and matching source
537
- hashes. Fixture allocations return to the same warmed codec-table baseline
538
- after every cell. Direct key loads with the earlier fused V decoder improve
539
- over the original operations, but lose against the integrated joint K/V
540
- decoder plus native attention. Paired median regressions are about 14% at
541
- N1024/1025, 19% at N2048, 6% at N8192/8193 and 8% at N16384, for contiguous
542
- and strided caches. All six pairs lose except two noisy N2048 contiguous
543
- cells. Peak temporary allocation falls by the removed bf16 K window, about
544
- 16 MiB at N8192 and 32 MiB at N16384, without a measured whole-model memory
545
- benefit. The initial key-only improvement therefore does not justify a new
546
- model/cache dispatch or production kernel. Evidence: tq-key-sdpa-screen.json
547
- and tq-key-sdpa-complete-repeat{,-review}.json. The pinned source is MLX's
548
- MIT-licensed sdpa_vector.h and scaled_dot_product_attention.cpp under
549
- upstream/mlx-0.31.2; the closed research helpers are removed.
550
-
551
- ## Gates — all passed 2026-07-06 (M1 Max 32 GB)
552
-
553
- 1. **Quantizer parity (bit-exact, the hard gate):** encode indices, scales,
554
- zeros, packed bytes, and dequant outputs match the vendored reference on
555
- golden vectors (head_dim 64/128; configs k8v3/k4v3/k4v2/k8v4/k2v5/k5v8 —
556
- every kBits/vBits value the CLI accepts).
557
- 2. **Math sanity (model-free):** FWHT involution/orthogonality; 3-bit
558
- roundtrip MSE on unit-normal data in the paper's D_mse≈0.03 band.
559
- 3. **Quality-vs-bpw curve (Phase 13 exit criterion)** — MiniCPM5-1B,
560
- teacher-forced serving-decode KL vs bf16, 8 prompts × 128 tokens, 32
561
- decode steps; affine baselines via the same harness:
562
-
563
- | scheme | effective KV bits | mean KL vs bf16 |
564
- |---|---|---|
565
- | bf16 | 16.00 | 0 (control) |
566
- | uniform kv8 (affine g64) | 8.50 | 0.00246 |
567
- | turbo k8v8 | 8.75 | 0.00214 |
568
- | turbo k8v4 | 6.75 | 0.00936 |
569
- | **turbo k8v3 (default)** | **6.25** | **0.0325** |
570
- | turbo k8v2 | 5.75 | 0.175 |
571
- | uniform kv4 (affine g64) | 4.50 | 0.0516 |
572
- | turbo k4v3 | 4.25 | 0.0622 |
573
- | turbo k4v2 | 3.75 | 0.205 |
574
-
575
- Shape reproduces the paper's law: value bits dominate, ~4^-b decay, cliff
576
- at v2. Turbo adds operating points between affine kv8/kv4; the k8v3
577
- default (2.56× KV compression) beats uniform kv4's KL with room to spare.
578
- Live smokes: cpm5 + e4b coherent under turbo:k8v3 (e4b emits the
579
- rotating-layers-stay-bf16 warning). The paper's LongBench numbers were NOT
580
- rerun — the reproduction is shape-level plus the codec-level D_mse anchor.
581
- 4. Whole-repo `tsc --noEmit` = 0; fast suite green; turbo requests route
582
- serial with a clear reason.
583
-
584
- The Phase 18 composition is integrated in the unreleased working tree;
585
- `~/.cache/mlx-bun/turboquant-composition-validation` remains a frozen comparison.
586
- It extracts the existing
587
- encode/decode operations behind a KV codec interface and applies that codec to
588
- one owner of five tensor fields with shared row positions. Merge, retirement,
589
- rollback and extraction operate on encoded bytes. A rotated-value attention
590
- port lets Gemma and MiniCPM consumers retain the existing deferred inverse
591
- rotation with either storage layout.
592
-
593
- On M1 Max and M4 Pro, the focused codec/kernel/row checks pass 29 tests and
594
- 2,828 assertions. A native Qwen target test passes 2,824 assertions on each
595
- machine, comparing retained state and subsequent full logits at the same B=2
596
- shape across unequal accepted prefixes. Existing fused kernel selection is
597
- preserved. The subsequent MLX cache-layout binding now serves ordinary and
598
- Qwen MTP groups through those same encoded rows. Scheduling retains its
599
- method lifecycle; sampling and fused codec selection are unchanged. The
600
- method key and paired-prefix namespace include the TurboQuant scheme.
601
- Temporary extracted-state views use the existing lease interface.
602
-
603
- Fused K8/V3 serving passes on both Macs: MTP2 and MTP4 each prove true B4,
604
- seeded logprobs, mixed grammar, joins and retirement; ordinary tests prove
605
- B1/B2/B3 and immutable RAM donor reuse. Paired RAM and SSD restart tests
606
- preserve target/draft/hidden state and continuations. Full suites pass
607
- 2,078 tests on M1 and 2,082 on M4, with typechecks clear. MTP3 also passes
608
- the M1 native/HTTP gate. On M1, all 21 saved-boundary requests match across
609
- 8 GiB synchronous, 1 GiB synchronous and 1 GiB asynchronous RAM-cache arms,
610
- including full usage and acceptance. Each arm durably flushes all seven
611
- snapshots with no missing, pending, dropped or failed writes. The constrained
612
- arms cause six eviction spills; the async observer confirms 3,264 submissions.
613
- These sequential shared-server pressure checks cause substantial swapping;
614
- B4 correctness is a separate native gate, and no speed or memory-reduction
615
- claim follows. The subsequent M4 combined pressure gate also passes with both asynchronous and blocking submissions exercised; full usage, responses and final persistence match. Current measurements and provenance live in benchmarks.md. This closes the named pressure gate; performance and default selection remain separate.
616
- Shared TurboQuant integration ships in v0.4.0; v0.3.0 retained the earlier
617
- placement limits.
618
- Evidence: `reports/qwen38-closeout/composition-baseline/turboquant-composition-manifest.json`.
619
- Integration evidence: `reports/qwen38-closeout/composition-baseline/turboquant-serving/`.
620
- Broader family checks pass MiniCPM seeded/logprob serving but reproduce a
621
- Gemma e4b/12B failure: attention borrows the row-offset array across a cache
622
- append that releases it. The adopted ownership fix passes seeded/logprob and
623
- prefix checks on both Gemma families, MiniCPM/Qwen prefix controls, and the
624
- complete suites on both Macs. M4 acceptance also passes fused and unfused
625
- Gemma seeded sampling, affine KV4 controls and Qwen MTP3 B4 serving.
626
- MiniCPM prefix checks allow the existing policy to supersede trimmable donors
627
- while proving byte identity and continuation through retirement.
628
-
629
- ### Fused codec default selection
630
-
631
- The unreleased decoder selects packed K/V fusion by default when a caller
632
- chooses TurboQuant. `turboQuantFusedDecode` resolves the runtime policy once;
633
- ordinary storage, shared rows and delayed conversion capture the same value.
634
- Copies and restored rows retain the codec selection through their existing
635
- interfaces. `MLX_BUN_TURBOQUANT_FUSED_DECODE=0` selects the original operations.
636
- The numerical kernels and eligibility rules are unchanged from the accepted
637
- opt-in. TurboQuant quantization itself remains an explicit cache-format choice.
638
- The current shared-serving comparison and combined pressure measurements are
639
- recorded in benchmarks.md; the earlier six-pair timing and native/state gates
640
- above remain the evidence for the fused implementation.
641
-
642
- ## KV-leg limits and non-goals (recorded so they don't creep)
643
-
644
- - Full-attention layers only; rotating/sliding-window layers stay bf16 (warn
645
- once, never throw). Head dims outside {64,128,256,512} refused at server
646
- start.
647
- - Shared ordinary execution supports row-local delayed TurboQuant; Qwen MTP
648
- requires start zero. Delayed affine conversion and paged-KV combinations
649
- remain unsupported.
650
- - No fused quantized-SDPA Metal kernel (remaining fetch cost is
651
- unpack+gather); no QJL residual stage; no entropy coding (the paper
652
- declined it too).
653
- - Strict legacy serial speculation and draft providers without grouped TQ
654
- support retain their existing exclusions. A shared server with one active
655
- row is the TQ/MTP B1 path.
656
- - No speed claims: v1 dequant-on-fetch is expected slower per step at long
657
- context; this ships as a memory/context feature like uniform KV. Admission
658
- still bills turbo as bf16 (server-config.md says so).
659
-
660
- ---
661
-
662
- # Part B — Weights leg (rotation-folded quantization)
663
-
664
- ## What it is
665
-
666
- Fold an orthogonal rotation R offline into producer/consumer weight pairs so
667
- every weight matrix is quantized in a rotated basis where outlier channels
668
- are smeared into near-Gaussian marginals — then quantize with mlx's EXISTING
669
- formats (affine / mxfp4 / nvfp4). Zero runtime cost, zero new kernels,
670
- output loadable by stock mlx-lm. The QuaRot/SpinQuant family; composes with
671
- (does not replace) per-layer allocation (OptiQ-style) and calibration.
672
-
673
- Target: the best-possible Qwen3.8-27B (+ MTP companion) on our hardware,
674
- beating OptiQ-4bit / plain 4bit at equal effective bpw (gate: ppl + frozen
675
- 6-task eval, eval DB rows, per-bpw-band comparisons).
676
-
677
- Why weights differ from KV (the 2026-07-06 framing that opened the leg):
678
- - Weights win on one axis: the rotation FOLDS into adjacent matrices offline
679
- (R into one layer, Rᵀ into the next) — no online transform at all.
680
- - Weights lose on the other: they are static, so calibration-aware methods
681
- (GPTQ/AWQ/imatrix, optiq sensitivity maps) are admissible and set a higher
682
- baseline than any calibration-free scheme — the win to chase is rotation
683
- COMPOSED WITH calibration/allocation, not instead of it.
684
- - A Lloyd-Max weight FORMAT needs custom quantized-matmul kernels — the 26B
685
- gather-qmv shelving (dispatch fixed-cost ate the prize) is the precedent.
686
- Folding into mlx's existing affine format needs none.
687
- - Activation quant (W4A4) is mispriced on this hardware (no int4 tensor
688
- cores, decode is weight-bandwidth-bound; docs/design/orpo-training.md).
689
-
690
- ## Oracle chain
691
-
692
- Folding mechanics come from the reference repos (read 2026-08-17, full-file
693
- agent reads):
694
-
695
- - **QuaRot** (arXiv:2404.00456, github spcl/QuaRot):
696
- `fake_quant/rotation_utils.py` (fuse_ln_linear, fuse_layer_norms,
697
- rotate_model), `fake_quant/hadamard_utils.py` (get_hadK, matmul_hadU,
698
- random_hadamard_matrix), `fake_quant/model_utils.py`.
699
- - **SpinQuant** (arXiv:2405.16406, github facebookresearch/SpinQuant):
700
- `utils/fuse_norm_utils.py` (a copy of QuaRot's γ-fold),
701
- `eval_utils/rotation_utils.py` (R1/R2 folds), `optimize_rotation.py`
702
- (Cayley-SGD learned R — deferred to W5-learned).
703
- - **GPTQ**: `mlx_lm/quant/gptq.py` in the pinned venv (forked minimally in
704
- `scripts/turboquant/tq-gptq.py`; see the two upstream defects below).
705
- - **Sensitivity**: `mlx_lm.quant.dynamic_quant` (gradient KL) + OptiQ's
706
- published `optiq/sensitivity.json` for this exact 27B (`sensitivities[b]`
707
- = measured KL GAIN at b bits — the first read had the sign flipped).
708
-
709
- Weight layout: torch and MLX `nn.Linear` are both `[out, in]`, `y = x @ W.T`
710
- — their fold table transfers verbatim.
711
-
712
- ## The recipe (weight-only, fully offline)
713
-
714
- Order matters: γ-fold FIRST (R1 commutes only with gain-free RMSNorm), then
715
- R1, then R2, then quantize.
716
-
717
- **0. Untie embeddings** if `tie_word_embeddings` (clone into a separate
718
- lm_head, set the flag false). Required: step 1 transforms lm_head but not
719
- embed_tokens (SpinQuant `ptq.py` does exactly this).
720
-
721
- **1. γ-fold (norm fusion)** — for each RMSNorm feeding linears,
722
- `W' = W · diag(γ)` on the INPUT dim, then set that norm's γ to ones (keep the
723
- module + its eps — do NOT copy QuaRot's replacement RMSN, which hardcodes
724
- eps=1e-5; our subjects use 1e-6):
725
- - input_layernorm → q/k/v_proj
726
- - post_attention_layernorm → gate/up_proj
727
- - final norm → lm_head
728
-
729
- **2. R1 residual fold** — one hidden-size orthogonal R1:
730
-
731
- | matrix | transform | reason |
732
- |---|---|---|
733
- | embed_tokens | `W @ R1` | writes residual (rows are embeddings) |
734
- | q/k/v_proj | `W @ R1` | reads residual (input dim) |
735
- | o_proj (+bias) | `R1ᵀ @ W` | writes residual (output dim) |
736
- | gate/up_proj | `W @ R1` | reads residual |
737
- | down_proj (+bias) | `R1ᵀ @ W` | writes residual |
738
- | lm_head | `W @ R1` | reads residual |
739
-
740
- Q/K outputs untouched → RoPE unaffected. Input-side folds never touch biases
741
- (bias lives on the output).
742
-
743
- **3. R2 per-head v/o fold — SpinQuant's version, NOT QuaRot's.** Per layer,
744
- one head_dim-sized orthogonal R2 applied block-diagonally: v_proj output
745
- blocks get R2ᵀ, o_proj input blocks get R2; softmax weights are R2-invariant
746
- so it cancels exactly, incl. under GQA (same R2 for all heads; repeat_kv
747
- replicates whole heads). QuaRot's variant folds a FULL Hadamard into o_proj
748
- and needs an ONLINE cross-head Hadamard (`online_partial_had`) to cancel —
749
- folding its v-side alone breaks the network. Skip QuaRot's pairing entirely.
750
-
751
- **4. Quantize** the folded weights with the stock convert path (affine g64 /
752
- mxfp4 / nvfp4 arms; only affine has been measured — see W3).
753
-
754
- ### Deviations from the references (decided, with reasons)
755
-
756
- These are the strings persisted per artifact in `optiq_metadata.json`
757
- `weight_transforms[].deviations` (`src/quantize/rotate.ts`).
758
-
759
- - **No embedding mean-centering.** Their `fuse_layer_norms` mean-centers
760
- embedding rows (SliceGPT LayerNorm→RMSNorm trick). For RMSNorm models this
761
- is NOT an exact invariance — they do it anyway; we don't, because W0's exit
762
- criterion is logit parity of the folded bf16 model.
763
- - **Delete the hidden R4 half-fold.** BOTH repos' `rotate_mlp_output`
764
- unconditionally applies a full Hadamard to down_proj's input dim right
765
- after the R1ᵀ fold — the offline HALF of R4, which requires the runtime
766
- `online_full_had` on down_proj's activation (QuaRot rotation_utils.py:173 /
767
- SpinQuant eval_utils/rotation_utils.py 98-100). Weight-only must skip both
768
- halves. The `R1ᵀ @ W_down` part stays.
769
- - **No R3.** Post-RoPE Q/K rotation exists only for KV-cache quant (their
770
- code registers it only when k_bits < 16). Our KV story is Part A — online
771
- rotation remains KV-only.
772
- - **γ kept in the module as ones (eps preserved).**
773
- - **Fold precision: fp32, not fp64.** References fold in fp64 (fp16-era
774
- caution). Our weights are bf16 (8-bit mantissa); fp32 accumulation at
775
- n≲6k leaves ample headroom. Escape hatch if a parity gate fails: fold
776
- goldens in the oracle venv (mlx CPU float64).
777
-
778
- ### R generation
779
-
780
- - Random-Hadamard R1 = `diag(±1 signs) · H_n / √n` (QuIP#-style). Signs are
781
- a seed-pinned splitmix32 stream (`signVector(seed, n, lane)`; R1 = lane 0,
782
- layer i's R2 = lane i+1) so the same (seed, n, lane) yields the same signs
783
- on every machine. R is never needed at runtime; provenance (transform id,
784
- family, seed, deviations) is written to `optiq_metadata.json`.
785
- - Supported n: the Llama adapter asserts power-of-two hidden and head dims;
786
- the Qwen adapter accepts `n = m·2^k, m ∈ {1,12,20,28}` — what mlx's
787
- `hadamard_transform` takes natively (verified live at 5120 = 20·256). The
788
- references' Kronecker table for other K values is NOT implemented; callers
789
- get a clear throw. (QR-of-Gaussian "random" mode from the references is
790
- likewise not implemented.)
791
- - R2 default: plain signed Hadamard of head_dim (must be pow-2).
792
- - Learned R (SpinQuant Cayley-SGD R1 + per-layer R2) stays deferred until a
793
- random-R recipe wins on task evals; it folds identically afterward.
794
-
795
- ## Implementation seam (verified 2026-08-23)
796
-
797
- `src/quantize/weight-transform.ts` separates pure tensor-name planning from
798
- lazy tensor application:
799
- - `WeightTransform { id, plan(names, config), createContext(weights, plan) }`;
800
- `plan()` is name/config analysis only (no arrays, no device work);
801
- `WeightTransformContext.apply(outputName, source)` returns a lazy owned
802
- array and never disposes `source`.
803
- - `WeightTransformPlan.sourceByOutput` makes untie/clone explicit (a
804
- synthesized `lm_head.weight` maps to `model.embed_tokens.weight`).
805
- - Adapters: `llamaWeightTransform` (`rotation.llama`), `qwen35WeightTransform`
806
- (`rotation.qwen3_5`), `qwenMtpWeightTransform` (`rotation.qwen3_5_mtp`), and
807
- `automaticRotationWeightTransform` (`rotation.auto`) which selects by
808
- schema: MTP if `fc.weight` + `pre_fc_norm_hidden.weight` are present, else
809
- by `model_type` ∈ {qwen3_5, llama}, else throws.
810
- - Fold math lives in `src/quantize/rotate.ts` (`foldLlamaWeights`,
811
- `planQwen35Fold`, `planQwenMtpFold`, `QwenFoldContext`; f32 chains → bf16;
812
- every returned array is a lazy graph over the source mmap so the writer
813
- materializes one tensor at a time).
814
- - `src/quantize/quantizer.ts` `quantizeModelDir` applies the plan in its
815
- existing module walk; refuses a transform when the source is already
816
- quantized ("requires full-precision source weights"); writes
817
- `weight_transforms` into both the uniform and the mixed-precision
818
- `optiq_metadata.json`. Mixed-precision calibration receives a
819
- `ProbeSource`; the default builds an 8-bit probe through the lower-level
820
- writer instead of recursively re-entering the top-level quantizer.
821
- - CLI: `mlx-bun convert --rotate-weights [--rotation-seed N]` (default seed
822
- 42; cli.md documents it). An MTP companion must be folded with the same
823
- seed as its trunk.
824
- - Tests: `tests/weight-transform-plan.test.ts`,
825
- `tests/weight-transform-numerics.test.ts`.
826
-
827
- Src-vs-doc note: the production Llama adapter currently REQUIRES tied
828
- embeddings (`planLlamaWeightTransform` throws if `lm_head.weight` exists) —
829
- the "untie if tied" recipe step is exercised only in that direction; an
830
- untied Llama source is not yet accepted. The Qwen adapter handles both.
831
-
832
- ## W1 — Qwen3.8 (qwen3_5) corridor map (2026-08-18, from `src/model/qwen3_5.ts` + `src/spec/qwen-mtp-source.ts` + `src/vision/qwen3vl-tower.ts` + tensor dumps)
833
-
834
- **R2 is architecturally OFF for this family:** full attention computes
835
- `o_proj(attention_output · σ(gate))` — q_proj emits 2×head_dim per head and
836
- the gate multiplies the attention output ELEMENTWISE in head space. An
837
- elementwise gate does not commute with a per-head rotation, so only γ+R1
838
- apply. hidden 5120 = 20·256 — mlx's hadamard_transform takes it natively.
839
-
840
- Trunk corridors (prefix `language_model.`):
841
- - readers (@R1 input dim, γ folded in): self_attn.q/k/v_proj,
842
- linear_attn.in_proj_{qkv,z,b,a}, mlp.gate/up_proj, lm_head (γ = model.norm)
843
- - writers (R1ᵀ output dim): self_attn.o_proj, linear_attn.out_proj,
844
- mlp.down_proj
845
- - vision: `vision_tower.merger.linear_fc2` weight+bias is the ONLY
846
- vision→residual seam (deepstack is empty for qwen3_5 and not ported) —
847
- output-dim fold; everything else in the tower passes through bf16
848
- - untouched internal bases: q_norm/k_norm (head-space), linear_attn.{norm,
849
- A_log, conv1d, dt_bias} (post-projection), rotary
850
- - 27B trunk is untied; the 0.8B proof subject is tied (untie step exercised)
851
-
852
- MTP companion (separate artifact, same seed/R1 — shared residual basis):
853
- - `fc [H,2H]`: input block 0 = embedding stream (γ = pre_fc_norm_embedding),
854
- block 1 = hidden stream (γ = pre_fc_norm_hidden) — per-block γ+@R1 — plus
855
- an output-dim R1ᵀ fold; both pre-fc norms → ones
856
- - `layers.0`: standard full-attention corridor treatment
857
- - **final `norm` γ is DROPPED (→ ones):** it feeds the SHARED trunk lm_head,
858
- which already carries the trunk's final γ. Draft logits see γ_trunk instead
859
- of γ_mtp — draft-quality-only (the verified target path is exact); revisit
860
- lever = ship a private folded head inside the companion. Persisted as the
861
- `mtp-final-gamma-dropped` deviation.
862
-
863
- Small-scale proof (0.8B, dequantized from OptiQ-4bit since no bf16 is
864
- published; fold-parity on dequant-vs-folded-dequant tests the fold exactly):
865
- teacher-forced logits through STOCK mlx-lm (also the W2 cross-stack check) —
866
- worst per-position KL 0.00353, argmax flips 2/42 positions BOTH at reference
867
- margin 0.0 (exact ties). Scripts: `scripts/turboquant/dequant-model.ts`,
868
- `scripts/turboquant/fold-qwen35.ts`, `scripts/turboquant/tq-fold-parity.py`.
869
-
870
- Quantization packaging (corrected 2026-08-18: OptiQ does NOT fully strip
871
- vision — its main weights omit it but `optiq/optiq_vision.safetensors`
872
- carries it, and `optiq/mtp.safetensors` bundles MTP; their artifact also
873
- publishes `optiq/sensitivity.json`. No kv_config.json is published.) Our
874
- packaging: language modules quantize uniformly (embed + lm_head included),
875
- `vision_tower.*` is predicate-excluded and stays bf16 both IN-MAIN (mlx-vlm
876
- compatible — OptiQ's sidecar-only vision is not) and as the `optiq/` sidecar
877
- (`scripts/turboquant/tq-make-vision-sidecar.ts`), so one self-contained
878
- artifact serves text+vision across stacks; the folded MTP companion ships at
879
- `<model>/mtp/` (engine: `--draft-kind mtp` with no `--draft-model` resolves
880
- it).
881
-
882
- ## Subject models
883
-
884
- - **W0/W3: mlx-community/Llama-3.2-1B-Instruct-bf16** (~2.5 GB; the
885
- reference repos' literal target family; TIED embeddings → exercises step
886
- 0; hidden 2048 / head_dim 64, both pow-2). MiniCPM5-1B is the alternate
887
- subject (no published mlx bf16; geometry fold-friendly: untied, head_dim
888
- 128, hidden 1536 = had12 ⊗ H128, eps 1e-6).
889
- - **W4: mlx-community/Qwen3.8-27B-bf16** (11 shards, 54.7 GB) +
890
- `Qwen3.8-27B-MTP-bf16` companion (~850 MB). The companion shares the
891
- trunk's residual basis → must fold consistently (W1 decision). 27B bf16
892
- never fully loads on either laptop: folding bit-identity is proven at W0
893
- scale plus per-tensor checks; the 27B only ever RUNS folded-and-quantized.
894
- Streaming fold/quantize (`ShardedWriter` + `Weights.releaseShard`; fold
895
- peak 17.9 GB after the naive whole-list path OOM'd a 51 GB model).
896
-
897
- ## W0 fold proof (2026-08-17, Llama-3.2-1B, M1 Max 32 GB, busy box — correctness only)
898
-
899
- Folded model loads + generates through the UNMODIFIED engine
900
- (UniversalDenseModel path); teacher-forced two-model KL (16×256 tok) mean
901
- 0.00131 / median 0.00119 / p95 0.00287 — below the KV curve's
902
- quality-neutral kv8 yardstick (0.00246); greedy 64-token trajectories 3/6
903
- token-identical, 3 diverge only at near-ties (margins 0.0/0.125/0.125);
904
- folded weights fully re-expressed (mean|Δ|≈mean|w|), per-tensor max|w| down
905
- 3–5× (q_proj 0.676→0.162, down_proj 0.578→0.110, gate 0.965→0.367), down_proj
906
- excess kurtosis 1.19→0.22. Runner: `scripts/turboquant/w0-fold-llama.ts`
907
- (`--skip-r1/--skip-r2` bisection arms + `turboquant_fold.json` sidecar).
908
-
909
- ## W3/W4 measured curve (2026-08-18, RTN affine g64, ppl via stock mlx-lm on the local UF-derived corpus, seq 512; M1 Max 32 GB)
910
-
911
- **Headline: rotation-only + RTN does NOT beat plain RTN at the 4-bit
912
- operating point; it wins decisively at 3-bit — the paper's law, reproduced.**
913
- Per-module function-space Frobenius error is a wash at 4-bit (~0.091 all
914
- arms, `scripts/turboquant/tq-quant-error.py` — γs are tame, 0.7–2.7, no
915
- module class is the culprit); the 4-bit regression is the anisotropy story
916
- (isotropic rotated error vs activation-aligned plain error), which is what
917
- GPTQ-style calibration fixes — the composition named as the real win.
918
-
919
- 0.8B lab (dequant-OptiQ source; PAIRED arms; bf16 anchor 6.41, 48×512):
920
-
921
- | arm | bpw | ppl |
922
- |---|---|---|
923
- | plain 4-bit | 4.50 | 7.01 |
924
- | TQ(R1+γ) 4-bit | 4.50 | 7.39 ← regression, reproduces 27B |
925
- | plain 3-bit | 3.50 | 19.19 ← RTN collapse |
926
- | **TQ 3-bit** | 3.50 | **14.54** ← rotation −24% ppl |
927
- | plain mixed (3-bit MLP, 4-bit attn/embed) | 4.15 | 9.69 |
928
- | **TQ mixed (same profile)** | 4.24 | **9.22** ← paired rotation win |
929
-
930
- 27B (32×512, same corpus): plain 4-bit 4.659 ±0.093 (4.50 bpw, 15.0 GB) ·
931
- TQ 4-bit 4.923 ±0.102 (+5.7%, consistent with the lab) · **TQ-mixed (4-bit
932
- attn/embed + 3-bit MLP) 4.932 ±0.098 at 3.86 bpw / 13.9 GB** — matches
933
- rotated-uniform-4-bit quality at −0.64 bpw; the artifact of record for the
934
- 14z M4-Pro fit lever.
935
-
936
- AWQ-style equalization spike (norm-carried per-channel scales, α=0.5,
937
- function-preservation verified at KL 0.0037/0 flips): TQ+eq 7.363 (≈no
938
- change), plain+eq 7.809 (HURT — per-channel scales inside a g64 group widen
939
- group ranges; real AWQ grid-searches a far gentler α and the real 4-bit fix
940
- is GPTQ-style compensated rounding). Scripts kept:
941
- `scripts/turboquant/tq-collect-actstats.py` + `tq-equalize.ts`.
942
-
943
- **End-to-end validation of the TQ-mixed 27B artifact (2026-08-18, M1 Max,
944
- busy box — correctness only):** server chat with correct arithmetic
945
- reasoning (thinking → `reasoning` field); vision through the folded merger +
946
- sidecar correctly identifies the gradient fixture's colors over HTTP; MTP
947
- via the 14g harness with the same-seed folded companion: 71% acceptance,
948
- 2.40 tok/target-forward, arms token-identical (losslessness), ON/OFF 0.726×
949
- (consistent with the stock 0.821× correct-but-slower verdict; MTP stays
950
- opt-in).
951
-
952
- Consequence for the release recipe: do NOT ship rotated uniform-4-bit (loses
953
- to the trivial baseline); rotation's band is the ≤4-bpw mixed recipe where
954
- it is decisively ahead. The 4.5-bpw flagship win waits for the calibration
955
- composition (W5).
956
-
957
- ## W5a corrected-GPTQ matrix (2026-08-18; 0.8B lab, 4.5 bpw arms, 48×512 ppl, anchor = dequant-OptiQ 6.41 — verified lossless: original OptiQ scores 6.4077)
958
-
959
- mlx-lm's shipped GPTQ (`mlx_lm/quant/gptq.py`) has TWO real defects that
960
- partially cancel: the in-loop update window is `k:k+j` (over-propagates past
961
- the block edge; must be `k:j` — the k term itself writes the quantized value
962
- since e·Hinv[k,k] = w−q) and `err[..., k:k+1]` indexes a group-local buffer
963
- with the GLOBAL k (mlx out-of-range slice assignment silently no-ops →
964
- cross-group propagation lost after block 0). Fixing only err
965
- DOUBLE-compensates [j, k+j) and REGRESSES below RTN (measured: 7.22/7.50);
966
- fixing both = paper GPTQ. [mlx-lm #1878](https://github.com/ml-explore/mlx-lm/issues/1878) contains the CPU-only reproduction, observed results against mlx-lm 0.31.3 and upstream `e5962529`, and proposed two-line correction; [mlx-lm PR #1880](https://github.com/ml-explore/mlx-lm/pull/1880) carries the fix plus `tests/test_gptq.py` (column-by-column reference, four groups fail on `main`, single-group control passes on both). Fork:
967
- `scripts/turboquant/tq-gptq.py` (also restricts GPTQ+fallback to language
968
- modules — vision H is a zero scalar and stays bf16).
969
-
970
- | arm | ppl |
971
- |---|---|
972
- | **plain + GPTQ (fixed)** | **6.741** |
973
- | TQ(R1) + GPTQ (fixed) | 6.847 |
974
- | plain RTN | 7.010 |
975
- | TQ RTN | 7.390 |
976
-
977
- **Verdict: calibration is the main course; rotation SUBTRACTS at the 4-bit
978
- band even under GPTQ on this family** (gap −1.6%; GPTQ closes half the
979
- RTN→anchor gap). Rotation remains the sub-4-bpw lever (−24% at 3-bit). 27B
980
- needs a chunked Hessian/GPTQ driver (stock flow = whole bf16 model + all
981
- Hessians resident; down_proj H = 1.2 GB f32 each) —
982
- `scripts/turboquant/tq-gptq-27b.py` (per-layer checkpoints, resumable, peak
983
- ≈ one bf16 layer + one Hessian + activations ≈ 6 GB).
984
-
985
- ## W5c 27B production results (2026-08-18)
986
-
987
- **v2 run (uniform GPTQ-4): BROKEN artifact (ppl 306k).** Root cause,
988
- evidence-backed: the compensation loop DIVERGED on layers with
989
- rank-deficient calibration Hessians (layer-0 down_proj group scales grew
990
- 0.003 → 27 monotonically across columns, max 2.8e7; cosine ~0 vs source;
991
- neighbors healthy). Early layers see low-rank activations (layer-0 input =
992
- raw embeddings; rank ≤ distinct calibration tokens), so 5120 dims outran
993
- the standard 1% damping — the 0.8B (1024 dims) never hit it.
994
-
995
- **v3 fixes (all landed in the 27B driver):** divergence guard in
996
- `gptq_one_guarded` (GPTQ scales vs 4× the RTN scale ceiling per matrix;
997
- damping escalation 1e-2→10; RTN fallback = never worse than RTN); 4×
998
- calibration (128×512); sensitivity-driven per-module bits from OptiQ's
999
- published sensitivity.json; greedy benefit-per-param to `--target-bpw`.
1000
- v3 27B: 169 modules @8-bit, 4.80 bpw, 17.0 GB, ZERO guard triggers (the
1001
- calibration bump fixed conditioning outright), 64 layers in 166 min.
1002
-
1003
- **27B ppl ladder (73×512, UF corpus, stock mlx-lm):** plain RTN-4 4.570
1004
- ±0.060 · OptiQ 5.14 bpw 4.574 ±0.061 · GPTQ+sens 4.80 bpw 4.618 ±0.061.
1005
- **At 27B every sane ≥4.5-bpw recipe SATURATES this instrument** — OptiQ's
1006
- +0.6 bpw buys nothing measurable, and GPTQ shows a small consistent deficit
1007
- (likely calibration-domain mismatch: calibration_v5 vs chat-flavored eval
1008
- text). This contradicts the 0.8B lab ordering (GPTQ clearly won there) —
1009
- quantization robustness grows with scale. Decision moved to task
1010
- benchmarks: MMLU-100 + GSM8K-50 across the arms (`scripts/turboquant/
1011
- tq-evals.py`, paired items through stock mlx-lm).
1012
-
1013
- ## FINAL BOARD + DECISION (2026-08-18 night 2)
1014
-
1015
- Task evals (lean mlx-lm runner, paired items; in-engine sweep swap-thrashed
1016
- the box — 73 GB swap at 0.7 GB resident — killed, gap recorded below):
1017
-
1018
- | arm | bpw | GB | ppl(73×512) | MMLU-100 | GSM8K-50 |
1019
- |---|---|---|---|---|---|
1020
- | **GPTQ+sens v3 (SHIPPED as mjriii/Qwen3.8-27B)** | 4.80 | 16.3 | 4.618 | 87 | **96** |
1021
- | plain RTN 4-bit | 4.50 | 15.0 | **4.570** | 88 | 94 |
1022
- | OptiQ published | 5.14 | 18.1 | 4.574 | **89** | 92 |
1023
- | TQ-mixed (staged, small-footprint variant) | 3.86 | 13.0 | 4.93 | 82 | 96 |
1024
-
1025
- All ≥4.5-bpw arms statistically tied on every instrument — 27B quality
1026
- SATURATES at 4-bit; recipes differentiate below 4 bpw and on completeness.
1027
- THE artifact = v3 (never trails; protective recipe; one-repo
1028
- vision+video+MTP; additive to the ecosystem where plain-4bit already exists
1029
- publicly). Serve gauntlet on THE artifact through OUR engine: text ✓
1030
- (23×19), image ✓ ("Green and pink"), video ✓ (gradient motion described;
1031
- AVFoundation chain), MTP harness 76% accept / 2.53 tok-per-forward with an
1032
- output-divergence flag vs plain greedy (consistent with verify-width
1033
- reduction-order near-ties, 12B step-0 class — margin analysis queued; NOT
1034
- claimed lossless on the card).
1035
-
1036
- ## Territory-mapping campaign (2026-08-18/19, Josh-directed: "map all the levers before concluding TQ-off")
1037
-
1038
- **sens3 arm (Josh's recipe: rotated 3-bit base + sensitivity-driven 8-bit,
1039
- 4.26 bpw / 15.25 GB incl. vision):** ppl 4.630 ±0.058 — TIED with the
1040
- 4.80-bpw flagship (4.618) at −0.54 bpw, and a full recovery over unprotected
1041
- TQ-mixed (4.93). GSM8K 46/50 = 92% (plateau band). **MMLU 83/100 — the
1042
- 3-bit-base dip persists** (TQ-mixed scored 82): two independent 3-bit-base
1043
- arms at 82–83 vs the 87–89 plateau → the knowledge-recall damage is SMEARED
1044
- across the MLP long tail; KL-derived sensitivity shields fluency, not
1045
- recall.
1046
-
1047
- Perplexity proxy calibration (from our own table): deltas <~0.1 ppl are
1048
- task-invisible; ppl's remaining role is catastrophe detection + screening
1049
- (see the g128 lesson below, which retired the "~0.3 ppl = visible damage"
1050
- rule). mlx kernel bound: group_size ∈ {32, 64, 128} — 256+ needs custom
1051
- kernels (non-goal).
1052
-
1053
- **Group-size lab (0.8B ppl) + 27B g128 arm:** rotation does NOT buy
1054
- coarse-group tolerance at 4-bit (tax +4.7% rotated vs +4.2% plain); at 3-bit
1055
- the dividend is real but partial (+29% vs +47%; rotated 3.25 bpw ≈ plain 3.5
1056
- bpw). 27B plain-4bit-g128 (4.25 bpw): ppl 4.714 (+3%), MMLU 88 (plateau!),
1057
- **GSM8K 62% — COLLAPSE via generation-behavior damage** (correct-but-rambling
1058
- truncations + instant-EOS empty outputs; single-forward instruments blind to
1059
- it). Lessons: (1) ppl deltas DO NOT bound task damage (+0.14 ppl ↔ −32 GSM8K
1060
- pts) — every finalist needs generative tasks; (2) g128 disqualified for
1061
- generative work.
1062
-
1063
- **Run B — the full suite (rotation + GPTQ + sensitivity, 4.80 bpw, 17.0 GB,
1064
- zero guard triggers):** ppl **4.5965** (best quantized arm, tied w/
1065
- plain-4bit) · MMLU 84 · raw-completion GSM8K **24% — and the collapse is a
1066
- FORMAT CLIFF, not a reasoning failure**: when it answers it is flawless, but
1067
- 3/4 raw few-shot prompts get INSTANT EOS; under the native chat template it
1068
- always answers (3/5 correct at a tight token cap). g128's 62% was the same
1069
- failure at lower frequency. **Methodology consequence: the raw-completion
1070
- GSM8K column conflates math ability with EOS-cliff robustness** — different
1071
- quant-noise realizations displace a razor-thin answer-vs-stop margin at
1072
- token 0. The map carries TWO generative columns: templated GSM8K
1073
- (serving-path reasoning) and raw-completion GSM8K (format-robustness probe).
1074
- Neither ppl nor MMLU sees any of this.
1075
-
1076
- ## THE FRONTIER (campaign complete, 2026-08-19; chart artifact `reports/frontier-map-2026-08-19.html` is machine-local — `reports/` is gitignored)
1077
-
1078
- | arm | bpw | GB | ppl | MMLU | tGSM | rawGSM | tok/s* | Pareto |
1079
- |---|---|---|---|---|---|---|---|---|
1080
- | **rot+sens48 RTN (Josh's recipe)** | 4.79 | 17.0 | 4.680 | **90** | 94 | 84 | **11.80** | **YES** |
1081
- | GPTQ+sens (staged flagship) | 4.80 | 17.0 | 4.618 | 87 | 94 | **96** | 11.42 | — |
1082
- | rot+GPTQ+sens (full suite) | 4.80 | 17.0 | **4.597** | 84 | 94 | 24 | 11.77 | — |
1083
- | OptiQ published | 5.14 | 18.1 | 4.574 | 89 | 94 | 92 | 8.92 | — (dominated) |
1084
- | **TQ-mixed** | 3.86 | 13.0 | 4.932 | 82 | 82 | 96 | 10.94 | **YES** |
1085
- | bf16 ceiling (streamed eval, `tq-bf16-ceiling.py`) | 16 | 54.4 | 4.552 | 87 | n/a | n/a | n/a | ref |
1086
-
1087
- *M1 Max 32 GB, busy box, spreads 8–34% — directional until a quiet
1088
- `scripts/bench-serve.ts all` run (probes: `scripts/turboquant/tq-tps.ts`).
1089
-
1090
- Findings of record: (1) the ≥4.5-bpw band sits AT the bf16 ceiling (ppl
1091
- within ~1%, MMLU within noise — a quant scoring 90 vs ceiling 87 proves ±3
1092
- noise); (2) BOTH Pareto points are ROTATED — rotation at 4-bit is
1093
- competitive exactly when paired with sensitivity allocation (the earlier
1094
- uniform-rotation loss concentrated in the sensitive modules, as Josh
1095
- hypothesized), and mandatory below 4 bpw; (3) OptiQ is dominated on all
1096
- three axes (its extra 0.34 bpw buys nothing and costs ~25% decode); (4)
1097
- GPTQ's measurable 27B contribution is ppl-only — it buys no task quality at
1098
- this scale and (with rotation) costs raw-format robustness; (5) 3-bit
1099
- kernels pay an unpack tax that eats their bandwidth win on M1 (see the M4
1100
- row for the reversal); (6) cross-engine parity CERTIFIED (byte-identical
1101
- greedy, ours vs stock mlx-lm, on the staged flagship). Certification
1102
- benchmark for the chosen artifact: GPQA Diamond at reasoning_effort=xhigh
1103
- (`scripts/turboquant/tq-gpqa.py`, local mlx-lm or `--server-url` through a
1104
- running `mlx-bun serve`; greedy runs bit-identical across the two paths).
1105
-
1106
- ## M4 Pro 24 GB speed rows (2026-08-20, mlx-bun, `scripts/turboquant/tq-speed-row.ts`)
1107
-
1108
- Winner artifact (rot+sens48), second reference machine (M4 Pro, 24 GB,
1109
- ~273 GB/s), `sysctl iogpu.wired_limit_mb=21504`, DeltaNet leak fix applied:
1110
-
1111
- | prompt | prefill tok/s | TTFT | decode tok/s | notes |
1112
- |---|---|---|---|---|
1113
- | 1,024 | 127 | 8.1 s | 14.66 (1.1%) | chunk 2048 |
1114
- | 8,192 | 124 | 66 s | 14.13 (1.3%) | chunk 2048 |
1115
- | 32,768 | 114 | 288 s | 12.77 | chunk 1024 (peak 19.3 GB) |
1116
-
1117
- - **Compute-bound decode confirmed cross-machine:** 14.7 tok/s here vs 11.8
1118
- on the M1 Max (400 GB/s) — the machine with 68% of the bandwidth is 25%
1119
- FASTER. Decode is dequant-ALU-bound, not weight-streaming-bound (M1
1120
- telemetry: GPU 100% @ ~266 GB/s of 400). Headroom to the ~24 tok/s
1121
- bandwidth roofline is a future perf program.
1122
- - **Decode-at-depth is nearly flat** (−13% at 32× context): only 16 of 64
1123
- layers grow KV; DeltaNet state is constant.
1124
- - **Prefill transient scales with chunk × offset** (~2.8 GB at 24k with
1125
- 2048-chunks; measured via `MLX_BUN_PREFILL_MEM_LOG` and
1126
- `scripts/turboquant/tq-mem-probe.ts`): on 24 GB the 32k row needs
1127
- 1024-token chunks (−8% prefill). Engine follow-up: serve should scale
1128
- prefillChunkSize from fit.ts headroom automatically.
1129
- - Prefill absolute rate (~125 tok/s) is the weak axis — suspected DeltaNet
1130
- per-token recurrence during prefill; compare against mlx-lm same-box
1131
- before treating as our bug (oracle-gap rule).
1132
-
1133
- Compact sibling (TQ-mixed) on the M4, same protocol, chunk 1024 all rows:
1134
-
1135
- | prompt | prefill tok/s | TTFT | decode tok/s (spread) |
1136
- |---|---|---|---|
1137
- | 1,024 | 117 | 8.8 s | **17.14** (0.7%) |
1138
- | 8,192 | 124 | 66 s | 16.05 (2.4%) |
1139
- | 32,768 | 85 | 6.4 min | 13.80 (2.9%) |
1140
-
1141
- **The 3-bit speed verdict is GPU-generation-dependent:** on M1 Max the
1142
- 3-bit-heavy artifact decoded SLOWER than the 4/8 winner (10.94 vs 11.80 —
1143
- unpack ALU dominates); on M4 Pro it decodes FASTER (17.14 vs 14.66 — newer
1144
- ALU absorbs the unpack, fewer bytes win). Card guidance: M1-class → winner
1145
- fastest; M4-class → compact is smaller AND faster. Compact 32k prefill
1146
- (85 tok/s) is its weak axis. Peak not instrumented this run; estimated
1147
- ~16 GB at 32k (likely fits the DEFAULT 24 GB wired limit — untested).
1148
-
1149
- ## Known engine gaps found in passing (not TQ defects)
1150
-
1151
- - `mlx-bun perplexity` cannot score qwen3_5: it routes through
1152
- `trainForward`, whose cache stub lacks the DeltaNet `SSMCache.advance`
1153
- (`qwen3_5.ts:226` throws on plain and TQ arms identically). 27B ppl runs
1154
- through stock mlx-lm (`scripts/turboquant/tq-ppl.py`) — which doubles as
1155
- the cross-stack load check for the release artifact.
1156
- - bf16 (unquantized) qwen3_5 trunks don't load in our engine:
1157
- `QuantizedEmbedding.load`/`QuantizedLinear.load` hard-require `.scales`.
1158
- The small-scale fold proof ran through stock mlx-lm instead. Backlog: not
1159
- needed to serve the published quant.
1160
- - `scripts/eval.ts` capability tasks at 27B swap-thrashed a 32 GB box — root
1161
- cause fixed (chunked `forwardHidden` prefill + allocator clear cadence);
1162
- verify at 27B post-GPQA.
1163
- - Qwen MTP via the HTTP serve lane 500'd (`[slice] Invalid number of
1164
- indices…`) — pre-existing serving-path bug, reproduced with stock
1165
- artifacts; FIXED 2026-08-20 (draft gate + `[1,V]` sampler contract). The
1166
- paired MTP harness is `scripts/turboquant/tq-mtp-ab.ts` (its header still
1167
- cites its old name, `qwen38-mtp-ab.ts`).
1168
- - DeltaNet prefill leak (~1 MB/token, `contiguous()` returning a no-op view
1169
- that pinned whole chunk buffers) FOUND+FIXED 2026-08-20 via this program's
1170
- dogfood gate; 27B now fits 24 GB (peak 19.2 GB at 16k probe).
1171
-
1172
- ## Weights-leg non-goals
1173
-
1174
- The original W recipe's scope below does not limit the 2026-09 Qwen performance
1175
- program. Custom formats, kernels, alternative algorithms and online-transform
1176
- candidates are now in scope under the gates in
1177
- [decode-speed-program.md](decode-speed-program.md#7-qwen38-27b-research-program).
1178
-
1179
- Mirrors the PLAN.md phase: no custom Lloyd-Max weight format / new qmm
1180
- kernels; no activation quantization; no runtime weight rotation of any kind
1181
- (weights fold offline; online rotation remains the KV codec's job); no
1182
- GGUF/AWQ export; group_size > 128.
1183
-
1184
- ---
1185
-
1186
- ## Q campaign — sub-4-bpw frontier: KL instrument, trellis, LDLQ, mixed-k (2026-08-31 → 09-02, M1 Max 32 GB)
1187
-
1188
- Josh's frame: the best Qwen3.8-27B for THIS 32 GB box — smallest, smartest,
1189
- fastest — using the rotation ("that was the entire point") plus the levers
1190
- the 900+ published quants do not combine: trellis coding (QTIP/TCQ), LDLQ,
1191
- and borrowed sensitivity measurements (EXL3/Unsloth/OptiQ). Program tag Q.
1192
-
1193
- **Q0 instrument — mean KL vs a bf16 teacher, on 32 GB.** `scripts/turboquant/
1194
- tq-dump-teacher-logits.py` streams the bf16 27B through stock mlx-lm once and
1195
- writes, per teacher-forced position, the top-2048 logits + full-vocab
1196
- logsumexp (fp16 lossless for bf16; captures 99.79% of full-vocab KL);
1197
- `tq-kl-vs-teacher.py` (Python) and `bun scripts/eval.ts kl --reference-logits`
1198
- (serving path) score any candidate; self-KL is exactly 0 and the two stacks
1199
- read the dump byte-identically. Corpus `runs/kl-corpus/uf-4096x32` (32×4096
1200
- UF-derived chat, sha `6594cfbf…`); dump `runs/kl-teacher/qwen38-27b-bf16`
1201
- (1.61 GB). Calibration warning of record: this protocol runs ~25× hotter than
1202
- the published self-generated-trace charts (RTN-4 = 0.1396 here vs ~0.005
1203
- there) — only within-dump comparisons are valid, never cross-paper numbers.
1204
-
1205
- **KL ladder (mean KL(bf16‖cand), same dump, lower is better):**
1206
-
1207
- | arm | bpw | GiB | KL | MMLU | tGSM | rawGSM |
1208
- |---|---|---|---|---|---|---|
1209
- | bf16 | 16 | 54 | 0 | | | |
1210
- | RTN-4 g64 (all 4-bit) | 4.5 | 15.0 | 0.1396 | | | |
1211
- | **Q3: rotation + LDLQ + mixed-k 3.00** (fake-quant; carrier8 dense 0.1568) | **3.55** | **~11.9 proj.** | **0.1553** | **88** | 48 | 44 |
1212
- | flagship GPTQ+sens (mjriii/Qwen3.8-27B) | 4.80 | 17.0 | 0.1646 | 87 | 94 | 96 |
1213
- | **compact allocation, NO rotation** (`tqalloc-norot`) | 3.858 | 13.13 | **0.2524** | 85 | 98 | **0/50** |
1214
- | q1-latemlp, no rotation | ~3.9 | | 0.2837 | | | |
1215
- | **trellis k3 uniform + rotation** (q2a, fake-quant) | ~3.4 | | 0.4240 | | | |
1216
- | trellis k3 uniform, no rotation (q2b) | ~3.4 | | 0.5648 | | | |
1217
- | compact allocation + rotation (mjriii/Qwen3.8-27B-TQ) | 3.86 | 13.9 | 0.6054 | 82 | 82 | 96 |
1218
- | q1-latemlp + rotation | ~3.9 | | 0.6519 | | | |
1219
-
1220
- Findings of record: (1) **rotation is a 2×2 crossover, not a lever with a
1221
- sign** — it HELPS the trellis (0.565 → 0.424) and HURTS affine g64
1222
- (0.252 → 0.605): the trellis codes a Gaussian source and needs the Hadamard;
1223
- affine's per-64 scale+bias already absorbs the outliers the rotation spreads.
1224
- (2) **KL is the screen, not the verdict**: the lowest-KL sub-4-bpw arm scores
1225
- 0/50 on raw GSM (an EOS cliff a single-forward instrument cannot see) while the
1226
- rotated compact arm at 2.4× the KL scores 96 — every finalist still needs the
1227
- task columns. (3) No trellis cell beats the affine compact arm yet; the two
1228
- open levers are LDLQ (Hessian error feedback) and mixed k — the published
1229
- EXL3 numbers (their protocol: SC 3 bpw 0.0257 vs UD-Q3_K_XL 0.0209; 4 bpw
1230
- 0.0062) say both are worth ~20–70%. (4) Weight-MSE is NOT a screen: it
1231
- predicted the unrotated trellis at 0.18–0.21; the measured KL was 0.5648.
1232
- (5) **The full recipe wins (2026-09-02):** rotation + LDLQ + EXL3-derived
1233
- mixed k at the 3.00 MLP budget scores KL 0.1553 at 3.55 coded bpw — below
1234
- the shipped 4.80-bpw flagship (0.1646), 38% below the previous sub-4 best
1235
- (compact-norot 0.2524), 11% above all-4-bit RTN (0.1396) — with MMLU 88/100
1236
- (flagship 87, compact 85), tGSM 48/50 (flagship 48), rawGSM 44/50 (flagship
1237
- 48, compact-norot 0): no EOS cliff. Each lever alone lost (q2a 0.4240); the
1238
- levers compound. At n=100/50 a one-point gap is noise: the claim of record
1239
- is "matches the 4.8-bpw flagship at 3.55 bpw", not "beats it". Gate Q3 PASSED.
1240
-
1241
- **Q2 trellis codec** (`scripts/turboquant/tq-trellis.ts`): QTIP bitshift
1242
- trellis L=12, k∈{1..4}, V=1, T=256, tail-biting Viterbi, 1MAD/RPTC/random
1243
- codebooks; `--validate` reproduces QTIP Table 2 exactly; 1.2 Mw/s on M1 Max
1244
- after replacing `argmax` (MLX ArgReduce is 85× slower than `max`) with
1245
- compare + uint8 max. Driver `tq-quantize-trellis.ts`: streaming fold +
1246
- quantize, trellis on the 192 MLP tensors along the rotated axis, affine
1247
- elsewhere per the compact allocation, fake-quant output (decoded bf16 flagged
1248
- `false`, so stock mlx-lm loads it). Real packed kernels (Q2b) only if a recipe
1249
- wins: Metal has no `lop3`, so decode costs 4–5 ALU ops/weight; M1 decode is
1250
- already ALU-bound (3-bit affine at 54% of roofline) → predicted 7–9 tok/s on
1251
- M1 (a regression), wash-to-win on M4 Pro; ~257 dispatches/token; fallback is
1252
- load-time expansion to affine.
1253
-
1254
- **Q2c LDLQ** (`tq-ldlq-hessians.py` + `--ldlq <hdir>`): per-layer MLP input
1255
- Hessians in the folded basis (gate/up captured pre-γ so H' = R1ᵀ E[nnᵀ] R1;
1256
- down basis-free), block-LDL on CPU, BlockLDLQ error feedback at block T (=
1257
- the trellis block, so only the objective changes vs q2a), 4× unweighted-peak
1258
- guard, 20 GiB leak abort. Calibration = 512×128 rows of the SAME chat domain
1259
- (disjoint from the scored rows; a domain mismatch was measured to hurt GPTQ).
1260
- Hessians: 64 layers in 35 min, 0/128 factorization fallbacks. The uniform-k3
1261
- LDLQ arm (Q2c) was paused at 72/192 and superseded: Q3 went straight to the
1262
- full recipe, so LDLQ's isolated contribution is not separately measured
1263
- (q2a → Q3 is LDLQ + mixed-k together, 0.4240 → 0.1553). Bug found on resume
1264
- (2026-09-02): the k-map refactor's block loop shadowed the codec k
1265
- (`trellisFor(blockIdx)`); the Trellis ctor now rejects K outside [1,L), the
1266
- L=0 selftest is byte-identical again, and the real-L probe on layer 21 runs
1267
- at 5.6 GiB peak with the unweighted MSE +32/+46% (gate/down), as expected for
1268
- a Hessian-weighted objective.
1269
-
1270
- **Q3 mixed k** (`--k-map reports/qwen38-allocation/trellis-kmap.json
1271
- --k-budget 3.00`): per-tensor k∈{2,3,4} greedily allocated from turboderp's
1272
- EXL3 per-tensor KLD-vs-k table for this exact model (gate/up tied like EXL3's
1273
- own recipe; 94.3% agreement with their 3.00 bpw recipe). Budgets 2.75 / 3.00
1274
- / 3.25 avg-MLP-bpw = k2/k3/k4 68/104/20, 26/140/26, 2/140/50 (≈10.8 / 11.3 /
1275
- 11.8 GiB projected). Run 2026-09-01/02 at 3.00: 259 min (257 in the encoder,
1276
- 1.11 Mw/s), 192 trellis tensors, 3.5468 coded bpw over 27.3 G params, 38 GiB
1277
- fake-quant on disk; artifact `mjriii/Qwen3.8-27B-q3-trellis-ldlq-k300-fakequant`
1278
- on the external volume, KL row `rows/q3-ldlq-k300.json`. Result: see finding
1279
- (5). 3.25 not run — 3.00 already clears the gate; a 2.75 arm is the next
1280
- size lever, not 3.25.
1281
-
1282
- **Q2b packed format + kernels** (`src/quantize/trellis.ts`,
1283
- `src/model/trellis-linear.ts`, driver `scripts/turboquant/
1284
- tq-quantize-trellis-packed.ts`; the fake-quant codec/driver that produced the
1285
- Q3 record are frozen, these are new files). On disk a trellis tensor is
1286
- `.weight` uint32 `[rows, cols·k/32]` + `.scales` fp16 `[rows]`, config entry
1287
- `{mode:"trellis", bits:k, group_size:T, trellis:{L, code:"1mad", axis}}`
1288
- (axis 1 = coded along the input dim, stored `[out, in·k/32]`; axis 0 = along
1289
- the output dim, stored as Wᵀ `[in, out·k/32]`). One block = T·k bits; symbol
1290
- b_t sits at bit offset (T−1−t)·k — REVERSED time — so the L-bit window at that
1291
- offset (wrapping, tail-biting) IS state_t, and any weight decodes in O(1):
1292
- two word loads, shift, mask, LUT. No sequential dependency, hence a plain
1293
- matvec. Three Metal kernels share that primitive: `reduce` (axis 1, one SIMD
1294
- group per output row, lanes stride consecutive coded positions → coalesced,
1295
- `simd_sum`), `scatter` (axis 0, 32 lanes = 32 consecutive outputs of one
1296
- block, loop over inputs, split-K ×16 partials summed by one mlx op), and
1297
- `expand` (whole tensor → bf16 for M>4, then a stock matmul; ≤178 MB
1298
- per expanded tensor). Packed prefill evaluates each projection before
1299
- building the next. Qwen also evaluates each layer's cache outputs: the
1300
- copied conv tail otherwise retains the whole chunk's conv input until
1301
- end-of-chunk cache evaluation. Decode remains lazy and uses packed kernels.
1302
- These evaluation boundaries bound temporary buffer lifetimes; disposing a
1303
- JS tensor handle alone does not release a lazy consumer's references.
1304
- The reconstructed weight is bf16(f32(lut[state])·f32(scale)) in
1305
- every path — bit-identical to the fake-quant artifact's stored bf16 (unit test
1306
- `tests/unit/trellis-linear.test.ts`: host unpack + expand kernel exact for
1307
- k∈{2,3,4}; matvecs within 2e-3 of a bf16 matmul). Engine wiring is additive:
1308
- `QuantSpec.trellis`, `loadLinear`/`Qwen3MLP` pick `TrellisLinear` per module;
1309
- trellis MLP tensors are not LoRA targets yet. `MLX_BUN_TRELLIS=expand` is the
1310
- load-time fallback (8-bit affine carrier). Encoding a packed artifact reruns
1311
- the Viterbi (the fake-quant stores values, not states; a state path cannot be
1312
- recovered from values because the 4096 states map onto 1021 distinct values).
1313
-
1314
- **Q2b measured (2026-09-02, M1 Max 32 GB).** Packed Q3 artifact
1315
- (`Qwen3.8-27B-q3-trellis-ldlq-k300-packed`): **12.14 GiB** on disk (fake-quant
1316
- 38 GiB, flagship 17 GiB), LDLQ applied 192/192, 0 guard trips; decoded
1317
- weights bit-identical to the fake-quant artifact through the expand kernel
1318
- (0 mismatches in 89 M per tensor, k=2 and k=3, both axes). Loads and generates
1319
- through the qwen3_5 graph; KL through OUR serving path 0.15501 (mlx-lm on the
1320
- fake-quant: 0.15532). Decode kernels, pipelined 8-deep (the in-graph cost; an
1321
- eval-per-call bench adds ~0.3 ms of sync and misleads), gate/up [17408×5120]
1322
- and down [5120×17408], k=3, M=1:
1323
-
1324
- | kernel | no decode (floor) | inline 1MAD, f32 weight | stock affine 3-bit g64 |
1325
- |---|---|---|---|
1326
- | gate/up matvec (reduce) | 0.24 ms | 0.41 ms | 0.16 ms |
1327
- | gate+up+swiglu fused | 0.37 ms | 0.73 ms | 2×0.16 |
1328
- | down matvec (scatter) | 0.54 ms | 0.77 ms | 0.16 ms |
1329
-
1330
- Whole model: **9.3 tok/s** vs the 4.80-bpw affine flagship at **18.9** on the
1331
- same box (kernels v3, `c0a1e00`); the first kernels read 4.4. What the
1332
- decomposition says: (1) the 1MAD decode is ~12 int ops/weight and costs
1333
- 0.17 ms per 89 M weights; a precise divide cost 1 ms (replaced by y×(1/d),
1334
- which is 1-ulp-off f32 for 398 of 1021 code values — a 2-FMA residual step
1335
- restores exactness at +0.05 ms, `trellis_val_rcp`); (2) rounding the decoded
1336
- weight to bf16 (to match the artifact's stored bf16) cost as much as the
1337
- decode, so the served weight is now f32 code×scale — MORE accurate than the
1338
- fake-quant, no longer bit-identical to it — measured on the served DECODE
1339
- path (`eval.ts kl --decode --self MLX_BUN_TRELLIS_VARIANT 1→6`, 16 prompts ×
1340
- 32 teacher-forced steps): KL(bit-exact ‖ f32-weight) mean 0.00089, p95
1341
- 0.0025, i.e. 0.6% of the model's own 0.155 to the teacher (the prefill/expand
1342
- path always rounds to bf16 and is unaffected); (3) the threadgroup LUT (16 KB) halves
1343
- occupancy and the device LUT gathers 32 lines per load — both slower than
1344
- computing the code; (4) the axis-0 (down) matvec is the hard one: the code
1345
- sequence runs along the OUTPUT dim, so a reduction over inputs is a column
1346
- gather; lanes-over-outputs looping rows costs a full line per 16-byte
1347
- segment, and lane-per-word (whole-line reads, shuffle for spilled windows)
1348
- did not beat it — its no-decode floor is 3× affine. M1 decode at these sizes
1349
- is latency/occupancy bound (affine reaches 200 GB/s of 400), so every ALU op
1350
- per weight lands on the wall clock. Verdict: the packed format works and is
1351
- the honest 12 GiB artifact; on M1 Max it decodes at ~half the flagship's
1352
- speed. Levers left: code down_proj along its INPUT dim (a recipe change —
1353
- the rotated axis is the output dim — needs a re-encode and a KL check),
1354
- half-precision LUT (8 KB, occupancy back, +double rounding), or accept
1355
- M4-class ALU. `MLX_BUN_TRELLIS=expand` (8-bit carrier, 23 GiB) is the
1356
- full-speed fallback where it fits.
1357
-
1358
- **The down_proj axis, settled (2026-09-02 night).** Re-encoded the same recipe
1359
- with `--down-axis in` (down_proj coded along its INPUT dim — the un-rotated
1360
- intermediate — so all three MLP projections decode with the plain reduce
1361
- kernel; `--reuse` copied the 128 unchanged gate/up tensors, so only 64 Viterbi
1362
- runs, 98 min):
1363
-
1364
- | arm | bpw | GiB | KL (engine) | top-1 | decode tok/s |
1365
- |---|---|---|---|---|---|
1366
- | down coded along the ROTATED output dim | 3.5468 | 12.14 | 0.15501 | 86.38% | 9.3 |
1367
- | **down coded along the INPUT dim** | 3.5463 | 12.14 | **0.15543** | **86.59%** | **11.3** |
1368
-
1369
- KL is a wash (+0.0004, 0.3% of the arm's own distance to the teacher) and
1370
- top-1 is marginally BETTER — so on the screen the input axis looked like a
1371
- free +22% decode. **The task columns overturned it** (8-bit carriers, same
1372
- frozen items, `tq-evals.py`):
1373
-
1374
- | arm | MMLU-100 | tGSM-50 | rawGSM-50 |
1375
- |---|---|---|---|
1376
- | down along the rotated output dim | 88 | 48 | **44** |
1377
- | down along the input dim | 88 | 47 | **29** |
1378
-
1379
- The rawGSM regression is STRICTLY NESTED — 15 items the output-axis arm
1380
- answers correctly that the input-axis arm fails, **0 the other way** (McNemar
1381
- p ≈ 3e-5) — and the failure mode is an EMPTY continuation: on those items the
1382
- model emits EOS immediately after `A:` (verified by dumping the raw
1383
- generations). That is the same EOS-cliff class as the unrotated affine arm
1384
- (`tqalloc-norot`, rawGSM 0/50 at KL 0.2524), and it is invisible to MMLU
1385
- (logprob over four letters), to templated GSM (chat template, 47 vs 48), and
1386
- to KL (a single-forward instrument that never asks the model to STOP).
1387
-
1388
- **Finding of record (third instance of "KL is the screen, not the verdict"):
1389
- one-sided incoherence processing must reach the CODED axis.** R1 gaussianizes
1390
- down_proj's output dim; coding along the un-rotated input dim leaves that
1391
- sequence non-Gaussian for a codebook that assumes unit-variance Gaussian
1392
- inputs, and what breaks is not average next-token quality but the model's
1393
- raw-format stopping behavior. **Carry-forward stays the output-axis arm**
1394
- (`…-k300-packed`, 9.3 tok/s); `--down-axis in` is kept as the measured
1395
- counter-example, not a default, and the scatter kernel stays load-bearing.
1396
- The re-encode also surfaced a driver bug: the LDLQ Hessian must be chosen by
1397
- MODULE, not by trellis axis (`2b29b18`).
1398
-
1399
- **Eval carrier** (`scripts/turboquant/tq-repack-fakequant.ts`): a 38 GiB
1400
- fake-quant cannot load dense on 32 GB, and `tq-evals.py` (MMLU logprob
1401
- scoring, GSM greedy generation) needs the whole model resident. The tool
1402
- re-packs exactly the bf16 MLP tensors flagged `false` as 8-bit g64 affine
1403
- (≈ −45 dB, negligible next to the ≈ −13 dB trellis error) and passes every
1404
- other tensor through byte-identical: 23 GiB, loads in 24 s, dense KL 0.1568
1405
- vs 0.1553 streamed (+1%, identity confirmed). All task columns for trellis
1406
- arms are measured on the carrier. NOT a shipping format — the real footprint
1407
- needs Q2b (packed trellis + Metal decode kernel).
1408
-
1409
- ## Packed kernel experiments (2026-09-05, M4 Pro 24 GB)
1410
-
1411
- Experimental `MLX_BUN_TRELLIS_VARIANT=7` reuses each decoded gate/up weight
1412
- across M=2..4 input vectors. The new kernels live in
1413
- `src/model/trellis-shared-m.ts`; the original kernels remain the default
1414
- (variant 6). Variant 7 keeps the same two-accumulator order, reductions and
1415
- bf16 activation boundaries. M=1, scatter/down and M>4 expansion retain the
1416
- variant-6 decoder and kernels. No weight format or crossover changed.
1417
-
1418
- The kernel diagnostic now loads an individual layer's real packed tensors
1419
- with `--model-path`, selecting a gate bit-width via `--k` (and optionally
1420
- `--layer`). It records the actual per-role geometry, tensor SHA-256 hashes,
1421
- source identity, every timing sample and memory. `--variants 6,7` compares
1422
- the implementations; `--reference-variant 6` checks outputs separately from
1423
- timing. `--m`, `--seed`, `--reps` and `--pipe` control the micro-workload;
1424
- `--skip-affine` excludes synthetic affine controls, which are not a quality
1425
- comparison. `--json reports/<name>.json` preserves results. Its complete-MLP
1426
- cell retains gate/up → SwiGLU → down dependencies and production barriers.
1427
- `--kernel-module` permits isolated candidate modules with the same exports.
1428
-
1429
- The first screen covers the packed artifact's k2/k3/k4 matrices at
1430
- M=1/2/3/4/5/8. Shared-M reduce and fused gate/up prototypes match the observed
1431
- outputs at M=1..4. Six sequential AB/BA blocks with different activation seeds
1432
- retain the gain in the complete MLP. Raw evidence is under
1433
- `reports/qwen38-rd/paired-shared-m/`; integrated variant-7 checks are under
1434
- `reports/qwen38-rd/variant7/`. Unit tests also compare exact output bytes for
1435
- bf16/f32, both axes, fused activation, the complete MLP and the M=4/5 boundary.
1436
- The complete packed 27B also passes candidate/current equality for all logits,
1437
- live KV/recurrent state and a subsequent token at M=1..5. Six AB/BA full-model
1438
- forward blocks at M=2/4 preserve state/logit identity on distinct token inputs;
1439
- results are in `reports/qwen38-rd/shared-m-full-model.json`. These timings
1440
- project every position from a short shared prefix. They do not measure HTTP
1441
- generation or strict fill's last-position-only head. The machine fails the
1442
- quiet/swap gate, so user-workload A/B and quiet M4 Pro evidence remain required
1443
- before a default. `tests/parity/trellis-shared-m.test.ts` retains the native
1444
- gate behind `MLX_BUN_TEST_TRELLIS_MODEL`; `MLX_BUN_TRELLIS_AB_REPORT` optionally
1445
- records the diagnostic forward timings.
1446
-
1447
- Experimental variant 8 combines variant 7 with balanced 3-bit scatter in
1448
- `src/model/trellis-balanced-scatter.ts`. The incumbent assigns one packed word
1449
- per lane and leaves eight SIMD lanes idle for a 3-bit block. The candidate
1450
- assigns eight outputs to each of all 32 lanes, loads adjacent packed words
1451
- and aligns them once before constant-shift decoding. It preserves each
1452
- output's row/FMA order, all split boundaries, partial reduction and final
1453
- cast. This path requires k=3, T=256 and L<=12; other geometries retain the
1454
- incumbent scatter. M>4 still expands. The default remains variant 6.
1455
-
1456
- Balanced lanes alone improve the diagnostic screen; aligning words improves
1457
- it further. Row-loop unrolling does not materially improve the aligned
1458
- candidate, so it is not retained. The unroll screen has no repeatable-win
1459
- verdict for k2/k4. Raw screens: `reports/qwen38-rd/balanced3-screen/`,
1460
- `scatter-unroll-screen/` and `aligned3-screen/`. Six blocks comparing
1461
- variants 6/7/8 at k3 and M=1/2/4 retain the down/complete-MLP gain with exact
1462
- observed outputs (`variant8-paired/`). Native packed-model logits, live state
1463
- and subsequent-token checks also pass M=1..5. Six full-model A/B blocks at
1464
- M=1/2/4 retain the gain (`variant8-full-model.json`). Select this gate with
1465
- `MLX_BUN_TRELLIS_AB_VARIANT=8`; these remain short-prefix diagnostics.
1466
-
1467
- `MLX_BUN_TRELLIS_AB_LAST=1` selects a native append screen at
1468
- M=1/2/3/4/5/8/9/16 with only the last vocabulary projection, closer to strict
1469
- fill's work. The variant-7 screen preserves state/logit identity and confirms
1470
- the M=4/5 cost discontinuity (`shared-m-append-lengths.json`). Splitting a long
1471
- span crosses the packed-f32/expanded-bf16 paths and is a separate numerical
1472
- experiment; the timing curve does not authorize that change.
1473
-
1474
- A device lookup table of variant-6 f32 code values also matched the observed
1475
- outputs but slowed the M=1 kernels for every tested bit width. That candidate
1476
- is a measured loss on this chip/regime (`reports/qwen38-rd/lut6-*.json`). The
1477
- M=4/5 gate-projection cost discontinuity remains; changing the crossover also
1478
- changes the accumulation/precision path and needs separate numerical gates.
1479
-
1480
- The smaller-table follow-up also loses on the M4 Pro. A constant-address-space
1481
- table stores all 4,096 integer code values in signed 16-bit entries, preserving
1482
- the reciprocal, scaling and reduction arithmetic. It matches the k3 M=1
1483
- checks but slows both projections and complete MLP execution. Device and
1484
- threadgroup tables store the same integers exactly in fp16, avoiding the
1485
- double rounding of fp16 normalized code values. Both lose at M=1/4; the
1486
- threadgroup version is the less costly choice. Those two experiments change
1487
- gate/up decoding while retaining the aligned k3 scatter's computed decoder.
1488
- None proceeds to full-model integration. Evidence: `trellis-constant-short-k3-m1.json`,
1489
- `trellis-device-half-k3-m1.json`, `trellis-device-half-k3-m4.json`,
1490
- `trellis-threadgroup-half-k3-m1.json` and `trellis-threadgroup-half-k3-m4.json`
1491
- under `reports/qwen38-rd/`, with source manifests and every timing sample.
1492
-
1493
- A later scatter-specific table experiment starts from the interleaved
1494
- variant-13 artifact. Each threadgroup computes the exact 4,096 integer code
1495
- values into an 8 KiB signed-short table; packed float multiplication and the
1496
- original dense-expansion LUT remain unchanged. An initial 45-process screen
1497
- across bf16/f16/f32 and M1/2/4/5/8 preserves all output hashes. Changing all
1498
- decode sites still loses because gate/up slows. The apparent M1 scatter gain
1499
- does not survive the narrower repeated control.
1500
-
1501
- Restricting the table to the balanced scatter kernels completes 72 processes
1502
- with exact separate-process output hashes, including complete MLP outputs
1503
- and M5/8 fallback. Six alternating bf16 pairs on the M4 Pro 24 GB change
1504
- complete-MLP time by +1.28% at M1, -0.62% at M2 and -4.12% at M4. All M1
1505
- pairs lose and all M2/M4 pairs improve. A 20-process M3 follow-up also preserves
1506
- every output hash; its six bf16 pairs improve the down projection by a median
1507
- 8.02% and the complete MLP by 2.52%. The smaller fp16/fp32 screens preserve
1508
- identity but do not establish retention. Each native/candidate pair reaches
1509
- the same final active-allocation baseline. These are diagnostic operation
1510
- timings, with fixed sources and all samples retained. The next full-model
1511
- prototype targets only M3/4 for the tested k3/L12/T256 interleaved down shape.
1512
- Ordinary M1 stays procedural. Full-model state, generation and actual serving
1513
- acceptance remain before integration. Evidence: `trellis-threadgroup-codebook.json`,
1514
- `trellis-threadgroup-scatter{,-review}.json` and
1515
- `trellis-threadgroup-scatter-m3{,-review}.json` in the campaign directory.
1516
-
1517
- The narrow full-model screen then preserves all 24 forward comparisons,
1518
- including every vocabulary row at M1..8, live attention/recurrent state and
1519
- the next token's logits/state. It also preserves four greedy/seeded-sampled
1520
- generation streams and their log-probabilities, counts and final cache bytes.
1521
- The prefix snapshot stays unchanged. Both fresh processes exit cleanly with
1522
- fixed sources, equal scatter-call counts and the same 1,015,814-byte final
1523
- active counter after model/cache disposal. The first pair's measured M3/4
1524
- forwards improve by 1.6–2.8%; ordinary 64-token generation changes by less
1525
- than 0.1%. This is an initial screen. Six balanced process pairs and actual
1526
- MTP serving comparisons remain before retaining the prototype. Evidence:
1527
- `trellis-scatter-full{,-review}.json`.
1528
-
1529
- Six balanced fresh-process pairs preserve all 144 forward/logit/state and
1530
- 24 generation comparisons, with fixed sources, identical call counts and
1531
- the same final active allocation. Taking the two measured forward samples
1532
- within each process before pairing, median M3/M4 forward changes are
1533
- -1.44/-2.00%, improving every pair. Ordinary 64-token greedy/sampled complete
1534
- times change by +0.045/-0.125%. The unchanged M128 prefill control is 2.59%
1535
- slower in this sequence and loses all six pairs. A focused M128-only control
1536
- tests whether that regression requires preceding M3/4 work. The initial actual MTP HTTP pair preserves all seven responses,
1537
- 7,100 eligible scatter calls per arm and equal final active counters, but
1538
- its complete-time changes are mixed. Evidence:
1539
- `trellis-scatter-full-repeat{,-review}.json` and
1540
- `trellis-scatter-http{,-review}.json`.
1541
-
1542
- Six subsequent balanced MTP HTTP pairs preserve all 42 paired responses,
1543
- call maps and final active allocations. Median complete-request changes are
1544
- -1.53% for code, -1.29% for explanation and -1.04% for JSON. Code and explanation
1545
- improve in every pair; JSON improves in four of six. TTFT changes by less than
1546
- 0.71% and median paired sampled peak RSS increases by 2.16 MiB. These are
1547
- M4 Pro 24 GB diagnostic results, with static swap still failing preflight.
1548
- They support a small serving benefit in this scope, not ordinary M1 decode.
1549
- The separate four-pair M128-only control executes no eligible M3/4 scatter
1550
- calls. All 20 forward/state comparisons remain exact and final active memory
1551
- is 16,390 bytes in every process. Its median paired time increases by 0.52%,
1552
- with individual process-median differences from 0.06% to 1.01%. This does not
1553
- reproduce the earlier 2.59% magnitude, but does not identify its cause either.
1554
- Keep both results and inspect scheduling before integration. Evidence:
1555
- `trellis-scatter-http-repeat{,-review}.json` and
1556
- `trellis-scatter-prefill{,-review}.json`.
1557
-
1558
- A four-pair sequence control adds 80 exact forward/state/continuation cases,
1559
- with the same 16,390-byte final active counter in all eight processes. M3/M4
1560
- forwards improve by median 1.45/1.73%, in every pair. The same-input M128
1561
- measurement immediately before and after those calls changes by -0.92/-1.77%
1562
- between arms; the after-versus-before difference does not show the suspected
1563
- slowdown. The unchanged M512 control instead changes by +1.11%, losing three
1564
- of four pairs. These controls do not reproduce the original M128 result or
1565
- establish a prefill benefit. Keep prefill variation in the uncertainty of this
1566
- small candidate and require integrated, combined and quiet acceptance.
1567
- Evidence: `trellis-scatter-sequence{,-review}.json`.
1568
-
1569
- The normal-scheduling recorder preserves the three HTTP responses and all
1570
- scatter calls in a separate JSON pair. The measured request has 76,928
1571
- dispatches, 3,153 command buffers with dispatches, 50,001 barriers and 3,870
1572
- concurrent dispatches in both arms. Temporary-reference counts and bytes also
1573
- match. Buffers without dispatches and fence waits differ slightly. Candidate
1574
- command-span union falls by about 51 ms, while gaps between those spans grow
1575
- by about 72 ms; instrumented complete time increases by 0.32%. Command spans
1576
- include internal waits and do not measure active GPU utilization. This pair
1577
- shows how scheduling gaps can cancel a small operation gain; it does not
1578
- override the six normal-library serving pairs or prove the cause of the
1579
- prefill difference. Evidence: `trellis-scatter-http-trace{,-review}.json`.
1580
-
1581
- The first ordinary four-request serving pair also preserves all 12 paired
1582
- responses, submitted-row counts, scatter-call maps and final active allocation.
1583
- The measured 256-token cohort completes in 11.342 versus 11.778 seconds,
1584
- 3.70% faster, with 4,050 eligible M4 scatter calls across its three cohorts.
1585
- This is one M4 Pro 24 GB diagnostic pair, not a repeat verdict. Explicit API
1586
- seeds require the serial lane, so this fixture uses temperature-zero argmax
1587
- without an explicit seed. The initial seeded attempt is retained as a rejected
1588
- batch fixture. Evidence: `trellis-scatter-cohort-v2{,-review}.json`.
1589
-
1590
- The codebook is now part of experimental variant 13. Qwen's MLP loader enables
1591
- it for the 5120/17408 down projection. `TrellisLinear` further requires bf16,
1592
- k3/L12/T256, two-block interleaving and M3/4. The generic shared scatter kernel
1593
- receives that decision as a compile-time integer. The table is initialized
1594
- before the threadgroup's bounds return, and no new MLX allocation or graph
1595
- boundary is introduced. Request and execution interfaces do not select it.
1596
- The 23 focused tests and all three typechecks pass. The new test compares
1597
- actual output bytes and dispatch eligibility across three dtypes, variants
1598
- 6/10/13, M1/2/3/4/5/8 and an incomplete row tile. Evidence:
1599
- `trellis-scatter-integration-source-change.json`,
1600
- `trellis-scatter-integration-focused-tests-final.txt` and
1601
- `trellis-scatter-integration-typecheck.txt`.
1602
-
1603
- The integrated full-model gate preserves all 24 forward/logit/state and four
1604
- generation comparisons, the immutable prefix, call maps and final allocation.
1605
- M3/M4 each exercise 150 table calls in the candidate. Timing also improves in
1606
- unchanged control shapes during an unrelated CPU workload burst; those broad
1607
- changes cannot be attributed to this kernel. Six integrated MTP HTTP pairs
1608
- then preserve all 42 responses and the same final active counter. Median
1609
- complete-time changes are -1.07/-1.27/-1.19% for code/explanation/JSON, with
1610
- 5/6, 5/6 and 4/6 pairs improving. TTFT changes remain below 0.46%. Retain every
1611
- losing pair and the diagnostic classification. Repeated ordinary four-request
1612
- serving, combined/pressure and quiet M4 Pro acceptance remain. Evidence:
1613
- `trellis-scatter-integrated-full{,-review}.json` and
1614
- `trellis-scatter-integrated-http{,-review}.json`.
1615
-
1616
- Six integrated ordinary four-request serving pairs preserve all 72 paired
1617
- responses, counts and finish reasons. Every cohort admits four batched rows,
1618
- uses the eligible M4 kernel and returns to the same final active counter.
1619
- Median measured cohort time changes by -1.49%, improving four of six pairs.
1620
- Four measured pairs have identical per-cohort call maps; their median is also
1621
- -1.49%, with three improving. The other two retain arrival-dependent M1/M2
1622
- work differences. Report all pairs and the work-matched subset separately;
1623
- do not silently discard scheduling differences or losing samples. The first
1624
- integrated attempt preserved all responses but failed its stricter total-call
1625
- map gate, motivating snapshots collected outside timed cohorts. This remains
1626
- diagnostic evidence, with combined/pressure and quiet acceptance open. Evidence:
1627
- `trellis-scatter-integrated-cohort.json` and
1628
- `trellis-scatter-integrated-cohort-v2{,-review}.json`.
1629
-
1630
- Sharing activation loads across multiple gate/up output rows per SIMD group
1631
- also loses in the k3 M=1 screen. Every tested layout preserves the incumbent
1632
- output bytes. One row per group reproduces the incumbent timing; two, four
1633
- and eight rows increase complete-MLP time. Reducing the threadgroup to one
1634
- or two SIMD groups does not rescue the two/four-row candidates. The original
1635
- row mapping remains. Evidence: `trellis-shared-rows-k3-r*-m1.json` and
1636
- `trellis-shared-rows-k3-r*-s*-m1.json` in the campaign report directory.
1637
-
1638
- An integer arithmetic rewrite replaces the final byte-pair sum and subtraction
1639
- with `as_type<int>(p * 65537u - (510u << 16)) >> 16`. If
1640
- `p = a + (b << 16)`, with both byte-pair sums at most 510, this returns
1641
- `a + b - 510` exactly. Host exhaustive-state/edge/random checks and all real
1642
- k2/k3/k4 M=1/4 operation checks pass. The timing screen gives no useful
1643
- additional gain, so the readable existing expression remains. Evidence:
1644
- `trellis-y-mad-manifest.json` and `trellis-y-mad-k*-m*.json`.
1645
-
1646
- The activation audit identifies a separate numerical distinction in the
1647
- existing Lab path. Its fused kernel uses a float32 precise-exp sigmoid,
1648
- whereas compiled MLX uses a dtype-specific abs/exp expression. Real k3 inputs
1649
- at M=1/4 differ for bf16 and f32. Applying the old activation independently
1650
- to the two projection outputs reproduces the fused result exactly, isolating
1651
- the difference to the activation. Earlier small-input tolerance tests did
1652
- not establish bit identity here. Existing variant-to-variant identity results
1653
- still compare the same packed activation. Changing it requires a separately
1654
- declared numerical/quality experiment; no default is changed by this audit.
1655
- Evidence: `trellis-activation-audit.json`.
1656
-
1657
- Variant 9 tests evaluation barriers separately. It keeps the variant-8
1658
- kernels but lets the three expanded projections remain lazy until the
1659
- existing layer-end hidden/state evaluation. The native last-head sweep
1660
- preserves logits and live state at all observed lengths. M>4 improves while
1661
- peak allocation grows; small M is unchanged. Evidence is in
1662
- `reports/qwen38-rd/variant9-full-model.json`, with per-arm memory peaks.
1663
- Larger prefill and the frozen long-agent pressure replay remain required.
1664
- The default's per-projection barriers remain in place.
1665
-
1666
- The variant-13 follow-up fixes the interleaved artifact and all kernels,
1667
- then changes only the returned expanded projection's evaluation. It compares
1668
- blocking evaluation, deferral to the existing layer boundary and asynchronous
1669
- submission followed by that same layer boundary. All 35 warm/measured cases
1670
- at M1/8/16/128/512 preserve logits, live state and continuation. Six balanced
1671
- blocks exercise 64 expansion boundaries at M16 and 192 at M128/512; M1/8
1672
- have none and are controls. Deferred evaluation reduces median paired time
1673
- by 2.46%, 5.15% and 2.03% at M16/128/512; asynchronous evaluation reduces it
1674
- by 2.39%, 6.56% and 2.89%. Every affected pair improves. M128/512 peak MLX
1675
- allocation grows by about 362/380 MB for deferral and 368/403 MB for async.
1676
- These M4 Pro 24 GB diagnostics do not remove the memory gate.
1677
- Evidence: `reports/qwen38-rd/trellis-v13-boundary-full-model{,-review}.json`.
1678
-
1679
- The serial HTTP follow-up completes six balanced three-arm blocks with 18
1680
- clean server exits, fixed sources and 126 requests. All 84 paired response
1681
- texts, usage counts and finish reasons match. At 128/512 prompt tokens,
1682
- deferral reduces median paired TTFT by 2.88%/0.53%; asynchronous submission
1683
- reduces it by 4.10%/1.41%, with all six pairs improving in each cell. Async
1684
- complete-response time falls by 0.90%/0.67%. Six-token TTFT and all decode
1685
- cells stay approximately flat. Per-server peak RSS is approximately flat;
1686
- the separately measured MLX transient-allocation increase still applies.
1687
- Evidence: `trellis-v13-boundary-http-serial{,-review}.json`.
1688
-
1689
- The saved-agent pressure gate rejects unrestricted deferral on this M4.
1690
- The synchronous control completes all seven requests, including 14,465 prompt
1691
- tokens, 12,953 cached tokens and a 512-token response, followed by a durable
1692
- SSD flush and clean exit. Deferral preserves the first five responses but
1693
- fails on the sixth request at 12,954 prompt tokens. Native tracing reports
1694
- Metal command-buffer insufficient memory and the child exits with SIGTRAP.
1695
- Sources remain fixed. The asynchronous and mapped arms had not started;
1696
- their outcome cannot be inferred from this failure. Keep per-projection
1697
- barriers while testing bounded alternatives. Evidence:
1698
- `qwen-long-boundary-serial{,-review}.json` and its deferred server trace.
1699
-
1700
- A fresh synchronous/asynchronous pair reaches the same result. The control
1701
- again completes all seven requests with a durable final flush and clean exit.
1702
- Async preserves the first five responses, then fails the sixth request with
1703
- the same Metal insufficient-memory error. Source fingerprints remain fixed.
1704
- Thus both unrestricted alternatives fail this pressure gate despite their
1705
- short-prompt timing gains. A further candidate must retain blocking evaluation
1706
- when available headroom is insufficient. Evidence:
1707
- `qwen-long-async-serial{,-review}.json` and its async server trace.
1708
-
1709
- The next policy submits asynchronously only while MLX active allocation is
1710
- below 75% of the device's recommended working set, retaining blocking
1711
- evaluation above that ceiling. It still evaluates at the existing layer
1712
- boundary. All 35 native warm/measured cases preserve logits, live cache bytes
1713
- and continuation. The short native sweep stays below the ceiling and exercises
1714
- asynchronous submission at every expanded projection. Median paired time
1715
- falls 2.00%/5.40%/3.07% at M16/128/512, with six wins per cell; M1/8 controls
1716
- are approximately flat. The short sweep does not exercise the pressure fallback.
1717
- Evidence: `trellis-v13-bounded-full-model{,-review}.json`.
1718
-
1719
- The bounded policy also passes a fresh serial saved-agent pair. All seven
1720
- responses and usage counts match, both servers exit cleanly, and the final
1721
- SSD flush reports durable state with no pending, missing or failed writes.
1722
- The candidate submits 1,152 expanded projections asynchronously and evaluates
1723
- 2,112 synchronously, exercising both branches. Its maximum observed active
1724
- allocation is 17.216 GB; the 14.302 GB threshold controls scheduling, not total
1725
- allocation. Peak sampled RSS is 13.370/13.743 GB for control/candidate.
1726
- This single pair establishes the pressure gate, not a timing or RSS win.
1727
- The default scheduler pressure gate remains.
1728
- Evidence: `qwen-long-bounded-serial{,-review}.json`.
1729
-
1730
- Six fresh serial HTTP pairs then complete 84 requests with fixed sources,
1731
- clean exits and all 42 paired responses identical. The bounded policy reduces
1732
- median paired TTFT by 4.42%/1.78% at 128/512 prompt tokens, with six wins in
1733
- each cell. Complete-response time falls 0.95%/0.80%; decode speed and the
1734
- six-token control are approximately flat. Median per-server sampled peak
1735
- RSS is 12.364/12.362 GB for synchronous/bounded evaluation. Each candidate
1736
- server exercises 768 asynchronous boundaries in this short sweep. These M4
1737
- diagnostics retain the separate native transient-allocation increase and
1738
- do not replace the default scheduler or quiet-machine gates. Evidence:
1739
- `trellis-v13-bounded-http-serial{,-review}.json`.
1740
-
1741
- The actual continuous-scheduler follow-up completes six pairs and 84 requests.
1742
- All 42 paired response texts, usage counts and finish reasons match; each
1743
- request reports `"batched"` and increments scheduler submissions. Sources
1744
- remain fixed and all 12 servers exit cleanly. Median paired TTFT falls
1745
- 4.46% at 128 tokens with six wins and 1.30% at 512 with five wins.
1746
- Complete-response time falls 0.96%/0.60%. Decode and six-token controls remain
1747
- approximately flat; median sampled peak RSS is 12.381/12.352 GB. MLX is seeded
1748
- to 42 at startup with greedy sampling; request-level seed is omitted because
1749
- it selects serial placement. Evidence:
1750
- `trellis-v13-bounded-http-default{,-review}.json`.
1751
-
1752
- The continuous saved-agent gate also passes all seven paired responses with
1753
- fixed sources. Every request reports the batched lane and a scheduler
1754
- submission. Both servers finish durable SSD flushes with no pending, missing
1755
- or failed writes and exit cleanly. The candidate again uses 1,152 async and
1756
- 2,112 blocking expansion boundaries; maximum observed active allocation is
1757
- 17.265 GB. Sampled peak RSS is 12.842/12.992 GB for control/candidate.
1758
- This one pair closes the prototype's continuous pressure gate, not a timing
1759
- or memory-saving claim. Evidence: `qwen-long-bounded-default{,-review}.json`.
1760
-
1761
- The integrated opt-in `MLX_BUN_TRELLIS_ASYNC_EXPAND` now applies that policy
1762
- to variant 13. It reads the execution's existing runtime snapshot and caches
1763
- only the fixed device threshold per linear layer. It preserves layer barriers
1764
- and blocks expanded projections above the threshold. Default remains off;
1765
- other variants retain their current behavior. Typechecks, hygiene and all
1766
- 1,822 model-free tests pass. Integrated native, both short HTTP repeats and both
1767
- long-agent pressure gates pass on the M4 Pro. Evidence:
1768
- `trellis-async-integrated-{typecheck,hygiene,model-free}.txt`.
1769
-
1770
- The integrated native sweep preserves all 35 logit/live-cache/continuation
1771
- cases with fixed sources. An observer records the implementation's own async
1772
- and blocking calls without substituting a scheduling decision. Median paired
1773
- forward time falls 2.09%/6.19%/2.80% at M16/128/512, with all six pairs
1774
- improving. M1/M8 exercise no expansion boundaries; their paired timings are
1775
- +1.16%/-0.21%, so the M1 control variation remains visible. M128/512 peak
1776
- MLX allocation again grows about 368/403 MB. Integrated serving and pressure
1777
- gates remain. Evidence: `trellis-async-production-full-model{,-review}.json`.
1778
-
1779
- The integrated serial HTTP repeat also passes all 42 paired responses across
1780
- 12 clean server exits with fixed sources. Median paired TTFT falls 4.00% at
1781
- 128 prompt tokens in all six pairs and 1.43% at 512 in five pairs. Request
1782
- wall time falls 0.88%/0.63%; decode and the six-token control remain flat.
1783
- Median sampled peak RSS is 12.331/12.355 GB for control/candidate. Each
1784
- candidate server exercises 768 async boundaries, with no blocking fallback
1785
- in these short prompts. These are M4 Pro diagnostics; pressure and quiet
1786
- acceptance remain. Evidence:
1787
- `trellis-async-production-http-serial{,-review}.json`.
1788
-
1789
- The integrated continuous repeat passes another 42 paired responses and
1790
- 12 clean exits with fixed sources. Every request reports the batched lane
1791
- and exactly one scheduler submission. Median paired TTFT falls 3.96%/1.40%
1792
- at 128/512 prompt tokens, with six/five improving pairs. Wall time falls
1793
- 0.87%/0.63% in five/four pairs. Decode and the six-token control remain flat.
1794
- Median sampled peak RSS is 12.353/12.349 GB. Short prompts exercise the async
1795
- branch only; integrated long-agent pressure gates are next. Evidence:
1796
- `trellis-async-production-http-default{,-review}.json`.
1797
-
1798
- The integrated serial saved-agent gate preserves all seven paired responses
1799
- and usage records with fixed sources and clean exits. Both SSD flushes finish
1800
- durably with no pending, missing or failed snapshots and a longest durable
1801
- prefix of 14,976 tokens. The candidate uses 1,151 async and 2,113 blocking
1802
- boundaries; its maximum observed active allocation is 17.227 GB. Sampled peak
1803
- RSS is 13.550/13.544 GB for control/candidate. The longest request prefills
1804
- 14,465 tokens, reuses 12,953 and generates 512. This is a single pressure
1805
- gate under system swap, without a performance or memory-saving claim.
1806
- Continuous pressure acceptance remains. Evidence:
1807
- `trellis-async-production-long-serial{,-review}.json`.
1808
-
1809
- The integrated continuous saved-agent pair also passes all seven responses,
1810
- usage records, source hashes and clean exits. Every request uses the batched
1811
- lane with one scheduler submission. Both final flushes are durable, with
1812
- 14 snapshots, a 14,976-token longest prefix and no pending, missing or failed
1813
- writes. The candidate uses 1,152 async and 2,112 blocking boundaries; maximum
1814
- observed active allocation is 17.253 GB. Sampled peak RSS is 12.994/12.873 GB
1815
- for control/candidate. This completes the integrated M4 pressure gates; the
1816
- one-pair RSS difference is not a memory-saving claim. Broader callers, combined
1817
- optimizations and quiet M4 Pro acceptance remain. Evidence:
1818
- `trellis-async-production-long-default{,-review}.json`.
1819
-
1820
- Variant 10 shares scatter weight decoding and scales across M=2..4 in
1821
- `src/model/trellis-shared-scatter.ts`. It uses aligned k3 decoding where
1822
- eligible and the incumbent packed-word mapping for other bit widths. Every
1823
- output retains its row/FMA order, split boundaries, sum and cast. M=1 uses
1824
- the existing variant-8 path; M>4 keeps the projection barriers. Variant 10
1825
- does not combine the variant-9 memory experiment.
1826
-
1827
- Real k2/k3/k4 screens improve down and complete-MLP time with exact observed
1828
- outputs. Unit checks cover both axes, bf16/f32 inputs, M=1..5 and the complete
1829
- MLP. The packed 27B passes exact logits, live state and continuation checks
1830
- at M=1..5. Six native A/B blocks against variant 8 improve M=2..4 while M=1
1831
- is unchanged. Raw evidence is in `shared-scatter-screen/`,
1832
- `shared-scatter-all-screen/` and `variant10-full-model.json` under
1833
- `reports/qwen38-rd/`. The native gate accepts
1834
- `MLX_BUN_TRELLIS_AB_BASELINE=8 MLX_BUN_TRELLIS_AB_VARIANT=10`.
1835
-
1836
- Variant 11 combines variant 10 with tiled axis-1 prefill at M=5..32.
1837
- `src/model/trellis-tiled-prefill.ts` reconstructs bf16 weights in threadgroup
1838
- storage and consumes them through SIMD-group matrix operations. Its shared
1839
- operation accepts other compatible matrix shapes; automatic experimental
1840
- dispatch is limited to the measured 5120-to-17408 geometry, bf16, T=256,
1841
- L=12 and k=2/3/4. Down projections keep stock expansion and matmul.
1842
- Dense expansion and layer-end evaluation boundaries remain in place.
1843
-
1844
- The initial computed-code prototype failed the full model despite matching
1845
- the sampled synthetic matrices. Expansion consumes the precise host LUT,
1846
- whereas variant-6 packed matvec uses an unrefined reciprocal. Refining that
1847
- reciprocal before scaling reproduces expansion's bf16 weights. The corrected
1848
- prototype passes logits, live cache state and continuation at M=1/4/5/8/16/32;
1849
- six paired native blocks improve M=5..32 without a larger observed peak.
1850
- Evidence: `trellis-tiled-initial-review.json`,
1851
- `trellis-tiled-refined-gate-model.json` and its review under
1852
- `reports/qwen38-rd/`. The integrated kernel repeats the full-model gate in
1853
- `variant11-full-model.json`. Six process A/B blocks per serving method also
1854
- improve first-token and complete-request latency on one six-token raw prompt,
1855
- with identical output at eight and 64 generated tokens. Serial and continuous
1856
- B=1 paths agree; this does not test concurrent users. Evidence:
1857
- `trellis-v11-http.json` and its review. Broader native/HTTP workloads, pressure
1858
- replay and quiet M4 Pro acceptance remain required. Variant 6 remains the default.
1859
-
1860
- Variant 12 also reconstructs axis-0 weights inside split-K matrix tiles at
1861
- M=5..8. The shared `trellis-splitk-prefill.ts` operation follows MLX 0.31.2's
1862
- partition geometry, float partials and ordered final sum, then rounds to bf16.
1863
- The measured dispatch profile covers 17408-to-5120 matrices at k2/k3/k4.
1864
- It avoids the dense down-projection weight allocation. Dense expansion and
1865
- layer evaluation boundaries remain. Larger M, wider tiles, padding and a device
1866
- lookup table did not give a consistent advantage in the initial sweep.
1867
-
1868
- Other-shape unit checks include transposed inputs and a longer final K
1869
- partition. Both the prototype and integrated packed 27B preserve logits,
1870
- live state and continuation. Six paired integrated blocks improve M=5/8;
1871
- M=1..4/9/16/32 retain their existing path and timing. Evidence:
1872
- `trellis-splitk-screen-review.json`, `trellis-splitk-tuning-review.json`,
1873
- `trellis-splitk-full-model-review.json` and `variant12-full-model.json` under
1874
- `reports/qwen38-rd/`. Combined native and HTTP results are recorded in
1875
- decode-speed-program §7; quiet-machine acceptance remains open.
1876
-
1877
- The calibrated operation trace led to a second tile pass. At M=5..8, both
1878
- direct kernels now use eight output rows and place all four SIMD groups
1879
- across columns. This removes unused row work while preserving each output's
1880
- matrix products, accumulation order, weight rounding and split reduction.
1881
- Contiguous packed reads with transposed threadgroup writes were slower in
1882
- the controlled screen; neither that layout nor padding is retained.
1883
-
1884
- Direct tiles also avoid per-projection evaluation. They keep activations and
1885
- bounded partials without constructing a dense weight matrix, so the existing
1886
- model layer boundary bounds their graph. Expansion paths retain their original
1887
- projection evaluations. A four-arm full-model experiment separates tile
1888
- geometry from synchronization: all logits, live cache bytes and continuation
1889
- match across six blocks at M=1/4/5/8/16/32/128. The combination improves the
1890
- eligible shapes with a small temporary-memory increase. A subsequent six-pair
1891
- check at M=5/8 adds the smaller split-K tile with exact outputs and unchanged
1892
- peak allocation. These changes remain within the experimental variants;
1893
- variant 6 is unchanged. Evidence: `trellis-tile-layout-screen-review.json`,
1894
- `trellis-tile-full-model-review.json`,
1895
- `trellis-splitk-bm8-other-bits-review.json` and
1896
- `trellis-splitk-bm8-full-model-review.json` under `reports/qwen38-rd/`.
1897
- The first layout screen also changed evaluation boundaries and is excluded
1898
- from isolated-kernel speed attribution. The integrated operation passes
1899
- targeted units and ten old/new full-model append lengths. Six subsequent
1900
- HTTP process pairs improve actual eight-request throughput and B=1 TTFT,
1901
- with identical responses and verified scheduler activity. Evidence:
1902
- `trellis-tile-integrated-forward-review.json` and `trellis-tile-http-review.json`.
1903
- Six old/new native process pairs also preserve every emitted ID and finish
1904
- reason, with lower first-token latency and a small complete-request gain;
1905
- single-row decode is unchanged. All workers complete with fixed source hashes.
1906
- Evidence: `trellis-tile-native-review.json`. These remain loaded-machine
1907
- diagnostics, with quiet M4 Pro acceptance pending.
1908
-
1909
- A corrected larger-prefill sweep checks ten tile geometries, packed-load
1910
- orders and threadgroup padding choices on actual k3 gate/down matrices at
1911
- M=128 and 512. Every one of the 40 cases reproduces the expansion-plus-matmul
1912
- output bytes, but none beats that existing path in six AB/BA timing pairs.
1913
- Both arms include output evaluation and GPU synchronization; the candidate
1914
- gets no pipeline-only timing advantage. Larger tiles and coalesced packed
1915
- loads therefore remain rejected for these measured shapes. Keep MLX's native
1916
- matrix multiplication and investigate the separate expansion operation.
1917
- Evidence: `trellis-large-prefill-screen.json` and
1918
- `trellis-large-prefill-screen-review.json` in the campaign report directory.
1919
-
1920
- A source audit also rejects an assumed fp16 throughput shortcut. In pinned
1921
- [MLX 0.31.2 Steel GEMM](https://github.com/ml-explore/mlx/blob/v0.31.2/mlx/backend/metal/kernels/steel/gemm/kernels/steel_gemm_fused.metal),
1922
- both half and bf16 instantiations explicitly select float accumulation.
1923
- `BlockMMA` loads both input tiles into float matrix fragments before the
1924
- matrix multiply. Changing storage dtype alone therefore does not select a
1925
- half-fragment multiply in this path. This is a dispatch/arithmetic finding,
1926
- not a measured bf16-versus-fp16 performance comparison; other native paths
1927
- need their own inspection before making the same claim.
1928
-
1929
- Variant 13 builds on variant 12 with `trellis-vector-expand.ts`: four adjacent
1930
- weights share two packed-word reads and the scale. An unrolled loop extracts
1931
- their circular windows and refines the computed code value to reproduce the
1932
- host f32 LUT before bf16 rounding. MLX's matrix multiplication and each dense
1933
- projection's evaluation boundary remain unchanged. The operation is independent
1934
- of the model; dispatch requires bf16 output, k2/k3/k4, T=256 and L=12. Other
1935
- packing/dtypes retain their existing expansion.
1936
-
1937
- The actual-weight screen passes all 96 configurations across three bit widths
1938
- and both projection axes. Four values per thread with 128 threads gives a
1939
- consistent isolated improvement. Explicit wider output stores add little in
1940
- a subsequent exact 24-case screen and are not retained. The initial full-model
1941
- prototype preserves logits, all live cache bytes and continuation in seven
1942
- blocks at M=1/8/16/128/512, including six measured AB/BA pairs. Eligible prefills
1943
- improve; M=1 and M=8 retain the variant-12 path. The integrated kernel repeats
1944
- those checks and passes the repository parity harness, whose variant-13 arm
1945
- also exercises larger prefills. All HTTP responses match in two existing-suite
1946
- pairs, but their timing is mostly flat; see decode-speed-program §7. Closed
1947
- research helpers are removed after recording their results. These are M4 Pro
1948
- diagnostics, with the
1949
- default still variant 6. Evidence: `trellis-vector-expand-screen-review.json`,
1950
- `trellis-vector-store-screen-review.json` and
1951
- `trellis-vector-expand-full-model-review.json` in the campaign directory.
1952
-
1953
- The R6 layout screen rearranges groups of coded blocks across input rows,
1954
- preserving the codes, payload size, arithmetic and split-K reduction order.
1955
- All six actual k3 down-projection layouts invert to the original code bytes
1956
- and produce identical output bytes. Two groupings improve the isolated
1957
- operation; the original-order control is flat. Both full-model groupings
1958
- preserve every eligible matrix's code bytes, logits, live cache state and
1959
- continuation, with a small single-token forward improvement. Group two is
1960
- simpler and group ten offers no additional model gain. The prototype
1961
- retains both layouts to alternate A/B arms, so its additional residency and
1962
- packing cost are recorded separately. Six subsequent production-generation
1963
- pairs with a fixed seed and 64 outputs preserve every emitted ID, final live
1964
- cache byte and continuation logit. The small gain survives the complete
1965
- generation loop. Six fresh-server pairs in each of serial and default
1966
- scheduling then preserve all 60 paired responses. Both prompt lengths retain
1967
- the small decode and complete-request improvement; the default scheduler's
1968
- longer-prompt TTFT is approximately flat. All servers exit cleanly, and
1969
- telemetry proves the configured execution path. Both arms retain the extra
1970
- code copy, so their flat RSS comparison is not a memory improvement. A stored
1971
- format usable by every prefill, scatter and expansion reader remains open.
1972
- No artifact or production dispatch is changed. Evidence:
1973
- `trellis-block-interleave-screen-review.json` and
1974
- `trellis-block-interleave-full-model-{g2,g10}-review.json`, plus
1975
- `trellis-block-interleave-native-generation-g2-interface-review.json` in the
1976
- campaign directory, plus `trellis-block-interleave-http-{serial,default}-review.json`.
1977
- The first generation driver used the wrong iterator
1978
- interface and failed before timing; its failed report remains separate.
1979
-
1980
- The replacement-layout reader prototype now preserves all 27 actual-matrix
1981
- projection cases across bf16/f16/f32 and three dense expansions. It covers
1982
- single-token and shared M2..4 scatter, M5..8 split-K and larger dense prefills,
1983
- through M512. The operation timings show small-batch gains with marginal
1984
- prefill regressions. The first full-model reader check preserves 63 cases,
1985
- but its wrapper changes input disposal and output evaluation order. A repeat
1986
- with the incumbent order preserves all 35 cases and retains the single-token
1987
- gain; M8/16 are approximately flat, while M128/512 are slightly slower.
1988
- Changing expansion threadgroup traversal preserves all five operation cases;
1989
- moderate row tiles improve that reader slightly, while fully prioritizing
1990
- contiguous code reads loses. The revised traversal preserves all 35 full-model
1991
- cases, retains the small single-token gain and has approximately flat prefills
1992
- in that repeat. The next gate uses a separate stored artifact through serving,
1993
- with every reader consuming one resident code copy. Evidence:
1994
- `trellis-interleaved-readers-screen-review.json`,
1995
- `trellis-interleaved-readers-full-model-count-review.json`,
1996
- `trellis-interleaved-readers-order-full-model-review.json`,
1997
- `trellis-interleaved-vector-schedule-screen-review.json` and
1998
- `trellis-interleaved-readers-schedule-full-model-review.json`. Those prototype
1999
- measurements keep both code copies resident; the stored-artifact gate below
2000
- removes that extra allocation.
2001
-
2002
- The integrated reader accepts an optional U32 code shape
2003
- `[coded_columns / 512, stored_rows, 48]` for k3, T256, L12, 1MAD, axis0.
2004
- Each 48-word row holds two original coded blocks; block groups precede rows.
2005
- Scales retain their original one-value-per-stored-row representation. The
2006
- existing 2D format retains its addressing. Shape validation rejects other
2007
- 3D geometries, and every scatter/expansion reader selects its address formula
2008
- at compile time. Variant 13 also uses the measured moderate row traversal
2009
- when rows divide its tile size; other shapes retain the original traversal.
2010
- No request, scheduler or state interface changes. Focused tests preserve all
2011
- 14 variants, bf16/f16/f32 outputs, strided inputs and expansion, with explicit
2012
- split-K partition-tail and malformed-format checks. Broader artifact and
2013
- serving acceptance remain open; this is not a default artifact change. All three
2014
- typechecks, hygiene and the complete model-free tier pass. A separately
2015
- written artifact verifies all converted code inverses and every unchanged
2016
- tensor payload. Native and HTTP comparisons load one artifact per process,
2017
- without runtime repacking or duplicate codes. Closed layout prototype helpers
2018
- are removed; their raw reports remain. The first native artifact driver fails
2019
- before spawning a child because of an unsupported stdout option; its corrected
2020
- file-descriptor version has a separate report. Evidence:
2021
- `trellis-interleave-integrated-tests.txt`,
2022
- `trellis-interleave-integrated-tail-tests.txt`,
2023
- `trellis-interleave-model-free.txt` and `trellis-interleave-artifact-review.json`.
2024
- The converter's header padding does not determine the kernel buffer's
2025
- alignment. `Weights` uses native MLX safetensors loading, whose pinned
2026
- `Load::eval_cpu` allocates its output buffer and reads the payload into it.
2027
- The paired kernels therefore consume MLX-owned buffers in both artifacts;
2028
- they do not access the file mapping at the tensor's raw header offset.
2029
- The packed quantizer's optional `--interleave-codes` switch produces this
2030
- layout for eligible tensors, including row-major tensors read through
2031
- `--reuse`. Other tensors retain their layout. The shared codec helper only
2032
- reorders words; the quantizer records the number of interleaved modules.
2033
- Six fresh-process native artifact pairs now preserve all warm/measured
2034
- forward logits, live states, continuations and generation IDs. Single-token
2035
- and M4 forwards improve in every pair; M8 is slightly slower, M16 improves,
2036
- and longer prefills are mixed. Complete 64-token generation improves in every
2037
- pair with equal peak MLX allocation. One slower M512 sample remains included.
2038
- This removes the prototype's duplicate-code residency from the comparison;
2039
- HTTP RSS and timing have their own gate below. Evidence:
2040
- `trellis-interleave-artifact-native-fd-review.json` and
2041
- `trellis-interleave-encoder-tests.txt`. Native research helpers are removed
2042
- after recording the finding; the artifact converter is superseded by the
2043
- quantizer's layout option and the retained codec helper.
2044
-
2045
- Six fresh-server serial HTTP artifact pairs preserve all 42 paired responses,
2046
- including warmups, usage, finish reasons and stream completion. Each process
2047
- loads only its selected artifact, uses production readers at variant 13, and
2048
- exits cleanly. Source hashes remain fixed. Decode improves in every measured
2049
- pair at each actual prompt length of 6, 128 and 512 tokens; TTFT changes are
2050
- small or mixed. RSS is approximately flat, with no retained duplicate code
2051
- buffer. These M4 Pro diagnostics use cache-disabled requests and do not
2052
- establish cached, pressure or quiet-machine acceptance. Six further pairs
2053
- under the default continuous scheduler preserve another 42 paired responses
2054
- with clean exits and fixed sources. Telemetry confirms the configured batch
2055
- capacity of eight, one submitted row per request and no remaining active or
2056
- pending rows. These are single-prompt measurements. Decode improves in every
2057
- pair at all three lengths; TTFT changes remain small or mixed, and RSS is
2058
- approximately flat. Evidence:
2059
- `trellis-interleave-artifact-http-{serial,default}-review.json`.
2060
- The completed HTTP research helper is removed; raw responses, telemetry,
2061
- source hashes and server logs remain in the reports.
2062
-
2063
- A separate M<=8 crossover prototype improves complete-MLP time at M=5/8
2064
- but changes output bytes for every tested bit width. It replaces expanded
2065
- bf16 matrix arithmetic with packed f32 code-times-scale arithmetic, so this
2066
- is a Lab precision change, not an exact optimization. The prototype is not
2067
- retained in production dispatch. `reports/qwen38-rd/m8-screen/` records the
2068
- timings and numerical differences. Quality and long-state checks must precede
2069
- any use of the larger crossover or equivalent small-chunk span splitting.
2070
-
2071
- # Open items (weights leg — mirrors the PLAN.md phase boxes; PLAN.md owns status)
2072
-
2073
- - **W5 calibration composition** — PLAN sub-boxes W5a (0.8B matrix), W5b
2074
- (allocation axis, pick the best ≤4.5 bpw recipe), W5c (chunked 27B
2075
- production run + gates) remain unchecked in PLAN.md although the results
2076
- above were measured; closing them is a PLAN.md edit, not new work.
2077
- Deferred lever inside W5: learned R (SpinQuant Cayley-SGD) — only if a
2078
- random-R recipe wins first.
2079
- - **W6 release — SINGLE REPO:** one artifact = quantized trunk + bf16 vision
2080
- (in-main + optiq sidecar) + folded MTP companion at `mtp/`. Engine landed
2081
- (`--draft-kind mtp` bundled resolution). Publish the winner via
2082
- `mlx-bun upload`; awaiting Josh's go. Card notes owed: M1-vs-M4 3-bit
2083
- speed guidance; MTP not claimed lossless; adapters trained on the artifact
2084
- are rotation-basis-married to it.
2085
- - **W6.5 dogfood gate (publish blocker, ahead of W6 upload):** open
2086
- sub-items — `mlx-bun perplexity` on qwen3_5 (SSMCache.advance stub);
2087
- dogfood close-out (re-score a ~30-question GPQA subset through mlx-bun and
2088
- match the mlx-lm scores); 24 GB near-ceiling UX (detect weightsBytes ≈
2089
- default iogpu wired limit and PRINT the sysctl advice up front instead of
2090
- dying mid-request — clamp/advise, never refuse).
2091
- - **W7 Pareto frontier (Josh's frame: "we shouldn't operate in a vacuum"):**
2092
- (intelligence × tok/s × memory) for local models on consumer Macs at the
2093
- 24 GB and 32 GB budgets, defended against NON-OURS points: ours
2094
- {GPTQ-4bit, TQ-mixed} × mlx-bun; published {OptiQ-4bit, mlx-community
2095
- RTN-4bit} × {mlx-bun, mlx-lm}; cross-ecosystem anchor {GGUF Q4_K_M ×
2096
- llama.cpp/Ollama}. Still owed: quiet-box tps per arm (labeled
2097
- host/chip/RAM), peak footprint + max-context-that-fits per budget, the
2098
- GGUF anchor. The KV axis composes: `--kv-quant turbo` (k8v3) is the
2099
- context-headroom lever at fixed weight bpw. `scripts/turboquant/
2100
- farm-setup.sh` provisions a rented Apple-silicon worker for these runs.
2101
- - **Q campaign (sub-4 bpw):** Q3 passed its gate (finding 5); Q2b packed
2102
- format landed and measured (12.1 GiB, KL 0.1550 through the engine, 9.3
2103
- tok/s vs 18.9 on M1 Max — "Q2b measured"); the down_proj axis is settled the
2104
- OTHER way (input-dim coding buys +22% decode but reintroduces the raw-GSM
2105
- EOS cliff, 29/50 vs 44/50 strictly nested — the coded axis must be the
2106
- rotated one). Owed: a 2.75-budget arm
2107
- for the size axis; task columns on q2a/q2b for the ladder's completeness;
2108
- root-cause the rawGSM EOS cliff on the unrotated affine arm. Source bf16,
2109
- all Q artifacts, Hessians live on the external `/Volumes/MLX-Models` volume.
2110
- - **Engine follow-up from the M4 rows:** serve should scale
2111
- prefillChunkSize from fit.ts headroom automatically; prefill-rate
2112
- oracle comparison vs mlx-lm same-box.
2113
- - **KV-leg projector:** `KvScheme.bytesAt` bills turbo as bf16; a packed-
2114
- layout projector would let admission advertise the real window.
2115
- - **Queued post-campaign (GPU owned by certification until then):** DSpark×27B
2116
- Track A (confidence-scheduled verification on the stock MTP head) and
2117
- Track B (multi-token drafter on the TQ trunk; gate: beat MTP's 0.68
2118
- generalizing acceptance or drop); ORPO LoRA on the TQ 27B (QLoRA shape:
2119
- frozen 17 GB base + bf16 adapters; first step a one-layer-backward memory
2120
- probe). Designs live in docs/design/speculative-decoding.md §"27B program".
2121
-
2122
- ## Invariants (both legs)
2123
-
2124
- - Rotation never enters the runtime graph for weights; for KV it enters only
2125
- inside the cache class (dequantize-on-fetch or deferred un-rotation at the
2126
- attention site). L1 attention math stays unmodified.
2127
- - Quantization groups run along head_dim (KV) — token-axis surgery stays
2128
- byte-safe.
2129
- - Oracle-backed at the codec level (KV: vllm-metal goldens; weights: fold
2130
- parity vs stock mlx-lm on the folded bf16 model). Quality of a recipe is
2131
- a measured curve with host/chip/RAM labels, never inferred from ppl alone
2132
- — every finalist needs generative tasks (templated + raw GSM8K).
2133
- - Same seed for a trunk and its MTP companion; provenance persisted in
2134
- `optiq_metadata.json`.
2135
- - Comparisons are per-bpw-band and paired (same corpus, same items, same
2136
- scorer); no perf claims off a loaded box.
2137
-
2138
- ## History
2139
-
2140
- - 2026-06-12 — TurboQuant KV promoted from research path to Phase 13.
2141
- - 2026-07-06 — KV v1 landed end-to-end (codec, `TurboQuantKVCache`,
2142
- `--kv-quant turbo`, kv-store persistence, goldens vs vllm-metal); Gate 3
2143
- curve passed on MiniCPM5-1B; deferred inverse FWHT landed same day; the
2144
- weights leg noted as "Future".
2145
- - 2026-07-07 — review fixes: spec-lane exclusion (turbo was silently routed
2146
- into speculation), head-dim refusal at server start.
2147
- - 2026-08-17 — weights phase opened; W0 Llama fold proof (`rotate.ts`).
2148
- - 2026-08-18 — W1 corridor map, W2 streaming fold/quantize at 27B, W3/W4
2149
- curves + TQ-mixed artifact, W5a corrected-GPTQ matrix, W5c v3 27B run,
2150
- FINAL BOARD (v3 staged as mjriii/Qwen3.8-27B).
2151
- - 2026-08-19 — territory campaign + THE FRONTIER; W6.5 dogfood gate opened.
2152
- - 2026-08-20 — `WeightTransform` seam promoted into production convert
2153
- (`--rotate-weights`, `optiq_metadata.json` provenance); MTP serve lane
2154
- fixed; DeltaNet prefill leak fixed; M4 Pro 24 GB speed rows.
2155
- - 2026-08-23 — research scripts moved to `scripts/turboquant/`; this
2156
- consolidated doc.
2157
- - 2026-08-31 — Q0 KL-vs-bf16-teacher instrument (both stacks); transformers-5.8
2158
- checkpoint loader.
2159
- - 2026-09-01 — Q2 trellis codec + driver, rotation 2×2, Q2c LDLQ, Q3 k-map;
2160
- KL ladder above.
2161
- - 2026-09-02 — Q3 full recipe (rot + LDLQ + k-map 3.00) PASSED: KL 0.1553 at
2162
- 3.55 bpw, MMLU 88 / tGSM 48 / rawGSM 44; eval-carrier repack tool; LDLQ
2163
- loop-shadow bug fixed.
2164
-
2165
- ## Delayed row conversion and reusable precision boundaries
2166
-
2167
- `DelayedTurboQuantKVCache` implements the existing batchable cache and
2168
- rotated-value attention ports. It keeps serial row caches during a mixed
2169
- plain/TQ phase and invokes the existing maintenance operation before each
2170
- row's next append. `KvTensorRows` supplies positions and masks without
2171
- dummy tensor planes. Once every row converts, `BatchedTurboQuantKVCache`
2172
- owns the encoded rows. The scheduler invokes a generic preparation hook;
2173
- it does not implement threshold, codec or inverse-rotation logic.
2174
-
2175
- The rotated-value port can capture an output transform for its fetched
2176
- state. Plain value rows pass through unchanged, and TQ rows receive the
2177
- existing inverse rotation. Gemma carries that transform through its donor
2178
- KV consumers. Model projections and attention remain at B=N. Start-zero
2179
- layouts and kernel selection retain their existing paths.
2180
-
2181
- A cache's `minimumReusableOffset` records an irreversible precision
2182
- boundary. Delayed maintenance sets it to the actual conversion offset,
2183
- which can exceed the configured threshold when a prefill chunk crosses it.
2184
- Clone, row extraction and SSD metadata retain the bound. RAM/SSD selection
2185
- and ancestor supersession check it independently of physical trimmability.
2186
- Earlier plain donors remain reusable after a converted descendant appears.
2187
- Old TQ SSD headers lacking the bound conservatively use their stored offset.
2188
-
2189
- Focused tests cover exact mixed-row bytes and output transforms through
2190
- reordering, retirement and re-admission, plus RAM/SSD ancestor retention,
2191
- restart, continuation and old-header compatibility. Native seeded/logprob
2192
- and prefix gates accept positive thresholds via their test environment
2193
- switches. Shared Qwen MTP also uses the delayed layout. Its transaction
2194
- begins conversion from committed history before verification. A verify block
2195
- may cross the configured threshold; resolution converts at the retained
2196
- offset after rollback and before checkpoint publication, so rejected tokens
2197
- never set the precision boundary.
2198
- The draft provider retains its existing paired checkpoint format.
2199
-
2200
- Mixed rollback and final packed promotion preserve each row's physical left
2201
- padding. Re-aligning it based on another row's accepted count changes SDPA
2202
- reduction positions even when all live cache bytes match. Same-batch native
2203
- controls check every target layer and subsequent hidden rows after unequal
2204
- acceptance. Affine delayed speculation and the legacy serial TQ speculative
2205
- path remain excluded. This implementation changes no defaults.
2206
-
2207
- ### Wider split-K verification screen
2208
-
2209
- The current packed down-projection operation covers five through eight input
2210
- vectors. An isolated candidate extended that operation through 32 vectors,
2211
- using 8-, 16- or 32-row tiles while retaining the native split partition and
2212
- accumulation order. Scheduler and speculation policy were unchanged.
2213
-
2214
- Actual 2-, 3- and 4-bit artifact projections pass exact expanded-weight
2215
- controls at every new width and three input seeds on both Macs. Full Qwen
2216
- logits, recurrent/KV state and continuation match the unchanged eligibility
2217
- control at B1/B2/B4/B8 on both Macs. Call-count assertions prove the wider
2218
- kernels ran. Updated unit coverage includes wider partition tails and
2219
- noncontiguous inputs; both complete suites and typechecks pass.
2220
-
2221
- The alternating M4 prompt-lookup comparison preserves all requests but loses
2222
- concurrent throughput. This wider eligibility is not adopted. Future work
2223
- needs serving dispatch/cost attribution before additional tile tuning.
2224
- Measurements: benchmarks.md. Evidence and source manifest:
2225
- `reports/qwen38-closeout/composition-baseline/trellis-batch-width/`.