mlx-bun 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/README.md +1449 -109
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +7 -5
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -1,346 +0,0 @@
1
- # mlx-bun: gemma4.ts decompose & optimize — action plan
2
-
3
- > This is the canonical **design/rationale** for the optimization work.
4
- > Live **status/tracking** (checkboxes, findings) for Phases A–D lives in
5
- > PLAN-archive.md; Phase E remains in PLAN.md.
6
-
7
- **Status (verified 2026-06-17):** Phases A–D are **DONE** (`[x]` in PLAN-archive.md, all landed 2026-06-10/11). Phase E — per-config fused decode-SDPA kernel — is **in progress** (`[~]` in PLAN.md, started 2026-06-11; fused kernel exists and is quality-gated per PLAN.md Step 4). The body of this doc remains the durable design rationale; completed phase checkboxes and findings live in PLAN-archive.md; Phase E tracking lives in PLAN.md.
8
-
9
- **Premise (confirmed from the source read):** the current engine sits at
10
- parity-to-ahead vs mlx-lm on the 12B *while still interpreting the decode
11
- graph every token through hundreds of `bun:ffi` crossings, uncompiled.* The
12
- largest remaining cost is host-side graph rebuilding that is identical
13
- token-to-token — exactly what `mx.compile` exists to erase. Specialization and
14
- custom kernels are real but smaller, and both are only *measurable* once the
15
- host overhead is gone.
16
-
17
- **Therefore the ordering is non-negotiable:** compile first (the big lever),
18
- then decompose + specialize (enables the kernel and cleans the graph), then the
19
- per-config fused kernel (the 2–3× on top). Doing it in any other order means
20
- optimizing against a baseline that compile would have changed anyway.
21
-
22
- **Invariant for the entire plan:** the compat-mode bit-exact parity gate
23
- (`toBe(0)` logits, identical greedy trajectories vs the oracle venv) stays green
24
- at *every* checkpoint. It is the instrument that makes refactoring safe to do
25
- fast — any step that changes behavior turns it red the same hour. No step
26
- proceeds with a red gate. No tolerance is ever added to make a refactor pass;
27
- divergence is root-caused, never papered over.
28
-
29
- ---
30
-
31
- ## Phase A — Compile the decode step (on the current monolith, before any split)
32
-
33
- **Why first:** this is the 14×-class lever for *this* runtime specifically,
34
- because mlx-bun's per-step cost is FFI-crossing-heavy in a way Python's
35
- interpreter loop is not. It is independent of decomposition. Landing it first
36
- means every later phase is measured against a compiled baseline, so you learn
37
- exactly how much headroom specialization actually has left to chase instead of
38
- chasing host overhead that compile already removed.
39
-
40
- **Steps:**
41
-
42
- 1. **Characterize before touching anything.** Run `decode-split.ts (deleted; git history)`
43
- (the per-step wall-time splitter that already exists) on all three models at
44
- @600 and @8k. Record GPU-blocked time vs JS-graph-build time per step. This
45
- is the control measurement; everything in Phase A is judged against it. The
46
- prediction: e4b shows the largest JS-graph-build fraction (it has the
47
- per-layer-input slicing loop no other model runs).
48
-
49
- 2. **Wire `mx.compile` around the single-token decode graph.** The unit to
50
- compile is one `forward(tokens=[next], cache)` step: embed → forwardLayers →
51
- finalNorm → logitsFromHidden → argmax. At fixed L=1 every op is shape-stable
52
- token-to-token; only input values and cache offsets change. Use
53
- `shapeless=True` semantics so the same compiled graph serves any decode step.
54
- The cache update is the one stateful part — confirm the compiled region
55
- either includes the sliceUpdate writes or is structured so the cache mutation
56
- happens at stable shapes (see step 4).
57
-
58
- 3. **Keep prefill uncompiled (or separately compiled).** Prefill is
59
- variable-length (L = prompt size), so it does not share a compiled graph with
60
- decode. Leave prefill on the current path initially; a separate
61
- fixed-tile-size compiled prefill is a later option, not part of this phase.
62
-
63
- 4. **Resolve the cache-mutation/compile boundary.** The quantized caches do
64
- `quantize → sliceUpdate(ring) → activeSlices` per step (≈670 FFI crossings
65
- per token on the 12B across 48 layers). Decide whether these live inside the
66
- compiled graph (preferred — collapses the crossings into one replay) or
67
- immediately outside it. The ring-index bookkeeping is host-side integer math
68
- and stays in JS; only the array ops compile.
69
-
70
- 5. **Parity gate.** Compiled decode must produce bit-exact identical token
71
- trajectories to the uncompiled path on the fixed prompt suite. Compile must
72
- not change numerics — if it does, a fusion inside the compiled graph reordered
73
- an op; root-cause it.
74
-
75
- 6. **Measure.** Re-run `decode-split.ts`. Expected: JS-graph-build fraction
76
- collapses, e4b ~5% residual shrinks or closes, 12B short-context moves
77
- further ahead. Record the delta — this number tells you how much the rest of
78
- the plan is even worth.
79
-
80
- 7. **Re-run the fused-decode A/B *after* compile, not before.**
81
- `MLX_BUN_FUSED_DECODE` measured ~3% *worse* uncompiled, almost certainly
82
- because the tile loop's per-iteration host overhead dominates at L=1. Compiled,
83
- that host cost vanishes and the flag may flip to a win with no kernel written.
84
- This is a free re-measurement that may close part of the gap on its own.
85
-
86
- **Phase A exit:** compiled decode green on parity, measured speedup recorded per
87
- model, fused-decode A/B re-evaluated. Decision point: how much headroom remains?
88
- That answer scopes Phases D–E.
89
-
90
- ---
91
-
92
- ## Phase B — Extract a shared, config-independent base
93
-
94
- **Why:** before generating per-model files, separate the machinery that is
95
- genuinely identical across all architectures from the parts that vary. This is
96
- mechanical, parity-preserving code movement — no behavior change, gate stays
97
- green throughout.
98
-
99
- **Moves into `gemma4-base.ts` (or `src/model/gemma4/base.ts`):**
100
-
101
- - Cache classes: `KVCache`, `QuantizedKVCache`, `RotatingKVCache`,
102
- `RotatingQuantizedKVCache` — these are architecture-independent storage; which
103
- *combination* a model uses varies, but the classes themselves don't.
104
- - SDPA functions: `quantizedSdpaUnfused`, `quantizedSdpaTiled`,
105
- `fusedSdpaSupported`, `quantizedSdpa`, plus `ops.sdpa` plain dispatch.
106
- - Mask builders: `createCausalMask`, `bidirMask`, the `Mask`/`MaskMode` types.
107
- - Primitives: `RMSNorm`, `QuantizedLinear`, `QuantizedEmbedding`,
108
- `QuantizedSwitchLinear` and the LoRA machinery (`LoraWeights`, `LoraState`).
109
- - Helpers: `disposing`, `mapTriple`, `disposeTriple`, `logitSoftcap`,
110
- `argmaxLastPosition`, `lastPositionLogits`, `FINFO_MIN`.
111
-
112
- **Stays model-specific (does NOT move to base):** `Attention`, `MLP`, MoE
113
- (`Router`/`Experts`/`SwitchGLU`), `DecoderLayer`, `Gemma4Model.forwardLayers`,
114
- `computePerLayerInputs` — these branch on architecture and become the
115
- per-model generated code.
116
-
117
- **Steps:**
118
-
119
- 1. Create the base module, move the listed classes verbatim, fix imports.
120
- 2. Run the full parity suite + all behavioral tests. Green = the move was
121
- behavior-preserving. This is the only acceptance criterion for Phase B.
122
- 3. No optimization in this phase. Pure extraction. Resist the urge to "improve
123
- while moving" — that conflates a refactor bug with an optimization bug.
124
-
125
- **Phase B exit:** base module extracted, every test green, monolith now contains
126
- only the model-specific assembly that Phase C will generate.
127
-
128
- ---
129
-
130
- ## Phase C — Generate three per-architecture files (not author — generate)
131
-
132
- **Reframe from the original request:** the per-model files are *outputs of a
133
- generator*, not hand-written variants. Loop unrolling and branch elimination are
134
- mechanical transforms; a codegen script performs them from each model's config.
135
- Three files = three generator outputs. When the base algorithm changes, you
136
- regenerate, not hand-edit three copies.
137
-
138
- **The three targets (your actual runnable set):**
139
-
140
- - `gemma4-12b.ts` — dense. Full-attention `KVCache` (or quantized variant),
141
- GQA, no per-layer-input, no MoE, no KV-sharing. The simplest graph.
142
- - `gemma4-e4b.ts` — the complex one. Per-layer-input gating, KV-sharing
143
- (donor/sharer layers), sliding/rotating quantized cache. This is where the
144
- per-step host overhead concentrated, so it's where specialization pays most.
145
- - `gemma4-26b.ts` — MoE. Router + experts (`SwitchGLU`/`gather_qmm`), parallel
146
- dense+routed branches.
147
-
148
- **The generator (`scripts/gen-model.ts`):** reads `config.json` +
149
- `kv_config.json` for a model and emits the specialized file. What it eliminates,
150
- all resolvable at generation time from known constants:
151
-
152
- - The per-layer `instanceof` cache-type check (gemma4.ts:1327) — each layer's
153
- cache type is known from `layer_types`, so the generated layer calls the right
154
- fetch directly, no runtime `instanceof`.
155
- - The `if (this.router)` / `if (perLayerGate)` / KV-sharing forks in
156
- `DecoderLayer.forward` and `forwardLayers` — each model takes exactly one
157
- branch; the others are deleted from its file.
158
- - The `forwardLayers` layer loop — unrolled into straight-line per-layer calls
159
- with each layer's constants (type, cache index, donor index, sliding/full)
160
- baked in. (Note: post-compile this is largely cosmetic for *speed* — compile
161
- already erased the per-step cost — but it produces a cleaner compiled graph
162
- and removes the `intermediates`/`previousKvs`/`cacheIndex` indirection arrays
163
- and their per-step lookups.)
164
- - The per-layer-input `slice`+`reshape` loop (gemma4.ts:1865) on non-e4b models:
165
- deleted entirely (they don't have it). On e4b: the slice bounds are constant
166
- per layer, so they're baked.
167
-
168
- **Steps:**
169
-
170
- 1. Write `gen-model.ts`: input = model dir (config + kv_config), output = one
171
- `.ts` file importing from `gemma4-base.ts`. Start with the 12B (simplest) to
172
- prove the generator end-to-end.
173
- 2. Generated 12B must pass parity bit-exact against the oracle. This proves the
174
- generator preserves behavior — the gate is the generator's test.
175
- 3. Generate e4b and 26B. Each passes parity. The KV-sharing donor/sharer wiring
176
- in e4b is the trickiest to generate correctly; its parity test is the proof.
177
- 4. Dispatch: model load picks the generated module by config fingerprint
178
- (arch + kv_config hash), with the **monolithic `gemma4.ts` retained as the
179
- general fallback** for any model without a generated specialization. Nothing
180
- is deleted; specialized files are opportunistic overrides.
181
-
182
- **Phase C exit:** three generated, branchless, unrolled per-model files, each
183
- bit-exact, dispatched by fingerprint, with the monolith as fallback. Measure
184
- each vs its Phase-A compiled baseline — expect small wins (cleaner graph, fewer
185
- indirection lookups), not large ones. The large one was compile.
186
-
187
- ---
188
-
189
- ## Phase D — Per-config kernel specialization (kv_config-driven)
190
-
191
- **Why:** now that each model has its own file and the cache/SDPA dispatch is
192
- already branch-free per model, bake the *quantization* constants. The
193
- kv_config.json's per-layer (bits, group_size) becomes compile-time information
194
- in the generated SDPA and cache calls.
195
-
196
- **What gets specialized, from the 12B's kv_config as the worked example**
197
- (42 layers @ 4-bit/gs64, 6 layers @ 8-bit/gs64, group_size uniformly 64):
198
-
199
- - **Per-layer bit-width resolved at generation, not per-step.** The generated
200
- layer for index 6 calls the 8-bit SDPA path; index 0 calls the 4-bit path.
201
- No runtime bit-width parameter, no `fusedSdpaSupported` bit check — the
202
- generator already knows.
203
- - **group_size folded as a compile-time constant** (64 everywhere in this
204
- config) — `dim / group_size`, `32 / bits` (elements-per-int) become literals.
205
- - **nRep (GQA ratio) baked** — the `nRep > 1` branch and the `expandDims`
206
- broadcast become a constant-folded reshape with the literal ratio.
207
- - **head_dim baked** — sliding (256) vs full-attention (512) head dims are known
208
- per layer.
209
-
210
- **Important honesty:** Phase D is specialization of the *existing* op-graph
211
- (constant-folding, branch deletion), still using `ops.quantizedMatmulQT` etc.
212
- It is NOT yet a custom kernel. Expected gain is modest — it removes parameter
213
- passing and branches the compiled graph would partly handle anyway. Its real job
214
- is to make Phase E's custom kernel *possible* by having a single known
215
- (bits, group_size, nRep, head_dim) per dispatch site.
216
-
217
- **Steps:**
218
-
219
- 1. Extend `gen-model.ts` to read kv_config and emit per-layer-specialized SDPA
220
- dispatch (right bit-width path per layer, constants folded).
221
- 2. Parity gate per generated model. Bit-exact required — constant-folding must
222
- not change numerics.
223
- 3. Measure vs Phase C. Record the (likely small) delta. If negligible, that's a
224
- *finding*, not a failure — it means compile already captured it, and it tells
225
- you the kernel in Phase E is the only remaining lever.
226
-
227
- **Phase D exit:** each generated model has branch-free, constant-folded,
228
- per-layer-specialized quant dispatch. Every dispatch site now has a single known
229
- shape — the precondition for Phase E.
230
-
231
- ---
232
-
233
- ## Phase E — Per-config fused decode-SDPA kernel (the 2–3×, last)
234
-
235
- **Why last:** this is the custom Metal kernel, the fun part, and it's the
236
- *smallest* lever (the search and the turboquant retro both say the fused kernel
237
- was 2–3× while the buffer/host path was the big win — which you've already
238
- captured in Phases A and D). Doing it last means you measure its true
239
- contribution against a compiled, specialized baseline instead of attributing
240
- host-overhead noise to it.
241
-
242
- **What the kernel does** (the mlx-qsdpa shape, specialized per bit-width):
243
-
244
- - Decode-time (L=1) fused attention: stream the quantized KV through QK^T and
245
- ×V in one Metal dispatch, dequantizing inline, **never materializing** the
246
- `[B,H,1,N]` scores row or the dequantized cache.
247
- - **nRep baked in** — no `expandDims` GQA broadcast (gemma4.ts:916); the kernel
248
- loops the query-head group internally with the literal ratio.
249
- - **bits/group_size as compile-time template parameters** — generate the 4-bit
250
- variant and the 8-bit variant; dispatch the right one per layer from the
251
- config (Phase D already resolved which).
252
- - Online-softmax fused (score → max → exp → ×V accumulate) so the scores never
253
- hit memory.
254
-
255
- **Mechanism:** `mx.fast.metal_kernel` (the intended extension point — no MLX
256
- fork). Lift the *dequant unpacking logic* from a known-correct reference
257
- (mlx-qsdpa is open, `_BaseCache`-compatible, ~200 lines) — the bit-unpacking and
258
- scale/zero-point application is the well-trodden, copyable part. The novel part
259
- is the *fusion boundary* (not writing the intermediate) and the *Bun dispatch*
260
- (every existing impl dispatches from Python; a Bun-dispatched fused quant-SDPA
261
- is genuinely unoccupied territory).
262
-
263
- **Correctness regime — this is where the gate model changes:**
264
-
265
- - A fused kernel that's faster will **not** be bit-exact with the unfused path
266
- (online softmax ≠ one-shot softmax in bf16 — this is already documented in the
267
- tiled path's "tier b" note). So the compat bit-exact gate does NOT apply to
268
- the kernel output directly.
269
- - Instead: the kernel runs under the **perf-mode flag** and is gated against the
270
- **frozen ground-truth snapshot** (capture today's compat-mode logits/
271
- trajectories on the fixed prompt suite *before* starting Phase E — that's the
272
- quality oracle once bit-exact-vs-optiq no longer applies).
273
- - Perf-mode gate = bounded logit tolerance + token-trajectory agreement above a
274
- set threshold, *labeled with the measured delta* (e.g. "+X% tok/s, −Y% on the
275
- eval set"), the way a quant ships with its perplexity hit. "No guarantee of
276
- identical output" means **bounded and measured**, never unchecked.
277
- - Compat mode (bit-exact, unfused) stays in the codebase permanently as the
278
- `-O0` reference and differential-testing oracle: when the kernel misbehaves,
279
- flip to compat, same prompt, and the diff localizes kernel-vs-expectation.
280
-
281
- **Steps:**
282
-
283
- 1. **Freeze the ground-truth snapshot** (compat-mode logits + trajectories,
284
- fixed prompt suite, all three models) before writing any kernel. This is the
285
- perf-mode oracle.
286
- 2. **Metal capture one decode step** (`mlx_metal_start_capture`) on the
287
- compiled+specialized 12B to confirm the prize size: is the dequantized-cache
288
- round-trip still fat after compile, or did fusion upstream already thin it?
289
- If thin, the kernel ceiling is low — record and decide. If fat, proceed.
290
- 3. **Toolchain derisk first:** get a trivial `mx.fast.metal_kernel` compiling,
291
- dispatched from Bun, running, verified — *before* the GQA numerics. (RMSNorm
292
- or a no-op fusion proves the `.metal` → mlx-c → `bun:ffi` pipeline end-to-end
293
- so the real kernel debugs numerics OR plumbing, not both at once.)
294
- 4. **Generate the 4-bit fused decode kernel** for the 42 four-bit layers (where
295
- 42/48 of KV traffic lives and 4-bit's dequant round-trip is most lopsided
296
- against compute). nRep, group_size baked.
297
- 5. **A/B vs compiled+specialized baseline**, paired, clean machine, at @8k (where
298
- KV traffic dominates and fusion shows). Isolate the kernel's contribution.
299
- 6. **Decide on the 8-bit six.** 8-bit dequant is cheaper and the data fatter, so
300
- the fusion win per-byte is smaller — possibly not worth a second kernel; stock
301
- MLX path may stay for those layers. Measure before committing kernel #2.
302
- 7. **Per-model:** repeat the generation for e4b and 26B configs only if the 12B
303
- kernel shows a real win. The generator (Phase C/D) already produces the
304
- dispatch; the kernel is one more generated, per-bit-width artifact keyed by
305
- fingerprint, each with its own auto-generated parity/quality test.
306
-
307
- **Phase E exit:** per-config fused decode kernel(s), perf-mode flag, gated
308
- against the frozen quality oracle with the trade *labeled*, compat mode retained
309
- as permanent reference. Measured isolated contribution recorded.
310
-
311
- ---
312
-
313
- ## Cross-cutting discipline (applies to every phase)
314
-
315
- - **Parity gate green at every checkpoint.** Compat bit-exact for Phases A–D;
316
- frozen-snapshot quality tolerance for Phase E's perf mode. Never add a
317
- tolerance to make a refactor pass — root-cause divergence.
318
- - **One flag, one measurement per lever.** Compile, fused-decode, each
319
- specialization, the kernel — each is independently togglable and independently
320
- measured ("run it both ways, compare"), so you always know what each bought.
321
- Never measure two new levers tangled together.
322
- - **Clean machine or it didn't happen.** Reboot + preflight-gate every quotable
323
- benchmark; `sudo purge` for cold-start rows.
324
- - **Losing experiments become documented default-off flags, never deletions.**
325
- - **Nothing deleted, fallback always present.** The monolith stays as the
326
- general fallback; specialized/generated files are opportunistic overrides
327
- dispatched by config fingerprint. An unhandled config runs slow, never broken.
328
- - **Generator over hand-edits.** Per-model files are regenerated from config,
329
- not maintained by hand. A base-algorithm fix is one regeneration, not three
330
- edits. Each generated artifact ships with its generated parity test.
331
-
332
- ## Expected outcome, honestly stated
333
-
334
- - **Phase A (compile):** the big win. Likely closes the e4b ~5% residual and
335
- pushes the 12B further ahead. This is the lever that matters most and it's
336
- pure host-side — no kernel, no Metal.
337
- - **Phases C–D (decompose + specialize):** small wins (cleaner graph, deleted
338
- branches/indirection), main value is enabling Phase E and improving
339
- maintainability via codegen.
340
- - **Phase E (kernel):** the 2–3× on the attention hot path, biggest at long
341
- context, smallest lever of the three but the one with no upstream Bun-dispatched
342
- equivalent — the genuinely novel contribution.
343
-
344
- The sequence front-loads the largest, cheapest win (compile) and ends with the
345
- most fun, most novel, smallest one (kernel), with every step gated by the oracle
346
- that's kept the project honest from the start.
@@ -1,120 +0,0 @@
1
- # ORPO from-base on UltraFeedback (mixed-5bpw) — results + research directions
2
-
3
- **Status:** experiment complete (2026-06-23). This is the validation run **and** the
4
- research program it surfaced. Detailed research notes for the session of 2026-06-21…23.
5
-
6
- **Companion docs:**
7
- - [orpo-dynamic-lambda.md](../design/orpo-dynamic-lambda.md) — the adaptive-λ / PID controller (extended below).
8
- - [orpo-future-enhancements.md](../design/orpo-future-enhancements.md) — SimPO + objective variants.
9
- - [orpo-uf-testing-handoff.md](orpo-uf-testing-handoff.md) — the **earlier** from-*instruct* UF run (4-bit, seq 2048, no-segment). **Distinct** from this run.
10
- - [segmented-backward-training.md](../design/segmented-backward-training.md), [steel-flash-cce-handoff.md](steel-flash-cce-handoff.md) — the memory/kernel stack this run exercised.
11
-
12
- ---
13
-
14
- ## 1. The run
15
-
16
- From-**base** (true base, not instruct) ORPO on UltraFeedback, MiniCPM5-1B.
17
-
18
- - **Base:** `openbmb/MiniCPM5-1B-Base-OptiQ-mixed-5bpw` — the **true base**, mixed-precision quant (unblocked by the quantization fix). NOT the instruct model the earlier run used.
19
- - **Data:** `uf-binarized-chat` — UltraFeedback as `{prompt:[{role,content}], chosen, rejected}`, **60,630 train pairs**. Prompt is a structured message array; chosen/rejected are raw response strings.
20
- - **Config:** ORPO, **1 epoch (3,790 optimizer steps)**, B=1, **seq 4096**, rank 16 / scale 2, **λ=0.1**, lr **1e-5**, **segmented backward (2 layers/seg)**, **flash-CCE head**, **grad-accum 16** (eff. batch 16), coeff filter ON (`MLX_BUN_CCE_BWD_FILTER_EPS`, real-data ~0.16%).
21
- - **Template:** the base quant has **no `tokenizer_config.chat_template`**; `ChatTemplate.load` falls back to **`chat_template.jinja`** (which *we* dropped into the quant when building it). It's **ChatML** (`<|im_start|>{role}\n…<|im_end|>`) **+ MiniCPM's XML tool format** (`<function><param>…</param></function>`, CDATA) **+ the hybrid `<think>` block**. We rendered `enableThinking:false` (injects an empty `<think>\n</think>\n\n` before the response).
22
- - **Recipe fidelity:** lr 1e-5 + λ 0.1 (NOT the saturating 5e-5); **mean-logp verified length-normalized** over response tokens (`responseOnlyLogpMean`: `sum(logp)/M`, M = response-token count) — this is the single most common ORPO parity break and we are on the right side of it, including in the flash-CCE head (parity-validated to 0.21% vs the full-logits mean path).
23
-
24
- ## 2. Memory validation (the headline systems result)
25
-
26
- - **Peak 4.82 GB** — the legitimate high-watermark, driven by the longest example (~2,354 tok chosen+rejected, idx 5582, **+ the prompt**), **not** the 4096 cap (all UF < 4096; 0 examples exceed it — that's *why* 4096 was chosen). My earlier ~4 GB estimate was ~0.5 GB low (slope under-call), not a leak.
27
- - **Active flat at 0.892 GB** across ~3,300+ steps — **bit-identical early-to-recent, zero drift → NO leak.** Active (the baseline), not peak (example-length-driven), is the leak signal. The ~0.4 MB/step leak we caught earlier would've surfaced as **~1.3 GB of drift** over the run; we saw **0**. So any residual leak is bounded *below detectability*.
28
- - The whole stack — flash-CCE, steel GEMM, segmented backward, AdamW, grad-accum, the coeff filter + block-skip — ran **dispose-balanced end-to-end** for a full epoch. **A 1B ORPO epoch in < 5 GB, holding flat.** This retires the memory risk for the bigger runs below.
29
-
30
- **Predictive memory model (validated):** peak ≈ resting + (2-layer-segment activation) × (longest sequence). Deterministic, bounded; plateaus once the longest example runs. Watch `active_gb` for drift = the leak detector.
31
-
32
- ## 3. Results — the model
33
-
34
- - **Val preference accuracy FLAT ~55.5%** across every eval (500→3000: 55.1, 55.1, 56.3, 55.9, 56.3, 55.9). Plateaued by step 500, **never strengthened**. The 55→56 wobble is 1–3 of 256 examples — inside the ±3.1% SE. n=256.
35
- - **Val loss** crept down (1.356 → 1.305 — the NLL/format half); **train margin** rose slightly (mean 0.19 → 0.25). A **weak, stable preference** reached early and held.
36
- - This is the **two-ORPO-halves-decouple** result again: the SFT/NLL half learns the format fast; the preference half barely generalizes on a 1B with subtle UF pairs.
37
-
38
- ## 4. Vibe-check — 20 questions through base+UF
39
-
40
- **Single-turn (fresh context each):**
41
- - **Good:** simple **code** (prime function correct, sqrt-optimized), **arithmetic** (17×23=391 ✓, 3+5−2=6 ✓), **creative persona** (the pirate plays the role).
42
- - **Weak/wrong:** **factual recall** ("capital of Australia" → *"there is no specific capital"*; "most recent election" → *"Trump won 2020"*), **translation** ("I love programming" → *"Je love à programmer"*), **identity/privacy/weather** (hedging non-answers), **instruction constraints** ("list exactly three… and nothing else" → preambled anyway).
43
-
44
- **Two failure MODES (the actually-useful findings):**
45
- 1. **Multi-turn copying loop** — in a running conversation, once a generic disclaimer enters the history, the model **parrots its own previous assistant turn** for nearly every subsequent question (Q4–9, 15–20 were byte-identical). **Root cause: UF is single-turn preference data** — it never learned to hold a conversation, so the path of least resistance is copy-the-last-turn.
46
- 2. **Hedging-disclaimer boilerplate** ("I'm here to help… I am a language model… respectful and safe… I will never fab[ricate]") — over-learned from UF's RLHF-safety filler.
47
-
48
- ## 5. Conclusions
49
-
50
- 1. **VALIDATION SUCCESS.** The chain works end-to-end: quant **base** loads → trains clean a full epoch → **zero leak** → **chats**. ORPO replicated at ~1/60th scale, **on a laptop**, single-stage base→assistant.
51
- 2. **Modest-as-predicted.** base + 1 epoch UF + λ=0.1 = a weak preference (flat 55.5%) and modest quality. We forecast this; it is the expected outcome, **not a miss**.
52
- 3. **The failure modes are DATA artifacts, not method artifacts.** Multi-turn collapse ← single-turn UF; hedging ← UF's disclaimer filler. Both fixable by **changing the data** → this *reinforces* the specialist-curation direction (we control the data). The vibe-check effectively handed us the **curation spec**: add multi-turn examples, filter the disclaimer filler, use our tools in our format.
53
- 4. **CONFOUND CORRECTION (load-bearing).** The gap vs `MiniCPM5-1B-SFT` is **NOT** evidence that single-stage can't replace SFT. We changed **method AND data simultaneously** — 60k UF pairs vs ~400B-token SFT (~1000×). The data difference dominates. The only clean claim is the near-tautological **"60k UF pairs ≠ 400B-token SFT"** (a *data* statement). The **method** question (single-stage vs multi-stage) is **untested** — it requires holding data constant (see §6.5).
54
-
55
- ## 6. Research directions (crystallized this session)
56
-
57
- These form a build: each removes a confound or fixes a measured weakness of the prior.
58
-
59
- ### 6.1 SimPO, and why it's nearly free for us
60
- SimPO = reference-free, length-normalized, `−log σ(β·(ℓw−ℓl) − γ)` with a **target margin γ** and **no SFT term** (pure preference; applied *after* SFT). We already compute the length-normalized `ℓw`, `ℓl` (`branchLogpMean`), so SimPO is a **one-term loss swap** → a `--method simpo` + `--beta`/`--gamma`. Natural fit for **SimPO-on-`MiniCPM5-1B-SFT`** (the staged comparison).
61
-
62
- ### 6.2 ORPO + SimPO's margin (the γ-hybrid) — the fix aimed at *our* result
63
- For our regime (ℓw≈ℓl), ORPO's odds-ratio ≈ the logp difference already; what SimPO *adds* is the **target margin γ**. ORPO's `−log σ(separation)` gradient **vanishes once chosen ≥ rejected** (separation ≥ 0) → the model plateaus at tiny separation = **our flat margin**. The γ margin **moves the saturation point from 0 to γ**, keeping gradient alive. So: `L = NLL(chosen) + λ·[−log σ(β·(ℓw−ℓl) − γ)]` — ORPO's SFT anchor + SimPO's non-saturating push. Aimed directly at the flat-55.5% we measured.
64
-
65
- ### 6.3 SFT + SimPO single-stage (the SimPO analog of ORPO)
66
- "SFT + SimPO at the same time," the way ORPO is "SFT + DPO at the same time." Composes cleanly (both NLL and SimPO push chosen-logp **up** → reinforce). **Watch-out:** SimPO also pushes `logp(rejected)` **down**, and the NLL anchor grounds chosen but **not** rejected — over-aggressive β/γ over-suppresses coherent rejected text → fluency erosion. Tune so the push doesn't outrun the anchor.
67
-
68
- ### 6.4 Dynamic preference controller (PID/AIMD) — see [orpo-dynamic-lambda.md](../design/orpo-dynamic-lambda.md)
69
- The flat margin looks like **saturation**, and the *optimal* preference pressure is **non-stationary** (fragile early, robust late) → **no fixed λ is optimal**; a controller tracks the moving target and **beats any fixed value** (a sweep finds the best *constant*; this finds the best *trajectory*). Reframed this session as a **control problem**: NLL = the process variable, the preference weight = the actuator, AIMD/PID = the law. The integral term (the "missing letter") kills chronic steady-state degradation; the derivative (slope) is a **leading** indicator that catches the helping→hurting inflection *before* the level rises. Build **P → PD → PID**, each term earning its place against an observed failure of the prior. Folds the λ/β/γ sweep into one run. Detail + the control-theory framing now in orpo-dynamic-lambda.md §"Control-theory framing (PID/AIMD)".
70
-
71
- ### 6.5 SFT-as-preference / SPIN comparison — the confound-free method test
72
- **The interesting one.** Take a **chunk of `UltraData-SFT-2605`** (CPM5's *own* SFT data), make preference pairs **SPIN-style** (chosen = the gold answer, **rejected = on-policy: the model's own generation** for that prompt), train single-stage. Removes the data confound (same data CPM5-SFT saw). Two comparisons:
73
- - **Method-isolating (rigorous):** plain SFT vs single-stage-preference on the **same chunk** → proves "preference-formatted SFT ≥/= SFT" with no confound. *Why it could be ≥:* ORPO on (gold vs self-gen) = NLL does the SFT **+** the preference term adds "commit to gold over your own output."
74
- - **"Approach CPM5-SFT" (aspirational, data-gated):** needs a large fraction of 400B tokens → the data gap re-enters; don't let it quietly re-import the confound.
75
- - Smart first cut: a **single-domain chunk** (knowledge or instruction-following — where base+UF was weakest) — small, legible.
76
- - **NOT an ORPO-paper replication** — a *different*, arguably more novel comparison.
77
-
78
- ### 6.6 Scale-up to a standard 7B, on the laptop
79
- Memory math (validated): 7B resting ~4.4 GB + 2-layer-segment activations → **~8–12 GB peak at seg 2** on UF-length data; **seg 1** halves the activation term (more recompute = slower) for headroom. **Fits 32 GB with room** — the segmented backward was *built* for exactly this (e4b targeted ~10 GB @ 8192; UF < 4096 is the easy end). **Time, not memory, is the cost** (~7× FLOPs/token → days on a laptop). Prefer a **standard dense 7B (Mistral-7B-base** — the ORPO paper's flagship) over e4b for direct literature comparison; it's standard Llama-arch (≈ MiniCPM5's family) so the handler is ~a day. **Strategic flip:** "7B preference-aligned on a 32 GB consumer laptop" *is* the local-to-you thesis at scale — scale-up strengthens the accessibility pitch instead of diluting it.
80
-
81
- ### 6.7 Diffusion-LM frontier (high-novelty, low *marginal* cost)
82
- Apply ORPO/SimPO/the controller to a **diffusion language model** (e.g. a Gemma-diffusion). Likely **open territory** (DPO-for-diffusion exists for *images* — Diffusion-DPO — not for diffusion *LMs* + single-stage/dynamic). The diffusion **forward is product-justified anyway** (mlx-optiq has it, mlx-lm doesn't, mlx-vlm does) → once it exists, the preference objective is the same **loss-head swap**. Technical crux: the likelihood is a **stochastic ELBO** (not exact logp), so `ℓw`/`ℓl` are noisy MC estimates → **the dynamic controller's noise-robustness is a *synergy*, not a mismatch.** Length normalization must be rederived for the diffusion loss. Base quality lags AR (24B-diff ≈ 12B-AR), so the contribution is *"does single-stage preference-opt work on diffusion LMs,"* novel regardless.
83
-
84
- ## 7. Template note (for any future run)
85
-
86
- - For **portability / paper-grade** runs, impose a **clean plain-ChatML** template (no MiniCPM XML-tool / `<think>` extensions) at data-prep instead of falling back to the model's custom one. Trivial (drop a clean `chat_template.jinja` / override `renderDpoPrompt`).
87
- - The model's **native tool format is the XML `<function>/<param>`** one — any tool-use training data must use **that**, not OpenAI JSON `tool_calls`.
88
-
89
- ## 8. The data — `UltraData-SFT-2605` (the substrate for §6.5)
90
-
91
- [openbmb/UltraData-SFT-2605](https://huggingface.co/datasets/openbmb/UltraData-SFT-2605) — the actual SFT data behind `MiniCPM5-1B-SFT`:
92
- - **15,036,178 examples · 319 GB · ~400B tokens** (200B deep-thinking + 200B hybrid-thinking). **Apache 2.0.**
93
- - **Single-response (gold only) — NOT preference pairs** → the rejected must be manufactured (SPIN-style on-policy).
94
- - **Single-turn** (no multi-turn) → won't, by itself, fix the multi-turn copying loop.
95
- - Domains: math / code / knowledge / instruction-following. Thinking split **6.5M deep / 8.5M non-thinking**. **Chunked by domain** → take a slice, never the full 319 GB. (Multi-GB download is the user's to kick off, not a session's.)
96
- - The three published models: `MiniCPM5-1B-Base` → `MiniCPM5-1B-SFT` → `MiniCPM5-1B` (instruct, RL+OPD on top of SFT).
97
-
98
- ## 9. The framing that ties it together
99
-
100
- - **What SFT builds vs what preference-opt aligns:** our failure list (multi-turn, instruction discipline, breadth, `<think>`) is ~the SFT stage's job description — but per §5.4 that's mostly a **data** statement (400B curated tokens), not proof the SFT *method* is irreplaceable.
101
- - **Where single-stage genuinely wins:** specialists (narrow curated data — no foundation breadth needed) and as a **final alignment stage on a good SFT**. NOT a foundation-SFT replacement — *and our own run is the evidence for that boundary, honestly scoped.*
102
- - **The narrow specialist is the product** (welcome-agent / memory-agent on our closed tool surface); the general UF model was always the **validation**, and it handed us the curation spec for free.
103
-
104
- ## 10. Choosing what's next — the three lenses (NO decision made yet)
105
-
106
- Apply all three to any §6 direction; they point different ways:
107
-
108
- 1. **Will it work + be useful to US?** (the *product* lens — primary.) Does it improve the specialists we actually ship? Usually gated by a **cheap diagnostic first** — e.g. for the controller: does a *higher fixed λ* or the **γ-margin** even unstick the flat preference? If a fixed push does nothing, *no controller can.* Run the cheap fixed-knob version before the fancy one.
109
- 2. **Interesting paper?** (read / replicated / adds to the ORPO-style discourse.) Strong hooks (control-theory/PID, SFT-as-preference, diffusion-LM preference-opt), but it's a **crowded, competitive space** → the result has to be the non-stationarity / confound-free kind to be more than "auto-tuning," and credibility likely needs **scale** (7B+, standard model, standard benches).
110
- 3. **Fundable / by whom?** The *technique* funds itself via the **product** (cheaper specialist training), independent of any paper. As a paper/grant: compute-cost-sensitive trainers + the local-AI community + project credibility. It's a *method* contribution, not a product.
111
-
112
- **The trap + the rule:** don't let the *paper* lens drive the work. **Let the product need drive it** (lens 1), run the cheap diagnostics first, and treat the **paper as a harvest** if the result turns out strong — the experiments that make it a good feature are the same ones that'd make it a paper, so the lens-2/3 decision can wait until lens 1 reports.
113
-
114
- **Rough risk / novelty / cost of the §6 directions (for when we pick):**
115
- - **§6.2 γ-hybrid / higher-λ diagnostic** — lowest cost, directly targets the measured flat preference. *The cheap first cut.*
116
- - **§6.1/6.3 SimPO-on-SFT / SFT+SimPO** — low (loss-swap), needs the SFT checkpoint pulled.
117
- - **§6.4 PID controller** — medium (build + tune), highest method-novelty of the AR options.
118
- - **§6.5 SPIN-on-UltraData** — medium (chunk + on-policy generation), the **confound-free method test**, distinct from ORPO replication.
119
- - **§6.6 7B-Mistral-on-laptop** — ~a day handler + days of compute; the credibility + thesis-at-scale move.
120
- - **§6.7 diffusion** — highest novelty, lift mostly paid by the product (the forward exists anyway); the ambitious swing.
@@ -1,167 +0,0 @@
1
- # flash-CCE host-buffer pin leak — post-mortem + L3 verification approach
2
-
3
- **Date:** 2026-06-21 · **Status:** fixed (`fix(train): stop host-buffer pin leak…`,
4
- commit `2592959`) + hardened (`harden(train): anchor ptr()'d FFI buffers…`, `6491696`).
5
-
6
- ## Symptom
7
-
8
- ORPO LoRA training (MiniCPM5-1B, flash-CCE head + prefix-share + segmented
9
- backward) crashed **natively** (segfault / "panic: A C++ exception occurred",
10
- SIGTRAP — *not* an MLX-reported error) after a few hundred steps:
11
-
12
- | config | crashed at |
13
- |---|---|
14
- | accum-4 + seg-2 (most ops/step) | step **363** |
15
- | accum-4 + no-seg | step **783** |
16
- | accum-1 + no-seg (fewest ops/step) | step **≥915** |
17
-
18
- Tells: **deterministic** (same step across runs), **monotonic in ops/step**
19
- (more kernel ops per step → earlier crash), and MLX `active` memory **flat**
20
- (~1.3 GB) the whole time. Crucially, **it ran the entire training with zero
21
- crashes on a 32 GB M1 Max**, and crashed on a 24 GB M4 Pro.
22
-
23
- ## Wrong turns (recorded so we don't repeat them)
24
-
25
- 1. **Agent sandbox** — the first crash was on a session-launched run, so the
26
- sandbox looked guilty. Ruled out: a user-launched run crashed at the *same*
27
- step 783.
28
- 2. **GPU-allocator fragmentation / OOM** — `peak` sat at 16.7 GB on a 24 GB
29
- box. Ruled out: with segmentation `peak` was only 2.9 GB and it crashed
30
- **earlier** (363), and the same 16.7 GB peak ran fine post-fix. Not memory.
31
- 3. **prefix-share fallback / templated-data seam** — a real new behavior (the
32
- `</think>\n\n` seam trips the byte-identical prompt check → two-forward
33
- fallback) but not the cause.
34
- 4. **grad-accum / grad-clip (the new settings this session)** — the right
35
- *thread* (look at what changed), wrong leaf. Both were exonerated.
36
-
37
- ## Root cause
38
-
39
- `u32()` in `flash-cce.ts` (and the twin in `model/flash-attention.ts`) built the
40
- tiny `shape` / `targets` kernel-argument arrays with **`MlxArray.fromView`** —
41
- the **zero-copy pinning** path. `fromView` inserts the host `Uint8Array` into a
42
- module-level `pinned` Map and hands MLX a raw pointer with an **async**
43
- `unpinCallback` ("mlx may release buffers from its eval thread"). These args feed
44
- a **lazy** kernel and are `dispose()`d in a `finally` *before the kernel
45
- evaluates* — so the pin is never reclaimed in time. The pins **leaked**.
46
-
47
- **Proof (the smoking gun).** Instrumenting `pinnedBufferCount()` per step on the
48
- buggy code:
49
-
50
- ```
51
- step 1: pinned 32 active 1.087GB
52
- step 2: pinned 64 active 1.088GB
53
- ...
54
- step 32: pinned 1024 active 1.099GB → +32 per step, never released
55
- ```
56
-
57
- Perfectly linear `+32/step`, `active` dead flat. The leaked buffers live in the
58
- JS heap + a threadsafe-JSCallback dtor queue, **outside MLX's `active`
59
- accounting** — which is exactly why every symptom held: per-op accumulation (more
60
- kernel calls/step → faster growth → earlier crash), `active` flat, native crash
61
- (host allocator / callback queue corruption), and **machine-dependence** (a
62
- 24 GB box reuses the freed-but-pinned buffer sooner → a latent use-after-free
63
- becomes a fatal read; 32 GB had the headroom to never hit it).
64
-
65
- ## Fix
66
-
67
- `u32()` → **`fromBytesCopy`** (`mlx_array_new_data`, which **copies**). These
68
- few-int arrays feed a lazy kernel and are disposed before it runs, so they must
69
- be **MLX-owned**, not host-pinned. A few-int copy is free.
70
-
71
- **Verification:** `pinned` goes `+32/step → flat 0`; the previously-fatal
72
- seg-2/accum-4 config ran to **step 548** (past 363) clean; numerics unchanged
73
- (copy vs pin = same bytes).
74
-
75
- ## Hardening (defense-in-depth)
76
-
77
- - **`MetalKernel.apply` keepAlive** — anchor every `ptr()`'d JS buffer (output
78
- shapes, template-arg names, the input-handle array, the result slot) in a
79
- `keepAlive` list referenced after the FFI calls. `bun:ffi` `ptr()` does not
80
- retain its argument; this closes the same lifetime class. Pure-additive.
81
- - Added `pinned: pinnedBufferCount()` to the per-step train metric as a permanent
82
- **canary** for this bug class (visible in `train-watch`).
83
-
84
- ## Lesson for the codebase
85
-
86
- `fromView` (zero-copy pin) is only safe for buffers that **outlive the MLX
87
- array** (mmap'd weights — `fromPointer`/`fromView` with process-lifetime memory).
88
- For any **transient** host buffer handed to a **lazy** op and disposed before
89
- eval, use the **copying** constructor (`fromBytesCopy`/`fromInt32`/`fromFloat32`).
90
- Grep for `fromView` in hot paths when adding kernels.
91
-
92
- ---
93
-
94
- # L3 verification approach (no oracle exists)
95
-
96
- This bug also clarified how we *should* verify the flash-CCE ORPO head, because
97
- "bf16-class error" was the wrong framing.
98
-
99
- ## The parity tiers
100
-
101
- - **L1** — bit-for-bit drop-in for **mlx-lm** (proven: 8192/8192 greedy tokens
102
- identical).
103
- - **L2** — bit-for-bit drop-in for **mlx-optiq**.
104
- - **L3** — mlx-bun originals (the flash-CCE ORPO training head). **Neither
105
- mlx-lm nor optiq ships ORPO+CCE training — there is no oracle to be bit-exact
106
- against.**
107
-
108
- So the "0.28% dh" figure is **not an error rate or a degradation.** It is the
109
- **floating-point reassociation gap between two *correct* implementations** — the
110
- flash kernel (tiled, online-softmax, fp32) vs the full-logits MLX head (a
111
- different reduction order) — and the full-logits head is itself only a *proxy*,
112
- not an oracle. Two correct reductions in different orders cannot be bit-identical;
113
- 0.28% is the inherent floor, not slop.
114
-
115
- **Correctness in L3 is proven by what does NOT need a reference implementation:**
116
-
117
- 1. **Finite-difference gradient check** (`flash-fd-check.ts`) — the kernel's `dh`
118
- vs numerical ground truth to ~4 decimals. This is the real proof: it says the
119
- kernel computes the *right gradient*, independent of any other implementation.
120
- 2. **By-hand math audit** of the dequant, online-LSE recurrence, `coeff =
121
- onehot − softmax`, dh accumulation, and the `1/M` cotangent (done; clean).
122
- 3. **Agreement with the full-logits proxy** to fp-reassociation precision
123
- (logp 0.21%, dh 0.28%) — corroboration, not the proof.
124
-
125
- ## The coeff filter — measure on REAL data, not synthetic
126
-
127
- `flash-cce-parity.ts` uses a **synthetic random hidden**, which gives a
128
- **flat-ish** softmax (high entropy) → gradient mass spread across many tokens →
129
- filtering the near-zero coeffs costs accuracy (the recorded 0.66%→2.7%). **That
130
- is the filter's worst case and not what it's for.** On real trained-model
131
- outputs the next-token distribution is **sharply peaked** (low entropy):
132
- `coeff_v = c·(onehot_v − softmax_v)`, and for almost every non-target token
133
- `softmax_v ≈ 0`, so its coeff ≈ 0 and dropping it costs ~nothing — the gradient
134
- mass is in the target + the handful of high-softmax tokens. **The filter is
135
- designed exactly for the peaky real-data regime; the synthetic benchmark
136
- maximizes its apparent cost.**
137
-
138
- **MEASURED (2026-06-22, `scripts/experiments/flash-cce-filter-realdata.ts`) — the
139
- hypothesis holds.** On 8629 real response tokens from real examples (real model
140
- forward, **real next-token targets**; mean P(true token) = 53.9% → genuinely
141
- peaked), the filter's dh error vs exact:
142
-
143
- | eps | dh error | backward speedup |
144
- |---|---|---|
145
- | 1e-6 | 0.024% | 1.15× |
146
- | **1e-5** | **0.162%** (below the 0.33% bf16 floor → indistinguishable) | **1.35×** |
147
- | 1e-4 | 0.681% | 1.47× |
148
- | 1e-3 | 1.943% | 1.52× |
149
-
150
- The synthetic `REAL=1` test (random targets) showed **21.4% @ 1e-4** — a ~30×
151
- overstatement, an artifact of the onehot landing on a ~0-softmax random token.
152
- **Verdict: enable the filter at eps ~1e-5** — free speed (error under the
153
- reassociation floor) on real data. Re-measure as the model trains (peakedness
154
- shifts), and always with REAL targets, never synthetic.
155
-
156
- ## Standing L3 gates (what to run, since there's no oracle)
157
-
158
- Per the project's parity-as-correctness model (bit-exact where an ancestor
159
- overlaps; KL + quality + benchmarks where it doesn't):
160
-
161
- 1. **Filter-on-real-data** — ✅ DONE (above): near-free at eps ~1e-5 on real
162
- targets (0.16% dh, 1.35× backward). `flash-cce-filter-realdata.ts`.
163
- 2. **Teacher-forced grad fidelity** — flash head vs full-logits head `dh`
164
- (gradient cosine + relnorm) on real data, as the standing L3 regression gate
165
- (replaces the synthetic-data parity number for *quality* claims).
166
- 3. **End-to-end quality eval** — the completed training run's downstream task
167
- quality (the real proof that L3 trains correctly).