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,2129 +0,0 @@
1
- ---
2
- status: landed
3
- axis: ON
4
- canonical-for: speculative-decoding
5
- plan-anchor: "Phase 14 — Qwen 3.x family bring-up `[~]`"
6
- last-verified: 2026-09-07
7
- ---
8
-
9
- # Speculative decoding — one verifier, every draft source
10
-
11
- Speculative decoding in mlx-bun is ONE verify/accept executor
12
- (`src/spec/serve-loop.ts`, `specServeRun`) behind ONE seam
13
- (`src/spec/source.ts`, `DraftProvider` / `DraftSource` / `TargetView`), with
14
- every drafter — a second model, a KV-borrowing head, a trained block
15
- drafter, a model-free lookup, a target-native MTP row — differing only in
16
- what fills the draft. Output is the target's own samples at every position;
17
- a drafter can only change decode SPEED (acceptance, tokens per target
18
- forward), never which tokens are emitted. This doc is canonical for the
19
- seam contract, the verifier/rollback contract, the source roster and each
20
- source's oracle, and the DSpark program (our trained drafter + DeepSeek's
21
- released one). Status and changelog prose live in PLAN.md; this doc keeps the
22
- design plus a short dated History.
23
-
24
- Consolidated 2026-08-23 from `docs/design/speculative-decoding.md` (base),
25
- `docs/design/speculative-decoding.md` (phases 0–6 + the wall-clock-negative problem
26
- statement) and `docs/design/speculative-decoding.md` (12B assistant γ=1 result).
27
- The DSpark handoff (first live run, recipe) is archived at
28
- [docs/archive/investigations/dspark-handoff.md](../archive/investigations/dspark-handoff.md).
29
-
30
- ## 1. The seam (`src/spec/source.ts`)
31
-
32
- ```
33
- DraftProvider server-lifetime: owns the loaded draft weights
34
- .open({ sampler, target: { model, caches } }) → DraftSource (per request)
35
- DraftSource per request: owns draft-side state
36
- prefillMode? "tail-split" (default, mlx-lm shape) | "full" (native MTP)
37
- pinTargetKernelFamily? GLM native MTP: one M=1 quantized family across the verify batch
38
- tapLayers? layer indices the loop must capture on prefill + every verify forward
39
- prefill(promptIds, ctxML?) seed draft state (ctxML iff tapLayers)
40
- draft(feed, n, stepBase, anchorHidden?) → 0..n RETURN LENGTH IS AUTHORITATIVE
41
- commit(d, kAccept, vCtxML?, verifiedHidden?, acceptedTokens?)
42
- weightsBytes admission accounting (0 when the provider owns the weights)
43
- ```
44
-
45
- - `target` is a read-only view of the target model + its LIVE caches (the
46
- same arrays the loop drives). Two-model ignores it; every KV-borrowing
47
- source reads donor K/V, embeddings, lm-head or hidden taps through it.
48
- - `sampler` is the REQUEST sampler (mlx-lm parity: drafts are sampled with
49
- the same sampler as the target; greedy drafting under a temperature>0
50
- request is not parity — two-model and both MTP sources honor this; the
51
- assistant and DSpark sources draft greedily, which is lossless but not
52
- parity at temp>0).
53
- - `feed` is mlx-lm's re-feed rule (generate.py:645-648): `[correction]` after
54
- a rejected round, `[lastDraft, bonus]` after an all-accept round.
55
- - `draft()` may return fewer than `n` (DSpark confidence pruning) or ZERO
56
- (DeepSpec ℓ=0 / ngram no-match): the loop degenerates to one plain target
57
- step, still tapped and committed for context-growing sources.
58
- - `commit()` ownership: `vCtxML` transfers to the source; `verifiedHidden`
59
- stays caller-owned.
60
- - Per-slot readiness: each source binds its own target state (donor views,
61
- anchor hidden, tapped context), which is what a batched executor would
62
- need to open one source per row. The executor is the hard part — variable
63
- accept length per slot breaks a uniform-B step — so per-slot spec is a
64
- batched-scheduler project tracked in
65
- [unified-engine-frontier-plan.md](unified-engine-frontier-plan.md), not
66
- free composition. Today a mounted draft forces the serial lane for every
67
- request (upstream `is_batchable = draft is None`).
68
-
69
- ## 2. The verifier / rollback contract (`src/spec/serve-loop.ts`)
70
-
71
- Faithful to mlx-lm `speculative_generate_step` (generate.py:473-654, read
72
- from the oracle venv). Per round:
73
-
74
- 1. **Draft** `d ≤ n` tokens (`n = min(γ, tokens left)`), with the anchor
75
- hidden offered to sources that borrow it.
76
- 2. **One target forward** over `[pending, ...drafts]` (d+1 positions),
77
- tapped when `tapLayers` is set. The lm-head runs ONCE over the whole
78
- window (batched — matches mlx-lm and optiq; NOT bit-exact to stock
79
- token-at-a-time decode at bf16 knife-edges, see §2.1).
80
- 3. **Accept walk**: sample the target at each position in order through the
81
- shared `StepSampler` (processors, grammar mask, history — identical
82
- ordering to the serial and batched lanes); accept while the target's
83
- token equals the draft's (exact token-match acceptance, NOT
84
- distribution-level rejection sampling); the first mismatch emits the
85
- target's correction, an all-accept round emits the bonus. EOS is never
86
- emitted as content, even when it arrives as an accepted draft.
87
- 4. **Emit** the round's tokens through `onToken` one at a time, in order
88
- (bursts of ≤ d+1), so stop-sequence matching and detokenization see the
89
- stream `generate()` would produce.
90
- 5. **Roll back + commit**: the verify window kept positions `0..kAccept`.
91
- Trimmable caches `trim(d − kAccept)`; recurrent caches
92
- `specRoundRollback(kAccept + 1)`; on full accept `specRoundCommit()`.
93
- Then `source.commit(d, kAccept, vCtxML, vHidden, drafts[0..kAccept))`;
94
- the next anchor hidden is the verify hidden at the emitted position.
95
- 6. **Chain** via the re-feed rule; `pending = emit`.
96
-
97
- **Cache rollback contract** (`src/model/gemma4-base.ts` `Cache`):
98
- `trim(n, bypass?)` for trimmable caches; the optional spec-round trio
99
- `specRoundBegin()` / `specRoundCommit()` / `specRoundRollback(keep)` for
100
- non-trimmable recurrent state. `SSMCache` (`src/model/qwen3-delta.ts`,
101
- gated-DeltaNet) implements the trio: the snapshot is free (MLX arrays are
102
- immutable — the layer hands its replaced conv/recurrent refs to the round),
103
- and rollback restores the snapshot then REPLAYS the kept `keep` window tokens
104
- through conv1d + the delta kernel from recorded position-local inputs
105
- (`qkv`/`a`/`b`, retained not copied). Replay is bit-exact by construction:
106
- the kernel's per-thread loop is serial, so the prefix arithmetic is identical
107
- whether or not the rejected tail was processed (gated in
108
- tests/qwen-ssm-specround.test.ts). The loop arms every cache before the
109
- verify forward; a cache that is neither trimmable nor round-capable ends
110
- speculation for the request.
111
-
112
- **Deliberate deviations from upstream**
113
-
114
- - Rotating-cache ring wrap: upstream RAISES when a `RotatingKVCache` stops
115
- being trimmable mid-generation (generate.py:529-533); a serve endpoint
116
- must not 500 mid-stream, so the loop checks `offset + n + 1 < maxSize`
117
- before each round and, if the window is about to wrap, STOPS SPECULATING
118
- and finishes with plain single-token decode (bit-equivalent — the
119
- target's own samples). The standalone `src/spec/generate.ts` loop keeps
120
- the reference behavior and throws.
121
- - Prompt-cache reuse is BYPASSED on the spec path (fresh caches per spec
122
- request, `cachedTokens = 0`). mlx-lm composes spec with its LRU prompt
123
- cache; wiring ours through `PromptCache` + the SSD tier is the open item
124
- in §8.
125
- - Grammar × spec (novel — no runtime serves both): the drafter runs FREE;
126
- the grammar mask rides the accept walk in `samplePos` (mask before
127
- sample; the matcher advances on emitted tokens only, so rejected drafts
128
- never touch grammar state and no matcher rollback exists). Grammar
129
- termination mid-burst truncates the round. Gates: greedy grammar+spec ≡
130
- greedy grammar-only long-prefix + 100% schema validity
131
- (tests/spec-serve.test.ts).
132
-
133
- Telemetry (`usage.speculation`): drafted / accepted / rejected / targetCalls /
134
- rounds / acceptanceLengths / tokensPerForward / forwardsSaved, plus
135
- per-position `draftedByPos` / `acceptedByPos` (the acceptance-A/B report).
136
- `MLX_BUN_SPEC_TRACE=1` prints per-round feed + drafts.
137
-
138
- ### 2.1 Prefill convention and what "lossless" means here
139
-
140
- - **Oracle prefill shape** (`MLX_BUN_PREFILL_TAIL_SPLIT`, default on): mlx-lm's
141
- speculative path drains BOTH models to len−1 and has NO separate step-0 —
142
- the un-drained last prompt token HEADS the first verify window, and the
143
- first emitted token is that window's position-0 sample. A separate L=1
144
- step-0 is ulp-different from the (1+γ)-window GEMM and flips near-ties.
145
- Gated live 4/4 token-for-token vs the oracle venv (γ∈{2,3} × 2 prompts,
146
- including a knife-edge cell). Sources with `prefillMode: "full"` (Qwen
147
- MTP, GLM MTP) take the full-prompt shape their references use.
148
- - **Batched verify vs stock decode**: both oracles (mlx-lm, optiq) batch the
149
- verify lm-head, so greedy spec is bit-exact to THE SPEC ORACLE and agrees
150
- with stock decode only on tie-free prompts. An earlier port verified
151
- per-position to match stock — a target no real implementation has, at a
152
- γ× lm-head read tax — and was replaced by `picksBatched`
153
- (`src/spec/generate.ts`, 2026-06-14). Losslessness gates therefore use
154
- TIE-FREE prompts (tests/spec-decode.test.ts, spec-serve-assistant,
155
- qwen38-mtp) or long-prefix agreement (spec-decode-12b): a flip on a
156
- tie-free prompt is an accept/reject/rollback bug, never rounding.
157
- - **"Lossless" is a claim about the verifier, not the artifact.** The
158
- Qwen3.8-27B TQ artifact's serve gauntlet recorded MTP at 76% acceptance /
159
- 2.53 tokens per forward WITH an output-divergence flag vs plain greedy
160
- (consistent with verify-width reduction-order near-ties, the same class as
161
- the 12B step-0 convention; margin analysis queued) — it is NOT claimed
162
- lossless on the model card. The 27B bf16-target pairing gate, by
163
- contrast, was token-identical on its tie-free prompt (PLAN 14g).
164
-
165
- ## 3. Draft-source roster
166
-
167
- `--draft-model <dir>` mounts a drafter; the artifact's KIND selects the
168
- provider (`src/server.ts` `detectDraftKind`; `--draft-kind` overrides).
169
- Detection order: `dspark.json` → `dspark`; `config.json` `architectures[0]
170
- === "Gemma4DSparkModel"` → `deepspec`; `model_type` containing `assistant` →
171
- `assistant`; `model_type` ending `_mtp` → `mtp`; else `two-model`. `ngram`
172
- is never detected (no artifact) and refuses a `--draft-model`; any other
173
- kind without one is refused. `--draft-kind mtp` with no `--draft-model`
174
- resolves the companion bundled at `<model>/mtp/` (single-repo artifacts) and
175
- refuses otherwise. GLM-5.2's checkpoint-native MTP row mounts by default
176
- (`--mtp on|off`) and is mutually exclusive with an explicit drafter.
177
-
178
- | kind | source | what fills the draft | target state used | draft sampler | default γ | oracle / gate |
179
- |---|---|---|---|---|---|---|
180
- | `two-model` | `src/spec/two-model.ts` | a full second model, autoregressive, own KV | none | request sampler | 3 (mlx_lm.server) | **L1**: mlx_lm.server `--draft-model`, same pair, greedy, token-for-token (spec-vs-spec). Shared B1/B>1 autoregressive draft state retains independent attention/recurrent boundaries and the pending final-token lag; paired RAM/SSD checkpoints use backend cache codecs. Tokenizer-family probe at startup refuses mismatches (upstream silently accepts ~0%). |
181
- | `assistant` | `src/spec/assistant-source.ts` (+ `drafter.ts`) | Gemma "-assistant" Q-only 4-layer head | donor K/V (last sliding + last full layer) + anchor hidden, borrowed each step | greedy (own head) | 3 | **L2**: optiq `spec_generate` — e4b γ=2 identical 48-token output AND identical accept/reject trace (drafted 60 / accepted 17 / target calls 31), `scripts/oracle/oracle-spec.py`. Head picked by TENSOR PRESENCE (centroid vs tied-embedding) — optiq's config-based detection loads the 12B/26B unified drafters with zero-init centroids → 0% acceptance; ours 29% on the same artifact. |
182
- | `dspark` | `src/spec/dflash-source.ts` (+ `dspark/module-dflash.ts`) | our trained DSpark block drafter (KV injection + Markov + confidence) | multi-layer hidden tap (`tapLayers`, e4b {20,31,41,42}) grown into H_ctx | greedy | pinned to `cfg.gamma` | **Lab** (no external oracle for our checkpoints): CPU smoke, infer-loop bit-identity pins, real-weights serve gate. See §4. |
183
- | `deepspec` | `src/spec/deepspec-source.ts` (+ `dspark/deepspec-module.ts`) | DeepSeek's released `Gemma4DSparkModel` drafters (e.g. `dspark_gemma4_12b_block7`, γ=7) | tap `[5,17,29,41,46]` on the 12B, projected into an incremental context-KV cache; accepted rows only | argmax (temp-0 reference) | pinned to `block_size` | **DeepSpec reference** at temperature 0: its leaky rejection sampling degenerates to exact argmax token-match, RNG-free — round-for-round trace fixtures (`scripts/oracle/oracle-dspark-deepspec.py`; the compare script was deleted 2026-08-23, git history). |
184
- | `ngram` | `src/spec/ngram-source.ts` | model-free prompt lookup: longest trailing k-gram (max..min) matched at its FIRST earlier occurrence; the continuation is the draft | token history rebuilt from prompt + feed/commit | none | 10 (Saxena `num_pred_tokens`); `--ngram-max 3` / `--ngram-min 1` | Ported from Prompt Lookup Decoding (Saxena) + vLLM `ngram`. Lossless by verify — gated token-identical to non-spec greedy (tests/spec-ngram.test.ts on e4b; tests/qwen35-spec-ngram.test.ts on the 0.8B hybrid, proving real accepts AND real DeltaNet rollbacks). |
185
- | `mtp` | `src/spec/qwen-mtp-source.ts` | Qwen-trained MTP head (`qwen3_5_mtp`, one full-attention layer + `fc` merge; `mlx-community/Qwen3.8-27B-MTP-*`) | target `embed_tokens` + `lm_head` (not standalone) + PRE-final-norm last-layer hidden via `tapLayers = [nLayers−1]`; `prefillMode: "full"` | request sampler | `block_size − 1` (=2) | Reference: mlx-vlm `qwen3_5_mtp` drafter. Draft-logit parity vs mlx-vlm 0.6.14: draft tokens exact through the chained block, worst \|Δlogprob\| 1.9e-1 = bf16-vs-f32 floor. Losslessness: token-identical on the tie-free 27B pairing gate (tests/qwen38-mtp.test.ts, opt-in `MLX_BUN_TEST_QWEN38_MTP=1`). Target rollback = the SSMCache spec-round contract (§2). |
186
- | GLM native | `src/spec/glm52-mtp-source.ts` | GLM-5.2's checkpoint-native MTP row (`enorm`/`hnorm`/`eh_proj` + one decoder layer, int8 routed experts) | target embeddings + output head + anchor hidden; own `MLACache` role `mtp`; `prefillMode: "full"`, `pinTargetKernelFamily` | request sampler | `glmMemoryPlan.mtpDraftTokens` | Direct Colibri (SPEC_PIN contract; "niente prefill" — the first draft opens a decode-only window from the anchor). Commit rebuilds accepted rows from the target's VERIFIED hidden window (only the first speculative row was conditioned on a true hidden). Measured in docs/reference/benchmarks.md "Colibri G4 serial native MTP". |
187
-
188
- The `source.ts` header roster lists five of these (two-model, assistant,
189
- dflash, ngram, GLM MTP); `deepspec` and `mtp` are wired in `server.ts` and
190
- the CLI and belong in the same list — this table is the complete roster.
191
-
192
- **Row conventions worth knowing.** Qwen MTP is predict-2-ahead: drafter KV
193
- row at position p is built from `(embed(token_{p+1}), hidden_p)`; `draft()`
194
- opens by building the pending token's row from the target's TRUE hidden at
195
- the emitted position (held over from the verify tap), then chains its own
196
- output for the rest of the block; `commit()` trims rejected rows and, on
197
- all-accept, appends the missing accepted row from the verify hidden. The
198
- sampler contract is `[1, V]` — the module output `[1,1,H]` must be
199
- reshaped before sampling or 2-D-slicing samplers (top-k) throw (the
200
- 2026-08-20 serve-lane MTP 500; both MTP sources carry the fix).
201
-
202
- ## 4. DSpark — the trained block drafter
203
-
204
- DSpark (DeepSeek, arXiv:2607.05147, "Confidence-Scheduled Speculative
205
- Decoding with Semi-Autoregressive Generation") = a **DFlash** parallel
206
- backbone (KV-injected, all γ draft tokens in one pass) + a lightweight
207
- **sequential head** (Markov, Eq 5; RNN, Eq 6) adding intra-block dependency
208
- + a **confidence head → calibration → draft-length scheduler**. DFlash alone
209
- suffers suffix decay; the sequential head is what makes it DSpark.
210
-
211
- ### 4.1 Mechanism (our module, `src/spec/dspark/module-dflash.ts`, paper Eq 2–3)
212
-
213
- - **Eq 2 (context):** tap the target's hidden states at layers `{l1…lm}`
214
- (e4b default {20,31,41,42}, the last = post-finalNorm sentinel at index
215
- nLayers), concat on the feature axis, project to draft width:
216
- `H_ctx ∈ [L_ctx, d]`. Extraction is the parity-safe `model.hiddenTap`
217
- (no-op when off) in `gemma4.ts` `forwardLayers`; `qwen3_5.ts` carries the
218
- same contract.
219
- - **Eq 3 (injection):** every draft layer forms
220
- `K_i = [W_i^K H_ctx; W_i^K H_d]`, `V_i` likewise, `Q_i = W_i^Q H_d`; the
221
- γ-block queries attend bidirectionally over `[context ++ block]`. The
222
- draft projects the target's HIDDEN STATES with its OWN Wk/Wv (not the
223
- target's K/V — that is the assistant drafter).
224
- - **Markov head (Eq 5):** `B_k = W1[x_{k−1}]·W2`, r=256, W2 zero-init →
225
- starts as pure DFlash, τ climbs as intra-block dependency is learned.
226
- - **Confidence head (Eq 7):** `c_k = σ(wᵀ[h_k; W1[x_{k−1}]])` (we add a
227
- zero-init bias — superset).
228
- - **Loss (Eq 8–12):** `0.1·CE + 0.9·TV + 1.0·BCE`, position weights
229
- `w_k = exp(−(k−1)/γ)`, analytic c*. Audit verdict: matches the paper to
230
- the letter; our defaults (γ=5, 5 layers, Markov) = their production
231
- config.
232
- - **RNN head (`cfg.seqHead: "rnn"`)**: ungated Elman
233
- `s_k = tanh(s_{k−1}·wH + E[x_{k−1}] + bH)`, `B_k = s_k·wO` (wO zero-init;
234
- init-equivalent to Markov). The paper's Eq 6 is a gated cell over
235
- `[s_{k−1}; W₁[x_{k−1}]; h_k]` — ours differs, kept as a variant (paper
236
- calls the RNN gains marginal; DeepSpec ships the gated form if ever
237
- wanted).
238
- - **Confidence-scheduled pruning (Alg 1, single-user form)**: `forwardInfer`
239
- drops position k (and truncates the block) when
240
- `c_k < thresholds[k] ?? minConf`; position 0 always survives. Activation is
241
- checkpoint-driven (`cfg.sts` thresholds) or `MLX_BUN_DSPARK_MINCONF`;
242
- uncalibrated checkpoints draft fixed-γ. Invariant: pruning changes how
243
- many positions the target verifies, never what is emitted (gated:
244
- truncation-never-redraw, prefix-identical to the unpruned block).
245
- - **Calibration (`src/spec/dspark/calibration.ts`)**: per position, the
246
- smallest threshold whose Laplace-smoothed `P(accepted | conf ≥ τ)` meets
247
- the target; pos 0 → 0; under-sampled → 0; unreachable → 1.0. This fits the
248
- RELEASED reference's scheduler shape (per-position threshold truncation on
249
- sigmoid confidence, default 0 = off, ℓ=0 allowed). The PAPER's §3.2.1 STS
250
- (per-position temperatures by ECE grid search on survival products) and
251
- Alg 1's throughput maximization over a profiled SPS(B) table live in
252
- DeepSeek's UNRELEASED serving layer — paper-faithful STS/Alg-1 is a Lab
253
- item only if the survival-product scheduler ever earns a default.
254
- - **Verify**: the serve loop's token-match acceptance (§2). The standalone
255
- `generate-dflash.ts` keeps the paper's distribution-level verify
256
- (`min(1, p/q)` accept + residual `norm(relu(p−q))` resample) for the
257
- measure path; greedy is identical, temp>0 is lossless either way but
258
- token-match accepts less.
259
- - **Rollback past the sliding window**: `trim(n, bypass=true)` physically
260
- slices rejected tips on rotating caches (`gemma4-base.ts`).
261
- - **Checkpoint format**: `dspark.json` stamps `variant: "dspark"` (legacy
262
- `"dflash"` accepted); `src/spec/dspark/loader.ts` `loadDsparkDrafter()`
263
- dispatches by variant and REFUSES v1 single-vector checkpoints
264
- (`module.ts`/`data.ts`/`generate.ts` — the superseded baseline that
265
- dropped KV injection) with a pointer at the trainer.
266
-
267
- ### 4.2 The v1 → v2 finding (why "faithful" matters)
268
-
269
- v1 fused a single final-hidden vector as one token — it removed the paper's
270
- load-bearing mechanism and never tested it. v2 is faithful. Getting v2 to
271
- paper-range required an off-by-one fix in the TV-loss target alignment
272
- (block position k predicts `x_{t+1+k}` whose target is
273
- `softmax(LM_head(h_{t+k}))`; the data gathered `t+k+1`) — present in both
274
- v1 and v2, fixed in `data-dflash.ts` (`blockIdx = g+k`). Overfit on 3
275
- articles: per-position acceptance ~0.75, τ 3.24 (paper range 0.6–0.9 / τ
276
- 3–4) — the architecture is correct. 160 articles generalize to ~0.17 and
277
- plateau; width is not the ceiling (`dDraft` 1024 and 2560 both plateau);
278
- the paper trains on 1.3M samples × 10 epochs. (M1 Max 32 GB, e4b
279
- OptiQ-4bit, 2026-06-30.)
280
-
281
- ### 4.3 DeepSpec — the released reference, and why DSpark has an oracle
282
-
283
- DeepSeek open-sourced DeepSpec (MIT) + trained drafters incl.
284
- `deepseek-ai/dspark_gemma4_12b_block7` (6.86 GB bf16, γ=7, for
285
- gemma-4-12B-it). Their drafter is a DIFFERENT module from ours: a full
286
- Gemma4-shaped 5-layer transformer — hidden 3840, 16 Q heads × head_dim 512,
287
- 1 KV head with K≡V (`attention_k_eq_v`, no v_proj), scale 1.0 (QK-norm),
288
- partial RoPE 0.25 θ=1e6, per-layer `layer_scalar`, scaled embed (×√3840),
289
- UNTIED lm_head, final softcap 30, incremental context-KV cache. 74 bf16
290
- tensors, no key prefix, `architectures: ["Gemma4DSparkModel"]`. 12B tap
291
- layers `[5,17,29,41,46]` (their layer_id+1 output convention == our
292
- `tapLayers` index; no final-norm sentinel). Ported verbatim in
293
- `deepspec-module.ts` (transcribe their forward, then op-for-op), with
294
- context rows cached post-norm-post-rope (bit-equivalent to their in-round
295
- concat; argued in `projectContextKV`). Argmax is over the bf16 sum — an f32
296
- sum reorders near-ties vs torch.
297
-
298
- Consequence: DSpark is no longer oracle-less. The DeepSpec port + their
299
- checkpoint is the no-training path to a 12B speedup, gateable
300
- round-for-round at temp 0. Our trainable module remains the research path
301
- for custom targets. Their training recipe (for scale reference):
302
- open-perfectblend regenerated by the target, 10 epochs, batch 512, lr 6e-4,
303
- ~38 TB cached hiddens.
304
-
305
- The drafter also loads QUANTIZED: `scripts/dspark.ts quantize` writes an
306
- mlx-native affine sibling (`src/spec/dspark/quantize-drafter.ts`: every 2-D
307
- matmul weight + `embed_tokens`/`markov_w1` as quantized-gather tables;
308
- `confidence_head`, norms, `layer_scalar`, biases stay bf16 — the mlx
309
- `false` convention), and `deepspec-module.ts` detects `.scales` siblings and
310
- routes through `quantized_matmul` / QuantizedEmbedding gather-dequant
311
- (mlx-lm numerics). 8-bit tracks bf16 token-for-token on the synthetic
312
- checkpoint. Drafter numerics only move ACCEPTANCE, never correctness, so the
313
- entire quality gate for any drafter quantization is one acceptance A/B.
314
-
315
- ### 4.4 The wall-clock problem (why spec is opt-in)
316
-
317
- Spec decode amortizes fixed draft overhead only when the TARGET forward is
318
- expensive. The recurring finding across every drafter and target:
319
-
320
- - **e4b is near the worst case** (fast target): assistant γ=2 ran 0.78× of
321
- a 54 tok/s baseline at ~23% acceptance (Phase 6, 2026-06-10); even a τ≈3
322
- DSpark drafter nets ~0.4–0.5×.
323
- - **12B assistant γ=1 is a modest win** — see History 2026-06-14.
324
- - **12B + DeepSpec block7 (first live run, 2026-07-07, loaded M4 Pro
325
- 24 GB, directional only):** τ ≈ 2.8 committed tokens per target forward
326
- at 26–33% per-token acceptance (the predicted OptiQ-4bit-target
327
- degradation vs their bf16 training) — the algorithm WORKS — but
328
- wall-clock LOST ~3.4× (spec 14.6 vs serial 49.8 aggregate tok/s, conc-4).
329
- The tax is the drafter: 6.9 GB bf16 → ~3 GB of weight reads per round
330
- (2 GB untied lm_head + 7 × 134 MB markov_w2 + layers), ~14 host syncs
331
- per round in the transcription-faithful `draftBlock`, tapped verifies
332
- falling back to the unoptimized monolith, and ~14 GB of paired weights
333
- on a 24 GB box.
334
- - **27B + Qwen native MTP (2026-08-18, quiet M1 Max 32 GB, interleaved
335
- off/on ×3, spreads 2.2%/4.4%, arms token-identical):** median OFF 15.75
336
- vs ON 12.93 tok/s — 0.821× at γ=2 despite 61% acceptance and 2.25
337
- tokens/forward. The bf16 head's serial per-draft cost (full-vocab lm-head
338
- matmul + sample per draft) exceeds the saved 27B forwards. Levers if
339
- reopened: quantize the head; batch/defer its per-draft lm-head sampling.
340
- - **GLM-5.2 native MTP (M1 Max 32 GB, Colibri G4):** 1.235× wall
341
- throughput, 32/92 accepted, 2.065 tokens per verify forward — the one
342
- measured wall-clock win, on a target whose forward is expensive enough
343
- (docs/reference/benchmarks.md).
344
-
345
- Doctrine: a lone request must never get slower because a flag exists; spec
346
- stays opt-in per (target, drafter) pair until it wins a clean-machine
347
- paired A/B; losing configs stay documented default-off. Denominator
348
- discipline: speedups only ever vs the SAME model's non-spec baseline.
349
-
350
- ### 4.5 The DSpark serving program (12B) — phases and gates
351
-
352
- Goal: spec ≥ 1.3× serial decode on 12B at the best config, clean-machine
353
- paired A/B — then decide when it is on by default. Objective stated right
354
- (Josh, 2026-07-07): 26–33% acceptance with the bf16 drafter is the
355
- WORKABLE baseline (τ≈2.8 already pays in forwards); the question
356
- quantization must answer is PRESERVATION — do we keep that number at
357
- 4-bit? Sensitivity is MEASURED, never guessed: optiq's method (simulate-quant
358
- one group → KL vs reference on a calibration mix → greedy knapsack to target
359
- bpw), cheaper on the drafter because cached tapped hiddens remove the 12B
360
- from the sweep loop. TurboQuant's role is better-quant-at-EQUAL-bits (finer
361
- levels around the Gaussian peak) — a preservation instrument, measured at
362
- equal bpw before any lower rung.
363
-
364
- | phase | what | state |
365
- |---|---|---|
366
- | 0a | oracle-gate the bf16 DeepSpec port ONCE (round-for-round vs their temp-0 trace on the bf16 HF 12B; OptiQ arm acceptance-only) | open (Josh: torch venv + GPU) |
367
- | 0b | γ sweep {2,3,5,7} at conc 1 → per-γ tok/s / acceptance / TTFT table | open |
368
- | 0c | time attribution (draft GPU / draft host syncs / verify / tap+commit; paging check) — orders phases 1–3 by measured value | open |
369
- | 1a | `scripts/dspark.ts quantize` | done 2026-07-07 |
370
- | 1b | quantized forward in `deepspec-module.ts` | done 2026-07-07 |
371
- | 1c | `scripts/dspark.ts ab` — same target, same ≥32 prompts, temp 0, drafter A vs B; per-position acceptance, τ, tok/s, paired verdict (drop ≤ 3 pts AND wall-clock strictly improves); stats in `ab-stats.ts`, unit-tested | done 2026-07-07 |
372
- | 1d | RUN 4-bit vs bf16 at best-γ | open (GPU) |
373
- | 1e | measured sensitivity map (optiq's method on cached hiddens) → knapsack allocation → one confirming A/B | open |
374
- | 1.5 | OPTIONAL acceptance upside: adaptation fine-tune on OUR target's tapped hiddens (their checkpoint as init; gradient in their torch trainer vs a local path — undecided); threshold sweep at 26% (objective = tok/s, not τ); target-fidelity axis measurement | open |
375
- | 2 | tighten `Gemma4DSparkModel.draftBlock`: on-device token chaining (one host read per round), compute no confidence at threshold ≤ 0, skip unread `baseLogits`; gate = bit-identity on the synthetic checkpoint + real-checkpoint determinism | open |
376
- | 3 | `captureLayer` in the generated Gemma forwards (`scripts/gen-model.ts`) so tapped prefill/verify keep the fast path; drop the `hiddenTap !== null` fallback guard; regen 12b/26b/e4b; gate = generated-parity + tap-parity + spec bench | open (guard still present 2026-08-23) |
377
- | 4 | serving UX on 0–3 data: per-kind γ default (trained γ is the cap, not necessarily the default), quantized-drafter UX (`mlx-bun get` → quantize), spec × prompt-cache composition, surface audit (`/stats` drafter+kind+γ; server-config "speculative serving" section), the default decision per pair written down | open |
378
- | 5 | TurboQuant weight scheme for the drafter: TQ-4 vs affine-4 AT EQUAL BPW through the 1c harness (headline); lower rungs only after that is won; method (TQ vs affine) and allocation (knapsack) are orthogonal axes, never mixed within an artifact; per-tensor mixed rungs from the measured table (lm_head ~2 GB read fully per round; embed ~2 GB gather-only; markov_w2 134 MB ×7) | open |
379
- | 6 | clean-machine protocol → promote to benchmarks + default decision; close or re-defer loose ends (gated RNN head, paper Alg-1/STS, per-slot spec) | open |
380
-
381
- Exit criteria: (1) ≥ 1.3× on 12B clean-machine paired, or a written verdict
382
- that it cannot be reached and why; (2) acceptance PRESERVED and understood
383
- (the quantized drafter holds the bf16 baseline, or the mixed rung that does
384
- is adopted, or the loss is measured and accepted); (3) the
385
- acceptance-per-byte curve exists (TQ vs 4-bit vs mixed vs bf16); (4) the
386
- surface is documented, defaults decided per pair, and `mlx-bun get` →
387
- serve → speedup works without reading a design doc.
388
-
389
- ### 4.6 The 27B program (Qwen3.8, 2026-08-19)
390
-
391
- The TurboQuant-weights campaign's 17 GB Qwen3.8-27B (~11.8 tok/s decode,
392
- 2026-08-19) is the slow-target regime where τ≈3 nets 2–3×, and it retires
393
- the "27B infeasible to train on 24 GB" premise: with the quantized trunk
394
- FROZEN (inference-only taps + teacher logits) and only the ~5-layer drafter
395
- holding grads/optimizer state, drafter training fits a 32 GB machine.
396
- Verify/rollback across the 48 DeltaNet layers is proven engine behavior
397
- (§2). Two tracks, cheap-first, queued behind the certification suite's GPU
398
- ownership (PLAN.md TurboQuant-weights phase, "Queued follow-ups"):
399
-
400
- - **Track A — confidence-scheduled verification on the stock MTP head (no
401
- training).** Dynamic per-step block length: v0 confidence = the draft's
402
- own token probability, mapped through the `scripts/dspark.ts calibrate`
403
- pattern to expected acceptance; stop drafting when marginal
404
- expected-accept drops below the verify amortization point. Calibration
405
- data = thousands of (confidence, accepted?) pairs from served traffic.
406
- Gate: paired A/B tok/s vs fixed-γ MTP; lossless by construction.
407
- - **Track B — true DSpark drafter for the 27B.** The faithful v2 retargeted:
408
- tap-layer selection for the 64-layer trunk (bias toward the 16
409
- full-attention layers + post-finalNorm), data by TEACHER-FORCED passes
410
- over corpus text with the frozen trunk (every position yields a sample).
411
- Open idea: initialize/distill against the shipped MTP head. Gate:
412
- generalizing per-position acceptance must beat the MTP head's 0.68 or
413
- Track B is dropped for Track A + MTP.
414
-
415
- Drafts trained on the TQ artifact are married to its rotation basis (card
416
- note if published). `RadixArk/Qwen3.8-27B-DSpark` exists as a cross-check
417
- candidate (PLAN 14h, optional).
418
-
419
- ### 4.7 Packed 27B MTP recheck after kernel changes (2026-09-05)
420
-
421
- The M4 Pro screen uses the actual packed k300 artifact and the existing
422
- folded MTP companion from the affine flagship. Their recorded R1 seed,
423
- hidden size and R2 setting agree; the head's documented final-gamma
424
- approximation remains a draft-quality limitation. No head was downloaded,
425
- trained or changed. The target verifies every MTP proposal; this is separate
426
- from strict fill's no-verification assertions.
427
-
428
- `tests/parity/qwen38-mtp.test.ts` now supports a warm native wall-time
429
- diagnostic via `MLX_BUN_TEST_MTP_REPORT`. Target/draft path overrides select
430
- the exact pair; `MLX_BUN_TEST_MTP_GAMMA` selects 1..4. The report records
431
- both token sequences, actual completion counts, first-token and full-request
432
- wall time, speculation counters, source and artifact identity, and machine
433
- state. It does not compare differently defined decode-rate counters.
434
-
435
- Six AB/BA blocks on the short enumeration fixture compare gamma 2 on variants
436
- 6 and 8, then gamma 1/2/3/4 on variant 8. The optimized verification kernels
437
- improve MTP's economics on that fixture; gamma 4 loses when the target append
438
- crosses the packed/expanded boundary. Exact emitted-token identity holds in
439
- the observed cells. These are loaded-machine diagnostics under
440
- `reports/qwen38-rd/mtp-v*-gamma*.json`, not default-promotion evidence.
441
-
442
- A predeclared code, explanation, arithmetic, extraction, JSON and prose
443
- screen has one warm pair per prompt with alternating arm order. Four valid
444
- cases improve, while prose loses with lower draft acceptance. The extraction
445
- case ran past chat EOS and is excluded from serving comparisons. All six
446
- preserve the observed token IDs, including that invalid overrun. Reports and the frozen prompts are under
447
- `reports/qwen38-rd/mtp-corpus-screen/` and `mtp-screen-prompts.json`. The
448
- fixed output budget truncates some answers; this is not a task-quality eval.
449
- MTP remains opt-in. Repeat diverse longer sessions, include rejection/rollback
450
- cost and memory, and test a bounded adaptive policy on held-out prompts before
451
- changing that decision.
452
-
453
- The next adaptive screen stays within the existing `DraftSource` contract:
454
- start at two drafts, decrease after a partial acceptance and increase toward
455
- three only after two fully accepted rounds. Per-request state stays with the
456
- source. Keep one draft as the floor for this experiment. Qwen MTP's current
457
- `draft(n<=0)` returns without appending its pending cache row, and the
458
- zero-draft commit does not add that row. A skip/recovery policy therefore
459
- needs an explicit cache-advancement design before it can preserve the source's
460
- alignment. This is a source-audit constraint on a future policy, not a failure
461
- in the current fixed-positive-length path. Compare complete native/HTTP
462
- requests and memory against both fixed gamma and non-spec generation on new
463
- frozen prompts before retaining an adaptive policy.
464
-
465
- The subsequent three-arm serving gate freezes three new prompts and the
466
- adaptive rule before measurement. It uses the lossless interleaved packed
467
- artifact, variant 13 and shared affine dispatch, with one serial request at a
468
- time, temperature zero, seed 42, thinking disabled, no prompt/SSD cache and a
469
- 128-token budget. Six balanced-order blocks start 18 fresh servers. All exit
470
- cleanly; measured sources remain fixed. Across 126 warm/measured responses,
471
- all 84 native-versus-MTP text, prompt-count and finish-reason comparisons
472
- match. The 12 JSON completion-count differences remain in the report. Native
473
- `generateInner` counts the stopping EOS before excluding it from content;
474
- `specRunInner` excludes it from both emitted content and `generatedTokens`.
475
- Thus JSON reports 112 versus 111 despite identical response text. Compare
476
- complete wall time for that cell, not the differently counted decode rates.
477
-
478
- On the M4 Pro 24 GB, these are diagnostic medians in seconds:
479
-
480
- | Frozen prompt | Native | Fixed two drafts | Adaptive one to three drafts |
481
- |---|---:|---:|---:|
482
- | TypeScript run-length encoder | 11.912 | 6.690 | 6.483 |
483
- | Composite database index explanation | 11.914 | 7.217 | 7.062 |
484
- | Normalize three records to JSON | 10.969 | 5.968 | 5.751 |
485
-
486
- Every fixed/native, adaptive/native and adaptive/fixed complete-time pair
487
- improves. Median paired adaptive/fixed time ratios are 0.9698, 0.9782 and
488
- 0.9624 respectively. Fixed MTP also reduces observed TTFT by about 160 ms;
489
- adaptive/fixed TTFT is essentially unchanged. Median per-server peak RSS is
490
- 12,370,534,400 bytes native, 13,045,129,216 fixed and 13,029,392,384 adaptive.
491
- The adaptive source exercises widths one, two and three; its policy state is
492
- per request through the existing provider interface. The earlier broad corpus
493
- and these held-out cells still do not establish a universal MTP gain. Code
494
- and explanation stop at the token budget, so this is not a task-quality eval.
495
- Machine preflight fails on existing swap use. Fixed MTP remains opt-in and
496
- the adaptive wrapper is research-only. Raw evidence and source identities are
497
- `reports/qwen38-rd/mtp-heldout-{plan,http,http-review}.json`. The native follow-up runs both arm orders and preserves every emitted token
498
- ID in all 18 runs. Its 500 draft rounds include 78 partial-acceptance commits
499
- and all three adaptive widths. Assertions check source offsets before and
500
- after each draft and all 488 commits; all 12 sources dispose cleanly. Both
501
- JSON runs emit exactly 111 IDs on every arm, confirming the separate native
502
- EOS accounting. This is an alignment and trajectory gate, not a claim of
503
- identical cache bytes between speculative and serial computation. The first
504
- native run includes loading, so its times do not form a warm performance
505
- comparison. Evidence: `reports/qwen38-rd/mtp-heldout-native{,-review}.json`.
506
- Longer contexts, other quants and both quiet-machine gates remain open.
507
-
508
- The EOS usage discrepancy is now fixed in the speculative serving loop.
509
- It counts a stopping EOS from the initial sample, accepted draft, correction,
510
- bonus or plain-decode fallback without emitting it. A callback or token-budget
511
- stop before that position excludes the unused suffix. This follows the pinned
512
- mlx-lm `stream_generate` final `generation_tokens=n+1` accounting. Nine
513
- model-free cases reproduce seven old failures and cover both early-stop
514
- controls. All typechecks, hygiene and 1,812 model-free tests pass. The fresh
515
- three-arm HTTP gate completes 21 requests with fixed sources, clean exits and
516
- no text, prompt-count, completion-count or finish-reason differences. JSON
517
- now reports 112 tokens on every arm. This single block checks the fix; the
518
- historical timing reports retain their original counts. Evidence:
519
- `spec-token-counts-{before,after,typecheck,hygiene,model-free}.txt` and
520
- `mtp-post-eos-http{,-review}.json` under the campaign reports.
521
-
522
- An observed EOS now survives the method and serving adapters as
523
- `finishReason: "stop"`. Native and speculative loops record it explicitly;
524
- the adapters use the observed cause before their legacy count-based fallback.
525
- Tool-call and explicit text-stop handling retain precedence. The first HTTP
526
- replay exposed two additional serving overrides: at the known 112-token JSON
527
- EOS budget, it still returned `"length"`. Three regression tests reproduced
528
- those failures before the adapter fix. The final fresh replay completes all
529
- 21 requests with fixed sources, clean exits and unchanged text/counts.
530
- Native, fixed and adaptive MTP now report `"stop"` for that JSON response
531
- and `"length"` for the two genuinely budget-limited responses. All typechecks,
532
- hygiene and 1,820 model-free tests pass. The speculative tests also cover
533
- bonus EOS at the limit and early callback stops. Evidence:
534
- `spec-eos-serving-{before,after,typecheck,hygiene,model-free}.txt`, the failed
535
- `mtp-eos-budget-http{,-review}.json` gate and the passing
536
- `mtp-eos-budget-integrated-http{,-review}.json` replay.
537
-
538
- The continuous scheduler already records the terminal cause in `BatchStats`;
539
- the gateway now preserves it when returning `GenerateStats`. Two regression
540
- tests reproduce the dropped stop/length field before this correction. The
541
- expanded model-free tier passes 1,822 tests, with all typechecks and hygiene
542
- passing. Two fresh default-scheduler servers then preserve all six HTTP
543
- responses under synchronous/bounded projection evaluation. Both measured JSON
544
- responses count 112 tokens and finish with `"stop"`; every request reports
545
- the wire lane `"batched"` and increments the scheduler submission count.
546
- Sources stay fixed and both servers exit cleanly. The test seeds MLX to 42
547
- at startup and uses greedy sampling; an explicit request seed would force
548
- serial placement. The initial harness used the wrong wire enum and stopped
549
- at its routing assertion. Evidence:
550
- `spec-eos-continuous-{before,after,typecheck,hygiene,model-free}.txt`,
551
- `eos-budget-continuous-http.json` and
552
- `eos-budget-continuous-v2-http{,-review}.json`.
553
-
554
- The first draft-only quantization screen replaces the MTP head's eight dense
555
- projections with affine g64 8-bit or 4-bit matmuls. Target computation and
556
- fixed two-token verification are unchanged. Three fresh servers complete 21
557
- requests with identical response text, counts and finish reasons, fixed
558
- sources and clean exits. Relative to the dense draft, 8-bit complete time is
559
- flat on code and falls about 2% on explanation/JSON; 4-bit falls 0.92%, 3.15%
560
- and 3.06%. These are single-block diagnostics, requiring repeated pairs.
561
- Acceptance changes slightly, including an extra code verification round.
562
- The prototype retains dense buffers in every arm and adds 451/239 MB of
563
- quantized arrays, so it establishes no memory saving. Its preload explicitly
564
- disposes providers after request shutdown because normal CLI exit retains
565
- the resident provider; the initial experiment stopped on that cleanup check.
566
- Evidence: `mtp-quantized-draft-screen-http.json` and the completed
567
- `mtp-quantized-draft-screen-v2-http{,-review}.json` under campaign reports.
568
-
569
- The six-block repeat completes 126 requests across 18 fresh servers with
570
- all 84 paired response comparisons identical, fixed sources, clean exits
571
- and explicit provider disposal. Median paired request wall time with the
572
- 4-bit draft falls 1.45% on code, 3.09% on explanation and 2.03% on JSON,
573
- with six/five/four improving pairs. The 8-bit reductions are 0.34%, 2.16%
574
- and 2.07%, with six/six/five improving pairs. TTFT is approximately flat.
575
- The retained dense buffers mean sampled RSS remains unsuitable evidence
576
- for the benefit of removing those weights. Quantized on-disk artifacts and
577
- their actual loader/serving/memory gates are next; broader prompts, quants
578
- and quiet acceptance remain. Evidence:
579
- `mtp-quantized-draft-repeat-http{,-review}.json`.
580
-
581
- The existing atomic CPU converter produces separate folded 4-bit and 8-bit
582
- MTP artifacts with 238,930,944 and 451,267,584 tensor bytes, respectively.
583
- Both retain all seven dense norm tensors and quantize exactly eight matrices.
584
- The 4-bit artifact fails the initial comparison against GPU quantization,
585
- but all 31 saved tensors match fresh CPU quantization or source passthrough.
586
- CPU/GPU results differ in 16 quantized tensors, totaling 810,927 differing
587
- bytes. The pinned Python oracle reproduces Bun's CPU and GPU hashes for all
588
- three fc tensors, and the original companion files are unchanged. MLX 0.31.2
589
- uses `std::rint` in the CPU affine quantizer and `round` in Metal; these
590
- artifacts therefore require fresh serving/acceptance gates rather than
591
- inheriting the GPU prototype's results. The 8-bit artifact passes all 31 CPU
592
- comparisons, with fixed sources and zero active allocation after cleanup.
593
- The provider now loads companion projections through the existing
594
- `QuantizedLinear` when scales are present and retains dense projection
595
- behavior otherwise. Its resource stack continues to own dense transpose
596
- views; quantized companions retain no dense matrices. No draft policy or
597
- target verification changes. The loader and initial serving/memory gates
598
- pass below. Evidence: `mtp-draft-artifact-q4-{build,audit}.json`,
599
- `mtp-draft-quant-oracle.json` and `mtp-draft-artifact-q8-build.json`.
600
-
601
- The integrated loader passes all three typechecks, hygiene and the existing
602
- 1,822-test model-free suite. Its ownership file also passes a new malformed
603
- quantization-metadata case after earlier dense projections have loaded.
604
- Nine materialized provider cycles cover dense/8-bit/4-bit heads three times
605
- each. Loaded allocation is exactly 849,398,784/451,267,584/238,930,944 bytes,
606
- and every cycle returns to its initial zero active allocation after repeated
607
- disposal, without GC. The initial ownership helper read the counter before
608
- lazy weight materialization and failed its coverage assertion at zero/zero;
609
- it did not reproduce a leak. These are companion allocation measurements,
610
- not complete-server RSS. The additional typecheck after the new ownership
611
- case also passes. Evidence: `mtp-quantized-loader-{typecheck,hygiene,model-free}.txt`,
612
- `mtp-quantized-loader-typecheck-v2.txt`,
613
- `mtp-quantized-loader-ownership-tests-v2.txt` and
614
- `mtp-artifact-ownership{,-v2}.json`.
615
-
616
- The saved-artifact HTTP screen completes 21 responses across three fresh
617
- servers. All 14 dense-versus-quantized comparisons preserve text, prompt and
618
- completion counts, and finish reasons. Sources remain fixed; all servers exit
619
- cleanly. Observation confirms dense projections only in the dense arm and
620
- quantized projections only in the smaller arms. Explicit provider disposal
621
- releases exactly each companion's tensor allocation and reaches the same
622
- 11,936,569,478-byte resident-target baseline. This proves the smaller heads
623
- load without retained dense matrices. Both quantized heads need one extra
624
- target call on the code prompt, so cheaper projections do not guarantee a
625
- faster request. Six balanced repeat blocks and instrumented native replay
626
- are the next gates. Evidence: `mtp-artifact-screen-http{,-review}.json`.
627
-
628
- Six balanced saved-artifact blocks then complete 126 responses from 18 fresh
629
- servers, with all 84 paired text/count/finish comparisons exact, fixed sources
630
- and clean exits. On the M4 Pro 24 GB, median paired complete-time changes
631
- for code/explanation/JSON are -1.48/-3.67/-2.95% for the 4-bit companion and
632
- -0.65/-2.29/-1.86% for 8-bit. The 4-bit arm wins 5/6, 6/6 and 5/6 pairs;
633
- 8-bit wins all six pairs per fixture. TTFT is approximately flat. Median
634
- per-server peak RSS is 13,036,756,992 bytes dense, 12,740,034,560 bytes 8-bit
635
- and 12,531,777,536 bytes 4-bit. Unlike the earlier GPU projection prototype,
636
- these arms actually replace the dense companion tensors. Every explicit
637
- provider disposal releases exactly its companion's allocation to the same
638
- resident-target baseline. Existing system swap prevents canonical benchmark
639
- claims. Instrumented native token/logit/state checks, broader contexts/quants,
640
- pressure and quiet-machine acceptance remain. Evidence:
641
- `mtp-artifact-repeat-http{,-review}.json`.
642
-
643
- The subsequent native audit runs all three saved companions against the same
644
- full-prefill native generation on each short fixture. All nine emitted-ID,
645
- usage and terminal-cause comparisons pass. For every verification window,
646
- it clones the incoming target state and replays the same tokens individually
647
- with the same hidden taps. All 1,184 complete vocabulary-logit rows across
648
- 395 windows match byte-for-byte. At the first three and every sixteenth
649
- window per request, every live attention and recurrent cache array also
650
- matches, covering 48 complete state samples. All 386 commits, including 58
651
- partial accepts, preserve the source position; all nine sources dispose.
652
- Three fresh children exit cleanly with fixed sources and the same 16,390-byte
653
- post-model-disposal active counter. This is instrumented correctness evidence,
654
- not a timing result. Longer fixtures and other quants remain separate gates.
655
- Evidence: `mtp-artifact-native{,-review}.json`.
656
-
657
- Two new warehouse-ledger fixtures extend that audit to 688 and 1,968 prompt
658
- tokens, using matching 2,048-token full-prefill chunks. Dense, 8-bit and 4-bit
659
- companions preserve all six native/MTP ID, count and finish comparisons.
660
- All 180 vocabulary-logit rows and 18 sampled complete cache states match;
661
- 54 fully accepted commits preserve position. All twelve native/MTP outputs
662
- are valid JSON and contain the independently computed requested records.
663
- Each response counts 30 generation tokens. Sources stay fixed, all three
664
- children exit cleanly and each leaves the same 16,390-byte active counter.
665
- This extends correctness coverage; long serving pressure and other quants
666
- remain open. Evidence: `mtp-artifact-native-context{,-review}.json`.
667
-
668
- The matching saved-companion HTTP screen completes 15 warm/measured responses
669
- from three fresh servers at those two context lengths. All ten paired
670
- text/count/finish comparisons match, with fixed sources and clean exits.
671
- Both measured fixtures stop at 30 generation tokens. Dense and quantized
672
- projection counts and explicit provider release pass on every arm. This is
673
- one serving screen, not a repeated performance or long-agent pressure claim.
674
- Evidence: `mtp-artifact-context-screen-http.json`.
675
-
676
- Matched-prefill timing screens now separate native tail-split, native full
677
- prefill and dense fixed-two MTP in fresh HTTP servers. All 21 packed responses
678
- preserve text/count/finish across the three arms. The RTN4 screen also completes
679
- 21 responses; MTP matches native full-prefill throughout, while the two measured
680
- code/explanation tail-split responses retain their known text differences.
681
- Both screens have fixed sources and clean exits. On the M4 Pro 24 GB, complete
682
- MTP request times improve 38.8–44.0% on packed and 27.6–38.1% on RTN4 relative
683
- to native full-prefill. Each is one block, pending balanced repeats. MTP's
684
- remaining TTFT advantage motivates checking native work before the first yield;
685
- its decode loop constructs the next step before emitting the current token.
686
- No default prefill policy changes. Evidence:
687
- `mtp-matched-prefill-{r6,rtn4}-screen-http{,-review}.json`.
688
-
689
- The packed matched-prefill repeat completes six balanced three-arm blocks,
690
- 18 servers and 126 warm/measured responses. All text, token counts and finish
691
- reasons match across native tail-split, native full-prefill and fixed-two
692
- MTP. Sources stay fixed and all servers exit cleanly. Against native full
693
- prefill on the M4 Pro 24 GB, MTP changes median paired complete request time
694
- by -43.22% for code, -38.81% for explanation and -44.92% for JSON. Every pair
695
- improves. Corresponding TTFT changes are -7.36/-8.42/-5.47%. Median paired
696
- peak server RSS rises by 684,335,104 bytes, about 653 MiB; this samples startup
697
- and the whole request sequence, not each fixture's physical-memory demand.
698
- Native tail-split adds roughly 0.77–0.86% complete time and 7.37–10.46% TTFT
699
- relative to native full-prefill. Existing swap and background CPU activity
700
- in the final block keep these results diagnostic. All samples are retained.
701
- Broader workloads and quiet acceptance remain.
702
- Evidence: `mtp-matched-prefill-r6-repeat{,-review}.json`.
703
-
704
- The RTN4 repeat also completes six balanced blocks, 18 servers and 126
705
- responses with fixed sources and clean exits. MTP and native full-prefill
706
- match all text/count/finish comparisons. Native tail-split retains the code
707
- and explanation differences in every block. Relative to native full-prefill
708
- on the M4 Pro 24 GB, median paired MTP complete-time changes are -34.95% for
709
- code, -26.95% for explanation and -38.48% for JSON. Code and explanation
710
- improve in five of six pairs; JSON improves in all six. Median paired sampled
711
- peak server RSS rises by 850,173,952 bytes, about 811 MiB. The losing block
712
- overlaps another application's TypeScript and Playwright work, followed by
713
- system indexing and increased swap. Retain that block and the other samples;
714
- these diagnostic medians do not substitute for quiet acceptance. Evidence:
715
- `mtp-matched-prefill-rtn4-repeat{,-review}.json`.
716
-
717
- The RTN4 cross-quant screen uses its unrotated target and the original
718
- unrotated mlx-community MTP head, with the same three held-out prompts and
719
- fixed/adaptive policies. All three servers exit cleanly with fixed sources.
720
- Usage counts and finish reasons match, but both MTP arms differ from native
721
- on the measured code and explanation responses. Those timings do not establish
722
- identical-work speedups. The JSON response matches at 117 counted tokens;
723
- its single-block complete times are 8.292/5.042/4.776 seconds for native,
724
- fixed and adaptive MTP. Repeated timing and a first-divergence audit remain.
725
- Keep the packed result specific to its tested artifact and prompts. Evidence:
726
- `mtp-rtn4-screen-{plan,http,http-review}.json` under the campaign reports.
727
-
728
- The RTN4 native follow-up reproduces code/explanation divergence at emitted
729
- token indices 48/26 with seed 42 and greedy sampling. For each of 140 target
730
- verification windows, it clones the pre-forward cache and replays the same
731
- IDs through serial M1 forwards with the same hidden taps. All 420 projected
732
- logit rows have identical values, and all cache offsets agree. Instrumented
733
- MTP preserves the uninstrumented emitted IDs on all three fixtures. Thus a
734
- local verification-window arithmetic difference does not explain these
735
- responses. Native tail-split versus MTP full-prompt prefill and state
736
- accumulation require separate controls.
737
- Sources remain fixed. Evidence: `mtp-rtn4-divergence-v2-audit{,-review}.json`.
738
-
739
- Two fresh processes isolate the prefill choice using the existing
740
- `MLX_BUN_PREFILL_TAIL_SPLIT` setting. Native traces show 57+1, 53+1 and 91+1
741
- prompt forwards with splitting, versus 58, 54 and 92 without it. MTP uses
742
- full-prompt prefill in both processes. With splitting enabled, the earlier
743
- code/explanation token differences recur. With splitting disabled, every
744
- native emitted ID matches MTP on all three fixtures; MTP itself is unchanged
745
- across processes. Counts are 128/128/117 including JSON EOS. Both children
746
- exit cleanly and all source hashes stay fixed. This isolates the observed
747
- trajectory differences to the native prefill policy for these fixtures.
748
- Retain the original failed comparisons and add a native full-prefill arm
749
- when measuring MTP, so prefill savings and drafting savings are distinct.
750
- Changing that policy still needs its own oracle/quality gates. Evidence:
751
- `mtp-rtn4-prefill-control{,-review}.json` under the campaign reports.
752
-
753
- Variant 10 further shares small-M scatter work. Six warm AB/BA blocks at
754
- gamma 2 and 3 on both enumeration and the earlier losing prose prompt now
755
- retain an observed wall-time gain with identical token IDs. Enumeration
756
- prefers gamma 3; prose prefers gamma 2. This changes the measured cost of
757
- verification, not the recorded acceptance sequences. The reports are
758
- `reports/qwen38-rd/mtp-v10-{planets,prose}-gamma{2,3}.json`. These repeated
759
- fixtures are still diagnostic, with no general workload or quiet-machine
760
- verdict. Native request rows are recorded in the eval DB under
761
- `mlx-bun-native-diagnostic`, which does not replace the status page's
762
- ordinary inference measurements.
763
-
764
- The native MTP test now also uses the server's config-plus-tokenizer EOS set
765
- and records it. The repeated variant-10 enumeration/prose cells contain no
766
- additional EOS ID within their fixed budget, so that correction does not
767
- truncate those sequences. The broader corpus audit found chat-EOS overrun
768
- in extraction only. Its two DB rows and the old strict-fill rows now carry
769
- explicit exclusion notes; corrected strict-fill reports are recorded separately.
770
-
771
- The provider-lifetime audit found a separate cleanup bug. The Qwen provider's
772
- old no-op `dispose()` assumed process-lifetime mapped weights, but `Weights`
773
- now owns native MLX maps and each dense projection also retains a transpose
774
- view. Three bounded load/use/source-dispose/provider-dispose cycles retained
775
- 849,398,784 additional MLX bytes each, including after garbage collection.
776
- The provider now owns a `DisposableStack`: weight-map cleanup is registered
777
- first, then each derived transpose view, so disposal releases views before
778
- maps. The same scope unwinds a partially constructed module. Disposal is
779
- idempotent and opening a source after provider disposal is rejected. The
780
- caller closes active request sources before unloading their provider, as for
781
- the other providers. Inference operations and their ordering are unchanged.
782
-
783
- The real 27B MTP-head probe returns active MLX memory to zero after each of
784
- three cycles, before GC. Model-free tests also cover map/view release, repeat
785
- disposal and failure at the final norm after earlier views have been created.
786
- Evidence: `reports/qwen38-rd/mtp-provider-dispose-{before,after}.json` and
787
- `mtp-provider-ownership-tests.txt`. All three typechecks, hygiene and the full
788
- model-free tier pass: 1,803 tests, 10 skips and no failures. The post-change serving
789
- gate completes all three native/fixed/adaptive servers with clean exits and
790
- matching response text on the frozen requests. Only the previously documented
791
- JSON EOS-count difference remains; sources stay fixed. Evidence:
792
- `reports/qwen38-rd/mtp-post-dispose-http.json`. This addresses drafter unload/replacement;
793
- it is separate from the already-fixed target-cache disposal and admission work.
794
-
795
- ### 4.8 Paired Qwen MTP conversation state
796
-
797
- `DraftSource.checkpoint` supplies the method's companion state. Qwen captures
798
- draft KV and the preceding target hidden row; the executor pairs these with
799
- target KV/recurrent state and exact processed token IDs in the shared cache.
800
- Restore requires an exact prefix under the same compatibility namespace.
801
- RAM hits lend immutable views and preserve the donor. Reuse never trims
802
- recurrent state to an arbitrary common prefix.
803
-
804
- The MTP cache is one position behind the target at a prefill boundary. Extending
805
- it first pairs the next incoming token with the saved preceding hidden row,
806
- then processes the remaining suffix. Future generation cannot alter the retained
807
- prefix. The working-tree migration removes the provider's private store and
808
- separate budget. All tensors use the existing RAM budget, eviction and SSD
809
- queue. Native bf16/KV4 tests pass on M1 Max and M4 Pro through repeated RAM
810
- reuse and SSD cache/provider restart. Completed generated-state publication
811
- and matched performance remain open. Storage and identity details live in
812
- [kv-cache method companion state](kv-cache.md#method-companion-state).
813
-
814
- `DraftProvider.grouped` now opens method-owned row state using the same
815
- companion checkpoint format. Its sampler is injected; the provider retains
816
- weights while the group owns draft KV and hidden rows. Prepared requests can
817
- join, retire, reorder, drain and rejoin without exposing tensor layouts to
818
- scheduling or introducing another cache store. Capture and membership changes
819
- occur between committed rounds. The request source and group share Qwen's
820
- attachment encoding and restoration.
821
-
822
- The provider interface is adopted in the working tree after bf16/KV4/KV8
823
- full-round controls at B=1/2/4 on both Macs, including rebuilt checkpoints,
824
- SSD restart continuations and both complete model-free suites. Extraction
825
- removes padding, so the continuation control also rebuilds its raw state to
826
- match attention geometry. The initial M4 comparison against retained padding
827
- changed subsequent draft KV despite matching tokens and target state; that
828
- result is retained. These are internal refactor controls. Coordinated
829
- target/draft admission now uses staged state publication, described in
830
- batching §7. Source
831
- identity and raw checks are in the composition-baseline reports under
832
- `mtp-provider-group-manifest.json`.
833
-
834
-
835
- The isolated serving candidate adds method preparation and advancement to the
836
- existing execution group. The scheduler retains its queue, execution lease and
837
- admission policy; the method owns target/draft state, acceptance and sampling.
838
- The gateway asks the binding for its supported grouped methods and forwards
839
- output metadata and speculative usage. No second MTP scheduler is introduced.
840
- Its real KV4 HTTP test passes on M1 Max and M4 Pro: four submitted requests
841
- reach a target verification graph with shape B=4, each returns seeded samples
842
- and logprobs, and the group drains. B=1 token and acceptance checks compare
843
- against the existing request producer. Callback-stop, failure, cancellation,
844
- EOS and shared RAM-prefix checks are included in the extended native gate.
845
- Mixed HTTP checks on both Macs compose structured JSON, seeded sampling and
846
- logprobs with ordinary requests in the same MTP group. Shared-method SSD
847
- restart preserves target/draft state, tokens and acceptance traces on both.
848
- An extended M1 native check also admits a shorter-lived request with a different
849
- prompt length while another request is decoding, then repeats the same schedule
850
- with matching outputs. Admission now publishes target state, draft state and
851
- executor membership together before releasing superseded state. A reproduced
852
- cleanup failure formerly left a rejected row active; the admission failure
853
- handler now retires that row before another method round. The candidate remains
854
- isolated pending complete composition and paired performance acceptance.
855
- Timing results and their limits live in benchmarks.md. Evidence:
856
- `reports/qwen38-closeout/composition-baseline/mtp-serving-method-manifest.json`.
857
-
858
- For the original private-cache candidate, the M4 Pro unit gate passed 18 tests. Native prompts at 128, 513 and
859
- 2,051 tokens pass six restore checks with unchanged state hashes, token IDs
860
- and acceptance traces; repeated allocation is stable at each length. The HTTP
861
- gate completes eight responses with identical text, token counts and finish
862
- reasons across uncached and cached MTP policies, including repeated cache hits.
863
- The native restore check also passes with Luke's coding sampling recipe,
864
- temperature 0.6, top-p 0.95, top-k 20 and seed 42: six unchanged state restores
865
- and exact repeated continuations. Evidence: `mtp-prefix-luke-sampling.json`.
866
- These gates establish the initial composition, not complete long-task speed or
867
- pressure acceptance. The fresh thinking-off Pi task reused saved prefixes and
868
- finished generation without compaction, but its generated app failed acceptance.
869
- The task disposition and next frozen configuration are in decode-speed-program
870
- section 7.7. Raw evidence: `reports/qwen38-rd/mtp-cache-candidate-native.json` and
871
- `reports/qwen38-rd/mtp-cache-http-gate.json`.
872
-
873
- ## 5. Files
874
-
875
- - `src/spec/source.ts` — the seam. `src/spec/serve-loop.ts` — the executor.
876
- - Sources: `two-model.ts`, `assistant-source.ts` (+ `drafter.ts`),
877
- `dflash-source.ts`, `deepspec-source.ts`, `ngram-source.ts`,
878
- `qwen-mtp-source.ts`, `glm52-mtp-source.ts`.
879
- - `src/spec/generate.ts` — the standalone optiq-oracled assistant loop
880
- (`specGenerate`, full-prompt prefill, throws on ring wrap).
881
- - `src/spec/dspark/`: `module-dflash.ts` (our module), `deepspec-module.ts`
882
- (DeepSeek's), `loader.ts`, `data-dflash.ts`, `generate-dflash.ts`,
883
- `loss.ts`, `sample.ts`, `calibration.ts`, `quantize-drafter.ts`,
884
- `ab-stats.ts`; `module.ts`/`data.ts`/`generate.ts` = v1 baseline (refused
885
- for serving).
886
- - `src/model/gemma4.ts` `hiddenTap`/`captureLayer`; `src/model/qwen3_5.ts`
887
- `hiddenTap`; `src/model/gemma4-base.ts` `Cache` (`trim(n, bypass)`, the
888
- spec-round trio); `src/model/qwen3-delta.ts` `SSMCache.specRound*`.
889
- - `src/server.ts` `detectDraftKind` / `loadContext` (provider selection, γ
890
- pinning, tokenizer probe, fail-fast pairing probe-open, admission).
891
- - `scripts/dspark.ts <train|regen|calibrate|quantize|ab>` — the DSpark
892
- pipeline (one dispatcher, jobs in `scripts/dspark/`):
893
- ```
894
- bun scripts/dspark.ts regen --topics <topics.txt> --out <data> --max-resp 320
895
- bun scripts/dspark.ts train --data <data> --out <ckpt> --iters 8000 --batch 8 [--resume] [--ddraft 2560] [--seq-head rnn]
896
- bun scripts/dspark.ts calibrate --drafter <ckpt> --data <prompts.jsonl>
897
- bun scripts/dspark.ts quantize <drafter-dir> [--out <dir>] [--bits 4|8] [--group-size 32|64]
898
- bun scripts/dspark.ts ab --target <id|dir> --drafter-a <dir> --drafter-b <dir> [--num-draft-tokens N] [--n-prompts 32] [--max-drop 3]
899
- ```
900
- (The standalone measure/compare/bench one-offs — `dspark-measure-dflash`,
901
- `dspark-deepspec-compare`, `spec-bench`, `spec-dump`, `qwen38-mtp-ab` —
902
- were deleted 2026-08-23; git history.)
903
- - Oracles: `scripts/oracle/oracle-spec.py` (optiq spec_generate),
904
- `scripts/oracle/oracle-dspark-deepspec.py` (DeepSpec temp-0 trace),
905
- `scripts/oracle/oracle-qwen38-mtp-logits.py` (mlx-vlm drafter logits).
906
- - Tests: `spec-decode.test.ts` (e4b assistant, exact + knife-edge),
907
- `spec-decode-12b.test.ts` (long-prefix rollback gate), `spec-serve.test.ts`
908
- (L1 knife-edge, grammar × spec), `spec-serve-assistant.test.ts`,
909
- `spec-ngram.test.ts`, `qwen35-spec-ngram.test.ts`,
910
- `qwen-ssm-specround.test.ts`, `qwen38-mtp.test.ts` (opt-in),
911
- `dspark-{smoke,infer-loop,rnn,calibration,deepspec,ab-stats}.test.ts`.
912
- - User-facing mirror: docs/reference/server-config.md (`--draft-model`,
913
- `--draft-kind`, `--num-draft-tokens`, `--ngram-*`, `--mtp`,
914
- `MLX_BUN_PREFILL_TAIL_SPLIT`, `MLX_BUN_DSPARK_MINCONF`), cli.md,
915
- docs/reference/server-config.md.
916
-
917
- ## 6. Composition rules (as served)
918
-
919
- - Method selection precedes placement. Qualified Qwen MTP uses grouped
920
- target/draft state, sampling and checkpoint interfaces in the shared
921
- executor. Other draft providers still use the serial verifier.
922
- - KV policy stays with the request. Shared Qwen MTP supports bf16 and
923
- start-zero uniform KV4/KV8/TurboQuant. Unsupported compositions select
924
- ordinary decoding. Current defaults and qualifications live in server-config.md.
925
- - Structured output composes (the constrained verify walk).
926
- - Qwen MTP prefill state uses the shared RAM/SSD cache. The source supplies
927
- draft KV and the pending hidden row through its checkpoint interface;
928
- the cache owns retention and persistence. Other speculative sources still
929
- begin with fresh state until they supply a checkpoint codec. Generated-output
930
- capture remains R17 work.
931
- - Native GLM MTP and an explicit `--draft-model`/`--draft-kind` are mutually
932
- exclusive; one provider per request so two draft histories never advance
933
- target or grammar state twice.
934
-
935
- ## 7. Token fast-forwarding — lookup, not speculation
936
-
937
- **No draft/verify contract is involved.** Nothing in this section routes
938
- through `src/spec/`; there is no drafter, no verify forward, no rollback, and
939
- no comparison against what the model "would have" produced. It is filed here
940
- only because the spec lane is the neighbouring mechanism and the two are
941
- routinely confused. The one fact borrowed from it is that a multi-token
942
- mid-decode append works — which the grammar jump-forward burst already proved.
943
-
944
- **The doctrine.** A transformer is a next-token function over a token
945
- sequence. It has no memory of who wrote which token, so an APPENDED token is
946
- indistinguishable from a sampled one: injection is pure context extension. When
947
- the engine already knows the next *m* tokens, consulting the model for them
948
- buys nothing — it writes them into the KV itself with ONE chunked forward and
949
- resumes sampling after them. The model is consulted only for tokens it does
950
- not already know.
951
-
952
- **What "already knows" means in the strict tier.** A request's
953
- `tools` array plus the model's own chat template determine large parts of the
954
- assistant turn: the tool-call opening scaffold, the remainder of a tool name
955
- after its first disambiguating token, the punctuation from the name to the
956
- arguments object, and — when the schema has exactly one required property —
957
- the argument key itself. Those spans are compiled per request by **scaffold
958
- probing**: render the same conversation several ways, tokenize each, and diff
959
- the token id sequences. What does not change is the template's fixed scaffold,
960
- by construction. The compiler knows nothing about tool-call syntax: Qwen3.5's
961
- `<function=NAME>`/`<parameter=KEY>` XML, a JSON `<tool_call>` template, and
962
- GLM's `<arg_key>`/`<arg_value>` all compile through the same diff, and a
963
- template that does not render `tool_calls` (or renders them without the name)
964
- produces identical probes, an empty diff, and no rows — degrade to no-fill,
965
- never wrong output. Same technique as `request-prep.ts::stableLenFor` uses on
966
- the generation primer, applied to the assistant turn.
967
-
968
- **Serialization and state invariants.**
969
- - **Every span is sliced from a rendering the model could actually produce** —
970
- real tool names, real schema keys. The diff only decides WHERE to cut; the
971
- ids always come from the real-name rendering, so every cut is a token
972
- boundary of a producible stream. This is not a stylistic preference. Qwen3.5
973
- renders `<function=get_weather>`, which the tokenizer encodes as
974
- `< function =get _weather >` — `=get` is ONE token. A probe named
975
- `zzalphatoolqq` splits the same position as `… = zzalpha…`, inventing a
976
- boundary after `=`. A scaffold row cut there injects a bare `=`, the model
977
- then emits `get` where it would have emitted `=get`, and the result is
978
- byte-identical TEXT over divergent token IDS — with KV that no longer
979
- matches what a plain decode would have written. Caught on Qwen3.5-0.8B
980
- (2026-08-31); the regression gate is id containment, not text containment
981
- (`tests/unit/fill-schema-rows.test.ts`, `tests/parity/fill-strict.test.ts`).
982
- With one tool the whole header through the sole key is one span; with
983
- several, the scaffold ends exactly where the real merged name tokens diverge
984
- (`=get` vs `=search`) and per-tool name rows resume from there.
985
- - Never `encode(fragment)` in isolation — same reason.
986
- - Every row is anchored at a token carrying LETTERS (e.g. `<tool_call>`,
987
- `</parameter`), with leading template-join whitespace dropped from the
988
- trigger. Markup alone is not enough: `</` opens every closing tag a model
989
- might write in prose or a code block, so arming on it would inject tool-call
990
- markup into an HTML snippet.
991
- - A close row exists only when EVERY tool in the request takes exactly one
992
- required argument — otherwise the model may still be about to write a second
993
- `<parameter=…>`, and injecting the close would silently drop it. The
994
- request's own schema decides whether the row exists.
995
- - Ending the turn stays the model's decision: every span is cut at the first
996
- EOS id (the grammar jump burst's missing EOS check is deliberately not
997
- inherited).
998
- - A span shorter than 2 ids is rejected — it would save no forward.
999
- - The cache-alignment invariant: the fill forward carries ONLY the injected
1000
- ids. The normal step already consumed the trigger token and wrote its KV;
1001
- forwarding `[trigger, ...ids]` would duplicate a position and silently
1002
- corrupt both the KV and `PromptCache.put`'s key. `MLX_BUN_FILL_TRACE=1`
1003
- asserts `cache[0].offset === promptTokens.length + forwarded.length` on both
1004
- sides of every append.
1005
- - Injected tokens flow through `CompletionSink.push` one at a time, in the
1006
- same shape as the jump burst, so `StopMatcher` fires mid-burst exactly where
1007
- it would have. The append happens BEFORE any of the burst's yields, which is
1008
- what makes a consumer break mid-burst safe — `forwarded` already describes
1009
- the cache exactly.
1010
-
1011
- **The deviation, stated plainly.** Injection bypasses the sampler. At
1012
- `temperature > 0` a filled reply is not the same draw an unfilled one would
1013
- have been (the sampler is never asked about those positions). That is a
1014
- behavior-policy deviation, not a numerics one, and it is why the feature is
1015
- opt-in (`MLX_BUN_FILL=strict`, default off). At `temperature 0` the strict
1016
- tier must demonstrate token identity against ordinary generation. A fixed
1017
- template serialization does not prove that the unconstrained model chooses
1018
- it. The weights gate is `tests/parity/fill-strict.test.ts`; section 7.4 states
1019
- the stronger contract needed for a claim of guaranteed deterministic replay.
1020
-
1021
- **Mechanism.** `src/generate.ts::generateInner` — the same burst shape as the
1022
- grammar `jumpEmit` branch, with the DEFERRED trigger (fill reads the token the
1023
- pipelined loop already read back; it does not add grammar's eager readback).
1024
- On an ASSERT fill the in-flight sample for the next position is dropped
1025
- unexamined — a discarded pipeline dispatch, counted as `wastedSamples`, not a
1026
- rejected draft. Grammar and fill are forbidden in the same iteration
1027
- (asserted).
1028
-
1029
- ### 7.1 One interface, two policies (`src/fill/proposal.ts`)
1030
-
1031
- Every source that can propose the next tokens implements one interface, and
1032
- one apply primitive in the decode loop hosts both policies — because the
1033
- EXPENSIVE half is identical: one chunked forward advancing the KV (and the
1034
- recurrent SSM state) over the whole span.
1035
-
1036
- ```ts
1037
- interface ProposalSource { propose(tail: TokenView): Proposal | null }
1038
- interface Proposal { ids: number[]; policy: "assert" | "verify"; origin: … }
1039
- ```
1040
-
1041
- - **assert** — the tokens are DETERMINED (a template scaffold). Append and move
1042
- on: no readback, no checkpoint, no rewind. Strict rows are always assert.
1043
- - **verify** — the tokens are LIKELY (a session self-copy). Position 0 is
1044
- checked BEFORE the forward against the in-flight sample — free, and a
1045
- mismatch costs nothing because nothing has been written yet. Positions
1046
- 1..m−1 are checked against the argmax already sitting in THAT SAME forward's
1047
- logits, so verification adds no pass over the weights. The rejected tail is
1048
- rewound and decode resumes at the first disagreement, which reproduces
1049
- exactly the stream an unfilled run would have produced. A wrong guess costs
1050
- a rewound forward, never a wrong token.
1051
-
1052
- **Rewind reuses the spec lane's cache contract, not its executor.** Trimmable
1053
- caches drop the tail with `trim(n)`; NON-trimmable recurrent caches (SSMCache —
1054
- gated-DeltaNet conv + recurrent state) go through `specRoundBegin()` before the
1055
- forward and `specRoundRollback(keep)` after the accept walk, which restores the
1056
- pre-round snapshot and bit-exactly REPLAYS the accepted prefix (§2). Those are
1057
- plain `Cache`-interface methods driven by the owning layer, so nothing in
1058
- `src/spec/serve-loop.ts` is touched. A model whose caches can do neither still
1059
- gets assert fills; verify proposals are dropped and counted
1060
- (`usage.fill.verifyUnsupported`). Checkpointing is real work (~48 DeltaNet
1061
- states on Qwen3.8) and is measured: `usage.fill.checkpointMs`.
1062
-
1063
- **Remaining fill integration.** Prompt lookup, Qwen MTP and standalone
1064
- drafting now share the grouped method lifecycle at B1/B>1 for qualified
1065
- target layouts (see batching.md). DSpark and other provider migrations remain.
1066
- Unifying fill proposals with draft proposals through one apply primitive is
1067
- still open; the existing fill implementation retains its cache transaction
1068
- contract while that method composition is qualified.
1069
-
1070
- ### 7.2 The echo tier (K3c, Lab, `MLX_BUN_FILL=echo`)
1071
-
1072
- A growing per-request k-gram index over promptIds plus everything emitted
1073
- (injected tokens included — the model cannot tell them apart, so neither does
1074
- the index). The structure is the TS port of `GrowingMatcher` from the corpus
1075
- study: sequence + k-gram → positions, appended incrementally, bucket scan
1076
- capped at the NEAREST occurrences (`src/fill/echo-index.ts`).
1077
-
1078
- The lookup is the boring half. The **stopping rule** is the measurement that
1079
- made the tier worth building:
1080
-
1081
- - **Branch-point stopping.** A match says where this context occurred before;
1082
- it says nothing about how far the future agrees with the past. So a span
1083
- extends only while EVERY nearby occurrence continues the same way, and stops
1084
- the moment they disagree. That fork is exactly where old-query-vs-new-query
1085
- divergence lives, and delimiters fall out for free — a closing quote is where
1086
- histories fork.
1087
- - **Corroboration decides the policy.** `assert` requires (a) no branch stop,
1088
- (b) the span ends at a delimiter-class token, AND (c) at least TWO
1089
- occurrences agreed across the whole span. A single occurrence is a copy, not
1090
- a pattern: it will happily replay whatever followed it in the transcript —
1091
- including another role's turn — so it is the model's call. Verified on the
1092
- 0.8B tokenizer against a synthetic agent transcript: an uncorroborated copy
1093
- ran 30 tokens past `</tool_call>` into a mocked tool RESULT. Under verify
1094
- that costs one rewound forward; under assert it would have been wrong
1095
- output. Everything else is `verify`.
1096
- - **Delimiters** are read off the template by the strict-row compiler (the
1097
- first non-whitespace token that follows an argument value — `"` for JSON,
1098
- `</` for Qwen3.5's XML). They clamp ECHO spans only: a strict scaffold
1099
- legitimately contains the same tokens as structure (`{"name": "` is three
1100
- quotes deep) and is determined by construction.
1101
-
1102
- Deterministic value transforms (url-encode, JSON-escape) as
1103
- `(source-span, transform)` table entries are NOT implemented — the seam is the
1104
- same `ProposalSource` interface, and the corpus rates that motivate them are in
1105
- PLAN K3.
1106
-
1107
- The bar for this tier is NOT token identity (sampling never guaranteed that):
1108
- it is a paired A/B on task success and wall clock over mocked-replay agent
1109
- sessions. Default off until that lands.
1110
-
1111
- **Composition.** Strict fill has serial and shared methods. Shared fill keeps
1112
- request-local sampler history and absolute seeded positions while using the
1113
- same preparation and encoded-row interfaces as other methods. Echo verification
1114
- remains an explicit serial operation. Grammar, probability metadata, media,
1115
- mounted drafting, paging and interrupted-generation checkpoints remain separate
1116
- compositions. Quantized committed append is supported by the qualified model
1117
- bindings described below; quantized echo verification remains inactive.
1118
-
1119
- **Mismatch policy.** If `parseGeneratedToolCalls` rejects the emitted markup
1120
- on a request whose rows fired, `usage.fill.parseFallback` increments and
1121
- strict rows disarm. Today the served parse runs at sink flush, i.e. after the
1122
- generation ends, so within one request this is telemetry; the seam is wired so
1123
- an incremental parse (or a plan cached across requests) disarms for real.
1124
-
1125
- ### 7.3 Measuring it (K3d, `scripts/fill.ts`)
1126
-
1127
- Neither tier ships on a vibe. The harness replays RECORDED agent sessions with
1128
- their tool results mocked verbatim from the JSONL — the transcript IS the
1129
- environment, a model cannot tell an executed result from a recorded one — so a
1130
- whole corpus replays deterministically and side-effect-free. The session reader
1131
- is a straight port of the corpus study's (`reports/k3-replication/analyze.py`
1132
- `load_session` / `serialize_tool_call`), including its `excludeFromContext` rule
1133
- and corrupt-line tolerance, so the measured rates in PLAN K3 keep describing
1134
- what the harness actually sends. The recordings carry no `tools` array, so the
1135
- harness SYNTHESIZES one per session (union of observed argument keys; keys
1136
- present in every call marked required) — a reconstruction that is itself part
1137
- of what the A/B measures.
1138
-
1139
- ```
1140
- bun scripts/fill.ts replay --sessions <file|dir> --server-url <url>
1141
- bun scripts/fill.ts ab --sessions <file|dir> --url-a <off> --url-b <echo>
1142
- bun scripts/fill.ts ab --showcase fixtures/showcase-silicon-exchange.txt --url-a … --url-b …
1143
- bun scripts/fill.ts report <runs.jsonl> [--by-tool]
1144
- ```
1145
-
1146
- Fill is a process-wide lever, so the two arms are two SERVERS (A without
1147
- `MLX_BUN_FILL`, B with it). Turns interleave A, B, A, B … so load drift and
1148
- thermal state land on both arms, and the verdict pairs on (session, turn, rep).
1149
-
1150
- **The echo-tier gate**: task-output agreement must not drop within CI AND
1151
- median wall clock must strictly improve. Agreement is the CALL the model made
1152
- (tool name + arguments, key-order independent) or a prose turn's normalized
1153
- text — never token identity, which sampling never promised and which an agent
1154
- loop does not care about. "Does not drop" is McNemar's paired counts with a
1155
- one-sided 95% bound, so a tie or a swing inside the noise passes and a real
1156
- regression does not. The strict tier keeps its own, stricter bar (token
1157
- identity at temperature 0, `tests/parity/fill-strict.test.ts`).
1158
-
1159
- **The showcase** runs ONE large tool-dense prompt ×3 interleaved and reports
1160
- emitted vs decoded tok/s, the fill fraction, time-to-first-tool-call, and the
1161
- comparison with a one-token-per-forward bandwidth estimate. An emitted rate
1162
- above that estimate can show amortized weight reads; the injected positions
1163
- still pass through the state-update graph. `apparent = decoded / (1 − fillFrac)`
1164
- omits append cost and is not a speedup measurement.
1165
-
1166
- The verdict math is model-free and unit-tested against a stub server
1167
- (`tests/research/fill-echo-replay.test.ts`), including the ways it FAILS — a
1168
- harness that can only produce PASS is not a gate.
1169
-
1170
- **Live result, 2026-09-02 (M1 Max 32 GB, mjriii/Qwen3.8-27B 4.80 bpw, six
1171
- recorded pi sessions, 32 paired turns, `--batch 1`).** Two servers do not fit
1172
- the wired ceiling at 27B, so the arms ran SERIALLY (one server restarted
1173
- between them; `fill report` now prints the paired verdict for two `replay`
1174
- files). Two false starts are findings in their own right: (1) the default
1175
- server lane is the batch scheduler, which never fills — an A/B on it is two
1176
- identical arms (fill 0.0%, same 4925 tokens); the serial lane needs
1177
- `--batch 1`. (2) The strict tier compiled ZERO rows on the 27B: Qwen3.x
1178
- thinking templates end the primer in `<think>\n` and the reply opens with
1179
- `\n</think>`, the tokenizer merges the two newlines, the primer stops being a
1180
- token prefix and the compiler bailed silently. Fixed (`schema-rows.ts
1181
- after()`: text-level boundary, suffix tokenized on its own; 4 rows compile on
1182
- the 27B). So the run measured the ECHO tier alone:
1183
-
1184
- | arm | tok/s emitted · decoded | fill | median wall | agreement |
1185
- |---|---|---|---|---|
1186
- | fill-off | 8.0 · 8.0 | 0 | 7663 ms | 3.1% |
1187
- | fill-echo | 8.1 · 7.5 | 7.4% (bash 10%, read 32%) | 7630 ms | 6.3% |
1188
-
1189
- 369 tokens injected in 66 echo events; verify accepted 369 / rejected 1195
1190
- (76% of proposed span positions), 31 branch stops, 147 ms of checkpoints.
1191
- Agreement held (B-only agreements 1, A-only 0; the McNemar bound cannot
1192
- resolve +3 pts at n=32). **Wall clock ×1.00 — the echo gate FAILS**: each
1193
- event pays a multi-token forward for its whole span and a rewind, and with
1194
- three of four proposed positions rejected the forward compute per accepted
1195
- token exceeds a decode step. Echo stays Lab, default off. Levers before a
1196
- rerun: a longer anchor (`MLX_BUN_FILL_K`), fewer candidates, a span cap near
1197
- the observed accepted length (~5–6), and asserting corroborated spans instead
1198
- of verifying. Absolute rates are not quotable: the box ran at 8 tok/s (2.3 GB
1199
- swapped, the 16 GB server plus the day's leftovers) where 19 is predicted;
1200
- both arms saw the same conditions.
1201
-
1202
- **Strict tier, same day, corrected rows** (serial arms back to back, 32 paired
1203
- turns): fill 5.3% of emitted tokens, all proposed strict spans injected
1204
- (assert policy, no agreement readback), identical tool calls on every paired turn,
1205
- median wall ×0.99 (the win is bounded by the fill fraction). The proposal
1206
- trace (`MLX_BUN_FILL_TRACE=<file.jsonl>`, `bun scripts/fill.ts trace`) is
1207
- what made the rows right: the first strict run's list showed the scaffold row
1208
- firing on `</think>` and asserting `<tool_call>…` where the model would have
1209
- written prose ("Hey", "You", "I") in 10 of 47 template proposals, while the
1210
- schema-derived name/close rows agreed 9/9. The scaffold trigger now runs
1211
- through the first token where the call rendering diverges from a plain-
1212
- content rendering — the model's own `<tool_call>` — and the failure class is
1213
- gone by construction. Echo-tier list, same tool: 66 events, verify accepted
1214
- 369 / rejected 1195, survival by position falls to ~50% by position 6 — the
1215
- policy levers named above are what the list points at. **Showcase measured**
1216
- (same day, `fixtures/showcase-silicon-exchange.txt`, 1024 tokens × 2 reps,
1217
- serial arms): echo 8.9 tok/s emitted = 8.9 decoded, off 9.0 — fill 0.0%.
1218
- A fresh build prompt has no earlier session text to copy, so the echo index
1219
- has nothing to propose; the bandwidth-ceiling demonstration (25.2 tok/s for
1220
- 14.76 GiB at 400 GB/s) needs a turn that REPEATS earlier context. The fixture
1221
- is the wrong shape for the tier it was written for — a multi-turn edit loop
1222
- is the honest showcase. Repro to file: turn 8 of session
1223
- `2026-08-18T04-34-36-341Z_01a01326…` kills the server on either lane (bare
1224
- MLX C++ exception, three of three runs, `runs/k3/serve-*.log`).
1225
-
1226
- **Files.** `src/fill/proposal.ts` (the interface + the two policies),
1227
- `src/fill/fill-session.ts` (sources, clamping, flags, telemetry),
1228
- `src/fill/schema-rows.ts` (scaffold probing + value delimiters),
1229
- `src/fill/echo-index.ts` (k-gram index + branch-point rule), the apply
1230
- primitive in `src/generate.ts`, `fillPlanFor` in `src/serve/request-prep.ts`,
1231
- the attach + serve-level refusals in `src/serve/chat-stage.ts`, `usage.fill` in
1232
- `src/serve/{completion-executor,openai-wire}.ts`. Tests:
1233
- `tests/unit/fill-{session,schema-rows,echo-index,generate-loop}.test.ts`,
1234
- `tests/serve/fill-{composition,stream}.test.ts`,
1235
- `tests/parity/fill-strict.test.ts` (weights-gated). Harness: `scripts/fill.ts`
1236
- + `scripts/fill/{session-replay,runner,client,metrics,args,replay,ab,report}.ts`,
1237
- `tests/unit/fill-session-reader.test.ts`,
1238
- `tests/research/fill-echo-replay.test.ts`,
1239
- `fixtures/showcase-silicon-exchange.txt`.
1240
- User-facing mirror: `docs/reference/server-config.md` (`MLX_BUN_FILL`,
1241
- `MLX_BUN_FILL_MAX_SPAN`, `MLX_BUN_FILL_TRACE`, `MLX_BUN_FILL_K`,
1242
- `MLX_BUN_FILL_CANDIDATES`, `MLX_BUN_FILL_INDEX_MAX`), `server-api.md`
1243
- (`usage.fill`).
1244
-
1245
- ### 7.4 No-verification replay contract and next experiments
1246
-
1247
- The 2026-09-04 Qwen performance program makes this a dedicated track.
1248
- Production `assert` must remain free of verification. Separate correctness
1249
- runs may inspect every skipped prediction; those instrumented runs cannot
1250
- supply the performance number. `applyProposal` in `generate.ts` already
1251
- implements this separation: `verify` or a trace filename computes logits at
1252
- all appended positions, while normal `assert` projects only the final hidden
1253
- state to resume sampling. It still forwards the span through model layers
1254
- and updates attention KV and GDN state.
1255
-
1256
- This track appends serialization fixed by the current tool-call state. It
1257
- does not predict unknown tokens. Once the protocol fixes a field following
1258
- a selected tool name, that field can become context immediately; sampling
1259
- resumes where the tool or argument value has a choice. Map fixed protocol
1260
- fields through the model's own chat template, including the preceding token
1261
- boundary. Pi's client-side tool representation and a model's wire rendering
1262
- can differ. Parser state must distinguish structural fields from the same
1263
- text inside argument strings, quoted examples or code. Offline parity audits
1264
- validate the implementation; they do not add verification to served asserts.
1265
-
1266
- There are different possible guarantees:
1267
-
1268
- | source | what would justify an assertion |
1269
- |---|---|
1270
- | Enforced output grammar/protocol | All legal continuations share the emitted token span at the current parser state. Account for tokenizer boundaries and stop conditions. Grammar uniqueness over bytes does not automatically imply unique token IDs. |
1271
- | Deterministic application transform | An explicit contract fixes the source span and transformation, such as escaping a selected literal. Choosing which source/value to emit remains a model/application decision. |
1272
- | Cached continuation | Exact model/quant, prefix, recurrent state, positional metadata and sampler/constraint state establish an identical continuation. A matching short suffix is insufficient. |
1273
- | Template/schema row | Establishes a valid serialization. Without enforced generation constraints, token identity with the model is an empirical gate and can fail even at temperature zero. |
1274
- | Repeated text | Agreement among observed occurrences is evidence, not certainty; retain the existing Lab distinction for echo assertions. |
1275
-
1276
- Audit suffix triggers against real parser/role state, tool-name prefixes,
1277
- optional/extra parameters, `additionalProperties`, multiple calls, quoted
1278
- markup, code blocks, escaping, EOS and partial-burst cancellation. The original
1279
- strict row source matched a token suffix without an independent parser-state
1280
- guard. Do not interpret an all-assert `accepted` count as verified agreement.
1281
-
1282
- A CPU-only audit with the actual R6 tokenizer/template finds a concrete close
1283
- boundary error in both thinking modes. The compiled close trigger ends at
1284
- `</parameter`, before `>`. A valid bash argument containing
1285
- `printf "%s" "</parameterization>"` therefore triggers the structural close
1286
- inside argument data. Injecting the current row changes the parsed command to
1287
- `printf "%s" "`. Both complete calls parse; the suffix alone cannot establish
1288
- that the value ended. The audit constructs valid token streams from the exact
1289
- compiled trigger IDs; it does not claim these are observed model trajectories
1290
- or quantify their frequency. Scaffold/close rows also match reasoning, quoted
1291
- prose and fenced examples without a role/parser guard. Evidence:
1292
- fill-parser-boundary-r6.json. Keep fill off by default. Complete the delimiter
1293
- and establish protocol state before asserting its continuation; runtime model
1294
- verification is not the remedy for a missing structural proof.
1295
-
1296
- An isolated parser prototype now waits for the complete `</parameter>` or
1297
- `</arg_value>` delimiter and requires a request-local tool-only assistant
1298
- context, optionally following closed reasoning. It reuses the tool parser
1299
- with full input consumption and no repair; quoted or fenced examples,
1300
- nested reasoning, unfinished literals, duplicate XML/GLM keys and requests
1301
- above the probe budget decline strict fills. Cached row plans create context
1302
- from the current prompt and do not retain the first request's messages.
1303
- The CPU-only real-R6-tokenizer audit rejects all sixteen negative contexts
1304
- and preserves four positive rendered token streams across both thinking
1305
- modes, including the original `</parameterization>` command. Each positive
1306
- case injects nineteen tokens in two spans with zero verification events.
1307
- The broader parser/stream suite passes 138 tests. Evidence:
1308
- `fill-boundary-tokenizer-audit-v4.json` and `fill-boundary-cpu-tests-v8.log`.
1309
- The parser and model-owned append method are integrated in the main tree.
1310
- The gates below distinguish the original short-context integration from
1311
- the subsequent attention-boundary correction.
1312
- On the consolidated MLX 0.32.2 core with the interleaved R6 artifact and
1313
- variant 13, the first weather fixture emits identical tokens but four-token
1314
- appends change recurrent state and continuation logits. One-token appends
1315
- restore exact state, all four continuation probes and disposal accounting,
1316
- with the same twelve injected tokens and zero verification. The earlier
1317
- four-token acceptance used a different runtime/artifact configuration;
1318
- it does not establish this combination. Isolate the changed arithmetic
1319
- before selecting an append shape. Evidence: `fill-boundary-native-r6.json`
1320
- and `fill-boundary-native-m1-r6.json`. A first-layer operation audit localizes
1321
- the drift to native affine projections: embedding and normalization match,
1322
- but MLX's new multirow matvec differs from repeated M1. Broadcast weight
1323
- views with input shape `[M,1,K]` select native batched M1 instead. All six
1324
- boundary/chunk cases then match every captured intermediate and both state
1325
- arrays exactly, without copying stored weights. The arithmetic prototype
1326
- then passes seven full native fixtures per R6/RTN4 quant, with exact emitted
1327
- IDs, complete state, four continuation probes, usage and disposal accounting.
1328
- Runtime verification remains zero. RTN4's negative-intent code-block prompt
1329
- produces a valid weather call in both arms; its original no-fill expectation
1330
- is retained as a failed fixture assumption, and the rerun classifies that
1331
- cell as a generated-call identity control. Forced-token negative contexts
1332
- remain covered by the tokenizer/parser gates. Evidence:
1333
- `fill-first-layer-shape-probe.json` and `fill-first-layer-batched-m1.json`.
1334
- The full-model reports are `fill-boundary-native-batch1-r6.json` and
1335
- `fill-boundary-native-batch1-v2-rtn4.json`.
1336
- The original guarded-parser/arithmetic prototype also passes six balanced
1337
- three-arm HTTP blocks per quant on the loaded M4 Pro 24 GB. All 144 responses
1338
- match across 36 clean server exits, with fixed effective seed 42, empty prompt
1339
- caches, identical tool calls and zero verification. Four-token append reduces
1340
- paired-median complete time for weather/bash fixtures by 9.95%/15.24% on R6
1341
- and 1.92%/3.34% on RTN4; every corresponding pair improves. M1 append is
1342
- mostly flat, and RSS supplies no memory-reduction claim. Tool output is
1343
- buffered until completion here, so these are complete-request and first
1344
- meaningful-tool-output results, not decode-rate measurements. Source hashes
1345
- remain fixed across the initial screen and five remaining order blocks.
1346
- Evidence: `fill-boundary-http-{screen,repeat,review}.json`. The model-owned
1347
- integration passes the same fourteen native cases and six balanced four-arm
1348
- HTTP blocks per quant. All 192 responses match across 48 clean server exits.
1349
- Paired-median weather/bash complete time improves by 9.87%/15.37% on R6
1350
- and 1.97%/2.77% on RTN4, with every pair improving. Ordinary generation's
1351
- before/after medians differ by at most 0.23%. These remain loaded M4 Pro
1352
- diagnostics. The independent-row operator matches sequential M1 across
1353
- 720 shape/bit/group/dtype/layout cases, with unchanged stored weight bytes.
1354
- The main-source state regression passes on both quants, and eight actual
1355
- HTTP cancellations recover exact responses and steady active allocations.
1356
- Evidence: `fill-append-integration.json`,
1357
- `fill-append-http-integration-review.json`, `fill-append-main-native.json`
1358
- and `fill-append-lifecycle.json`.
1359
-
1360
- A longer-context audit finds another native dispatch dependency. MLX 0.32.2
1361
- changes its attention kernel and two-pass reduction block count according
1362
- to sequence length and GPU architecture. The rules are in
1363
- [MLX's attention dispatch](https://github.com/ml-explore/mlx/blob/v0.32.2/mlx/backend/metal/scaled_dot_product_attention.cpp).
1364
- The qualified GQA-6/D256 path on
1365
- `applegpu_g16s` must end chunks at inclusive KV lengths 1023, 1024, 8192,
1366
- 32768 and 65536. An unsplit append that crosses a transition can change
1367
- arithmetic for its earlier positions. The first operation screen reproduces
1368
- 18 failures among 108 cases. The corrected model-owned limit is rechecked
1369
- after every chunk; MLX still selects the kernels. Other architectures retain
1370
- single-token appends pending their own qualification.
1371
-
1372
- All 225 corrected attention cases through 65,537 cached tokens are exact
1373
- across bf16, fp16 and fp32, and active allocation returns to zero. Full R6
1374
- and RTN4 models also match eight committed positions from identical prefixes
1375
- of 1021 and 8189 tokens. Hidden rows, per-position M1 vocabulary projections,
1376
- complete live state and four ordinary continuation probes match exactly;
1377
- the borrowed prefix state and post-arm active allocation are unchanged.
1378
- These teacher-forced checks establish arithmetic identity, not that the
1379
- model would independently choose those committed IDs. Production regression
1380
- coverage checks the attention boundaries and dynamic model limit. The final
1381
- model-free suite passes 1,947 tests with ten skips and no failures; all three
1382
- typechecks pass. The corrected path also passes eight actual HTTP
1383
- cancellations, fourteen completed responses and exact steady allocation
1384
- recovery across both quants. Final serving timing acceptance passes the
1385
- internal-SSD diagnostic below; held-out, combined, pressure and quiet gates
1386
- remain open.
1387
- Evidence: `fill-sdpa-context-probe.json`,
1388
- `fill-sdpa-context-boundaries.json`, `fill-append-context.json`,
1389
- `fill-append-final-model-free.log` and `fill-append-lifecycle-boundaries.json`.
1390
- The final-source timing attempts complete 116 responses with exact content,
1391
- tool calls and usage comparisons. Two RTN4 first-request warmups hit Metal
1392
- GPU timeouts, one with fill disabled and one with fill enabled. Neither
1393
- executes an append forward. Keep both failed requests and the incomplete
1394
- block in the evidence. Complete three-arm blocks cover six R6 pairs and
1395
- three RTN4 pairs; every append-versus-native pair improves complete time on
1396
- both fixtures. The dynamic boundary checks retain the earlier append benefit.
1397
- Separate recovery, storage and loading controls do not fill missing timing
1398
- cells. The failure investigation and its limits live in
1399
- [environment.md](../reference/environment.md#external-storage-loading).
1400
- Evidence: `fill-append-http-final.json`, `fill-append-http-resume.json` and
1401
- `fill-append-http-final-partial-review.json`.
1402
-
1403
- After Josh specifies internal storage for active models, a separate final
1404
- comparison uses byte-verified R6 and RTN4 copies with ordinary lazy loading.
1405
- All 96 responses across 24 fresh servers match, with twelve balanced pairs,
1406
- zero failures, zero verification calls and identical final active allocation.
1407
- On the M4 Pro 24 GB, the median paired complete-time reductions are 9.83% and
1408
- 15.40% for R6's weather/bash fixtures, and 1.63% and 2.94% for RTN4. Every pair
1409
- improves on each fixture. Tool output is buffered, so first visible output
1410
- arrives near completion; these figures do not establish faster ordinary
1411
- decode. The machine still fails the quiet preflight, so these are diagnostic
1412
- results. Both external-drive failures remain recorded separately. Evidence:
1413
- `fill-append-http-internal-repeat.json` and `fill-append-http-internal-review.json`.
1414
-
1415
- The original quantized-KV append screen passed TurboQuant K8V3 after fixing
1416
- retained temporary state views through `leaseCacheStates`, but affine KV4
1417
- changed recurrent state after the first full-attention layer. That failure
1418
- is now resolved: multi-token affine attention selected different arithmetic
1419
- from one-token decode, both in tiled and ordinary unfused forms. The model's
1420
- committed-append path now computes each query against its own causal KV
1421
- prefix using the one-token attention operation, while retaining shared
1422
- projection work. No sampled decode or ordinary prefill arithmetic changes.
1423
-
1424
- On M4 Pro, packed and RTN4 Qwen27B both preserve complete hidden/logit/cache
1425
- bytes and four subsequent continuations for KV4/KV8 at prefixes 128 and
1426
- 1021, including the attention boundary. The real KV4 generation loop also
1427
- preserves emitted IDs, final state, subsequent logits and active allocation,
1428
- with nonzero fill and zero verification. The append binding declares affine
1429
- format support; HTTP preparation and placement leave that decision to the
1430
- method. K8V3 TurboQuant now uses the same declaration and delayed-conversion
1431
- boundary interface. Both Qwen artifacts pass real-generation state/continuation
1432
- and six-pair HTTP comparisons; quantized echo verification remains separate.
1433
- Full numerical and HTTP measurements live in benchmarks.md. Tests:
1434
- `tests/unit/quantized-append-attention.test.ts`,
1435
- `tests/parity/qwen-affine-append.test.ts`, and
1436
- `MLX_BUN_TEST_FILL_KV_BITS=4` with the existing strict-fill parity test.
1437
- Earlier failure/lease evidence remains `fill-append-quant-cache-review.json`
1438
- and `fill-append-state-ownership-native-test.log`.
1439
-
1440
- The literal/reasoning checks deliberately decline ambiguous text, including some
1441
- otherwise valid prose with unmatched quote characters. This is bounded
1442
- coverage, not proof for every unconstrained model trajectory.
1443
-
1444
- The schema-choice audit reproduced assertions that selected a first key or
1445
- closed the call while other valid arguments remained. The compiler now uses
1446
- a sole required key only when `additionalProperties: false` and no nonempty
1447
- `patternProperties` map establish that no other key is legal. Optional keys
1448
- may come before a required key. When no property is required, the common
1449
- span also includes the empty-argument rendering. This follows the
1450
- [JSON Schema object applicators](https://json-schema.org/draft/2020-12/json-schema-core#section-10.3.2),
1451
- where omitting `additionalProperties` leaves those properties unconstrained.
1452
- Open objects also compare an undeclared-key rendering, even when declared
1453
- keys share a tokenizer prefix. Twenty-seven regressions across XML, JSON and
1454
- GLM templates preserve these
1455
- choices, alongside the existing positive fill cases. This is a compiler
1456
- correctness fix, with no runtime verification or new inference operation.
1457
- The real packed-Qwen and RTN4 tokenizers each pass 20 cases across thinking
1458
- on/off with nonzero row matches. The packed weighted regression also retains
1459
- token-identical output and nonzero injection with four-token appends. All
1460
- 1,867 model-free tests and three typechecks pass. Parser/role-state proof
1461
- and the broader session corpus remain. Evidence is
1462
- `fill-schema-open-objects-before.json`,
1463
- `fill-schema-choices-original-control-corrected.txt`,
1464
- `fill-schema-shared-prefix-merged-before.txt`,
1465
- `fill-schema-choices-model-free-final.txt`,
1466
- `fill-schema-tokenizer-{r6,rtn4}-final.json` and
1467
- `fill-schema-choices-weighted-r6.json` in the campaign report directory.
1468
-
1469
- Run the actual artifact regression with
1470
- `MLX_BUN_TEST_FILL_MODEL=<local-model-dir> MLX_BUN_FILL=strict bun test tests/parity/fill-strict.test.ts`.
1471
- It selects one artifact per process and defaults to the small Qwen fixture
1472
- when no override is set. This is an initial positive-fill identity check;
1473
- extend it to the held-out 27B session/adversarial corpus before a default.
1474
- Track token IDs and subsequent logits/state as well as parsed tool arguments.
1475
-
1476
- On 2026-09-05 the actual packed Qwen3.8-27B passes this regression on both
1477
- trellis variants 6 and 7. Both runs perform nonzero assert injection with
1478
- zero verification events and emit the same token IDs as their unfilled
1479
- control. Logs: `reports/qwen38-rd/strict-fill-variant{6,7}.txt`. This is one
1480
- weather/tool-call fixture; it does not establish universal determinism or a
1481
- wall-time win. Test duration includes loading and warmup and is not the
1482
- performance comparison. The older logs' `baselineForwardSteps` field contains
1483
- the baseline generated-token count; the test now labels it accordingly.
1484
-
1485
- The native tests now union config EOS with tokenizer EOS, matching
1486
- `loadRuntimeModel`. The packed config alone omits the chat terminator. Earlier
1487
- `strict-fill-v10-{wall,max4-wall}.json` runs continued beyond the first chat
1488
- turn and are excluded from serving-performance conclusions. This was a test
1489
- policy error; the server already applies the union. The initial variant-6/7
1490
- logs also used the config-only stop policy.
1491
-
1492
- Corrected variant-10 diagnostics warm complete answers and retain six
1493
- alternating on/off pairs per cap. Both the default cap and the existing
1494
- `MLX_BUN_FILL_MAX_SPAN=4` cap preserve the first-turn token IDs with nonzero
1495
- assertions and no verification. Both improve observed request time; the
1496
- shorter cap injects fewer tokens and avoids an expanded append. These are
1497
- separate diagnostic sessions with prefill noise, not a default-policy verdict
1498
- or a direct comparison of truncation against chunking. Corrected reports:
1499
- `reports/qwen38-rd/strict-fill-v10-cap{32,4}-served-eos.json`.
1500
- `MLX_BUN_TEST_FILL_REPORT` enables the retained test's paired diagnostic;
1501
- `MLX_BUN_TEST_FILL_BLOCKS`, `MLX_BUN_TEST_FILL_PROMPT` and
1502
- `MLX_BUN_TEST_FILL_REVERSE` select its workload and schedule. Reports record
1503
- the cap, rows, prompt IDs, exact emitted IDs, counters and whole-request time.
1504
- `MLX_BUN_TEST_FILL_THINKING=0|1` and `MLX_BUN_TEST_FILL_TOKENS` select the
1505
- thinking policy and completion budget for broader fixtures. The test rejects
1506
- emitted EOS IDs; its report records the effective stop set.
1507
- The corrected variant-11 default-cap repeat also preserves first-turn IDs
1508
- with nonzero injection, zero verification and lower complete-request time.
1509
- Evidence: `reports/qwen38-rd/strict-fill-v11-cap32-served-eos.json`.
1510
- The EOS-correct five-case audit (weather control plus four frozen adversarial
1511
- prompts) preserves all emitted IDs, cache-token records and offsets. Quoted
1512
- malformed markup and code blocks produce no injections and retain exact
1513
- state/probe logits. The three injected cases preserve the response but differ
1514
- in live state after longer appends; subsequent teacher-forced logits differ
1515
- too. All verification counts remain zero. Explicit seed 42 reproduces those
1516
- results; temperature-zero sampling uses argmax. Reducing the span cap to four
1517
- restores exact state and four subsequent probes in the weather/multiple-call
1518
- fixtures, while injecting fewer tokens. Evidence:
1519
- `reports/qwen38-rd/fill-adversarial-state-v12-eos-review.json`,
1520
- `fill-state-v12-cap4-eos.json` and
1521
- `fill-state-v12-cap{32,4}-seed42.json` in the same directory.
1522
-
1523
- An isolated follow-up removes generation and sampling entirely. It copies a
1524
- nine-token span from the unfilled model's recorded output and appends it to
1525
- byte-identical cloned starting caches. Serial and repeated serial appends,
1526
- full M3/4 appends, and chunks of at most four tokens agree exactly in state,
1527
- final logits and the next teacher-forced probe. Full M5/9 appends reproduce
1528
- the numerical difference. Restoring the saved serial cache preserves its
1529
- bytes and next logits exactly. Thus copying a cached state works as expected;
1530
- recomputing known tokens through a different graph shape changes numerics.
1531
- The packed projection dispatch crosses from small-M matvec to prefill at
1532
- M=5; that prefill path also rounds reconstructed weights to the activation
1533
- dtype. This is a compute-path distinction, not a changed token span or seed.
1534
- Evidence: `reports/qwen38-rd/fill-identical-input-append-review.json`.
1535
-
1536
- Four-token execution chunks now preserve every asserted token and pass all
1537
- five complete-generation fixtures at seed 42. Emitted ids, cache-covered ids,
1538
- live cache bytes and four subsequent teacher-forced logits are exact against
1539
- ordinary generation. Positive cases still inject 12, 8 and 20 tokens with no
1540
- verification; both negative cases inject zero. The production implementation
1541
- passes the same audit, without the prototype model adapter. It is a shared
1542
- MLX append operation, selected by a captured FillSession setting rather than
1543
- model inspection in the generation loop. Verify proposals retain a single
1544
- forward because recurrent rollback records one forward per round. Tests cover
1545
- budget clamping, one final vocabulary projection, a consumer break inside the
1546
- burst, cancellation, failed-chunk cleanup and recurrent verification rollback.
1547
- The setting and default live in server-config.md.
1548
-
1549
- Six balanced three-arm blocks per positive timing fixture compare ordinary
1550
- generation, existing full-span fill and four-token execution chunks. The full
1551
- span is retained in both fill arms; every pair preserves emitted ids and
1552
- cache-covered ids. The chunked prototype improves complete-request diagnostic
1553
- timing in every pair, with higher peak allocation than ordinary generation.
1554
- These are local M4 Pro observations with residual swap, not quiet benchmark
1555
- rows or a universal determinism guarantee. Six production HTTP server pairs
1556
- then preserve all 24 paired warm/measured responses, tool calls and injection
1557
- counts. Every measured fixture pair improves complete-request time. Dispatch
1558
- counters confirm chunking is used only by the candidate, all twelve servers
1559
- exit cleanly, and source hashes remain fixed. HTTP uses greedy temperature zero
1560
- without an explicit seed because explicit HTTP seeds currently exclude fill;
1561
- the separate native acceptance uses seed 42. Broader held-out/parser, model
1562
- and quiet/second-Mac gates remain. Evidence:
1563
- `reports/qwen38-rd/fill-chunked-complete-requests-review.json`,
1564
- `fill-chunked-state-v12-seed42-review.json`,
1565
- `fill-integrated-state-v12-seed42-review.json` and
1566
- `fill-integrated-http-packed-review.json`, plus
1567
- `fill-chunked-integrated-{unit,model-free,typecheck,hygiene}.txt`.
1568
-
1569
- Performance experiments: eliminate redundant in-flight sampling/head work,
1570
- merge adjacent determined spans, reuse compiled schema plans with exact
1571
- identity keys, and choose append batch size from the packed-trellis M curve.
1572
- For the discarded head, test scheduling the next model body first, reading
1573
- the current token while that body runs, then projecting only when the fill
1574
- decision requires a sampled continuation. The existing graph interface already
1575
- separates body and head. Cache advancement must be tracked independently of
1576
- a pending sample. Verify and trace policies still require their sampled
1577
- position; assert must not acquire runtime verification. Check EOS, cancellation,
1578
- budget limits and consumer breaks, and measure unfilled tokens for any loss
1579
- of pipeline overlap before retaining this change.
1580
- The first staged-body prototype passes 26 lifecycle/verification checks and
1581
- all five frozen 27B fixtures. Both arms retain strict fill and four-token
1582
- appends, with compiled decode disabled. Emitted IDs, cache-covered tokens,
1583
- live cache bytes and all continuation probes match. The positive fixtures
1584
- retain their injected spans with zero wasted samples and zero verification;
1585
- the two negative fixtures still inject nothing. This establishes the staged
1586
- path's tested correctness, not its speed or a universal forced-token proof.
1587
- Six complete-request pairs per fixture include an enabled-fill negative
1588
- fixture and an explicit fill-disabled control. All emitted IDs, cache-covered
1589
- tokens and injection counts match. Timing is approximately flat in every
1590
- fixture; the disabled control moves by as much as the best positive fixture.
1591
- Peak allocation is unchanged or slightly higher. Close this staging prototype
1592
- without integration: removing discarded samples does not establish a useful
1593
- complete-request gain. Evidence: `reports/qwen38-rd/fill-staged-unit.txt`,
1594
- `fill-staged-state-v13-seed42-review.json` and
1595
- `fill-staged-complete-requests-review.json`. Closed staging helpers are removed.
1596
- Superseded chunking/state/HTTP research helpers are removed; their frozen
1597
- fixtures, raw reports and the retained production append helper remain.
1598
- On default variant 6, M>4 triggers dense expansion. Experimental variants
1599
- 11/12 add direct tiles and change that cost curve; span policy needs the
1600
- selected variant's measured append costs. A longer known span is not
1601
- necessarily cheaper per token. Inspect cache writes and resume logits in traces, then
1602
- time with `MLX_BUN_FILL_TRACE` unset. Measure emitted/predicted counts, total
1603
- wall time, first-tool-call latency and task success. Extend the current
1604
- grammar/KV/batch/logprobs/seed exclusions individually after their own gates.
1605
- The full experimental matrix and completion rule are in
1606
- [decode-speed-program.md](decode-speed-program.md#7-qwen38-27b-research-program).
1607
-
1608
- #### Shared strict-fill method
1609
-
1610
- `backends/mlx/fill-group.ts` composes `MlxPrefillCohort`, `MlxStateRows`, the
1611
- model graph, the sampler and the common prompt-cache interface. The scheduler
1612
- continues to select work through `MlxGroupedMethod`. It does not compile tool
1613
- schemas or choose filled tokens. A request owns its `FillSession`, partial
1614
- proposal and sampler history.
1615
-
1616
- Ordinary samples retain build-next-before-read overlap. The method commits a
1617
- token to sampler history only when that token becomes model input. An in-flight
1618
- sample replaced by a strict continuation never enters history. Known positions
1619
- skip sampling; if every next position is known, the method also omits the
1620
- vocabulary projection. The model binding supplies the maximum committed chunk
1621
- size for the current row geometry. When every row has a known continuation and
1622
- the model permits wider chunks, the method uses the same append operation as
1623
- explicit serial execution. Qualified Qwen B1 uses its specialized multi-position
1624
- operation; wider rows retain one-position arithmetic and pipeline overlap.
1625
- Performance parity remains a measured acceptance gate.
1626
-
1627
- Before a row joins, the method flushes pending outputs. Retirement and
1628
- cancellation settle exactly the emitted prefix of a proposal once. Cache
1629
- publication uses the tokens actually consumed by the model, which can lead
1630
- visible output by one pipelined position or the remaining committed span.
1631
- The cache owns RAM retention and
1632
- queued SSD persistence. No storage work is awaited by the method.
1633
-
1634
- The row-aware `appendHiddenRows` interface separately accepts borrowed `[B,L]`
1635
- inputs and asks the model for its maximum chunk length at the actual B. The
1636
- qualified Qwen binding retains its specialized B1 append and declares one
1637
- position for wider rows. Full hidden outputs, live cache bytes and subsequent
1638
- logits match ordinary same-B forwards after retirement on M1 MiniCPM/Qwen0.8B
1639
- and M4 packed Qwen27B with bf16, KV4 and k8v3.
1640
-
1641
- `tests/unit/fill-group.test.ts` exercises actual shared execution, including
1642
- mixed sampled/filled rows, head omission, stream stops, length limits,
1643
- consumer failures, cancellation and late joins. `tests/parity/shared-fill.test.ts`
1644
- compares ordinary, empty-fill and saved-continuation arms at matched B1/B2/B4
1645
- with seeded sampling, presence/repetition penalties and bf16/KV4/k8v3. All
1646
- nine cases pass on M1 MiniCPM, Qwen0.8B and Gemma4-e4b and M4 packed Qwen27B.
1647
- Gemma's sliding layers remain bf16 in the TurboQuant arm.
1648
-
1649
- The M4 delayed-conversion gate caught two composition defects. Shared row
1650
- layouts did not expose their pending precision boundary to committed append;
1651
- the affine attention view also bypassed the model's single-position reduction
1652
- policy. The cache now publishes `maxAppendTokens()` from logical row offsets,
1653
- including padding and retirement, and the attention view carries the qualified
1654
- committed-position policy to its codec. Both delayed KV4 and k8v3 seeded cases
1655
- pass after splitting the five-token span into two and three positions at the
1656
- boundary. Separate B1 full-hidden/cache-byte/continuation comparisons pass for
1657
- bf16, KV4, k8v3 and both delayed formats. Earlier failed logs are retained.
1658
-
1659
- The first unequal-prompt comparison did not fix the admission geometry and
1660
- produced different later tokens; preserve it as an unmatched experiment.
1661
- A later fixture reused a short suffix which recurred during stochastic
1662
- sampling and wrongly supplied the same continuation twice. The numerical
1663
- gate now supplies a saved span at one exact position. Parser/source validity
1664
- has its own tests; numerical replay does not prove arbitrary suffix asserts.
1665
- The failed logs and corrected runs remain in `reports/prefill-observation/`.
1666
- Serving binding tests also cover seeded placement and `usage.fill` propagation.
1667
- The six-arm M4 HTTP comparison preserves all 108 responses and all paired token/cache counts, with six durable SSD restarts. Sequential shared strict-fill performance matches serial within 0.13%; the fill-off comparison and concurrent latency tradeoffs are recorded in benchmarks.md. Model-declared codec eligibility is resolved once at binding: unsupported multi-position formats still use shared one-position fill. A separate k4v3 seeded gate proves that execution with no specialized append.
1668
-
1669
- #### Shared echo verification
1670
-
1671
- The fill method accepts both asserted and verified proposals. A pending
1672
- sample checks the first echo token without replacing the sampler's choice.
1673
- When a live row has a verified echo continuation, the method supplies
1674
- its proposal to `advanceSpeculativeOutputs`, the same grouped target
1675
- verification and output-aligned rollback operation used by speculative
1676
- providers. Ordinary rows join with empty proposals and retain only their
1677
- consumed inputs. Asserted spans keep their append policy. Proposals discovered
1678
- while publishing pending output stay within the scheduler's declared token
1679
- work; any remainder belongs to the request's next iteration.
1680
- No scheduler or storage branch chooses echo tokens.
1681
-
1682
- Each request retains its own seed and processor history. The sampler adapter
1683
- commits a token when it becomes model input; rejected proposals never enter
1684
- that history. Eligible plain-greedy rows use the sampler's existing independent
1685
- verification kernel. Output delivery determines how much state survives a consumer
1686
- stop, then the common cache receives the corresponding tokens and row state.
1687
- The cache retains RAM donors and owns SSD persistence. Checkpoint telemetry
1688
- includes the shared cohort's begin and resolve time for each participating
1689
- request. Fill remains opt-in. Shared paged execution is unsupported. Qwen MTP can
1690
- consume verified echo continuations through the provider operation below.
1691
-
1692
- `shared-echo.test.ts` audits the real sampler against an independent sampler
1693
- on the exact same score tensor and selected-token history, across B1/B2/B4,
1694
- bf16, KV4, k8v3 and delayed quantization. It covers accepted, first-rejected,
1695
- partially rejected, mixed and staggered proposals plus a consumer stopping inside
1696
- the span. Published cache keys must match emitted history and every layer offset.
1697
- B2 retained state also survives SSD store/reopen with identical state and two
1698
- subsequent logit vectors against its RAM clone. These checks pass on M1
1699
- Qwen0.8B/Gemma-e4b and M4 packed Qwen27B. HTTP tests cover actual copied tool arguments,
1700
- seeded concurrent requests, follow-up reuse and durable SSD restart.
1701
-
1702
- An early experiment compared multi-position verification against one-position
1703
- ordinary decoding and found changed sampled tokens. That comparison changes
1704
- numerical geometry and is preserved as an unmatched experiment, not an exact
1705
- oracle. The original strict-fill exact replay gate remains unchanged. Echo
1706
- acceptance preserves the sampler's decision for the verified logits; it does
1707
- not promise identical text to a different forward shape. Request timing and
1708
- paired-response results are recorded in benchmarks.md.
1709
-
1710
- #### Echo with a mounted MTP provider
1711
-
1712
- `DraftRowGroup.consume` consumes externally verified target tokens and hidden
1713
- context, retaining the specified prefix length for each row. Provider
1714
- capabilities advertise this operation before execution. The Qwen MTP provider
1715
- uses its existing true-hidden prefill graph and per-row rollback; it neither
1716
- samples draft tokens nor projects its vocabulary during this operation.
1717
-
1718
- The speculative method first compares ordinary MTP output with a pending copy
1719
- proposal. A first-token mismatch uses no additional target forward. Once output
1720
- establishes a matching prefix, the method verifies the remaining copied span.
1721
- Other rows supply empty proposals. The existing verifier and
1722
- sampler select output, then output delivery determines how many inputs survive.
1723
- The provider consumes that same prefix before ordinary MTP resumes. Target and
1724
- companion state are published together through the unchanged cache interface.
1725
- No scheduling or storage implementation selects between echo and MTP.
1726
-
1727
- `FillSession.observe` records sampled output independently of proposal timing.
1728
- The method asks for verified proposals at committed output boundaries. Under
1729
- MTP, asserted template spans remain ordinary sampled output; this combination
1730
- adds echo without changing the strict append algorithm. Grammar, probability
1731
- metadata, media, paging and providers without external-token consumption remain
1732
- outside this combination's serving coverage.
1733
-
1734
- `usage.fill` counts verified echo proposals. Learned-provider drafted/accepted
1735
- counts, rounds and acceptance histograms exclude echo. Target calls and tokens
1736
- per forward cover both kinds of round. A request can legitimately use no
1737
- learned drafts if echo supplies every continuation. Both-machine companion
1738
- oracle checks cover external prefixes and subsequent full decoder output;
1739
- shared tests cover sampling, mixed rows, rejection, stop and paired SSD state.
1740
-
1741
-
1742
- ### 7.5 Logical jump-ahead prefill
1743
-
1744
- Proposal by Josh Rossi, recorded 2026-09-08. Research proposal, not an
1745
- implemented semantic intervention or a measured task-time improvement.
1746
- This is the canonical write-up and proposed preprint question. The existing
1747
- fixed-serialization implementation is described in §7.4. The broader
1748
- proposal deliberately permits a different continuation.
1749
-
1750
- The governing [product objective](../planning/PRODUCT_ROADMAP.md#product-north-star),
1751
- in Josh's words, is "The absolute BEST local AI experience on a mac". It
1752
- covers the entire project, including simple installation, direct application
1753
- integration and JavaScript/TypeScript development. A preprint is optional.
1754
- This research serves that objective by finishing tasks sooner, producing
1755
- better results, or making a more capable model practical on the same hardware.
1756
- A hypothetical 30% reduction in task completion time would be a meaningful
1757
- product improvement, not a measured result of this proposal. Evaluate the
1758
- complete experience, including quality, reliability, latency and memory,
1759
- rather than treating a token-rate increase or a publication as the goal.
1760
-
1761
- The model often spends time deciding what to do, writes relevant content
1762
- in its reasoning, and then generates that content again inside a tool call.
1763
- Josh proposes letting the runtime recognize the intended action, construct
1764
- some or all of its tool-call representation, and append it through prefill.
1765
- The model continues from the supplied history and actual tool result.
1766
- The runtime does not ask the target model to verify that it would have
1767
- sampled each supplied token.
1768
-
1769
- The research question has two parts:
1770
-
1771
- 1. With perfect knowledge of an eligible continuation, how much decode time
1772
- can be replaced by cheaper prefill and construction work?
1773
- 2. With an imperfect predictor, how often can the model recover from an
1774
- unsuitable intervention, and what does that recovery cost?
1775
-
1776
- The deciding quantity is time saved by logical jump-ahead prefill minus time
1777
- spent on recovery, with intervention overhead included and task quality held
1778
- to an independently evaluated standard. Prediction errors do not by
1779
- themselves rule out a useful speedup. Their consequences determine the cost.
1780
-
1781
- #### Context management is the broader premise
1782
-
1783
- Josh's framing is that working with LLMs is largely context management.
1784
- For the local inference system under our control, the runtime owns every
1785
- token supplied to the model. At each generation step, the abstraction is
1786
- `token sequence in -> next-token distribution -> sampled token`.
1787
- The KV and recurrent caches are computed representations of that history,
1788
- not an independent record of the path the model might have taken.
1789
-
1790
- The runtime can construct, insert, replace, summarize or remove context.
1791
- It can choose what the model needs to decide and what software can supply.
1792
- The full original transcript need not remain the active inference context.
1793
- It can remain in the audit log while a different sequence drives the next
1794
- step. The resulting sequence still must be processed consistently by the
1795
- model and preserve enough information for the task.
1796
-
1797
- Logical jump-ahead prefill and micro-compaction are two applications of this
1798
- control. One supplies a continuation before it is redundantly generated.
1799
- The other retires or rewrites material after its immediate purpose is served.
1800
- Both should be judged by successful task completion, elapsed time and the
1801
- cost of recovering from an inadequate context decision.
1802
-
1803
- #### Mechanism and example
1804
-
1805
- Suppose the reasoning contains a settled instruction to write `hello.txt`
1806
- with the contents `hello, world!`. The normal path generates a tool name,
1807
- argument names, path and escaped contents. The proposed path constructs that
1808
- representation from the available trace, appends it as assistant tool-call
1809
- content, and executes the call through the normal tool dispatcher.
1810
-
1811
- An intervention consists of:
1812
-
1813
- 1. Detect an eligible boundary using only context available at that moment.
1814
- 2. Select an action or source span and construct the continuation, including
1815
- required escaping and protocol delimiters.
1816
- 3. Append the supplied tokens through the model's state-update path, then
1817
- resume generation at the next unresolved choice or dispatch a complete call.
1818
- 4. Return the actual tool outcome and allow the model to continue, including
1819
- correcting an unsuitable action when needed.
1820
-
1821
- The state update still runs model forward computation. Attention KV,
1822
- recurrent state, positions and parser state must describe the new sequence.
1823
- It saves sequential token decisions and can avoid intermediate vocabulary
1824
- projections and verification work. Copying text from an earlier position
1825
- does not generally permit copying that position's KV, because its context
1826
- and position differ. Editing an existing prefix also requires invalidating
1827
- and recomputing affected state. Appending at the current boundary is the
1828
- smallest implementation to study.
1829
-
1830
- There is no hidden record of the alternate tokens the model would have
1831
- sampled. Given consistent state for the supplied prefix, subsequent decoding
1832
- conditions on that prefix. This does not imply that every supplied action is
1833
- appropriate or that the model always recovers. Those are empirical questions.
1834
-
1835
- #### Perfect prediction and imperfect recovery
1836
-
1837
- Perfect prediction supplies an upper-bound experiment. Replacing a known
1838
- span's serial generation with a cheaper append saves time. Span size,
1839
- context length, kernel behavior and construction overhead determine the
1840
- amount. Very short spans can cost more to detect and append than to decode.
1841
-
1842
- For the oracle experiment, use the saved future continuation to choose the
1843
- span, while requiring the copied source content to exist before the jump.
1844
- This deliberately uses hindsight to measure opportunity. It is not evidence
1845
- that an online detector can identify those opportunities. An online policy
1846
- must receive only the prefix available at the intervention boundary.
1847
-
1848
- With an imperfect policy, an action may still satisfy the task even when it
1849
- differs from the saved continuation. Another action may require correction.
1850
- For example, the runtime supplies `ls` in an unsuitable working directory.
1851
- The returned listing fails to answer the model's question, so the model
1852
- changes directory or asks for a different listing. The extra reasoning,
1853
- request prefill, tool calls and tool execution count as recovery cost.
1854
-
1855
- Record errors the model fails to notice, persistent loops and unsuccessful
1856
- tasks too. Recovery is possible, not guaranteed. A retry alone is not proof
1857
- of recovery; the task must regain useful progress and ultimately meet its
1858
- acceptance criteria. Identical sampled tokens are not required for success.
1859
-
1860
- #### Cost model
1861
-
1862
- For an intervention, define:
1863
-
1864
- | Symbol | Cost |
1865
- |---|---|
1866
- | `D` | Serial decode time avoided for the replaced span |
1867
- | `P` | Time to prefill the supplied continuation and resume |
1868
- | `H` | Detection, selection, serialization and other intervention overhead |
1869
- | `R` | Additional downstream time caused by correction or other consequences |
1870
-
1871
- The local accounting model is:
1872
-
1873
- ```text
1874
- net saving = D - P - H - R
1875
- ```
1876
-
1877
- If a fraction `q` of interventions require recovery, and their mean added
1878
- cost is `C`, a simplified expectation is:
1879
-
1880
- ```text
1881
- expected net saving = E[D - P - H] - q * C
1882
- break-even recovery frequency = E[D - P - H] / C
1883
- ```
1884
-
1885
- The break-even expression assumes positive `C`, successful eventual recovery
1886
- and no other downstream differences. Here `q` measures harmful interventions
1887
- requiring recovery, not disagreement with a hypothetical sampled string.
1888
- Span length, uncertainty and recovery cost may be correlated; measure their
1889
- joint behavior rather than multiplying unrelated averages.
1890
-
1891
- This decomposition explains the mechanism. The authoritative measurement is
1892
- complete task wall time against a paired baseline. A changed trajectory can
1893
- alter later reasoning, tool latency, cache reuse and compaction. Those effects
1894
- belong in the result even when they cannot be assigned to one jump. Do not
1895
- double-count overlapping spans or add savings from dependent interventions
1896
- as if each occurred in the original unmodified run.
1897
-
1898
- #### Evidence and first experiment
1899
-
1900
- The completed Kanban trace supplies a workload and an offline opportunity
1901
- analysis. Generation-to-generation duplicate coverage and the narrower
1902
- reasoning-to-tool coverage are recorded in the
1903
- [completed Kanban benchmark](../reference/benchmarks.md#completed-fresh-pi-kanban-with-bounded-range-cache-m4-pro-2026-09-08).
1904
- Those counts retain first occurrences, merge overlapping later positions and
1905
- exclude replayed request history. They use retokenized payloads rather than
1906
- the original sampled token stream, so they are opportunity estimates.
1907
- The longest whole-file repeat was a write followed by a read. It does not
1908
- establish that the model first wrote that whole file in reasoning.
1909
-
1910
- Start with these experiment arms:
1911
-
1912
- | Arm | Purpose |
1913
- |---|---|
1914
- | Ordinary decoding | Establish task success, timing and natural retry behavior |
1915
- | Existing strict fill | Isolate savings from fixed serialization already supported |
1916
- | Oracle content jumps | Estimate savings with hindsight and no selection mistakes |
1917
- | Online logical jumps | Measure an implementable policy using only the current prefix |
1918
- | Controlled mistaken jumps | Measure detection, recovery and failure under known perturbations |
1919
-
1920
- For the online arm, begin with complete literal content already in the trace
1921
- and a partially generated tool call that identifies the destination. This
1922
- reduces the decisions the runtime must infer. Then evaluate earlier action
1923
- selection as a separate policy. Track changes in opportunity coverage and
1924
- recovery cost as the policy becomes more permissive.
1925
-
1926
- Use fresh workspaces and matched prompts, models, quantization, tool access,
1927
- context limits and hardware conditions. Preserve the same cache and decoding
1928
- configuration across arms where supported. The Kanban configuration and
1929
- strict fill currently have composition restrictions; establish a supported
1930
- common control before attributing a difference to logical jumps. Keep the
1931
- separate MLX-LM comparison as a reference experiment, not a substitute for
1932
- this within-engine ablation.
1933
-
1934
- Record supplied and sampled tokens separately, source-span provenance,
1935
- intervention boundaries, append cost, selection cost, tool outcomes, extra
1936
- turns, recovery time, compactions and complete task time. Keep raw generated
1937
- text and supplied text distinguishable in the audit log, while making the
1938
- model-visible history consistent with the action actually executed.
1939
-
1940
- Repeat paired runs over multiple tasks and sampling trials. A matching seed
1941
- does not preserve the trajectory after an intervention. Evaluate artifacts
1942
- with independent task checks. Report success rate and the distribution of
1943
- task times, including slow recoveries, timeouts and failures. Fast failed
1944
- runs must not improve the reported time-to-success result. Where retries
1945
- are allowed, include their cost under a predefined retry budget.
1946
-
1947
- #### Micro-compaction after tool execution
1948
-
1949
- Josh proposes replacing a long reasoning segment after its associated tool
1950
- calls have completed. For example, the model may spend roughly 50,000 tokens
1951
- planning and drafting, then write files and inspect the results. At that
1952
- boundary, the runtime could replace the reasoning with a concise account of
1953
- decisions, completed actions, observed results and unresolved work.
1954
-
1955
- This is selective compaction at a task boundary. It need not wait until the
1956
- whole context window approaches its limit. A candidate procedure is:
1957
-
1958
- 1. Identify the reasoning segment whose associated actions have completed.
1959
- 2. Preserve current requirements, decisions that still constrain the work,
1960
- observed failures and pending questions in a compact replacement.
1961
- 3. Retain the relevant tool-call/result pairs and references to written
1962
- artifacts. Keep the original trace available outside the active context.
1963
- 4. Build the revised token sequence, recompute affected model state, and
1964
- continue the task from that sequence.
1965
-
1966
- The replacement may come from a model-generated summary or deterministic
1967
- extraction of completed actions and results. Compare these methods rather
1968
- than assuming another long generation is necessary. A successful file write
1969
- provides an artifact the model can read again; whether that makes the full
1970
- earlier draft disposable depends on the remaining task. Missing rationale
1971
- or a discarded constraint can require recovery even when the file survives.
1972
-
1973
- Removing earlier tokens changes the context for retained later tokens.
1974
- Ordinary prefix caching can preserve the unchanged prefix, but it cannot
1975
- generally reuse the old suffix state as if the removed reasoning were still
1976
- present. Recompute that suffix under the new history. Any method that keeps
1977
- stale state intentionally is a separate approximation to evaluate.
1978
-
1979
- Micro-compaction cannot recover the time already spent generating the long
1980
- reasoning segment. It can reduce later context-processing work and memory
1981
- use, and may change subsequent generation or avoid a larger compaction.
1982
- Measure those effects over the remaining task:
1983
-
1984
- ```text
1985
- net saving = future context-processing and trajectory savings
1986
- - summary/extraction cost
1987
- - state-rebuild and management cost
1988
- - extra recovery cost
1989
- ```
1990
-
1991
- Because a warm prefix cache already avoids much repeated prefill, removed
1992
- token counts alone do not establish savings. Context length can still affect
1993
- subsequent attention work and capacity. Record actual cache reuse, rebuild
1994
- time, memory, later decode time and rereads caused by missing information.
1995
-
1996
- Compare the existing compaction policy, post-tool micro-compaction,
1997
- jump-ahead alone, and their combination. Use the same task checks and failure
1998
- accounting as the jump experiment. Their gains need not add: removing a
1999
- reasoning segment also removes a potential source for later content copying.
2000
- An external source store could retain it, with retrieval cost included.
2001
-
2002
- #### Related work and the proposed preprint
2003
-
2004
- Josh identified the connection to structured output and grammars at the
2005
- outset. [XGrammar](https://github.com/mlc-ai/xgrammar) implements efficient
2006
- grammar-constrained generation. SGLang's
2007
- [jump-forward decoding](https://www.lmsys.org/blog/2024-02-05-compressed-fsm/)
2008
- directly prefills strings fixed by a grammar until the next branch. These
2009
- are established relatives of fixed-serialization fill.
2010
-
2011
- [Copy-as-Decode](https://arxiv.org/abs/2604.18170), an April 2026 preprint,
2012
- is direct prior art for unverified content prefill. The model emits an
2013
- explicit instruction selecting input line ranges, then the runtime prefills
2014
- their contents without probabilistic verification. It studies an oracle
2015
- savings bound and span-selection errors. Editing belongs within this
2016
- proposal's scope, including when edits are tool calls; the application label
2017
- does not establish a separate invention. The relevant difference to study
2018
- is runtime inference from reasoning or a partial call versus an explicit
2019
- model-selected copy instruction, and the cost of subsequent agent recovery.
2020
- The paper does not establish agentic multi-file coverage.
2021
-
2022
- Harness intervention is also established. AI SDK supports
2023
- [custom tool-call repair](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#tool-call-repair),
2024
- Pydantic AI exposes
2025
- [JSON and argument modification hooks](https://github.com/pydantic/pydantic-ai/blob/main/docs/capabilities/custom.md),
2026
- and OpenClaw can
2027
- [insert loop warnings and block repeated calls](https://docs.openclaw.ai/tools/loop-detection).
2028
- These show that an agent system can alter actions or subsequent context
2029
- outside the sampler. They do not measure this proposal's speedup.
2030
-
2031
- Exact [speculative sampling](https://proceedings.mlr.press/v202/leviathan23a.html)
2032
- preserves the target distribution conditional on a given context and sampling
2033
- policy. Logical jumps choose supplied context without that requirement.
2034
- An exact speculative decoder could still accelerate free generation between
2035
- jumps.
2036
-
2037
- The search so far has not identified a direct demonstration of runtime
2038
- inference of a tool continuation from current reasoning, unverified prefill
2039
- of that continuation, and whole-agent evaluation of savings against recovery
2040
- cost. This is a bounded search finding, not a priority claim or proof of
2041
- absence. The broader unverified-copy mechanism already has overlapping work.
2042
-
2043
- A working preprint title is **Logical jump-ahead prefill: trading redundant
2044
- agent decoding for recovery cost**. The contribution to pursue is a defined
2045
- intervention mechanism, an oracle opportunity bound, an online policy, and a
2046
- measured relationship between saved decode time and recovery cost at retained
2047
- task quality. A negative or workload-dependent result would still answer the
2048
- question. The current trace analysis motivates that study; it does not yet
2049
- establish the paper's performance result. A broader literature review and
2050
- the controlled experiments above remain necessary before claiming novelty
2051
- or a practical speedup.
2052
-
2053
- ## 8. Open items
2054
-
2055
- - K3 (fill): the packed 27B positive-fill token-identity fixture passes;
2056
- held-out/adversarial token and state identity plus a paired wall-time win
2057
- remain before default-on (§7.4). Echo-tier policy levers before any
2058
- rerun (§7.3); a multi-turn showcase fixture (the single-prompt one fills
2059
- 0%); the turn-8 server-crash repro (`lab/repro/serve-crash-turn8`).
2060
-
2061
- - DSpark serving program phases 0, 1d, 1e, 1.5, 2, 3, 4, 5, 6 (§4.5) —
2062
- every GPU measurement is Josh's shell; Phase 3 (generated-forward tap)
2063
- and Phase 2 (draftBlock tightening) are agent-runnable.
2064
- - 27B Track A / Track B (§4.6; PLAN.md boxes) + 14h DSpark cross-check.
2065
- - Spec × prompt-cache composition (serve-loop v1 bypass).
2066
- - Per-slot spec under batching (unified-engine frontier row, not this
2067
- program).
2068
- - Qwen MTP wall-clock: head quantization / deferred per-draft lm-head
2069
- sampling (the 0.821× verdict's levers); the TQ-artifact divergence-flag
2070
- margin analysis (§2.1).
2071
- - Assistant drafter γ≥2 on 12B: the 262k tied-embedding argmax per draft
2072
- step is the dominant cost; capping/approximating it could extend the win
2073
- past γ=1. 26B-MoE unmeasured (expected loss — decode reads top-8/128
2074
- experts, so per-token target cost is lower than its size).
2075
- - Optional `strictVerify` (per-position verify, "spec output identical to
2076
- spec-off") — a product nicety no oracle provides; not implemented; ask.
2077
- - Verify the Eq 6 / §3.2.1 shapes against the paper PDF (both flagged in
2078
- code); paper-faithful gated RNN head and survival-product scheduler stay
2079
- Lab items.
2080
-
2081
- ## History
2082
-
2083
- - **2026-06-10** — e4b assistant drafter measured a net loss (γ=2 0.78× of
2084
- 54 tok/s, ~23% acceptance); spec ships default-off.
2085
- - **2026-06-14** — `docs/design/speculative-decoding.md` result: the verify path
2086
- had targeted the WRONG oracle (per-position lm-head to match stock decode;
2087
- no real implementation does this) — fixed with `picksBatched`, now
2088
- bit-exact to optiq `spec_generate` on e4b γ=2 (identical output and
2089
- accept/reject trace). 12B + `gemma-4-12B-it-assistant-bf16`, batched
2090
- verify, loaded machine (paired ratios only): γ=1 **1.09×** (42%
2091
- acceptance), γ=2 0.91× (29%), γ=3 0.72× (23%), γ=4 0.56× (17%) — the
2092
- earlier "net loss at every γ" (0.96/0.77/0.67/0.52×) was partly the
2093
- wrong-oracle tax. γ≥2 loses because the 12B drafter is heavy (hidden
2094
- 1024, 16 heads, 262k tied head per draft step). Clean-machine rerun
2095
- never promoted; 26B not run.
2096
- - **2026-06-29/30** — DSpark v1 (single-vector, superseded) then faithful
2097
- v2 (KV injection + Markov + confidence) built; TV-loss off-by-one found;
2098
- overfit τ 3.24 proves the architecture (M1 Max 32 GB, e4b).
2099
- - **2026-07-06** — Serve integration: the seam extended to carry target
2100
- state (TargetView, tapLayers, ctx flow); provider selection by artifact
2101
- kind; γ pinned to the trained block. Paper components code-complete
2102
- (pruning, calibration, RNN variant, loop tightening, `dspark` rename +
2103
- loader). DeepSpec audit: our loss/heads match the paper; the released
2104
- scheduler is threshold-truncation, not the paper's STS/Alg-1; DeepSpec's
2105
- temp-0 trace becomes the oracle. Tests 21/21 smoke, 17/17 dspark files,
2106
- 3/3 real-weights serve gate.
2107
- - **2026-07-07** — DeepSpec port first live run on 12B (τ≈2.8, 26–33%
2108
- acceptance, wall-clock −3.4× on a loaded M4 Pro 24 GB); the serving
2109
- program written; 1a/1b/1c landed the same day; oracle prefill convention
2110
- re-anchored to mlx-lm's spec shape (4/4 token-for-token incl. knife-edge);
2111
- accepted-draft EOS leak fixed.
2112
- - **2026-08-17/18** — Qwen native MTP: DeltaNet rollback solved via the
2113
- spec-round snapshot/replay contract (bit-exact by construction, gated);
2114
- 27B pairing gate token-identical (88% = 30/34, 2.82 tok/forward); quiet
2115
- M1 Max A/B 0.821× at γ=2 (61% acceptance) — durable negative perf
2116
- verdict, opt-in only; drafter-logit parity vs mlx-vlm 0.6.14 exact
2117
- through the chained block. TQ artifact gauntlet: MTP 76% accept / 2.53
2118
- tok/forward with a divergence flag, not claimed lossless.
2119
- - **2026-08-19** — 27B program (Track A / Track B) recorded, queued behind
2120
- the certification suite.
2121
- - **2026-08-20** — MTP `[1,V]` sampler-shape fix (serve-lane 500 under
2122
- top-k); GLM native MTP source carries the same note.
2123
- - **2026-08-23** — DSpark scripts consolidated under `scripts/dspark.ts
2124
- <job>`; one-off measure/compare/bench scripts deleted (git history); this
2125
- doc consolidates the three design docs.
2126
- - **2026-09-02** — K3 live A/B on the 27B (§7.3): echo tier injects 7.4%
2127
- but wall clock ×1.00 (76% verify rejection) — gate FAILS, stays Lab; batch
2128
- lane never fills; strict rows were silently empty on thinking templates
2129
- (primer newline merge) — fixed.