mlx-bun 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/README.md +1449 -109
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +7 -5
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -1,1987 +0,0 @@
1
- ---
2
- status: active
3
- axis: ON
4
- canonical-for: engine-architecture
5
- plan-anchor: "Interface-based engine refactor `[~]`"
6
- last-verified: 2026-08-23
7
- ---
8
-
9
- # Engine architecture — four layers, per-scheme oracles, one request path
10
-
11
- This is the canonical architecture doc for mlx-bun's engine. It owns:
12
-
13
- - the **four layers** (L1 graph / L2 KV+quant schemes / L3 engine / L4 surface)
14
- and the rule that features decompose along them;
15
- - the **fidelity tiers** — L1 = mlx-lm bit-exact, L2 = mlx-optiq bit-exact,
16
- Lab = no-oracle experiments gated by KL/eval and a paired A/B before any
17
- default — and the decision procedure that places every optimization;
18
- - the **naked default IS L1** decision (2026-07-05);
19
- - the **engine** decision that concurrency is the batch size;
20
- - the **request path** as it exists in `src/` today, the single-path rule, and
21
- the known deviations from it;
22
- - the **flag end-state** and how it maps onto the layers.
23
-
24
- The v2 refactor is in [§12](#12-interface-based-engine-refactor).
25
- Josh requested replaceable implementations behind interfaces on 2026-09-04.
26
- That section defines the target and migration, with implementation status below.
27
- The portable session and native implementation ports are documented in the
28
- library API; existing model-class exports remain supported.
29
- Earlier sections retain the current architecture and numerical contracts.
30
- `last-verified` above dates the earlier inventory, not a whole-document reaudit.
31
-
32
- Folded in (2026-08-23): `docs/design/unified-engine-frontier-plan.md` (tier framing, two axes, flag
33
- classification) and `docs/archive/investigations/faithful-l1-consolidation.md` (the 2026-07-04 faithful→L1
34
- consolidation and the 2026-07-05 deletion pass, now the History section).
35
- Status and changelog prose lives in PLAN.md — see "Decision: naked default =
36
- --l1; levers must beat the baseline (2026-07-05, Josh)" for the decision
37
- record and "Serving architecture consolidation" for the live S0–S4 work. Every
38
- `src/` claim below was re-read against the tree on 2026-08-23; where an older
39
- draft of this doc disagreed with the code, the code wins and the note says so.
40
-
41
- Companions: `docs/design/batching.md` (B=1 gap numbers), `docs/design/batching.md` and
42
- `docs/design/batching.md` (scheduler mechanics — the mode-switch decision there is
43
- superseded by §5), `docs/design/unified-engine-frontier-plan.md` (the S0–S3 seam),
44
- `decode-speed-program.md` (the only doc that ranks speed levers; it also
45
- carries the oMLX port ledger that used to be `docs/design/decode-speed-program.md`).
46
-
47
- ---
48
-
49
- ## 1. The two-part product and the contract
50
-
51
- 1. **A drop-in replacement for mlx-lm: everything they do, bit-exact.** This is
52
- the default. Parity is only *defined* over outputs mlx-lm can produce — you
53
- cannot ask for "mlx-lm's bits under mixed-precision KV" because mlx-lm
54
- cannot output anything under it.
55
- 2. **Beyond mlx-lm — features you opt into by deliberately trading the parity
56
- guarantee for something you value more**, each answering to its own oracle:
57
- mixed-precision KV (optiq), structured output (oMLX/xgrammar), speculative
58
- decoding (mlx-lm's `speculative_generate_step`; optiq for the KV-borrowing
59
- assistant drafter), prompt caching (mlx-lm's `LRUPromptCache`), prefix
60
- sharing and paged KV (vLLM/SGLang), multi-model switching (optiq
61
- per-request switching / oMLX EnginePool).
62
-
63
- **THE CONTRACT (Josh, 2026-07-05) — two rules that compose:**
64
-
65
- 1. **The drop-in promise: the same BITS as mlx-lm.** How the bits are produced
66
- (storage, kernels, scheduling, engine, language) is the space we compete in.
67
- 2. **The oracle for anything is whoever already does that thing.** Want
68
- mlx-lm's decode → mlx-lm. optiq's mixed KV → optiq. vLLM's paged attention
69
- → vLLM: read their implementation, copy what they did, verify against them,
70
- then optimize. "No oracle" means *nobody* does the thing — genuine research
71
- — and that, and only that, is what the Lab is for.
72
-
73
- Verification form follows the oracle's framework: same-libmlx oracles (mlx-lm,
74
- optiq) admit bit-exact gates; cross-framework oracles (vLLM, CUDA/PyTorch)
75
- anchor the algorithm and behavior while rule 1 still binds the output bits in
76
- the default regime. "Faithful" kernel-set identity is the easiest route to
77
- same-bits, not the contract; the one constraint bit-exactness puts on an
78
- implementation is math/reduction order.
79
-
80
- Two consequences drive everything below:
81
-
82
- - **The baseline must be even and proven before optimizing.** The L1 path is
83
- bit-exact with mlx-lm and at decode parity on every model (PLAN.md, the
84
- 2026-07-05 decision). Anything claiming to beat it proves it with a paired
85
- A/B on a stable pass; otherwise it is noise or a regression.
86
- - **Frontier-shifting work is usually a quality-per-byte play, not a raw kernel
87
- play.** Mixed-precision quantization (weights and KV) moves memory down while
88
- holding or raising intelligence. Quantized KV stays first-class even though
89
- it lost the speed A/B: it buys context headroom.
90
-
91
- The frontier axes we measure: memory (generation peak, fit-model), decode
92
- tok/s (paired h2h, stable cells), prefill/TTFT, batched aggregate throughput,
93
- and intelligence (the frozen eval suite in evals.sqlite). Curated numbers live
94
- in `docs/reference/benchmarks.md`.
95
-
96
- ## 2. The four layers
97
-
98
- ```mermaid
99
- flowchart TB
100
- subgraph clients["CLIENTS"]
101
- direction LR
102
- PI["Pi agent<br/>chat UI + terminal"]
103
- CLI["mlx-bun CLI"]
104
- API["any OpenAI / Anthropic / Responses client"]
105
- LIB["TS/Bun library import"]
106
- end
107
- subgraph surface["L4 SERVING SURFACE — src/server.ts + src/serve/*"]
108
- V1["/v1 endpoints → prepareCompletion → CompletionExecutor"]
109
- ADMIT["admission: --memory-budget · --kv-budget"]
110
- end
111
- subgraph engine["L3 ENGINE — GenerationGateway.place() → serial | continuous"]
112
- SCHED["BatchScheduler (--batch N cap, default 8)<br/>B=1 adopted-cache fast path · B≥2 step"]
113
- SERIAL["strict serial executor (generate.ts)<br/>--batch 1 and not-yet-batchable compositions"]
114
- FEAT["shared: prompt cache · SSD tier · grammar · samplers"]
115
- end
116
- subgraph models["L1 MODEL GRAPH — profile-routed, never flag-routed"]
117
- OPT["dedicated / generated graphs<br/>gemma4 · MiniCPM5 · Qwen3/3.5/3.8 · Qwen3-MoE · GLM-5.2"]
118
- UNI["universal dense graph — any supported HF arch, best effort"]
119
- end
120
- subgraph numerics["L2 KV / QUANT SCHEMES — per-scheme oracles"]
121
- BF["bf16 (default) — oracle: mlx-lm"]
122
- UKV["uniform kv 4/8 — oracle: mlx-lm --kv-bits"]
123
- MKV["mixed kv_config — oracle: mlx-optiq"]
124
- LAB["Lab: TurboQuant KV · rotation-folded weights · new kernels — KL + eval gates"]
125
- end
126
- HW["libmlx (Metal) via bun:ffi — the only runtime link"]
127
- PI --> V1
128
- CLI --> V1
129
- API --> V1
130
- LIB --> SERIAL
131
- V1 --> ADMIT --> SCHED
132
- ADMIT --> SERIAL
133
- SCHED -.-> FEAT
134
- SERIAL -.-> FEAT
135
- SCHED --> OPT
136
- SERIAL --> OPT
137
- SCHED --> UNI
138
- SERIAL --> UNI
139
- OPT --> BF
140
- OPT --> UKV
141
- OPT --> MKV
142
- UNI --> BF
143
- MKV -.-> LAB
144
- BF --> HW
145
- UKV --> HW
146
- MKV --> HW
147
- ```
148
-
149
- ### Layer responsibilities (the contract)
150
-
151
- 1. **Model graph (L1)** — one forward step given hidden + caches; attention
152
- dispatches on the *cache type it is handed* (bf16 → `ops.sdpa`, quantized →
153
- the quantized SDPA); shape-generic in B; selected by model profile, never by
154
- flags. *Responsibility: the numerics of a step, for any B, for whatever
155
- cache it is given.* The contract ENDS AT LOGITS.
156
- 2. **KV scheme (L2, cache classes)** — the memory format and its semantics:
157
- bf16 / uniform / mixed per-layer / TurboQuant; conversion timing (bf16
158
- prefill → quantize populated rows, optiq's hook semantics); in batched form
159
- the multi-row layout (padding, per-row rope, merge/extract/extend/filter).
160
- *Responsibility: the scheme PER ROW — a row's bytes and math identical solo
161
- or batched. This is where each scheme's oracle binds.* In code: `KvScheme`
162
- (`src/kv-scheme.ts`, kinds `bf16 | affine-uniform | affine-config | turbo`),
163
- the cache classes in `src/model/gemma4-base.ts`, and the batched variants in
164
- `src/model/batched-*.ts`.
165
- 3. **Engine (L3, scheduler)** — rows: admission, solo prefill, join/merge, the
166
- step loop, per-row sampling, eviction, pipelining, the concurrency cap.
167
- Never implements scheme math; calls layer-2 operations. *Responsibility: how
168
- many rows and when — never what a row's bytes mean.* In code:
169
- `src/serve/generation-gateway.ts` (placement + the single mutual-exclusion
170
- domain), `src/serve/batch-scheduler.ts`, `src/generate.ts` (the strict
171
- serial loop), `src/spec/serve-loop.ts` (the verify loop).
172
- 4. **Serving surface (L4)** — endpoints, per-request features (adapters,
173
- grammar, sampling, spec policy), prompt cache (keyed by fingerprint +
174
- effective scheme + adapter), admission budgets. *Responsibility: requests,
175
- not tensors.* In code: `src/server.ts`, `src/serve/request-plan.ts`,
176
- `src/serve/completion-executor.ts`, `src/serve/completion-sink.ts`.
177
-
178
- ### Model selection is a declared profile, not a flag
179
-
180
- `resolveModelProfile()` (`src/model/profile.ts`) freezes, before construction,
181
- the artifact/config identity, the fidelity target, the required engine
182
- capabilities, and the loader/graph/loop composition. Exact artifact profiles
183
- outrank family profiles; dedicated/generated graphs outrank the universal dense
184
- fallback; an exact profile whose config or capabilities mismatch refuses
185
- instead of downgrading. Profiles declare construction only — they cannot
186
- rewrite MTP, KV scheme, adapters, grammar, or sampling (those are request
187
- methods resolved independently). Promotion universal → dedicated is a
188
- checklist: custom graph file, bit-exact goldens vs the scheme oracle, an h2h
189
- entry at ≥1.00× vs mlx-lm on a stable pass, eval-suite rows recorded.
190
-
191
- Note: `profile.ts` keeps `FidelityTier = "l1" | "l2" | "l3"`, where `l3` means
192
- `oracle: null, claim: "measured"` — the Lab, named by its old letter. There is
193
- no `--l3` on the CLI (it hard-errors; §7).
194
-
195
- ### Features decompose ALONG the layers
196
-
197
- Per-request LoRA is the worked example: L1 = the math (`Wx + scale·B(Ax)`,
198
- oracle-gated vs mlx-lm's tuner); L3 = the policy (which rows run which
199
- adapter; today one active adapter per batch, and adapter requests run on the
200
- serial mechanism); L4 = the surface (`adapter` field, mount/hot-swap,
201
- discovery); plus one sideways obligation — KV under adapter A ≠ base KV, so the
202
- prompt cache keys by adapter namespace (`cacheNs` in `runGeneration`). When
203
- placing a feature, name its component at each layer and each component's gate.
204
-
205
- ### Sampling's placement and the debranching invariant
206
-
207
- Sampling is *specified* at L4 (request params → a per-row `StepSampler`,
208
- `src/sampler.ts`) and *executed* at L3 (each step, on each row's `[1,V]`
209
- slice; vectorized when all-greedy) — it never enters L1. Everything
210
- per-request-variable is either POST-GRAPH (sampling, grammar masks, stop
211
- logic) or DATA the fixed graph consumes (adapter weights, caches). This is
212
- what keeps the generated graph a straight line. Debranching backlog, still
213
- open: the generated gemma files carry per-token runtime checks (`L > 1 &&
214
- fusedSdpaRuntimeOk(q, mask)` in `src/model/generated/gemma4-*.ts`) that are
215
- per-generation-decidable and should be hoisted out of the token path; compiled
216
- decode already achieves the debranched line dynamically (trace once, replay).
217
-
218
- The shared greedy operation uses native logsumexp followed by tiled normalized
219
- score/index reductions in `src/mlx/normalized-argmax.ts`. It preserves rounding
220
- and lowest-ID ties without materializing the normalized vocabulary array.
221
- The step sampler applies processors and grammar first, and selects this operation
222
- only for built-in greedy requests that do not require metadata. Independent
223
- verification calls the same operation. Fixed-shape compilation caches each
224
- geometry; enclosing shapeless graphs retain native operations. No scheduler,
225
- model-family branch or separate sampling setting selects this optimization.
226
- Actual-model and operation comparisons, plus both-machine serving measurements,
227
- are recorded in benchmarks.md under fused normalized greedy selection.
228
-
229
- ### Layer 0 — the SSD spill substrate
230
-
231
- It is almost always faster to cache to SSD and mmap it back than to
232
- regenerate, and spilling lets RAM be a cache instead of the only tier. Three
233
- implementations prove it: the SSD KV cold tier (`src/ssd-cache.ts`, a
234
- `ColdTier` inside `PromptCache.take()` so both mechanisms restore prefixes
235
- from disk at admission), MoE expert offload (page-aligned mmap), and the
236
- byte-capped prompt cache. Decision: one generic substrate — content-addressed
237
- keys (fingerprint + scheme + adapter + producer version), zero-copy mmap
238
- restore, byte-capped LRU, corruption self-quarantine — that layers 1/2/4
239
- consume. Future clients: vision encoder features, compiled grammars,
240
- quantization results, TurboQuant artifacts. Economics (Josh): the SSD
241
- competes with RECOMPUTE, not RAM — a long agent context is minutes of prefill
242
- vs about a second of NVMe restore, and the ratio grows with context.
243
-
244
- ### The option surface IS the four layers
245
-
246
- Users adjust: (1) how the model graph works — profile, compiled decode; (2)
247
- how quantization works — weight bpw, KV scheme, TurboQuant; (3) how the
248
- scheduler works — concurrency cap, KV budget, drafting policy; (4) the serving
249
- surface — endpoints, adapters, structured output, sampling defaults, caches,
250
- multi-model. Flags, help text, and reference docs should be arranged in these
251
- four groups (§7).
252
-
253
- ## 3. Fidelity: per-scheme oracles, two axes, one decision procedure
254
-
255
- The tier ladder is not a product mode. It is a **map from numeric scheme to
256
- its verification oracle**:
257
-
258
- | scheme | oracle | verification |
259
- |---|---|---|
260
- | bf16 (default), any batch B | **mlx-lm** at the same composition | bit-exact goldens (serial + B=2) |
261
- | uniform kv 4/8 | **mlx-lm** `--kv-bits` (+ optiq's rotating cache class where upstream is NYI) | bit-exact (`kv-quant` tests) — `quantizedSdpaUnfused` is op-for-op mlx-lm's `quantized_scaled_dot_product_attention` |
262
- | mixed per-layer kv (`kv_config.json`) | **mlx-optiq** `install_mixed_kv` | bit-exact (`mixed-kv-parity` test; batched rows per-row vs the serial oracle) |
263
- | TurboQuant KV, rotation-folded weights, mixed-bpw weights, original kernels, batch-invariant kernels | **none exists** → Lab gates | KL vs our own reference path + frozen eval suite + envelope tests + kill switch |
264
-
265
- `--l1`/`--l2` therefore name the first three rows' oracles. Mixed-precision
266
- quantization is NOT demoted by the naked-=-L1 decision — it is the flagship of
267
- the row that mlx-lm cannot oracle.
268
-
269
- ### The two axes (parity gates performance)
270
-
271
- Every optimization has two independent coordinates, and conflating them is
272
- what made the flag surface unreadable:
273
-
274
- 1. **Parity** — which reference does it reproduce bit-for-bit? This sets the
275
- *lowest* tier it may live in: matches mlx-lm → L1; matches optiq but not
276
- mlx-lm → L2; matches neither → no oracle, Lab-gated.
277
- 2. **Performance** — is it the fastest correct way? This sets whether it is
278
- the **default (on)** within its tier or a kept-but-off opt-in.
279
-
280
- **Parity gates performance.** A faster kernel that breaks mlx-lm parity is not
281
- "a faster L1" — it bubbles up to whatever tier its parity allows, and the user
282
- opts in. An *optimization* that still matches the oracle stays low:
283
- compiled decode is ours but is L1 because it replays the same ops bit-for-bit.
284
- Only nodes with no oracle are forced into the Lab.
285
-
286
- ### Decision procedure for any new optimization
287
-
288
- 1. **Measure its parity** (run both ways, compare — one flag, one measurement
289
- per lever). The lowest oracle it matches bit-for-bit is its tier ceiling.
290
- 2. **Measure its performance** vs that tier's current default on a stable
291
- pass:
292
- - faster AND holds the guarantee → becomes the **default (on)** for the tier;
293
- - slower but still correct → a documented **default-off kill switch**
294
- (useful for A/B; never the default);
295
- - breaks the guarantee but offers a real trade-off → a **Lab item**
296
- (env flag, bench script, expiry); earns a default only by beating the L1
297
- baseline in a paired A/B (+ KL PASS if output-changing).
298
-
299
- Worked: *5% less memory, still bit-for-bit* → default-on in L1. *2× tok/s at
300
- KL 0.0015* → Lab item. *Another way, 3% slower, still correct* → kept, off.
301
-
302
- ### Composition rule: a composition inherits its scheme's oracle
303
-
304
- Batching, prompt cache, spec decode, adapters — none change a scheme's
305
- numerics, so composing them with a scheme verifies against THAT scheme's
306
- oracle, per row. Batched bf16 anchors to mlx-lm B=N goldens; batched mixed-KV
307
- anchors to optiq's per-row mechanics (our serial `maybeQuantizeKv` is the
308
- verified op-for-op copy) and gates on per-row bit-exactness of the unpadded
309
- row plus a calibrated envelope for padded rows (their noise is pre-existing
310
- bf16 reduction order under grid snapping, measured at the pinned join step).
311
- Do NOT invent Lab-style KL/teacher-forced gates for a composition of an
312
- oracle-backed scheme; the Lab is only for schemes with no oracle at all.
313
-
314
- ### Flag classification (from the tier framing)
315
-
316
- A flag falls into exactly one of three buckets:
317
-
318
- | flag selects… | tier effect | what it IS | action |
319
- |---|---|---|---|
320
- | the only viable route | — | not a choice | always-on default; no flag |
321
- | between two routes at the same tier / same oracle | none | a kill switch (A/B, debugging) | default the fast one; keep the slow one documented |
322
- | between an oracle-backed route and a no-oracle route | tier ↔ Lab | a real parity ⇄ optimization knob | keep, document as such, group by layer |
323
-
324
- Training flags classify the same way (verified in `src/cli.ts` train help):
325
- `--grad-clip` is an always-on guard; `--seg N` / `--no-segment` is a
326
- memory↔compute knob, bit-exact either way; `--grad-accum` and `--lambda` are
327
- training-quality/hyperparameter knobs; `--no-flash` (flash-CCE head → the
328
- MLX fused head) and `--no-prefix` (prefix-shared forward → two-forward) are
329
- the only true parity ⇄ optimization toggles on that surface. The 2026-06-21
330
- "parity-tier DAG" HTML map that motivated this classification
331
- (`docs/dag/training-inference-map.html`) no longer exists in the tree; the
332
- roadmap it proposed — derive the graph from code, CI-enforce "an L1-tagged
333
- node has a passing bit-exact test", shrink the no-oracle surface, generate the
334
- flag surface from the graph — remains an idea, not a phase.
335
-
336
- ### Lab lifecycle rule (the anti-flag-pile law)
337
-
338
- Every Lab experiment ships with (a) a hypothesis in frontier-axis terms, (b) a
339
- paired A/B bench script, (c) an expiry review date. Outcomes: promote to
340
- default (with stable-pass numbers) or delete (with a breadcrumb in the design
341
- doc). No third state. "Off in every regime with no promotion path" is a
342
- deletion that hasn't happened yet.
343
-
344
- ## 4. Decision: the naked default IS L1 (2026-07-05, Josh)
345
-
346
- The 2026-07-05 h2h pass showed the L1 kernel set at decode parity with mlx-lm
347
- on every model while every output-changing lever failed to beat it in a paired
348
- A/B, and quantized KV measured slower than bf16 at ≤16k on both stacks (it
349
- buys memory headroom only). The record with numbers is PLAN.md "Decision:
350
- naked default = --l1".
351
-
352
- - **Naked = `--l1`.** `applyDecodeRoute` (`src/cli.ts`) defaults the tier to
353
- `l1`: bf16 KV, compiled decode on, compiled activations on, fused SDPA off.
354
- - **Prior perf-optimization work is untrusted until re-proven** from this
355
- baseline (the losers were deleted the same day — §11 History).
356
- - **The bar for any lever to earn a default back:** a paired A/B win vs L1 on
357
- a stable pass (no `unstable` tag), plus KL PASS if output-changing.
358
- - **Explicit `--kv-quant` picks its oracle's composition**: `config` → optiq's
359
- fused prefill SDPA + stock unfused decode (the L2 golden composition);
360
- uniform `4|8` → unfused (mlx-lm's algorithm, L1-eligible); `turbo[:k.v.]` →
361
- dequantize-on-fetch through stock `ops.sdpa` (Lab). `--fused-sdpa` still
362
- overrides either.
363
- - **`--l1`/`--l2` are pure aliases.** Each expands to a fixed set of per-fork
364
- values (`TIERS` in `applyDecodeRoute`), installed through
365
- `configureRuntime()` into the immutable runtime snapshot before model modules
366
- load; a per-fork flag overrides one value. Two invariants: a user can
367
- reproduce any tier byte-for-byte from individual flags, and no preset may set
368
- anything that isn't also an individual flag.
369
-
370
- ## 5. The engine: concurrency IS the batch size
371
-
372
- **Decision (Josh, 2026-07-05): batching is determined by how many concurrent
373
- requests are in flight, not by a flag.** One request = a lone row at serial
374
- speed; N requests = continuous batching; rows join and leave running batches.
375
- This reversed `docs/design/batching.md`'s "`--batch N` is a mode switch" decision.
376
- The old objection — "an idle vs loaded server produces different numerics for
377
- the same request" — gets a real answer:
378
-
379
- 1. **The L1 oracle itself behaves this way.** `mlx_lm.server` auto-batches;
380
- "drop-in for mlx-lm" *requires* concurrency-driven batching. The parity
381
- contract is **bit-exact to mlx-lm at the same batch composition**.
382
- 2. Anyone who needs load-independent numerics pins `--batch 1`.
383
- 3. **Batch-invariant kernels** (identical numerics regardless of B) are a Lab
384
- research item; if they land, determinism-under-load returns for free.
385
-
386
- **The flag stays `--batch`** (no rename); its semantics are the cap on
387
- concurrent rows (`--decode-concurrency` is accepted as the mlx_lm.server
388
- alias). **Default 8** (`serverOptions.batch ?? 8` in `src/server.ts` and
389
- `src/cli.ts`) — optiq's Mac-safe concurrency default and the 4–8-sub-agent
390
- workload, superseding the earlier 32. `--batch 1` pins the strict serial
391
- executor. An older draft of this doc and its diagram said 32; the code says 8.
392
-
393
- **The workload this is for**: a user's agent harness pointing sub-agents at
394
- one local server. Serial, the Nth agent's first token waits for N−1 full
395
- generations; batched, every agent starts instantly and the fleet's wall-clock
396
- collapses. Consequences: concurrency-driven batching (sub-agents don't
397
- coordinate arrivals), prefix sharing gains priority (shared system prompts),
398
- per-slot adapters, and batching × quantized KV first (long contexts).
399
- "Single-user" in this project means single user, many agents.
400
-
401
- ### The B=1 fast path (the crux gate, met)
402
-
403
- The unified engine could not replace the serial lane until a lone request
404
- through the scheduler matched serial decode speed and bits. mlx-lm's own
405
- `BatchGenerator` at B=1 runs within a few percent of its `stream_generate`
406
- (paired A/B, PLAN.md), so the design was proven achievable; our gap was an
407
- implementation artifact, closed in two moves (both are now design contracts,
408
- §8): readbacks in a pipelined loop must not create ops, and a lone row keeps
409
- bare serial-class caches so the step dispatches the same graph the serial loop
410
- builds. Today `BatchScheduler` runs, for `B === 1 && unpadded && supports(inners)`
411
- with a uint32 pipeline register, the serial engine's `CompiledDecode` step
412
- (adopt-don't-copy: a row joining an empty batch keeps its solo caches as the
413
- inners; the merge copy runs only when a second row actually joins). The
414
- recorded scheduler/serial paired decode ratios are 0.992–0.996 (PLAN.md
415
- "Serving architecture consolidation"), and `GATE-B1-PARITY` (bit-exact vs the
416
- L1 goldens through the scheduler) is green on the curated probes.
417
-
418
- ### Composition is the product
419
-
420
- Every serving capability is a STACKABLE layer on one engine — never a
421
- lane-routing condition, never mutually exclusive. The matrix the engine must
422
- satisfy, with the state of `GenerationGateway.#supportsContinuous` as read on
423
- 2026-08-23:
424
-
425
- | layer | today (src) | end state |
426
- |---|---|---|
427
- | dedicated per-model graph | both mechanisms (profile-routed) | unchanged |
428
- | mixed-precision KV (`affine-config`) | supported per-layer and uniform affine KV use continuous groups; incompatible layouts remain open | one active scheme per server, any B |
429
- | LoRA adapters | compatible ordered adapter sets share a group; context and cache identity bind under the execution lease | per-slot adapter state (vLLM Punica/SGMV pattern: every row runs the adapter math, non-adapter rows at scale 0) |
430
- | speculative decoding (two-model · assistant · dspark · deepspec · native MTP · ngram) | actual speculation uses the serial verifier; supported ordinary requests can batch with a mounted draft | per-slot drafting behind the `DraftSource` seam |
431
- | structured output (grammar) | both (per-row matchers; `MLX_BUN_GRAMMAR_BATCH=0` forces serial) | unchanged; keep the conformance gate |
432
- | sampling (temp/top-p/top-k/min-p/XTC/penalties/HLG/seed) | per-row sampling sessions, including explicit seeds, repetition penalty and logits extras | fully per-row, seeds included |
433
- | logprobs capture | shared row sampling and readback in continuous groups | preserve method composition |
434
- | vision / audio media prompts | serial only (`shape.hasVision`; embeddings-prefill bypasses the prompt cache) | batched media prefill |
435
- | prompt cache / SSD tier | both: scheduler joiners `take()` the longest usable prefix at admission, never-merged rows `put()` back on finish; the cold tier restores inside `take()` | block-granular sharing across rows |
436
- | paged KV (`--paged-kv`) | serial only, Gemma4 bf16, refuses `--batch N>1`, `--kv-quant`, `--draft-model`; bypasses the prompt cache | block-level CoW prefix sharing (vLLM oracle) |
437
-
438
- Ordering of the remaining rows (by value): adapters per slot, then spec per
439
- slot, then logprobs, then chunked prefill interleaving (vLLM policy) so a long
440
- prefill doesn't stall running streams. `scripts/bench-matrix.ts modes` is the
441
- composition scoreboard — every layer added to the scheduler gets a cell and a
442
- parity gate.
443
-
444
- ## 6. Request path today
445
-
446
- Modules in order, as read in `src/` on 2026-08-30:
447
-
448
- 1. **The request pipeline** (`src/serve/`). A request is data; each stage
449
- is one program with a declared input and output, composed in order by
450
- `src/server.ts` (which otherwise only assembles the server — KV scheme,
451
- prompt cache + SSD tier, gateway, admission — and dispatches routes):
452
- `new ChatRequest(body)` (`chat-request.ts`; validation at construction,
453
- mlx-lm's 400 messages) → `ChatStage.run` (`chat-stage.ts`; template render
454
- + prompt ids, media embeddings by family, grammar, adapters, sampling
455
- defaults via `request-prep.ts`) → `InferenceRequest` (`inference-request.ts`)
456
- → `InferenceStage.admit` (memory ceiling → reject or clamp; seals the plan)
457
- → `InferenceStage.run` → `InferenceResult` → wire. `/v1/completions` is
458
- `TextCompletionStage` into the same inference stage; `/v1/messages` and
459
- `/v1/responses` reuse `ChatStage` and format the result themselves. One
460
- JSON/SSE writer (`http.ts`) serves every surface; the protocol object
461
- (`openai-wire.ts`, `src/anthropic.ts`, `src/responses.ts`) is the only
462
- thing that differs.
463
- 2. **`src/serve/completion-executor.ts` `prepareCompletion()`** → **`src/serve/request-plan.ts` `planRequest()`** — admission (memory budget → reject or clamp `maxTokens`), capture options, adapter selection, and the `RequestShape` are derived ONCE for chat and raw-text, streaming and non-streaming. The result is an opaque, single-use `PreparedCompletion`; adapters cannot inspect or rewrite the plan. Owned resources (media arrays, grammar) dispose on rejection.
464
- 3. **`CompletionExecutor.execute()`** — owns one completion attempt: asks the engine for placement, records the lane (`src/serve/lane-registry.ts`), builds the `CompletionSink` (semantic events: content / reasoning / tool calls / stop), collects logprobs, transfers resource ownership exactly once, runs, and settles the terminal summary (finish reason, usage, cached tokens, final lane, speculation stats). Adapters only format that summary.
465
- 4. **`src/serve/generation-gateway.ts` `GenerationGateway.place(shape)`** — freezes one `GenerationPlacement { shape, mechanism: "serial" | "continuous" }`. `#supportsContinuous` is a capability check only (§5 matrix); it never rewrites MTP, KV scheme, TurboQuant, grammar, adapters, or sampling. `run()` rejects a placement made for another shape. One `AsyncMutex` is the single mutual-exclusion domain: a serial run holds it; the scheduler holds it for its whole active period; a waiting serial request drains the batch (mlx-lm's `drain_batch`).
466
- 5. **`continuous` →** `src/serve/batch-scheduler.ts` — admission under `--kv-budget`, chunked interleaved solo prefill, join/merge/extend/filter over per-layer cache types, the pipelined step loop, per-row `StepSampler`, eviction. B=1 takes the adopted-cache fast path (§5). **`serial` →** `runGeneration` in `src/server.ts` → `src/generate.ts` (prompt-cache take/put, snapshot boundary, the chunked prefill, the pipelined compiled decode loop) or, when a draft is mounted and the request is spec-eligible, `src/spec/serve-loop.ts`.
467
-
468
- **The single-path rule.** Options are *declarations* carried through
469
- placement, never forks above the scheduler. A request's resolved settings
470
- (KV scheme, TurboQuant, drafting, grammar, adapters, sampling) are authoritative
471
- from `planRequest` onward; `place()` may only answer "does the continuous
472
- mechanism implement exactly this composition?" — it may not substitute a
473
- cheaper composition to make a request batchable (the optiq bug class: silently
474
- serving bf16 under a quantized scheme). The scheduler independently refuses a
475
- scheme it cannot execute at construction, and `KvScheme` freezes its per-layer
476
- entries so a caller cannot mutate conversion or accounting after resolution.
477
-
478
- **Known deviations from the single-path rule (verified 2026-08-23):**
479
-
480
- 1. **Two prefill loops.** `src/generate.ts` (the chunk loop with the
481
- `snapshotAt` split, the mlx-lm tail-split convention
482
- `min(prefillChunkSize, remaining-1)`, per-chunk `clearCache`) and
483
- `BatchScheduler.#prefillChunk` in `src/serve/batch-scheduler.ts` (the same
484
- conventions re-implemented over `PrefillState` for interleaved admission).
485
- Both are gated bit-exact, but a convention change must land in two places.
486
- 2. **Method selection now precedes placement.** `resolveExecution` selects
487
- speculative or ordinary decoding from the actual request and backend
488
- capabilities. Configuring a draft no longer forces supported ordinary work
489
- into the serial executor. The final design has one shared executor; changing
490
- method must not select a retired execution path. Concurrent speculation is
491
- still an implementation gap, tracked in batching.md.
492
-
493
- 3. **Speculative decoding depth** — DFlash/DSpark, native MTP, behind the
494
- `DraftSource` seam (`docs/design/speculative-decoding.md`).
495
- 4. **Per-model graph work from the baseline** — unroll a model's flat DAG,
496
- find fusion the compiler misses, prove with kernel-trace diffs, promote per
497
- model.
498
- 5. **Batch-invariant kernels** (research) — restores determinism under load.
499
-
500
- ## 10. Decisions log and open items
501
-
502
- 1. **Cap default 8** — flipped 2026-07-05 after the B=1 gates; `--batch 1`
503
- pins arrival-independent numerics; kv-budget admission keeps 8 safe on
504
- small boxes.
505
- 2. **Flag stays `--batch`**; semantics = cap.
506
- 3. **Perf kernel deleted**; a future flash-decode kernel re-derives from the L1
507
- baseline in the Lab — no resurrection.
508
- 4. **`--l1`/`--l2` remain user-facing CLI aliases** (`src/cli.ts` documents
509
- them under "Parity tier"). The 2026-07-05 intent that they become
510
- bench/test vocabulary only has not been executed; if it is, `serve --help`,
511
- `docs/reference/cli.md`, and `server-config.md` change in the same commit.
512
- 5. **Block-paged KV**: an optional serial-only v1 exists (`--paged-kv`,
513
- `docs/design/kv-cache.md`); padded-batch waste removal and block CoW prefix
514
- sharing are its follow-ups, triggered when prefix sharing under batching
515
- becomes the bottleneck.
516
- 6. **Prefix sharing scope**: must extend to the disk tier; first-class cases
517
- are new-session spin-up and server restart — the shared prefix is a durable
518
- object, not a property of one conversation's entry.
519
- 7. **Open composition rows** (§5): adapters, spec, logprobs, media on the
520
- continuous mechanism; chunked prefill interleaving as policy.
521
- 8. **Open single-path deviations** (§6): unify the prefill loops; move
522
- prompt/media/grammar construction behind the seam; lift spec eligibility
523
- into `RequestShape`.
524
- 9. **Debranching backlog** (§2): hoist the generated files' per-token
525
- `L > 1 && fusedSdpaRuntimeOk` checks.
526
-
527
- ## 11. History
528
-
529
- **2026-07-04 — faithful → L1 consolidation.** An audit found three
530
- overlapping "match mlx-lm" mechanisms that disagreed: the `--l1/--l2/--l3`
531
- tier presets, an `MLX_BUN_FAITHFUL` preset that forced the gemma monolith and
532
- set choices no flag could reach, and a family of unwired `Faithful*` model
533
- subclasses. The decisive rule that collapsed them: **"compiled" kernels
534
- (`@mx.compile` geglu/swiglu, compiled decode) go through the same libmlx as
535
- mlx-lm → bit-exact and faster → L1 defaults; custom "fused" Metal kernels were
536
- mlx-bun originals with a proven residual → not bit-exact.** Landed in four
537
- phases: compiled activations default-on everywhere (qwen3, qwen3.5, universal
538
- dense, gemma geglu via `MLX_BUN_COMPILED_GEGLU`, MiniCPM5 swiglu), verified
539
- `maxDiff === 0` vs mlx-lm; `--compiled-activations` and `--fused-gelu` added as
540
- per-fork flags so `--l1` became a pure alias; `MLX_BUN_FAITHFUL`, `faithful.ts`
541
- (→ `flags.ts`, only `flagOn` kept), and the four unwired subclasses deleted;
542
- docs + the "cost of removing each faithful kernel" bench matrix. The only
543
- family that had it right from the start was `qwen3_moe`: the production class
544
- IS the faithful port. Bit-exact-to-mlx-lm *wants* compiled activations (mlx-lm
545
- `@mx.compile`s them), so the earlier `--l1` "unfused" help text was backwards.
546
-
547
- **2026-07-05 — the Phase-1 deletion pass** (same day as the naked-=-L1
548
- decision; ~50 files touched, 23 deleted, suite green). Josh: "we will end up
549
- redoing all the work we have currently done given that we now have a different
550
- starting point." Deleted, one funeral each:
551
-
552
- - `--fused-decode` / `MLX_BUN_FUSED_DECODE` — 1.00×, forced uncompiled decode,
553
- a silent-wrongness footgun.
554
- - `--fused-gelu` / `MLX_BUN_FUSED_GELU` and `MLX_BUN_FUSED_SWIGLU` (+
555
- `fused-mlp-kernel.ts`, `steel-linear-kernel.ts`, the swiglu/geglu/steel
556
- one-off scripts) — +0–1%; the compiled closures already own the fusion win
557
- bit-exactly.
558
- - `--perf-kernel` / `MLX_BUN_PERF_KERNEL` (the fused online-softmax decode
559
- SDPA) with its frozen-oracle scaffolding (`perf-kernel-oracle.test.ts`,
560
- `freeze-perf-oracle.ts`) — regressed e4b in the paired A/B; its one win
561
- carried a KL WARN. Its earlier placement in the L2 preset (commit `f1bf5cc`)
562
- had claimed a bit-exact optiq oracle; the golden was frozen from mlx-bun's
563
- own engine and the gate was argmax agreement, so 2026-07-01 had already
564
- restored the rule that the bare tier is the guarantee.
565
- - `MLX_BUN_CPM5_FAITHFUL` + `FaithfulMiniCPM5` (`minicpm5-faithful.ts`) — the
566
- default IS the faithful path; the op-for-op A/B reference served its purpose
567
- (it is how the unfused-swiglu dispatch tax was found).
568
- - `--l3` as a product mode — the Lab replaces it; the flag hard-errors.
569
- - Training-side flag sanitization (`MLX_BUN_PERF_KERNEL=0` /
570
- `MLX_BUN_FUSED_GELU=0` in trainers, launchers, recipes) — obsolete.
571
-
572
- **2026-07-05 — engine unification** (Phases 0–3.2 of the original migration
573
- plan; numbers in PLAN.md): the B=1 batch-lane gap measured, root-caused to the
574
- two host bugs in §8, closed; batched mixed-KV for full-attention and rotating
575
- layers; adopt-don't-copy + compiled decode at B=1 + prompt cache on the batch
576
- lane; SSD tier moved inside `PromptCache.take()`; non-consuming prefix sharing;
577
- `--isolate` P1 (proxy) and P2 (`ModelPool`, multi-model switching); `--batch`
578
- default 8.
579
-
580
- **2026-08-21 — serving architecture consolidation S0–S3** (live in PLAN.md):
581
- `PreparedCompletion` + `CompletionExecutor` (S0), immutable
582
- `GenerationPlacement` (S1), declared model profiles (S2), `serial | continuous`
583
- as the placement vocabulary with the scheduler's B=1 fast path as the default
584
- lone-request route (S3). S4 (land + post-merge verify) is the open box.
585
-
586
- ## 12. Interface-based engine refactor
587
-
588
- Design requested 2026-09-04. Initial implementation is recorded in §12.13. The R0–R10
589
- checkboxes live in PLAN.md under "Interface-based engine refactor". This
590
- section owns the contracts, migration details, and acceptance criteria.
591
-
592
- ### 12.1 Outcome and scope
593
-
594
- The product objective is to push the Pareto frontier of **speed, quality, and
595
- size for local AI on a Mac**. Josh's goal is that a user sees the result and
596
- asks how that quality, performance, and model size are possible on their
597
- laptop. Interface consistency is useful when it makes those gains easier to
598
- build, compare, compose, and ship. It is not an independent reason to accept
599
- slower execution or a larger working set.
600
-
601
- The current target is **Josh's designated Qwen3.8-27B quants**. They are on a
602
- drive unavailable to this session. Artifact access is needed for target-specific
603
- numerical and performance validation; it does not block the refactor.
604
- The locally cached published flagship and TQ snapshots are not those targets
605
- (Josh clarified this on 2026-09-04); availability must not select the product
606
- baseline. Quant recipes and quality findings remain in [TurboQuant](turboquant.md),
607
- including rejected variants and raw-EOS regressions. Interfaces must preserve
608
- exact packing, rotation, per-layer precision, recurrent-state, and kernel
609
- choices. Other artifacts/families provide compatibility coverage only.
610
-
611
- A downloaded quant supplies weights, configuration, and tokenizer data. The
612
- engine owns the hyperoptimized implementations and the rules for identifying
613
- which quant each one supports. Resolve artifact identity and configuration at
614
- load time, select registered engine code, then retain that binding for execution.
615
- The quant does not supply a graph, kernel, method, plugin, or executable manifest.
616
- An unknown artifact may use a compatible family implementation. An exact
617
- declaration with missing code or incompatible configuration must fail explicitly.
618
- Sessions remain independent of the selected implementation.
619
-
620
- Aggressive specialization for a particular quantization is expected. A
621
- quant-specific layout, graph, fused kernel, cache scheme, compiled schedule,
622
- or complete execution method is a legitimate production implementation.
623
- Several specialized implementations can be worth maintaining when each wins
624
- in a useful regime. Shared orchestration must not force the fastest numerical
625
- implementation through an inefficient generic operator path.
626
- A model implementation may expose several supported execution methods. Loading
627
- the weights does not permanently choose one method; request planning selects
628
- among the compatible methods. Their private graphs, state and numerical loops
629
- can differ while the session contract remains the same.
630
-
631
- A session must work without knowing the model class, graph implementation,
632
- decoding algorithm, cache layout, or scheduling mechanism. Every replaceable
633
- component exposes an interface. Immutable configuration, events, and results
634
- remain data records; implementations keep private helpers private.
635
-
636
- There are three distinct replacement operations:
637
-
638
- | Replacement | Integration change | What must remain compatible |
639
- |---|---|---|
640
- | Dedicated graph → generated, compiled, or quant-specialized graph | Replace one graph registration in a model bundle | Graph ABI, backend, input/output shapes, state ABI, numerical contract |
641
- | Autoregressive → speculative or diffusion method | Select a method registration and its compatible graph bundle | Session lifecycle, committed-output events, cancellation, accounting |
642
- | MLX implementation → another runtime | Register a complete backend bundle with its graphs, state, sampling, and resource services | Engine/session contracts; a numerical claim requires separate evidence |
643
-
644
- The first operation must require no session, scheduler-policy, route, or
645
- application changes. The second must require no method-specific session or
646
- protocol branches. A different numerical runtime cannot reuse MLX tensor
647
- handles merely because the TypeScript interface matches.
648
-
649
- Preserve the existing APIs and numerical defaults during migration. A new
650
- internal interface does not implicitly expand supported feature combinations.
651
- Keep one repository and the single-binary distribution. Remote compute, new
652
- model families, a universal tensor library, a generic graph compiler, and true
653
- B-wide prefill are separate projects. Training gets its own task interface;
654
- it does not pretend to be a text-generation session.
655
-
656
- This scope boundary does not defer quant-specific optimization. The refactor
657
- must accommodate the existing quantization campaign and future optimized
658
- implementations throughout migration. New numerical work has separate paired
659
- validation, so structural changes cannot conceal a quality or performance
660
- tradeoff. §12.11 defines the shared frontier scorecard.
661
-
662
- Package organization is now a planned decision in the
663
- [public-readiness program](../../PLAN.md#public-readiness), separate from
664
- the optimization campaign. §12.15 records the initial boundary audit and
665
- remaining evidence needed before choosing a workspace layout. Preserve
666
- in-process execution and the single-binary distribution; package boundaries
667
- must follow ownership and dependency needs without adding decode overhead.
668
-
669
- ### 12.2 Dependency structure
670
-
671
- ```mermaid
672
- flowchart TD
673
- Apps["CLI / HTTP / Pi / memory / evaluation"] --> Client["CompletionClient and task interfaces"]
674
- Client --> Prep["Prompt preparation and request planning"]
675
- Prep --> Engine["InferenceEngine"]
676
- Engine --> Session["GenerationSession lifecycle"]
677
- Engine --> Schedule["Scheduler policy and resource admission"]
678
- Session --> Method["InferenceMethod"]
679
- Schedule --> Group["SchedulingAdapter / ExecutionGroup"]
680
- Group --> Method
681
- Method --> Graph["Graph interface"]
682
- Method --> State["State and checkpoint interfaces"]
683
- Method --> Sample["Sampling / constraints / draft interfaces"]
684
- Graph --> Backend["Backend runtime and resource leases"]
685
- State --> Backend
686
- Sample --> Backend
687
- Compose["Composition root and implementation registry"] -.-> Engine
688
- Compose -.-> Method
689
- Compose -.-> Graph
690
- Compose -.-> Backend
691
- ```
692
-
693
- Interfaces belong to the consumer's contract layer. Composition roots import
694
- implementations and supply them explicitly. No service locator inside a token
695
- loop, import-time self-registration, dependency injection framework, or
696
- reflection-based constructor discovery is needed.
697
-
698
- Proposed homes, introduced only as their migration phase lands:
699
-
700
- | Home | Responsibility and permitted dependencies |
701
- |---|---|
702
- | `src/contracts/` | Portable requests, events, results, session/client/task interfaces. No Bun, DOM, MLX, concrete model, or application imports. |
703
- | `src/engine/` | Session lifecycle, planner, scheduler policy, admission. Depends on contracts and injected ports. |
704
- | `src/inference/` | Method and graph contracts; reusable AR orchestration, verification, and scheduling adapters. Tensor-facing code is parameterized by a backend binding. |
705
- | `src/backends/mlx/` | MLX runtime, typed bindings, resource owners, execution groups, state adapters. Wrap existing numerics before relocating files. |
706
- | `src/model/` | Existing model math behind graph adapters, artifact profiles, loaders. Concrete implementations may use MLX internally. |
707
- | `src/serve/` | Protocol parsing/framing and transport; calls the completion client. No concrete graph selection or cache surgery. |
708
- | `src/app/` | Composition roots, runtime bootstrap, server/application assembly. The intentional location for concrete imports. |
709
- | Existing application directories | Memory, Pi, web, eval, train, quantize consume their declared client/task ports. Move root modules only when their dependencies have been separated. |
710
-
711
- Use TypeScript projects plus an AST/import-resolution boundary check. The check
712
- must follow type-only imports, re-exports, aliases, and literal dynamic imports.
713
- New forbidden edges fail; temporary legacy edges have a named R-phase owner and
714
- a deletion gate. Browser contracts cannot import declarations out of pi-web.ts.
715
- No new concrete model checks in engine/session/planner code. Model-specific
716
- checks remain legitimate inside the model's own adapter.
717
-
718
- ### 12.3 Interface inventory
719
-
720
- These are responsibility boundaries, not a mandate for one class per row.
721
- Small stateless ports may be implemented by functions or object literals.
722
-
723
- | Interface | Owns | Must not own |
724
- |---|---|---|
725
- | `CompletionClient` | Semantic completion request, event stream, terminal result, cancellation | Tensor/state handles, model class selection |
726
- | `PromptPreparer` | Coordinate renderer, tokenizer and media preparation; produce token IDs and a stable-prefix boundary | Template syntax, tokenizer algorithms, GPU scheduling or request-global model mutation |
727
- | `RequestPolicyResolver` | Resolve defaults and explicit overrides once into immutable policy | Executing model work or resampling defaults inside a token loop |
728
- | `ChatTemplateRenderer` | Render messages, tools and reasoning markers; identify stable rendered boundaries | Tokenizer algorithms, scheduling or cache retention |
729
- | `Tokenizer` | Encode/decode, token metadata and incremental encoding | Chat-template policy, sampling or scheduling |
730
- | `ExecutionPlanner` | Effective immutable policy, implementation selection, capability negotiation, declared implementation choices, plan identity | Starting generation or inventing new feature support |
731
- | `InferenceEngine` | Session creation, runtime coordination, shutdown | Per-family forward math |
732
- | `GenerationSession` | Lifecycle, committed output, result, cancellation and close | Token-at-a-time assumption, KV offsets, concrete method branches |
733
- | `InferenceMethod` | AR/speculative/diffusion algorithm and private per-run state | HTTP framing or application sessions |
734
- | `SchedulingAdapter` / `ExecutionGroup` | Method-specific join/leave and bounded execution work | Queue priority policy or independent memory admission |
735
- | `Scheduler` | Fairness, active-row cap, queue limits, safe-point dispatch | Cache merge math, sampler math, model-family checks |
736
- | `ModelBundle` / `GraphFactory` | Artifact construction, graph selection, compatible backend/state services | Rewriting requested sampling or KV policy |
737
- | `AutoregressiveGraph` | Forward-to-hidden and selective logits projection | Token selection, prefill loop, stopping, persistence |
738
- | `DenoisingGraph` | Canvas/noise-step operations required by diffusion | Pretend AR cache or fake next-token API |
739
- | `SpecializedExecutionFactory` | Quant/artifact/device-specific fused execution behind the same method/group contract | Changing quality policy or observable session semantics without a declared plan |
740
- | `SamplingPolicy` / `SamplingKernel` | Shared processor/mask/logprob/sample/history semantics and backend execution | Transport, independent request defaults |
741
- | `ConstraintProvider` / `DraftProvider` | Per-run constraint state or proposals under declared capabilities | Mutating target model fields outside a bound context |
742
- | `StateFactory` and capability facets | Owned state, borrowing, snapshots, batch operations, rollback where supported | Assuming every state is trimmable token KV |
743
- | `PrefixStore` / `CheckpointStore` | Lookup, retention, integrity, atomic persistence and version checks | Reconstructing arbitrary concrete cache classes itself |
744
- | `ResourceManager` / `ResourceLease` | Reservations, backing memory lifetime, device completion, release | Model math or hiding synchronization |
745
- | `ArtifactResolver` / `TokenizerProvider` | Pinned artifact identity, tokenizer/template provenance and loading | Request execution |
746
- | `TelemetrySink` / `Clock` | Structured observations and time | Scheduling or output decisions |
747
- | `EngineHost` / `TaskRunner` | Direct or isolated runtime lifecycle; train/quantize task execution | Sending live tensor handles across a process boundary |
748
-
749
- Existing `CompletionExecutor`, `CompletionSink`, `DraftProvider`, `DraftSource`,
750
- model profiles, `KvScheme`, and the cache codec table are starting points.
751
- Adapt or evolve them; do not retain a second permanent wrapper hierarchy.
752
-
753
- ### 12.4 Session and graph contracts
754
-
755
- Illustrative signatures below fix the intended separation. Supporting record
756
- types are specified by the semantics in this section and finalized in R1.
757
- They are not implemented public exports yet.
758
-
759
- ```ts
760
- interface InferenceEngine {
761
- open(request: GenerationRequest, control: RunControl): Promise<GenerationSession>;
762
- close(): Promise<void>;
763
- }
764
-
765
- interface GenerationSession {
766
- readonly id: string;
767
- readonly events: AsyncIterable<GenerationEvent>;
768
- readonly result: Promise<GenerationOutcome>;
769
- cancel(reason: CancelReason): Promise<void>;
770
- close(): Promise<void>;
771
- }
772
-
773
- type GenerationEvent =
774
- | { type: "committed"; sequence: number; tokenIds: readonly number[] }
775
- | { type: "progress"; usage: UsageSnapshot };
776
-
777
- interface InferenceMethod<Binding> {
778
- readonly descriptor: MethodDescriptor;
779
- createRun(plan: ExecutionPlan, binding: Binding): Promise<MethodRun<Binding>>;
780
- }
781
-
782
- // Tensor-facing contracts exist only inside a compatible backend bundle.
783
- interface AutoregressiveGraph<Tensor, State, Inputs> {
784
- readonly descriptor: GraphDescriptor;
785
- forwardHidden(inputs: Inputs, state: State): Tensor;
786
- projectLogits(hidden: Tensor, selection: LogitSelection): Tensor;
787
- }
788
-
789
- interface GraphFactory<Graph, Binding> {
790
- readonly descriptor: GraphDescriptor;
791
- open(artifact: ResolvedArtifact, binding: Binding): Promise<Graph>;
792
- }
793
- ```
794
-
795
- `GenerationSession` is one completion attempt, distinct from a Pi conversation
796
- or application thread. The engine coordinates independent sessions sharing a
797
- resident model. The method's private run owns prompt position, sampler history,
798
- pending device work, and caches/canvas; those do not become session fields.
799
- `RunControl` uses a portable cancellation port; HTTP adapters translate their
800
- AbortSignal into it. Contract declarations do not pull in browser/server modules.
801
-
802
- All methods publish only irrevocably committed token spans. A span can contain
803
- one token, an accepted speculative group, or a whole completed diffusion
804
- result. Tentative diffusion canvas revisions and rejected draft tokens are
805
- private. A non-streaming method may publish nothing until its final output.
806
- The existing completion sink converts committed tokens to semantic text,
807
- reasoning, tools, stops, and protocol usage. Tokenizer identity is fixed at
808
- session open. Task types that cannot provide this token contract use a separate
809
- task interface rather than fabricated tokens or usage.
810
-
811
- Lifecycle is `created → preparing → queued → running → settling → terminal`.
812
- Terminal outcome is exactly one of completed, cancelled, or failed. Each state
813
- accepts cancellation. Early iterator return initiates cancellation. Only one
814
- consumer may read events; progress observation cannot steal output. A bounded
815
- queue propagates backpressure to scheduling between safe work units. Never
816
- silently drop output or let a slow consumer retain unlimited device state.
817
-
818
- `result` settles once on every path, including no consumer, worker death,
819
- preparation failure, and cancellation. It contains a discriminated outcome
820
- with final usage/error data. Events already emitted remain a partial result
821
- on failure. GenerationRequest declares streaming or collecting consumption at
822
- open. Streaming starts on demand and has a configured idle-consumer deadline;
823
- an abandoned/unread stream cancels when that deadline expires. Collecting runs
824
- without an event reader, reserves output storage against the admitted maximum,
825
- and returns collected tokens with the outcome. Insufficient collection capacity
826
- fails admission; it never silently truncates output. R1 fixes the queue/deadline
827
- defaults with tests. Completed sessions reject further advancement;
828
- cancel/close are idempotent. Close cancels live work and awaits safe release.
829
-
830
- Graph calls remain direct device operations. The interface does not insert
831
- an await, readback, tensor wrapper, or synchronization for each operator.
832
- `forwardHidden` plus selective `projectLogits` preserves the existing ability
833
- to avoid a full prompt-length × vocabulary logits allocation. Compile caches
834
- belong to the implementation and key on the graph/state/request parameters
835
- that affect their trace. A graph factory owns and closes resident weights;
836
- individual runs borrow them through leases.
837
-
838
- The selective-hidden/logits interface is the reusable AR path. A specialization
839
- may instead implement a coarse execution contract that fuses graph, head,
840
- sampling, or state updates and never materializes those intermediate tensors.
841
- It must preserve the declared sampler/constraint semantics, accounting, safe
842
- points, and resource ownership, and pass the same conformance suite. Do not
843
- require a fused kernel to synthesize hidden/logits objects solely to satisfy
844
- an abstraction. The planner binds this alternative once through the registry;
845
- the session and scheduler policy remain unchanged.
846
-
847
- R1 must specify graph ABI dimensions, dtypes, mutation rules, position/mask
848
- inputs, output ownership, and evaluation semantics. Include media inputs,
849
- hidden taps, and adapter bindings as typed graph capabilities. Move mRoPE,
850
- adapter selection, and hidden taps out of mutable model-global request fields
851
- into bound per-run contexts. While legacy models still mutate those fields,
852
- their adapter requires the exclusive lease and restores them on every exit.
853
-
854
- The registration bundle binds graph, tensor type, state factory, sampler,
855
- device runtime, and optional capabilities together. Use generics and opaque
856
- handles internally; do not erase them with `any` or public casts. Validate
857
- backend ID, state ABI, graph ABI, and artifact identity at construction and
858
- restore. TypeScript compatibility alone does not establish numerical parity.
859
-
860
- Specialization keys may include exact artifact fingerprint, weight quant/layout
861
- and packing version, layer/shape geometry, KV scheme, Mac GPU capabilities,
862
- context regime, and batch regime. Dispatch is planned or bound at a safe shape
863
- transition, with a validated compatible fallback outside the optimized range.
864
- It must not become a collection of per-token environment checks. Fused paths
865
- may retain optional features only when implemented; capability negotiation
866
- selects another faithful implementation when the requested composition needs it.
867
-
868
- ### 12.5 Capability negotiation and planning
869
-
870
- Replace scattered feature booleans with versioned capability descriptors and
871
- typed capability interfaces. Obtain a complete optional facet once during
872
- planning, such as rollback or batch join. The core never probes a handful of
873
- optional methods and hopes they form a complete implementation.
874
-
875
- Evaluate the whole composition: artifact/profile, graph, method, KV scheme,
876
- sampler, seed, constraints, adapters, media, checkpointing, and batching.
877
- Two independently supported features do not prove their combination works.
878
- Each supported composition links to its conformance/oracle test cell.
879
-
880
- Within a compatible composition, selection may use a measured execution recipe
881
- for the artifact/quant/device/workload. A recipe binds the entire implementation
882
- bundle, its quality contract, and resource model. It can choose a quant-specific
883
- fused method rather than a generic graph. Record provenance and the evidence
884
- behind automatic selection. Never optimize by changing the requested artifact,
885
- quant, or quality tier without an explicitly permitted product policy.
886
-
887
- Planning returns supported, refused, or an explicit policy-permitted fallback
888
- with reasons. Distinguish required request behavior from preferred acceleration.
889
- Retain existing intentional fallback behavior during migration and record it
890
- in the plan. Never silently change a required scheme, constraint, seed, or
891
- adapter to gain batching. Preserving existing support also means retaining
892
- explicit refusals. Fallback ordering is deterministic and tested.
893
-
894
- The plan contains artifact and tokenizer identities, implementation IDs/ABIs,
895
- oracle tier, actual algorithm, resolved sampling/stop policy, state layout,
896
- cache/checkpoint policy, resource estimates, and allowed execution shapes.
897
- Dynamic batch membership is runtime state within those allowed shapes. Record
898
- it in traces; do not freeze a future arrival schedule into admission.
899
-
900
- Normalize environment/CLI/request configuration at the boundary. Capture an
901
- immutable effective snapshot per engine/run. No runtime configuration lookups
902
- inside forward/decode after binding. Experiment commands construct separate
903
- bindings with explicit snapshots. Diagnostics may observe a running request
904
- but cannot change its numeric policy halfway through execution.
905
-
906
- Configuration follows ownership: scheduling owns concurrency and queue policy;
907
- methods own sampling, speculation and stopping; backends own kernels and state
908
- layouts; storage owns cache budgets, tiers and persistence. The application
909
- composition root binds these interfaces. A single-request caller supplies the
910
- same method configuration as a batched caller. Consolidate duplicate controls
911
- as implementations migrate, retaining documented CLI aliases where needed.
912
-
913
- Default memory estimates are advisory by Josh's instruction. Attempt the
914
- requested work without predicted-memory refusals or automatic token clamping.
915
- Explicit user limits and actual layout requirements still apply. Account for
916
- shared weights once, live state, draft resources, preparation transients and
917
- retained/write-behind buffers. Release actual resources on failure; a
918
- conservative estimate does not establish that execution is impossible. This
919
- supersedes the earlier mandatory reservation-before-preparation design.
920
-
921
- ### 12.6 State, ownership, and persistence
922
-
923
- Resource rules apply to success, partial construction, eviction, cancellation,
924
- rollback, shutdown, and native failure:
925
-
926
- - A resource has one owner, with explicit borrowed views or retained leases.
927
- Ownership transfer is a checked operation; a resource cannot be disposed by
928
- both the old and new owner. Close is idempotent and attempts every release
929
- even if one cleanup fails, preserving the original execution error.
930
- - Device handles and host/mmap backing memory have distinct lifetimes. A native
931
- completion fence governs final backing release. JS scope exit or array
932
- disposal alone is insufficient. Never restore a JS callback destructor on
933
- a Metal completion thread. Finalization remains a diagnostic/backstop.
934
- - Replace `stateNeedsDispose` with an explicit owned state-view lease. Snapshot
935
- creation returns a stable owner; later writes to the donor cannot change it.
936
- Prefix lookup returns retained state and its exact logical coverage.
937
- - State capability facets include snapshot, prefix reuse, trimming, batch
938
- merge/extract/filter, and speculative transaction. Recurrent state supports
939
- exact restore/replay where proven; diffusion state can expose a different
940
- snapshot without claiming a token prefix or trim operation.
941
- - A speculative transaction includes every participating layer and draft-side
942
- state. Commit or rollback leaves one consistent accepted prefix. Partial
943
- failure invalidates the run; it cannot return uncertain state to PrefixStore.
944
- - Storage policy is separate from layout codecs. Provider-owned codecs bind
945
- formats to a compatible implementation. Keep streamed tensor writes,
946
- corruption checks, atomic publication, byte caps, and bounded spill queues.
947
- Do not replace the current copy-restore with unsafe mmap borrowing for style.
948
-
949
- Prefix identity and generation-resume identity are separate records. Prefix
950
- identity covers artifact content, tokenizer/template interpretation, adapters
951
- and their revisions, effective numeric scheme, graph/state compatibility, and
952
- media content when reuse is supported. Generation identity additionally covers
953
- the complete normalized request, stop strings, sampling/seed policy, method,
954
- constraints, generation limit, and resume schema. Canonicalize map keys while
955
- preserving semantically ordered arrays. Store the descriptor as well as its
956
- digest, and validate it on restore.
957
-
958
- A resume snapshot includes consumed input coverage, committed completion count,
959
- pending token/device work in a restorable form, RNG/history position, and any
960
- method/constraint state needed for exact continuation. Physical cache offset,
961
- committed output, and bytes delivered to a client are different quantities.
962
- Snapshots are legal only at declared safe points. Unsupported exact-resume
963
- compositions remain refused or disabled as documented.
964
-
965
- Retries must distinguish a new generation from a resumed attempt. Preserve the
966
- current replay contract through its compatibility adapter; explicitly design
967
- any future idempotency/resume field before changing the public API. Never claim
968
- exactly-once delivery across a broken stream or automatically replay tool side
969
- effects. Cold-prefix misses may recompute; an incompatible exact-resume request
970
- must report the mismatch rather than invent a continuation. Version the format
971
- and define read-old/write-new compatibility or explicit invalidation per change.
972
-
973
- ### 12.7 Scheduling and inference methods
974
-
975
- Keep policy independent from mechanics. Scheduler chooses eligible work,
976
- fairness, queue bounds and active-row limits. A method's
977
- scheduling adapter creates execution groups and implements join/leave/advance
978
- over its own state. Native batch merge and filter stay inside the MLX adapter.
979
- Scheduler must not import KV classes or perform a per-layer tensor loop.
980
-
981
- The consolidation target is single-request execution as a batch of one through
982
- these same contracts. Methods publish reusable checkpoints through the shared
983
- cache interface at completed boundaries. The cache owns prefix selection,
984
- retention and RAM/SSD placement; scheduling does not choose a storage tier, and
985
- decode does not inspect the request queue. Model/method codecs describe the
986
- state needed to restore a prefix, including draft state when applicable.
987
- Prefill and generated tokens populate the same cache. R17 in the decode-speed
988
- program owns the current implementation and acceptance work.
989
-
990
- Full batch feature parity is required, including speculation. The current
991
- serial exclusions are migration work, not the target architecture. Keep an
992
- explicit feature matrix in the batching design and retire duplicate request
993
- lifecycles only after the batched implementation covers every serial feature
994
- and equals or beats serial performance in matched measurements. B=1 latency
995
- and feature-specific costs must pass independently of aggregate throughput.
996
- The optimized kernels already built remain behind the backend interface;
997
- scheduling policy does not choose or reimplement their arithmetic. Continue
998
- building faster specializations, fusing operations, removing work and avoiding
999
- materialization. Interfaces must permit complete fused work units rather than
1000
- force one call or intermediate tensor per logical operation. Measure kernel
1001
- changes separately from composition refactors so their effects are attributable. Interface
1002
- extraction must not force tensor copies, materialization, synchronization or
1003
- additional dispatches; compare B=1 latency and B>1 throughput at fixed settings.
1004
-
1005
- An advancement is a bounded safe unit, not necessarily a token: one prefill
1006
- chunk, a pipelined decode step, one verify round, or one denoising iteration.
1007
- Budgets describe admitted resources and work hints separately. A synchronous
1008
- kernel cannot be interrupted; cancellation is honored at the next safe point.
1009
- Keep pending MLX work between advancements to preserve decode overlap. No
1010
- mandatory GPU synchronize or full logits readback at the scheduling boundary.
1011
-
1012
- An execution group owns its resident run handles exclusively. Join/leave
1013
- validates compatibility before state mutation. Group-wide failure either
1014
- proves unaffected rows safe or fails the entire group; it cannot publish
1015
- possibly corrupted snapshots. Slow readers stop receiving dispatch while their
1016
- reservations remain accounted for; cancellation releases them after pending
1017
- device work is safe. Queued cancellation removes the waiter promptly so a dead
1018
- serial request cannot keep batch admission in drain mode.
1019
-
1020
- Migrate these existing algorithms behind the contracts:
1021
-
1022
- | Method/component | Preserved behavior |
1023
- |---|---|
1024
- | AR method | Shared prefill program, existing tail split/snapshot boundaries, sampler order, pending-token pipeline |
1025
- | Speculative method | Existing verifier and DraftSource variants, actual proposal length, target taps, per-step RNG, recurrent rollback, source-specific prefill convention |
1026
- | Fill/grammar acceleration | Explicit assert/verify proposal policy and constraint state; preserve current exclusions and fidelity gates |
1027
- | Diffusion method | Existing denoising behavior with private canvas state and committed output only; no fabricated AR state |
1028
- | Continuous execution adapter | B=1 adopted-cache path; existing merge/extract/filter operations and per-row sampler history |
1029
- | Quant-specific execution | Fused or precompiled work units with the same observable semantics and explicit numerical tier; no forced intermediate allocations |
1030
-
1031
- Shared AR prefill does not imply full-prompt forwarding for every method.
1032
- Native GLM MTP already declares a different prefill convention. Preserve it as
1033
- data in the method plan. Likewise, unifying solo prefill code does not establish
1034
- bit identity with B-wide prefill or broaden the batch support matrix.
1035
-
1036
- The shared prefill program is the canonical policy for segmentation, snapshots,
1037
- and cancellation. A measured specialization can execute that program through
1038
- a different kernel schedule while satisfying its numerical and resource
1039
- contract. Share the decisions; do not prohibit a faster executor merely because
1040
- its implementation cannot reuse a helper function.
1041
-
1042
- ### 12.8 Applications, library, and process boundaries
1043
-
1044
- Keep the existing token-to-semantic completion pipeline. `CompletionClient`
1045
- is the application/transport boundary; `GenerationSession` is the worker's
1046
- method-neutral token boundary. An ordinary OpenAI-compatible remote endpoint
1047
- can implement CompletionClient without exposing token IDs or local checkpoints.
1048
- It cannot masquerade as a fully capable local GenerationSession.
1049
-
1050
- Provide direct and isolated CompletionClient/EngineHost implementations. Evolve
1051
- the existing `src/serve/isolate.ts` EngineChild, ModelPool, health gating,
1052
- restart policy, and HTTP-over-Unix-socket proxy. Isolation already exists.
1053
- Do not build a competing supervisor or change the wire protocol merely to
1054
- match internal interfaces. Current whole-server isolation remains supported
1055
- while CPU application services are separated from worker-owned compute.
1056
-
1057
- Worker requests contain portable policy and media descriptors/bytes. Grammar
1058
- controllers, media tensors, sampler closures, state handles, and device leases
1059
- are created in the worker. A crash fails in-flight completion attempts, resets
1060
- worker-owned residency, and preserves parent health/application state. Existing
1061
- GET/HEAD retry behavior does not authorize automatic generation POST replay.
1062
- Cross-process resume requires the explicit checkpoint/replay contract above.
1063
-
1064
- One resource coordinator covers inference and managed training/quantization
1065
- jobs that share a runtime host. Preserve the existing jobs subprocess design
1066
- and persist terminal job state. Do not describe this coordinator as controlling
1067
- unrelated external Python processes or a separately launched training run.
1068
-
1069
- The high-level library opens a runtime asynchronously before importing/loading
1070
- native implementations. Root high-level imports must work without installed
1071
- MLX. Keep advanced native/model access in explicit low-level exports with clear
1072
- ownership and bootstrap requirements. Compatibility wrappers preserve current
1073
- exports until a deliberate versioned removal; they may not maintain duplicate
1074
- generation loops. Validate the packaged binary and native sidecars, not only
1075
- source execution, before release.
1076
-
1077
- ### 12.9 Current-to-target migration map
1078
-
1079
- | Current code | Target and removal condition |
1080
- |---|---|
1081
- | `src/server.ts` runGeneration | Method/cache orchestration moves to inference/engine services; server retains composition and route dispatch |
1082
- | `src/generate.ts` | Compatibility entry around the AR method/session; one shared prefill and pending-token implementation |
1083
- | `src/serve/batch-scheduler.ts` | Split queue policy from MLX execution-group mechanics; delete duplicate prefill after parity gates |
1084
- | `src/serve/generation-gateway.ts` | Planner plus scheduling/resource coordination; remove late feature eligibility and concrete model probes |
1085
- | `src/serve/{request-plan,completion-executor,completion-sink}.ts` | Evolve into the request/session boundary and semantic adapter; retain tested accounting/framing behavior |
1086
- | `src/model/{factory,profile}.ts` and concrete graph files | Model bundle registration and graph adapters; replace the central concrete RuntimeModel union in generic consumers |
1087
- | `src/model/gemma4-base.ts` cache classes | Shared state contracts leave the Gemma module; implementations remain behind MLX state adapters until moved independently |
1088
- | `src/{prompt-cache,kv-store,ssd-cache}.ts` | Prefix/checkpoint policies use provider codecs and explicit retained snapshots |
1089
- | `src/{runtime-config,mlx/array,mlx/ffi}.ts` | Bound immutable configuration, explicit runtime opening, native resource owners |
1090
- | `src/spec/` and `src/fill/` | Typed method/draft/constraint capabilities; existing algorithms and oracle fixtures retained |
1091
- | `src/pi-web.ts`, Pi provider files, `src/web/src/` | Shared portable protocol declarations, client adapters, one provider-wiring implementation |
1092
- | `src/memory/`, `src/eval/`, `src/train/`, `src/quantize/`, `src/jobs/` | Completion/task clients and explicit artifact/resource services; preserve task-specific semantics |
1093
- | `src/serve/isolate.ts`, `src/index.ts`, `src/cli.ts` | Host/client adapters and composition roots; async high-level bootstrap and compatibility exports |
1094
-
1095
- File moves follow responsibility extraction. Every temporary adapter has a
1096
- deletion criterion. Do not combine renames, numerical rewrites, and protocol
1097
- changes in one patch. Preserve failure reproduction fixtures through migration.
1098
-
1099
- ### 12.10 Implementation stages and dependencies
1100
-
1101
- Each stage is one or more reviewable PRs. No calendar promise is made before R0
1102
- establishes the fixture and machine prerequisites. Checkboxes are in PLAN.md.
1103
-
1104
- **R0. Stabilize and record the baseline.** Pin the compiler and align local/CI
1105
- typechecks. Reproduce and fix checkpoint stop-policy identity and serial
1106
- cancellation with targeted tests. Diagnose the recorded Qwen cache-reuse crash
1107
- before migrating its state implementation. Record exact revisions, existing
1108
- support/refusal cells, public defaults, ABI/schema versions, and resource
1109
- ownership. Capture quiet-machine baselines using existing bench tooling.
1110
- Structural refactoring and model-free validation proceed while target artifacts,
1111
- quiet hardware, or crash diagnosis are unavailable. Preserve existing numerical
1112
- and state behavior; changing the affected state implementation or promoting a
1113
- default still requires its relevant correctness and performance gates.
1114
- Exit: fixes independently verified, baseline manifest available, missing
1115
- machine/oracle cells explicitly listed. No unverified previous-review claim
1116
- becomes a passing gate merely by entering this plan.
1117
-
1118
- **R1. Land contracts and prove method independence.** Depends on R0's inventory.
1119
- Create portable interfaces and dependency checks. Implement scripted AR-like
1120
- and final-output-only fake methods with different private state. Run the exact
1121
- same session lifecycle suite against both, including cancellation, failure,
1122
- backpressure, no-consumer behavior, and close. Introduce a legacy adapter around
1123
- the current executor so existing APIs still run. Exit: engine/session modules
1124
- import no concrete graph/native module; switching fake methods edits registration
1125
- only. Finalize the illustrative signatures through these executable contracts.
1126
-
1127
- **R2. Bind real graphs and backend capabilities.** Depends on R1. Wrap existing
1128
- models with GraphFactory/ModelBundle bindings, beginning with one dedicated
1129
- graph and its existing generated counterpart. Bind sampler/state/runtime types,
1130
- resource estimates, artifact profile, media inputs, taps, and adapter context.
1131
- Exit: both real graphs run through the same method/session without consumer
1132
- edits; direct forward logits match their pinned oracle; backend/state mismatch
1133
- fails before allocation. Keep old models reachable through adapters until their
1134
- family-specific tests have migrated.
1135
-
1136
- Also adapt an existing quant-specific path through its bundle and verify that
1137
- the interface adds no obligatory dequantization, tensor copy, intermediate
1138
- allocation, or synchronization. Validate the coarse fused-execution contract
1139
- before standardizing the reusable graph ABI.
1140
-
1141
- **R3. Establish resource and state ownership.** Depends on R2 and the relevant
1142
- R0 crash fix. Introduce explicit state views, retained snapshots, device-backed
1143
- leases, and complete rollback facets. Evolve the codec table into provider-bound
1144
- codecs. Validate prefix and resume identities, including stop policy and adapter
1145
- revision. Exit: injected failures release all owners; donor/clone isolation,
1146
- ring wrap, recurrent rollback, cold restore, and restart fixtures pass. No new
1147
- GC-dependent lifetime or unsafe mmap release is accepted.
1148
-
1149
- **R4. Resolve plans and reservations once.** Depends on R1–R3. Move speculation,
1150
- fill, compilation, cache bypass, and capability selection into one planner.
1151
- Use exact resolved plan data for execution, metrics, and checkpoint identity.
1152
- Move native media/constraint allocation behind preparation admission. Capture
1153
- configuration per binding. Exit: table-driven tests cover every shipped
1154
- composition and refusal; lane reports agree before/after execution; engine code
1155
- does not reread mutable global configuration. Existing fallbacks stay explicit.
1156
-
1157
- **R5. Share AR prefill and session execution.** Depends on R2–R4. Extract a
1158
- step-able prefill program preserving chunk/eval/quantization/snapshot/final-token
1159
- order. Route serial execution and current solo batch-prefill through it. Move
1160
- pending-token, history, and checkpoint-safe-point state into the AR method run.
1161
- Thread cancellation through queue, preparation, prefill, and decode. Exit:
1162
- duplicate prefill loops are removed, phase-specific abort tests release the
1163
- lease, and cold/warm/restored logits plus streamed results match the baseline.
1164
- This is the Maintainability prefill item; Phase 18 S1a remains separate.
1165
-
1166
- **R6. Adapt other methods and extensions.** Depends on R3–R5. Move the existing
1167
- speculative verifier and all retained DraftSource implementations behind typed
1168
- target views. Adapt fill/grammar acceleration and diffusion without expanding
1169
- their support. Exit: the same session suite passes for each; accepted/rejected
1170
- trace, pending-token accounting, stop handling, and recurrent rollback match
1171
- their method oracle. No session branch identifies AR/spec/diffusion by name.
1172
-
1173
- **R7. Separate scheduler policy from batch execution.** Depends on R5–R6.
1174
- Move merge/extract/filter and B=1 adoption into execution groups. Centralize
1175
- fairness, drain policy, queue bounds, reservations, and cancellation. Exit:
1176
- dynamic join/leave, uneven rows, slow consumers, group failure, mixed-KV,
1177
- recurrent state, and ring-wrap cells pass wherever supported; unsupported
1178
- compositions retain their recorded placement/refusal. Preserve pipeline overlap.
1179
- Do not merge true B-wide prefill or new concurrency features into this stage.
1180
-
1181
- **R8. Move applications onto client/task interfaces.** Depends on R1 and R4;
1182
- runtime cutover follows R5–R7. Separate shared web/Pi protocol declarations,
1183
- consolidate Pi provider configuration, and route memory/eval through clients.
1184
- Train/quantize retain task ports and dedicated numerical graphs. Add async
1185
- high-level library bootstrap and compatibility exports. Exit: CPU-only clients
1186
- and high-level package imports need no MLX; API/CLI/UI fixtures preserve current
1187
- behavior; task progress/cancellation and artifact semantics remain intact.
1188
-
1189
- **R9. Adapt isolation and resource coordination.** Depends on R7–R8. Implement
1190
- EngineHost over existing isolation/model-pool code, separate parent application
1191
- state from worker compute, and coordinate managed GPU jobs. Exit: worker startup
1192
- failure, death mid-stream, bounded restart, model eviction, disconnect, and
1193
- shutdown tests pass; no automatic POST replay or native object serialization;
1194
- direct/isolated clients share the semantic contract. Compare transport overhead
1195
- before any default change. Existing `--isolate` behavior remains available.
1196
-
1197
- **R10. Cut over, remove duplication, and close.** Depends on R0–R9. Default to
1198
- the new engine only after the full supported matrix and performance gates pass.
1199
- Delete legacy executor branches and temporary import exceptions. Review generated
1200
- twins, diffusion, curve/HLG, expert offload, paged KV, DSpark variants, compiled
1201
- decode, and Pi wiring using the existing D6 requirement: demonstrated use or
1202
- measured value, otherwise an explicit deletion decision. Retained experiments
1203
- register through declared interfaces. Update reference docs and package exports
1204
- in the same change as any public difference. Exit: replacement exercise below
1205
- passes, no duplicate engine remains, binary packaging works, and open-phase
1206
- blocks close without archiving this still-canonical architecture document.
1207
-
1208
- ### 12.11 Validation and release gates
1209
-
1210
- **Contract tests on every PR.** Run without native MLX: scripted alternate
1211
- methods, lifecycle, ownership transfer, capability composition/refusal, stable
1212
- identity, queue fairness, resource accounting, event ordering/backpressure,
1213
- partial result/error behavior, and dependency boundaries. Add graph adapter
1214
- type-tests that reject incompatible backend/state bindings. Existing protocol
1215
- and UI tests remain their behavioral reference.
1216
-
1217
- **Numerical and state matrix on available Apple Silicon machines.** Use the
1218
- pinned oracle and existing machine-layered goldens. Cover dedicated/generated
1219
- graphs, dense/MoE/recurrent/rotating state, bf16/uniform/mixed/TurboQuant where
1220
- supported, cold/warm/SSD/resume, B=1 and matching-B concurrent composition,
1221
- constraints, seeds, logprobs, adapters, media, speculation, and fill. Use targeted
1222
- pairwise cases plus every known failure reproduction; do not imply every
1223
- Cartesian combination is supported. Diffusion keeps its distinct oracle gate.
1224
- Exact cells remain exact. Existing tolerance cells require their recorded
1225
- justification; a refactor cannot loosen a gate to get green.
1226
-
1227
- **Lifecycle sequences.** Exercise cancel before preparation, during admission,
1228
- between prefill chunks, after dispatch but before readback, during verify, during
1229
- checkpoint write, and on slow/broken streams. Check one terminal outcome and
1230
- eventual reservation release after device completion. Restore-and-continue must
1231
- equal uninterrupted execution for the exact supported resume policy. Test
1232
- incompatible/corrupt checkpoints and failed cleanup. Measure steady memory
1233
- after synchronization across repeated warm and aborted requests.
1234
-
1235
- **Frontier scorecard.** Speed, quality, and size are independent axes. Keep a
1236
- Pareto set rather than collapsing them into one weighted score that hides a
1237
- regression. Every optimization names its target Mac memory budget, workload,
1238
- context, and concurrency before measurement.
1239
-
1240
- | Axis | Required evidence |
1241
- |---|---|
1242
- | Speed | Short/long-context TTFT, sustained decode, inter-token latency, concurrent throughput; include startup/compile and cold/warm behavior separately |
1243
- | Quality | Oracle identity for unchanged numerics; for changed quants/numerics, KL as a screen plus frozen task evaluations, raw-prompt/EOS checks, and representative multi-turn agent/tool outcomes |
1244
- | Size | Actual artifact bytes and effective bpw including scales/codebooks/sidecars; peak unified-memory footprint at the declared context, including KV, draft model, workspaces and retained snapshots |
1245
- | Practical experience | Largest useful context that fits, responsiveness during long work, completion correctness, restart behavior, and a reproducible local task with visible user benefit |
1246
-
1247
- A frontier improvement improves at least one axis without a meaningful loss on
1248
- the others at the declared measurement precision. A useful tradeoff can also be
1249
- a new non-dominated point; describe the lost/gained quantities explicitly and
1250
- apply the intended quality floor. A smaller model that causes an EOS/task
1251
- failure is not a quality-preserving win because its KL or aggregate benchmark
1252
- looked similar. Neither faster kernels alone nor smaller on-disk weights alone
1253
- establish a better product experience.
1254
-
1255
- Compare to the best relevant measured recipe, including the current shipping
1256
- bundle and credible same-budget alternatives, not an intentionally weak
1257
- baseline. Publish artifact provenance, input corpus, evaluator, uncertainty,
1258
- machine and memory accounting. Keep training/tuning examples separate from the
1259
- held-out promotion set. Include ordinary laptop use and cold-start experience
1260
- in product evaluation while keeping quotable paired microbenchmarks quiet.
1261
-
1262
- Optimization cycle: choose a bottleneck and target budget → propose a quant,
1263
- layout, graph/kernel or execution recipe → establish its numerical/quality
1264
- contract → measure the full scorecard → retain the non-dominated recipes →
1265
- register validated selectors for the appropriate Macs and workloads. Negative
1266
- findings belong in the topic doc; one-off research scripts are then removed.
1267
- The existing TurboQuant, decode-speed, KV and speculative programs own their
1268
- experiments. This architecture supplies the common registration and evaluation
1269
- contract without duplicating their backlogs.
1270
-
1271
- Pure refactor PRs may be frontier-neutral. V2 product promotion requires at
1272
- least one reproducible frontier advance plus a representative local workload
1273
- that demonstrates the benefit. Until measured, it is an objective, not a claim.
1274
- Supporting multiple useful quant-specialized implementations is intentional;
1275
- remove duplicated lifecycle policy, not a demonstrated numerical advantage.
1276
-
1277
- **Performance regression guard.** Record host/chip/RAM, revisions, artifact, effective plan,
1278
- concurrency, context, cache warmth and native runtime. Compare paired old/new
1279
- runs on the same quiet machine with existing tooling. Track startup, short/long
1280
- TTFT, inter-token latency, decode throughput, concurrent throughput/fairness,
1281
- peak memory, cancellation delay, and checkpoint stall. Predeclare a 3% median
1282
- regression investigation trigger for TTFT/decode on each representative cell, with
1283
- enough repetitions to distinguish it from noise; noisy results are unresolved.
1284
- Even smaller repeatable losses require a fix or an explicit measured benefit
1285
- elsewhere. No unexplained growing memory retention or disabled pipeline overlap.
1286
- The trigger prioritizes investigation; it is not an acceptable abstraction tax,
1287
- does not redefine a Pareto improvement, and does not permit quality degradation.
1288
- Report on both dev machines before final cutover; do not compare bits across
1289
- their different metallibs. Curated numbers go only in benchmarks.md.
1290
-
1291
- **Replacement exercise.** Before closure, replace a real compatible graph with
1292
- another registered graph, run a quant-specific coarse/fused implementation
1293
- without adding session branches, then swap the method for a final-output-only test
1294
- implementation, then run the client through direct and isolated hosts. Session,
1295
- scheduler-policy, protocol, and application code must remain unchanged. Changes
1296
- belong only to the implementation/bundle registration and its tests. This is the
1297
- acceptance test for Josh's "swap one piece" requirement.
1298
-
1299
- ### 12.12 Rollout rules and remaining design decisions
1300
-
1301
- Each stage routes a bounded set of existing configurations through a temporary
1302
- implementation selector in the composition root. Preserve the old implementation
1303
- only for paired comparison and rollback while that stage is open. Do not add
1304
- permanent user modes for intermediate architecture. Rollback selects a coherent
1305
- bundle and compatible persistence schema; never mix old graph state with a new
1306
- codec because both happen to implement an interface.
1307
-
1308
- Decisions still requiring implementation evidence have explicit owners:
1309
-
1310
- | Decision | Owner / decision gate |
1311
- |---|---|
1312
- | Exact event buffering and collect-mode limits | R1 contract tests; no-consumer and slow-consumer behavior must be bounded |
1313
- | Smallest graph ABI that covers existing taps/media/compiled paths | R2 real graph replacement plus per-family adapters |
1314
- | Fence/lease implementation and old checkpoint compatibility | R3 native lifetime tests and restore/restart fixtures |
1315
- | Which batch mechanics can share a method adapter | R7 parity and pipeline-overlap measurements |
1316
- | Whether finer worker separation should become a default | R9 crash containment, packaging, and transport measurements |
1317
- | Retirement of each experimental/duplicate implementation | R10 D6 usage or paired measurement; no deletion by interface preference |
1318
- | Which optimized recipe becomes the automatic choice for a Mac/workload | R10 full frontier scorecard and held-out quality gate; no universal winner assumed |
1319
-
1320
- R0 fixes are small independent changes. R1–R4 establish and validate the
1321
- contracts. R5–R7 perform the execution migration. R8–R10 complete applications,
1322
- isolation, and deletion. Contract drafting must lead to the first real graph
1323
- replacement in R2; it cannot grow indefinitely without that working proof.
1324
-
1325
- ### 12.13 Implementation status (2026-09-05)
1326
-
1327
- Branch: `refactor/interface-engine-v2`. The comparison baseline is
1328
- `6d45ca1e17e825c48af9b246a37486380117f640` (`origin/main`, fetched again
1329
- 2026-09-05). Its reference docs and tests freeze the pre-refactor public
1330
- defaults, supported combinations and refusals; use `git show <revision>:<path>`
1331
- to inspect that baseline without consulting a moving branch.
1332
-
1333
- | Baseline dimension | Frozen source / compatibility rule |
1334
- |---|---|
1335
- | Flags, defaults and routes | Baseline `docs/reference/{server-config,server-api,cli}.md`; no new architecture mode becomes a default in this phase |
1336
- | Families, quants and feature support | Baseline `docs/reference/models.md`, model profiles and parity tests; the locally available published Qwen artifacts supply compatibility evidence only |
1337
- | Native oracle and machine | Baseline `docs/reference/environment.md` plus its machine-layered golden manifests; all branch numerical comparisons reported here use the M1 Max 32 GB and the pinned venv |
1338
- | Toolchain | Bun 1.4.0 (`34cbb9a40`), TypeScript pinned to 6.0.3; Python MLX/Metal 0.31.2, mlx-lm 0.31.3, mlx-optiq 0.2.15 |
1339
- | Graph/state representation | Existing MLX hidden `[batch, positions, width]` and legacy cache arrays; newly declared `mlx-hidden-bsh-v1` / `legacy-cache-array-v1` describe those representations without converting them. Denoising uses its distinct `mlx-denoising-v1` graph ABI |
1340
- | Persistence | SSD prefix format 3 is retained; legacy codec identity remains readable. Generation resume identity advances from the baseline's unversioned policy hash to version 4, including stops, adapter content, implementation and resolved policy |
1341
- | Ownership | Resident weights remain borrowed; request caches, rollback scratch, native preparation and retained prefix backing release at their existing device-safe boundaries, now expressed through owners and leases |
1342
- | Performance | Baseline/candidate paired diagnostics exist for available artifacts; quiet-machine preflight did not pass, so none establishes a quotable regression result or frontier advance |
1343
-
1344
- Outstanding evidence is explicit: Josh's designated quant artifacts, the M4 Pro
1345
- 24 GB matrix, quiet paired performance, unavailable diffusion/drafter weights,
1346
- the Qwen 4B B=2/persistence oracle fixtures, and reconciliation of the reported
1347
- other-machine Metal-memory fix. The crash is diagnosed as a native allocation
1348
- failure; this branch preserves the affected cache math. These missing cells
1349
- do not prevent interface work. They keep the full frontier scorecard and
1350
- production acceptance gate open after the branch implementation is complete.
1351
-
1352
- R0 fixes pin TypeScript 6.0.3 for
1353
- local/CI checks, add stop strings and a version to generation-checkpoint
1354
- identity, remove cancelled serial waiters immediately, and check cancellation
1355
- between AR/spec target-prefill chunks and committed-token boundaries.
1356
-
1357
- `src/contracts/generation.ts` defines portable planner, method/run, session,
1358
- output, result, cancellation, and timer ports. `src/engine/` implements lifecycle
1359
- and delivery without model or runtime imports. The dedicated TypeScript project
1360
- has ES2022 only and no ambient runtime types; an AST/resolved-import test also
1361
- checks type imports, re-exports, and dynamic imports against dependency layers.
1362
-
1363
- Streaming starts on the first reader demand. Defaults are 32 queued events,
1364
- 256 queued token IDs, 20 top-logprob entries per token, and a 30-second
1365
- idle-consumer deadline. Large committed spans split under backpressure.
1366
- Collecting reserves a Uint32 buffer before method creation, with an aggregate
1367
- 65,536-token active-collection ceiling; terminal output ownership transfers to
1368
- the caller. Collection currently returns IDs only; logprobs require streaming.
1369
- Cancellation and early iterator return wait for run cleanup. Failure outcomes
1370
- retain the execution error if cleanup also fails. These are internal defaults,
1371
- not new server flags.
1372
-
1373
- HTTP completion execution now uses the shared session by default.
1374
- `createSessionCompletionEngine` delivers tokens directly to the existing
1375
- stop/tool parser through callback output, avoiding a second queue. The callback
1376
- is awaited and can request a normal stop; cleanup completes before the result
1377
- settles. Streaming/collection library consumers retain their bounded delivery.
1378
- AR, speculative and denoising methods honor callback stops. Denoising now settles
1379
- its emitted-token count when delivery closes before the completed canvas ends.
1380
- `src/backends/mlx/text-engine.ts` is the data-only token API. It snapshots requests
1381
- before demand-start and shares `createCompletionMethod` with HTTP. Native media,
1382
- adapters and grammar still require prepared inputs; their HTTP requests now run
1383
- through the same session lifecycle. The temporary text-only legacy engine is gone.
1384
-
1385
- `ModelServingBinding` owns the gateway binding, serial execution construction,
1386
- prompt/media preparation, SSD restore, signal evaluation, embedding execution and
1387
- model diagnostics. The server consumes model metadata and this binding.
1388
- `MlxGatewayBinding` owns compatibility decisions and batch-group construction;
1389
- method IDs are implementation-owned strings. A model can expose several methods
1390
- with unrelated private state. Existing classes enter through the MLX binder;
1391
- replacement implementations supply the port directly. `loadContext` selects an
1392
- engine-owned host implementation before either default weight loader runs.
1393
- The HTTP replacement test selects a synthetic exact artifact registration and
1394
- runs two custom methods with no concrete model, forward function or cache factory.
1395
- This proves the construction-to-session path, not quant quality or performance.
1396
-
1397
- `src/inference/graph.ts` declares the backend-bound graph ABI.
1398
- `src/backends/mlx/graph.ts` binds synchronous/streamed forwards once and selects
1399
- hidden positions before vocabulary projection. `src/backends/mlx/autoregressive.ts`
1400
- defines one `MlxAutoregressiveBinding` for the graph, cache construction, media
1401
- forwarding, adapter state, memory accounting, and optional compiled/fused decode.
1402
- `generateAutoregressive()` consumes that interface without requiring a
1403
- `RuntimeModel`. The existing `generate()` API adapts AR models into it, preserving
1404
- the serial loop's sampling, prefill chunks, lazy evaluation, and decode pipeline.
1405
- No tensor wrapper, device readback, or synchronization was introduced.
1406
-
1407
- Concrete Gemma compiled-decode selection and rollback-based fallback now live
1408
- in the legacy binding. A replacement supplies its own decoder; the loop never
1409
- infers one from the model family. A declined step must leave state unchanged.
1410
- Unrecovered errors propagate without retry. Bindings must declare the MLX
1411
- hidden-state ABI and legacy `Cache[]` ABI; mismatches fail before cache allocation.
1412
-
1413
- The host now captures AR/denoising and speculative bindings once. Compiled
1414
- replay permission and grammar jumping are resolved alongside placement and
1415
- included in checkpoint identity. Serial execution consumes that policy; B=1
1416
- batch replay also honors it, with dynamic cache geometry still allowed to
1417
- decline replay transactionally. A lazily created batch group inherits the
1418
- gateway's runtime snapshot. Composition and snapshot tests cover later config
1419
- changes, adapters, paged/media fallback, speculation, denoising and logprobs.
1420
- Legacy kernel flag reads now resolve through an execution-local runtime snapshot.
1421
- AR/denoising generator resumes and cleanup, the speculative verifier and its
1422
- memory scope, and each batch driver retain that snapshot across awaits. A later
1423
- host configuration change cannot alter a running binding's kernel policy.
1424
- Nested/concurrent scope tests and native binding tests cover early close,
1425
- verification callbacks and lazy batch construction. The scope adds no tensor
1426
- copy, evaluation or device fence; its performance remains part of the paired gate.
1427
- Rejected initial state releases owned caches while preserving borrowed caches.
1428
- Decoder cleanup completes before cache disposal, including early iterator return.
1429
- If execution and decoder cleanup both fail, the aggregate retains both errors.
1430
- The legacy descriptor is not a persistence identity. Rich media remains a native
1431
- preparation input; tap capabilities and provider-bound persistence are described
1432
- below. A different cache ABI requires its own compatible method/backend binding.
1433
-
1434
- Serial cache lookup, checkpoint replay/persistence and prompt-boundary snapshots
1435
- now live in `src/backends/mlx/serial-executor.ts`. The HTTP server injects a bound
1436
- generator/verifier, cache constructor, prefix/checkpoint stores, clone function
1437
- and adapter namespace service. Native Qwen media context is installed/restored
1438
- by its compatibility binder. The executor has no concrete model dispatch;
1439
- the existing gateway still owns scheduling and exclusive execution.
1440
- Native input ownership starts before cache lookup/construction. A failed lookup,
1441
- cache constructor or trace hook releases prepared grammar/media and any acquired
1442
- cache state; one failed destructor does not skip sibling releases or replace
1443
- the execution error. Checkpoint replay checks cancellation before each saved
1444
- token and retains its durable checkpoint when interrupted.
1445
- Failed prefix trimming releases acquired clone/restored state. Prefix insertion
1446
- validates cache metadata before adopting ownership; eviction cleanup errors are
1447
- reported after adoption without inviting the caller to dispose the live stored
1448
- entry. Clear detaches entries and attempts cleanup for every sibling. Backing
1449
- retention is released only after successful cache disposal. Rejected optional
1450
- prompt-boundary snapshots release their clones while generation retains its
1451
- live state. These are failure-path ownership changes, with no cache-math change.
1452
-
1453
- Model-free binding tests exercise an independent graph, a replacement fused
1454
- decoder, declined steps, unrecovered errors, and unsupported ABI/media/adapter
1455
- requests. The native `generated-parity` gate runs dedicated and generated Gemma
1456
- bindings through the same gateway method and portable session consumer. Tokens
1457
- and cache coverage match, and its counter verifies the generated path executed.
1458
- This is a compatibility gate using available weights, not a product speed claim.
1459
- The binding migration also passes all eight compiled-decode parity/recovery
1460
- checks and the Qwen3.8-27B TQ smoke below on the M1 Max 32 GB.
1461
-
1462
- `src/model/implementation.ts` defines the backend-parameterized
1463
- `ModelImplementation` construction port and immutable registration table.
1464
- `ModelExecutionComposition.implementation` lets an exact engine-owned artifact
1465
- profile name its code. Existing identity/config guards perform the matching;
1466
- the registry does not introduce another artifact matcher. `src/model/factory.ts`
1467
- now registers the existing resident constructors, including generated Gemma,
1468
- and selects one before construction. `openModel` checks the binding before
1469
- opening weights; callers can compose profiles and implementations through its
1470
- options. `createModel` accepts a registry for already-open weights. No selection
1471
- is added to the token loop, and no model file format changes.
1472
- Both factories preserve a supplied registry's return interface; replacement
1473
- implementations need not join the concrete `RuntimeModel` union. Construction
1474
- does not select the request's execution method. An implementation can support
1475
- several methods, including quant-specific paths, while the session consumes
1476
- the selected method's execution, output and cleanup contract. The shared
1477
- contract does not require a shared numerical loop.
1478
-
1479
- Unknown artifacts retain existing family selection. Missing implementations,
1480
- graph/loader/loop mismatches, duplicate IDs, and inconsistent exact identities
1481
- fail explicitly. Construction failures propagate without trying another graph.
1482
- Model-free tests exercise the factory with a synthetic exact quant identity and
1483
- an alternate constructor; this establishes selection, not numerical or speed
1484
- claims. No registration pretends to identify Josh's inaccessible quants.
1485
- This step covers resident graph construction. Colibri retains its existing
1486
- streamed opener and refuses supplied resident registries or named overrides
1487
- until its resident loader binding exists. Existing class-based library exports
1488
- remain available through compatibility binders. The server consumes the
1489
- model-owned serving port; host implementations can own resident or streamed
1490
- loading. Specialized inference methods remain.
1491
-
1492
- Artifact-parameterized native smoke gate:
1493
- `MLX_BUN_QWEN_QUANT_PATH=/path/to/our/artifact bun test tests/parity/qwen-quant-engine.test.ts`.
1494
- Run one artifact per process. Compatibility-only checks on the M1 Max 32 GB
1495
- pass for the locally cached published `mjriii/Qwen3.8-27B` and
1496
- `mjriii/Qwen3.8-27B-TQ`: direct-versus-bound logits, legacy-versus-session greedy
1497
- output/cache coverage, and repeated recurrent-prefix borrowing. These are not
1498
- Josh's current target quants. Target validation awaits access to those artifacts;
1499
- implementation continues independently. The test is a bounded smoke, not a full model oracle or the
1500
- recorded turn-8 repro. Gemma compiled-decode checks are secondary coverage too.
1501
-
1502
- R1 is complete. Incremental and final-only producers run the same lifecycle
1503
- cases for collection/streaming, blocked-consumer cancellation, partial failure,
1504
- and no-consumer/pre-cancelled settlement. Additional tests cover preparation
1505
- cancellation, admission refusal, metadata bounds, and cleanup failures.
1506
-
1507
- R3 now gives request resources one checked owner. Transfer invalidates the
1508
- previous owner, close is idempotent even after a destructor failure, and cleanup
1509
- attempts all releases while preserving the original execution error. MLX state
1510
- views expose a lease; prefill and prefix-cache accounting close it without
1511
- knowing whether handles are borrowed or temporary. Only the compatibility
1512
- adapter reads the legacy ownership marker. No tensor copy, evaluation or device
1513
- synchronization is added by these leases. Fault-injection tests cover transfer,
1514
- partial view acquisition and throwing destructors. Existing native fences remain
1515
- in place; codec binding and persistence identity are described below.
1516
-
1517
- R4 now resolves method, scheduling mechanism, paged-KV fallback, prompt-cache
1518
- bypass, fill eligibility and checkpoint eligibility in one portable planner.
1519
- The gateway passes that immutable decision to serial execution; lane accounting
1520
- uses the actual method, including AR fallback with a configured draft. Request
1521
- policy arrays/maps are copied and frozen at admission. AR runtime settings and
1522
- batch work flags use a binding snapshot. Native grammar/media preparation takes
1523
- the gateway execution lease before allocation; text rendering remains outside
1524
- that lease. Cancellation before/during preparation is covered with allocation
1525
- and cleanup assertions.
1526
- Native AR/speculative/denoising method creation now uses the same policy snapshot
1527
- as HTTP admission. Scalar settings and nested policy arrays/maps cannot change
1528
- between registration and the first reader demand. A binding without an explicit
1529
- runtime captures the host default at method creation; kernels execute under
1530
- that snapshot. Native caches, controllers and callbacks retain their declared
1531
- ownership instead of being cloned with policy data.
1532
-
1533
- Checkpoint request identity is now canonical SHA-256 over sampling/stop policy,
1534
- resolved execution and the artifact/implementation/state ABI. Object insertion
1535
- order is ignored; array order remains meaningful. Version-4 keys include the
1536
- resolved compiled/grammar policy; version-2/3 generation keys do
1537
- not resume through this version; ordinary prefix-store format is unchanged.
1538
- Nine native scheduling gates pass after planner integration, including rotating
1539
- dynamic joins, row failure containment, serial drain, prefix sharing, SSD restore
1540
- and compiled B=1. Preparation reservations now remain owned through execution; see below.
1541
-
1542
- R3 state persistence now uses `CacheCodecProvider`, bound through the server's
1543
- model context, RAM cloner, batch snapshots and SSD store. A provider supplies
1544
- clone/snapshot/restore/trimmability together; ambiguous matches refuse. Persisted
1545
- provider identity is checked before cache allocation or mmap. Earlier v3 files
1546
- implicitly use the legacy provider; a different provider must identify itself.
1547
- Restore still copies one tensor at a time and unmaps only after those copies,
1548
- so this change introduces no new device/backing lifetime assumption. Failed
1549
- clone and snapshot construction release intermediate owned views.
1550
-
1551
- Adapter namespaces now hash the weight file plus scale/rank policy once at
1552
- mount. Remounting the same name with different bytes or scale cannot reuse its
1553
- old RAM prefix or generation checkpoint. The shared server cache uses that
1554
- namespace for both lookup and persistence. Codec provider fault/round-trip tests
1555
- pass; native persistence passes five cells with one unavailable golden skipped,
1556
- and dedicated/generated Gemma passes six cells, including direct logit identity.
1557
-
1558
- R5 now shares a portable prefill program between serial AR and solo batch
1559
- admission. Its MLX executor preserves drain evaluation, KV maintenance, allocator
1560
- clears, stable-boundary snapshots, and the separate final-token forward. Batch
1561
- admission retains its short-tail scheduling behavior. Six native scheduler
1562
- checks pass, including dynamic rows, prompt reuse, SSD restore and compiled B=1;
1563
- the dedicated/generated same-session test also passes on the M1 Max 32 GB.
1564
- The native AR method run owns its generator's pending tokens, history and
1565
- checkpoint boundary. Phase-specific tests now cover cancellation before any
1566
- cache allocation, after a prefill chunk, after decode dispatch/before emission,
1567
- and while an asynchronous checkpoint borrows live state. Cancellation waits for
1568
- the checkpoint to finish before releasing state. Current-token logprob arrays
1569
- remain owned until readback succeeds, including forward/grammar failure;
1570
- cancelled execution stops before emission or a subsequent checkpoint write.
1571
-
1572
- R6 now runs the speculative verifier through `MlxSpeculativeBinding`. Target
1573
- forwards, projection, tap capture, draft construction and kernel pinning bind
1574
- outside the verifier. Legacy tap contexts restore their previous value on exit.
1575
- The complete rollback facet validates recurrent begin/commit/replay together;
1576
- partial layer failures invalidate the transaction and the run discards its state.
1577
- Ring-capacity fallback retains its strict pre-write boundary. The verifier owns
1578
- input/hidden scratch on failure and attempts every final release.
1579
-
1580
- AR and speculative methods now implement `InferenceMethod` directly. Their shared
1581
- host adapter translates cancellation and waits for native cleanup. The same
1582
- session tests exercise collection, streaming, early reader closure and forward
1583
- failure for both. Four native Qwen3.5-0.8B gates pass, including recurrent
1584
- rejections and identical speculative acceptance traces through a portable
1585
- session. This smaller available model supplies compatibility coverage only.
1586
- Denoising now implements that same method/session contract through a separate
1587
- `DenoisingGraph<Tensor, State>`. Its test binding uses a position-only state
1588
- record, with no AR cache or token-prefix API. The existing synchronous diffusion
1589
- entry and cooperative generation drain one denoising program. Cooperative calls
1590
- yield between denoising steps and publish only the final output; cancellation
1591
- releases canvas, feedback, embedding weights and graph state. Generation holds
1592
- the existing exclusive runtime lease, including the diffusion global RNG.
1593
-
1594
- Scripted regression tests cover both samplers, RNG-dependent canvases across
1595
- multiple blocks, sync/async identity, preparation failure, cancellation between
1596
- steps and repeated-run native memory accounting. The existing soft-embedding
1597
- lifetime test passes. Diffusion weights are absent on this machine, so its
1598
- weight/oracle gates remain unrun. Draft sources now consume declared target
1599
- ports for assistant donor views/scaled embeddings, Gemma hidden taps/output
1600
- projection and Qwen MTP embeddings/output projection. The target view contains
1601
- no concrete model or cache array; the MLX compatibility binder owns family
1602
- checks and donor layout. Native GLM providers compare an opaque target identity
1603
- before borrowing their own model-owned weights. Both retained DSpark variants
1604
- use the projection interface. Missing extensions refuse before draft allocation.
1605
- An independent assistant target fixture proves construction and draft cleanup
1606
- without a model class; donor acquisition releases partial views on failure.
1607
- The locally cached published Qwen3.8-27B and its bundled MTP head pass the
1608
- same-artifact greedy comparison after this migration. This does not establish
1609
- performance or compatibility for Josh's unavailable exact quants.
1610
-
1611
- R7 now separates the portable scheduling driver from `MlxBatchExecutionGroup`.
1612
- The driver sees queue/active counts, admission readiness and bounded work units;
1613
- it imports no model, cache, tensor or runtime implementation. Native admission,
1614
- merge/extract/filter, sampling and pipeline state live in `src/backends/mlx/`.
1615
- A compatibility re-export preserves existing batch-scheduler imports.
1616
-
1617
- The driver retains short-admission grouping, long-prefill interleaving, serial
1618
- drain and the 25 ms single-row responsiveness budget. Six native scheduler
1619
- checks and two native failure-containment/serial-drain checks pass. Policy tests cover those ordering rules, execution failure and
1620
- lease release; backend fault tests cover a request removed from the queue when
1621
- admission fails, retained-prefix cleanup, shutdown and submission after close.
1622
- Closing a group stops at a safe boundary, rejects pending/active requests and
1623
- releases owned state. Bounded request and preparation queues now reject overflow explicitly. The full
1624
- mixed-state concurrency/performance matrix remains open.
1625
-
1626
- R8 now shares Pi/browser messages, history, sampling data and route IDs in
1627
- `src/contracts/pi.ts`. Compatibility re-exports preserve server-side imports.
1628
- The browser TypeScript project has no Bun ambient types; Bun UI tests remain
1629
- covered by the root project. The resolved-import gate prevents browser modules
1630
- from importing server implementations, including type-only imports.
1631
-
1632
- R4/R7 admission now uses a portable FIFO `AdmissionPool`. The gateway bounds
1633
- active requests and queued waiters; cancelled waiters do not release another
1634
- request's capacity. Media and grammar preparation reserve capacity before native
1635
- allocation. The request owner retains that reservation after transferring native
1636
- resources to execution, then releases it on success, failure or cancellation.
1637
- The direct batch group also bounds pending submissions. Overload is explicit in
1638
- the existing HTTP/SSE error contract. Nine native scheduling checks pass after
1639
- this integration, including rotating joins, failure containment, prefix/SSD reuse
1640
- and compiled B=1. The gateway's shared execution lease covers preparation,
1641
- generation and managed GPU jobs.
1642
-
1643
- R8 is complete: completion/batch/task contracts are portable. Memory calls accept an injected
1644
- client; their existing native implementation moved behind a lazy backend import.
1645
- Eval generation accepts a replacement completion client and retains its separate
1646
- bit-exact greedy oracle path in the MLX backend. Training and quantization keep
1647
- their numerical runners and artifact results; both job execution modes now use
1648
- the task adapter. Progress delivery is synchronous and unbuffered; cooperative
1649
- cancellation checks before work and at progress boundaries. Native work already
1650
- dispatched still completes at its safe boundary.
1651
-
1652
- Pi's embedded registry and generated extension use one model-definition builder.
1653
- Job and Pi/browser messages now share portable declarations. New `mlx-bun/engine`
1654
- and `mlx-bun/client` exports import without MLX; `initializeMlx()` explicitly
1655
- bootstraps the compatibility API. The existing root import remains compatible.
1656
- The JSON completion client uses either HTTP or an `EngineHost` without changing
1657
- callers, preserves abort, and never retries completion POSTs.
1658
-
1659
- R9 adapts the existing `EngineChild` into `EngineHost`, bounds restart attempts,
1660
- cancels restart backoff on close, kills failed startup, and checks disconnect
1661
- while waiting for readiness. Model-pool startup failures and shutdown close their
1662
- owned children; an evicted default can be resolved again for an absent/unknown
1663
- model request. The fake-host proxy suite now runs in the model-free CI tier.
1664
- Real MiniCPM JSON and incremental SSE requests pass through the isolated host.
1665
-
1666
- Managed GPU subprocess jobs reserve the same gateway lease as inference: the
1667
- current batch drains before spawn, and the job retains the lease through child
1668
- exit, including crashes. Host shutdown cancels admission/queued jobs and terminates
1669
- its active job before releasing the lease. Fault tests cover rejected admission,
1670
- spawn failure, child death and shutdown. The isolation parent now owns job/settings routes and their store. A portable
1671
- shared/exclusive coordinator covers every worker's startup, restart, response
1672
- body and eviction. Before GPU job spawn, live UDS lease responses reserve each
1673
- worker's gateway after durability flush; disconnect releases the worker lock.
1674
- Those connections remain owned through subprocess exit, not merely until a
1675
- client HTTP disconnect. Native MiniCPM checks verify that generation waits for
1676
- the parent lease and resumes after release. Worker death does not remove parent
1677
- job records. In-process task cancellation waits for runner cleanup before closing
1678
- the store. The parent serves the same embedded web assets and owns Responses
1679
- conversation history; direct and isolated serving share conversation-resolution
1680
- policy. Workers skip duplicate history retention for parent-owned requests. A
1681
- real worker replacement preserves previous-response continuation and streamed
1682
- metadata. WebSocket chat remains an explicit unsupported isolation cell. No
1683
- process-host default has changed. R9's direct/isolated transport comparison is
1684
- complete on the M1 Max using the same MiniCPM artifact and CLI/request cells:
1685
- completion and chat probes each matched 64 greedy tokens; cold, warm, SSD
1686
- restart and concurrent legs completed. The run is diagnostic because the quiet
1687
- gate failed. The optional `mlx-bun-isolated` benchmark arm accounts for parent
1688
- and worker RSS; raw reports stay machine-local. R9 is complete for the retained
1689
- opt-in host; promotion and the other machine's scorecard remain R10 gates.
1690
-
1691
- The current model-free suite passes; root, browser and portable typechecks pass.
1692
- Native state checks cover mixed-KV oracle logits, wrapped-ring conversion,
1693
- speculative recurrent rollback and persistence. The Qwen B=2 oracle and one
1694
- Qwen persistence fixture are absent and skip. The binary builds and its CLI/Pi
1695
- asset smoke passes. Managed jobs now self-exec the packaged binary; literal
1696
- runner imports retain quantize/train code in the bundle, and a compiled
1697
- subprocess smoke verifies progress and terminal persistence. These checks do not replace the unavailable artifact/machine
1698
- cells or the final production acceptance gate.
1699
-
1700
- The Qwen replay now has a native exception diagnosis: Metal reports insufficient
1701
- memory from its completion handler. Details remain in the existing turn-8 repro.
1702
- Josh reports a possible fix on the other machine; reconcile it before changing
1703
- the affected state path. The 2026-09-05 benchmark preflight found 4 GB of existing swap and high
1704
- background CPU load. Measurements taken without that gate are diagnostic only.
1705
- Quiet-machine baselines remain open. Remaining R0–R10
1706
- work is tracked in PLAN.md; no speed/quality/size improvement is claimed yet.
1707
-
1708
- The first per-file native matrix at `a75cd39` ran 84 local parity files with
1709
- batch-decode opt-in: 338 passes, 44 skips and seven failed assertions. Five
1710
- audio failures were a fixture path left behind by the test-directory move.
1711
- The two numerical failures reproduced on baseline `6d45ca1`: the local CPM
1712
- mixed-KV blobs did not match their manifest hashes, and CPM extend-join fell
1713
- back to the M4 reference because no M1 override existed. The pinned Python
1714
- oracle regenerated the mixed-KV manifest's exact hashes and an M1 extend-join
1715
- trajectory identical to the implementation. The corrected batch suites pass
1716
- 15 tests with one unavailable e4b oracle skip. Tests now check blob hashes;
1717
- the mixed-KV generator writes blobs and manifests to the same resolved output
1718
- directory. A second per-file run enables the local train/quantize/LoRA/generated
1719
- and model-family gates. Two rotating-quantized continuation failures also
1720
- reproduced on the baseline: the test compared `generate()`'s bf16-head/quantize/
1721
- tail prefill with a fully quantized single-forward oracle. The generator now
1722
- records both procedures separately. Existing mechanics, single-forward logits
1723
- and trajectories regenerated unchanged; the matching serving trajectories pass
1724
- the original prefix threshold. All six rotating tests pass. Missing new
1725
- continuation fixtures skip explicitly on other machines until regeneration.
1726
- A process that exits successfully without registering tests is not a passing
1727
- matrix cell; absent large-model/drafter fixtures remain open.
1728
- The production test runner now uses a fresh process for each native test file,
1729
- preserving model residency and runtime isolation between cells. The complete
1730
- default runner passed at `2a14021`, including hygiene,
1731
- all TypeScript projects, the model-free suite and available parity/research
1732
- tests. Optional cells are reported separately; a green default run does not
1733
- imply unavailable weights or opt-in cases ran.
1734
- That run reports 2,344 passes, 98 skips and no failures, with 109 native files
1735
- each receiving a fresh process.
1736
- The expanded runner at `ab0db74` enabled the locally applicable model-family,
1737
- training, quantization, LoRA and batch-decode gates: 2,427 passes, 44 skips and
1738
- no failures across the model-free tier and 109 native files. Ten native files
1739
- registered no tests because their configured model/drafter fixtures were absent;
1740
- those are unavailable cells, not passes. At `b9b56aa`, the model-free suite
1741
- passed 1,718 tests with 10 skips. All TypeScript projects, hygiene and compiled
1742
- CLI/Pi/assets/job smokes passed. The subsequent focused native run passed 44
1743
- tests covering batch lifecycle, SSD state, generated graphs, ngram verification,
1744
- both available published Qwen graph/session bindings and the published Qwen MTP
1745
- target/draft pair. Explicit MTP paths supplied one previously unavailable cell.
1746
- These results do not close the target-artifact, second-machine or default-cutover
1747
- gates.
1748
-
1749
- The sequential Gemma e4b repeat compares baseline `6d45ca1` with `5e3b92e`
1750
- using default and serial HTTP arms, the same artifact, a 4K context and 96
1751
- requested tokens. Both arms preserve the completion/chat greedy probes and
1752
- durable restart state. The earlier long-context prefill slowdown and default-arm
1753
- RSS increase did not reproduce; warm-cache latency still varies across runs.
1754
- Background load and existing swap keep these reports diagnostic. This repeat
1755
- does not establish a speed win or satisfy the quiet-machine frontier gate.
1756
-
1757
- R10's implementation-retention review currently records these decisions. None
1758
- of the open measurement cells changes an existing numerical default:
1759
-
1760
- | Implementation | Current disposition and remaining evidence |
1761
- |---|---|
1762
- | Pi provider wiring | Consolidated into one builder; generated-extension and binary asset tests pass. Duplicate policy is removed |
1763
- | Dedicated/generated Gemma | Both register through the engine and pass the same session/oracle gates. Keep both during paired comparison; numerical equivalence alone does not choose a winner |
1764
- | Compiled decode | Retained behind the declared decoder capability and resolved eligibility. Existing recovery/parity gates pass; final paired regression measurements remain required |
1765
- | Diffusion | One denoising program and method interface replace duplicate orchestration. Real model/oracle fixtures remain unavailable; no promotion or deletion decision is implied by scripted tests |
1766
- | Assistant/DSpark/DeepSpec/MTP | Typed draft target ports replace concrete target dispatch. Available Qwen MTP and ngram verification pass; source-specific drafter validation and the DSpark wall-clock decision remain open in the speculative program |
1767
- | Curve/HLG and paged KV | Existing opt-in placement and refusals remain. Their experiment-specific quality/performance gates remain open; this refactor does not make them defaults |
1768
- | Expert offload | Existing streamed GLM loading/task semantics remain behind native bindings; model-free streamed/provider tests and packaged task entry pass. The larger-model value/footprint decision remains in its own program |
1769
- The final server cutover is implemented at `015f56d`. The model-free suite passes
1770
- 1,732 tests with 10 skips. Fresh native processes run all 109 parity/research
1771
- files with the locally applicable opt-ins, including the published Qwen target
1772
- and MTP paths: 720 passes, 33 skips, no failures. Nine fixture-dependent files
1773
- register no tests and remain unavailable cells. The second published Qwen TQ
1774
- artifact also passes the graph/session test. The public replacement and import/
1775
- docs boundary checks pass after the final exports. Commit `d1abd60` also puts
1776
- embeddings under the shared GPU lease. Its new ownership test, the public
1777
- replacement test and both native embedding-route tests pass. All three
1778
- TypeScript projects pass, as does hygiene. The standalone binary built at
1779
- `d1abd60` passes CLI, Pi asset and managed-job subprocess smoke checks.
1780
-
1781
- The final HTTP comparison uses the frozen `6d45ca1` baseline and this branch on
1782
- the M1 Max 32 GB, with MiniCPM5 and Gemma e4b, default and serial arms, a 4k
1783
- context and 96 generated tokens. The first candidate run overlapped a repository
1784
- hygiene scan and showed slower e4b long prefill and SSD restart. A sequential
1785
- e4b repeat without other checks removed the long-prefill gap, but restart
1786
- latency still varied. A further candidate-then-baseline default-arm pair removed
1787
- that restart gap too. Completion and chat parity probes match between default
1788
- and serial arms; every restart restores a durable prefix with no failed or
1789
- dropped spills. These loaded-machine diagnostics do not establish a quiet
1790
- performance acceptance result. Raw reports remain local in
1791
- `/tmp/mlx-bun-cutover-{baseline,candidate}-report.md`,
1792
- `/tmp/mlx-bun-cutover-repeat-{baseline,candidate}-report.md` and
1793
- `/tmp/mlx-bun-cutover-reverse-{baseline,candidate}-report.md`.
1794
-
1795
- R1–R9 implementation and R10 code migration are complete. Existing model-class
1796
- exports use backend compatibility binders; there is one default session lifecycle
1797
- and no alternate legacy HTTP executor. R10's retained implementations keep their
1798
- existing placement and numerical defaults. Their independent experiment programs
1799
- still own promotion/deletion decisions. Quiet performance, exact target quants,
1800
- unavailable oracle/drafter fixtures and the second machine remain acceptance
1801
- work, not missing interface code. No frontier advance is claimed by this refactor.
1802
-
1803
- ### 12.14 Request flow and interface ownership
1804
-
1805
- This is the target responsibility map for Phase 6/18. A request carries one
1806
- resolved policy: measured defaults plus explicit user overrides. Each component
1807
- consumes its own part of that policy. The table below distinguishes existing
1808
- contracts from implementation and migration work still in progress.
1809
-
1810
- ```mermaid
1811
- flowchart TB
1812
- client["Client: chat, Pi, API or library"]
1813
- server["Server adapter<br/>receive requests and send responses"]
1814
- policy["Request policy interface<br/>resolve defaults and user overrides once"]
1815
- template["Chat template interface<br/>messages and tools → rendered prompt"]
1816
- tokenizer["Tokenizer interface<br/>rendered prompt → token IDs"]
1817
- session["InferenceEngine / GenerationSession<br/>own request lifecycle and cancellation"]
1818
- scheduler["Scheduler / ExecutionGroup<br/>choose when ready work runs"]
1819
- method["InferenceMethod<br/>ordinary decode or MTP proposal / verification"]
1820
- graph["Model graph interface<br/>prefill, forward passes and specialized kernels"]
1821
- sampler["SamplingSession<br/>apply settings and grammar; select tokens"]
1822
- output["Response interface<br/>decode committed tokens; emit text and tool events"]
1823
- state["Active state interface<br/>target KV, recurrent state, draft state and positions"]
1824
- cache["PrefixCache interface<br/>restore and retain aligned token / state checkpoints"]
1825
- ram["RAM cache<br/>retain reusable checkpoints"]
1826
- persistence["Persistence interface<br/>queue background writes and restore from SSD"]
1827
-
1828
- client --> server --> policy --> template --> tokenizer --> session
1829
- session -->|ready work| scheduler
1830
- scheduler -->|admit and advance a batch of 1 or more| method
1831
- method -->|inputs and state| graph
1832
- graph -->|device logits| sampler
1833
- sampler -->|selected tokens or proposals| method
1834
- method -->|committed tokens only| output
1835
- output -->|response events| server
1836
- method <-->|borrow, update, snapshot, rollback| state
1837
- session <-->|restore / publish prefill checkpoint| cache
1838
- method -->|publish generated checkpoint| cache
1839
- cache <-->|fast reuse| ram
1840
- ram <-->|spill and restore when needed| persistence
1841
- ```
1842
-
1843
- The scheduler chooses **when** work runs and which requests are active. The
1844
- inference method chooses **what numerical work** advances them. A batch of one
1845
- uses the same method and state contracts as a larger batch. The final design
1846
- has one shared executor and no separate serial executor to fall back to.
1847
-
1848
- The model graph returns logits to the sampler. The sampler applies temperature,
1849
- penalties, grammar, sampling filters and RNG policy, and returns selected tokens
1850
- with requested logprobs. MTP keeps proposals private until verification commits
1851
- them. The response formatter sees committed tokens only.
1852
-
1853
- Live KV is working state for the current computation. A reusable checkpoint
1854
- contains token IDs plus the corresponding target, recurrent and optional draft
1855
- state. Both prefill and generated output must feed the same cache interface.
1856
- Only an exact, rendered-stable token boundary can be published for state that
1857
- cannot be trimmed. RAM retention, eviction, asynchronous SSD writes and restart
1858
- restore belong behind that interface. Scheduling does not wait for an ordinary
1859
- SSD spill; an explicit durability flush can wait for persistence.
1860
-
1861
- | Piece | Current code or contract | Remaining work |
1862
- |---|---|---|
1863
- | Server / response adapters | `CompletionEngine`, `CompletionSink`, `GenerationOutput` | Preserve the same semantics through the final shared-executor cutover. |
1864
- | Request policy | `RequestPlan`, request preparation and execution planning | Consolidate configuration into one resolved policy; choose measured defaults for typical multi-turn use and retain user overrides. |
1865
- | Chat template | `ChatTemplate.render` | Expose the renderer as its own narrow port instead of requiring a concrete serving context. Record rendered-stable boundaries for generated checkpoint alignment. |
1866
- | Tokenizer | `LoadedTokenizer` | Reuse the same encode/decode contract across preparation, caching and output. Keep incremental encoding inside this component. |
1867
- | Session / scheduling | `InferenceEngine`, `GenerationSession`, `ExecutionGroup`, `SchedulingClock` | Close all feature and performance gaps before deleting the remaining serial executor. |
1868
- | Inference method | `InferenceMethod`; shared ordinary and speculative methods | Complete every shared-method composition and acceptance gate. Draft depth belongs here, independently of queue policy. |
1869
- | Numerical graph / kernels | `AutoregressiveGraph`, `GraphFactory`, backend bindings | Continue hardware-specific fusion and kernel optimization behind these contracts. |
1870
- | Sampler | `SamplingSession` | Retain one set of sampling/history/logprob semantics for ordinary and speculative execution. |
1871
- | Active state / codec | `Cache`, `KvAttentionState` / `KvAttentionView`, row layouts, `SpeculativeTransaction`, checkpoint attachments | Appending and attending are separate operations. One captured view can serve multiple model layers while retaining pre-write positions and tensor ownership. Delayed affine/TurboQuant and rotating layouts are integrated; qualify additional model/layout combinations separately. |
1872
- | Reusable cache | `PrefixCache.take/put`, shared `PromptCache` | Prefill and processed generated output populate the same immutable RAM/SSD cache. Session lookup and rendered-token alignment are integrated. |
1873
- | Persistence | `ColdTier`, `SpillSink`, `SsdCacheStore`, `SsdDurabilityCoordinator` | Queued persistence, native/restart checks and full Kanban durability acceptance are complete. RAM/SSD retention remains behind cache operations. |
1874
-
1875
- An interface boundary does not require copying tensors, downloading logits,
1876
- or adding an RPC or synchronization per token. Device handles can stay lazy;
1877
- the backend may fuse compatible graph and sampling operations while preserving
1878
- policy, ownership and observable results. Each component can improve its own
1879
- implementation without adding model, cache or sampling decisions to scheduling.
1880
-
1881
- Contract sources: [generation](../../src/contracts/generation.ts),
1882
- [scheduling](../../src/contracts/scheduling.ts),
1883
- [sampling](../../src/contracts/sampling.ts),
1884
- [prefix cache](../../src/contracts/prefix-cache.ts),
1885
- [graph](../../src/inference/graph.ts),
1886
- [tokenizer](../../src/tokenizer.ts),
1887
- [cache tiers](../../src/prompt-cache.ts).
1888
- Performance evidence and default selection live in
1889
- [benchmarks.md](../reference/benchmarks.md); open acceptance remains in Phase 6/18.
1890
-
1891
- #### Kernel configuration ownership
1892
-
1893
- Shared and serial bindings execute within one immutable `RuntimeConfig`.
1894
- Numerical helpers read that scope; they do not read process environment in
1895
- forward loops. The serial speculative trace switch is captured once per run.
1896
- Trellis mode resolves through the same configuration port at weight creation.
1897
-
1898
- TurboQuant caches capture their codec's fused-decode choice at construction.
1899
- RAM clones, full-prefill row restoration, batch layout factories, extraction
1900
- and delayed conversion preserve that choice. KV maintenance binds its runtime
1901
- before conversion, including conversion performed after a host setting changes.
1902
- SSD formats contain numerical state, not a frozen process configuration; their
1903
- receiving cache factory selects the destination binding's policy.
1904
-
1905
- The configuration tests change host settings around scoped construction,
1906
- copy/extraction and delayed conversion. Existing codec/donor tests now select
1907
- both fused settings through `configureRuntime`, so they exercise the same
1908
- configuration contract as serving. Paged request policies also bind the numerical
1909
- namespace and construction policy before deferred lookup or allocation, including
1910
- when a gateway outlives later host configuration changes. The serving reference
1911
- maps flags to their owning interfaces and records supported combinations. The
1912
- legacy internal `flagOn` wrapper is removed; CLI controls remain compatible.
1913
- The new paged-policy tests first reproduce both deferred-setting failures, then
1914
- pass with the captured policy. Paged operation/layout checks pass on both Macs;
1915
- the full local model-free suite and all typechecks pass.
1916
-
1917
- ### 12.15 Package boundaries before community outreach
1918
-
1919
- Initial audit, 2026-09-11. The public-readiness program owns the packaging
1920
- work; the existing interface and optimization milestones retain their scope.
1921
- The three published entry points need different treatment:
1922
-
1923
- | Entry or layer | Verified dependency boundary | Packaging consequence |
1924
- |---|---|---|
1925
- | `mlx-bun/client`, `src/client.ts` | Imports only completion/host contracts; uses standard Request, Response, fetch and cancellation APIs | A candidate for independent client installation. The current npm package still has Darwin/arm64 metadata and application dependencies; a portable source file alone does not change that install contract. |
1926
- | `src/contracts/`, `src/engine/`, `src/inference/` | Separate TypeScript project excludes Bun and DOM types; the AST boundary test limits imports by layer | Keep these interfaces and policies together inside the engine. They do not each need a published package. |
1927
- | `mlx-bun/engine`, `src/library.ts` | CPU-safe entry exports engine/client APIs, but `initializeMlx()` dynamically imports the broad root API; `openIsolatedHost()` imports serving isolation and locates the CLI | Preserve this compatibility entry. Separate native engine initialization from application/worker assembly before treating it as a standalone engine package. |
1928
- | `mlx-bun`, `src/index.ts` | Re-exports concrete models, generation, downloads, registry, fit and server construction | Already a published compatibility API. A workspace move needs forwarding exports, not a silent reduction of available functionality. |
1929
- | Browser application | Own TypeScript project; boundary test allows web code and contracts | A candidate private application workspace. Its assets still participate in the CLI/native bundle. |
1930
- | Website | Already has its own package manifest and build; generates reference pages from canonical docs | Keep one source for reference facts. A root workspace declaration alone would not improve this ownership. |
1931
-
1932
- The source audit followed static imports, re-exports, type imports and literal
1933
- `import()`/`require()` references using TypeScript module resolution. The
1934
- client closure contained four source files and no external module imports.
1935
- The high-level engine entry reached the broad root API, including Pi and web
1936
- assets. This is a dependency inventory, not a claim that importing the
1937
- CPU-safe entry eagerly loads those modules. Non-code assets and executable
1938
- paths also need a packaging check; import analysis cannot establish that they
1939
- ship correctly.
1940
-
1941
- Recommended direction for the remaining audit: one engine package containing
1942
- models, native bindings, cache codecs, inference methods and their interfaces;
1943
- application assembly outside it; a small client package if independent
1944
- installation is useful. Keep specialized kernels and tensor ownership within
1945
- that engine. Memory, Pi and training require their own dependency and asset
1946
- review before deciding whether they become private workspaces. A general MLX
1947
- array binding is a separate API commitment and is not implied by this split.
1948
-
1949
- Before choosing and implementing the layout, map the engine-to-application
1950
- edges through server construction, native bootstrap, worker commands and
1951
- bundled assets. Verify the package tarball and a consumer installed outside
1952
- the repository. Public import compatibility and the single-binary release are
1953
- acceptance requirements. The initial audit does not yet close the package
1954
- organization milestone.
1955
-
1956
- The initial `bun pm pack --dry-run --ignore-scripts` also confirms that the
1957
- package includes the whole `docs/` tree, including archived investigations
1958
- and active plans. Review that allowlist during packaging work; these are not
1959
- runtime dependencies. This dry run inventories the candidate but does not
1960
- replace installation and asset checks against an actual tarball.
1961
-
1962
-
1963
- ### 12.15 Prefill workspace policy
1964
-
1965
- `PrefillPolicy` selects a request's chunk size independently of scheduling,
1966
- cache placement and sampling. The MLX backend captures model geometry and
1967
- explicit configuration when it binds the policy. Ordinary generation,
1968
- shared rows and speculative preparation consume the selected size through
1969
- their existing prefill interfaces. A caller's explicit request value wins.
1970
- The automatic recurrent-attention policy bounds the temporary materialized
1971
- SDPA score workspace; it does not inspect live free memory or refuse work.
1972
- Default values and precedence live in [server configuration](../reference/server-config.md).
1973
-
1974
- ### 12.16 Committed append cache formats
1975
-
1976
- `MlxTokenAppend` declares supported affine precisions and TurboQuant K/V
1977
- formats. Qualified Qwen27B bindings expose KV4/KV8 and K8V3.
1978
- Request preparation supplies template-derived candidates; placement selects
1979
- an eligible method without inspecting numerical cache formats. The ordinary
1980
- method consumes the binding's declaration once and uses its committed-append
1981
- operation. Qwen shares projection work over known tokens while retaining each
1982
- query's one-token affine attention calculation and causal KV extent.
1983
- `KvMaintenance.maxAppendTokens` bounds a committed chunk at a pending
1984
- precision transition; the method runs maintenance before continuing.
1985
- Verification remains a separate method capability: enabling committed
1986
- quantized appends does not enable quantized echo verification. No default fill setting or
1987
- shared-group support is inferred from that declaration.