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