mlx-bun 0.0.13 → 0.3.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 (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -0,0 +1,1162 @@
1
+ # mlx-bun benchmark results (curated)
2
+
3
+ The durable, hand-maintained benchmark record. Raw per-run files
4
+ (`benchmarks-h2h-<date>-<machine>.md/.html`) are gitignored ephemera; the
5
+ structured backing record is the user-local eval DB
6
+ (`~/.cache/mlx-bun/evals.sqlite`). Promote a run into this file
7
+ deliberately when it becomes the new reference.
8
+
9
+ The optional `mlx-bun-isolated` arm runs the same CLI/model/request cells through
10
+ `--isolate`; select it alongside `mlx-bun` to compare transport cost. Its RSS
11
+ column sums the parent and descendant processes. This is aggregate process RSS,
12
+ not deduplicated physical memory; shared runtime pages may appear in both.
13
+
14
+ ## Running the benchmark
15
+
16
+ `bun scripts/bench-serve.ts all` is THE benchmark — one pass, real servers,
17
+ real paths, every number that matters. Per model × arm (mlx-bun@defaults ·
18
+ mlx-bun `--batch 1` [the control arm — `--no-serial` skips] · mlx-lm ·
19
+ mlx-bun-mixed · optiq-mixed) it measures decode tok/s (five fixed samples,
20
+ all retained; unstable runs flagged), TTFT cold (~1k, nonce-busted) and warm/cached (each stack's own
21
+ prompt cache), prefill tok/s, long-context prefill/TTFT/decode (ONE measured
22
+ prefill; decode sampled on 64 tok + 2 cached repeats), aggregate tok/s at 4
23
+ concurrent streams, peak RSS (sampled; undercounts GPU), and load→ready time.
24
+ The same cells compare decoded text from greedy probes of up to 64 tokens
25
+ between stacks of the same scheme, including the serial control vs mlx-lm.
26
+ Prompt-count inequality rejects a comparison as template/tokenizer drift;
27
+ matching counts and text are a smoke check, not proof of identical token IDs
28
+ or logits. Missing usage cannot produce a passing verdict. The engine's
29
+ pinned logit oracle remains the correctness gate.
30
+
31
+ ```sh
32
+ bun scripts/bench-serve.ts all # cpm5 + e4b + 12B + Qwen3.8-27B, all arms
33
+ bun scripts/bench-serve.ts all --no-serial # skip the --batch 1 control arm
34
+ bun scripts/bench-serve.ts all --models cpm5,qwen27b # subset
35
+ bun scripts/bench-serve.ts all --skip-context # drop the long-context leg
36
+ bun scripts/bench-serve.ts all --context 8192 # shorter context leg
37
+ ```
38
+
39
+ For an exact local quant use `--model-path <dir>` and optionally `--label`.
40
+ It replaces the registry selection and cannot be combined with `--models`.
41
+ `--dry-run` prints artifact metadata and server commands, with no preflight,
42
+ model load, database write or server process. Packed trellis skips stock
43
+ mlx-lm/optiq arms; explicitly requesting those arms fails before starting a
44
+ server. A fake-quant/8-bit carrier is a separate artifact and cannot establish
45
+ same-artifact packed performance or decode parity.
46
+
47
+ ```sh
48
+ bun scripts/bench-serve.ts all --model-path /path/to/quant --label qwen38-quant --dry-run
49
+ bun scripts/bench-serve.ts all --model-path /path/to/affine --arms mlx-bun-serial,mlx-lm --context 4096 --out reports/affine-h2h.md
50
+ bun scripts/bench-serve.ts all --model-path /path/to/packed --arms mlx-bun-serial --context 4096 --out reports/packed-baseline.md
51
+ bun scripts/bench/model-inventory.ts /path/to/affine /path/to/packed > reports/model-inventory.json
52
+ ```
53
+
54
+ `--workload-seed <block-id>` generates identical nonce-prefixed prompts for
55
+ every engine and artifact in that block, with distinct nonces for retries.
56
+ Thinking is pinned on for all chat measurements. Long-context filler uses a
57
+ fixed character estimate so token-count drift cannot silently change the
58
+ input on one engine. Record actual token counts and compare raw request hashes.
59
+ Use phase/attempt/index to distinguish a cold request from its identical warm
60
+ repeat; request hashes alone do not identify cache state.
61
+ For paired trials, alternate `--arms mlx-bun-serial,mlx-lm` and the reversed
62
+ order across blocks; give every block its own seed and `--out` path.
63
+
64
+ Configured serial experiments accept `--draft-model`, `--draft-kind`,
65
+ `--num-draft-tokens`, `--kv-quant` and `--prompt-cache`. These options require
66
+ `--arms mlx-bun-serial`; record default and oracle controls in separate runs.
67
+ The dry-run, raw JSON and Markdown report retain the settings and relevant
68
+ runtime overrides. No script under `reports/` is required to launch them.
69
+ For the current packed Qwen artifact on the M4 Pro, run this after closing
70
+ other workloads. It exercises the opt-in KV4/MTP/paired-prefix configuration
71
+ through the current checkout and writes a new dated report under `reports/`.
72
+
73
+ ```sh
74
+ MLX_BUN_TRELLIS_VARIANT=13 MLX_BUN_QWEN_SPEC_KV4=1 MLX_BUN_MTP_PROMPT_CACHE=1 MLX_BUN_RD_PREFILL_CHUNK=256 \
75
+ bun scripts/bench-serve.ts all \
76
+ --model-path "$HOME/models/Qwen3.8-27B-q3-trellis-ldlq-k300-packed-interleave2-rd" \
77
+ --arms mlx-bun-serial \
78
+ --draft-model "$HOME/models/Qwen3.8-27B-MTP-folded-rtn4-g64-rd" \
79
+ --draft-kind mtp --num-draft-tokens 2 --kv-quant 4 --prompt-cache 4 \
80
+ --context 4096 --tokens 192 --workload-seed pr47-block-0
81
+ ```
82
+
83
+ Append `--dry-run` to inspect the command first. This serving suite is separate
84
+ from the Luke Kanban task and does not establish its task-time speedup. The
85
+ portable multi-machine HTML report in the performance plan remains open;
86
+ this entry point currently writes Markdown and JSON.
87
+
88
+ `--diagnostic` explicitly permits a loaded-machine serving run. It records
89
+ the preflight snapshot and writes `*-serve-diagnostic` DB rows, which cannot
90
+ serve as canonical results. Server children use the invoking Bun executable,
91
+ so an isolated runtime comparison actually changes the server runtime too.
92
+
93
+ The Markdown report has a `<report>.md.json` companion containing all chat
94
+ requests, results, failures and retries, plus config/source-diff hashes and
95
+ server commands. Schema 4 also hashes a sorted manifest of tracked and
96
+ untracked source files at startup and save time, so new local kernels cannot
97
+ escape source identity. External native libraries and weights need their own
98
+ manifests. Failed attempts include the child's stderr tail and process
99
+ status; a successful retry keeps the recovered failure visible. It is saved
100
+ after each completed or failed cell. The report
101
+ separately records total request wall time and actual-output throughput.
102
+ The decode columns use the first-to-last visible SSE interval: bursty chunks
103
+ can distort that interval, so it is not a GPU timing. Token throughput requires
104
+ valid server usage; chunk counting is no longer a fallback. Raw results also
105
+ record response-header, first-byte and first-SSE-event latency, then every
106
+ content/reasoning/tool-output event arrival. Event gaps measure stream
107
+ delivery, not individual token latency. Tool-only streams have an output TTFT.
108
+ Malformed/error SSE and responses without a finish reason or `[DONE]` fail
109
+ the measurement. Match output counts, finish reasons and text before
110
+ interpreting a speed difference. The exported `measureCompletionRequest`
111
+ helper applies the same timing and stream-validation contract to raw
112
+ `/v1/completions` requests, without chat-template preparation.
113
+
114
+ The inventory reads shard headers and config only, reconstructs matrix
115
+ shapes including trellis axis-0 storage, and counts actual tensors rather
116
+ than duplicate config aliases. Its matrix effective-bpw figure includes
117
+ scales/biases but excludes norms, convolutions and sidecars; it is explicitly
118
+ not whole-model bpw or peak memory. Config/index/layout hashes do not hash
119
+ weight payloads. Use existing shard hashes or hash weights outside timed runs
120
+ when certifying artifact identity. The complete Qwen campaign is in
121
+ [the performance program](../design/decode-speed-program.md#7-qwen38-27b-research-program).
122
+
123
+ For native engine isolation, `scripts/bench/native.ts` runs dense Qwen3.5/3.8
124
+ with bf16 attention KV, f32 recurrent state and greedy decoding. Supply a
125
+ frozen JSON array of prompt token IDs and the exact local artifact to both
126
+ stacks. Each request starts with a fresh cache; warmups and every measured
127
+ sample are retained. Reports include actual output IDs, EOS policy, TTFT,
128
+ wall time through cache cleanup/GPU synchronization, memory and source pins.
129
+ They record the effective wiring policy and active/cached memory around each
130
+ request. The oracle worker enters mlx-lm's normal scoped wired limit; compare
131
+ that policy with Bun's model-sized scope before interpreting a ratio.
132
+ `--clear-before-request` is a separate allocator-cache experiment on both
133
+ stacks, with cleanup included in wall time. Keep it fixed within a pair;
134
+ it does not clear model weights or substitute for a fresh inference cache.
135
+ Stock mlx-lm rejects packed trellis. This worker uses the pinned oracle
136
+ environment and never starts a server or downloads a model.
137
+
138
+ ```sh
139
+ bun scripts/bench/native.ts --model-path /path/to/affine --prompt-ids reports/prompt-ids.json --stack mlx-bun --json reports/native-bun.json --dry-run
140
+ bun scripts/bench/native.ts --model-path /path/to/affine --prompt-ids reports/prompt-ids.json --stack mlx-lm --json reports/native-oracle.json
141
+ ```
142
+
143
+ Alternate stack order across predeclared process pairs. Check token IDs,
144
+ output counts and finish reasons before comparing request wall times.
145
+ `--diagnostic` permits a failed quiet-machine preflight and records that
146
+ failure. Native results remain diagnostic, including on a quiet machine;
147
+ they do not establish HTTP throughput, task quality or full logit parity.
148
+ The repaired legacy `bench-h2h.ts direct` command delegates to this worker,
149
+ requires `--models` and bf16 KV, and writes only `*-native-diagnostic` DB
150
+ rows with raw report paths. Its rates use actual emitted tokens and all
151
+ fixed samples. Use the worker directly to avoid registry ambiguity.
152
+
153
+ `all` runs the clean-machine preflight first (refuses headline numbers from
154
+ a loaded or swapped box) and holds `caffeinate` for the pass. Quotable
155
+ numbers and ratios need a quiet machine; loaded runs are diagnostic only.
156
+ Results land in the eval DB (`~/.cache/mlx-bun/evals.sqlite`) plus dated
157
+ Markdown and JSON reports under `reports/` by default. Developer lever A/Bs are NOT benchmarks — run
158
+ `scripts/bench-levers.ts <faithful-matrix|fused-prefill|compiled-decode>` or
159
+ `scripts/bench-matrix.ts <modes|features>` directly when touching those paths.
160
+
161
+ There are **three categorically different kinds of measurement** — kept in
162
+ separate sections because they answer different questions:
163
+
164
+ 1. **Parity** — are we *bit-exact* with the upstream oracle? (pass/fail)
165
+ 2. **Performance** — *numbers* under like-for-like config (tok/s, memory…).
166
+ 3. **Quality** — for non-bit-exact optimizations, what does the speed cost
167
+ in output quality? (6-test mean + KL)
168
+
169
+ **Default machine for older rows:** Apple M4 Pro, 24 GB unified
170
+ (`Joshs-MBP-2025`), ~273 GB/s. Newer subsections name their machine explicitly.
171
+ **Oracle toolchain:** Bun 1.3.14; Python 3.13.5 with mlx 0.31.2,
172
+ mlx-lm 0.31.3, mlx-optiq 0.2.1. Numbers below are the 2026-06-14
173
+ cleared-machine run (commits `97457e4` / `d1e0296`), preflight-gated,
174
+ median-of-N with warmups discarded.
175
+
176
+ **Model legend** (registry hash → repo):
177
+
178
+ | hash | model |
179
+ |---|---|
180
+ | `664aabaed233` | `MiniCPM5-1B-OptiQ-4bit` (sub-GB starter) |
181
+ | `fcdb12d740cd` | `gemma-4-e4b-it-OptiQ-4bit` |
182
+ | `5b1101065d20` | `gemma-4-12B-it-OptiQ-4bit` |
183
+ | `dbfd2a779b03` | `gemma-4-26B-A4B-it-OptiQ-4bit` (MoE) |
184
+
185
+ > **Legend corrected 2026-06-15.** An earlier revision had the gemma
186
+ > hashes cycled (`5b…`→e4b, `dbfd…`→12B, `fcdb…`→26B). The mapping above is
187
+ > the authoritative one from `tests/support/paths.ts` (`SNAPSHOT`=`5b…`=12B,
188
+ > `SNAPSHOT_26B`=`dbfd…`=26B) and the e4b snapshot hash used across
189
+ > `tests/*.test.ts` (`fcdb…`=e4b), corroborated by on-disk weight size
190
+ > (e4b 7.0G · 12B 8.4G · 26B 18G). The **Performance** rows below were
191
+ > labeled by the old legend; each gemma row has been relabeled to its true
192
+ > model, re-identified by its gen-peak / steady-RSS fingerprint —
193
+ > e4b≈6.6 GB, 12B≈9.0 GB, 26B≈17.7 GB — which is stable across runs. The
194
+ > row *data* was correct; only the model labels moved.
195
+
196
+ ---
197
+
198
+ ## 1. Parity (porting correctness) — bit-exact vs the oracle
199
+
200
+ The correctness oracle. Each cell is **bit-for-bit** logit parity against
201
+ the upstream reference under matched config, proven by the test suite
202
+ (regenerated only by `scripts/regen-*.ts` against the oracle venv). This
203
+ is the gate the Performance/Quality numbers are only meaningful *under*.
204
+
205
+ | model | L1: mlx-lm, standard (bf16) KV | L2: mlx-optiq, mixed-precision KV | proof |
206
+ |---|---|---|---|
207
+ | MiniCPM5-1B | ✓ 100/100 logit vectors | ✓ 100/100 logit vectors | `tests/parity/minicpm5-parity.test.ts`, `tests/parity/minicpm5-kv-parity.test.ts` |
208
+ | gemma-4-e4b | ✓ | ✓ | `tests/parity/parity.test.ts`, `tests/parity/kv-quant.test.ts` |
209
+ | gemma-4-12B | ✓ | ✓ | `tests/parity/parity.test.ts`, `tests/parity/kv-quant.test.ts` |
210
+ | gemma-4-26B | ✓ | ✓ (mixed per-layer scheme) | `tests/parity/parity-26b.test.ts`, `tests/parity/rotating-kvq.test.ts` |
211
+
212
+ Fused quantized-attention prefill is separately bit-exact against
213
+ optiq's reference (`tests/parity/fused-sdpa.test.ts`).
214
+
215
+ ### GLM-5.2 direct-Colibri oracle closure — M1 Max 32 GB
216
+
217
+ The direct-container port uses pinned Colibri, rather than mlx-lm, as its
218
+ implementation oracle. The public artifact is
219
+ `mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp@3cc8db9`; direct component and
220
+ G0 controls use Colibri `44e489b`, while the later official DSA replay is
221
+ pinned to `ecade075` with indexers sourced from
222
+ `zai-org/GLM-5.2-FP8@ba978f7d`.
223
+
224
+ | gate | result | durable proof |
225
+ |---|---|---|
226
+ | tiny converted Q4 trajectory | 32/32 greedy tokens exact with `IDOT=0`; all 8,192 logits max abs `1.3113e-6`, RMSE `2.7423e-7` | `fixtures/colibri-glm52/tiny-teacher-forcing.json` |
227
+ | production Q4/router cells | layer-0 SwiGLU max abs `5.2387e-9`; layers 3/77 exact ordered top-8 | `fixtures/colibri-glm52/production-probe.json` |
228
+ | real-model oracle | 140 GLM/MLA/router/MTP/KV records reproduced byte-for-byte twice; both heads predict teacher token 16 | `fixtures/colibri-glm52/real-model-oracle.json` |
229
+ | full target trajectory | all 128 cold/warm, MTP-on/off target token IDs identical; first 64 also match direct Colibri | machine-local `runs/colibri-g5/summary.json` |
230
+ | first-sparse DSA | all 21 official score rows replay to exact ordered positions and float32 thresholds at context 2,049; both engines emit `[264,264]` | `~/.cache/mlx-bun/evidence/glm52-dsa-stage0-2026-08-17/` |
231
+
232
+ These are quality-preserving gates: checkpoint precision, true top-8 routing,
233
+ and the 21-full/57-shared DSA schedule remain unchanged. Consequently there is
234
+ no KL/eval tradeoff row in section 3 for this path.
235
+
236
+ **Served-surface parity (2026-07-07, prefill tail-split fix):** the two
237
+ serve-bench parity residuals (cpm5 + 12B `/v1/completions` probe ✗ on the
238
+ 07-07 run) are closed — with the oracle's step-0 prefill convention
239
+ adopted (drain to len−1, step 0 from an L=1 forward of the last prompt
240
+ token; `MLX_BUN_PREFILL_TAIL_SPLIT`), live HTTP probes are
241
+ **byte-identical** to `mlx_lm.server`/optiq serve for MiniCPM5-1B,
242
+ gemma-4-e4b, AND gemma-4-12B, on completion + chat probes, in both the
243
+ unified (`--batch 8` default) and `--batch 1` lanes; script-level A/B
244
+ shows 64/64 token ids + top-2 logprob values identical per step
245
+ (`serve-parity-probe.ts (deleted; git history)`,
246
+ `step0-top2-dump.ts (deleted; git history)`).
247
+
248
+ ---
249
+
250
+ ## Methodology change (2026-07-05)
251
+
252
+ The primary benchmark is now **`bun scripts/bench-serve.ts all` → `scripts/bench-serve.ts`**:
253
+ real servers on real paths — the mlx-bun arms spawn the ACTUAL CLI at its
254
+ actual defaults (the old harness used a bench-local wrapper, since deleted),
255
+ and every metric arrives over HTTP as a user would see it. One server per
256
+ cell yields: decode tok/s, cold TTFT (~1k, nonce-busted), warm/cached TTFT
257
+ (each stack's own prompt cache), prefill tok/s, long-context
258
+ prefill/TTFT/decode (ONE measured prefill; decode sampled on 64 tokens),
259
+ aggregate tok/s at 4 concurrent streams, and load→ready time. Context
260
+ lengths are recorded from usage.prompt_tokens (measured, not requested).
261
+ Engine-level questions (in-process kernel parity, gen-peak memory,
262
+ kill-switch A/Bs) live behind `bun scripts/bench-serve.ts all --engine`. Numbers below this
263
+ note predate the redesign; the next quiet-machine pass supersedes them.
264
+
265
+ ## 2. Performance — like-for-like numbers
266
+
267
+ Two comparison axes: **vs the oracles**, and **our optimized path vs our
268
+ own bit-exact compat path** (does an optimization beat the baseline it
269
+ diverges from). Within mlx-bun, `bf16` is the L1-compatible path and
270
+ `mixed` is the L2-compatible path; both are bit-exact, so the bf16↔mixed
271
+ delta is the first "our-vs-our" axis. Lab experiment rows (no external
272
+ oracle; KL/eval-gated) land here once one beats the L1 baseline in a
273
+ paired A/B — none recorded yet (the 2026-07-05 candidates were deleted).
274
+
275
+ ### Standard serve matrix — M4 Pro 24 GB (2026-09-08, incomplete acceptance)
276
+
277
+ Josh ran `bun scripts/bench-serve.ts all` at clean commit `86738ac` on
278
+ `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, Bun 1.4.0, with the matching
279
+ MLX 0.32.2 reference. Quiet preflight passed. There were no runtime overrides;
280
+ the workload used `bench-serve-v2`, thinking enabled, five 192-token decode
281
+ requests and a requested context target of 16,384. The actual context probes
282
+ contained 9,062 MiniCPM tokens and 9,589 Gemma tokens. This is one ordered
283
+ suite, not an alternating before/after optimization comparison.
284
+
285
+ | Model | Default mlx-bun decode tok/s | mlx-lm decode tok/s | Default mlx-bun request time | mlx-lm request time | Request-time reduction |
286
+ |---|---:|---:|---:|---:|---:|
287
+ | MiniCPM5-1B | 278.65 | 223.55 | 0.710 s | 0.936 s | 24.2% — output mismatch |
288
+ | Gemma4-e4b | 57.86 | 53.63 | 3.402 s | 3.810 s | 10.7% |
289
+ | Gemma4-12B | 26.14 | 25.40 | 7.576 s | 7.969 s | 4.9% |
290
+ | Qwen3.8-27B 4/8-bit winner | 14.75 | 14.19 | 13.814 s | 14.523 s | 4.9% — output mismatch |
291
+
292
+ The table uses medians of the same five requests, all with exactly 192 output
293
+ tokens. Request hashes, input/output counts and cached-token counts match
294
+ between these arms. Both Gemma models also match all five timed output texts
295
+ and both short parity probes. MiniCPM and Qwen differ on all five timed
296
+ outputs despite matching counts; Qwen's separate 64-token probes match, while
297
+ MiniCPM's chat probe diverges. Their timing rows remain observations pending
298
+ the exact-token/logit investigation. The Gemma12B reference command invokes
299
+ OptiQ's model registration before its mlx-lm serving path.
300
+
301
+ For Gemma e4b, cold/cached TTFT is 559/72 ms versus 707/212 ms in the
302
+ reference, and the approximately 1K prefill estimate is 1,199 versus 947
303
+ tok/s. For Gemma 12B those values are 2,531/157 ms versus 2,677/333 ms and
304
+ 265 versus 250 tok/s. The serial controls finish the same short requests in
305
+ 3.360 s and 7.514 s, respectively. Cached TTFT is one warm sample per cell.
306
+
307
+ Acceptance is incomplete. Qwen hits Metal out-of-memory errors in both the
308
+ approximately 1K and context phases, in default and serial serving. Its
309
+ reference recovers an initial 1K timeout, then fails the context phase and
310
+ skips concurrency. MiniCPM and Gemma12B each report missing SSD snapshots on
311
+ the first restart-flush attempt in default and mixed serving; retries succeed.
312
+ Mixed-KV rows are not compared for L1 identity against bf16 KV. The complete
313
+ report retains eleven phase-failure records, including recovered failures.
314
+
315
+ The Qwen artifact is the registry's 4/8-bit winner, not the required 12.14 GiB
316
+ packed Trellis target. No MTP draft was configured. These numbers neither
317
+ replace the Trellis/KV4/MTP measurements nor establish a Kanban task-time gain.
318
+ Raw evidence: `reports/benchmarks-serve-2026-09-08-Joshs-MBP-2025.md` and its
319
+ `.md.json` companion; source hashes are unchanged across the run.
320
+
321
+ The SSD follow-up at `f144516` fixes flush ordering: an ancestor removed from
322
+ RAM can be covered by a longer trimmable snapshot written later in that same
323
+ flush. After all writes settle, the coordinator checks committed coverage
324
+ again and keeps uncovered prefixes dirty. The regression fails before the
325
+ change and all 29 SSD tests pass afterward. The same M4 Pro repeats pass all
326
+ phases on the first attempt for MiniCPM and Gemma12B in both default and mixed
327
+ serving, restoring 9,061 and 9,588 tokens after restart. Source hashes stay
328
+ fixed in both repeats. Default-arm timed request hashes and all ten output
329
+ texts match the original run. The original failure records remain intact;
330
+ this follow-up does not resolve their separate cross-oracle output differences.
331
+ Evidence: `reports/qwen38-rd/pr47-ssd-followup.md.json` and
332
+ `reports/qwen38-rd/pr47-ssd-followup-mixed.md.json`.
333
+
334
+ ### Current standard serve matrix — M1 Max 32 GB (2026-08-22)
335
+
336
+ Real-server HTTP matrix on commit `4103ae1`, with the canonical preflight
337
+ passing at the start of both runs: zero swap, ample free memory, and no large
338
+ foreign process. The Qwen extension ended with 944 MiB of inactive swap,
339
+ below the harness's 3 GiB mid-run rejection threshold. No benchmark phase
340
+ failed. Raw gitignored reports:
341
+ `benchmarks-serve-2026-08-22-Joshs-MacBook-Pro-2.md` and
342
+ `benchmarks-serve-2026-08-22-Joshs-MacBook-Pro-2-qwen27b.md`.
343
+
344
+ | model | arm | short decode tok/s | decode @ ~15.8k tok/s | aggregate ×4 tok/s | restart TTFT ms (cached tokens) |
345
+ |---|---|---:|---:|---:|---:|
346
+ | MiniCPM5-1B | mlx-bun | **267.7** | 122.0 | **420.1** | 207 (15,817) |
347
+ | | mlx-bun serial | 266.4 | 124.6 | 245.9 | 182 (15,889) |
348
+ | | mlx-lm | 179.7 | 96.2 | 181.4 | 10,355 (0) |
349
+ | | mlx-bun mixed | 194.2 | **127.0** | 397.5 | **130 (15,815)** |
350
+ | gemma-4-e4b | mlx-bun | **61.5** | 43.7 | 20.7 | 18,863 (4) |
351
+ | | mlx-bun serial | **61.5** | 43.1 | 59.7 | **661 (15,940)** |
352
+ | | mlx-lm | 52.8 | 42.8 | 72.3 | 20,187 (0) |
353
+ | | mlx-bun mixed | 57.3 | **49.0** | **97.4** | 20,510 (0) |
354
+ | gemma-4-12B | mlx-bun | **29.6** | 28.3 | 5.6 | 85,180 (4) |
355
+ | | mlx-bun serial | **29.6** | **28.4** | 27.5 | **1,338 (15,866)** |
356
+ | | mlx-lm | 27.1 | 25.8 | 32.5 | 89,504 (0) |
357
+ | | mlx-bun mixed | 28.7 | 24.4 | **38.7** | 93,068 (6) |
358
+ | Qwen3.8-27B winner | mlx-bun | **18.5** | 16.5 | 19.3 | 173,215 (0) |
359
+ | | mlx-bun serial | **18.5** | **16.7** | 15.8 | 172,400 (0) |
360
+ | | mlx-lm | 16.5 | 14.9 | 18.3 | 177,066 (0) |
361
+ | | mlx-bun mixed | 18.1 | 14.9 | **19.4** | **3,328 (15,112)** |
362
+
363
+ - All four models passed 64-token greedy completion and chat parity for
364
+ mlx-bun bf16 versus mlx-lm, and unified scheduling versus `--batch 1`.
365
+ - Qwen's standard mlx-bun arm beat mlx-lm by 12.1% at short decode and
366
+ 10.7% at long-context decode. The mixed arm did not beat bf16 on decode;
367
+ its useful result was restoring the full 15,112-token cache after restart.
368
+ - The e4b and 12B unified arms restored only four cached tokens after restart,
369
+ while their serial controls restored the full cache. This is a real
370
+ scheduler/SSD-persistence regression and explains their poor aggregate rows.
371
+ Qwen bf16 restored no cache in either scheduler mode.
372
+ - Qwen mixed KV is a Lab characterization, not an L2 correctness claim. Its
373
+ policy is copied from the official same-topology Qwen3.6 OptiQ artifact;
374
+ Qwen3.8 has no model-specific mixed-KV oracle yet. Its 15,278 MB sampled peak
375
+ RSS also failed the harness's `mixed < bf16` diagnostic, so the run proves
376
+ that the policy loads and serves, but not that KV quantization was effective.
377
+
378
+ #### Bun 1.4.0 repeat
379
+
380
+ The full matrix repeated after upgrading from Bun 1.3.14 to 1.4.0. Starting
381
+ state was 401 MiB inactive swap, 93% free memory, load 3.7, and no large
382
+ foreign process, which passed the canonical preflight. All completion, chat,
383
+ and unified-versus-serial parity probes passed again. Core mlx-bun performance
384
+ was stable; the largest one-run movements were MiniCPM aggregate +5.0% and
385
+ Qwen long-context decode +3.0%, neither promoted as a Bun speed claim without
386
+ repeats.
387
+
388
+ | model | engine | short decode tok/s | short prefill tok/s | long decode tok/s | warm TTFT ms | aggregate ×4 tok/s |
389
+ |---|---|---:|---:|---:|---:|---:|
390
+ | MiniCPM5-1B | mlx-bun | **265.8** | **2,576** | **124.2** | **26** | **441.3** |
391
+ | | mlx-lm | 177.0 | 1,907 | 96.5 | 86 | 185.8 |
392
+ | gemma-4-e4b | mlx-bun | **61.7** | **868** | **43.1** | **39** | 21.2 |
393
+ | | mlx-lm | 52.4 | 676 | 42.5 | 268 | **72.4** |
394
+ | gemma-4-12B | mlx-bun | **29.7** | **191** | **28.4** | **77** | 6.0 |
395
+ | | mlx-lm | 26.7 | 181 | 25.3 | 388 | **33.4** |
396
+ | Qwen3.8-27B winner | mlx-bun | **18.6** | 64 | **17.0** | **116** | **19.5** |
397
+ | | mlx-lm | 16.5 | **85** | 14.8 | 284 | 18.6 |
398
+
399
+ The e4b and 12B aggregate losses remain contaminated by the SSD durability
400
+ race. Their unified arms restored 2 and 4 tokens; serial restored 15,939 and
401
+ 15,794. Qwen's short-prefill loss is different: both mlx-bun schedulers lose
402
+ at the roughly 754-token shape, while sustained prefill reaches 87 tok/s at
403
+ 15.1k versus mlx-lm's 88. This points to fixed graph-build or shape overhead,
404
+ not a slower sustained prefill kernel. Split timing is still required before
405
+ assigning the cause.
406
+
407
+ ### Colibri G1/G3 component matrix — M1 Max 32 GB
408
+
409
+ Cleared-machine run on 2026-07-30, commit `47c4d6d`, Bun 1.3.14, pinned
410
+ Colibri `44e489b`, public artifact revision `3cc8db9`, ten warmups and fifteen
411
+ measured samples. Values are synchronized median milliseconds at identical
412
+ production shapes; every arm passed its correctness oracle. These are
413
+ component timings, not end-to-end generation claims.
414
+
415
+ | production-shape cell | direct Colibri Metal | selected mlx-bun path | decision |
416
+ |---|---:|---:|---|
417
+ | Q4 dense decode M=1 | 0.302 | 1.372 stock MLX | stock MLX (only mlx-bun dense candidate) |
418
+ | Q4 dense prefill M=32 | 1.286 | **1.030 stock MLX** | stock MLX |
419
+ | routed SwiGLU decode, top-8 M=1 | **1.401** | 4.282 custom Metal | custom Metal; 16.0% faster than stock MLX's 5.099 ms |
420
+ | routed SwiGLU ragged M=11/23 experts | **10.851** | 18.100 stock MLX | stock MLX |
421
+ | routed SwiGLU prefill M=32/64 experts | **32.906** | 45.558 stock MLX | stock MLX |
422
+ | absorbed MLA decode, position 128 | **1.014** | 11.506 stock MLX | stock MLX; largest remaining component gap |
423
+
424
+ For the selected custom decode path, max absolute delta versus stock is
425
+ `2.33e-9`, relative RMSE `5.56e-7`, and cosine
426
+ `0.9999999999998354`. A separate three-warmup/eleven-sample run also selected
427
+ custom Metal by 5.4%. Swap was unchanged at 339.25 MiB. Matched idle-power
428
+ arms (baseline, 1, 2, and 4 native workers, repeated in reverse order) show no
429
+ monotonic CPU/GPU/package-power increase, proving the condition-variable
430
+ workers are passive; two workers remain the default. Raw gitignored reports:
431
+ `runs/colibri-g1/*matrix*-2026-07-30.json` and
432
+ `runs/colibri-g1/passive-worker-power*-2026-07-30.json`.
433
+
434
+ ### Colibri G4 serial native MTP — M1 Max 32 GB
435
+
436
+ Production-artifact separate-process A/B on 2026-07-30, Bun 1.3.14, pinned
437
+ Colibri `44e489b`, public artifact revision `3cc8db9`, greedy gamma=3, 32-token
438
+ prompt and 64 generated tokens. Both arms reproduced the same direct-Colibri
439
+ 64/64 target-token trajectory. Generation wall time is the comparison metric;
440
+ the probe's prefill/decode sub-buckets place the first sample on different
441
+ sides of that boundary and are therefore not compared.
442
+
443
+ | arm | generation wall | wall throughput | target/verify forwards | draft acceptance |
444
+ |---|---:|---:|---:|---:|
445
+ | MTP off | 834.172 s | 0.0767 tok/s | 63 continuation | — |
446
+ | MTP on | **675.654 s** | **0.0947 tok/s (1.235x)** | **31 verify (32 saved)** | 32/92 |
447
+
448
+ MTP-on emitted 2.065 tokens per verify forward and reduced end-to-end
449
+ generation time by 19.0%. Its direct-oracle acceptance prefix was exact for
450
+ the tie-free first four rounds `[1,1,1,0]` (eight emitted tokens; minimum
451
+ first-draft margin 3.5675). Later acceptance is intentionally non-gating
452
+ across engines because direct Colibri's float64 RMSNorm reduction and MLX's
453
+ float32 graph produce different recurrent MTP hidden states while preserving
454
+ all target tokens. The machine was not swap-cleared, so the
455
+ 14,679,224,320-byte completed MTP-on physical footprint is not a G5 memory
456
+ claim. Stable record:
457
+ `fixtures/colibri-glm52/g4-native-mtp-e2e.json`.
458
+
459
+ ### Colibri G5–G7 full-model productization — M1 Max 32 GB
460
+
461
+ Final curated result for the streamed runtime. Bun 1.3.14, 32 GiB unified
462
+ memory, 25 GiB process ceiling, batch 1, 4,096-token supported context, 128
463
+ generated tokens, greedy decoding, true top-8, and quality-preserving defaults.
464
+ The G5 before/after run is 2026-08-15; G6 learning telemetry is a three-repeat
465
+ paired run on 2026-08-16; the DSA and API gates are 2026-08-17.
466
+
467
+ #### Resource contract
468
+
469
+ The current artifact-aware preflight, including the locally installed stock
470
+ DSA indexer overlay, reports:
471
+
472
+ | resource | bytes | GiB |
473
+ |---|---:|---:|
474
+ | full artifact on disk (streamed, not resident) | 383,739,826,712 | 357.39 |
475
+ | resident non-expert weights + DSA indexers | 11,074,469,760 | 10.31 |
476
+ | main Q4 expert slab (139 slots) | 2,632,646,656 | 2.45 |
477
+ | MTP Q8 expert slab (25 slots) | 945,356,800 | 0.88 |
478
+ | target + MTP compressed KV | 789,577,728 | 0.74 |
479
+ | reconstructed KV + verify + allocator/Bun/safety reserves | 5,910,612,992 | 5.50 |
480
+ | **planned process** | **21,352,663,936** | **19.89 / 25.00** |
481
+ | **process/macOS headroom** | **5,490,881,664** | **5.11** |
482
+
483
+ The original G5 measurement preceded the 197,202,400-byte stock indexer
484
+ overlay and planned 21,111,440,128 bytes. The overlay raises the current
485
+ preflight by 241,223,808 bytes but does not alter the short-context trajectory
486
+ or the observed G5 footprints below.
487
+
488
+ > **Measurement outcome:** the requested before/after observation closed the
489
+ > 32 GB fit question, but did **not** satisfy the harness's stricter
490
+ > zero-compression/zero-swap contract. Peak physical footprint stayed at or
491
+ > below 14,807,789,616 bytes (13.791 GiB), while maximum system/task compressor
492
+ > growth was 4,402,905,088 / 1,939,537,920 bytes; MTP-off observed 7,143,424
493
+ > bytes of swapout and MTP-on observed zero. The source result is correctly
494
+ > labeled `observed`, not `pass`.
495
+
496
+ #### Cold/warm MTP and memory
497
+
498
+ | arm / turn | decode tok/s | end-to-end tok/s | final physical footprint |
499
+ |---|---:|---:|---:|
500
+ | MTP off · cold | 0.1330 | 0.1274 | 13,490,515,008 B |
501
+ | MTP off · warm | 0.1190 | 0.1139 | 13,510,634,560 B (+19.2 MiB) |
502
+ | MTP on · cold | 0.1557 | 0.1456 | 14,673,342,512 B |
503
+ | MTP on · warm | **0.1577** | **0.1487** | 14,697,574,448 B (+23.1 MiB) |
504
+
505
+ MTP-on accepted 72/166 drafts over 56 verify forwards on each turn. Warm
506
+ end-to-end throughput was 1.306x MTP-off. It is also only 55% of the rounded
507
+ same-machine direct-Colibri MTP-on control (0.27 tok/s), and 0.1487 tok/s is
508
+ 7.43% of the aspirational 2 tok/s target—a **13.45x** remaining gap. The
509
+ aspiration is not a release gate or a `fit` prediction.
510
+
511
+ #### Expert delivery and policy decisions
512
+
513
+ The replicated G6 control's median warm turn read exactly
514
+ 1,974,949,363,712 logical bytes from the expert artifact, or
515
+ 15.429291904 decimal GB per generated token. Its hit rate was 1.6597%; median
516
+ main-tier disk-service p95 was 90.98 ms, foreground-wait p95 92.66 ms, and
517
+ expert-layer-forward p95 167.84 ms. This is the measured reason the runtime is
518
+ disk/serialization-bound rather than compute-bound.
519
+
520
+ | MTP-on policy (three paired repeats) | warm hit rate | disk GB/token | warm e2e tok/s | decision |
521
+ |---|---:|---:|---:|---|
522
+ | control | 1.66% | 15.429 | **0.149** | default |
523
+ | startup auto-pin | 9.62% | 14.191 | 0.143 | off: 4.06% slower, +3.337 GiB footprint |
524
+ | auto-pin + live LFRU | 9.62% | 14.191 | 0.148 | off: zero swaps; no benefit beyond run-order noise |
525
+
526
+ PILOT measurement found 69.90% next-layer top-8 precision/recall, but advisory
527
+ `PILOT_K=4` left demand bytes unchanged and reduced warm throughput to 0.9746x.
528
+ Two-step correction improved recall to 73.01% while reducing warm throughput
529
+ 10.13%. All learning/prediction/hint policies therefore remain off by default.
530
+
531
+ #### DSA and served API
532
+
533
+ The paired DSA matrix measured 24 eligible fresh-process cells (2K/8K × DSA
534
+ off/on × MTP off/on × three repeats), all with exact cold/warm/repeat/MTP
535
+ tokens. Positive decode delta means DSA was faster; negative wall delta means
536
+ less total time.
537
+
538
+ | context | MTP | paired median decode delta | paired median wall delta | decision |
539
+ |---:|---|---:|---:|---|
540
+ | 2,048 | off | -2.80% | +4.14% | no speed claim |
541
+ | 2,048 | on | -32.90% | +20.95% | regression |
542
+ | 8,192 | off | +12.38% | -1.89% | below 5% total-wall win gate |
543
+ | 8,192 | on | -34.33% | +8.19% | regression |
544
+ | 32,768 | off/on | not run | not run | ineligible: 27.320/28.540 GiB exceeds 25 GiB |
545
+
546
+ The checkpoint's 21-full/57-shared schedule remains a semantic requirement,
547
+ but no DSA product-speed claim is made. Stage-2 manifest SHA-256:
548
+ `90b3fe4ed53714604b7a747991b3bb1b87aedbf57a139915065f5b4be42cda38`.
549
+
550
+ Finally, the fresh real-artifact G7 smoke returned HTTP 200 with correct
551
+ envelopes for chat completions, text completions, Anthropic Messages, and
552
+ OpenAI Responses; SSE used `text/event-stream`, emitted four events, ended in
553
+ `[DONE]`, and reported the truthful `serial+spec` lane. Health, discovery,
554
+ exact-plan stats, and post-run idle rows also passed. This is protocol/API
555
+ evidence, not a throughput benchmark.
556
+
557
+ Primary raw records: machine-local `runs/colibri-g5/{summary,mtp-on,mtp-off}.json`,
558
+ `runs/colibri-g6-learning-shakeout-2026-08-15/summary.json`, and
559
+ `~/.cache/mlx-bun/evidence/glm52-dsa-stage2-2026-08-17/`.
560
+
561
+ ### Served (warm) — the path agents actually use
562
+
563
+ decode tok/s · TTFT ms · server-ready s · steady RSS GB
564
+
565
+ | model | mlx-bun (mixed) | mlx-bun (bf16) | mlx-lm (bf16) | optiq (mixed)† |
566
+ |---|---|---|---|---|
567
+ | MiniCPM5-1B | **252.9** · 34 · 0.17 · 1.22 | — | — | 223.6 · 64 · 0.84 · 1.82 |
568
+ | gemma-4-e4b | 55.7 · 44 · 0.36 · 7.14 | **57.3** · 48 · 0.36 | 53.5 · 218 · 0.98 · 7.55 | 53.4 · 221 · 0.78 · 7.53 |
569
+ | gemma-4-12B | **25.9** · 85 · 0.38 · 9.46 | — | — | 25.5 · 326 · 1.24 · 9.86 |
570
+ | gemma-4-26B | 54.2 · **45** · 0.47 · 18.25 | **55.0** · 44 · 0.47 | 52.3 · 228 · 0.77 · 4.87 | — |
571
+
572
+ † **The served `optiq (mixed)` cells are effectively bf16** — optiq's
573
+ KV-quant patch is inert on mlx-lm 0.31.3's batched server path:
574
+ `install_mixed_kv` hooks `mlx_lm.generate.maybe_quantize_kv_cache` and
575
+ `mlx_lm.server.stream_generate`, but the server routes every *seedless*
576
+ text chat request through `BatchGenerator`, which calls neither hook, and
577
+ the h2h harness's server requests carry no `seed`. See
578
+ `lab/repro/optiq-mixed-kv-inert/` for the mechanism + repro. The data
579
+ fingerprint agrees: e4b optiq-mixed served 53.4 tok/s · 7.53 GB RSS ≡
580
+ mlx-lm bf16's 53.5 · 7.55. Same caveat applies to any serve-mode
581
+ optiq-mixed cell in raw `benchmarks-serve-*` artifacts dated ≤ 2026-07-06.
582
+ The **Direct** and **Long context** optiq (mixed) rows below DID measure
583
+ real quantized-KV execution (the legs passed `kv_bits=8` straight into
584
+ `mlx_lm.generate.stream_generate` — old `bench.ts --baseline-kv config` —
585
+ so the 64k collapse and the lower peaks are genuine quantized-KV
586
+ behavior), but a second installer defect means the scheme was **uniform
587
+ 8-bit, not the per-layer map**: `install_mixed_kv`'s hook patch lands on
588
+ the `generate` *function* that shadows `mlx_lm.generate` in mlx-lm's
589
+ package namespace, never on the module, so mlx-lm's stock uniform
590
+ `maybe_quantize_kv_cache` is what ran (empirically proven in the repro
591
+ dir). Read "optiq (mixed)" in those two tables as "optiq (uniform kv8)".
592
+ mlx-bun (mixed) columns are unaffected — our engine implements the
593
+ per-layer scheme natively — and the L2 parity goldens stay valid: every
594
+ `regen-*` oracle script applies the scheme explicitly (direct per-layer
595
+ `to_quantized`, or calling optiq's patched hook by name), never through
596
+ the dead serve-path indirection.
597
+
598
+ Across every served model: mlx-bun has the fastest decode and the fastest
599
+ TTFT/startup (2–5×), at ~0% server tax vs its own direct engine.
600
+
601
+ ### Served h2h post-consolidation (2026-08-22, e4b, single pass — directional)
602
+
603
+ Real servers via `bench-serve.ts` on merged main `4103ae1`; loaded machine
604
+ (ambient loadavg ~3), so treat as directional until a quiet-box pass. Full
605
+ findings + root-cause sweep: PLAN.md "Prefill vs mlx-lm (2026-08-22)".
606
+
607
+ | arm | prefill@1k tok/s | ttft cold/warm ms | decode tok/s | parity |
608
+ |---|---:|---|---:|---|
609
+ | mlx-bun | **1143** | 578 / **39** | **53.9** | ✓✓ byte-identical |
610
+ | mlx-lm | 866 | 772 / 230 | 50.3 | (oracle) |
611
+
612
+ Served prefill stays a decisive mlx-bun win (+32% @1k, warm TTFT 5.9×)
613
+ after the serving-architecture merge. Engine-direct prefill is
614
+ parity-within-noise elsewhere (cpm5/12B/26B; e4b@256 fresh-process −12%
615
+ is the one reproducible engine-level residual). Chunk-size tuning below
616
+ the 2048 convention is NOT L1-safe: logits are convention-pinned in BOTH
617
+ stacks (mlx reduction-order sensitivity; python drifts more than we do).
618
+ Open lead from this pass: e4b agg×4 read 26.6 vs mlx-lm 107.3 — RESOLVED
619
+ same day as a `443f333` regression (bf16 BatchedRotatingCache lost its
620
+ signature-based route in the join merge → whole-batch drop on joiners;
621
+ PLAN.md "agg×4 regression"). Post-fix: 122-126 tok/s aggregate, matching
622
+ pre-merge.
623
+
624
+ ### Direct (engine only)
625
+
626
+ decode tok/s · prefill tok/s · gen-peak GB
627
+
628
+ | model | mlx-bun (bf16) | mlx-bun (mixed) | mlx-lm (bf16) | optiq (mixed) |
629
+ |---|---|---|---|---|
630
+ | MiniCPM5-1B | 268.6 · 1817 · 1.01 | 241.9 · 1651 · 1.01 | **271.0** · 800 · 1.03 | 249.5 · 706 · 1.03 |
631
+ | gemma-4-e4b | **57.1** · 304 · 6.61 | 55.7 · 283 · 6.61 | 56.5 · 373 · 6.65 | 56.1 · 368 · 6.65 |
632
+ | gemma-4-12B | **26.0** · 168 · 8.99 | 25.8 · 166 · 8.99 | 25.9 · 141 · 9.10 | 25.7 · 137 · 9.00 |
633
+ | gemma-4-26B | 55.0 · 206 · 17.71 | 53.9 · 208 · 17.71 | **55.6** · 187 · 17.78 | 55.0 · 190 · 17.72 |
634
+
635
+ Direct decode is at parity-to-slightly-behind mlx-lm (the residual host
636
+ overhead per step); prefill leads on the larger models. See PLAN.md
637
+ "Decode gap RESOLVED" for the root-cause/fix history.
638
+
639
+ ### Logprob metadata readback (2026-07-29)
640
+
641
+ Paired internal before/after measurement on the M1 Max 32 GB,
642
+ Qwen2.5-0.5B-Instruct-4bit, Bun 1.3.14: 256 generated tokens, two warmups,
643
+ five randomized measured rounds. This isolates mlx-bun's API metadata
644
+ readback; it is **not** a Bun-versus-Python FFI comparison.
645
+
646
+ | arm | before total / decode | after total / decode | overhead vs off, before → after |
647
+ |---|---:|---:|---:|
648
+ | off | 802.75 ms / 328.92 tok/s | 803.94 ms / 328.81 tok/s | control |
649
+ | `logprobs` | 1,185.89 ms / 220.52 tok/s | 802.77 ms / 329.18 tok/s | +47.7% → −0.1% |
650
+ | `top_logprobs=5` | 1,354.21 ms / 192.69 tok/s | 856.24 ms / 307.63 tok/s | +68.7% → +6.5% |
651
+
652
+ The fix reads uint32 IDs directly and expands the few bf16/f16 values on the
653
+ host instead of queueing `astype(float32)` behind the already-dispatched next
654
+ decode step. The off control stayed flat; all 40 parity checks and all 1,280
655
+ selected/top-k comparisons were exact. Clean commits: before `00e597e`, after
656
+ `b1cb7cb`. Raw artifacts are recorded in the Phase 22 ledger in
657
+ `docs/archive/investigations/pre-colibri-stabilization.md`.
658
+
659
+ ### Long context (gemma-4-12B) — where the gap opens
660
+
661
+ decode tok/s · gen-peak GB
662
+
663
+ | context | mlx-bun (bf16) | mlx-bun (mixed) | mlx-lm (bf16) | optiq (mixed) |
664
+ |---|---|---|---|---|
665
+ | 16k | 23.9 · 11.82 | 23.5 · 10.61 | 23.9 · 11.72 | 21.6 · 11.19 |
666
+ | 64k | **20.9** · 15.77 | 18.7 · 10.46 | 20.9 · 15.91 | 12.3 · 14.89 |
667
+
668
+ At 64k mlx-bun holds parity with mlx-lm on bf16 while optiq collapses to
669
+ 12.3 tok/s; mlx-bun's mixed-KV trades ~2 tok/s for ~5 GB lower peak.
670
+
671
+ ### Attempted but failed (2026-06-14)
672
+
673
+ - `gemma-4-12B/optiq/kv=config`: `quantized_matmul` weight/scales
674
+ shape mismatch (upstream optiq bug; tracked). _(Relabeled from the
675
+ old-legend name "e4b" = hash `5b…` = 12B; no gen-peak was recorded for
676
+ this failed run, so the model id here is inferred from the legend, not
677
+ fingerprinted.)_
678
+
679
+ ---
680
+
681
+ ## 3. Quality — for non-bit-exact (Lab) optimizations only
682
+
683
+ When a custom path trades bit-exactness for speed, quantify the cost so a
684
+ perf win is only claimed with its quality delta — e.g. *"+23% tok/s while
685
+ holding ±5% on the 6-test mean."*
686
+
687
+ - **6-test mean** — mean score across `src/eval/tasks/`: bfcl, gsm8k,
688
+ hashhop, humaneval, ifeval, mmlu — optimized path vs the compatible
689
+ upstream.
690
+ - **KL divergence** — optimized vs compatible token distribution.
691
+
692
+ This section is the home for a Lab experiment's quality measurements
693
+ when it's promoted (the bar: paired-A/B win vs L1 on a stable pass +
694
+ KL PASS — see docs/design/unified-engine-frontier-plan.md §6-7).
695
+
696
+ ### TurboQuant KV quality-vs-bpw (2026-07-06, M1 Max 32 GB, MiniCPM5-1B)
697
+
698
+ > Note: measured on an M1 Max 32 GB, not this file's M4 Pro reference
699
+ > box — valid as a paired quality/KL measurement (machine-independent),
700
+ > not as a perf number.
701
+
702
+ Opt-in memory/context scheme (`--kv-quant turbo[:k<bits>v<bits>]`), not a
703
+ speed lever. Teacher-forced serving-decode KL vs bf16 KV (8×128 tokens, 32
704
+ decode steps, `eval-turboquant-curve.ts (deleted; git history)`); affine rows same harness:
705
+
706
+ | scheme | effective KV bits | KV compression | mean KL vs bf16 |
707
+ |---|---|---|---|
708
+ | uniform kv8 (g64) | 8.50 | 1.88× | 0.00246 |
709
+ | turbo k8v8 | 8.75 | 1.83× | 0.00214 |
710
+ | turbo k8v4 | 6.75 | 2.37× | 0.00936 |
711
+ | **turbo k8v3 (default)** | **6.25** | **2.56×** | **0.0325** |
712
+ | uniform kv4 (g64) | 4.50 | 3.56× | 0.0516 |
713
+ | turbo k4v3 | 4.25 | 3.76× | 0.0622 |
714
+ | turbo k4v2 | 3.75 | 4.27× | 0.205 |
715
+
716
+ Read: turbo k8v3 beats uniform kv4's KL at 2.56× compression; k4v3 is
717
+ on-curve with affine at matched bits; 2-bit values are the cliff (matches
718
+ the TurboQuant paper's law). Codec is bit-exact vs the vendored vllm-metal
719
+ reference (goldens/turboquant.json); details in
720
+ docs/design/turboquant.md.
721
+
722
+ ## 4. Composition — feature-default decisions (measured, per pair)
723
+
724
+ The doctrine (docs/design/speculative-decoding.md Phase 4e): a feature is ON by
725
+ default for a (model, config) pair only when it WINS a clean-machine
726
+ paired A/B on that pair; losing configs stay documented default-off
727
+ levers. This section records the decisions and the numbers behind them.
728
+
729
+ ### Packed Trellis with KV4/MTP and paired prefixes, M4 Pro, 2026-09-08
730
+
731
+ The configured serial suite passes every phase on the required 12.14 GiB
732
+ packed Trellis artifact at clean commit `1a80401`, with unchanged source
733
+ hashes throughout. Machine: `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB,
734
+ Bun 1.4.0, bundled MLX 0.32.2. Quiet preflight passes. This is one run,
735
+ not a matched original/final performance claim or a new Kanban task.
736
+
737
+ | Metric | Result |
738
+ |---|---:|
739
+ | Short-prompt decode, median of five 192-token samples | **18.806 tok/s** |
740
+ | Short complete-request time, median | **11.389 s** |
741
+ | Output / complete-request time, median | 16.859 tok/s |
742
+ | Cold TTFT, median of three approximately 1K probes | 6.537 s |
743
+ | Warm TTFT, 754 cached tokens | **94.586 ms** |
744
+ | Approximately 1K prefill estimate, median | 115.747 tok/s |
745
+ | Context probe, actual input tokens | 2,677 |
746
+ | Context prefill estimate | 116.808 tok/s |
747
+ | Context decode, median of three samples | 22.763 tok/s |
748
+ | Cached context TTFT | 95.434 ms |
749
+ | Peak sampled process RSS | 11,973.656 MiB (11.693 GiB) |
750
+ | Phase failures | 0 |
751
+
752
+ Arguments are `--draft-kind mtp --num-draft-tokens 2 --kv-quant 4
753
+ --prompt-cache 4`, with the folded RTN4 MTP draft. Runtime overrides select
754
+ Trellis variant 13, uniform KV4 speculation, paired MTP prefixes and prefill
755
+ chunks of 256. Async Trellis expansion, early-first-token and structural fill
756
+ are off. Workload seed is `pr47-block-0`, thinking is enabled, and the
757
+ requested context target is 4,096; the table reports the actual token count.
758
+ All five short samples emit exactly 192 tokens with no reused prefix.
759
+
760
+ The speculative prefix store is RAM-only. Restarting restores zero cached
761
+ tokens and the context request takes 24.404 seconds to first output. The
762
+ ordinary SSD flush returns durable with zero entries; this is not proof of
763
+ speculative SSD persistence. No stock mlx-lm arm supports this packed artifact.
764
+ The faster context decode sample reflects a different prompt and MTP acceptance
765
+ workload; it does not establish that increasing context makes inference faster.
766
+
767
+ Raw evidence: `reports/qwen38-rd/pr47-trellis-kv4-mtp-serve.md` and its `.md.json`
768
+ companion. These serving timings are separate from the completed fresh Pi
769
+ Kanban measurement below.
770
+
771
+ ### Original and optimized serving diagnostics, M4 Pro, 2026-09-07
772
+
773
+ Machine: `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, Bun 1.4.0.
774
+ `bench-serve.ts all` used workload seed `kanban-final-0`, thinking enabled,
775
+ 192 requested output tokens and five decode samples. These are earlier
776
+ diagnostic runs, with existing swap, rather than final-PR quiet acceptance.
777
+ All columns below use the serial serving lane and the required packed target
778
+ weights. Baseline uses `673b43f`, Trellis variant 6 and the older native library;
779
+ optimized arms use variant 13, the lossless interleaved artifact and the local
780
+ MLX 0.32.2 candidate. Each run's source stayed fixed.
781
+
782
+ All three serving arms use **bf16 KV**, with `--kv-quant off`. The MTP arm
783
+ adds two drafts and paired RAM prefixes. This differs from the completed
784
+ long Kanban task's KV4 configuration. These runs predate the later ownership
785
+ and bounded-range fixes, so they do not measure the exact final task revision.
786
+
787
+ | Serial serving metric | Original | Optimized, ordinary decode | Optimized, MTP + RAM cache |
788
+ |---|---:|---:|---:|
789
+ | Median decode, tok/s | 10.140 | 11.712 | 19.426 |
790
+ | Cold-request TTFT, ms | 5,923.576 | 6,164.498 | 5,801.504 |
791
+ | Cached TTFT, ms | 190.841 | 436.308 | 91.916 |
792
+ | 1K prefill, tok/s | 127.963 | 122.962 | 130.522 |
793
+ | Peak process RSS, reported MB | 11,958.984 | 13,859.828 | 12,061.219 |
794
+
795
+ Ordinary decode improves **15.5%**. The MTP configuration improves decode
796
+ **91.6%** relative to the original, with cached TTFT **51.8% lower**.
797
+ Its cold TTFT changes by -2.1%, prefill by +2.0%, and sampled RSS by +0.9%.
798
+ Ordinary decode's gain does not extend to every metric: its cached TTFT and
799
+ RSS regress in this diagnostic. The percentages describe these specific
800
+ serving configurations; they are not a measured Kanban task-time reduction.
801
+
802
+ The baseline context phase crashed and recovered on retry; no context-phase
803
+ speedup is claimed here. MTP prefix state is RAM-only: the restart probe
804
+ restored zero tokens and does not establish SSD persistence. Stock mlx-lm
805
+ cannot read this packed Trellis artifact, so it supplies no same-artifact
806
+ serving baseline for these rows.
807
+
808
+ Raw evidence: `reports/qwen38-rd/kanban-final/suite-driver.json`,
809
+ `baseline-suite.md.json`, `optimized-ordinary-suite.md.json`, and
810
+ `optimized-mtp-cache-suite.md.json`. The driver records all commands,
811
+ environments, source hashes and exits. The completed task and its separate
812
+ acceptance are recorded below.
813
+
814
+ ### Fresh Pi kanban diagnostic, M4 Pro, 2026-09-07
815
+
816
+ Machine: `Joshs-MBP-2025.local`, M4 Pro, 24 GB; Bun 1.4.0, Pi 0.85.1,
817
+ MLX 0.32.2. These are task diagnostics with existing swap. The first attempt
818
+ also had a brief background browser-test CPU burst. Neither is a quiet-machine
819
+ speed claim.
820
+ The model is the required 12.14 GiB packed Qwen3.8-27B Trellis artifact with
821
+ lossless interleaving. The selected Luke profile is
822
+ `qwen3.8-27b-q3_k_xl-coding-128k`, pinned at repository commit
823
+ `3288d1918fa6140c10f3b2de2d37f9d717a5ab75`. It uses the unchanged prompt,
824
+ xhigh thinking, temperature 0.6, seed 42 and 131072 context. The MLX mapping
825
+ uses target affine KV4 group64, two MTP drafts, paired RAM prompt prefixes
826
+ and 256-token prefill chunks.
827
+
828
+ | Attempt | Time until Pi stopped | Output tokens | Overall tok/s | First-turn tok/s, including prefill | First reasoning TTFT | Peak server + Pi RSS | Result |
829
+ |---|---:|---:|---:|---:|---:|---:|---|
830
+ | History fixed; original tool-value parser | 65m 30.245s | 53,631 | 13.646 | 15.965 | 22.869s | 12.042 GiB | Failed: only HTML and two JS modules; final edit call remained assistant text |
831
+ | History and tool-value parsing fixed | 106m 6.531s | 82,015 confirmed | 12.882 | 16.154 | 22.892s | 13.795 GiB | Failed inference: Metal out of memory at the 85,238-token request; Pi did not finish |
832
+
833
+ All four request prompt counts matched independent renders. Later requests
834
+ reused 2,549, 53,174 and 54,859 prompt tokens, with MTP active. Pi had no
835
+ automatic retries or compactions. Its clean process exit did not mean the
836
+ app was complete: the mandatory README was absent and most app files were
837
+ never written. The untouched output fails acceptance. No successful task
838
+ completion time or matched task-time speedup is established by this row.
839
+
840
+ The saved final edit parameter is valid JSON. The engine decoded XML
841
+ entities before JSON parsing and its repair pass misidentified the nested
842
+ array as the outer call. The corrected parser preserves the complete argument
843
+ array through the actual tokenizer and streaming path.
844
+
845
+ The fresh attempt with both fixes completed ten requests. Every completed
846
+ prompt count matched the independent render and every response used MTP.
847
+ The aggregate accepted/drafted ratio was 80.038%. The first tool transition
848
+ took 524.244 seconds to first output while processing newly generated history.
849
+ Later requests reused progressively longer prompt prefixes. The cache still
850
+ captures prompt boundaries rather than the newly generated history.
851
+
852
+ The eleventh request reached a Metal allocation failure after its first
853
+ reasoning fragment. Its terminal usage was unavailable, so the output total
854
+ counts only completed responses. The wall-clock interval includes that failed
855
+ request, prefill, tools and agent overhead. Ten completed response intervals,
856
+ excluding TTFT, average 15.270 output tokens/s. This is distinct from both
857
+ overall task throughput and the short-context serving-suite decode rate.
858
+ There were no retries, compactions or tool errors. Engine source hashes stayed
859
+ fixed. All inference processes exited during bounded cleanup.
860
+
861
+ The untouched app has HTML, CSS, twelve JavaScript modules and package.json,
862
+ but no README. Syntax checks pass. A separate browser smoke test after server
863
+ shutdown shows the default columns and keyboard card creation work, but opening
864
+ the editor throws `ReferenceError: renderLabels is not defined`. Remaining UI
865
+ checks were not run after that blocking failure. No app edits or repair prompts
866
+ were supplied. These are findings about an incomplete artifact, not a completed
867
+ model submission. No successful completion time or matched task-time gain exists.
868
+
869
+ Process RSS does not measure all Metal allocations. The out-of-memory failure
870
+ does not establish the model's architectural context limit; the tested KV4,
871
+ MTP and retained-prefix combination needs a separate memory diagnosis.
872
+
873
+ Protocol and design: [decode-speed-program §7.7](../design/decode-speed-program.md#77-gates-scheduling-and-completion).
874
+ Raw evidence: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-history-fixed/`
875
+ and `luke-q3-128k-xhigh-tool-values-fixed/`, including `quality-static.json`,
876
+ `quality-browser.json` and screenshots. Portable report:
877
+ `reports/qwen38-rd/kanban-final/comparison.html`.
878
+
879
+ ### Kanban capacity diagnosis, M4 Pro, 2026-09-08
880
+
881
+ Native Bun screen on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, using the
882
+ same 12.14 GiB target, MTP head, MLX 0.32.2 candidate and KV4/prefix settings
883
+ as the failed Pi attempt above. The saved failing history renders to 85,238
884
+ tokens. Fixed text tokens extend it to 110,000 for this capacity screen.
885
+ No Pi task runs in this screen. Sampling follows the selected profile, but
886
+ EOS stopping is disabled to require a short continuation. This is neither
887
+ a fresh task result nor a quiet-machine performance claim.
888
+
889
+ The unchanged control finished target prefill and emitted one token, then
890
+ failed with Metal out of memory in the first MTP draft round. Its wall time
891
+ was 1,482.497 seconds. Peak active Metal allocation reached 19,451,721,310
892
+ bytes against a recommended working set of 19,069,665,280 bytes. Immediately
893
+ before draft prefill, active allocation was 14,593,938,440 bytes; at the
894
+ first emitted token it was 17,494,527,842 bytes. The retained prefix reported
895
+ 2,633,836,544 logical bytes. These counters measure different things from
896
+ process RSS and do not establish a model context limit. Source hashes stayed
897
+ fixed; the worker exited with failure and bounded cleanup completed.
898
+
899
+ Raw control: `reports/qwen38-rd/kanban-capacity-110k-control.json` and its
900
+ allocation event log. A focused small ownership regression retains 8,405,016
901
+ bytes before the fix, despite requiring only small KV state and one hidden
902
+ row. The isolated candidate now evaluates draft KV at each existing prefill
903
+ chunk and materializes the retained final hidden row. The ownership,
904
+ prefix-position and provider-disposal tests pass. Full-model exactness and
905
+ large-context acceptance are checked separately. A sampling-failure
906
+ regression retains 524,288 bytes before scoped disposal; it now passes the
907
+ under-4-KiB cleanup guard without running GC after the failure.
908
+
909
+ The final-source small native comparison uses the same first 8,192 history
910
+ tokens and generates 32 tokens twice. Before and after the ownership changes,
911
+ both responses and all MTP acceptance decisions match exactly. Each process
912
+ first prefills from zero, then restores 8,191 cached tokens. Peak active
913
+ allocation is 13,330,783,014 bytes before and 13,105,695,458 after. Both source
914
+ manifests stay fixed. This is one correctness/allocation comparison, not a
915
+ request-time speed claim. Typechecks pass. Evidence: `kanban-capacity-8k-final-comparison.json`
916
+ and its two referenced control/candidate reports in `reports/qwen38-rd/`.
917
+
918
+ The final native capacity screen passes at 110,000 prompt tokens. It completes
919
+ three identical 256-token continuations, with 109,999 tokens restored on each
920
+ cached request. Between the latter two, an intentional output-sink error after
921
+ eight emitted tokens exercises request cleanup. Retained active allocation is
922
+ 14,911,641,794 bytes after every completed or intentionally failed request.
923
+ The next request recovers in the same process and reproduces the continuation.
924
+ Peak active allocation is 17,981,018,362 bytes, 1,470,702,948 bytes below the
925
+ failing control, despite the longer continuation. The first request takes
926
+ 1,525.095 seconds including full prefill; the two complete cached requests take
927
+ 33.148 and 33.175 seconds. Instrumented synthetic-context timings are not
928
+ Kanban completion estimates. Final provider/weight disposal leaves 101,892,102
929
+ active bytes; the equal per-request counters establish no incremental retention
930
+ from the injected failure, not zero global runtime allocation. The worker exits
931
+ successfully, its source hashes stay fixed and its deadline is not reached.
932
+
933
+ The main source has the same ownership fixes. Its focused memory/provider tests
934
+ and a real-target MTP/non-MTP short greedy identity gate pass, as do all
935
+ typechecks.
936
+ Native evidence: `reports/qwen38-rd/kanban-capacity-110k-owned-final.json`.
937
+
938
+ The saved-history HTTP gate also passes on the isolated candidate. It first
939
+ replays the exact failed request, then appends that response and synthetic
940
+ tool/user history to test growth. Tool calls are recorded but never executed
941
+ by this diagnostic. Each response allows up to 512 output tokens and stops
942
+ naturally. Both repeated responses preserve all text, tool arguments, output
943
+ counts and MTP acceptance decisions.
944
+
945
+ | Prompt tokens | Cached tokens | Output tokens | Complete request, s | TTFT, s |
946
+ |---:|---:|---:|---:|---:|
947
+ | 85,238 | 0 | 42 | 988.103 | 984.951 |
948
+ | 85,238 | 85,237 | 42 | 3.283 | 0.225 |
949
+ | 110,014 | 85,237 | 92 | 401.843 | 393.126 |
950
+ | 110,014 | 110,013 | 92 | 8.931 | 0.255 |
951
+
952
+ Source hashes stay fixed and server cleanup exits successfully. This validates
953
+ serving capacity and cache reuse, not a completed Kanban task. Raw evidence:
954
+ `reports/qwen38-rd/kanban-memory-http-owned.json` and the saved request/response
955
+ files beside it. These checks exercise short continuations. The fresh Pi
956
+ retry below still fails during sustained generation.
957
+
958
+ During the saved-history HTTP prefill, simultaneous read-only `/health` and
959
+ `/stats` requests both returned 200, taking 4,776.475 and 4,776.682 ms. This
960
+ single busy-server observation does not establish an idle baseline or latency
961
+ distribution. It identifies responsiveness during native prefill for a separate
962
+ serving check. Evidence: `reports/qwen38-rd/kanban-memory-http-responsiveness.json`.
963
+
964
+ ### Fresh Pi Kanban after MTP ownership fixes, M4 Pro, 2026-09-08
965
+
966
+ The fresh retry on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, failed with
967
+ Metal out of memory after **106m 5.416s**. It used the same 12.14 GiB target,
968
+ published Luke Q3 128K xhigh profile and unchanged prompt as the preceding
969
+ attempt. The source and every saved request's profile pass the post-run audit.
970
+ The first request body is byte-identical to the preceding attempt; its entire
971
+ response and MTP acceptance trace also match. Later history includes actual
972
+ tool results, including changed directory timestamps.
973
+
974
+ Eight requests completed, reporting **73,831 output tokens**. The ninth
975
+ request started with **77,077 prompt tokens**, emitted its first output after
976
+ 26.415 seconds and failed after 780.891 seconds, during sustained decode.
977
+ Its terminal usage is missing. Retokenizing delivered reasoning estimates
978
+ another 5,659 tokens, but excludes buffered tool arguments, so the full
979
+ generation count is unknown. The completed-response rate after first output
980
+ is 15.658 tok/s; this excludes prefill, tool time and the failed response.
981
+ Peak combined server/Pi RSS is **13.836 GiB**. Completed requests report
982
+ 79.911% MTP acceptance. There were no retries, compactions or tool execution
983
+ errors. Pi exited with code zero but reported a terminal error; the task
984
+ therefore failed. No successful completion time or task-time speedup is
985
+ established.
986
+
987
+ The untouched app supplies its README and passes syntax, basic card creation,
988
+ board/theme persistence, column creation/rename and between-column card drag
989
+ checks. The card editor throws `ReferenceError: renderLabels is not defined`;
990
+ the archive panel throws `TypeError: K.render.renderArchive is not a function`.
991
+ Required functional acceptance fails. Reorder interaction probes remain
992
+ unconfirmed because their input simulation needs validation. Independent UI
993
+ checks ran only after inference exited. No app code was edited and no repair
994
+ prompts were supplied.
995
+
996
+ The short native and HTTP capacity checks above did not reproduce this long
997
+ decode failure. It motivated the sustained allocation check below. Raw result,
998
+ source/profile audit and untouched
999
+ app checks: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-mtp-memory-fixed/`
1000
+ contains `result.json`, `measurement-audit.json`, `quality.json` and its
1001
+ referenced evidence.
1002
+
1003
+ ### Sustained Kanban decode allocation diagnosis, M4 Pro, 2026-09-08
1004
+
1005
+ A fresh native process loaded the failed task's saved **77,077-token** request
1006
+ and generated **12,288 tokens** with the same model, MTP, KV and sampling
1007
+ settings. EOS stopping was disabled for this bounded diagnostic; no tools
1008
+ were executed. The unchanged control completed in 2,408.753 seconds including
1009
+ 923.348 seconds to first output. Decode was 8.272 tok/s. Peak active MLX
1010
+ allocation was **18,204,808,450 bytes**; **1,593,360,390 bytes** remained active
1011
+ after provider/weights disposal and allocator-cache clearing. Source hashes
1012
+ stayed fixed. This is a saved-history diagnostic, not a fresh task result or
1013
+ a quiet-machine speed claim.
1014
+
1015
+ The large-range cache retained every distinct causal-mask range above 65,536
1016
+ elements. Early comparable rounds each added **311,296 bytes**, matching the
1017
+ page-rounded int32 range allocation. A focused regression with 256 changing
1018
+ context lengths retained **79,790,080 bytes** in the old implementation and
1019
+ **7,258,112 bytes** after bounding cached array data to 8 MiB. Three oversized
1020
+ ranges retained **37,748,736 bytes** before and **zero additional bytes** after.
1021
+ The regression fails before the change and passes after it, including exact
1022
+ range values, vocabulary reuse and lazy-view ownership after eviction. Eight
1023
+ focused main-source tests, the candidate regression and both workspace
1024
+ typechecks pass.
1025
+
1026
+ Reconstructing the target prefill lengths and verification windows from the
1027
+ control's acceptance trace predicts 4,685 distinct large mask ranges occupying
1028
+ 1,592,344,576 page-rounded bytes. That accounts for more than 99.9% of the
1029
+ observed allocation left after model disposal. This is allocation attribution
1030
+ from the recorded execution and source, not a measurement of every cache entry.
1031
+
1032
+ The bounded-cache full-model repeat passes: all **12,288 output tokens** and
1033
+ all **4,638 MTP acceptance decisions** are identical. Source and harness hashes
1034
+ stay fixed, with `src/mlx/ops.ts` the only engine difference between arms.
1035
+ Both runs exit normally without cleanup errors.
1036
+
1037
+ | Native diagnostic metric | Unbounded cache | Bounded cache |
1038
+ |---|---:|---:|
1039
+ | Complete request time | 2,408.753 s | 2,461.051 s |
1040
+ | Time to first output | 923.348 s | 939.902 s |
1041
+ | Decode rate | 8.272 tok/s | 8.078 tok/s |
1042
+ | Peak active MLX allocation | 18,204,808,450 B | 16,622,195,970 B |
1043
+ | Active MLX allocation after model disposal | 1,593,360,390 B | 8,224,774 B |
1044
+ | Observed peak process RSS | 14,324,711,424 B | 12,745,523,200 B |
1045
+ | OS lifetime peak process footprint | 18,969,882,768 B | 18,826,963,720 B |
1046
+
1047
+ Peak active allocation falls by **1,582,612,480 bytes**. The single diagnostic
1048
+ pair takes **2.171% longer**, so it establishes a memory/ownership correction,
1049
+ not a throughput gain. RSS, active allocation and physical footprint remain
1050
+ distinct measurements. The process monitor started during control prefill
1051
+ and before candidate prefill; native allocation instrumentation is identical.
1052
+ The fresh Pi task with this correction completed; its separate task result
1053
+ and functional acceptance are recorded below.
1054
+
1055
+ Raw evidence: `reports/qwen38-rd/kanban-sustained-77k-owned-control.json`, its
1056
+ allocation/process-memory traces, `kanban-arange-allocation-evidence.json`,
1057
+ `kanban-arange-regression.json`, `kanban-arange-micro-memory.json` and
1058
+ `kanban-arange-reconstruction.json`. Full-model comparison:
1059
+ `kanban-sustained-arange-comparison.json`, with both raw runs and their traces.
1060
+
1061
+ ### Completed fresh Pi Kanban with bounded range cache, M4 Pro, 2026-09-08
1062
+
1063
+ The untouched app passes the required functional checks after a fresh Pi run
1064
+ on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, using the required 12.14 GiB
1065
+ Trellis target. The published Luke Q3 coding 128K profile, unchanged prompt,
1066
+ xhigh thinking, sampling and seed 42 remain fixed. The candidate uses MLX
1067
+ 0.32.2, target KV4, MTP depth 2 and paired RAM prefixes. Processes, application
1068
+ caches, Pi session and task workspace started fresh; OS file cache was not purged.
1069
+
1070
+ | Completed task metric | Result |
1071
+ |---|---:|
1072
+ | Prompt submitted to Pi settled | **3h 33m 7.685s** |
1073
+ | Including server startup | 3h 33m 8.581s |
1074
+ | First request time to first output | 23.145 s |
1075
+ | Reported output tokens, including reasoning and compaction | **130,494** |
1076
+ | Completed inference requests | 62 |
1077
+ | Output / whole task elapsed time | 10.205 tok/s |
1078
+ | Completed-response rate after first output | 13.904 tok/s |
1079
+ | Sum of request time before first output | 56.665 min |
1080
+ | MTP draft-token acceptance | 79.706% |
1081
+ | Peak sampled combined server/Pi RSS | 11.916 GiB |
1082
+
1083
+ All 443 source, profile, request, usage and timing audit checks pass. Every
1084
+ response has terminal usage; the output total is exact. Pi and the server
1085
+ exit normally, with no inference error or automatic retry. Pi encounters
1086
+ seven tool execution errors during its own debugging and completes the task
1087
+ without external repair prompts.
1088
+
1089
+ One context compaction is included in the total. Its summary request uses
1090
+ 90,214 input tokens, reports 1,404 output tokens, and takes **19m 42.705s**,
1091
+ including 17m 37.551s before first output. The following coding request has
1092
+ 28,126 input tokens and takes another 4m 22.552s before first output.
1093
+ Both prompts have zero cached tokens because the summary changes the exact
1094
+ serialized prefix. The first ordinary tool turn separately takes 8m 53.415s
1095
+ before first output after the initial 50,533-token response; its cached prefix
1096
+ contains only 2,549 tokens. These are measured targets for reducing repeated
1097
+ prefill, not claimed savings. The frozen outcome helper recorded zero
1098
+ compactions because it recognized only `auto_compaction_start`; derived
1099
+ reports count the observed `compaction_start` while preserving the raw result.
1100
+
1101
+ The server's last observed OS lifetime peak physical footprint is
1102
+ **18,913,094,336 bytes**. The external monitor began during the task and
1103
+ sampled through five seconds before exit; lifetime counters include earlier
1104
+ process history but may miss the final interval. Physical footprint and the
1105
+ runner's sampled combined RSS are different measurements. Separate process
1106
+ lifetime peaks are not added as though they were concurrent.
1107
+
1108
+ After inference exited, independent browser checks passed card creation,
1109
+ required-title editing, description/labels/assignee fields, combined filters,
1110
+ archive/restore, column creation/rename/safe deletion/restore, native card
1111
+ and column reordering, the Done indicator, and persisted theme/board/order.
1112
+ The app supplies run instructions and modular vanilla code. No generated
1113
+ source was edited. Earlier automated reorder probes remain recorded; native
1114
+ mouse motion with dragover before release confirms both reorder operations.
1115
+
1116
+ This establishes a completed task on the frozen candidate. There is no
1117
+ matched successful original baseline, so it establishes no task-time speedup
1118
+ percentage. The complete first response and every MTP acceptance decision
1119
+ match the preceding failed attempt; its time changes from 3,152.595 to
1120
+ 3,147.633 seconds, effectively flat in one pair. The bounded range cache's
1121
+ measured benefit remains retained-memory correction and successful completion.
1122
+
1123
+ Raw evidence: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-arange-bounded/`
1124
+ contains `result.json`, `measurement-audit.json`, `quality.json`, referenced
1125
+ browser evidence, `memory-summary.json`, the untouched app and saved sources.
1126
+ The derived HTML report is `reports/qwen38-rd/kanban-final/comparison.html`.
1127
+
1128
+ ### Speculative decoding — "should spec be on?" (decision pending Phase 0/1 runs)
1129
+
1130
+ Decision rule: spec defaults ON for a (target, drafter) pair iff
1131
+ serve-path decode ≥ 1.3× serial at the recommended γ, clean-machine
1132
+ paired (`scripts/bench-serve.ts all` preflight, `bench-feature-matrix.ts --cells
1133
+ serial,spec`), with acceptance within 3 pts of the bf16-drafter baseline
1134
+ (`scripts/dspark.ts ab`). Prediction to test: ON for
1135
+ 12B + quantized DeepSpec drafter, OFF for e4b + anything.
1136
+
1137
+ | target | drafter | γ | acceptance | τ | spec tok/s | serial tok/s | verdict |
1138
+ |---|---|---|---|---|---|---|---|
1139
+ | 12B-OptiQ-4bit | DeepSpec bf16 (6.9 GB) | 7 | 26–33% | ≈2.8 | 14.6 agg | 49.8 agg | **OFF** — drafter tax −3.4× (2026-07-07 first live run, loaded box, conc-4; directional) |
1140
+ | 12B-OptiQ-4bit | DeepSpec affine-q4-g64 (1.8 GB, built 2026-07-07) | best-of-0b | _1d run_ | _1d run_ | _0b/6 run_ | _0b/6 run_ | _pending_ |
1141
+ | e4b-OptiQ-4bit | (expected-negative control) | — | — | — | — | — | _pending_ |
1142
+
1143
+ Runbook (Josh's shell; directional passes fine loaded, the FINAL pair
1144
+ clean-machine per the house rule):
1145
+ 1. **1d acceptance A/B** (no server): `bun scripts/dspark.ts ab
1146
+ --target gemma-4-12B-it-OptiQ-4bit --drafter-a <bf16-snap>
1147
+ --drafter-b <q4-snap> --json ab-q4.json` — gate: drop ≤ 3 pts AND
1148
+ wall-clock strictly improves.
1149
+ 2. **0b γ sweep** (server): serve 12B `--draft-model <q4-snap>
1150
+ --num-draft-tokens {2,3,5,7}` × `bun scripts/bench-matrix.ts features
1151
+ --concurrency 1 --cells serial,spec` — pick best-γ by per-request tok/s.
1152
+ 3. **Phase 6 decision pair** (clean machine: reboot + `sudo purge`):
1153
+ best-γ config, `--cells serial,spec` at conc 1 AND agg×4 — fill the
1154
+ table, flip the features-matrix default cell if ≥ 1.3×.
1155
+
1156
+ ### TurboQuant KV — decided OFF (2026-07-06, re-affirmed post-leak-fix)
1157
+
1158
+ Opt-in memory/context lever, not a speed feature (v1 dequant-on-fetch is
1159
+ slower per step at long context; no speed claim made). The KL-vs-bpw
1160
+ curve above is the quality evidence. NOTE: any turbo perf/RSS impression
1161
+ formed before 2026-07-07 is invalid — the pre-fix build leaked
1162
+ window-scale buffers per decode step (PLAN Phase 13 post-merge fix).