mlx-bun 0.3.0 → 0.5.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 (231) hide show
  1. package/README.md +57 -32
  2. package/docs/README.md +58 -42
  3. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +3617 -0
  4. package/docs/archive/investigations/openjarvis-fit.md +198 -0
  5. package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
  6. package/docs/archive/planning/release-notes-v0.4.0.md +45 -0
  7. package/docs/archive/planning/release-notes-v0.5.0.md +37 -0
  8. package/docs/design/batching.md +1535 -50
  9. package/docs/design/decode-speed-program.md +394 -1171
  10. package/docs/design/generic-model-support.md +195 -3
  11. package/docs/design/kv-cache.md +538 -225
  12. package/docs/design/speculative-decoding.md +552 -50
  13. package/docs/design/turboquant.md +140 -17
  14. package/docs/design/unified-engine-frontier-plan.md +259 -150
  15. package/docs/planning/PRODUCT_ROADMAP.md +21 -6
  16. package/docs/planning/public-readiness-handoff.md +244 -0
  17. package/docs/planning/public-readiness.md +149 -0
  18. package/docs/reference/benchmarks.md +3537 -1112
  19. package/docs/reference/cli.md +102 -2
  20. package/docs/reference/distribution.md +45 -13
  21. package/docs/reference/environment.md +159 -13
  22. package/docs/reference/library-api.md +18 -4
  23. package/docs/reference/memory.md +1 -1
  24. package/docs/reference/models.md +28 -7
  25. package/docs/reference/server-api.md +257 -33
  26. package/docs/reference/server-config.md +372 -151
  27. package/docs/reference/troubleshooting.md +13 -21
  28. package/package.json +2 -2
  29. package/src/audio/audiotoolbox.ts +112 -0
  30. package/src/audio/conformer.ts +8 -0
  31. package/src/audio/mic-capture.ts +98 -0
  32. package/src/audio/silero-vad.ts +379 -0
  33. package/src/audio/whisper-decode.ts +774 -0
  34. package/src/audio/whisper-fast.ts +732 -0
  35. package/src/audio/whisper-format.ts +73 -0
  36. package/src/audio/whisper-mel.ts +185 -0
  37. package/src/audio/whisper-timing.ts +274 -0
  38. package/src/audio/whisper-tokenizer.ts +239 -0
  39. package/src/audio/whisper-transcribe.ts +410 -0
  40. package/src/backends/mlx/assistant-target.ts +46 -0
  41. package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
  42. package/src/backends/mlx/autoregressive.ts +22 -1
  43. package/src/backends/mlx/batch-group.ts +464 -236
  44. package/src/backends/mlx/cache-attachment.ts +67 -0
  45. package/src/backends/mlx/cache-layout.ts +31 -0
  46. package/src/backends/mlx/checkpoint-state.ts +53 -0
  47. package/src/backends/mlx/continuation-persistence.ts +107 -0
  48. package/src/backends/mlx/continuation-request.ts +43 -0
  49. package/src/backends/mlx/continuation.ts +77 -0
  50. package/src/backends/mlx/draft-target.ts +7 -22
  51. package/src/backends/mlx/encoder-cache.ts +25 -0
  52. package/src/backends/mlx/fill-append.ts +21 -8
  53. package/src/backends/mlx/fill-group.ts +497 -0
  54. package/src/backends/mlx/full-kv-row-append.ts +32 -0
  55. package/src/backends/mlx/full-kv-row-donor.ts +54 -0
  56. package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
  57. package/src/backends/mlx/gateway-binding.ts +122 -19
  58. package/src/backends/mlx/kv-codec.ts +9 -0
  59. package/src/backends/mlx/kv-maintenance.ts +161 -0
  60. package/src/backends/mlx/kv-tensor-rows.ts +212 -0
  61. package/src/backends/mlx/mixed-iteration.ts +62 -0
  62. package/src/backends/mlx/model-prompt.ts +46 -32
  63. package/src/backends/mlx/model-serving.ts +5 -4
  64. package/src/backends/mlx/paged-cache-codec.ts +27 -0
  65. package/src/backends/mlx/prefill-cohort.ts +100 -0
  66. package/src/backends/mlx/prefill-policy.ts +26 -0
  67. package/src/backends/mlx/prefill-rows.ts +244 -0
  68. package/src/backends/mlx/prefill.ts +1 -1
  69. package/src/backends/mlx/projected-context-rows.ts +72 -0
  70. package/src/backends/mlx/prompt-input.ts +29 -0
  71. package/src/backends/mlx/qwen-prompt-input.ts +40 -0
  72. package/src/backends/mlx/request-state-policy.ts +54 -0
  73. package/src/backends/mlx/rollback.ts +45 -4
  74. package/src/backends/mlx/row-sampling.ts +49 -0
  75. package/src/backends/mlx/serial-executor.ts +51 -73
  76. package/src/backends/mlx/speculative-group.ts +438 -0
  77. package/src/backends/mlx/speculative-round.ts +161 -0
  78. package/src/backends/mlx/speculative.ts +24 -7
  79. package/src/backends/mlx/state-rows.ts +104 -0
  80. package/src/backends/mlx/state-views.ts +21 -1
  81. package/src/backends/mlx/target-layout-capability.ts +35 -0
  82. package/src/backends/mlx/transitioning-kv-rows.ts +173 -0
  83. package/src/cli.ts +333 -36
  84. package/src/contracts/execution.ts +21 -0
  85. package/src/contracts/object-cache.ts +8 -0
  86. package/src/contracts/pi-provider.ts +1 -1
  87. package/src/contracts/pi.ts +3 -1
  88. package/src/contracts/prefix-cache.ts +33 -0
  89. package/src/contracts/resources.ts +7 -0
  90. package/src/contracts/sampling.ts +23 -0
  91. package/src/contracts/scheduling.ts +27 -0
  92. package/src/engine/execution-plan.ts +38 -25
  93. package/src/engine/execution-tasks.ts +44 -0
  94. package/src/engine/namespaced-cache.ts +13 -0
  95. package/src/engine/resources.ts +12 -1
  96. package/src/engine/scheduler.ts +32 -7
  97. package/src/fill/fill-session.ts +14 -3
  98. package/src/fit.ts +29 -15
  99. package/src/generate.ts +105 -195
  100. package/src/grammar.ts +13 -0
  101. package/src/inference/draft-acceptance.ts +41 -0
  102. package/src/inference/draft-output.ts +49 -0
  103. package/src/inference/prefill.ts +6 -0
  104. package/src/inference/rollback.ts +2 -2
  105. package/src/kv-scheme.ts +92 -12
  106. package/src/kv-store.ts +183 -93
  107. package/src/lab/README.md +5 -1
  108. package/src/lab/paged-kv/paged-attention.ts +117 -0
  109. package/src/lab/paged-kv/paged-kv-rows.ts +111 -0
  110. package/src/lab/paged-kv/paged-kv.ts +126 -46
  111. package/src/md-modules.d.ts +5 -0
  112. package/src/mlx/array.ts +39 -1
  113. package/src/mlx/ffi.ts +19 -0
  114. package/src/mlx/normalized-argmax.ts +116 -0
  115. package/src/mlx/ops.ts +97 -10
  116. package/src/model/artifact-identity.ts +73 -0
  117. package/src/model/batched-kv.ts +235 -0
  118. package/src/model/batched-mask.ts +12 -4
  119. package/src/model/batched-quant.ts +8 -2
  120. package/src/model/batched-quantized-kv.ts +144 -0
  121. package/src/model/batched-rotating-quant.ts +76 -15
  122. package/src/model/batched-rotating-state.ts +76 -0
  123. package/src/model/batched-rotating.ts +64 -22
  124. package/src/model/batched-row-storage.ts +52 -0
  125. package/src/model/batched-ssm.ts +52 -0
  126. package/src/model/batched-turboquant-kv.ts +94 -0
  127. package/src/model/compiled-decode.ts +7 -1
  128. package/src/model/decoded-kv-donor.ts +12 -0
  129. package/src/model/delayed-quantized-kv.ts +72 -0
  130. package/src/model/delayed-rotating-quantized-kv.ts +93 -0
  131. package/src/model/delayed-turboquant-kv.ts +57 -0
  132. package/src/model/factory.ts +26 -0
  133. package/src/model/fingerprint.ts +12 -0
  134. package/src/model/full-prefill-padding.ts +56 -0
  135. package/src/model/full-prefill-row.ts +105 -0
  136. package/src/model/gemma4-base.ts +183 -82
  137. package/src/model/gemma4.ts +116 -28
  138. package/src/model/generated/gemma4-12b.ts +4 -1
  139. package/src/model/generated/gemma4-26b.ts +4 -1
  140. package/src/model/generated/gemma4-e4b.ts +4 -1
  141. package/src/model/glm52-cache.ts +80 -4
  142. package/src/model/glm52-mla.ts +12 -6
  143. package/src/model/glm52.ts +19 -40
  144. package/src/model/kv-attention-view.ts +70 -0
  145. package/src/model/minicpm5.ts +11 -7
  146. package/src/model/profile.ts +29 -4
  147. package/src/model/quantized-append-attention.ts +31 -0
  148. package/src/model/qwen3-delta-state.ts +74 -0
  149. package/src/model/qwen3-delta.ts +59 -36
  150. package/src/model/qwen3-mrope.ts +7 -9
  151. package/src/model/qwen3_5.ts +177 -75
  152. package/src/model/rotating-kv-donor.ts +35 -0
  153. package/src/model/rotating-kv-layout.ts +262 -0
  154. package/src/model/rotating-row-transaction.ts +35 -0
  155. package/src/model/speculative-rotating-kv.ts +101 -0
  156. package/src/model/ssm-prefill-padding.ts +39 -0
  157. package/src/model/support.ts +8 -0
  158. package/src/model/token-groups.ts +66 -0
  159. package/src/model/trellis-linear.ts +4 -4
  160. package/src/model/turboquant-codec.ts +89 -0
  161. package/src/model/universal/dense.ts +14 -13
  162. package/src/model/whisper.ts +435 -0
  163. package/src/native/mic_capture.swift +92 -0
  164. package/src/native-pack.ts +6 -5
  165. package/src/pi-web.ts +9 -1
  166. package/src/preflight.ts +31 -15
  167. package/src/prompt-cache.ts +306 -86
  168. package/src/runtime-config.ts +1 -5
  169. package/src/safetensors.ts +9 -2
  170. package/src/sampler.ts +37 -25
  171. package/src/serve/audio-routes.ts +323 -0
  172. package/src/serve/chat-request.ts +2 -0
  173. package/src/serve/chat-stage.ts +19 -14
  174. package/src/serve/completion-executor.ts +9 -1
  175. package/src/serve/discovery-routes.ts +17 -1
  176. package/src/serve/generated-token-history.ts +57 -0
  177. package/src/serve/generation-gateway.ts +88 -38
  178. package/src/serve/model-binding.ts +7 -1
  179. package/src/serve/model-host.ts +3 -4
  180. package/src/serve/preparation.ts +3 -3
  181. package/src/serve/prompt-response-trace.ts +14 -0
  182. package/src/serve/request-plan.ts +6 -3
  183. package/src/serve/request-prep.ts +40 -25
  184. package/src/serve/text-completion-stage.ts +2 -2
  185. package/src/serve/transcription-server.ts +64 -0
  186. package/src/serve/transcription-service.ts +502 -0
  187. package/src/server.ts +185 -261
  188. package/src/spec/assistant-rows.ts +93 -0
  189. package/src/spec/assistant-source.ts +28 -18
  190. package/src/spec/cache-identity.ts +22 -0
  191. package/src/spec/deepspec-rows.ts +29 -0
  192. package/src/spec/deepspec-source.ts +12 -10
  193. package/src/spec/dflash-source.ts +28 -4
  194. package/src/spec/drafter.ts +153 -142
  195. package/src/spec/dspark/deepspec-module.ts +95 -120
  196. package/src/spec/dspark/module-dflash.ts +126 -170
  197. package/src/spec/glm52-mtp-graph.ts +29 -0
  198. package/src/spec/glm52-mtp-rows.ts +132 -0
  199. package/src/spec/glm52-mtp-source.ts +54 -136
  200. package/src/spec/glm52-mtp-state.ts +33 -0
  201. package/src/spec/ngram-source.ts +115 -21
  202. package/src/spec/projected-draft-rows.ts +73 -0
  203. package/src/spec/qwen-mtp-module.ts +171 -0
  204. package/src/spec/qwen-mtp-rows.ts +230 -0
  205. package/src/spec/qwen-mtp-source.ts +84 -226
  206. package/src/spec/qwen-mtp-state.ts +30 -0
  207. package/src/spec/serve-loop.ts +73 -69
  208. package/src/spec/source.ts +93 -15
  209. package/src/spec/two-model-rows.ts +62 -0
  210. package/src/spec/two-model.ts +45 -103
  211. package/src/ssd-cache.ts +107 -36
  212. package/src/ssd-durability.ts +29 -27
  213. package/src/storage/host-buffer.ts +24 -0
  214. package/src/storage/kv-writer.ts +83 -0
  215. package/src/storage/kv-writer.worker.js +264 -0
  216. package/src/storage/retention-policy.ts +37 -0
  217. package/src/tiered-prompt-cache.ts +45 -0
  218. package/src/vision/embedder.ts +8 -0
  219. package/src/vision/prompt.ts +101 -65
  220. package/src/vision/qwen3vl-prompt.ts +101 -64
  221. package/src/vision/qwen3vl-tower.ts +11 -0
  222. package/src/vision/siglip.ts +8 -0
  223. package/src/web/app.html +12 -0
  224. package/src/web/app.js +217 -57
  225. package/src/web/src/chat.ts +4 -1
  226. package/src/web/src/composer.ts +3 -0
  227. package/src/web/src/voice.ts +141 -0
  228. package/src/web/sw.js +1 -1
  229. package/src/backends/mlx/memory-guard.ts +0 -40
  230. package/src/spec/prefix-state.ts +0 -45
  231. /package/docs/{planning → archive/planning}/release-notes-v0.3.0.md +0 -0
@@ -3,7 +3,7 @@ status: active
3
3
  axis: ON
4
4
  canonical-for: batching
5
5
  plan-anchor: "Phase 18 — Concurrent / batched serving (slots) + parallel load benchmark `[~]` (2026-06-13)"
6
- last-verified: 2026-08-23
6
+ last-verified: 2026-09-10
7
7
  ---
8
8
 
9
9
  # Batching — continuous scheduling for `--batch N`
@@ -19,6 +19,14 @@ docs/design/kv-cache.md. Status and dated progress live in PLAN.md (see the
19
19
  plan anchor above); this file describes the mechanism as it exists and
20
20
  what is still open.
21
21
 
22
+ Phase 6 now requires shared method/session execution at B=1 and B>1, full
23
+ batch feature parity, and configuration organized by owning interface. The
24
+ boundaries are defined in [engine architecture §12.5–12.7](unified-engine-frontier-plan.md#125-capability-negotiation-and-planning).
25
+ The separate serial mechanism described below is the current implementation;
26
+ retiring its duplicate lifecycle is open work. Backend specializations may
27
+ remain when they improve measured performance. R17 owns output checkpoint
28
+ publication to the shared RAM/SSD cache.
29
+
22
30
  User-facing mirror: docs/reference/server-config.md ("Execution modes",
23
31
  compatibility matrix, known limitations) and docs/reference/cli.md.
24
32
 
@@ -84,7 +92,9 @@ and the engine runs its B=1 fast path (§4.4).
84
92
  - **Never downgrade a composition to make it batchable.** Placement is a
85
93
  support check only: it does not strip MTP/drafting, KV schemes,
86
94
  TurboQuant, grammar, adapters, or sampling. A composition the scheduler
87
- does not implement runs unchanged on the serial mechanism.
95
+ does not implement runs unchanged on the serial mechanism today. That
96
+ fallback preserves behavior during migration; it does not meet the new
97
+ batch feature-parity requirement.
88
98
  - **Drain, never starve.** A serial-lane waiter pauses admission; running
89
99
  rows finish; the lock hands over FIFO; admission resumes (mlx-lm
90
100
  `drain_batch`). One `AsyncMutex` is the single exclusion domain for
@@ -108,10 +118,11 @@ and the engine runs its B=1 fast path (§4.4).
108
118
  `setImmediate` hop costs microseconds; there is nothing to dodge.
109
119
  Reverted; the per-yield step is the measured optimum. Don't re-add
110
120
  without new evidence.
111
- - **Spec decode and batching are different mechanisms.** A mounted
112
- `--draft-model` routes every request serial (upstream
113
- `is_batchable = draft is None`); per-row speculation inside the batch
114
- is a research question, not a feature gap.
121
+ - **Spec decode and scheduling are separate concerns.** A mounted
122
+ `--draft-model` selects speculation only for compatible requests. Ordinary
123
+ fallback requests can batch when their actual features permit it. Concurrent
124
+ speculation is an explicit feature gap in the shared-execution program;
125
+ accepted lengths and target/draft state belong to the decode method.
115
126
 
116
127
  ## 3. Scheduling seam — `GenerationGateway`
117
128
 
@@ -125,13 +136,10 @@ continuous iff
125
136
  model is not DiffusionGemmaModel (non-autoregressive)
126
137
  AND batch > 1
127
138
  AND #modelCachesBatchable() (cache-capability gate, below)
128
- AND !hasVision (offset-0 prefill + bidirectional mask)
129
- AND !hasAdapters (loraState is one global field)
130
- AND !wantsLogprobs (batch sampler does not capture logprob arrays)
131
- AND !userSeed (reproducibility ⇒ solo, matches mlx-lm)
132
- AND !(kvQuant AND !#kvBatchable()) (scheme must be a batchable per-layer config)
133
- AND !turboQuant (solo-only v1; belt on top of the capability braces)
134
- AND !hasDraft (spec is a B=1 mode)
139
+ AND (!hasVision OR model supports prepared media input)
140
+ AND adapter state supports compatible groups (when adapters are selected)
141
+ AND KV scheme supports the loaded cache layouts
142
+ AND selected method has a grouped implementation
135
143
  AND !(hasGrammar AND MLX_BUN_GRAMMAR_BATCH=0)
136
144
  ```
137
145
 
@@ -154,17 +162,17 @@ server.py's all-caches-have-`merge` check), memoized from a fresh
154
162
  merge/extract/filter and byte projection), or `SSMCache` (Qwen3.5's
155
163
  gated-DeltaNet state; `MLX_BUN_BATCH_SSM=0` removes it → serial).
156
164
 
157
- **KV-scheme gate** (`#kvBatchable`): the server's resolved `KvScheme`
158
- batches iff `kind === "affine-config"` and `scheme.batchable()` holds
159
- with every configured layer a plain `KVCache` or plain `RotatingKVCache`.
160
- Uniform `--kv-quant 4|8` (quantizedKvStart threshold semantics) and
161
- `turbo` route serial with a startup warning. The scheme is threaded to
162
- the scheduler only when this passes; the scheduler re-checks at
163
- construction and throws on an unsupported scheme (never bf16 service
164
- with quantized accounting).
165
-
166
- Startup refusals (server.ts): `--paged-kv` with `--batch N>1` throws
167
- (paged caches can't merge); GLM `--mtp on` (its default) mounts the MTP
165
+ **KV-scheme capability:** the resolved `KvScheme` qualifies per-layer affine,
166
+ start-zero uniform affine, and ordinary TurboQuant with immediate or delayed
167
+ conversion through actual cache and layout support. The MLX layout binding
168
+ creates encoded rows; scheduling does not encode or decode KV. Qualified methods
169
+ share delayed affine/TurboQuant conversion and per-layer affine policies through
170
+ these row interfaces; TurboQuant sliding layers remain bf16.
171
+ Unsupported compositions retain the existing serial route until their shared implementation and acceptance are complete.
172
+
173
+ Paged Gemma4 bf16 requests compose through `PagedKvRows`; the request state
174
+ policy supplies block storage and prompt-cache bypass without changing scheduling.
175
+ GLM `--mtp on` (its default) mounts the MTP
168
176
  drafter and therefore routes serial+spec — `--mtp off` exposes ordinary
169
177
  GLM batching.
170
178
 
@@ -308,13 +316,30 @@ dense model, the scheduler replays the serial engine's compiled step
308
316
  transactional: the scheduler permanently falls back to the graph path.
309
317
 
310
318
  **Vectorized homogeneous sampling.** When every live row is plain greedy
311
- (`plainGreedy` from the gateway: temperature 0, no processors, no
319
+ (`plainGreedy` from the gateway: temperature 0, no logprob capture, no processors, no
312
320
  grammar), one `toLogprobs` + `argmaxAxis` over `[B,V]` replaces B
313
321
  slice/sample/concat graphs — per-row identical math, tie behavior
314
322
  included. `MLX_BUN_BATCH_VEC_SAMPLE=0` forces the per-row closure path.
315
323
  Length-doomed rows get a placeholder slot (never emitted; one KV write
316
324
  on their own about-to-evict row).
317
325
 
326
+ **Sampling boundary.** `contracts/sampling.ts` defines `SamplingSession`:
327
+ borrow model logits, apply request-owned processing/selection, return the
328
+ chosen token and optional probability tensors. Device and host-token MLX
329
+ samplers implement the same generic contract. `createRowSampling` accepts a
330
+ sampler through that interface and binds its captures to output delivery.
331
+ The scheduler receives token tensors and a callback, with no probability
332
+ retention policy. Captures are evaluated with their token and retained by
333
+ request-local step until emission; cancellation and unconsumed lookahead
334
+ release them. Token-only requests retain the existing vectorized shortcut.
335
+ Explicit seeds no longer determine scheduler placement. The seed and local
336
+ sample index select the random key, independently of sibling requests.
337
+ Reproducibility is conditional on the same numerical execution composition,
338
+ not a promise of equal logits across different batch shapes. The preserved
339
+ `--batch 1` control supplies the earlier fixed-shape behavior.
340
+ Vectorized logprob capture and the broader sampling-kernel interface remain
341
+ optimization work; this change establishes no performance dominance.
342
+
318
343
  **Grammar rows** (`#stepGrammar`): read the previous register *before*
319
344
  building the graph (the matcher's `accept` needs JS numbers), `accept()`
320
345
  per live grammar row (fires async bitmask fills that overlap the graph
@@ -348,8 +373,12 @@ dropped (`dropOnly`, never put). A prefill error rejects only the joiner.
348
373
  **Eviction** (`#applyFilter(keep)`): `filterRows` on batched/owned
349
374
  caches; `filterKVRows` / `filterQuantRows` (B-axis `takeAxis`) on full
350
375
  layers; the pending register and `#pendingReal` flags are filtered in
351
- lockstep. Full-layer filter keeps stale left padding (no `min_left_pad`
352
- shift-left) — width waste, not correctness (open, §8).
376
+ lockstep. Full layers also remove the minimum left padding shared by all
377
+ survivors, matching `mlx-lm BatchKVCache.filter`. Buffer width and per-row
378
+ padding shrink together, preserving absolute RoPE positions. Quantized full
379
+ layers slice the token axis of packed/scales/biases together; rotating layers
380
+ retain their separate layout. Keeping those unused columns can change logits
381
+ through a different attention reduction shape.
353
382
 
354
383
  **Finish-time prompt-cache put.** A lone never-merged row hands its
355
384
  adopted serial-class caches back zero-copy, keyed by `promptIds + fed`
@@ -444,7 +473,7 @@ consistency check only, never the gate.
444
473
  | rotating merge/decode/mask/filter incl. ring wrap vs mlx-lm; generic row-storage state | `tests/batched-rotating.test.ts`, `batched-rotating-state.test.ts` | fast, oracle |
445
474
  | static B=2 + dynamic join/leave + extend-join vs mlx-lm (CPM, Gemma 12B/e4b/26B, Llama 3B Tier-0) | `tests/batched-decode-parity.test.ts` (`MLX_BUN_TEST_BATCH_DECODE=1`) | gated, oracle |
446
475
  | Qwen3.5 SSM batched vs mlx-lm B=2 | `tests/qwen35-batched-parity.test.ts` | gated, oracle |
447
- | scheduler orchestration (admit/step/evict/join) | `tests/batch-scheduler.test.ts` | gated (teacher-forced KL + 12B golden) |
476
+ | scheduler orchestration (admit/step/evict/join) | `tests/batch-scheduler.test.ts` | gated, exact live same-B protocol oracle (CPM and Gemma 12B) |
448
477
  | per-row containment, drain, full-attention join routing | `tests/batch-containment.test.ts` | gated |
449
478
  | rotating-layer join mid-decode (2026-08-22 regression) | `tests/batch-rotating-join.test.ts` | gated |
450
479
  | KV-budget queueing + projection math | `tests/batch-kv-budget.test.ts`, `kv-budget-projection.test.ts` | gated / fast |
@@ -454,6 +483,28 @@ consistency check only, never the gate.
454
483
  | per-row extract == solo bytes | `tests/batched-extract.test.ts` | fast |
455
484
  | live server: engage, `/stats`, SSE fan-out, serial coexistence | `tests/batch-serving.test.ts` | gated smoke |
456
485
 
486
+ Closeout recheck (2026-09-08, Apple M1 Max 32 GB, Bun 1.4.0,
487
+ MLX 0.32.2): the old Gemma solo-KL bound failed even though all 24 captured
488
+ simultaneous-admission vectors matched the same-B oracle exactly. Replaying
489
+ the mid-stream join exposed a separate mismatch in two later vectors: the
490
+ native full cache retained padding that `BatchKVCache.filter` removes.
491
+ The scheduler now performs that removal. The live protocol gate passes all
492
+ 48 full-vector hashes on each of MiniCPM5 and Gemma 12B, including row
493
+ retirement and a join triggered after two emitted tokens. The oracle receives
494
+ inputs and row/step identities, never the native expected hashes. It uses
495
+ mlx-lm merge/extend/filter operations and ordinary full-attention KV caches
496
+ when the reference state has no padding, matching serving's scalar-position
497
+ policy. No tolerance was increased and no golden was regenerated.
498
+
499
+ Production oracle: `scripts/oracle/batch-scheduler-reference.py`. Initial
500
+ capture and comparison: `reports/qwen38-closeout/gemma-protocol/`.
501
+ Before/after gates: `gemma-protocol-gate.log`,
502
+ `gemma-protocol-filter-trim-gate.log`, `batch-protocol-final-gate.log`.
503
+ The original unchanged-HEAD failure remains in
504
+ `memory-baseline-batch-scheduler.log`. Quantized slice and broader serving
505
+ checks accompany the filter change; M4 campaign acceptance remains separate.
506
+
507
+
457
508
  Benchmark harness: `scripts/bench-matrix.ts features` (six-cell
458
509
  composition matrix over live SSE: TTFT p50/p95 at the first SSE token,
459
510
  wall-clock aggregate tok/s, schema conformance as a hard gate);
@@ -463,37 +514,333 @@ naive tok/s — use wall-clock.
463
514
 
464
515
  ## 8. Open items
465
516
 
517
+ ### Consolidation matrix
518
+
519
+ This is the implementation gap inventory, not a claim that all combinations
520
+ have passed acceptance. Phase 6 coordinates the work; Phase 18 tracks its
521
+ batch cells. Current placement rules are in `src/engine/execution-plan.ts`.
522
+
523
+ The window-crossing scheduler gate in `tests/parity/batch-scheduler.test.ts`
524
+ now passes on Gemma 12B and e4b on both development machines. Two rows cross
525
+ the sliding window during decode; a third begins beyond it and joins late.
526
+ The pinned oracle replays the same admissions, merges and retirements and
527
+ compares every sampled full float32 logit vector. Run with
528
+ `MLX_BUN_TEST_BATCH_RING_WRAP=1`; `MLX_BUN_TEST_BATCH_RING_MODEL` selects the
529
+ existing artifact. Evidence is recorded in benchmarks.md.
530
+
531
+ Josh revised the immediate objective to shared batching by default with
532
+ effectively equal measured single-request performance. Serving already defaults
533
+ to a concurrency cap of eight, with B1 execution for a lone eligible request.
534
+ Explicit `--batch 1` and compatibility routing retain serial. Removing that
535
+ executor is deferred; complete feature parity is follow-up work, not a blocker
536
+ for the current default. Supported ordinary requests use the shared method.
537
+ Compare single-request B=1 latency, cold/cached
538
+ prefill and sustained decode as well as concurrent throughput. Record memory,
539
+ cache reuse and actual admitted rows. Keep kernel settings fixed for the
540
+ refactor comparison; measure new kernel optimizations in separate experiments.
541
+ Keep measured single-request regressions and unsupported features explicit.
542
+ They do not require repeating completed checks or withholding the current default.
543
+
544
+ | Concern | Current implementation | Required completion |
545
+ |---|---|---|
546
+ | Scheduling and ordinary decode | Default cap eight uses shared execution at B1/B>1; explicit `--batch 1` retains serial | Keep the batched default using existing measurements; address specific regressions separately. Serial removal is deferred |
547
+ | Speculative decode | Qwen MTP, prompt lookup, standalone, assistant, DeepSpec and seeded DSpark/DFlash providers are integrated through shared B1/B>1 interfaces, with the native/HTTP/cache checks recorded below | Finish specific unsupported combinations and measured regressions; GLM artifact testing is deferred and no trained DSpark/DFlash checkpoint exists |
548
+ | Sampling and logprobs | Shared sampler contract; ordinary groups capture logprobs and accept explicit seeds | Extend same-B oracle/feature compositions and matched performance; preserve per-request RNG/history |
549
+ | Grammar and fill | Shared grammar proposals use grouped verification. Shared strict fill composes prefill, rows, sampling and committed append; native and HTTP/cache/timing gates pass | Shared echo uses grouped verification and row rollback; Qwen MTP consumes verified echo through the provider interface. Asserted fill with speculation, other providers and other named combinations remain. Keep grammar proposals opt-in after mixed timing results |
550
+ | Adapters and media | Compatible adapter groups use shared execution; Gemma4 image/audio and Qwen image/video inputs, encoder caching and generated media-prefix reuse pass native/HTTP and M4 comparisons | Chunked media prefill, lone-media latency costs, adapter performance and broader compositions |
551
+ | KV layout | Full and rotating affine/TurboQuant layouts, delayed/per-layer transitions, speculative donors and ordinary paged storage are integrated and tested below | C1–C5 add shared SSD blocks and optional direct bf16/affine paged attention with native/HTTP evidence. TQ pages and paged speculation remain extensions; reuse completed row-layout gates |
552
+ | Prefix and output reuse | Ordinary and grouped methods publish generated target/companion state to one RAM/SSD cache | Native/HTTP and full Kanban retention/durability acceptance are complete; investigate new regressions without reopening unchanged gates |
553
+ | Generation resume | Shared ordinary resume is integrated after both-machine native/HTTP compiled, quantized/delayed and mixed-grammar checks, combined suites and eight M4 timing arms. The packed-model fixture now owns fresh weights per server | Adapter resume is integrated through the same policy; native/HTTP composition checks accompany it. Reuse the completed ordinary resume evidence |
554
+ | Usage and cleanup | The gateway forwards timing/rates; the missing first-token timestamp in ordinary batch admission is now fixed | Consistent events/accounting, row cancellation, failure cleanup and persistence on shutdown |
555
+ | Configuration | Bound configuration reaches each owner, including delayed KV conversion, copied codecs and paged cache identity; the flag-owner inventory is complete | Preserve the contract when adding settings; completed policy tests and fixed-settings performance remain accepted |
556
+
557
+ ### Prepared media and execution tasks
558
+
559
+ `MlxPromptInput` lets the model binding consume prepared embeddings and return
560
+ an owned final hidden row. `MlxPrefillCohort` retains initialization, precision
561
+ maintenance, projection and completion. An indivisible media attention span
562
+ declines prefill joins and mixed token packing; it processes the whole prompt
563
+ before entering ordinary shared decode. Sampling, row merging, retirement and
564
+ cancellation remain in their existing owners. Prepared media producers supply
565
+ an opaque identity for their exact media, encoder and preceding token prefix.
566
+ The ordinary cache combines this with the adapter namespace to retain generated
567
+ conversation state in RAM/SSD. Inputs without that identity remain uncached;
568
+ token IDs alone do not identify media contents. The input binding resumes
569
+ positioned text from the retained offset. Cache ownership and precision boundaries
570
+ are described in [kv-cache](kv-cache.md#514-prepared-media-prefix-identity).
571
+
572
+ Native preparation uses `ExecutionTasks` through the portable scheduler's
573
+ optional task boundary. The queue owns cancellation and failure settlement;
574
+ the scheduler owns when to advance it under the existing execution lease.
575
+ A task cannot replace model state. Exclusive mutations retain drain priority,
576
+ including a waiter arriving while preparation is running. Started work settles
577
+ before its owner releases native resources. The queue uses the portable
578
+ cancellation contract; the MLX binding adapts request AbortSignals.
579
+ `ModelPromptBuilder` receives a `PromptNativeWork` callback. Media downloads
580
+ and container transcoding finish outside that callback; lazy tower loading
581
+ and native prompt construction enter it. Encoder-local preprocessing remains
582
+ part of prompt construction. Grammar compilation enters the same execution
583
+ domain without putting template rendering or tokenization on the queue.
584
+
585
+ Gemma4 binds image/audio embeddings to this input interface. Qwen binds
586
+ image/video embeddings and a `MlxDecodeState` carrying each request's position
587
+ delta. The backend passes the current row order to that state after joins and
588
+ retirement. Its forward uses the cache's logical position array on device;
589
+ attention receives explicit positions without a module-global variable.
590
+ Input-state compatibility remains separate from cache-layout compatibility.
591
+ Media forwards with additional position state decline mixed-token packing.
592
+ Qwen image/video preprocessing completes outside the native execution lease.
593
+ Exact encoder features now use the shared cache object port; SSD reads finish
594
+ before native preparation. Cache placement remains independent of batching.
595
+ Diffusion retains its separate method. Qwen's source-controlled native comparison
596
+ and padded B1/B2/B4 affine/TurboQuant checks pass on both Macs, as do real image
597
+ HTTP checks on the packed 27B. The M4 image/video ABBA comparison preserves full
598
+ usage with faster concurrent completion; different batch geometries change some
599
+ responses. See [Qwen media evidence](../reference/benchmarks.md#shared-qwen-image-and-video-execution-2026-09-13)
600
+ for the source identity checks, probe correction and latency costs.
601
+ The input and task tests cover atomic boundaries, final projection geometry,
602
+ full same-machine Gemma logits/cache/continuation, active B1/B2 logit identity,
603
+ cancellation and mutation priority. Both-machine audio HTTP checks preserve the existing
604
+ transcription golden, exercise actual B2 decode and complete text generation
605
+ while an audio download is held open. The complete model-free suite and all
606
+ three TypeScript projects pass. The M4 ABBA media comparison preserves every
607
+ response and token count; concurrent completion improves with documented lone-
608
+ request and first-submitted-request costs in [benchmarks.md](../reference/benchmarks.md#shared-gemma-media-execution-2026-09-13);
609
+ see `tests/parity/shared-media-input.test.ts` and
610
+ `reports/prefill-observation/shared-media-*`.
611
+
612
+ Tests must exercise actual B>1 work, not requests routed back to serial.
613
+ Completed checks remain evidence for their recorded source and settings. A new
614
+ run needs a named changed behavior, uncovered case or reproduced failure;
615
+ an open umbrella row is not a reason to repeat all its passing checks.
616
+ The working tree now has a shared transaction lifecycle for request-owned
617
+ acceptance counts. Recurrent state and attention KV implement the same round
618
+ operations. Attention rollback changes logical coverage without moving KV;
619
+ subsequent appends overwrite rejected tips. Positions, masks, extraction,
620
+ empty draft prefixes, late joins and retirement belong to that storage layout.
621
+ A singleton preserves allocated prefill capacity and uses the existing scalar
622
+ RoPE and causal-mask operations. Removing the longest recurrent row now updates
623
+ the group's maximum coverage to its survivors.
624
+
625
+ `MlxStateRows` applies admission, filtering and extraction through layer-owned
626
+ row layouts. Attention KV and `BatchedSSMCache` implement the same port; the
627
+ collection contains no model-family branches or persistence policy. Admission
628
+ borrows prepared state and builds all layer replacements before releasing the
629
+ active collection. Unit checks cover reorder, extraction, removal of every row,
630
+ reuse, donor ownership and failed admission. Full-target MTP controls preserve
631
+ all retained state at B=1/2/4 on both Macs through this collection.
632
+
633
+ The affine row layout composes those same position/retention
634
+ operations for affine KV's packed values, scales and biases. It adds no
635
+ dequantization to joins, rollback or extraction. Qwen attention consumes a
636
+ quantized numerical port rather than selecting the concrete cache class.
637
+ Focused KV4/KV8 storage checks pass, including unequal acceptance, overwritten
638
+ rejected tips, joins, growth, removal and compact extraction. Full-target MTP
639
+ bf16/KV4/KV8 round checks pass on both Macs, including output-aligned stopping
640
+ and survivor continuation at smaller B. Both complete model-free suites and
641
+ typechecks pass. `BatchedQuantizedKVCache` and the numerical attention port are
642
+ adopted in the working tree. The tested source matches the adopted source;
643
+ native logs and the `batched-quantized-state-manifest.json` live in the
644
+ composition-baseline reports. Same-B external quantized-oracle coverage and
645
+ actual speculative serving acceptance remain open.
646
+
647
+ The row method also handles a zero-proposal round through the
648
+ same graph/commit interfaces. It processes the pending companion KV row without
649
+ sampling a draft or projecting draft logits, then retains the target hidden
650
+ row needed for later speculation. The old request producer skips this update;
651
+ the native control instead discards a depth-one proposal to obtain the same
652
+ processed state. The change is adopted after full-round bf16/KV4/KV8 checks at B=1/2/4 on
653
+ both Macs, companion checks that forbid draft sampling/head projection in the
654
+ zero round, both complete model-free suites and typechecks. The source manifest
655
+ and native logs live in the composition-baseline reports. This does not adopt
656
+ the separately measured request-producer replacement or B=1 hidden slice.
657
+
658
+ The provider exposes grouped companion state through the existing
659
+ checkpoint representation. `PreparedStateChange` lets target and draft owners
660
+ stage a join independently; `applyStateChanges` publishes both only after all
661
+ preparation succeeds, then releases their old state. A failed preparation
662
+ leaves active membership intact. Publication performs no graph construction or
663
+ validation, and adds no operation to the decode round. Focused checks cover
664
+ failed joins, cleanup errors and released allocations. Full bf16/KV4/KV8
665
+ rounds through coordinated admission and both complete suites pass on both
666
+ Macs. This interface is adopted; serving must now use it before exposing a new
667
+ request to scheduling. Source identity and checks live in the
668
+ composition-baseline `mtp-admission-manifest.json`. Companion ownership
669
+ details live in speculative-decoding §4.8.
670
+
671
+ The MTP numerical graph is separate from request lifecycle and sampling. It
672
+ uses the cache's positions for both singleton and batched forwards. Native
673
+ checks on both Macs preserve full-target state and subsequent output at B=2,
674
+ plus the companion graph's output and KV after unequal prefix retention.
675
+ Uniform acceptance uses the existing recurrent kernel; unequal acceptance uses
676
+ the row-length-aware state-only kernel. The separate uniform state-only replay
677
+ experiment did not establish a serving win, so it is not promoted.
678
+
679
+ The exact-token acceptance walk is now a portable request state machine.
680
+ It tracks accepted drafts, correction/bonus tokens, EOS, token budgets and
681
+ grammar termination. Sampling still owns score processing and request history.
682
+ A group can stop sampling a finished walk while advancing the others.
683
+
684
+ The MTP row method keeps draft-token arrays on device between steps and reads
685
+ one complete proposal block. Its sampler is injected; committed state can be
686
+ extracted, filtered and joined between rounds. Greedy and seeded sampling pass
687
+ at depths 1/2/4 on both Macs, including retirement, reorder, rejoin and reuse
688
+ after removing every row. B=1 preserves the existing producer's proposals and
689
+ state. At B=2, per-step host-read and device-chain controls match at the same B.
690
+ The M4's B=2 KV differs from independent B=1 controls; cross-B byte equality is
691
+ not claimed, and the initial result remains in the raw logs.
692
+
693
+ `advanceSpeculativeRows` composes injected drafting, target verification,
694
+ request samplers and state transactions into one committed round. It has no
695
+ admission, output delivery or persistence policy. Each sampler walks only its
696
+ accepted prefix, recording logprobs and respecting EOS, grammar and remaining
697
+ token budget. The existing request adapter and grouped method now use the same
698
+ `sampleSpeculativeRows` operation. Failure tests cover disposal of verification
699
+ tensors when sampling or target/draft retention fails; the caller discards the
700
+ failed method state.
701
+
702
+ Native complete-round tests pass on both Macs at B=1/2/4 and depths 1/2/4,
703
+ with seeded depth-two coverage. They compare proposals, target samples,
704
+ logprobs, every retained target layer and draft KV/hidden state across three
705
+ rounds. B=1 uses the prior request producer and manual accept loop as control;
706
+ B=2/4 use a manual same-B loop with host reads between draft steps. These are
707
+ internal refactor controls, not a replacement for the external numerical oracle.
708
+ The row method is adopted in the working tree but not yet selected by serving;
709
+ matched complete-request performance remains an acceptance gate.
710
+
711
+ The next isolated candidate replaces the request producer's draft/commit loop
712
+ with the shared row method at B=1. The frozen `mtp-shared-draft-reference`
713
+ checkout retains the previous producer for native continuation and paired
714
+ serving comparisons. A zero-proposal round must retain its pending companion
715
+ KV row before resuming speculation; the old producer skipped that state update.
716
+ Native continuation checks pass on both Macs. Both serving orders preserve
717
+ responses but do not establish equal-or-better performance; the candidate is
718
+ not adopted. Numbers and frozen source identities live in benchmarks.md.
719
+ The subsequent isolated change replaces the B=1 hidden gather with a slice of
720
+ the same verification context, retaining the shared method. Its first serving
721
+ block is essentially flat in decode, but the reverse-order block regresses;
722
+ neither the source replacement nor the slice specialization is adopted.
723
+
724
+ The isolated round interface also separates verification/sampling from state
725
+ commit. `advanceSpeculativeOutputs` composes that round with the portable
726
+ `deliverDraftOutputs` operation. Each consumer receives verified tokens through
727
+ `GenerationOutput`; its stop, failure or cancellation affects its own request.
728
+ Both target and draft state then retain the same published, processed prefix,
729
+ excluding unpublished EOS and unprocessed correction/bonus tokens. Failed or
730
+ cancelled state must be discarded. Continuing requests keep their complete
731
+ accepted prefix. Verification context is an opaque disposable resource,
732
+ allowing graph-specific hidden taps without putting model details into
733
+ scheduling. The output method is adopted in the working tree; it is not wired
734
+ to serving. Focused tests and the complete isolated model-free suite pass.
735
+ Final-source native controls pass on both Macs, including removal of stopped
736
+ requests and continued generation at B=4→2 and B=2→1. They retain the old
737
+ request producer as the independent B=1 control. Same-B survivor comparisons
738
+ check tokens, logprobs and every retained target/companion state. Logs and the
739
+ source manifest live in the composition-baseline reports.
740
+
741
+ These are method/state dependencies, not served batched MTP acceptance. Grouped
742
+ draft generation, verification and sampling still need to be integrated into
743
+ the shared executor, with actual concurrent serving, cancellation, persistence,
744
+ quantized-layout composition and matched performance checks.
745
+ Parallel tool execution in Pi only exercises inference batching if model
746
+ requests overlap; record admitted rows and arrival schedules in the evidence.
747
+ Josh's September 8 M1 Max and M4 Pro suites are the ordinary-execution
748
+ baseline, recorded in [benchmarks.md](../reference/benchmarks.md#direct-scheduler-b1-versus-serial--both-machines-2026-09-08).
749
+ Retain those results and target new measurements at changed implementations
750
+ and newly supported features. They justify consolidation, but do not prove
751
+ the missing feature combinations or removal of host overhead.
752
+
753
+ ### Remaining mechanisms
754
+
466
755
  - **`--prompt-concurrency`**: not accepted by the CLI (mlx-lm's cap on
467
756
  joiners per iteration; the drop-in alias slot). Today at most one
468
757
  joiner prefills at a time.
469
758
  - **Rotating-layer `extend`**: Gemma joins extend their full layers but
470
759
  re-merge their sliding layers (`BatchedRotatingCache.merge` only).
471
- - **Full-layer filter `min_left_pad` shift** after eviction (mlx-lm
472
- cache.py does it); width waste only.
473
- - **Logprobs on the batch lane**: `wantsLogprobs` routes serial; the
474
- per-row sampler already computes `toLogprobs` — extend `RowSampler` to
475
- return extras and pass them through `onToken`.
476
- - **Batched timing stats**: the gateway returns `prefillMs/decodeMs/
477
- *Tps = 0` for continuous rows; `usage` timing is missing there.
478
- `maxTokens ?? 512` fallback in the gateway differs from the server
479
- default (dead in practice, a trap for library callers).
480
- - **LoRA-group batching**: adapter requests route serial. Design
481
- decided (adapter-set as the batch compatibility key; join if equal,
482
- drain if not; `loraState.active` set once per epoch); end state is
483
- per-slot adapter state in the batched step (vLLM/Punica is the oracle).
760
+ - **Logprobs acceptance**: ordinary batch capture is implemented through
761
+ the sampler interface. Unit coverage checks interleaved pipelines,
762
+ processor-adjusted probabilities, top-only capture and abandoned outputs;
763
+ `tests/parity/batch-logprobs.test.ts` exercises real B=1/B=2 and retirement.
764
+ On M4 Pro, the packed Qwen campaign artifact passes native and HTTP
765
+ serial/B=1 identity, actual B=2 capture on/off token identity, row retirement,
766
+ selected/top-only wire shapes and SSE omission. This is an internal
767
+ composition check, not a same-B external oracle or performance comparison.
768
+ Explicit-seed gateway tests also reproduce serial/B=1 outputs and repeat
769
+ fixed B=2 and controlled B=3 joins on M1 Gemma e4b and M4 packed Qwen.
770
+ These keep the numerical composition fixed; they do not assert
771
+ arrival-independent output across different batch shapes.
772
+ Broader compositions and matched performance remain open.
773
+ Cached-request diagnostics found synchronous recurrent-boundary persistence
774
+ inside a RAM hit and a serial request-time durability flush. Both are
775
+ removed: the shared cache lends immutable state views, and SSD writes run
776
+ independently of requests, acquiring idle ownership without draining active
777
+ batches. Explicit flush and shutdown remain durability
778
+ boundaries. Native repeated-prefix and SSD-restart continuation checks pass
779
+ on M1 and M4, including the saved long-prefix size on M4. A stalled-write
780
+ regression verifies RAM reuse and snapshot lifetime through donor eviction.
781
+ Balanced Bun 1.4.2 serving preserves outputs and near-equal decode time,
782
+ but a small cached first-output gap remains. First admission now seeds the existing device-token register to overlap its readback
783
+ with the following forward. Same-B MiniCPM/Gemma oracle vectors, compiled
784
+ B=1, grammar, first-token stop/EOS/length, callback containment, seeded
785
+ sampling and native/HTTP logprobs pass. Both serving arm orders preserve
786
+ outputs and close most of the remaining gap; the change is adopted in the
787
+ working tree. Actual method selection now precedes scheduling: configuring
788
+ a draft does not force ordinary logprob or supported affine-KV fallbacks
789
+ onto the serial executor. Native B=2 fallback outputs match ordinary B=2
790
+ on M1 and M4; HTTP tests with a configured draft also reach B=2 without
791
+ opening the producer. HTTP correctness tests align request arrivals at the gateway
792
+ to require concurrent work; serving benchmarks retain natural arrivals.
793
+ Broader pressure acceptance remains open.
794
+ Measurements live in benchmarks.md.
795
+ The gateway forwards timing/rates, but native regression coverage found that
796
+ ordinary admission never set the first-token timestamp. That caused zero decode
797
+ time even for multi-token responses. The timestamp is now recorded at first-token
798
+ emission; repeated shared-prefix B=2 tests check positive decode time and rate.
799
+ Both execution lanes already use the same omitted-library-cap fallback. Broader
800
+ usage and stopping compositions remain in the matrix.
801
+ - **LoRA-group batching**: ordered adapter sets now select compatible groups
802
+ through a backend-owned execution context. The scheduling driver sees only
803
+ readiness. Context changes and prefix identity bind under the execution
804
+ lease; adapter replacement while queued cannot reuse stale KV. Gemma e4b
805
+ native B=1/B=2, mixed queues, callback failure, separate prefix reuse and
806
+ queued replacement pass on M1/M4. Both machines match the pinned same-B
807
+ oracle through retirement and late joins; KV4/logprobs composition also passes.
808
+ Both M4 serving arm orders preserve single-request output. A small cached
809
+ first-output gap keeps strict performance dominance open;
810
+ simultaneous different adapters within a single forward remain future work.
811
+ Shared adapter speculation is qualified by the grouped provider's
812
+ `supportsTargetAdapters` capability. Prompt lookup declares it because its
813
+ draft state contains token history, with no separate learned graph to adapt.
814
+ Target prefill and verification retain the existing group adapter context;
815
+ adapter revision namespaces protect both target and lookup checkpoints.
816
+ Unqualified combinations retain ordinary execution. Learned providers do not
817
+ declare this capability. The native `adapter-lookup.test.ts` gate covers
818
+ compatible rows, seeded logprobs, failure cleanup and adapter prefix isolation;
819
+ both-machine bf16/KV4/TurboQuant checks pass, including existing ordinary-adapter
820
+ regressions. HTTP tests verify actual generated token alignment, exact seeded
821
+ RAM/SSD restart choices and speculation metadata, adapter namespace isolation
822
+ and concurrent requests. Concatenating a second newline can change the rendered
823
+ token boundary; the negative tokenization control preserves that distinction.
824
+ Full suites/typechecks pass; eight M4 comparisons are complete. Ordinary source cost is
825
+ effectively flat. Enabled lookup has low draft acceptance and loses concurrent
826
+ throughput on this workload; stricter matching is under separate measurement.
827
+ The feature remains opt-in and does not qualify a new default.
828
+ Evidence: `reports/qwen38-closeout/composition-baseline/adapter-lookup/`.
484
829
  - **Prompt-cache byte interplay**: mirror mlx-lm's
485
830
  `trim_to(total − activeBatchBytes)` so the LRU and the live batch
486
831
  share one ceiling. Derived default for `--kv-budget` (usable − weights
487
832
  − prompt-cache cap − headroom) instead of unlimited-when-unset.
488
- - **Long-context batched golden**: bf16 batched decode past the sliding
489
- window is oracle-gated model-free (`batched-rotating`), not yet as an
490
- end-to-end forward golden on a real Gemma.
833
+ - **Long-context batched golden is complete** for the recorded Gemma 12B/e4b
834
+ same-B window-crossing, retirement and late-join cases on both machines.
835
+ See the ring-wrap gate above; it is not outstanding implementation work.
491
836
  - **Unvalidated model cells** stay serial by the capability gate:
492
837
  gemma2-family (`maskArray`) and sliding-window universal archs.
493
- - **Paged KV batched integration** (§6 rung 3): block allocation in the
494
- scheduler, block-count admission, block CoW, fused paged kernel.
495
- - **GLM per-row MTP**: `--mtp on` routes serial+spec; batched MTP is
496
- post-release.
838
+ - **Paged KV**: ordinary shared storage is integrated and measured. Direct
839
+ paged attention, block sharing and quantized/speculative paging remain;
840
+ the state/cache interfaces own storage, independently of scheduling.
841
+ - **GLM MTP with concurrent requests**: the isolated shared provider passes
842
+ tiny-model and same-B Python state checks. Josh deferred final real-artifact
843
+ testing; see the GLM section below.
497
844
  - **Grammar jump-forward** (`MLX_BUN_GRAMMAR_JUMP`) is serial-only;
498
845
  `#stepGrammar` does not jump. Native XGrammar-2 via TVM-FFI has a
499
846
  B≫8 trigger.
@@ -502,8 +849,10 @@ naive tok/s — use wall-clock.
502
849
  its headroom.
503
850
  - **Batch-invariant kernels** (identical numerics regardless of B): Lab
504
851
  research item; would restore determinism under load for free.
505
- - **Per-row speculation inside the batch**: non-goal (variable accept
506
- lengths break uniform B); research question, not scheduled.
852
+ - **Qwen MTP with concurrent requests is integrated**: variable accepted
853
+ lengths, method-owned state alignment, shared sampling and generated RAM/SSD
854
+ reuse have passed the controls recorded below. Further work must identify a
855
+ specific unsupported composition or regression.
507
856
  - **Stale source comments**: `batch-scheduler.ts` header still says
508
857
  joins re-merge (extend landed 2026-07-04); `generation-gateway.ts`
509
858
  header and server-config.md say merged rows are never re-put
@@ -567,3 +916,1139 @@ naive tok/s — use wall-clock.
567
916
  `BatchableCache`.
568
917
  - 2026-08-22 — rotating-join regression from 443f333 fixed (capability-only
569
918
  merge routing); `tests/batch-rotating-join.test.ts`.
919
+
920
+ ### Shared KV maintenance
921
+
922
+ `createKvMaintenance` resolves the KV policy once when composing an execution
923
+ session. The ordinary generator, speculative prefill and the MLX execution group call
924
+ this same backend operation at their populated-cache boundaries. Per-layer lookup
925
+ is no longer rebuilt on every serial decode step. Streaming conversion still
926
+ materializes and releases each layer before converting the next. The existing
927
+ single-call `maybeQuantizeKv` export remains a compatibility entry point.
928
+ Server uniform KV4/KV8 now uses the same operation and existing quantized
929
+ batch layouts. Capability discovery probes actual cache-owning layers, including
930
+ Gemma's shorter donor prefix; it does not infer a separate scheduler from the
931
+ quantization label. M1 Gemma e4b and M4 packed Qwen native tests cover seeded
932
+ sampling with logprobs, exact serial/B=1 output, and repeatable controlled
933
+ B=2/B=3 joins. Matched serving performance and same-B external oracle coverage
934
+ remain open. Start-zero TurboQuant now has encoded row-layout support for
935
+ ordinary and Qwen MTP methods. Positive ordinary TurboQuant thresholds now
936
+ have merged-row transitions; Qwen delayed affine conversion is also adopted.
937
+
938
+ Prefill policy is now shared too. The execution group captures its chunk
939
+ default once; ordinary and speculative preparation use it, and both honor a
940
+ library request override. The gateway forwards that override instead of
941
+ silently using the group default for ordinary requests. The scheduler does
942
+ not choose a numerical prefill chunk. M1 native seeded-sampling and MTP
943
+ RAM/SSD checks pass on both Macs. The first matched M4 short control preserves
944
+ all measured outputs with effectively unchanged timing; long-context checks
945
+ and balanced acceptance remain open.
946
+
947
+ Delayed ordinary TurboQuant conversion is now adopted after the mixed-phase,
948
+ prefix-reuse, fused/unfused and composed MTP/generated-output checks pass on
949
+ M4 as well as the original M1 family gates. The cache publishes its actual
950
+ irreversible conversion boundary through clone, extraction, RAM lookup and
951
+ SSD metadata; earlier plain donors remain usable. The first M4 hygiene run
952
+ found only a stale generated docs map. After regeneration, full hygiene passes
953
+ on both machines without changing tested code. The main full suite and typecheck
954
+ pass for ordinary conversion. Delayed shared MTP is also adopted after native
955
+ state/continuation, seeded B1/B3/late-admission, SSD and complete-suite gates on
956
+ both machines. Conversion follows retained state after rollback and preserves
957
+ physical row positions; the codec and kernels are unchanged. The main full suite, typecheck and hygiene pass. Qwen delayed affine is also adopted; these correctness gates establish
958
+ no new TQ default or performance gain.
959
+
960
+ ### Variable proposal lengths
961
+
962
+ The shared method accepts 0..depth proposals independently per
963
+ request. It sizes the rectangular target graph from the longest returned
964
+ proposal, right-pads shorter rows, and samples only through each row's own
965
+ bonus position. State commit retains the pending token and accepted inputs;
966
+ no padding enters a reusable checkpoint. If every proposal is empty, the
967
+ method runs one target step even when the configured draft depth is positive.
968
+ Scheduling does not choose proposal lengths or manage their acceptance.
969
+
970
+ The M1 Qwen control covers four rows with 0/1/2/3 proposals, greedy and seeded
971
+ sampling, independent retirement and re-admission. Both bf16 and KV4 preserve
972
+ tokens, logprobs, target state and companion state against explicit same-B
973
+ controls that use a different right-padding token. These are internal
974
+ composition checks, not an external oracle or a performance claim. Unit tests
975
+ also prove that padding consumes no sampler steps and terminal consumers
976
+ retain only delivered inputs. The complete candidate suite and typecheck pass.
977
+ M4 uniform/variable native controls and the complete suite also pass. The
978
+ first fixed-settings serving comparison was slower despite identical outputs
979
+ and speculation statistics. Alternating frozen-source controls do not reproduce
980
+ that slowdown and retain identical work. The three-file verifier patch is now
981
+ adopted; the main complete suite and typecheck pass. Provider migrations must retain their own
982
+ prefill/checkpoint conventions; this verifier alone does not change eligibility.
983
+ Evidence: `reports/qwen38-closeout/composition-baseline/variable-proposals/`.
984
+
985
+ ### Prompt lookup through the shared method
986
+
987
+ The shared executor now implements prompt lookup as a provider-owned draft
988
+ row group. Each row holds committed token history, proposes repeated spans,
989
+ and appends only inputs retained by verification. It uses the same variable
990
+ proposal verifier, sampler, target state, membership transactions and cache
991
+ publication as MTP. Scheduling has no prompt-lookup branch.
992
+
993
+ Preparation explicitly supplies processed-token coverage to the provider.
994
+ For tail-split lookup, the last prompt token becomes the first pending input;
995
+ completed-output keys include it exactly once. Integer history tensors use the
996
+ existing companion-checkpoint format and byte accounting. The generic tensor
997
+ reader now supports int32 for streamed SSD persistence; no separate prompt
998
+ lookup writer or storage queue is introduced.
999
+
1000
+ M1 Qwen bf16/KV4/KV8/fused-TQ serving checks pass B1 controls, real B4 verification, independent
1001
+ consumer stops/failures, cancellation, late joins, seeded logprobs and grammar.
1002
+ All four schemes pass tool turns with thinking off/on, generated-prefix RAM reuse and fresh-PID
1003
+ SSD restoration with identical responses, logprobs and acceptance. The initial
1004
+ SSD flush failure exposed the missing int32 raw-byte reader; its regression
1005
+ now passes. MTP3 serving regressions also pass in bf16/KV4/TQ after the shared
1006
+ preparation changes. Unsplit-prefill serving and the complete model-free/SSD
1007
+ suite and typecheck also pass. The same planned native/HTTP scheme matrix,
1008
+ MTP regressions, unsplit-prefill and complete suite now pass on M4. An initial
1009
+ M4 wrapper failure supplied CLI quantization value `0` instead of `off`; it
1010
+ failed before inference, was retained, and the corrected wrapper resumed
1011
+ without source changes. Fixed-MTP timing is effectively unchanged. Both lookup arm orders preserve
1012
+ single-request outputs with small decode improvements and new cached-prefix
1013
+ reuse. Concurrent outputs differ and observed shared throughput is lower, so
1014
+ strict dominance is unproven. Default depth-10 KV4 serving checks now pass on
1015
+ both Macs and exercise all ten proposal positions. Serving eligibility is
1016
+ currently Qwen only. The seven-file patch is adopted; its concurrent
1017
+ performance gap remains open, and serial deletion is not qualified.
1018
+ Evidence: `reports/qwen38-closeout/composition-baseline/ngram-group/`.
1019
+
1020
+ A separate composed checkout combines the adopted variable verifier and ordinary
1021
+ TQ cache with prompt lookup and delayed speculative TQ. The only production
1022
+ hunk shared by the two candidate patches is the generic cache preparation hook
1023
+ before state admission; the merged source is verified against both deltas.
1024
+ M1 fused/unfused target/MTP and prompt-lookup native checks, threshold-crossing
1025
+ SSD restart, full suite and typecheck pass. The lookup extension exercises the
1026
+ same delayed-cache serving test by substituting its draft provider, including
1027
+ mixed phases, seeded metadata, retirement and late joins. M4 composition now passes the same native/SSD gates, full suite, typecheck
1028
+ and hygiene. Both production patches are now adopted in main, with exact
1029
+ file identity against the tested composed source. Fixed-MTP composition
1030
+ timing is effectively unchanged. Main full-suite, typecheck and hygiene checks pass.
1031
+ Evidence: `reports/qwen38-closeout/composition-baseline/method-composed/`.
1032
+
1033
+ ### One-token prefill allocator maintenance candidate
1034
+
1035
+ A native first-output diagnostic found milliseconds of allocator cleanup after
1036
+ a cached one-token target forward. A separate candidate retains allocator
1037
+ buffers for single-token prefill work and still clears after larger chunks.
1038
+ This is method-owned maintenance; the scheduler, sampler and cache-persistence
1039
+ policy are unchanged. KV4 and delayed-TQ one-token suffix SSD continuations,
1040
+ complete suites and typechecks pass on M1/M4. Alternating M4 fixed-MTP timing
1041
+ preserves every request/output/usage record and consistently reduces cached
1042
+ first-output latency. The first control has slower cold/decode timings, so
1043
+ a broad throughput gain is not established. The 8k M1 allocation comparison
1044
+ retains identical output/acceptance, nearly equal peak live allocation and a
1045
+ larger final allocator pool. Matched serial/shared timing still shows a cached-latency regression; the
1046
+ candidate remains isolated and long-context/SSD pressure remains open.
1047
+ Evidence: `reports/qwen38-closeout/composition-baseline/single-token-maintenance/`.
1048
+
1049
+ ### Delayed affine conversion
1050
+
1051
+ The adopted delayed-affine implementation extracts `TransitioningKvRows` from the
1052
+ existing TurboQuant adapter. It owns committed positions, conversion, physical
1053
+ padding, merge/extract and speculative rollback. Codec-specific adapters retain
1054
+ their attention arithmetic. The affine adapter uses the storage-owned
1055
+ `KvAttentionState` port for mixed-precision rows and the existing packed batch
1056
+ attention once every row converts. Model binding declares support once and
1057
+ passes that capability to request planning and executor construction.
1058
+
1059
+ Both Macs pass KV4/KV8 target rollback and continuation, ordinary serial/B1
1060
+ seeded token/logprob equality, MTP B1/B3 retirement and late admission, plus SSD
1061
+ restoration with conversion in prefill or decode. Fused/unfused TQ native and
1062
+ serving regressions pass. Final full suites and typechecks pass on both Macs.
1063
+ Positive affine thresholds and non-default group sizes have distinct cache
1064
+ identities; captured conversion floors survive extraction and SSD restoration.
1065
+ The original constructor-capability failure is retained in the raw evidence.
1066
+
1067
+ Alternating M4 fixed-settings comparisons preserve every request output, usage
1068
+ and finish reason with effectively unchanged timing. The reviewed implementation
1069
+ is adopted in the unreleased working tree. Eligibility currently covers Qwen;
1070
+ other model attention ports remain open. Main full-suite/typecheck/hygiene checks pass. Prompt lookup also passes KV4/KV8
1071
+ B1/B3 seeded continuation, actual proposals, retirement and late admission on
1072
+ both Macs without scheduler or sampler changes.
1073
+ No serial deletion or performance gain is established by these checks. Evidence is under
1074
+ `reports/qwen38-closeout/composition-baseline/delayed-affine/`.
1075
+
1076
+ The adopted attention port preserves Gemma's donor/shared-layer contract: a donor
1077
+ calls `Cache.attentionState.appendAndFetch` once, then every sharing layer calls
1078
+ `KvAttentionView.attend` on the same captured state. The view owns tensor handles
1079
+ and captured row alignment independently of later cache mutation or disposal.
1080
+ The model retains pre-write RoPE positions through all consumers and releases
1081
+ the view once at the end of the pass. Qwen and MiniCPM use one consumer per
1082
+ append. Existing training attention paths remain separate from these inference
1083
+ cache views. Scheduling and sampling do not manage attention-view lifetimes.
1084
+
1085
+
1086
+ The captured-view implementation exposes `appendAndFetch` and a
1087
+ reusable `KvAttentionView.attend`. Qwen consumes one view per append; Gemma can
1088
+ retain it for sharing layers. KV4/KV8 unit checks preserve two distinct queries
1089
+ after further appends, conversion, row reordering and disposal of the original
1090
+ cache. Full-model Gemma 12B logits and active cache state match the existing
1091
+ consumer path. The initial state test compared unused allocator capacity;
1092
+ the corrected check compares every processed value, and keeps the failed raw
1093
+ comparison. Gemma 12B/e4b and MiniCPM KV4/KV8 pass on both machines. The e4b checks
1094
+ exercise multiple reads per append. The M4 full suite passes. The initial M1
1095
+ suite used a fallback DeltaNet fixture because this worktree lacked the
1096
+ already-qualified machine golden; copying that unchanged fixture makes the
1097
+ focused test pass. Qwen KV4/KV8 rollback, MTP and prompt lookup regressions plus the corrected
1098
+ M1 suite pass. Both-machine typechecks and KV4/KV8 SSD continuations pass.
1099
+ Alternating M4 decode/cached/throughput timing is effectively unchanged. The
1100
+ final control end check flags a small CPU daemon; the raw result is retained
1101
+ and assessed under the campaign background-CPU policy. Startup remains less
1102
+ stable and is not qualified by this screen. The reviewed change is adopted;
1103
+ main integration suite, typecheck and hygiene pass.
1104
+ Gateway eligibility is unchanged until the broader storage combinations pass.
1105
+ Candidate evidence: `reports/qwen38-closeout/composition-baseline/kv-attention-view/`.
1106
+
1107
+
1108
+ Delayed rotating affine storage remains a separate missing composition. Its
1109
+ logical row positions and physical ring columns are different state: conversion
1110
+ or packing must preserve the mask/column relationship. Existing
1111
+ `BatchedRotatingQuantCache` has encoded row merging; the shared
1112
+ `BatchedRotatingState` owns ring positions. Reuse those interfaces rather than
1113
+ introducing a scheduler quantization branch. Qualify unequal offsets, conversion
1114
+ before/after wrap, retirement, late admission, shared Gemma consumers and
1115
+ persisted conversion floors before widening the gateway capability.
1116
+
1117
+ The first M4 benchmark wrapper stopped before inference because its parent
1118
+ shell inherited an older oracle path. The Qwen correctness child had already
1119
+ passed with the explicit pinned environment. Only the unstarted benchmark was
1120
+ resumed, with that same explicit environment; the completed four-arm comparison
1121
+ and failed launch log are retained.
1122
+
1123
+
1124
+ ### Multi-token rotating storage
1125
+
1126
+ The adopted rotating-block implementation removes the one-token-only restriction
1127
+ from both bf16 and affine batched rings. `RowStorage` supplies encoded tensor
1128
+ operations; `appendRotatingStorage` retains chronological history without
1129
+ unpacking affine tensors; `BatchedRotatingState.commitConcat` owns padding,
1130
+ logical positions and the physical write head. One-token updates retain their
1131
+ existing in-place implementation. The port follows the pinned mlx-lm
1132
+ `BatchRotatingKVCache._update_concat` for left-padded inputs.
1133
+
1134
+ A block temporarily holds up to window + block length - 1 columns so every
1135
+ query retains its full context. Extraction preserves that active block, while
1136
+ merge views select the newest window. Dropping the temporary suffix during
1137
+ extraction would corrupt subsequent continuation. No scheduler or sampler
1138
+ changes are needed for these storage operations.
1139
+
1140
+ The same-B live oracle gate covers B=1/2/3, unequal left padding, mixed
1141
+ one-token and block writes, repeated wrap, overshoot, row reordering,
1142
+ retirement, late admission and extracted state. bf16 values and masks match
1143
+ mlx-lm exactly on both Macs. KV4/KV8 share its geometry and preserve every
1144
+ extracted affine component against the native quantizer. Existing Gemma 12B
1145
+ ring-wrap serving still matches 48 full logit vectors per machine. Both-machine model-free/SSD suites and typechecks pass. The reviewed six-file
1146
+ change is adopted; main typecheck/hygiene pass. No performance or full
1147
+ batched-prefill claim is made.
1148
+ Right-padded prefill finalization and speculative rollback of overwritten
1149
+ ring entries remain part of the shared-execution work. Delayed rotating
1150
+ precision conversion is implemented below.
1151
+ Evidence: `reports/qwen38-closeout/composition-baseline/rotating-block/`.
1152
+
1153
+
1154
+ ### Delayed rotating affine conversion
1155
+
1156
+ The adopted implementation uses `TransitioningKvRows` for ordinary membership,
1157
+ retirement, checkpoints and precision changes. `SpeculativeTransitioningKvRows`
1158
+ adds rollback for layouts that implement it; ordinary rotating storage does not
1159
+ advertise speculative rollback. `TransitioningKvPositions` supplies geometry
1160
+ without a codec. Full-attention positions retain the existing `KvTensorRows`
1161
+ operations, and rotating positions use `BatchedRotatingState`.
1162
+
1163
+ An aligned row keeps the group's physical ring columns while exposing its own
1164
+ logical position to the shared affine-maintenance policy. Conversion quantizes
1165
+ the existing buffers without changing their physical layout, write head or
1166
+ padding. Once every row is converted, the encoded planes concatenate
1167
+ without reordering columns. `captureKvAttention` provides the same owned read
1168
+ view for either representation; Gemma's donor and sharing layers can keep
1169
+ reading it after the cache advances. No scheduling or sampling branch is added.
1170
+
1171
+ Membership changes normalize borrowed solo rows through owned clones. Empty
1172
+ plain and affine cache clones now remain valid empty caches, enabling a group
1173
+ to be assembled before its first input. Extraction preserves each row's
1174
+ conversion floor in the existing persistence schema. The implementation enables
1175
+ positive affine thresholds for ordinary Gemma execution; other speculative
1176
+ providers, rotating rollback and true batched-prefill scheduling remain open.
1177
+
1178
+ Gemma 12B and e4b KV4/KV8 pass exact hidden/logit and active-state checks before
1179
+ and after the real sliding window on both Macs. Serialized output snapshots
1180
+ preserve token IDs, state and conversion floors; restored snapshots continue
1181
+ identically to RAM snapshots in the same process. These are not fresh-process
1182
+ or long Kanban acceptance. Seeded gateway checks match serial at B1 and repeat
1183
+ B2/B3 admission schedules exactly on both machines. The model-free checks cover
1184
+ mixed precision, empty rows, conversion before/after wrap, block updates,
1185
+ retirement, late joins and attention reads after owner disposal. Final complete suites and typechecks pass on both Macs, as do Qwen affine
1186
+ MTP/lookup and fused/unfused TurboQuant regressions. Artifact-defined per-layer
1187
+ Gemma compression also passes both-machine hidden/logit/state and persistence
1188
+ checks. Four alternating M4 default Qwen benchmark arms preserve all responses
1189
+ and show effectively flat decode, cached latency and concurrent throughput;
1190
+ startup equivalence remains open. The reviewed fifteen-file implementation is
1191
+ adopted in the unreleased working tree. Main integration suite, typecheck and hygiene pass.
1192
+ Measurements and source identities live in benchmarks.md.
1193
+ Evidence: `reports/qwen38-closeout/composition-baseline/delayed-rotating/`.
1194
+
1195
+
1196
+ ### Singleton admission copy candidate
1197
+
1198
+ An isolated candidate replaces singleton `copyOf` calls with `contiguous` in
1199
+ attention and recurrent admission. The proposed GPU-copy saving is not
1200
+ supported: the M4 MLX 0.32.2 probe shows both operations share existing storage.
1201
+ This agrees with the existing explanation in `mlx/materialize.ts`; a method
1202
+ name is not evidence of a physical copy. The evaluated synthetic Qwen-shaped
1203
+ probe shows no additional GPU allocation for either version. Also, shared MTP
1204
+ publishes its first token before the singleton group merge, so that merge is
1205
+ not on its first-output critical path.
1206
+
1207
+ Both-machine ownership tests cover independent updates, donor immutability,
1208
+ self-merge, spare capacity and source/group disposal. Typechecks pass. The M4
1209
+ bf16/KV4/KV8 round matrix, fused/unfused TQ, delayed affine/TQ serving and full
1210
+ suite pass. M1 native/serving and the complete suite also pass. The alternating
1211
+ M4 HTTP comparison preserves all responses and records lower cached latency
1212
+ in both candidate arms. The physical-copy explanation is disproven, so further
1213
+ attribution/repetition remains before adoption. Startup equivalence and direct
1214
+ serial dominance are still unproven. Extraction and larger group concatenation
1215
+ are unchanged. Timing belongs in benchmarks.md.
1216
+ Evidence: `reports/qwen38-closeout/composition-baseline/singleton-state/`.
1217
+
1218
+
1219
+ ### Recurrent output-row retention
1220
+
1221
+ `SSMCache.extractRow` used `copyOf` with a comment promising compact storage.
1222
+ The current MLX implementation aliases that storage: after releasing a B>1
1223
+ source group, one retained row still owns the entire group's backing buffers.
1224
+ The M1 allocation probe reproduces this for B=2/4/8. This is separate from
1225
+ singleton admission, where sharing a complete allocation is appropriate.
1226
+
1227
+ The adopted extraction fix uses the existing `materializeCopy` port for
1228
+ a proper subset of a batch and retains a separate array handle for B1. Row
1229
+ values and logical offsets do not change. The allocation regression fails on
1230
+ the unchanged control and passes on the candidate, including exact values and
1231
+ disposal on both Macs. Both-machine KV4 MTP round matrices, bf16/KV4/TQ generated
1232
+ RAM/SSD continuations, complete suites and typechecks pass. Four alternating
1233
+ M4 HTTP arms preserve all responses and support integration without a broad
1234
+ speed claim. The source and regression test are adopted; main integration
1235
+ suite and typecheck pass. Long-context pressure acceptance remains open.
1236
+ No scheduler, sampler, persistence queue or quantization policy changes.
1237
+ Evidence: `reports/qwen38-closeout/composition-baseline/ssm-extraction/`.
1238
+
1239
+
1240
+ ### Padded prefill cache interfaces
1241
+
1242
+ The adopted cache-interface portion adds `PaddedPrefillCache`. Its frozen
1243
+ validation checkout is `padded-prefill-validation`.
1244
+ Preparation receives each prompt's lengths and left/right padding. Finalization
1245
+ removes trailing padding from logical coverage and aligns retained state before
1246
+ decode or checkpoint publication. The cache owns these operations; neither the
1247
+ scheduler nor a quantization codec chooses token positions.
1248
+
1249
+ `FullPrefillPadding` applies one row-roll index to arbitrary full-cache tensor
1250
+ planes. Plain KV, affine KV4/KV8 and TurboQuant reuse it without dequantizing or
1251
+ requantizing the stored values. Rotating storage instead moves completed rows'
1252
+ padding ahead of valid history before each block trims its window. Both plain
1253
+ and affine rings share that position logic and preserve physical alignment.
1254
+
1255
+ One-token padded chunks use the existing rotating concat operation and block
1256
+ mask. MLX-LM's public dispatch rejects this case before finalization. The gate
1257
+ therefore invokes its existing `_update_concat` and takes the first query from
1258
+ its two-token block mask for this extension. Ordinary decode retains the ring
1259
+ write. This is an extension checked against oracle operations, not a claim that
1260
+ the upstream public dispatcher supports the same call.
1261
+
1262
+ The live geometry gate checks B1/B2/B3, left/right padding, an existing prefix,
1263
+ window overflow, zero-length prefixes, one-token chunks, finalization, extraction
1264
+ and continuation.
1265
+ Plain tensors, masks and positions match the reference. Affine and TurboQuant
1266
+ retained bytes match their existing codecs applied to oracle-retained rows.
1267
+ MiniCPM5 and Gemma 12B/e4b also match full same-B logit vectors after padded
1268
+ prefill and three continuations with whole-prompt, 5/5/1 and singleton chunks
1269
+ on both Macs. Complete suites and typechecks pass on both machines. Qwen KV4
1270
+ MTP rounds, both TurboQuant decode settings and generated-prefix bf16/KV4/TQ
1271
+ RAM/SSD continuations also pass on both Macs. These regression runs use ordinary
1272
+ unpadded preparation; they do not qualify Qwen padded prefill.
1273
+
1274
+ The cache-interface changes are adopted; main integration suite and typecheck pass.
1275
+ Qwen recurrent-state masking, delayed rotating transitions and ordinary
1276
+ preparation cohorts are adopted below, including cancellation/checkpoints.
1277
+ MTP preparation and full-cache delayed padding still keep S1a open.
1278
+ No serving performance result or default change is claimed for this candidate.
1279
+ Evidence: `reports/qwen38-closeout/composition-baseline/padded-prefill/`.
1280
+
1281
+ Full-cache finalization now retains absolute valid ends, as rotating storage
1282
+ already does. It removes only padding actually processed. This lets a cohort
1283
+ finish early after a longer request leaves, or finalize a partial prefix before
1284
+ the original planned width. Ending before any right padding leaves tensors and
1285
+ positions untouched. Filtering and reordering requests also filters those ends.
1286
+ The unchanged control subtracts unprocessed padding and produces negative
1287
+ coverage in the shortened-cohort regression; its failure log is retained.
1288
+
1289
+ Both-machine geometry checks cover completed and shortened B1/B2/B3 prefills,
1290
+ cached prefixes, leading padding, request retirement/reordering before
1291
+ finalization, extraction and three subsequent decode steps. The reference full
1292
+ cache receives the effective padding of the processed prefix; Bun receives the
1293
+ original plan. Survivor checks select the corresponding oracle rows without
1294
+ changing their physical columns. Plain state/masks match exactly; affine and
1295
+ TurboQuant retained bytes match encoding those oracle rows. Host lifecycle
1296
+ tests also cover finalization before any work and preparation after a partial
1297
+ checkpoint. Model-free suites, SSD tests and typechecks pass on both Macs.
1298
+ This fixes cache preparation semantics; serving cohorts and their cancellation
1299
+ handling are still unwired. No speed or default change is claimed.
1300
+ Evidence: `reports/qwen38-closeout/composition-baseline/padded-partial/`.
1301
+
1302
+
1303
+ ### Recurrent-state padding
1304
+
1305
+ The adopted recurrent-padding change extends the same prefill port to
1306
+ Qwen's recurrent cache. `SsmPrefillPadding` tracks remaining real-token lengths
1307
+ and leading padding. Each cache advances coverage by real tokens only and
1308
+ filters that metadata with its rows. Finalization clears preparation state.
1309
+ Uniform prompts keep the unmasked kernel and ordinary convolution tail.
1310
+
1311
+ The model constructs one mask for all recurrent layers. DeltaNet zeroes padded
1312
+ QKV inputs before convolution, selects each row's convolution tail by its
1313
+ remaining length, and uses the pinned oracle's masked recurrence. Masked steps
1314
+ leave recurrent state unchanged. The existing kernel body is shared between
1315
+ masked and unmasked specializations; scheduling does not choose or manipulate
1316
+ these state operations. The convolution-tail selection already used by
1317
+ variable speculative rollback is reused here.
1318
+
1319
+ The primitive gate compares full output and state hashes with the pinned GPU
1320
+ oracle at the 27B head geometry. It includes B1/B3, fully masked rows, singleton
1321
+ steps and an unmasked continuation. The unchanged control fails this gate.
1322
+ The small Qwen model passes padded full-model checks on M1. Both Macs pass
1323
+ same-B 27B full-logit and convolution/recurrent-state checks for unequal prompts,
1324
+ batch-of-one and uniform B3, with whole-prompt, singleton-tail and all-singleton
1325
+ chunks. The machines use their locally installed affine 27B artifacts; these
1326
+ are per-machine oracle comparisons, not an engine or artifact speed comparison.
1327
+
1328
+ The isolated checkout initially retained three obsolete HEAD files and lacked
1329
+ its machine-specific golden blobs. Those setup problems were corrected against
1330
+ the validated base; no golden was regenerated. Initial scalar creation also
1331
+ needed the existing typed-array constructor. Failure logs remain with the
1332
+ candidate evidence. Both-machine MTP/TQ/generated RAM/SSD regressions, full
1333
+ suites and typechecks pass. Four alternating M4 HTTP arms preserve all responses
1334
+ with roughly flat decode/cached/throughput timing. Startup equivalence remains
1335
+ open. The change is adopted; main integration suite and typecheck pass.
1336
+ Delayed-codec preparation and actual serving cohorts remain open.
1337
+ Evidence: `reports/qwen38-closeout/composition-baseline/padded-ssm/`.
1338
+
1339
+ ### Delayed rotating compression during padded prefill
1340
+
1341
+ Delayed rotating KV4/KV8 now implements the same preparation/finalization port.
1342
+ Each physical row receives its own token lengths and the common batch layout.
1343
+ All rows use the padded block operation when any sibling has right padding,
1344
+ including a singleton chunk in a row without padding. An initial implementation
1345
+ lost alignment by letting that row switch to a ring write while its sibling
1346
+ continued block writes. The retained failing regression exposed incorrect cache
1347
+ bytes when those rows later packed together.
1348
+
1349
+ The shared position snapshot now combines every row's pending valid end when
1350
+ format conversion packs a group. Maintenance uses valid token counts, so a
1351
+ padded suffix cannot cross a precision threshold or inflate the earliest
1352
+ reusable prefix. Physical write positions remain separate. Retirement and
1353
+ reordering preserve pending preparation state before and after packing.
1354
+
1355
+ Both-machine geometry gates include B1/B2/B3/B4/B8, KV4/KV8, multiple transition
1356
+ thresholds, cached history, ring overflow, singleton chunks, early finalization
1357
+ and survivor continuation. Cache geometry comes from the pinned MLX-LM oracle.
1358
+ Encoded bytes match the existing codec applied to oracle-retained rows; exact
1359
+ attention checks use those oracle tensors and masks with the native operation
1360
+ at the same B as each mixed or packed representation. Gemma 12B/e4b also pass
1361
+ same-B padded model logits through the delayed layout before conversion.
1362
+ The latter is plain-KV model coverage, not a quantized padded full-model oracle.
1363
+ Ordinary Gemma conversion and RAM/SSD continuations, complete model-free suites
1364
+ and typechecks pass on both Macs.
1365
+
1366
+ The change is adopted in the unreleased working tree. Four alternating Gemma
1367
+ M4 benchmark arms preserve all responses; the small timing differences are
1368
+ recorded in benchmarks.md and establish no speed win or serial dominance.
1369
+ Full-attention delayed affine/TurboQuant padding remains open. Ordinary serving
1370
+ now uses the real-token cohort described below.
1371
+
1372
+ Ordinary serving uses a method-owned cohort of equal-length
1373
+ chunks of real tokens. It admits later arrivals between forwards. Each request
1374
+ retains its planned maintenance, checkpoint and tail boundaries when a peer
1375
+ causes an earlier split. Scheduling chooses membership; the preparation method
1376
+ runs shared forwards; cache layouts merge positions and retain precision policy.
1377
+ The same target driver now serves MTP and prompt lookup; their providers own
1378
+ companion prefill state through the separate method interface.
1379
+
1380
+ The first lifecycle runs exposed an empty-state native evaluation and missing
1381
+ initialization when a cold recurrent row joins populated state. Empty caches
1382
+ submit no evaluation. The recurrent layout initializes the new row's state
1383
+ with zeros, matching the pinned reference's ArraysCache.merge behavior.
1384
+ Qwen 27B on the M4 then exposed a logit mismatch immediately after retirement.
1385
+ Full-attention storage now removes padding shared by all survivors, matching
1386
+ BatchKVCache.filter. Affine planes inherit that operation; TurboQuant's tensor
1387
+ storage applies it too. These are cache membership operations, independent of
1388
+ scheduler, sampler and inference method.
1389
+
1390
+ Focused tests cover staggered B1→B2→B3 joins, real-token identity, native retained
1391
+ bytes with immediate/delayed affine and TurboQuant conversion, checkpoint
1392
+ boundaries, cancellation and completion callback failure. A scheduler-level test
1393
+ submits a request during the first forward and observes it in the next chunk.
1394
+ The model gate compares every full logit vector to the pinned same-B reference
1395
+ through joins and retirement, then compares each extracted row's continuation.
1396
+ It passes Qwen 27B and Gemma 12B on both Macs; the M1 also passes Qwen 0.8B.
1397
+ Padded cache geometry/encoded-state/attention checks pass on both machines.
1398
+ The padded oracle now performs retirement itself; stock filter omits pending
1399
+ prefill metadata, so the fixture selects its right-padding/length metadata with
1400
+ the same row indices before calling the existing finalize operation.
1401
+
1402
+ MTP delayed affine/TurboQuant regressions pass on both Macs. Four-arm M4
1403
+ timing and response differences are recorded in benchmarks.md.
1404
+ An added token-zero check then found that the M4 Qwen 27B sampler receives
1405
+ different logits when each completed row projects its hidden state separately.
1406
+ The shared forward's full vectors still match; the M=1 projection changes its
1407
+ arithmetic. A follow-up candidate projects the batch before selecting logits
1408
+ for each sampler. Its focused lifecycle checks and the M4 Qwen 27B/Gemma 12B full-vector,
1409
+ sampler-logit and continuation checks pass on both Macs. Full model-free suites
1410
+ and typechecks pass on both; all 829 nonignored source/test files match across
1411
+ the isolated copies. Fresh four-arm M4 timing is effectively flat. The corrected
1412
+ cohort is adopted in the unreleased working tree; main integration suite, typecheck and hygiene pass. Seeded delayed-TQ/affine serving and logprob/wire checks also pass on
1413
+ M1. Unsplit-prefill seeded serving passes M1 Qwen 0.8B and M4 Gemma 12B.
1414
+ Validated source: `/Users/joshrossi/.cache/mlx-bun/prefill-cohort-logits-validation`.
1415
+ A separate admission-control benchmark retains the measured code but disables
1416
+ additional cohort admission. That control restores every baseline response,
1417
+ attributing the changed concurrent text to shared prefill.
1418
+ Full delayed affine/TurboQuant padded preparation and MTP prefill cohorts remain
1419
+ open. The production HTTP benchmark now measures long aggregate prompts and
1420
+ staggered arrivals. Its four-arm M4 comparison exposes a first-output latency
1421
+ regression and no throughput win at the current chunk size. M1 traces show
1422
+ internal token zero ready before a long B3 preparation chunk delays the first
1423
+ response write. A matching smaller-chunk M4 screen still loses latency and
1424
+ throughput. Prefill work-unit sizing and admission policy need tuning through
1425
+ the shared scheduler/preparation interfaces. This is a scheduling decision
1426
+ within the shared executor; it must not introduce another serial method.
1427
+ See benchmarks.md for numbers and limits.
1428
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`.
1429
+
1430
+ An isolated follow-up exposes preparation work through the scheduling contract.
1431
+ The preparation owner reports each admitted request's initial uncached token
1432
+ count; the queue adapter reports the next prompt length as an upper bound before
1433
+ cache restoration. The scheduler extends a cohort only while the combined
1434
+ weight fits its internal preparation budget, currently 2,048 tokens. The first
1435
+ request always enters and can exceed that budget alone. No request is rejected
1436
+ or sent to another executor. Short late arrivals still join ongoing preparation.
1437
+ An earlier version reduced the weight as prefill progressed. That allowed a
1438
+ nearly completed request to attract another long request into its tail; the
1439
+ first M4 screen restored early latency but still lost total request time. The
1440
+ current candidate retains admission weight until the request leaves preparation.
1441
+ This policy changes grouping, not per-request chunk or precision boundaries.
1442
+ Cache lookup/restoration remains in preparation, not scheduling. The conservative
1443
+ queued estimate can postpone a cached long request until current preparation
1444
+ ends. A native Qwen/TurboQuant check with a long RAM prefix passes repeat output,
1445
+ retirement, immutable cache bytes and actual B2 decode on M1. The original late
1446
+ prefill join remains covered, alongside a group test that holds a nearly finished
1447
+ row's weight and then advances its queued sibling through the same executor.
1448
+ The seven-file fixed-weight policy is adopted in the unreleased working tree.
1449
+ Both complete suites/types and long-prefix ownership checks pass. The M4
1450
+ comparison restores the large first-output loss and all response identity,
1451
+ while small unfavorable timing differences remain in benchmarks.md. Main
1452
+ integration suite/typecheck pass; strict performance dominance remains open.
1453
+ Candidate: `/Users/joshrossi/.cache/mlx-bun/prefill-budget-validation`.
1454
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/budget*`.
1455
+
1456
+ A separate two-file lifetime candidate releases input IDs after the forward and
1457
+ releases unused hidden output before cache evaluation/maintenance, matching the
1458
+ existing shared prefill primitive. The cohort previously retained those handles
1459
+ until the end of the work unit. Finished rows still retain hidden output through
1460
+ batched projection and sampling. Focused ownership checks pass on M1, and the Qwen 27B
1461
+ same-B model/sampler/continuation gates pass on both Macs. The M1 full suite and
1462
+ typecheck pass. The four-arm M4 comparison preserves all responses but shows no
1463
+ throughput or material measured-memory benefit. This candidate is not adopted;
1464
+ its M4 full suite/typecheck was not run. Timing and limits are in benchmarks.md.
1465
+ Candidate: `/Users/joshrossi/.cache/mlx-bun/prefill-drain-validation`.
1466
+
1467
+ The next isolated candidate exposes `DraftPrefillGroup` from the draft provider.
1468
+ It borrows each batch of new target tokens and context, and owns companion KV,
1469
+ the pending true hidden row, cold/restored membership and checkpoint capture.
1470
+ `QwenMtpRows` supplies preparation and draft/commit state at B1 and B>1;
1471
+ its preparation port requires no sampler. A restored request bridges its next
1472
+ token to the saved preceding hidden; cold members discard that bridge. The
1473
+ remaining chunk pairs each shifted token with its preceding target hidden.
1474
+ Preparation evaluates KV and the retained final hidden, leaving unused decoder
1475
+ outputs outside the evaluated graph. Membership and state extraction reuse the
1476
+ existing cache storage and checkpoint format. The scheduler is unchanged.
1477
+
1478
+ Pinned same-B checks pass companion KV and full decoder continuation through
1479
+ B1/B2/B3/B4, cold joins, restored prefixes, retirement and a long chunk boundary
1480
+ on both Macs. Those checks exposed a pre-existing unfused activation in the MTP
1481
+ MLP. Reusing the target's compiled SwiGLU matches the reference vectors. Existing
1482
+ MTP draft/commit checks and both complete suites/typechecks pass. Initial suite
1483
+ failures came from omitted benchmark fixtures and an old M1 DeltaNet golden in
1484
+ the isolated checkouts; restoring each machine's existing inputs fixes them
1485
+ without changing the implementation or regenerating goldens.
1486
+
1487
+ The seven-file provider port and numerical correction are adopted in the
1488
+ unreleased working tree. The M4 HTTP comparison preserves response text and
1489
+ prompt/output counts with effectively flat timing, while draft acceptance
1490
+ traces change. That comparison did not exercise batched MTP prefill because
1491
+ shared target preparation was not yet connected to the new port. Numbers and limits are in
1492
+ benchmarks.md. Main integration suite/typecheck pass.
1493
+
1494
+ The isolated `MlxPrefillRows` driver now owns target membership and chunk
1495
+ progression for ordinary, Qwen MTP and prompt-lookup preparation. Each method
1496
+ supplies initialization, chunk planning, checkpoint capture and completion.
1497
+ The draft provider owns companion prefill state and materializes restored
1498
+ companion copies before target membership releases an SSD backing lease.
1499
+ Final-step maintenance is explicit in the chunk plan. A fully restored
1500
+ pending-token prefix completes without a zero-length model forward.
1501
+ Prepared rows return to scheduling before joining active decode, preserving
1502
+ the first-output publication boundary.
1503
+
1504
+ The connected implementation passes full suites and typechecks on both Macs,
1505
+ and the target's same-B oracle checks through staggered prefill and continuation.
1506
+ The companion and Gemma 12B target oracles also pass on M1. Expanded native MTP serving checks on both
1507
+ Macs prove that a request submitted during the first target chunk joins the
1508
+ next chunk before any output. M4 passes this check with prompt lookup and
1509
+ TurboQuant as well. These checks also cover B1 producer parity, B4 execution,
1510
+ retirement, cache reuse and HTTP grammar/logprobs. Generated target/draft
1511
+ checkpoints preserve RAM/SSD continuation after restart on both Macs with TQ.
1512
+ An added M1 probe confirms four rows actually share prefill in that cache test,
1513
+ before the first output.
1514
+
1515
+ Added method lifecycle checks verify exact target/history coverage, zero-work
1516
+ restored prefixes and cancellation before and after preparation completes.
1517
+ The latter exposed a failure that rejected siblings before active admission.
1518
+ The method now rejects and releases only the cancelled ready row. A first-token
1519
+ consumer failure also leaves an unfinished sibling running. M1 delayed affine
1520
+ MTP/lookup and delayed TurboQuant MTP checks preserve seeded continuation,
1521
+ metadata and speculation through mixed precision, retirement and late joins.
1522
+ The common driver also passes M1 ordinary TQ ownership checks with a 4096-token
1523
+ RAM prefix through concurrent use, retirement and supersession.
1524
+ The balanced M4 comparison is complete. Shared MTP prefill reduces concurrent
1525
+ throughput. Two attribution runs retain the same shared engine but prepare
1526
+ requests individually; both reproduce control responses and restore throughput.
1527
+ This isolates the regression to enabling shared preparation, without requiring
1528
+ a separate serial executor. A narrower policy that finishes a resumed final
1529
+ prefill step before admitting new rows does not recover throughput and produces
1530
+ the same responses and speculation counters as the shared-prefill candidate.
1531
+ Neither scheduling variant is adopted. The common driver is adopted with the
1532
+ cache ownership fix described below.
1533
+ Phase/layer probes narrow the sustained gap to MLP evaluation despite identical
1534
+ Trellis routes, shapes, dtypes and call counts. Settling target state and clearing
1535
+ the temporary pool after preparation does not restore throughput and is not
1536
+ adopted. The snapshot-lifetime investigation below recovers this loss. Numbers
1537
+ and conditions are in benchmarks.md. Broader composed oracle/cache coverage and
1538
+ other draft providers remain open.
1539
+ Candidate: `/Users/joshrossi/.cache/mlx-bun/mtp-prefill-validation`.
1540
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/mtp-prefill*`.
1541
+
1542
+ Common-driver candidate: `/Users/joshrossi/.cache/mlx-bun/mtp-cohort-validation`.
1543
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/mtp-cohort*`.
1544
+ The integration patch and source hashes are recorded in
1545
+ `mtp-cohort-integration.patch` and `mtp-cohort-integration-manifest.json`
1546
+ under that evidence directory. Native logs identify which test expansion
1547
+ ran; earlier serving checks did not include arrival during target prefill.
1548
+
1549
+
1550
+ A deferred compact row snapshot retained its full parent batch until evaluated.
1551
+ Resolving target snapshots before RAM retention recovers the concurrent loss
1552
+ in two M4 runs while preserving every shared-prefill response and full usage
1553
+ record. Failed tile-size, input-evaluation and residency experiments are closed.
1554
+
1555
+ The adopted implementation moves snapshot materialization into the
1556
+ RAM prefix-cache implementation. A backend operation resolves target state and
1557
+ opaque companion tensors before storage accepts ownership. It performs no
1558
+ serialization or disk I/O; eventual SSD persistence keeps its existing queue.
1559
+ Ordinary decode, MTP and lookup publish through the same interface and need no
1560
+ method-local evaluation rule. Evaluation failure leaves ownership with the
1561
+ publisher. The regression test measures retained allocation before any cache
1562
+ read and covers both target and companion rows. Both-machine suites/typechecks, composed native checks and the matched M4
1563
+ comparison pass. Main integration suite, typechecks and hygiene pass. Strict B1/long-prefill
1564
+ acceptance and remaining feature combinations are still open. Numbers belong in
1565
+ benchmarks.md; source and validation records are in
1566
+ `mtp-cohort-cache-boundary-manifest.json` under the cohort evidence directory.
1567
+
1568
+
1569
+ ### Full-attention delayed compression during padded prefill
1570
+
1571
+ The integrated full-attention implementation provides the existing padded-prefill
1572
+ port for delayed affine and TurboQuant rows. Each row keeps physical write
1573
+ positions, valid token coverage and pending finalization separately. Conversion
1574
+ uses valid coverage; codec tensors retain their physical alignment. When all
1575
+ rows share an encoding, the packed layout inherits pending valid ends. Finalizing
1576
+ and retiring rows move encoded planes without re-encoding live values. The same
1577
+ row wrapper and transition lifecycle serve affine and TurboQuant; model methods
1578
+ and scheduling are unchanged.
1579
+
1580
+ The extended pinned cache oracle passes on both Macs with KV4/KV8 and TQ K8/V3
1581
+ and K4/V4, multiple conversion thresholds, cached history, shortened prefill,
1582
+ retirement/reorder, continuation, and leading padding across multiple chunks.
1583
+ It checks masks, positions, retained encoded bytes and same-B attention. Invalid
1584
+ padding bytes are not state: moving encoded zero padding can preserve a different
1585
+ signed zero than encoding it again, while retained values and attention remain
1586
+ exact. Existing unpadded row/cohort regressions pass on M1. The Gemma model gate
1587
+ exposes a before-conversion mismatch when affine attention runs uniform BF16
1588
+ rows separately. The candidate now assembles those tensors through the same
1589
+ helper as TurboQuant and runs attention at the model's B. The cache oracle
1590
+ passes after that change, as does the Gemma affine full-model gate. Both
1591
+ regression suites and typechecks pass. Affine MTP/lookup and delayed affine/TQ
1592
+ seeded serving pass on M1; TQ MTP serving passes on M4. Generated MTP3/B4
1593
+ RAM/SSD continuations pass on both Macs. All four matched M4 arms preserve responses and usage. The measured small
1594
+ throughput decrease is recorded in benchmarks.md; strict B1/long-prefill
1595
+ acceptance remains open. Main integration suite/typechecks pass. Candidate:
1596
+ `/Users/joshrossi/.cache/mlx-bun/full-delayed-prefill-validation`; evidence:
1597
+ `reports/qwen38-closeout/composition-baseline/full-delayed-prefill/`.
1598
+
1599
+
1600
+ ### Standalone autoregressive draft graph integration
1601
+
1602
+ The integrated implementation runs a standalone draft graph at the group's B and
1603
+ hands its log-probabilities to the existing row sampler. Immutable batch
1604
+ snapshots retain accepted recurrent/attention boundaries without changing
1605
+ scheduler policy. Full acceptance retains the last draft token as companion
1606
+ state and re-feeds it with the next target token in one forward, preserving
1607
+ the reference's two-token shape. Mixed one-/two-token feeds use the existing
1608
+ padding interface. Zero-proposal rounds preserve processed-token coverage.
1609
+
1610
+ The lifecycle test covers mixed acceptance, removal/reordering, zero proposals
1611
+ and mixed re-feed lengths. A native Qwen 0.8B gate on M1 checks exact B1
1612
+ attention/recurrent state and continuation at depths 0, 1, 3 and 4. The provider is integrated; its old single-request source now
1613
+ adapts the same draft engine at B1. The small Qwen target/drafter passes B1/B4
1614
+ serving, late joins, consumer failures, seeded sampling/logprobs and HTTP
1615
+ coverage. Companion state reuses backend cache codecs; asynchronous prefill
1616
+ completion now preserves target-context ownership. The 27B target with the 0.8B
1617
+ standalone drafter passes B1/B4 serving on both Macs (228 assertions each),
1618
+ and depth-three TurboQuant generation restores through RAM and cold SSD
1619
+ (33 assertions each). The M4 pinned Python oracle passes the Llama 3B/1B
1620
+ pair, including four templated cases at draft depths two and three, grammar
1621
+ and stopping. Full suites pass on M1/M4 (2,153/2,157 tests), as do all
1622
+ typechecks and the existing MTP/lookup native regressions. The first matched M4 comparison improves B1 decode and cache reuse but
1623
+ hits a GPU allocation failure in the four-request phase, including the
1624
+ benchmark’s retry. The allocation trace explains why short correctness
1625
+ coverage did not expose this workload failure. Replaying
1626
+ all prior requests reproduces the failure with 4,005 MiB of accounted RAM
1627
+ cache entries and a 17,987 MiB observed allocation peak. A fresh aggregate
1628
+ passes. The retained entries consume the remaining working-set headroom;
1629
+ the repeated comparison holds both arms at 2 GiB RAM plus SSD and completes
1630
+ all four arms. Decode/cached/aggregate gains and cold/startup costs are
1631
+ recorded in benchmarks.md. Main integration suite, typechecks and hygiene pass. The retained 4 GiB failure remains part of cache-settings acceptance.
1632
+ Validation source:
1633
+ `/Users/joshrossi/.cache/mlx-bun/two-model-batch-validation`; source hashes and
1634
+ checks: `reports/qwen38-closeout/composition-baseline/two-model-batch/`.
1635
+
1636
+ ### Full-attention target capability binding
1637
+
1638
+ The integrated implementation moves the shared target-layout factory behind
1639
+ one storage capability binding. Grouped speculation then depends on the
1640
+ model graph's batch support and the storage transaction factory, replacing
1641
+ the Qwen-only target selection. Scheduler and draft-provider policy are
1642
+ unchanged; quantized speculation retains its existing qualification while
1643
+ plain full-attention targets are tested. On M1, Llama 3B with the same model
1644
+ as drafter passes shared B1/B4 serving, late joins, retirement, seeded
1645
+ sampling/logprobs and grammar (224 assertions). Prompt lookup passes the
1646
+ same serving harness; generated RAM/SSD continuation passes at depth three.
1647
+ The pinned Llama model oracle is exact at B1/2/3/4/8 across padding, chunks
1648
+ and continuation (541 assertions), and mixed-prefix target rollback passes
1649
+ 1,352 state/continuation assertions. The complete M1 suite and typechecks pass.
1650
+ Both-machine Llama and MiniCPM serving/lookup/cache checks pass, as do the
1651
+ wide same-B oracle, Qwen MTP/TQ regressions, full suites and typechecks.
1652
+ The M4 shared B1 path also passes the pinned templated speculation oracle.
1653
+ Four matched M4 arms complete; gains, cold-prefill cost and the changed
1654
+ concurrent response are recorded in benchmarks.md. Main integration suite, all typechecks and full hygiene pass. Rotating target transactions remain the next storage gap.
1655
+ Validation source:
1656
+ `/Users/joshrossi/.cache/mlx-bun/full-kv-speculation-validation`;
1657
+ evidence: `reports/qwen38-closeout/composition-baseline/full-kv-speculation/`.
1658
+
1659
+
1660
+ ### Rotating target transactions
1661
+
1662
+ The rotating-storage adapter now exposes independent speculative acceptance
1663
+ through the existing target transaction interface. It reuses the existing
1664
+ ring kernels and keeps the verification rectangle: rejected suffixes move
1665
+ into masked left padding. Contracting the rectangle preserved KV columns
1666
+ but failed Gemma continuation equality; that candidate was replaced.
1667
+ Published rows contain the newest accepted window; ordinary ring extraction
1668
+ retains its pinned-oracle oversized-block behavior. No scheduler change.
1669
+
1670
+ Tagged storage windows, cloning, retirement and subsequent writes pass.
1671
+ Both-machine Gemma 12B lookup serving passes at B1/B4, including late joins,
1672
+ consumer failures, grammar, seeded sampling/logprobs and HTTP coverage.
1673
+ Both-machine Gemma target transactions pass 3,080 assertions across prompts
1674
+ straddling the actual 1,024-token window, unequal acceptance and continuation.
1675
+ Both-machine pinned padded-model oracle passes at B1/2/3/4/8, and
1676
+ standalone draft generation restores through RAM/cold SSD. The default
1677
+ lookup depth of ten exposed a singleton geometry difference; an unwrapped
1678
+ single row now retains its scalar prefix geometry without adding padding.
1679
+ The depth-ten serving gates now pass for Gemma 12B and e4b on both Macs.
1680
+ Both final suites/typechecks pass, alongside the Qwen MTP/TurboQuant regression.
1681
+ The final-source matched M4 comparison completes: concurrent throughput and
1682
+ cache reuse improve, while B1 decode is effectively equal. Startup variation
1683
+ and different concurrent trajectories are recorded in benchmarks.md.
1684
+ The adapter is integrated; main integration suite, all typechecks and full hygiene pass. Quantized rotating
1685
+ speculation and the remaining providers are still open.
1686
+ Validation source: `/Users/joshrossi/.cache/mlx-bun/rotating-speculation-validation`.
1687
+ Evidence: `reports/qwen38-closeout/composition-baseline/rotating-speculation/`.
1688
+
1689
+
1690
+ ### Assistant draft rows
1691
+
1692
+ The assistant provider now supplies the same prefill and decode row interfaces
1693
+ as standalone drafting. It retains only the last true target hidden and its
1694
+ processed-token count. The target layout supplies captured donor attention;
1695
+ full and rotating layouts own valid intervals and masks. The draft graph does
1696
+ not know the scheduler or cache geometry. Matching layers and draft steps reuse
1697
+ the same donor mask. All proposals remain on device until the chain completes.
1698
+ Generated checkpoints store the hidden companion alongside existing target KV,
1699
+ using the same RAM ownership and queued SSD persistence.
1700
+
1701
+ Both e4b centroid and 12B tied heads use one graph at B1/B2/B4. The pinned
1702
+ optiq loader assumes centroid presence from config; the 12B numerical test binds
1703
+ its actual tied embedding head by tensor presence while retaining upstream
1704
+ layers. The e4b end-to-end test uses unmodified optiq `spec_generate`. Both
1705
+ machines pass these checks, serving/retirement/late joins, grammar/logprobs and
1706
+ generated RAM/SSD continuations. Tagged donor columns independently verify
1707
+ padding, rejected suffixes, wrap and row removal. The old contiguous transposed
1708
+ weights caused a hidden-state mismatch on M4 even before this refactor. Keeping
1709
+ upstream's strided weight views restores exactness and avoids duplicate weights.
1710
+
1711
+ The candidate is integrated after both regression suites/types and the four-arm
1712
+ M4 comparison. Main integration suite, all typechecks and full hygiene pass. Throughput and cached
1713
+ latency improve; readiness and concurrent-trajectory differences remain recorded
1714
+ in benchmarks.md. DeepSpec follows through projected context rows.
1715
+ Evidence: `reports/qwen38-closeout/composition-baseline/assistant-batch/`.
1716
+
1717
+
1718
+ ### Shared DeepSpec context rows
1719
+
1720
+ DeepSpec's context projections and block graph now accept the active row count.
1721
+ The MLX projected-context owner reuses full-attention row storage, cache codecs
1722
+ and coordinated membership. Its attention port hides context geometry and
1723
+ validity from the block graph. The provider declares its target taps and stores
1724
+ projected context as the ordinary method companion in RAM and queued SSD.
1725
+ Accepted lengths advance each row independently; rejected context never survives
1726
+ in a published checkpoint. The sequential proposal head stays on device through
1727
+ the block, and serving skips unconsumed confidence values when truncation is off.
1728
+
1729
+ Synthetic tests cover bf16/quantized projections, confidence truncation through
1730
+ zero proposals, differing commit lengths, restoration and retirement. Real Gemma
1731
+ 12B serving/generated RAM/SSD checks pass with both DeepSpec bf16 and its affine
1732
+ 4-bit sibling on both Macs, including the trained seven-token block. Native B1
1733
+ full logits and confidence match the frozen implementation; B2/B4 repeat exactly
1734
+ with independent positions. These comparisons are regression controls, not a new
1735
+ external DeepSpec oracle: the existing Torch oracle requires a separate reference
1736
+ environment and bf16 target that are not currently installed on either laptop.
1737
+ Real-window checks confirm that shared speculation remains active across wrap
1738
+ while the previous serial path stops drafting there. Both-machine regression
1739
+ suites and all typechecks pass. Four matched M4 arms improve aggregate throughput
1740
+ and cached latency; startup cost and one changed concurrent response remain
1741
+ recorded in benchmarks.md. The candidate is integrated; the main regression
1742
+ suite, all typechecks and full hygiene pass. DSpark/DFlash is next and shares the projected-context lifecycle.
1743
+ Evidence: `reports/qwen38-closeout/composition-baseline/deepspec-batch/`.
1744
+
1745
+
1746
+ ### Shared DSpark/DFlash provider
1747
+
1748
+ The draft graph accepts B1 and B>1 through one backbone and sequential proposal
1749
+ head. Markov and RNN heads retain their existing numerical behavior. Confidence
1750
+ can retire proposals independently for each row, and sampled proposal streams
1751
+ remain independent. Serving avoids confidence and float-logit outputs it does
1752
+ not consume. Scheduling does not select a draft implementation.
1753
+
1754
+ DSpark and DeepSpec use the same projected-context lifecycle. The provider binds
1755
+ projection and proposal operations; the shared owner handles prefill, accepted
1756
+ lengths, row membership, capture and restoration. The MLX context store applies
1757
+ padding and attention validity. Generated context enters the existing RAM cache
1758
+ and queued SSD persistence as a method companion.
1759
+
1760
+ Pinned graph outputs and both-machine Markov/RNN real-Gemma serving/generated
1761
+ RAM/SSD tests pass. Those tests use seeded draft weights, so they establish
1762
+ execution and state contracts, not trained acceptance or quality. Josh confirms
1763
+ that no DSpark/DFlash checkpoint has been trained yet. DeepSpec's real trained provider passes again
1764
+ after the extraction. Full suites and all typechecks pass on both Macs. Four M4
1765
+ arms measure the extraction using the same trained DeepSpec checkpoint and
1766
+ preserve all responses and usage. The measured throughput cost is recorded in
1767
+ benchmarks.md. The provider is integrated; the main suite, all typechecks
1768
+ and full hygiene pass. Trained DSpark performance qualification remains open. Evidence:
1769
+ `reports/qwen38-closeout/composition-baseline/dflash-batch/`.
1770
+
1771
+
1772
+ ### Affine rotating speculation and encoded assistant donors
1773
+
1774
+ Uniform start-zero KV4/KV8 target layouts now compose with grouped draft
1775
+ providers on full-attention and rotating targets. Acceptance bookkeeping is
1776
+ shared by plain and encoded rings. Packed values, scales and biases use the
1777
+ same row operations; rollback, retirement and snapshots never dequantize.
1778
+ Ordinary rotating extraction retains the oracle's oversized-block geometry;
1779
+ committed speculative snapshots retain only the newest valid window.
1780
+ Unpadded verification keeps the existing fused attention mask dispatch.
1781
+ Standard universal attention and MiniCPM now consume encoded cache ports
1782
+ instead of assuming plain arrays or a concrete affine cache class. The
1783
+ universal softcap branch retains its existing plain-only qualification.
1784
+
1785
+ Assistant drafting consumes an opaque donor-attention interface. Storage owns
1786
+ the encoded planes and validity ranges; the assistant only supplies queries.
1787
+ Its compatibility source now adapts the same row graph at B1. The redundant
1788
+ plain-only AssistantTarget interface is removed. Additive donor masks follow
1789
+ the pinned affine attention operation, independently of boolean cache masks.
1790
+
1791
+ Native continuation controls must hold both batch size and physical attention
1792
+ width fixed. The pinned Python oracle reproduces the captured different-width
1793
+ full-attention results byte for byte: one bf16 output differs despite identical
1794
+ queries and valid KV. The transaction test pads only the reference's fetched
1795
+ views to the compared width, retaining exact state and hidden checks.
1796
+ The old executor disables speculation near the rotating boundary, so its KV4
1797
+ text can differ from active shared speculation. Live-window tests record that
1798
+ comparison and check repeated active execution; they do not relabel ordinary
1799
+ fallback as an exact speculative oracle.
1800
+
1801
+ Both-machine KV4/KV8 serving and generated RAM/SSD checks pass for DeepSpec,
1802
+ assistant, standalone and lookup providers; seeded DSpark heads pass the same
1803
+ state contracts. Real-window transactions, same-width target controls, pinned
1804
+ regressions, full suites and all typechecks pass. Six M4 benchmark arms preserve
1805
+ bf16 responses and usage with effectively unchanged throughput. KV4 improves
1806
+ aggregate throughput on this workload, with different generated text and more
1807
+ prefill time; the comparison is recorded in benchmarks.md. The change is
1808
+ integrated; the main suite, all typechecks and full hygiene pass.
1809
+ Evidence: reports/qwen38-closeout/composition-baseline/rotating-spec-quant/.
1810
+ Strict performance dominance and removal of the serial control remain open.
1811
+
1812
+
1813
+ ### TurboQuant donor attention and grouped draft composition
1814
+
1815
+ Solo, packed and delayed TurboQuant storage expose the same owned donor-attention
1816
+ interface as plain and affine caches. Captures preserve physical columns, row
1817
+ validity and right-prefill padding without appending tokens, converting precision
1818
+ or advancing membership. Assistant attention consumes eagerly decoded values,
1819
+ preserving its existing operation order. MiniCPM retains its explicit deferred
1820
+ value rotation. Storage chooses the existing codec and fused decode kernels;
1821
+ scheduling does not identify the encoding or draft provider.
1822
+
1823
+ The gateway advertises grouped TurboQuant from the bound target and provider
1824
+ capabilities. Positive conversion thresholds use the existing row-local
1825
+ transition lifecycle; sliding layers remain bf16. Per-layer affine speculative
1826
+ configuration composes through the same bound row capabilities. Group binding now snapshots per-layer and
1827
+ TQ options so caller mutation cannot change a live graph or its persisted
1828
+ identity. Explicit per-layer schemes get distinct group/cache keys, with
1829
+ canonical layer ordering; absent/empty schemes preserve existing keys exactly.
1830
+
1831
+ The isolated candidate passes independent K8/V3 donor codec plus pinned assistant
1832
+ graph controls at B1/B2/B4 with fused decoding on/off for both Gemma assistant
1833
+ artifacts on the M4, alongside the unchanged bf16 oracle. M1 assistant and
1834
+ MiniCPM lookup pass start-zero serving/generated RAM/SSD and delayed conversion,
1835
+ retirement and late admission. Both-machine assistant, DeepSpec, standalone and lookup serving/generated
1836
+ RAM/SSD, delayed conversion and late admission pass, along with seeded DSpark
1837
+ heads, Qwen regressions, final suites and typechecks. Twelve M4 timing arms
1838
+ record both source-only costs and TQ configuration tradeoffs in benchmarks.md.
1839
+ The source is integrated; main suite, all typechecks and full hygiene pass.
1840
+ Evidence: `reports/qwen38-closeout/composition-baseline/turboquant-donor/`.
1841
+
1842
+ The independent assistant control also exposed an existing centroid-head
1843
+ numerical shortcut on M1: matrix multiplication did not preserve the oracle's
1844
+ bf16 multiplication followed by reduction. On identical B2 hidden state, Python
1845
+ reproduced the old candidate token with matmul and the oracle token with explicit
1846
+ multiply/sum. The shared head now preserves that operation order at every B and
1847
+ selects the lowest vocabulary ID among tied candidate scores, matching sparse
1848
+ vocabulary argmax without materializing a full-vocabulary logits buffer. The
1849
+ independent codec, hidden-state and token assertions remain exact. The M1 e4b
1850
+ control and unmodified end-to-end optiq generation pass after the correction;
1851
+ final both-machine regressions pass. The source-only and TQ timing comparisons
1852
+ are recorded in benchmarks.md. Attribution repeats recover the prior decode rate on the unchanged candidate, so they do not establish a code regression. Captured diagnostics live
1853
+ with the composition evidence.
1854
+
1855
+
1856
+ ### Delayed and per-layer affine rotating speculation
1857
+
1858
+ Rotating storage owns an accepted-column transaction shared by plain and affine rings. The generic transition interface invokes that transaction while rows have different precisions; after conversion it packs them into the existing affine layout. Conversion sees only committed tokens. Scheduling and draft providers do not inspect the quantization scheme.
1859
+
1860
+ Full and rotating caches expose owned donor-attention views. Mixed rows retain their physical columns, valid offsets and padding; assistants submit queries and masks without materializing a common decoded cache. Pending right-prefill padding is excluded before finalization, including when a physical block exceeds the sliding window. Captures survive cache conversion, row reordering and disposal.
1861
+
1862
+ The gateway now advertises supported affine configurations from the target/provider binding, including model-defined per-layer schemes and positive library thresholds. The served CLI schemes retain start zero. Independent attention fixtures cover padding and ownership; exact target hidden/logit controls cross the real sliding boundary at verification widths one and eight. Native checks cover continuation, precision transitions, unequal retirement, late admission, grammar/logprobs and generated RAM/SSD companions. Legacy serving rejects some of these combinations; repeated shared execution is not relabeled as a legacy speculative oracle.
1863
+
1864
+ Both-machine provider/native/suite/typechecks and six matched M4 benchmark arms are complete. Bf16 responses and usage remain exact; model-defined per-layer KV trades higher single-request decode for lower aggregate throughput on the measured workload. The change is integrated; main suite, types and full hygiene pass. Evidence: `reports/qwen38-closeout/composition-baseline/delayed-rotating-spec/`. Defaults and the serial retirement criterion remain unchanged.
1865
+
1866
+
1867
+ ### GLM compressed target and native MTP rows
1868
+
1869
+ The integrated implementation adds independent accepted-column transactions and cold-row membership to compressed MLA/DSA storage, without reconstructing full K/V. Native MTP exposes a shared numerical graph and a grouped provider. Its prompt prefill retains the target anchor while leaving MTP cache empty; committed accepted positions are rebuilt from true target hidden states. Target token coverage and the shorter draft-cache offset remain separate checkpoint metadata. The existing attachment interface persists both through the generic RAM/SSD cache.
1870
+
1871
+ Both-machine tiny-model controls cover exact B1 proposals/absorption, zero-proposal rounds, streamed expert calls, B4 membership with DSA enabled, late admission, retirement, generated-prefix identity and identical RAM/SSD next drafts. DSA verification retains every request row and shares each logical query selection across FULL/SHARED layers. Compressed multi-token attention now masks physical left padding, including native MTP absorption. Empty DSA rows survive filtering and resumed writes. Six two-layer dense/sparse boundary cases per machine match independent pinned Python/MLX hidden and every cache plane byte-for-byte. Python uses the uncompiled sigmoid/multiply activation that this model graph calls. Different-B controls retain greedy IDs but can differ in small f32 values because physical widths select absorbed/reconstructed attention and different matrix kernels; they are not the exact numerical oracle. Both full model-free suites, the SSD suite and all typechecks pass. The tested implementation is integrated in the PR. Josh has deferred final GLM-5.2 Colibri artifact testing. This does not establish real-artifact numerical or performance acceptance. Evidence: `reports/qwen38-closeout/composition-baseline/mla-transaction/`.
1872
+
1873
+
1874
+ ### Paged storage through shared row and request-state interfaces
1875
+
1876
+ `PagedKvRows` owns per-request block pools, immutable snapshots, gathering, masks, offsets and row membership. The existing executor binds it through the cache-layout interface. `MlxRequestStatePolicy` supplies compatible state construction and a prompt-cache port; paging selects no prefix store. Switching back to ordinary requests restores their cache port. The same paging constructor serves the compatibility entry point and shared prefill. B1 keeps the existing paged numerical graph; B>1 gathers padded attention inputs while retaining separate persistent pools. Gemma12 full sampled logits and HTTP choices match the ordinary same-B controls, including seeded sampling, logprobs and grammar. Both-machine model-free, SSD and typechecks pass. The native storage comparison fixes cohort membership and snapshot boundaries on both sides, covering small blocks and the default block boundary; otherwise cache publication changes the numerical prefill graph. The matched M4 source comparison is effectively flat, and shared paging improves concurrent throughput versus serial while retaining effectively equal B1 decode. Concurrent text can differ across batch geometries; the exact storage oracle compares the same geometry. Timing and limitations live in benchmarks.md; evidence is `reports/qwen38-closeout/composition-baseline/paged-rows/`. Subsequent C1–C5 work adds shared SSD blocks and optional direct bf16/affine paged attention; its measured results are recorded in benchmarks.md. TQ pages and paged speculation remain separate extensions.
1877
+
1878
+ The sampler now exposes an optional stateless operation for compatible independent score rows. Ordinary decode and speculative verification share normalized-score argmax. Verification can sample a rectangle in one device operation and readback; acceptance still consumes only each request's valid positions. Grammar, processors, stochastic sampling, logprob capture and custom sampler functions retain their request-local operation. Same-shape numerical tests include rounding-created ties and large vocabularies; both-machine native/generated RAM/SSD and suites pass. Twelve matched M4 arms preserve ordinary throughput and improve lookup aggregate throughput; startup and trajectory limits are recorded in benchmarks.md. Lookup defaults remain unchanged. Evidence: `reports/qwen38-closeout/composition-baseline/independent-sampling/`.
1879
+
1880
+
1881
+ The affine same-B oracle now covers full-attention and rotating mixed-precision
1882
+ rows, including unequal lengths, window crossing, reordering and retirement.
1883
+ Equal-length rotating storage uses the pinned OptiQ implementation. Padded
1884
+ rotating cases compose it with stock mlx-lm batch positions and masks; they do
1885
+ not substitute solo-row logits for the batch oracle. The test-only reference
1886
+ and its limits are described in [benchmarks.md](../reference/benchmarks.md#same-batch-rotating-affine-oracle).
1887
+ Existing delayed-conversion, provider and lifecycle tests remain separate evidence.
1888
+
1889
+ ### Campaign checkout consolidation
1890
+
1891
+ The PR incorporates the accepted implementations from the M1 and M4 campaign
1892
+ checkouts, including ordinary resume, adapter-aware resume and GLM shared MTP
1893
+ state. Older TQ, provider, cache and prefill candidates are superseded by the
1894
+ integrated compositions above. Benchmark baselines and rejected wider-Trellis,
1895
+ option-capture, state-only replay and cohort scheduling variants remain
1896
+ experiment records; copying them over the selected implementation would undo
1897
+ later work. The singleton `copyOf` to `contiguous` candidate remains unpromoted
1898
+ because its attribution and startup result are unresolved.
1899
+
1900
+ The 80 secondary Git worktrees and 99 campaign source copies were removed
1901
+ after their source files and reports were verified in a content-addressed local archive under
1902
+ `reports/pr-closeout/checkout-archive/`, with per-checkout manifests, SHA-256
1903
+ objects and the recorded base commit. The PR retains the implementation and
1904
+ findings; bulky raw experiment data stays local under the repository policy.
1905
+
1906
+
1907
+ ### Scheduling reference algorithms and request observations
1908
+
1909
+ The next scheduling baseline is an iteration token budget, following the
1910
+ upstream implementations below. Review date: 2026-09-12. Read implementation
1911
+ order as well as configuration docs; scheduling first does not necessarily
1912
+ mean delivering output before the iteration's other GPU work finishes.
1913
+
1914
+ | Reference | Algorithm and ownership | Application here |
1915
+ |---|---|---|
1916
+ | [vLLM V1 scheduler, `dff76bc`](https://github.com/vllm-project/vllm/blob/dff76bc3e8d702901e6dda5971f9506a6c1bc00f/vllm/v1/core/sched/scheduler.py#L562) | Tracks computed tokens against required tokens, including speculative positions. Allocates the iteration budget to running requests before waiting requests. Prefill chunks and decode tokens can enter the same execution batch. | Represent remaining work through the scheduling interface; methods supply valid token work and the backend owns batch packing and kernels. |
1917
+ | [llama.cpp server, `3057bb6`](https://github.com/ggml-org/llama.cpp/blob/3057bb66c86c46d5781e50e85462a760ba7d1feb/tools/server/server-context.cpp#L2974) | Adds generating/drafting slots before filling the remaining batch capacity with compatible prompt tokens. Logical batch and physical microbatch capacities are distinct. HTTP workers own parsing, templates and streaming; one inference thread owns slots. | Preserve execution ownership while allowing request preparation and response transport to progress independently. A shared request count is insufficient; account for token work too. |
1918
+ | [mlx-lm generator, `dcbcf78`](https://github.com/ml-explore/mlx-lm/blob/dcbcf786c0cf56f9a12fabe9468c887781431ae2/mlx_lm/generate.py#L1783) | Advances generation first, admits/splits prompt rows, then processes bounded prompt chunks. Prompt and generation batches remain separate. Responses return after prompt processing, whose cache evaluation synchronizes. The pinned oracle has the same order. | This is the closest numerical/backend reference, but its response timing is not evidence that output is immediately flushed. Compare its actual request timeline. |
1919
+ | [LangChain streaming](https://docs.langchain.com/oss/python/langchain/streaming) | Routes model-provided text, reasoning and tool-call chunks through the agent application. | Reference for stream semantics; this layer does not select GPU prefill/decode work. |
1920
+
1921
+ [vLLM's tuning guidance](https://docs.vllm.ai/en/latest/configuration/optimization/#chunked-prefill)
1922
+ explicitly treats token budget as a latency/throughput tradeoff. Its GPU-specific
1923
+ budget recommendations are not Apple Silicon defaults. Start with the established
1924
+ algorithm, measure the same submitted work on M4, and retain deviations only
1925
+ with recorded benefits and costs. No framework guarantees one universally best
1926
+ chunk size or latency policy.
1927
+
1928
+ The established backend exposes `advance()` and `advancePreparation()`
1929
+ operations. `MlxPrefillRows` groups prompt rows, while ordinary and speculative
1930
+ methods advance decoding rows separately. The existing preparation budget limits
1931
+ cohort admission; it is not vLLM's combined per-iteration token budget. True mixed
1932
+ execution therefore needs backend work as well as scheduling policy. Padding a
1933
+ single decode token to a long prompt's width would defeat the intended saving.
1934
+
1935
+ Phase 18 S1b adds bounded mixed work. The method retains request identity,
1936
+ computed/required positions and candidate state. Scheduling allocates
1937
+ bounded work to active requests and then queued requests; the backend executes
1938
+ compatible selections. Sampling and cache ownership remain unchanged. Acceptance
1939
+ covers lone requests, arrivals during prefill and decode, unequal lengths,
1940
+ cancellation/retirement, speculative work and quantized state. Compare first
1941
+ semantic output, inter-output gaps, total workload time, occupancy, padding and
1942
+ memory alongside aggregate throughput. Same-B numerical contracts remain binding.
1943
+
1944
+ The P2R observer now separates row preparation, forward, remaining cache
1945
+ execution, maintenance, checkpoint capture, projection, completion and companion
1946
+ work. Shared work IDs and process-local time origins allow cross-request
1947
+ attribution without counting shared GPU work several times. Bounded initial
1948
+ routing spans expose hidden control tokens. Measurement semantics and the report
1949
+ command live in [server-config](../reference/server-config.md); measured results
1950
+ live in [benchmarks](../reference/benchmarks.md#prefill-observation-and-scheduling-screen).
1951
+ The simple active-before-prefill experiment remains an unadopted patch in the
1952
+ local report directory; it is not the mixed execution design above.
1953
+
1954
+ A second bounded screen submits shared prefill evaluation asynchronously and
1955
+ polls MLX completion while allowing Bun to service I/O. MLX's
1956
+ [`array::is_available`](https://github.com/ml-explore/mlx/blob/main/mlx/array.cpp)
1957
+ checks the completion event, not merely graph submission; the pinned native
1958
+ pack exports mlx-c's `_mlx_array_is_available`. This avoids holding the host
1959
+ thread during the GPU wait, but changes when requests become visible to the
1960
+ existing scheduler. Both M1 MiniCPM arm orders delay the first staggered
1961
+ request substantially; aggregate results are inconsistent. The candidate is
1962
+ removed. [Measurements](../reference/benchmarks.md#nonblocking-prefill-completion-screen)
1963
+ retain the excluded patch. Host responsiveness and request scheduling must be
1964
+ measured together before retaining a different completion boundary.
1965
+
1966
+
1967
+ #### Mixed token execution
1968
+
1969
+ The Lab Gemma and Qwen3.5/3.8 paths execute running decode and queued prompt work together.
1970
+ `ExecutionGroup.mixedPreparation` reports running-token demand and the minimum
1971
+ prompt work needed for progress. The scheduler reserves that demand and assigns
1972
+ the remaining iteration budget to preparation. Existing cohort admission still
1973
+ accounts for total prompt work. Removing that limit was measured and rejected:
1974
+ on this M4 workload, larger cohorts lost throughput and delayed later first
1975
+ outputs. Both variants execute the same bounded mixed-token model port.
1976
+
1977
+ `MlxPreparationWork` carries a token allowance and forward operation into the
1978
+ shared preparation driver. It limits actual tokens across rows while preserving
1979
+ planned precision conversions and checkpoint endpoints. `runMixedTokenIteration`
1980
+ collects the preparation and decode forward inputs. The model's `MixedTokenModel`
1981
+ port receives independent `TokenGroup` inputs with their existing row geometry
1982
+ and caches. Decode finishes sampling, publication and retirement before a
1983
+ completed preparation can join the active rows. A restored or cancelled
1984
+ preparation can finish without producing model work; an exhausted decode can
1985
+ publish its pending token without another forward.
1986
+
1987
+ Gemma reuses its existing attention and feed-forward layer interfaces. Attention
1988
+ retains each group's RoPE positions, masks, SDPA shape and cache operations.
1989
+ `mapPackedTokens` concatenates only real tokens for the feed-forward block and
1990
+ restores each group's output shape afterwards. It adds no padding or host
1991
+ readback. This is shared feed-forward execution, not a fully packed attention
1992
+ kernel. The unpacked control keeps the same scheduler budget to isolate the
1993
+ packing benefit. The original single-group model call remains unchanged.
1994
+
1995
+ Packing can change GEMV/GEMM dispatch relative to solo generation. The numerical
1996
+ contract therefore uses the pinned oracle with the same packed feed-forward
1997
+ geometry and independent attention shapes. The real-model test passes on M4 for
1998
+ Gemma e4b, 12B and 26B with bf16 and uniform affine KV4, continuation, and unequal
1999
+ decode/prefill row counts. The
2000
+ uniform-KV oracle explicitly uses stock quantized SDPA on both sides. Native
2001
+ state tests also cover bounded preparation with immediate and delayed affine
2002
+ and TurboQuant conversion. Failure, cancellation and retirement tests exercise
2003
+ the shared execution group and the work coordinator.
2004
+
2005
+ Qwen reuses its attention/DeltaNet and feed-forward blocks through the same
2006
+ model port. Masks, convolution tails and recurrent state remain per group;
2007
+ layer evaluation materializes both residual and cache outputs to bound prefill
2008
+ memory. Each `TokenGroup` can supply a borrowed layer-capture callback and
2009
+ request preservation of its matmul geometry. Speculative methods use those
2010
+ options for target verification, including pending tokens and draft candidates,
2011
+ and keep provider companion updates in their preparation/verification adapters.
2012
+ The scheduler sees the method’s target-token demand, not its draft algorithm.
2013
+ Hidden captures belong to each work item instead of a shared mutable model tap.
2014
+
2015
+ The measured default decision is to retain mixed execution as opt-in. Gemma
2016
+ first-output latency improves with an aggregate-throughput cost; Qwen MTP has
2017
+ no first-output win and loses aggregate throughput, despite a shorter worst
2018
+ streaming pause. This closes the bounded S1b comparison. Trace phase
2019
+ `engine.mixed_forward` records the model-call construction span and real token
2020
+ counts; GPU waits remain at the existing evaluation/readback boundaries. The
2021
+ [measured comparison](../reference/benchmarks.md#mixed-prefill-and-decode-token-work)
2022
+ records latency, throughput, streaming gaps and the unpacked control. Runtime
2023
+ settings live in [server-config](../reference/server-config.md).
2024
+
2025
+
2026
+ ### Grammar candidates through the shared verifier
2027
+
2028
+ `GrammarController.proposeTokens` reads xgrammar's forced continuation without
2029
+ advancing the matcher. It joins the existing WASM queue so concurrent requests
2030
+ cannot overlap calls into the single WASM instance. A request-owned constraint
2031
+ port supplies candidates to the same grouped verifier used by learned drafts
2032
+ and prompt lookup. The sampler applies each request's mask and commits its
2033
+ accepted tokens; scheduling only sees method work. Target graph binding no
2034
+ longer requires a serial draft constructor.
2035
+
2036
+ The constraint provider reuses prompt lookup's committed-history ownership and
2037
+ checkpoint format. It never searches history and has no serial draft method.
2038
+ Empty candidate lists use the verifier's existing one-token step. Candidate
2039
+ rejection and row retirement keep target and companion state aligned through
2040
+ the existing transaction and output interfaces.
2041
+
2042
+ `MLX_BUN_GRAMMAR_JUMP=1` selects this method for eligible shared structured-output
2043
+ requests without a configured drafter; `MLX_BUN_GRAMMAR_DRAFT_TOKENS` controls
2044
+ depth separately from batching. Shared logprobs remain available because every
2045
+ output is sampled. Explicit serial retains direct retokenized jump-forward.
2046
+ That algorithm skips target sampling for forced spans; the shared proposal
2047
+ algorithm verifies them. Both remain opt-in and must be compared separately.
2048
+
2049
+ The focused MiniCPM and packed-Qwen checks cover nonmutating proposals, B1 and
2050
+ concurrent requests, independent stopping/cancellation, affine/TurboQuant and
2051
+ logprob delivery. Fixed bf16 MiniCPM outputs match ordinary decoding. Affine
2052
+ MiniCPM can choose different valid tokenizations across verification widths;
2053
+ repeated fixed-configuration outputs match. Same-geometry verifier/KV oracles
2054
+ remain the numerical contract. Performance is recorded in benchmarks.md.