mlx-bun 0.4.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 (158) hide show
  1. package/README.md +57 -32
  2. package/docs/README.md +55 -42
  3. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +3617 -0
  4. package/docs/archive/planning/release-notes-v0.5.0.md +37 -0
  5. package/docs/design/batching.md +220 -7
  6. package/docs/design/decode-speed-program.md +121 -66
  7. package/docs/design/generic-model-support.md +116 -0
  8. package/docs/design/kv-cache.md +380 -211
  9. package/docs/design/speculative-decoding.md +165 -26
  10. package/docs/design/turboquant.md +20 -7
  11. package/docs/design/unified-engine-frontier-plan.md +120 -13
  12. package/docs/planning/PRODUCT_ROADMAP.md +5 -6
  13. package/docs/planning/public-readiness-handoff.md +244 -0
  14. package/docs/planning/public-readiness.md +149 -0
  15. package/docs/reference/benchmarks.md +3463 -3489
  16. package/docs/reference/cli.md +62 -1
  17. package/docs/reference/distribution.md +29 -4
  18. package/docs/reference/environment.md +104 -8
  19. package/docs/reference/library-api.md +18 -4
  20. package/docs/reference/memory.md +1 -1
  21. package/docs/reference/models.md +17 -5
  22. package/docs/reference/server-api.md +181 -11
  23. package/docs/reference/server-config.md +232 -105
  24. package/package.json +2 -2
  25. package/src/audio/audiotoolbox.ts +112 -0
  26. package/src/audio/conformer.ts +8 -0
  27. package/src/audio/mic-capture.ts +98 -0
  28. package/src/audio/silero-vad.ts +379 -0
  29. package/src/audio/whisper-decode.ts +774 -0
  30. package/src/audio/whisper-fast.ts +732 -0
  31. package/src/audio/whisper-format.ts +73 -0
  32. package/src/audio/whisper-mel.ts +185 -0
  33. package/src/audio/whisper-timing.ts +274 -0
  34. package/src/audio/whisper-tokenizer.ts +239 -0
  35. package/src/audio/whisper-transcribe.ts +410 -0
  36. package/src/backends/mlx/autoregressive.ts +22 -1
  37. package/src/backends/mlx/batch-group.ts +111 -27
  38. package/src/backends/mlx/cache-layout.ts +3 -3
  39. package/src/backends/mlx/continuation-persistence.ts +5 -4
  40. package/src/backends/mlx/encoder-cache.ts +25 -0
  41. package/src/backends/mlx/fill-append.ts +21 -8
  42. package/src/backends/mlx/fill-group.ts +497 -0
  43. package/src/backends/mlx/gateway-binding.ts +56 -12
  44. package/src/backends/mlx/kv-maintenance.ts +30 -2
  45. package/src/backends/mlx/mixed-iteration.ts +62 -0
  46. package/src/backends/mlx/model-prompt.ts +46 -32
  47. package/src/backends/mlx/model-serving.ts +4 -3
  48. package/src/backends/mlx/paged-cache-codec.ts +27 -0
  49. package/src/backends/mlx/prefill-cohort.ts +15 -4
  50. package/src/backends/mlx/prefill-policy.ts +26 -0
  51. package/src/backends/mlx/prefill-rows.ts +57 -13
  52. package/src/backends/mlx/prompt-input.ts +29 -0
  53. package/src/backends/mlx/qwen-prompt-input.ts +40 -0
  54. package/src/backends/mlx/request-state-policy.ts +18 -5
  55. package/src/backends/mlx/rollback.ts +6 -3
  56. package/src/backends/mlx/serial-executor.ts +16 -7
  57. package/src/backends/mlx/speculative-group.ts +105 -26
  58. package/src/backends/mlx/speculative.ts +24 -7
  59. package/src/backends/mlx/target-layout-capability.ts +1 -1
  60. package/src/backends/mlx/transitioning-kv-rows.ts +8 -0
  61. package/src/cli.ts +322 -0
  62. package/src/contracts/execution.ts +10 -0
  63. package/src/contracts/object-cache.ts +8 -0
  64. package/src/contracts/pi-provider.ts +1 -1
  65. package/src/contracts/pi.ts +3 -1
  66. package/src/contracts/prefix-cache.ts +13 -3
  67. package/src/contracts/scheduling.ts +9 -0
  68. package/src/engine/execution-plan.ts +23 -12
  69. package/src/engine/execution-tasks.ts +44 -0
  70. package/src/engine/namespaced-cache.ts +13 -0
  71. package/src/engine/scheduler.ts +22 -2
  72. package/src/fill/fill-session.ts +14 -3
  73. package/src/generate.ts +28 -22
  74. package/src/grammar.ts +13 -0
  75. package/src/inference/prefill.ts +6 -0
  76. package/src/kv-scheme.ts +22 -0
  77. package/src/kv-store.ts +115 -79
  78. package/src/lab/README.md +5 -1
  79. package/src/lab/paged-kv/paged-attention.ts +117 -0
  80. package/src/lab/paged-kv/paged-kv-rows.ts +33 -5
  81. package/src/lab/paged-kv/paged-kv.ts +108 -42
  82. package/src/md-modules.d.ts +5 -0
  83. package/src/mlx/array.ts +37 -0
  84. package/src/mlx/ffi.ts +19 -0
  85. package/src/mlx/normalized-argmax.ts +116 -0
  86. package/src/mlx/ops.ts +97 -10
  87. package/src/model/batched-turboquant-kv.ts +6 -5
  88. package/src/model/delayed-quantized-kv.ts +3 -3
  89. package/src/model/delayed-rotating-quantized-kv.ts +1 -1
  90. package/src/model/delayed-turboquant-kv.ts +6 -4
  91. package/src/model/factory.ts +26 -0
  92. package/src/model/fingerprint.ts +12 -0
  93. package/src/model/full-prefill-row.ts +1 -1
  94. package/src/model/gemma4-base.ts +25 -6
  95. package/src/model/gemma4.ts +82 -2
  96. package/src/model/kv-attention-view.ts +4 -1
  97. package/src/model/profile.ts +29 -4
  98. package/src/model/quantized-append-attention.ts +31 -0
  99. package/src/model/qwen3-mrope.ts +7 -9
  100. package/src/model/qwen3_5.ts +99 -37
  101. package/src/model/support.ts +8 -0
  102. package/src/model/token-groups.ts +66 -0
  103. package/src/model/trellis-linear.ts +2 -2
  104. package/src/model/turboquant-codec.ts +6 -0
  105. package/src/model/whisper.ts +435 -0
  106. package/src/native/mic_capture.swift +92 -0
  107. package/src/native-pack.ts +6 -5
  108. package/src/pi-web.ts +9 -1
  109. package/src/prompt-cache.ts +265 -43
  110. package/src/runtime-config.ts +1 -5
  111. package/src/safetensors.ts +9 -2
  112. package/src/sampler.ts +5 -4
  113. package/src/serve/audio-routes.ts +323 -0
  114. package/src/serve/chat-request.ts +2 -0
  115. package/src/serve/chat-stage.ts +17 -12
  116. package/src/serve/completion-executor.ts +9 -1
  117. package/src/serve/discovery-routes.ts +17 -1
  118. package/src/serve/generated-token-history.ts +57 -0
  119. package/src/serve/generation-gateway.ts +52 -11
  120. package/src/serve/model-binding.ts +7 -1
  121. package/src/serve/preparation.ts +3 -3
  122. package/src/serve/prompt-response-trace.ts +14 -0
  123. package/src/serve/request-plan.ts +2 -0
  124. package/src/serve/request-prep.ts +38 -21
  125. package/src/serve/transcription-server.ts +64 -0
  126. package/src/serve/transcription-service.ts +502 -0
  127. package/src/server.ts +132 -164
  128. package/src/spec/assistant-rows.ts +1 -0
  129. package/src/spec/deepspec-rows.ts +1 -1
  130. package/src/spec/dflash-source.ts +1 -1
  131. package/src/spec/glm52-mtp-source.ts +1 -0
  132. package/src/spec/ngram-source.ts +27 -5
  133. package/src/spec/projected-draft-rows.ts +2 -2
  134. package/src/spec/qwen-mtp-rows.ts +11 -0
  135. package/src/spec/qwen-mtp-source.ts +3 -0
  136. package/src/spec/serve-loop.ts +5 -3
  137. package/src/spec/source.ts +14 -1
  138. package/src/spec/two-model-rows.ts +1 -0
  139. package/src/spec/two-model.ts +2 -2
  140. package/src/ssd-cache.ts +76 -17
  141. package/src/ssd-durability.ts +20 -22
  142. package/src/storage/host-buffer.ts +24 -0
  143. package/src/storage/kv-writer.ts +83 -0
  144. package/src/storage/kv-writer.worker.js +264 -0
  145. package/src/storage/retention-policy.ts +37 -0
  146. package/src/tiered-prompt-cache.ts +45 -0
  147. package/src/vision/embedder.ts +8 -0
  148. package/src/vision/prompt.ts +101 -65
  149. package/src/vision/qwen3vl-prompt.ts +101 -64
  150. package/src/vision/qwen3vl-tower.ts +11 -0
  151. package/src/vision/siglip.ts +8 -0
  152. package/src/web/app.html +12 -0
  153. package/src/web/app.js +160 -0
  154. package/src/web/src/chat.ts +4 -1
  155. package/src/web/src/composer.ts +3 -0
  156. package/src/web/src/voice.ts +141 -0
  157. package/src/web/sw.js +1 -1
  158. /package/docs/{planning → archive/planning}/release-notes-v0.4.0.md +0 -0
@@ -0,0 +1,3617 @@
1
+ # Benchmark ledger through v0.4.0
2
+
3
+ Frozen campaign record moved from `docs/reference/benchmarks.md`. Entries describe
4
+ the source and machine conditions at measurement time; references to unreleased
5
+ work and internal procedures are historical. Current results and reproduction
6
+ instructions live in [benchmarks.md](../../reference/benchmarks.md).
7
+
8
+ The durable, hand-maintained benchmark record. Raw per-run files
9
+ (`benchmarks-h2h-<date>-<machine>.md/.html`) are gitignored ephemera; the
10
+ structured backing record is the user-local eval DB
11
+ (`~/.cache/mlx-bun/evals.sqlite`). Promote a run into this file
12
+ deliberately when it becomes the new reference.
13
+
14
+ New raw request records also retain the server's final `usage` object,
15
+ including execution lane and speculative counters when supplied. The reader
16
+ captures these already-parsed fields after timing finishes; older reports may
17
+ lack them. This lets settings comparisons verify which method actually ran.
18
+
19
+ The optional `mlx-bun-isolated` arm runs the same CLI/model/request cells through
20
+ `--isolate`; select it alongside `mlx-bun` to compare transport cost. Its RSS
21
+ column sums the parent and descendant processes. This is aggregate process RSS,
22
+ not deduplicated physical memory; shared runtime pages may appear in both.
23
+
24
+ The current closeout candidate follows Josh's advisory-memory policy: requests
25
+ are attempted without fit-based refusal or completion clamping by default.
26
+ Earlier reservation variants remain diagnostics, including successful trials;
27
+ they are not the product policy. Explicit budgets/context caps still apply.
28
+ No speed default has been promoted by these memory experiments.
29
+
30
+ The advisory candidate's M4 Pro replay (`m4-advisory-short.md.json`) retains
31
+ all 23 comparable successful request outputs and usage/cache counts from
32
+ the earlier R0 run. Five-sample decode medians are 14.812 tok/s serial and
33
+ 14.677 tok/s continuous; this is one diagnostic run, not a paired speed win.
34
+ Both lanes complete decode and cold/warm 1K prefill. The aggregate retained
35
+ history hits actual Metal insufficient-memory errors: serial recovers on the
36
+ harness retry; continuous fails both attempts. These are runtime failures,
37
+ not predictive refusals. Local regression tests deliberately give the live
38
+ model an impossible accounting estimate and verify both lanes still execute.
39
+ Review: `reports/qwen38-closeout/m4-advisory-short-review.json`.
40
+
41
+ ## Rotating target speculation through shared execution
42
+
43
+ M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2. Gemma 4 12B OptiQ, prompt lookup
44
+ at its default depth ten, bf16 KV, 2 GiB RAM cache plus temporary SSD,
45
+ 192 decode tokens, four concurrent requests and default capacity eight.
46
+ Production `bench-serve.ts all`, context sweep skipped, seed `rotating-spec-0`,
47
+ diagnostic mode under Josh's machine policy. Final comparison order is
48
+ control-1, candidate-2, control-2, candidate-3; an earlier candidate-1 predates
49
+ the final singleton boundary correction and is excluded from these means.
50
+
51
+ | Metric (mean of two arms) | Previous serial placement | Shared rotating placement | Change |
52
+ |---|---:|---:|---:|
53
+ | Single-request decode | 16.928 tok/s | 16.894 tok/s | −0.2% |
54
+ | Four-request throughput | 17.269 tok/s | 22.130 tok/s | +28.1% |
55
+ | Four-request wall time | 29,648.128 ms | 23,139.278 ms | −22.0% |
56
+ | Repeated-prompt TTFT | 2,505.201 ms | 199.600 ms | −92.0% |
57
+ | Cold prefill TTFT | 2,515.753 ms | 2,524.302 ms | +0.3% |
58
+ | Launch to first output | 1,571.428 ms | 1,631.817 ms | +3.8% |
59
+
60
+ All 60 recorded requests complete with matching bodies and token budgets.
61
+ Single-request text and raw completion/chat probes match. All four concurrent
62
+ responses differ across implementations, while each implementation's repeats
63
+ are exact. This measures fixed output budgets with different concurrent
64
+ trajectories. The shared cache reuses 671 tokens versus zero in the control.
65
+ Startup spans roughly 1.1–2.2 seconds in both arms; its mean does not establish
66
+ strict dominance. This closes the bf16 rotating transaction implementation,
67
+ not all speculative compositions or strict serial-removal acceptance.
68
+
69
+ Control source: `20c21f2f62383b9878966f8ea1bf74c98d58942d33351430042ff7801cb929c4`.
70
+ Final candidate: `c8213540beb87f438fbafad7115b49f494e92526c28acca930f134883d5cfdcf`.
71
+ The change is integrated in the unreleased tree. Evidence:
72
+ `reports/qwen38-closeout/composition-baseline/rotating-speculation/`, including
73
+ `benchmark-comparison.json` and all raw M4 reports.
74
+
75
+ ## Full-attention speculation through shared execution
76
+
77
+ M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2. Llama 3.2 3B target and 1B
78
+ standalone drafter (4-bit weights), draft depth two, bf16 KV, 2 GiB RAM
79
+ plus temporary SSD. Production `bench-serve.ts all`, 192 decode tokens,
80
+ four concurrent requests, default capacity eight, seed `full-kv-spec-0`,
81
+ context sweep skipped, diagnostic mode under Josh's machine policy.
82
+ The same draft engine runs in both arms; target placement and paired cache
83
+ reuse change. Order: control, candidate, candidate, control.
84
+
85
+ | Metric (mean of two arms) | Previous serial placement | Shared placement | Change |
86
+ |---|---:|---:|---:|
87
+ | Single-request decode | 120.890 tok/s | 129.319 tok/s | +7.0% |
88
+ | Four-request throughput | 108.167 tok/s | 162.331 tok/s | +50.1% |
89
+ | Four-request wall time | 4,733.455 ms | 3,154.056 ms | −33.4% |
90
+ | Repeated-prompt TTFT | 891.394 ms | 44.685 ms | −95.0% |
91
+ | Cold prefill TTFT | 893.065 ms | 919.492 ms | +3.0% |
92
+ | Launch to first output | 1,070.260 ms | 978.795 ms | −8.5% |
93
+
94
+ All 60 requests complete, with identical request bodies and token counts.
95
+ Single-request text and raw completion/chat probes match. One of four
96
+ concurrent responses changes across implementations; each implementation's
97
+ repeats are exact. Usage differs by execution lane, repeated-prefix reuse
98
+ (752 tokens versus zero), and the changed response's speculative counters.
99
+ Thus aggregate timing holds token budgets fixed, with one changed trajectory.
100
+ The control launch times span 970–1,171 ms; this is not strict startup
101
+ acceptance. Cold-prefill latency still regresses. The change is integrated
102
+ in the unreleased tree; defaults remain unchanged.
103
+
104
+ Control source: `3a420497bf8a8c6be5896050b45773d541515a22e737d8775522d742221a8d41`.
105
+ Candidate source: `20c21f2f62383b9878966f8ea1bf74c98d58942d33351430042ff7801cb929c4`.
106
+ Evidence: `reports/qwen38-closeout/composition-baseline/full-kv-speculation/`,
107
+ including four raw M4 reports and `benchmark-comparison.json`.
108
+
109
+ ## Standalone drafting: first shared-executor comparison
110
+
111
+ M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2. Qwen3.8 packed 27B target plus
112
+ Qwen3.5 0.8B OptiQ standalone drafter, depth two, KV4 from token zero,
113
+ 4 GiB RAM cache plus temporary SSD, 192 decode tokens and four concurrent
114
+ requests. Production `bench-serve.ts all`, seed `standalone-serving-0`,
115
+ context sweep skipped; advisory diagnostic mode under Josh's machine policy.
116
+
117
+ | First run | Single-request decode | Repeated-prompt TTFT | Reused tokens | Four-request throughput |
118
+ |---|---:|---:|---:|---:|
119
+ | Previous standalone provider | 8.936 tok/s | 5,987.688 ms | 0 | 8.617 tok/s |
120
+ | Shared standalone candidate | 13.945 tok/s | 122.100 ms | 756 | GPU allocation failure |
121
+
122
+ The initial candidate's aggregate phase failed both attempts with native Metal
123
+ insufficient-memory errors. A complete-sequence profile reproduces the failure
124
+ with 4,005 MiB of accounted cache entries and an observed 17,987 MiB peak;
125
+ a fresh aggregate completes. Retained RAM entries consume batch headroom.
126
+
127
+ A second matched comparison uses **2 GiB RAM plus SSD in both arms**, in
128
+ candidate/control/control/candidate order. Other settings are unchanged;
129
+ default capacity is eight, with four concurrent requests. All 60 recorded
130
+ requests complete without failures. Means of the per-arm measurements:
131
+
132
+ | Metric | Previous standalone provider | Shared standalone provider | Change |
133
+ |---|---:|---:|---:|
134
+ | Single-request decode | 8.882 tok/s | 13.970 tok/s | +57.3% |
135
+ | Four-request throughput | 8.614 tok/s | 9.343 tok/s | +8.5% |
136
+ | Four-request wall time | 59.437 s | 54.807 s | −7.8% |
137
+ | Repeated-prompt TTFT | 5,989.823 ms | 122.527 ms | −98.0% |
138
+ | Cold prefill TTFT | 5,993.083 ms | 6,153.492 ms | +2.7% |
139
+ | Launch to first output | 4,332.735 ms | 4,537.720 ms | +4.7% |
140
+
141
+ All request bodies, token counts and single-request text match; raw completion
142
+ and chat probes also match. Candidate repeats preserve single-request text and
143
+ usage. Concurrent text and acceptance counters differ both across implementations
144
+ and between candidate repeats as admission geometry changes; throughput is a
145
+ fixed-token-budget serving measurement, not identical generated content.
146
+ The new provider retains recurrent draft history after rejection; the old
147
+ provider discarded that history. It also retains paired cache state, with
148
+ 756 tokens reused on the repeated prompt versus zero in the control.
149
+
150
+ The provider is integrated in the unreleased working tree. The cold/startup
151
+ cost and the 4 GiB failure remain; this does not close strict serial dominance
152
+ or select application defaults. MTP comparisons use a different drafter and
153
+ must remain separate. Control source is
154
+ `0a7e65986e57b493e7ab30a2e328a1eb591b03b029f59e342fd8a01471538613`;
155
+ candidate source
156
+ `3a420497bf8a8c6be5896050b45773d541515a22e737d8775522d742221a8d41`.
157
+ Evidence: `reports/qwen38-closeout/composition-baseline/two-model-batch/`,
158
+ including `ram2/benchmark-comparison.json` and raw request records.
159
+
160
+ ## Current serial versus shared execution: staggered Gemma requests
161
+
162
+ M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0, unreleased source
163
+ `0a7e65986e57b493e7ab30a2e328a1eb591b03b029f59e342fd8a01471538613`.
164
+ Gemma 4 12B OptiQ, ordinary KV4, 4 GiB RAM prompt cache and temporary SSD.
165
+ `bench-serve.ts all` uses 192 decode tokens, skipped context sweep,
166
+ `--aggregate-context 2048 --aggregate-stagger-ms 25`, seed `prefill-long-0`.
167
+ The serial arm pins `--batch 1`; the shared arm uses the default capacity eight. The four aggregate prompts contain 1,289/1,281/1,287/1,287
168
+ tokens with 13/12/14/12 cached, and each emits 128 tokens. Diagnostic mode
169
+ follows Josh's retained-swap policy; no competing GPU job runs during timing.
170
+
171
+ | run order | median decode tok/s | cached first-token ms | aggregate tok/s | aggregate wall ms | first request TTFT ms | mean TTFT ms |
172
+ |---|---:|---:|---:|---:|---:|---:|
173
+ | serial 0 | 26.3177 | 155.205 | 11.4938 | 44545.58 | 10037.72 | 24644.60 |
174
+ | shared 0 | 26.0648 | 155.797 | 19.7660 | 25903.03 | 9287.39 | 16360.50 |
175
+ | shared 1 | 26.2129 | 154.351 | 20.1601 | 25396.75 | 9031.62 | 15985.86 |
176
+ | serial 1 | 25.9724 | 156.207 | 13.0064 | 39365.23 | 4776.07 | 19477.02 |
177
+
178
+ Mean aggregate throughput increases **62.96%**, total aggregate time falls
179
+ **38.86%**, and mean first-token latency falls **26.69%**. Single-request
180
+ decode is effectively equal, −0.024% in throughput or +0.056% in summed
181
+ request time; cached latency falls 0.406%. First-request latency does not
182
+ dominate: the second serial sample starts in 4.78 s versus shared samples
183
+ near 9.1 s. Startup also has an initial serial outlier, so it is not a settled
184
+ comparison. These limits keep strict serial deletion acceptance open.
185
+
186
+ All 60 requests complete without failure. Request bodies, usage excluding
187
+ the expected lane label, token/cache counts and finish markers match. All
188
+ single-request texts match; all four concurrent texts differ between serial
189
+ and shared. Repeated runs of each arm produce identical text. This measures
190
+ throughput for the same submitted workload and output-token budgets, not
191
+ identical generated content. Same-B model oracle checks remain separate.
192
+ Source hashes stay fixed throughout both blocks. Raw reports and comparison:
193
+ `reports/qwen38-closeout/composition-baseline/current-serial-dominance/`.
194
+
195
+ ## Delayed full-attention padding: M4 comparison
196
+
197
+ The unreleased cache implementation now supports padded prefill while full
198
+ attention rows transition independently from BF16 to affine or TurboQuant.
199
+ Shared row positions and codec ownership replace separate padding logic.
200
+ The existing uniform KV4 decode still uses the same packed attention code.
201
+
202
+ M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0. Qwen3.8-27B packed
203
+ interleave2 target and folded RTN4 MTP companion, depth 2, KV4 from token zero,
204
+ 4 GiB RAM prompt cache, temporary SSD cache, configured batch capacity 8,
205
+ four concurrent requests. Production `bench-serve.ts all`, 192 decode tokens,
206
+ `--skip-context`, workload seed `mtp-serving-block-0`, async expansion off and
207
+ fused TQ decode enabled. Diagnostic mode follows Josh's retained-swap policy;
208
+ free memory starts at 90–93%, retained swap at 1.6–2.8 GiB. No other GPU job
209
+ runs during timing. The audio-daemon allowance is explicit.
210
+
211
+ | arm, in order | median decode tok/s | aggregate tok/s | cached first-token ms | ready ms | cold start ms |
212
+ |---|---:|---:|---:|---:|---:|
213
+ | control 1 | 19.2267 | 16.4810 | 98.186 | 610.78 | 4085.57 |
214
+ | candidate 1 | 19.1023 | 16.4524 | 98.070 | 821.10 | 4167.10 |
215
+ | candidate 2 | 19.1224 | 16.4746 | 99.601 | 614.60 | 4009.12 |
216
+ | control 2 | 19.3181 | 16.5351 | 99.174 | 621.53 | 3982.93 |
217
+
218
+ Candidate/control means change decode throughput by −0.831%, aggregate
219
+ throughput by −0.270%, cached latency by +0.157%, and cold start by +1.335%.
220
+ One candidate readiness sample is about 200 ms higher; the other overlaps
221
+ controls. These measurements establish no speed improvement or strict serial
222
+ performance dominance. The feature is integrated with these limits recorded;
223
+ long-prefill and B1 performance acceptance remain open.
224
+
225
+ All 60 request bodies, responses, usage/speculation counters, token counts,
226
+ finish reasons and completion markers match. No requests fail. Each source
227
+ snapshot stays fixed: control `7f06df944eb062703711f29b086879718868803c00367dd992b3a5bb8d0fac8e`,
228
+ candidate `0a7e65986e57b493e7ab30a2e328a1eb591b03b029f59e342fd8a01471538613`.
229
+ Both-machine cache/model and seeded delayed-conversion gates accompany this
230
+ comparison. Evidence: `reports/qwen38-closeout/composition-baseline/full-delayed-prefill/`,
231
+ including `benchmark-comparison.json`, `manifest.json`, and `m4/` raw reports.
232
+
233
+ ## Shared MTP prefill: M4 comparison and scheduling attribution
234
+
235
+ Apple M4 Pro, 24 GB; Bun 1.4.2, MLX 0.32.2. Packed interleave2
236
+ Qwen3.8-27B, affine KV4, folded MTP2, four concurrent requests (configured
237
+ maximum batch 8), 4 GiB prompt cache,
238
+ 192 output tokens per decode request, five decode samples, context sweep off.
239
+ `bench-serve.ts all` uses workload seed `mtp-serving-block-0`, fused TQ enabled
240
+ and async Trellis expansion disabled. Four balanced runs use
241
+ control/candidate/candidate/control order. The first control started with zero
242
+ swap; subsequent runs used `--diagnostic` after swap returned. All runs finished
243
+ without request failures and retained stable source hashes within each run.
244
+
245
+ | Preparation policy | Runs | Mean decode median tok/s | Mean concurrent tok/s |
246
+ |---|---:|---:|---:|
247
+ | Control: existing MTP preparation | 2 | 19.331 | 15.194 |
248
+ | Common driver, shared prefill | 2 | 19.069 | 14.076 |
249
+ | Common driver, individual preparation | 2 | 19.158 | 15.508 |
250
+ | Common driver, finish resumed final step first | 1 | 19.3 | 14.099 |
251
+
252
+ Shared prefill loses **1.35%** single-request decode rate and **7.36%** concurrent
253
+ throughput relative to the balanced control means. Mean concurrent wall time
254
+ rises from 33.718 to 36.374 seconds. Cached first-output latency is 98.23 versus
255
+ 99.85 ms; cold 1K first-output latency is 5844.61 versus 5997.68 ms.
256
+
257
+ All 60 requests in the balanced comparison preserve request hashes,
258
+ prompt/output/cache counts, finish reasons and completion markers. Single-request
259
+ text and usage are exact. Three of four concurrent responses change between
260
+ control and candidate; each arm reproduces its own text and full usage exactly.
261
+ Thus this is a serving comparison with changed concurrent numerical trajectories,
262
+ not an identical-work kernel timing. Total concurrent speculative rounds fall
263
+ from 234 to 232, so an increase in round count does not explain the slowdown.
264
+
265
+ The individual-preparation control changes only the scheduler admission budget
266
+ from 2048 to zero and retains B4 decode and the same common driver. Both runs
267
+ reproduce every control response and full usage record. The clean repeat
268
+ confirmed that this is the only source difference. Finishing resumed final
269
+ steps first instead leaves concurrent responses/usage identical to shared
270
+ prefill and does not recover its throughput. None of these isolated candidates
271
+ is adopted. The next investigation is preparation-to-decode cache state and
272
+ actual work per round.
273
+
274
+ Two instrumented follow-ups locate the sustained cost in target verification.
275
+ Across 53 B4 rounds per arm, median complete-round time is 540.64 ms with
276
+ shared preparation versus 459.01 ms with individual preparation. The target
277
+ forward interval is 510.50 versus 430.34 ms; draft generation is 12.11 versus
278
+ 12.15 ms. These are lazy-execution phase timings, so the target interval includes
279
+ any work it forces; layer-level attribution is still needed. Independent saved
280
+ SSE timestamps reproduce the uninstrumented gap (about 542 versus 459 ms
281
+ between output bursts during seconds 10–25).
282
+
283
+ Further probes run three B4 rounds with layer synchronization. Both arms use
284
+ 128 packed gate/up calls and 64 expanded down-projection calls, with identical
285
+ M=12 and bf16 geometry. The down-projection evaluation interval, which also
286
+ forces the preceding lazy packed gate/up work, is 412.68 versus 355.75 ms.
287
+ This narrows the cost to MLP evaluation but does not distinguish its packed
288
+ kernels from weight expansion/native matmul. Phase/layer probes preserve their
289
+ respective control responses and usage. A separate candidate evaluates target
290
+ state and clears the temporary buffer pool after preparation; it completes
291
+ without failures at 14.3 concurrent tok/s, still below individual preparation.
292
+ It is not adopted. Profiles: `mtp-cohort-layer-profile.json` and
293
+ `mtp-cohort-trellis-profile.json`; drain result: `mtp-cohort-drain-manifest.json`.
294
+
295
+ A subsequent split probe evaluates inputs, packed projections, expanded weights
296
+ and matrix products separately. Across three instrumented B4 rounds, median
297
+ expansion time is 157.92 ms after shared preparation versus 85.55 ms after
298
+ individual preparation. Packed gate/up evaluation is 232.03 versus 229.83 ms;
299
+ expanded-weight matrix multiplication is 88.75 versus 84.07 ms. These inserted
300
+ synchronization points change absolute latency and serve only to locate work.
301
+ The separate input-evaluation candidate passes M1 native MTP serving but reaches
302
+ 13.8 concurrent tok/s on the M4, so it is not adopted. Evidence:
303
+ `mtp-cohort-split-profile.json`, `split-profile-*.md.json`, `input-eval-1.md.json`.
304
+
305
+ Smaller vector expansion tiles (32, 64 and untiled) reach 14.15–14.22
306
+ concurrent tok/s; variant 12 reaches 13.30; a residency refresh reaches 14.00.
307
+ All preserve their shared-prefill reference responses and usage, and none is
308
+ adopted. Memory instrumentation observes 16.823 GiB active after shared
309
+ preparation versus 16.534 GiB after individual preparation. A native ownership
310
+ probe confirms that a deferred compact row copy retains its larger parent
311
+ allocation until evaluated.
312
+
313
+ Evaluating target snapshots before RAM retention recovers concurrent throughput
314
+ in two M4 runs: **16.268 and 16.299 tok/s**, averaging 16.283, versus 14.076
315
+ for the original shared-preparation pair (**+15.68%**) and 15.508 for the two
316
+ individual-preparation controls (**+5.00%**). Concurrent wall time falls to
317
+ 31.473 and 31.414 seconds. Single-request decode medians are 19.277 and 19.108
318
+ tok/s; cached first output is 100.66 and 100.76 ms. All 30 requests preserve
319
+ request hashes, output text and full usage exactly against shared preparation.
320
+ Source is stable in both runs. The M1 native serving test passes 229 assertions.
321
+ The final implementation below moves this behavior from method-local capture
322
+ to the common cache ownership boundary for every producer.
323
+ Evidence: `mtp-cohort-snapshot-eval-review.json`,
324
+ `mtp-cohort-expansion-screen-review.json`, `mtp-cohort-memory-profile.json`.
325
+
326
+ Moving materialization into the shared RAM cache, including companion tensors,
327
+ preserves all 30 responses and usage records in two further M4 runs. Concurrent
328
+ throughput is **16.477 and 16.384 tok/s**; single-request decode is 19.127 and
329
+ 19.205 tok/s; cached first output is 97.62 and 98.79 ms. The common implementation
330
+ passes 2,150 M1 tests (14 skipped), all typechecks, and the generated TurboQuant
331
+ RAM/SSD continuation test at MTP3/B4. M1 native lookup passes 228 assertions and the ordinary 4096-token TQ prefix
332
+ ownership test passes 40. A fresh current-tree control reaches 19.245 decode
333
+ and 15.539 concurrent tok/s, with 99.02 ms cached first output. Against that
334
+ control, the common-cache pair averages **5.74% higher concurrent throughput**,
335
+ 0.41% lower single-request decode and 0.83% lower cached first-output latency.
336
+ This is a two-candidate/one-control comparison; the older balanced control
337
+ pair remains above. The M4 suite passes 2,154 tests (10 skipped), both-machine typechecks pass, and
338
+ M4 native TQ MTP serving passes 229 assertions. The shared driver and common
339
+ cache fix are adopted in the unreleased working tree; main integration
340
+ suite, typechecks and hygiene pass. Strict serial dominance remains open. Review:
341
+ `mtp-cohort-cache-boundary-review.json`; source/validation:
342
+ `mtp-cohort-cache-boundary-manifest.json`.
343
+
344
+ The final memory profile differs from the original shared-preparation profile
345
+ only in the two cache implementation files. Active GPU allocation falls from
346
+ 16.823 to **16.458 GiB**, releasing **373.37 MiB**. Median weight-expansion time
347
+ falls from **147.57 to 86.17 ms** across three instrumented B4 rounds, matching
348
+ the individual-preparation profile's 87.99 ms. Routes, geometry and call counts
349
+ are unchanged; all 15 responses and full usage remain exact. The retained-memory
350
+ regression passes with materialization and fails when it is disabled. Profile
351
+ latencies locate the cost; the uninstrumented runs above measure serving speed.
352
+ Evidence: `mtp-cohort-memory-profile.json` and
353
+ `memory-profile-cache-boundary.md.json`.
354
+
355
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`:
356
+ `mtp-cohort-benchmark-comparison.json`, `mtp-cohort-admission-comparison.json`,
357
+ source manifests/patches, seven comparison runs and instrumented follow-ups in
358
+ `mtp-cohort-m4/*.md.json`; phase timing is in `mtp-cohort-phase-profile.json`.
359
+
360
+ ## Delayed affine row composition: fixed-settings M4 regression
361
+
362
+ Apple M4 Pro, 24 GB, macOS 27.0.0, Bun 1.4.2, MLX 0.32.2/native pack
363
+ 0.4.0. The existing `bench-serve.ts all` suite ran control/candidate/candidate/control
364
+ on the packed interleave2 Qwen3.8-27B artifact with KV4, MTP2, 192 output tokens,
365
+ five decode requests, prompt cache 4 and context sweep disabled. Workload seed
366
+ `mtp-serving-block-0`; fused TQ enabled, async Trellis expansion disabled.
367
+ All preflights passed with Josh's audio-daemon allowance. Source stayed fixed:
368
+ control `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`,
369
+ candidate `eacbb8c7d9e1a2f06c4235f71dc7db51f29b8bd27a9940a5e802a056220ff336`.
370
+ Remote checkout HEAD was `0c355f4`; source hashes include the unreleased changes.
371
+
372
+ | Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
373
+ |---|---:|---:|---:|
374
+ | Control 1 | 55,730.95 | 97.33 | 15.9259 |
375
+ | Candidate 1 | 55,585.20 | 97.57 | 15.8891 |
376
+ | Candidate 2 | 55,678.22 | 99.36 | 15.7890 |
377
+ | Control 2 | 55,682.47 | 99.41 | 15.7812 |
378
+
379
+ All 60 request records retain identical request hashes, response text, complete
380
+ usage, token counts and finish reasons. Combined candidate/control changes are
381
+ −0.135% decode wall time, +0.099% cached latency and −0.091% aggregate throughput.
382
+ Peak RSS is effectively unchanged. Startup was less stable: the initial control
383
+ reached readiness in 608 ms versus about 800 ms in the later arms, and its cold
384
+ start was 3,443 ms versus about 4,200–4,300 ms afterward. The candidate overlaps
385
+ the final control, but this screen does not establish startup equivalence.
386
+ The decode and cached-latency changes overlap the observed
387
+ control variation: the existing default path is effectively flat. This is a
388
+ regression check for integrating delayed-affine support and the shared transition
389
+ lifecycle, not a measurement of delayed conversion speed or serial dominance.
390
+ Both-machine native/serving/SSD correctness gates qualify the new composition.
391
+ Raw records and comparison: `reports/qwen38-closeout/composition-baseline/delayed-affine/`.
392
+
393
+ ## Captured attention views: M4 regression
394
+
395
+ Same M4 Pro 24 GB/toolchain, packed Qwen artifact and 192-token KV4/MTP2
396
+ protocol as the delayed-affine comparison above. Order is again
397
+ control/candidate/candidate/control, with unchanged requests and initial cache
398
+ settings. Control source is
399
+ `eacbb8c7d9e1a2f06c4235f71dc7db51f29b8bd27a9940a5e802a056220ff336`;
400
+ candidate source is
401
+ `f94a8212be222056a0d1cdc70c45c3d7f2e50a937eb89560a719ee4bf21c61f7`.
402
+ Both sources remain fixed throughout their runs.
403
+
404
+ | Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
405
+ |---|---:|---:|---:|
406
+ | Control 1 | 55,784.51 | 97.57 | 15.8553 |
407
+ | Candidate 1 | 55,656.05 | 97.18 | 15.9355 |
408
+ | Candidate 2 | 55,687.98 | 97.26 | 15.9648 |
409
+ | Control 2 | 55,680.16 | 97.45 | 15.9668 |
410
+
411
+ All 60 request records match in input hash, output text, complete usage, token
412
+ counts and finish reason. Combined decode wall time changes −0.108%, cached
413
+ latency −0.298%, and aggregate throughput +0.246%; peak RSS is unchanged.
414
+ These are effectively flat regression results, not a general speedup or serial
415
+ dominance result. Initial-control startup was faster than every subsequent
416
+ arm: readiness 607 ms versus 817–818 ms; cold start 3,487 ms versus 4,210–4,254 ms.
417
+ Startup equivalence remains unproven.
418
+
419
+ All start checks pass with the audio-daemon allowance. The final control's raw
420
+ end check flags `/usr/libexec/mobileassetd` at 84% CPU and 23 MB RSS, while free
421
+ memory remains 92%. That flag remains in the raw result. Under Josh's policy
422
+ allowing isolated background CPU activity, the stable paired decode/cached
423
+ measurements support feature integration; this is not an entirely unflagged
424
+ four-arm run. The initial wrapper's separate oracle-path error occurred before
425
+ inference and is retained as a failed launch, not a timing sample.
426
+
427
+ The changed attention-view operations are qualified by both-machine full-model
428
+ Gemma/MiniCPM state/logit checks, Qwen rollback/MTP/lookup checks and exact SSD
429
+ continuations. This default-settings screen does not measure delayed conversion
430
+ speed. Evidence: `reports/qwen38-closeout/composition-baseline/kv-attention-view/`.
431
+
432
+ ## Delayed rotating affine composition: M4 regression
433
+
434
+ Same M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0 and packed
435
+ Qwen KV4/MTP2 protocol as the preceding comparisons: 192 output tokens,
436
+ five decode requests, prompt cache 4, workload seed `mtp-serving-block-0`,
437
+ context sweep disabled, fused TQ enabled and async expansion disabled.
438
+ The four arms ran control/candidate/candidate/control with stable sources:
439
+ control `1b1ededa649088e8338a2930b4ae152e66edf7e4048e2dc8d0b7a3859691800c`,
440
+ candidate `c7d58f7ec867015eff7bbc9a7f02d13baea28173dd312bd504e9b880659278eb`.
441
+ Every start/end preflight passed with the recorded audio-daemon allowance;
442
+ there were no request or phase failures.
443
+
444
+ | Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
445
+ |---|---:|---:|---:|
446
+ | Control 1 | 55,775.68 | 97.24 | 15.9569 |
447
+ | Candidate 1 | 55,608.34 | 97.49 | 16.0176 |
448
+ | Candidate 2 | 55,692.19 | 97.55 | 15.8421 |
449
+ | Control 2 | 55,661.04 | 99.17 | 15.8041 |
450
+
451
+ All 60 records match in request hash, response text, complete usage including
452
+ speculation counters, token counts and finish reason. These HTTP records do
453
+ not contain emitted token IDs; native tests provide the numerical evidence.
454
+ Candidate versus control means change decode wall time by −0.122%, cached
455
+ latency by −0.696% and aggregate throughput by +0.311%. Peak RSS spans
456
+ 12,208–12,224 MB. These are effectively flat regression results. The first
457
+ control reaches readiness in 609 ms and cold start in 3,610 ms; the remaining
458
+ arms take 817–818 ms and 4,235–4,288 ms. Startup equivalence remains unproven.
459
+
460
+ This checks the shared lifecycle on the existing default Qwen path. It does
461
+ not measure positive-threshold Gemma conversion speed or establish serial
462
+ dominance. Both-machine Gemma KV4/KV8 and per-layer native state/logit,
463
+ RAM/SSD continuation and seeded serving tests cover the new composition;
464
+ fresh-process Gemma and long-pressure acceptance remain open.
465
+ Evidence: `reports/qwen38-closeout/composition-baseline/delayed-rotating/`.
466
+
467
+ ## Singleton admission attribution on M4 Pro
468
+
469
+ A synthetic Qwen-shaped MLX 0.32.2 probe compares singleton `copyOf` with
470
+ `contiguous`, using evaluated donors: 48 recurrent states, 16 KV4 layers at
471
+ 757 logical tokens with 768-token capacity, and their combination. Each arm
472
+ has four warmups and twenty samples; order is control/candidate/candidate/control.
473
+ The combined logical storage is 168,099,840 bytes. Both implementations add
474
+ **zero live GPU allocation** during admission. Combined median admission times
475
+ are 0.1463/0.1435/0.1470/0.1464 ms in execution order. There is no demonstrated
476
+ physical-copy saving; `copyOf` already shares storage in this runtime.
477
+ These synthetic measurements do not establish complete-request speed. The
478
+ initial probe launch omitted the required stream argument to `synchronize`;
479
+ its failure is retained separately and supplied no timing sample.
480
+
481
+ The completed four-arm `bench-serve.ts all` comparison uses the same M4
482
+ Qwen KV4/MTP2, 192-token protocol as above. Control source is
483
+ `c7d58f7ec867015eff7bbc9a7f02d13baea28173dd312bd504e9b880659278eb`;
484
+ candidate is `b7361d962c70f0efbb5c55c32f06996103015477095833c98d83928cc23ddd52`.
485
+ All source snapshots and start/end preflights pass. All 60 request hashes,
486
+ response texts, complete usage/speculation counters, token counts and finish
487
+ reasons match, with no request or phase failures.
488
+
489
+ | Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
490
+ |---|---:|---:|---:|
491
+ | Control 1 | 56,033.78 | 99.64 | 15.8719 |
492
+ | Candidate 1 | 55,590.06 | 97.28 | 15.9511 |
493
+ | Candidate 2 | 55,682.16 | 97.35 | 15.9217 |
494
+ | Control 2 | 55,725.68 | 99.44 | 15.9324 |
495
+
496
+ Candidate/control means change decode wall time −0.436%, cached latency
497
+ −2.230% and aggregate throughput +0.216%. Both candidate cached samples are
498
+ lower than both controls, although the physical-copy hypothesis is disproven
499
+ and MTP group admission follows its first published token. The latency result
500
+ needs attribution/repetition before treating this replacement as an accepted
501
+ optimization. Controls report readiness at 608 ms and candidates at 816 ms;
502
+ the readiness probe polls every 200 ms, so these observations have coarse
503
+ resolution. Cold starts are 3,414/4,114/4,224/4,017 ms in execution order.
504
+ Startup equivalence and direct serial dominance remain unproven. Both-machine
505
+ native, serving, full-suite and typecheck checks pass; the candidate is isolated.
506
+ Evidence: `reports/qwen38-closeout/composition-baseline/singleton-state/`.
507
+
508
+ ## Recurrent row retention diagnostic on M1 Max
509
+
510
+ Apple M1 Max 32 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0. A synthetic
511
+ Qwen-shaped recurrent layer contains 3,207,168 logical bytes per row. After
512
+ extracting one row and disposing its source, the existing implementation keeps
513
+ 3,211,264 / 6,422,528 / 12,828,672 / 25,657,344 live allocator bytes for source
514
+ B=1/2/4/8. A proper-subset compact copy retains 3,211,264 bytes in every case,
515
+ including allocator rounding. B1 continues to share its whole allocation.
516
+ This measures one layer, not full-model RSS or request time. The allocation
517
+ regression fails against unchanged source and passes with exact values on the
518
+ isolated fix. Both-machine MTP and bf16/KV4/TQ generated RAM/SSD continuation,
519
+ complete-suite and typecheck checks pass. The allocation regression also passes
520
+ on M4. The reviewed extraction fix is adopted in the unreleased working tree.
521
+
522
+ The M4 Pro 24 GB `bench-serve.ts all` check uses the same packed Qwen KV4/MTP2,
523
+ 192-token protocol above, in control/candidate/candidate/control order. Sources
524
+ remain fixed: control
525
+ `c7d58f7ec867015eff7bbc9a7f02d13baea28173dd312bd504e9b880659278eb`, candidate
526
+ `bdc1241596526f42d68ba0988fc63cd90dce73ce8d048b45d9bfa1cc0c5872c7`.
527
+ All start/end preflights pass; all 60 request hashes, response texts, full usage
528
+ and speculation counters, token counts and finish reasons match. No failures.
529
+
530
+ | Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
531
+ |---|---:|---:|---:|
532
+ | Control 1 | 56,548.78 | 99.48 | 15.7814 |
533
+ | Candidate 1 | 55,608.23 | 99.02 | 15.9869 |
534
+ | Candidate 2 | 55,785.82 | 97.41 | 15.8657 |
535
+ | Control 2 | 55,636.97 | 99.47 | 15.9106 |
536
+
537
+ Candidate/control means change decode wall time −0.706%, cached latency
538
+ −1.264% and aggregate throughput +0.507%. The initial control is slower than
539
+ the remaining arms; candidate throughput overlaps the control range, and the
540
+ second candidate decode total is slightly above the second control. Treat
541
+ these as a regression check for the storage fix, not a broad speedup or serial
542
+ dominance result. Peak RSS spans 12,208–12,240 MB. Startup remains unresolved:
543
+ readiness is 608/816/816/817 ms and cold start 3,704/4,177/4,240/4,181 ms.
544
+ The short workload does not establish long-context pressure acceptance.
545
+ Evidence: `reports/qwen38-closeout/composition-baseline/ssm-extraction/`.
546
+
547
+ ## Batched prefill cohorts: M4 regression before projection correction
548
+
549
+ Unreleased isolated candidate against the previously validated delayed-padding
550
+ checkout. Apple M4 Pro, 24 GB; Bun 1.4.2, MLX 0.32.2/native pack 0.4.0.
551
+ Gemma 4 12B OptiQ, ordinary generation, KV4, RAM prompt cache 4 GB, default
552
+ batch capacity 4. Both checkouts have HEAD `0c355f4` plus frozen source changes.
553
+ Control source SHA-256 `89d209400c1f683143ee9afea30e8a440ee00159fe96ba8e1c3bbe5893c744ac`;
554
+ candidate `2431d0395ad7e752991bc47817cf8c6f54a6d74fb6e0f6fc08598e314ce6d937`.
555
+
556
+ Protocol: `bun scripts/bench-serve.ts all --model-path <Gemma-12B-OptiQ>
557
+ --arms mlx-bun --tokens 192 --skip-context --kv-quant 4 --prompt-cache 4
558
+ --workload-seed delayed-padding-0 --allow-cpu-process /usr/libexec/audiomxd`.
559
+ Run order is control, candidate, candidate, control. All preflights and saved
560
+ machine checks pass, with 217 MB swap and the explicitly allowed audio daemon.
561
+ Source hashes remain fixed throughout all four arms; no request failures.
562
+
563
+ | arm | five decode requests, total ms ↓ | cached first-token ms ↓ | B4 aggregate tok/s ↑ | ready ms | cold-start ms | peak RSS MiB |
564
+ |---|---:|---:|---:|---:|---:|---:|
565
+ | control 1 | 38,010.26 | 154.517 | 72.966 | 609.34 | 2,150.35 | 8,985.45 |
566
+ | candidate 1 | 38,063.00 | 154.884 | 72.965 | 608.25 | 1,026.27 | 8,990.06 |
567
+ | candidate 2 | 37,950.08 | 154.601 | 73.024 | 608.52 | 1,024.44 | 8,985.66 |
568
+ | control 2 | 37,906.38 | 154.930 | 73.032 | 609.03 | 1,029.51 | 8,967.28 |
569
+
570
+ Candidate means: decode wall **+0.127%**, cached latency **+0.012%**, aggregate
571
+ throughput **−0.006%**. These results establish no speed win or strict serial
572
+ dominance. The first control's cold-start outlier does not establish a startup
573
+ improvement. This short-prompt workload does not measure long-prefill scaling.
574
+
575
+ All request bodies, token counts, usage, finish reasons and completion markers
576
+ match. Both candidates change the text of concurrent rows 1–3; candidate repeats
577
+ are identical to each other, as are control repeats. Other responses and parity
578
+ probes match. This is not an all-responses-identical regression result. Same-B
579
+ model checks pass on Qwen 27B and Gemma 12B on both Macs, and an admission-only diagnostic restores all
580
+ baseline responses, tying the text changes to shared prefill. An added M4 token-zero check subsequently
581
+ found a sampler-logit mismatch when finished rows project separately. A follow-up
582
+ candidate projects the batch before selecting sampler rows; these timing numbers
583
+ do not measure that fix. The corrected projection passes the M4 model/sampler
584
+ checks. Its fresh comparison is recorded below; the earlier measured candidate is not adopted.
585
+
586
+ Raw evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
587
+ including source manifest/patch, native checks and the four complete reports.
588
+
589
+ ## Batched prefill cohorts: corrected M4 comparison
590
+
591
+ The benchmark now also accepts `--aggregate-context <approximate tokens>` and
592
+ `--aggregate-stagger-ms <milliseconds>` for long, staggered HTTP requests.
593
+ Zero preserves the original short-prompt/simultaneous workload. Reports record
594
+ these settings, actual submission offsets, prompt/cache counts, first-token
595
+ latencies and total aggregate wall time. These workload changes must match
596
+ between comparison arms; the historical short-prompt numbers below use zeros.
597
+
598
+ The corrected candidate projects the forward batch before selecting each
599
+ sampler's logits. It is adopted in the unreleased working tree. Same machine,
600
+ model, protocol, settings and control as the preceding comparison, with fresh
601
+ control/candidate/candidate/control runs. Candidate source SHA-256
602
+ `84abd86ac44155298ec14cc59eeb0b51a0f1862d45e199b3597ef8a22d24a31f`.
603
+ All source hashes remain fixed, all preflight/save checks pass, and every arm
604
+ reports zero failures. Retained swap is 215 MB; the audio daemon allowance is
605
+ explicit, as in the preceding run.
606
+
607
+ | arm | five decode requests, total ms ↓ | cached first-token ms ↓ | B4 aggregate tok/s ↑ | ready ms | cold-start ms | peak RSS MiB |
608
+ |---|---:|---:|---:|---:|---:|---:|
609
+ | control 1 | 37,975.15 | 155.060 | 73.009 | 608.52 | 1,033.49 | 8,977.16 |
610
+ | candidate 1 | 37,989.93 | 154.810 | 73.042 | 608.63 | 1,029.35 | 8,980.83 |
611
+ | candidate 2 | 37,971.84 | 154.802 | 73.071 | 608.51 | 1,030.21 | 8,974.33 |
612
+ | control 2 | 37,974.80 | 154.991 | 73.003 | 609.87 | 1,027.01 | 8,954.62 |
613
+
614
+ Candidate means: decode wall **+0.016%**, cached latency **−0.142%**, aggregate
615
+ throughput **+0.069%**. Ready time changes by −0.102%, cold-start time by
616
+ −0.045%, and peak RSS by +0.130%. This is effectively flat performance for the
617
+ short-prompt workload, with no established speed win or strict serial dominance.
618
+ Long-prefill scaling remains unmeasured by this workload.
619
+
620
+ All 60 requests complete. Request bodies, token counts, usage, finish reasons
621
+ and completion markers match the baseline. The two candidate repeats produce
622
+ identical responses; the two controls do too. Three concurrent responses differ
623
+ between candidate and control, as in the earlier admission-only attribution.
624
+ Other responses match. These cross-shape text differences do not establish
625
+ an engine-only coding-task speedup or an all-responses-identical result.
626
+ The corrected same-B Qwen 27B and Gemma 12B checks include full logits,
627
+ token-zero sampler logits and restored continuation on both Macs.
628
+
629
+ Raw evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
630
+ particularly `projection-m4/`, `projection-benchmark-comparison.json`, and
631
+ `projection-manifest.json`. Main integration results are recorded in the manifest.
632
+
633
+ ## Staggered long prefill: M4 regression
634
+
635
+ Gemma 4 12B OptiQ, M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0.
636
+ Same ordinary KV4/cache settings as the preceding corrected comparison.
637
+ The benchmark adds `--aggregate-context 2048 --aggregate-stagger-ms 25` and
638
+ uses `--workload-seed prefill-long-0`. Actual aggregate prompt counts are
639
+ 1,289/1,281/1,287/1,287, with matching cache hits of 13/12/14/12 across all arms.
640
+ The target length is a character-based estimate, not a measured token count.
641
+ Client submission offsets are approximately 0/26/51/76 ms. Each request
642
+ produces 128 completion tokens. The existing prefill chunk default is 2,048.
643
+
644
+ Control source SHA-256
645
+ `4ab50112e6464d0d778f80398d8f61e3740c9a6dd5c3c9725f34b255c26b7711`;
646
+ candidate `003827c79e0bcefd65c33fe7366faa28ca60d7fd428063f6c3a159efd7a60991`.
647
+ Both include the same benchmark extension; inference code matches the preceding
648
+ control/corrected candidate respectively. All source hashes stay fixed, all
649
+ preflight/save checks pass, and all requests complete without failure. The
650
+ explicit audio allowance applies; retained swap remains 215 MB.
651
+
652
+ | arm | aggregate wall ms ↓ | aggregate tok/s ↑ | first request TTFT ms ↓ | mean request TTFT ms ↓ | peak RSS MiB |
653
+ |---|---:|---:|---:|---:|---:|
654
+ | control 1 | 25,278.61 | 20.254 | 9,007.88 | 15,911.29 | 8,947.95 |
655
+ | candidate 1 | 26,328.98 | 19.446 | 18,696.52 | 19,042.67 | 8,997.20 |
656
+ | candidate 2 | 26,543.42 | 19.289 | 18,849.50 | 19,193.88 | 9,013.50 |
657
+ | control 2 | 26,388.15 | 19.403 | 9,493.52 | 16,771.75 | 8,949.66 |
658
+
659
+ Candidate means show **2.333% longer aggregate wall time**, **2.324% lower
660
+ throughput**, **102.936% higher first-request TTFT**, and **16.992% higher mean
661
+ TTFT**. The controls' aggregate wall times differ by 4.4%, so the exact small
662
+ throughput penalty is not stable enough to generalize. The large first-request
663
+ latency penalty repeats clearly. Short decode request wall time changes by
664
+ −0.066%, and cached TTFT by −0.036%. Shared prefill has not passed long-request
665
+ performance acceptance. No serial deletion or default promotion follows.
666
+
667
+ Requests, usage, counts, finish reasons and completion markers match. Concurrent
668
+ rows 1–3 change text; other responses match, and each pair of repeated arms is
669
+ internally identical. This remains a comparison of identical submitted work,
670
+ not an all-responses-identical result or a coding-task quality assessment.
671
+
672
+ An M1 diagnostic with `MLX_BUN_P2R_TRACE=1` records the first request's internal
673
+ token-zero completion at about 6.25 s, but its first response write at 25.94 s.
674
+ The following B3 prefill chunk spans 18.25 s. This points to long preparation
675
+ work delaying active output, rather than admission waiting alone. It is
676
+ instrumented M1 attribution, not an M4 performance claim. A bounded M4 screen
677
+ with prefill chunks of 256 completes at 26,526.13 ms aggregate wall time and
678
+ 19.302 tok/s, with first-request TTFT 13,235.29 ms. It improves first output
679
+ relative to the candidate's 2,048-token chunks but still trails the earlier
680
+ control. The matching 256-token control completes at 26,011.10 ms and
681
+ 19.684 tok/s, with first-request TTFT 7,232.19 ms. The candidate therefore
682
+ still has 1.980% longer wall time and 83.005% higher first-request TTFT at
683
+ matching chunk size. Source/preflight/save checks pass with no failures.
684
+ Requests, usage/counts and completion markers match, but all four concurrent
685
+ texts differ. This one-pair screen does not qualify a default. Smaller chunks
686
+ change KV conversion boundaries and do not resolve the admission/work-unit
687
+ performance problem. Raw comparison: `long-chunk256-comparison.json` in the
688
+ evidence directory below.
689
+
690
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
691
+ including `long-m4/`, `long-benchmark-comparison.json`, and
692
+ `long-m1-prefill-traces.json`.
693
+
694
+ ## Prefill admission work budget: M4 comparison
695
+
696
+ The isolated scheduler candidate limits admission to an existing prefill cohort
697
+ using initial uncached token work. Its internal budget is 2,048 tokens; a larger
698
+ request still enters alone and runs through the same preparation method. An
699
+ earlier shrinking-weight screen restored first TTFT to 9,538.63 ms but completed
700
+ the group in 26,797.77 ms, versus 9,012.73/25,295.58 ms in the first control,
701
+ and still changed three responses. The fixed-weight candidate below avoids
702
+ attaching another long prompt to a nearly completed request.
703
+
704
+ M4 Pro 24 GB, Gemma 4 12B OptiQ, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0.
705
+ Same protocol and exact inputs as the preceding staggered-long comparison,
706
+ including KV4, prompt cache 4 GB, chunk default 2,048, 25 ms arrival spacing,
707
+ and `prefill-long-0`. Actual prompt/cache/output counts match. Control source
708
+ SHA-256 `4ab50112e6464d0d778f80398d8f61e3740c9a6dd5c3c9725f34b255c26b7711`;
709
+ fixed candidate `2dcee8a99708c66facd8aa296fe8b990de92eca5031453888947e9f9f35dfd72`.
710
+ Run order was control 1, the earlier shrinking-weight screen, fixed candidate 1,
711
+ fixed candidate 2, control 2. All source hashes remain fixed within their runs;
712
+ all preflight/save checks pass under the explicit audio-daemon allowance, with
713
+ 215 MB retained swap and no failed requests.
714
+
715
+ | arm | aggregate wall ms ↓ | aggregate tok/s ↑ | first request TTFT ms ↓ | mean TTFT ms ↓ | five decode requests, total ms ↓ | cached TTFT ms ↓ |
716
+ |---|---:|---:|---:|---:|---:|---:|
717
+ | control 1 | 25,295.58 | 20.241 | 9,012.73 | 15,955.67 | 37,922.95 | 154.872 |
718
+ | candidate 1 | 25,550.88 | 20.038 | 9,031.34 | 16,089.03 | 37,960.58 | 154.755 |
719
+ | candidate 2 | 26,390.25 | 19.401 | 9,526.85 | 16,783.75 | 38,091.45 | 155.456 |
720
+ | control 2 | 26,122.33 | 19.600 | 9,289.83 | 16,519.82 | 37,973.20 | 155.051 |
721
+
722
+ All 60 responses in the four fixed-candidate/control arms match exactly, including
723
+ request bodies, usage/counts, finish reasons and completion markers. Candidate
724
+ means are +1.018% aggregate wall time, −1.007% throughput, +1.397% first-request
725
+ TTFT, +1.223% mean TTFT, +0.205% short decode wall and +0.093% cached TTFT.
726
+ This restores the large latency regression from unrestricted cohorts, but does
727
+ not establish strict performance dominance. Aggregate timings vary by about
728
+ 3.3% within both candidate and control pairs. No default-speed win is claimed.
729
+
730
+ The policy is adopted in the unreleased working tree. Complete suites/types
731
+ and long-prefix Qwen/TurboQuant and Gemma/KV4 ownership checks pass on both
732
+ Macs. Main integration suite/typecheck pass.
733
+ A separate lifetime review found that the new loop retains unused hidden output
734
+ through cache maintenance, unlike the existing shared prefill primitive. Its
735
+ release-order screen is complete and is not adopted, as recorded below.
736
+
737
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
738
+ including `budget-m4/`, `budget-fixed-benchmark-comparison.json`, the earlier
739
+ `budget-remaining.patch`, and `budget-fixed-manifest.json`.
740
+
741
+ ## Prefill early-release lifetime screen: no measured win
742
+
743
+ The candidate disposes input IDs immediately after prefill forward and unused
744
+ hidden output before cache maintenance. Its control is the adopted fixed-work
745
+ admission policy above. Same M4 Pro 24 GB, Gemma 4 12B OptiQ snapshot, Bun 1.4.2,
746
+ MLX 0.32.2/native pack 0.4.0 and production `bench-serve.ts all` protocol:
747
+ KV4, prompt cache 4 GB, 192 decode tokens, skipped context sweep,
748
+ `prefill-long-0`, aggregate context target 2,048 and stagger 25 ms.
749
+ Actual aggregate prompts/cache hits remain 1,289/13, 1,281/12, 1,287/14,
750
+ 1,287/12, with 128 output tokens each. Control source SHA-256
751
+ `2dcee8a99708c66facd8aa296fe8b990de92eca5031453888947e9f9f35dfd72`;
752
+ candidate `46b351c3a4f4ed1442c946de388638b01611419fcc5a060c407f7a9da9584a80`.
753
+
754
+ | arm, in run order | aggregate wall ms ↓ | aggregate tok/s ↑ | first request TTFT ms ↓ | five decode requests, total ms ↓ | cached TTFT ms ↓ |
755
+ |---|---:|---:|---:|---:|---:|
756
+ | control 1 | 25,394.38 | 20.162 | 9,020.58 | 38,018.88 | 154.911 |
757
+ | candidate 1 | 25,537.82 | 20.049 | 9,033.96 | 37,966.96 | 154.710 |
758
+ | candidate 2 | 26,290.25 | 19.475 | 9,402.95 | 38,027.90 | 154.732 |
759
+ | control 2 | 25,888.99 | 19.777 | 9,164.43 | 38,000.93 | 154.781 |
760
+
761
+ All 60 responses, request bodies, usage/counts, finish reasons and completion
762
+ markers match exactly. All source/preflight/save checks pass; retained swap
763
+ stays at 208.25 MB under the explicit audio-daemon CPU allowance. No requests
764
+ fail. Candidate means are +1.062% aggregate wall time, −1.039% throughput,
765
+ +1.385% first TTFT, +1.366% mean TTFT, −0.033% short decode wall and
766
+ −0.081% cached TTFT. Aggregate run spread is 1.95% in controls and 2.95% in
767
+ candidates, so these small differences do not establish a causal slowdown.
768
+ Mean peak RSS differs by only −1.95 MB, or −0.022%, with no pressure test.
769
+ Cold start has a 2,132 ms first-control outlier versus roughly 1,095–1,100 ms
770
+ in the other three arms; its mean ratio is not evidence of a startup gain.
771
+
772
+ No speed or material measured-memory benefit is established. The candidate
773
+ remains isolated and is not adopted. M1 full suite/typecheck and Qwen 27B
774
+ same-B model/sampler/continuation checks on both Macs pass; M4 full suite and
775
+ typecheck were not run for this unadopted screen.
776
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`,
777
+ including `drain-m4/`, `drain-benchmark-comparison.json` and `drain-manifest.json`.
778
+
779
+ ## MTP preparation port and compiled activation: M4 comparison
780
+
781
+ This seven-file change adds provider-owned draft prefill using the existing
782
+ Qwen row state and replaces the companion's unfused MLP activation with the
783
+ compiled SwiGLU already used by the target. The new prefill port is not yet
784
+ connected to shared target preparation. This HTTP comparison therefore covers
785
+ the activation and row-lifecycle changes, not batched MTP prefill performance.
786
+ The same-B pinned companion check found 11 differing bf16 output values out of
787
+ 10,240 in one decoder continuation with the old activation, maximum absolute
788
+ difference 0.0078125; KV already matched. The shared compiled activation passes
789
+ all tested KV/full-decoder continuations at B1/B2/B3/B4 on both Macs, including
790
+ a 2,051-token prefix and cold/restored joins.
791
+
792
+ M4 Pro 24 GB, packed Qwen 27B Trellis interleave2 artifact and folded RTN4/g64
793
+ MTP companion, Bun 1.4.2, MLX 0.32.2/native pack 0.4.0. Production
794
+ `bench-serve.ts all`, explicit `mlx-bun` arm, MTP2, KV4, prompt cache 4 GB,
795
+ 192 decode tokens, five decode requests, context sweep disabled, original
796
+ short aggregate prompts at concurrency four, seed `mtp-serving-block-0`.
797
+ `MLX_BUN_TURBOQUANT_FUSED_DECODE=1` and
798
+ `MLX_BUN_TRELLIS_ASYNC_EXPAND=0` match the preceding MTP controls.
799
+ Control source SHA-256
800
+ `2dcee8a99708c66facd8aa296fe8b990de92eca5031453888947e9f9f35dfd72`;
801
+ candidate `69f3f37388ca0fdda2dd836786a20cb588c947fdc476b6206d617d7312d366fa`.
802
+
803
+ | arm, in run order | five decode requests, total ms ↓ | concurrent aggregate tok/s ↑ | cached TTFT ms ↓ |
804
+ |---|---:|---:|---:|
805
+ | control 1 | 55,546.48 | 15.7645 | 99.415 |
806
+ | candidate 1 | 55,705.24 | 15.6455 | 99.348 |
807
+ | candidate 2 | 55,931.24 | 15.7543 | 96.942 |
808
+ | control 2 | 55,905.67 | 15.7074 | 97.644 |
809
+
810
+ All 60 request bodies, response texts, prompt/output/cache token counts,
811
+ finish reasons and completion markers match. Five records per candidate arm
812
+ have different speculation statistics; candidate repeats agree exactly, as do
813
+ the controls. Four of the five decode requests have changed acceptance traces,
814
+ and one concurrent response has changed draft/acceptance counts. This follows
815
+ the corrected draft arithmetic and is not identical internal work. The targets
816
+ still return the same text and token counts.
817
+
818
+ Descriptive candidate/control means change decode wall by +0.165%, aggregate
819
+ throughput by −0.229%, aggregate wall by +0.230% and cached TTFT by −0.390%.
820
+ Readiness and cold-start means change by +0.059% and +0.051%. Mean peak RSS is
821
+ 14.82 MB lower, without a pressure test. All source/preflight/save checks pass
822
+ under the audio-daemon allowance, with no request or phase failures. Retained
823
+ swap grows across the runs, from 200.25 MB before the first control to 297.88 MB
824
+ after the final control; the environment is not a fixed zero-swap control.
825
+
826
+ No speed win, identical-work ratio or serial dominance is established. The
827
+ provider port and numerical correction are adopted in the unreleased working
828
+ tree after both-machine companion-oracle, native MTP, full-suite and typecheck
829
+ checks. Main integration suite/typecheck pass. Shared target/MTP prefill integration,
830
+ its serving/caching gates and a combined performance comparison remain open.
831
+ Evidence: `reports/qwen38-closeout/composition-baseline/prefill-cohort/`, including
832
+ `mtp-prefill-m4/`, `mtp-prefill-benchmark-comparison.json`,
833
+ `mtp-prefill-manifest.json`, and `mtp-prefill.patch`.
834
+
835
+ ## Delayed rotating prefill: M4 regression
836
+
837
+ Gemma 4 12B OptiQ 4-bit, snapshot
838
+ `5b1101065d2094c8f12aa87fee80e0afa5b292b7`, on the **M4 Pro / 24 GB**.
839
+ Bun 1.4.2, MLX 0.32.2, native pack 0.4.0. The control is
840
+ `padded-partial-validation`; the candidate is `delayed-padding-validation`.
841
+ Both use remote HEAD `0c355f4` plus their recorded working-tree changes.
842
+ The production snapshots are respectively
843
+ `27b65281f031a4ffc4f7db057a264f32aa8bbfab70bf4c2acb357176148f38b2` and
844
+ `89d209400c1f683143ee9afea30e8a440ee00159fe96ba8e1c3bbe5893c744ac`.
845
+
846
+ Four alternating runs use `bun scripts/bench-serve.ts all`, the exact artifact
847
+ above, `--arms mlx-bun --tokens 192 --skip-context --kv-quant 4 --prompt-cache 4
848
+ --workload-seed delayed-padding-0 --allow-cpu-process /usr/libexec/audiomxd`.
849
+ All preflights pass under the authorized audio-daemon CPU allowance, with fixed
850
+ source in each arm and identical workload/runtime settings. All 60 request
851
+ bodies, response texts, usage records, token counts and finish reasons match;
852
+ the separate parity probes also match. No request or phase failed.
853
+
854
+ | Arm | Five decode requests, total wall ms | Cached TTFT ms | B4 aggregate tok/s | Ready ms | Cold start ms | Peak RSS MiB |
855
+ |---|---:|---:|---:|---:|---:|---:|
856
+ | Control 1 | 37,952.57 | 154.73 | 72.98 | 608.63 | 1,022.52 | 8,992.91 |
857
+ | Candidate 1 | 37,969.02 | 155.03 | 72.85 | 607.89 | 1,024.32 | 8,971.34 |
858
+ | Candidate 2 | 38,284.21 | 155.46 | 72.54 | 608.21 | 1,021.92 | 8,982.78 |
859
+ | Control 2 | 38,207.34 | 155.07 | 72.90 | 608.12 | 1,023.51 | 8,990.95 |
860
+
861
+ Candidate means are **0.123% higher decode wall time**, **0.222% higher cached
862
+ TTFT** and **0.339% lower aggregate throughput**. Both candidate aggregate
863
+ observations are below both controls. These are small unfavorable differences,
864
+ not evidence of a speed win. Readiness is in the same 200 ms polling interval;
865
+ this Gemma block does not resolve the separate Qwen startup/cached-latency debt.
866
+
867
+ The change adds delayed rotating-cache preparation and is retained as feature
868
+ work. This benchmark exercises current serving, which still prefills requests
869
+ separately; it does not measure the future batched-prefill path or establish
870
+ serial dominance. Native preparation tests cover mixed-format attention and
871
+ encoded state through B8, with the numerical scope documented in batching.md.
872
+ Raw records and comparison: `reports/qwen38-closeout/composition-baseline/delayed-padding/`.
873
+
874
+ ## Recurrent padded prefill: M4 regression
875
+
876
+ Joshs-MBP-2025.local, Apple M4 Pro 24 GB, Bun 1.4.2, MLX 0.32.2/native
877
+ pack 0.4.0. Four alternating `bench-serve.ts all` arms use the same packed
878
+ Qwen KV4/MTP2, 192-token protocol above. The control includes the adopted
879
+ full/rotating KV padding interfaces. Sources remain fixed: control
880
+ `5431fdd0f20225e0493b12fb251db0b773f93d6ca92a2a5d09d64882a1161d04`,
881
+ candidate `98f5fb5038e3b63f3d1e28a3084f5d1da0a475aa28307761defd26f681e4eb82`.
882
+ Every start/end preflight passes with the audio-daemon allowance. All 60
883
+ requests match in request hash/body, text, complete usage/speculation counters,
884
+ token counts and finish reason. The separate parity probes also match. There
885
+ are no request or phase failures.
886
+
887
+ | Arm | Five decode requests, total ms | Cached TTFT ms | Concurrent aggregate tok/s |
888
+ |---|---:|---:|---:|
889
+ | Control 1 | 55,951.11 | 97.49 | 15.7960 |
890
+ | Candidate 1 | 55,713.07 | 97.38 | 15.8332 |
891
+ | Candidate 2 | 55,628.97 | 97.20 | 15.9066 |
892
+ | Control 2 | 55,639.46 | 98.99 | 15.9824 |
893
+
894
+ Candidate/control means change decode wall time by −0.223%, cached latency
895
+ by −0.964% and aggregate throughput by −0.122%. Candidate aggregate throughput
896
+ falls within the control range; cached latency is lower in both candidate arms.
897
+ This supports integration as a feature addition with
898
+ roughly flat decode/request performance, not a speedup or serial-dominance
899
+ claim. Peak RSS ranges from 12,161 to 12,227 MB. Readiness is
900
+ 608/817/813/612 ms; both candidate observations fall one 200-ms polling
901
+ interval later. Cold start is 3,726/4,207/4,200/4,006 ms. Startup equivalence
902
+ remains unproven and is not covered by the flat decode conclusion.
903
+
904
+ This checks existing unpadded serving behavior. Actual padded behavior passes
905
+ same-B 27B logit and convolution/recurrent-state oracles on both machines,
906
+ including B1 and uniform/unequal B3. MTP, TurboQuant, generated RAM/SSD reuse,
907
+ complete suites and typechecks also pass on both Macs. True batched serving
908
+ prefill, delayed-codec preparation and long-pressure acceptance remain open.
909
+ The recurrent-padding change is adopted in the unreleased working tree.
910
+ Evidence: `reports/qwen38-closeout/composition-baseline/padded-ssm/`.
911
+
912
+ ## Packed Qwen serial closeout on M4 Pro
913
+
914
+ Six balanced v6/v13 pairs on **Joshs-MBP-2025.local, Apple M4 Pro 24 GB**
915
+ complete with **114 matching paired requests and no failures**. This uses
916
+ Bun 1.4.0, MLX 0.32.2 and the advisory-memory candidate on `0c355f4` plus
917
+ its recorded patch. Source snapshot
918
+ `e0ebcb3fd1be6024623ffb4db08cdb5b7322a823d43df7ef1e803d11b37131b7`
919
+ is unchanged across all twelve runs. The packed interleaved artifact's
920
+ 20-file manifest hashes to
921
+ `24c56033e1ae4c816747f763b76a7420b6327236a3736c2a89462a22e4e512ce`.
922
+ Preflight passes under Josh's explicit `/usr/libexec/audiomxd` CPU allowance;
923
+ all blocks retain their memory, swap and thermal observations.
924
+
925
+ | Metric | v6 → v13 or paired factor | 95% block interval |
926
+ |---|---|---|
927
+ | Decode request wall time | 20.507 → 17.826 seconds pooled median; **1.1504×**, or **13.08% less time** | 1.1493–1.1514× |
928
+ | Decode SSE-window rate | 10.026 → 11.593 tok/s pooled median; 1.1562× | 1.1557–1.1568× |
929
+ | Cold 1K TTFT | 1.0145× | 0.9997–1.0292×; inconclusive |
930
+ | Warm 1K TTFT | 1.0889× | 1.0710–1.1083× |
931
+ | Long-prompt TTFT | 1.0039× | 0.9995–1.0083×; inconclusive |
932
+ | Four queued requests, aggregate rate | 1.1464× | 1.1457–1.1470× |
933
+ | Peak process RSS, inverse ratio | 0.9948× | 0.9755–1.0107×; no demonstrated reduction |
934
+
935
+ Factors above one favor v13. Intervals resample the six block log-ratios of
936
+ within-run summaries, not the individual requests. These describe this
937
+ controlled session, not variation across days or p99 latency. Each run has
938
+ five 192-token decode requests, cold/warm prefix requests, restart restoration
939
+ and the four-request aggregate leg. Actual long prompts contain
940
+ 10,397–10,399 tokens despite the synthetic `--context 16384` target. Both arms
941
+ use serial serving and bf16 KV; output hashes, prompt/output/reused-token
942
+ counts and finish reasons match throughout. The aggregate leg is queued
943
+ serial throughput, not evidence of simultaneous batch execution.
944
+
945
+ Final-source native checks also preserve full logits, cache state and
946
+ continuation at eight input lengths. Paired MTP-prefix restoration passes with
947
+ both bf16 and KV4 storage. Continuous and combined paired results follow below;
948
+ broader composed/pressure acceptance remains open; **no default is promoted by this serial result alone**.
949
+ Raw bundle: `reports/qwen38-closeout/m4-v6-v13-b{0..5}-v{6,13}.md.json`;
950
+ review and offline HTML: `m4-v6-v13-review.json`,
951
+ `m4-v6-v13-comparison.html`. Native evidence: `m4-final-native-runner.json`
952
+ and `m4-final-v13-*.log` in the same directory.
953
+
954
+ Six balanced longer-context continuous-serving pairs now pass on the same
955
+ M4 Pro, artifact, Bun/MLX versions and CPU allowance above. All 114 paired
956
+ requests match with no failures. Each run uses 256-token decode requests and
957
+ actual long prompts of about 20,717 tokens. The frozen source snapshot is
958
+ `363f74acc1e432677bfe333eec001c9111a1fb2c10128603409568f86dad58bb`.
959
+ The paired decode request-time factor is 1.15235×, or 13.22% less time,
960
+ with a 95% block interval of 1.15164–1.15316×. Four-request aggregate
961
+ throughput improves 2.37742×, with a 95% block interval of 2.37615–2.37856×.
962
+ These are same-session intervals, not across-day or sustained-load results.
963
+ Raw reports and review are
964
+ `reports/qwen38-closeout/m4-final-continuous-b{0..5}-v{6,13}.md.json`
965
+ and `m4-final-continuous-review.json`.
966
+
967
+ All six serial KV4 plus two-token MTP pairs with paired RAM prefixes now
968
+ pass, with all 114 paired requests matching and no failures. Source, host,
969
+ artifact and qualification match the longer-context continuous series above.
970
+ The paired decode request-time factor is 2.15832×, or 53.67% less time,
971
+ with a 95% block interval of 2.15467–2.16129×. Aggregate queued throughput
972
+ improves 2.07990×, with a 95% block interval of 2.07838–2.08162×. At long
973
+ context, decode SSE-window throughput improves 2.03668× and first-token time
974
+ improves 1.03885×. These compare kernel variant 13 with variant 6 while keeping
975
+ KV4 and MTP enabled in both arms; they do not isolate the benefit of MTP or
976
+ compare KV formats. All twelve restart requests reuse zero tokens: paired MTP
977
+ prefixes are RAM-only, so this is fresh-prefill restart measurement, not SSD
978
+ restoration. Raw reports and review are
979
+ `reports/qwen38-closeout/m4-final-kv4-mtp-b{0..5}-v{6,13}.md.json`
980
+ and `m4-final-kv4-mtp-review.json`. These measured settings are now selected in
981
+ the unreleased candidate source as documented in server-config.md; changing
982
+ default selection does not complete output-cache or execution consolidation.
983
+
984
+ The saved Kanban first-turn audit finds 50,479 reasoning tokens shared with
985
+ the next request beyond the original 2,550-token prompt. The following prompt
986
+ has 53,175 tokens. This is an offline tokenizer/template comparison, not a
987
+ performance measurement: no generated-state checkpoint has yet been accepted
988
+ for this saved long turn, and no saved time is claimed for it. Evidence:
989
+ `reports/qwen38-closeout/r17-first-tool-prefix-opportunity.json`.
990
+
991
+ ## Running the benchmark
992
+
993
+ `bun scripts/bench-serve.ts all` is THE benchmark — one pass, real servers,
994
+ real paths, every number that matters. Per model × arm (mlx-bun@defaults ·
995
+ mlx-bun `--batch 1` [the control arm — `--no-serial` skips] · mlx-lm ·
996
+ mlx-bun-mixed · optiq-mixed) it measures decode tok/s (five fixed samples,
997
+ all retained; unstable runs flagged), TTFT cold (~1k, nonce-busted) and warm/cached (each stack's own
998
+ prompt cache), prefill tok/s, long-context prefill/TTFT/decode (ONE measured
999
+ prefill; decode sampled on 64 tok + 2 cached repeats), aggregate tok/s at 4
1000
+ concurrent streams, peak RSS (sampled; undercounts GPU), and load→ready time.
1001
+ The same cells compare decoded text from greedy probes of up to 64 tokens
1002
+ between stacks of the same scheme, including the serial control vs mlx-lm.
1003
+ Prompt-count inequality rejects a comparison as template/tokenizer drift;
1004
+ matching counts and text are a smoke check, not proof of identical token IDs
1005
+ or logits. Missing usage cannot produce a passing verdict. The engine's
1006
+ pinned logit oracle remains the correctness gate.
1007
+
1008
+ ```sh
1009
+ bun scripts/bench-serve.ts all # cpm5 + e4b + 12B + Qwen3.8-27B, all arms
1010
+ bun scripts/bench-serve.ts all --no-serial # skip the --batch 1 control arm
1011
+ bun scripts/bench-serve.ts all --models cpm5,qwen27b # subset
1012
+ bun scripts/bench-serve.ts all --skip-context # drop the long-context leg
1013
+ bun scripts/bench-serve.ts all --context 8192 # shorter context leg
1014
+ ```
1015
+
1016
+ For an exact local quant use `--model-path <dir>` and optionally `--label`.
1017
+ It replaces the registry selection and cannot be combined with `--models`.
1018
+ `--dry-run` prints artifact metadata and server commands, with no preflight,
1019
+ model load, database write or server process. Packed trellis skips stock
1020
+ mlx-lm/optiq arms; explicitly requesting those arms fails before starting a
1021
+ server. A fake-quant/8-bit carrier is a separate artifact and cannot establish
1022
+ same-artifact packed performance or decode parity.
1023
+
1024
+ ```sh
1025
+ bun scripts/bench-serve.ts all --model-path /path/to/quant --label qwen38-quant --dry-run
1026
+ bun scripts/bench-serve.ts all --model-path /path/to/affine --arms mlx-bun-serial,mlx-lm --context 4096 --out reports/affine-h2h.md
1027
+ bun scripts/bench-serve.ts all --model-path /path/to/packed --arms mlx-bun-serial --context 4096 --out reports/packed-baseline.md
1028
+ bun scripts/bench/model-inventory.ts /path/to/affine /path/to/packed > reports/model-inventory.json
1029
+ ```
1030
+
1031
+ `--workload-seed <block-id>` generates identical nonce-prefixed prompts for
1032
+ every engine and artifact in that block, with distinct nonces for retries.
1033
+ `--logprobs` and `--top-logprobs N` apply capture settings to every timed
1034
+ request, including concurrent requests, and record them in the workload and
1035
+ request hashes. SSE timing measures capture cost; wire-level logprob values
1036
+ are checked separately by the native/HTTP composition tests.
1037
+ Thinking is pinned on for all chat measurements. Long-context filler uses a
1038
+ fixed character estimate so token-count drift cannot silently change the
1039
+ input on one engine. Record actual token counts and compare raw request hashes.
1040
+ Use phase/attempt/index to distinguish a cold request from its identical warm
1041
+ repeat; request hashes alone do not identify cache state.
1042
+ For paired trials, alternate `--arms mlx-bun-serial,mlx-lm` and the reversed
1043
+ order across blocks; give every block its own seed and `--out` path.
1044
+
1045
+ Configured engine experiments accept `--draft-model`, `--draft-kind`,
1046
+ `--num-draft-tokens`, `--kv-quant`, `--prompt-cache` and `--adapter`. These options
1047
+ require explicit `--arms mlx-bun-serial,mlx-bun` (or either engine arm); run
1048
+ oracle controls separately. Both selected engine arms receive identical overrides.
1049
+ The dry-run, raw JSON and Markdown report retain the settings and relevant
1050
+ runtime overrides. No script under `reports/` is required to launch them.
1051
+ For the current packed Qwen artifact on the M4 Pro, run this after closing
1052
+ other workloads. It exercises the opt-in KV4/MTP/paired-prefix configuration
1053
+ through the current checkout and writes a new dated report under `reports/`.
1054
+
1055
+ ```sh
1056
+ MLX_BUN_TRELLIS_VARIANT=13 MLX_BUN_QWEN_SPEC_KV4=1 MLX_BUN_MTP_PROMPT_CACHE=1 MLX_BUN_RD_PREFILL_CHUNK=256 \
1057
+ bun scripts/bench-serve.ts all \
1058
+ --model-path "$HOME/models/Qwen3.8-27B-q3-trellis-ldlq-k300-packed-interleave2-rd" \
1059
+ --arms mlx-bun-serial \
1060
+ --draft-model "$HOME/models/Qwen3.8-27B-MTP-folded-rtn4-g64-rd" \
1061
+ --draft-kind mtp --num-draft-tokens 2 --kv-quant 4 --prompt-cache 4 \
1062
+ --context 4096 --tokens 192 --workload-seed pr47-block-0
1063
+ ```
1064
+
1065
+ Append `--dry-run` to inspect the command first. This serving suite is separate
1066
+ from the Luke Kanban task and does not establish its task-time speedup. This
1067
+ entry point writes Markdown plus the `<report>.md.json` companion; the offline
1068
+ HTML comparison report renders from saved companions:
1069
+
1070
+ ```sh
1071
+ bun scripts/bench/report.ts reports/a.md.json reports/b.md.json --out reports/compare.html
1072
+ bun scripts/bench/report.ts reports/a.md.json reports/native-bun.json --out reports/compare.html --baseline mlx-bun-serial
1073
+ ```
1074
+
1075
+ Use `--baseline mlx-bun-serial --baseline-env MLX_BUN_TRELLIS_VARIANT=6`
1076
+ to compare environment-selected variants of that same arm. The selected
1077
+ setting stays visible in both serving tables; the usual identity and workload
1078
+ requirements still apply.
1079
+
1080
+ Inputs are auto-detected: bench-serve schema-4 `<report>.md.json` files and
1081
+ `scripts/bench/native.ts` `native-inference-diagnostic` JSON. Rendering reads
1082
+ the saved JSON only — no weights, server, GPU, Python or network. The single
1083
+ self-contained file shows a provenance panel per input (file sha256, machine
1084
+ string, commit, Bun, runtime overrides, source snapshot hashes, server
1085
+ commands, workload seed, thinking mode), a per-machine serving matrix with a
1086
+ status on every cell (measured, recovered on retry, failed with the phase
1087
+ error, not-measured, or unsupported with the reason), correctness flags beside
1088
+ the timings (finish-reason mix, actual vs requested output counts, early EOS,
1089
+ warm/restart cached-token counts, durability, request errors, retries, parity
1090
+ verdicts), ratios only against a baseline arm on the same machine key,
1091
+ artifact and workload (`--baseline mlx-lm|mlx-bun-serial|mlx-bun`; default
1092
+ mlx-lm when present), per-machine comparison columns, decode-sample strips,
1093
+ an RSS-versus-decode plot, a native token-identity table, and the retained
1094
+ failures, stderr tails and raw request table. "decode" stays the SSE-window
1095
+ rate and "actual output / wall" the completion-token rate; RSS is process
1096
+ RSS from `ps`. The paired uncertainty table groups fixed-source trials across
1097
+ workload seeds and gives a 95% percentile-bootstrap interval for the geometric
1098
+ mean of block ratios. It resamples block log-ratios, requires at least five
1099
+ distinct seeds and ignores duplicate seeds. Its baseline is fixed when the
1100
+ report is generated. Quality-versus-size renders "not measured" until a quality
1101
+ input exists.
1102
+
1103
+ Request-derived speed ratios require matching request hashes, attempts, full
1104
+ output hashes, prompt/output and reused-token counts, and finish reasons. A mismatch keeps the
1105
+ absolute timings visible and suppresses the ratio. Full output hashes survive
1106
+ fixture trimming. Retry summaries use the final attempt; earlier samples and
1107
+ failures remain in the raw table. Diagnostic, nonquiet and changing-source
1108
+ runs cannot earn speed ratios. Cross-file comparisons require a recorded
1109
+ hostname, matching artifact path/config and the complete workload definition;
1110
+ matching config files alone do not establish matching weights. New serving
1111
+ companions record hostname and OS. Old files with no hostname compare only
1112
+ within their own file. Displayed ratios are ratios of medians, not paired
1113
+ confidence intervals or default-promotion evidence.
1114
+
1115
+ The bounded M1 Max smoke of this path uses MiniCPM, 16 requested decode
1116
+ tokens, `--skip-context`, and the unsplit reference. Both real-server arms
1117
+ complete without failed phases on fixed source. Warmup, the parity chat,
1118
+ five decode requests and the cold/warm 1K requests match full output hashes
1119
+ and reused-token counts. Concurrent four-request outputs still differ.
1120
+ Short decode timings are unstable; the run is explicitly diagnostic and
1121
+ cannot supply speed ratios or M4 acceptance. Raw data and review:
1122
+ `reports/qwen38-closeout/serve-smoke.md.json` and `serve-smoke-review.json`.
1123
+ The offline `comparison.html` includes this run beside both machines' saved
1124
+ evidence. Automated rendering/escaping checks pass; browser URL policy
1125
+ blocked visual inspection of the local HTML file.
1126
+
1127
+ `--reference-prefill server` keeps stock MLX-LM system/thinking segmentation
1128
+ and is the default. `--reference-prefill unsplit` selects an explicit Python
1129
+ reference control that passes one whole-prompt segment to BatchGenerator,
1130
+ which still reserves the final token. Tokenization, model operations,
1131
+ sampling and HTTP handling remain in the pinned reference. This changes
1132
+ prefill and cache policy and is recorded in commands, workload identity and
1133
+ the Markdown report. It applies to the `mlx-lm` arm, including models that
1134
+ need OptiQ registration. Use it only where it matches the Bun request's
1135
+ boundaries; it does not promise matching arbitrary multi-turn snapshots.
1136
+
1137
+ ```sh
1138
+ bun scripts/bench-serve.ts all --models cpm5,qwen27b --arms mlx-bun,mlx-bun-serial,mlx-lm --reference-prefill unsplit --out reports/matched-prefill.md
1139
+ ```
1140
+
1141
+ For an exclusively allocated GPU, `--allow-cpu-process /absolute/command`
1142
+ permits one explicitly reviewed background command to exceed the CPU
1143
+ threshold. The exact command and observed activity remain in the raw
1144
+ preflight snapshots and the report names the allowance. RSS, swap, thermal
1145
+ and overall-load checks still apply. This is not proof of an idle GPU or
1146
+ stable timing: verify GPU ownership and compare alternating repeated runs.
1147
+ Josh authorized this policy for `/usr/libexec/audiomxd` on the M4 Pro;
1148
+ CPU activity alone no longer blocks this campaign. Earlier diagnostic
1149
+ runs keep their original classification.
1150
+
1151
+ `--diagnostic` explicitly permits a loaded-machine serving run. It records
1152
+ the preflight snapshot and writes `*-serve-diagnostic` DB rows, which cannot
1153
+ serve as canonical results. Server children use the invoking Bun executable,
1154
+ so an isolated runtime comparison actually changes the server runtime too.
1155
+
1156
+ The Markdown report has a `<report>.md.json` companion containing all chat
1157
+ requests, results, failures and retries, plus config/source-diff hashes and
1158
+ server commands. Schema 4 also hashes a sorted manifest of tracked and
1159
+ untracked source files at startup and save time, so new local kernels cannot
1160
+ escape source identity. External native libraries and weights need their own
1161
+ manifests. Failed attempts include the child's stderr tail and process
1162
+ status; a successful retry keeps the recovered failure visible. It is saved
1163
+ after each completed or failed cell. The report
1164
+ separately records total request wall time and actual-output throughput.
1165
+ The decode columns use the first-to-last visible SSE interval: bursty chunks
1166
+ can distort that interval, so it is not a GPU timing. Token throughput requires
1167
+ valid server usage; chunk counting is no longer a fallback. Raw results also
1168
+ record response-header, first-byte and first-SSE-event latency, then every
1169
+ content/reasoning/tool-output event arrival. Event gaps measure stream
1170
+ delivery, not individual token latency. Tool-only streams have an output TTFT.
1171
+ Malformed/error SSE and responses without a finish reason or `[DONE]` fail
1172
+ the measurement. Match output counts, finish reasons and text before
1173
+ interpreting a speed difference. The exported `measureCompletionRequest`
1174
+ helper applies the same timing and stream-validation contract to raw
1175
+ `/v1/completions` requests, without chat-template preparation.
1176
+
1177
+ The inventory reads shard headers and config only, reconstructs matrix
1178
+ shapes including trellis axis-0 storage, and counts actual tensors rather
1179
+ than duplicate config aliases. Its matrix effective-bpw figure includes
1180
+ scales/biases but excludes norms, convolutions and sidecars; it is explicitly
1181
+ not whole-model bpw or peak memory. Config/index/layout hashes do not hash
1182
+ weight payloads. Use existing shard hashes or hash weights outside timed runs
1183
+ when certifying artifact identity. The complete Qwen campaign is in
1184
+ [the performance program](../../design/decode-speed-program.md#7-qwen38-27b-research-program).
1185
+
1186
+ For native engine isolation, `scripts/bench/native.ts` runs dense Qwen3.5/3.8
1187
+ with bf16 attention KV, f32 recurrent state and greedy decoding. Supply a
1188
+ frozen JSON array of prompt token IDs and the exact local artifact to both
1189
+ stacks. Each request starts with a fresh cache; warmups and every measured
1190
+ sample are retained. Reports include actual output IDs, EOS policy, TTFT,
1191
+ wall time through cache cleanup/GPU synchronization, memory and source pins.
1192
+ They record the effective wiring policy and active/cached memory around each
1193
+ request. The oracle worker enters mlx-lm's normal scoped wired limit; compare
1194
+ that policy with Bun's model-sized scope before interpreting a ratio.
1195
+ `--clear-before-request` is a separate allocator-cache experiment on both
1196
+ stacks, with cleanup included in wall time. Keep it fixed within a pair;
1197
+ it does not clear model weights or substitute for a fresh inference cache.
1198
+ Stock mlx-lm rejects packed trellis. This worker uses the pinned oracle
1199
+ environment and never starts a server or downloads a model.
1200
+
1201
+ ```sh
1202
+ bun scripts/bench/native.ts --model-path /path/to/affine --prompt-ids reports/prompt-ids.json --stack mlx-bun --json reports/native-bun.json --dry-run
1203
+ bun scripts/bench/native.ts --model-path /path/to/affine --prompt-ids reports/prompt-ids.json --stack mlx-lm --json reports/native-oracle.json
1204
+ ```
1205
+
1206
+ Alternate stack order across predeclared process pairs. Check token IDs,
1207
+ output counts and finish reasons before comparing request wall times.
1208
+ `--diagnostic` permits a failed quiet-machine preflight and records that
1209
+ failure. Native results remain diagnostic, including on a quiet machine;
1210
+ they do not establish HTTP throughput, task quality or full logit parity.
1211
+ The repaired legacy `bench-h2h.ts direct` command delegates to this worker,
1212
+ requires `--models` and bf16 KV, and writes only `*-native-diagnostic` DB
1213
+ rows with raw report paths. Its rates use actual emitted tokens and all
1214
+ fixed samples. Use the worker directly to avoid registry ambiguity.
1215
+
1216
+ `all` runs the clean-machine preflight first (refuses headline numbers from
1217
+ a loaded or swapped box) and holds `caffeinate` for the pass. Quotable
1218
+ numbers and ratios need a quiet machine; loaded runs are diagnostic only.
1219
+ Results land in the eval DB (`~/.cache/mlx-bun/evals.sqlite`) plus dated
1220
+ Markdown and JSON reports under `reports/` by default. Developer lever A/Bs are NOT benchmarks — run
1221
+ `scripts/bench-levers.ts <faithful-matrix|fused-prefill|compiled-decode>` or
1222
+ `scripts/bench-matrix.ts <modes|features>` directly when touching those paths.
1223
+
1224
+ There are **three categorically different kinds of measurement** — kept in
1225
+ separate sections because they answer different questions:
1226
+
1227
+ 1. **Parity** — are we *bit-exact* with the upstream oracle? (pass/fail)
1228
+ 2. **Performance** — *numbers* under like-for-like config (tok/s, memory…).
1229
+ 3. **Quality** — for non-bit-exact optimizations, what does the speed cost
1230
+ in output quality? (6-test mean + KL)
1231
+
1232
+ **Default machine for older rows:** Apple M4 Pro, 24 GB unified
1233
+ (`Joshs-MBP-2025`), ~273 GB/s. Newer subsections name their machine explicitly.
1234
+ **Oracle toolchain:** Bun 1.3.14; Python 3.13.5 with mlx 0.31.2,
1235
+ mlx-lm 0.31.3, mlx-optiq 0.2.1. Numbers below are the 2026-06-14
1236
+ cleared-machine run (commits `97457e4` / `d1e0296`), preflight-gated,
1237
+ median-of-N with warmups discarded.
1238
+
1239
+ **Model legend** (registry hash → repo):
1240
+
1241
+ | hash | model |
1242
+ |---|---|
1243
+ | `664aabaed233` | `MiniCPM5-1B-OptiQ-4bit` (sub-GB starter) |
1244
+ | `fcdb12d740cd` | `gemma-4-e4b-it-OptiQ-4bit` |
1245
+ | `5b1101065d20` | `gemma-4-12B-it-OptiQ-4bit` |
1246
+ | `dbfd2a779b03` | `gemma-4-26B-A4B-it-OptiQ-4bit` (MoE) |
1247
+
1248
+ > **Legend corrected 2026-06-15.** An earlier revision had the gemma
1249
+ > hashes cycled (`5b…`→e4b, `dbfd…`→12B, `fcdb…`→26B). The mapping above is
1250
+ > the authoritative one from `tests/support/paths.ts` (`SNAPSHOT`=`5b…`=12B,
1251
+ > `SNAPSHOT_26B`=`dbfd…`=26B) and the e4b snapshot hash used across
1252
+ > `tests/*.test.ts` (`fcdb…`=e4b), corroborated by on-disk weight size
1253
+ > (e4b 7.0G · 12B 8.4G · 26B 18G). The **Performance** rows below were
1254
+ > labeled by the old legend; each gemma row has been relabeled to its true
1255
+ > model, re-identified by its gen-peak / steady-RSS fingerprint —
1256
+ > e4b≈6.6 GB, 12B≈9.0 GB, 26B≈17.7 GB — which is stable across runs. The
1257
+ > row *data* was correct; only the model labels moved.
1258
+
1259
+ ---
1260
+
1261
+ ## 1. Parity (porting correctness) — bit-exact vs the oracle
1262
+
1263
+ Parity results moved to the [current benchmark reference](../../reference/benchmarks.md).
1264
+
1265
+ ### GLM-5.2 direct-Colibri oracle closure — M1 Max 32 GB
1266
+
1267
+ The direct-container port uses pinned Colibri, rather than mlx-lm, as its
1268
+ implementation oracle. The public artifact is
1269
+ `mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp@3cc8db9`; direct component and
1270
+ G0 controls use Colibri `44e489b`, while the later official DSA replay is
1271
+ pinned to `ecade075` with indexers sourced from
1272
+ `zai-org/GLM-5.2-FP8@ba978f7d`.
1273
+
1274
+ | gate | result | durable proof |
1275
+ |---|---|---|
1276
+ | tiny converted Q4 trajectory | 32/32 greedy tokens exact with `IDOT=0`; all 8,192 logits max abs `1.3113e-6`, RMSE `2.7423e-7` | `fixtures/colibri-glm52/tiny-teacher-forcing.json` |
1277
+ | production Q4/router cells | layer-0 SwiGLU max abs `5.2387e-9`; layers 3/77 exact ordered top-8 | `fixtures/colibri-glm52/production-probe.json` |
1278
+ | real-model oracle | 140 GLM/MLA/router/MTP/KV records reproduced byte-for-byte twice; both heads predict teacher token 16 | `fixtures/colibri-glm52/real-model-oracle.json` |
1279
+ | full target trajectory | all 128 cold/warm, MTP-on/off target token IDs identical; first 64 also match direct Colibri | machine-local `runs/colibri-g5/summary.json` |
1280
+ | first-sparse DSA | all 21 official score rows replay to exact ordered positions and float32 thresholds at context 2,049; both engines emit `[264,264]` | `~/.cache/mlx-bun/evidence/glm52-dsa-stage0-2026-08-17/` |
1281
+
1282
+ These are quality-preserving gates: checkpoint precision, true top-8 routing,
1283
+ and the 21-full/57-shared DSA schedule remain unchanged. Consequently there is
1284
+ no KL/eval tradeoff row in section 3 for this path.
1285
+
1286
+ **Served-surface parity (2026-07-07, prefill tail-split fix):** the two
1287
+ serve-bench parity residuals (cpm5 + 12B `/v1/completions` probe ✗ on the
1288
+ 07-07 run) are closed — with the oracle's step-0 prefill convention
1289
+ adopted (drain to len−1, step 0 from an L=1 forward of the last prompt
1290
+ token; `MLX_BUN_PREFILL_TAIL_SPLIT`), live HTTP probes are
1291
+ **byte-identical** to `mlx_lm.server`/optiq serve for MiniCPM5-1B,
1292
+ gemma-4-e4b, AND gemma-4-12B, on completion + chat probes, in both the
1293
+ unified (`--batch 8` default) and `--batch 1` lanes; script-level A/B
1294
+ shows 64/64 token ids + top-2 logprob values identical per step
1295
+ (`serve-parity-probe.ts (deleted; git history)`,
1296
+ `step0-top2-dump.ts (deleted; git history)`).
1297
+
1298
+ ---
1299
+
1300
+ ## Methodology change (2026-07-05)
1301
+
1302
+ The primary benchmark is now **`bun scripts/bench-serve.ts all` → `scripts/bench-serve.ts`**:
1303
+ real servers on real paths — the mlx-bun arms spawn the ACTUAL CLI at its
1304
+ actual defaults (the old harness used a bench-local wrapper, since deleted),
1305
+ and every metric arrives over HTTP as a user would see it. One server per
1306
+ cell yields: decode tok/s, cold TTFT (~1k, nonce-busted), warm/cached TTFT
1307
+ (each stack's own prompt cache), prefill tok/s, long-context
1308
+ prefill/TTFT/decode (ONE measured prefill; decode sampled on 64 tokens),
1309
+ aggregate tok/s at 4 concurrent streams, and load→ready time. Context
1310
+ lengths are recorded from usage.prompt_tokens (measured, not requested).
1311
+ Engine-level questions (in-process kernel parity, gen-peak memory,
1312
+ kill-switch A/Bs) live behind `bun scripts/bench-serve.ts all --engine`. Numbers below this
1313
+ note predate the redesign; the next quiet-machine pass supersedes them.
1314
+
1315
+ ## 2. Performance — like-for-like numbers
1316
+
1317
+ Two comparison axes: **vs the oracles**, and **our optimized path vs our
1318
+ own bit-exact compat path** (does an optimization beat the baseline it
1319
+ diverges from). Within mlx-bun, `bf16` is the L1-compatible path and
1320
+ `mixed` is the L2-compatible path; both are bit-exact, so the bf16↔mixed
1321
+ delta is the first "our-vs-our" axis. Lab experiment rows (no external
1322
+ oracle; KL/eval-gated) land here once one beats the L1 baseline in a
1323
+ paired A/B — none recorded yet (the 2026-07-05 candidates were deleted).
1324
+
1325
+ ### Default batched h2h without serial controls — M4 Pro (2026-09-11)
1326
+
1327
+ Default batched h2h moved to the [current benchmark reference](../../reference/benchmarks.md).
1328
+
1329
+ ### Released v0.4.0 packed Qwen with KV4/TQ and MTP2 — M4 Pro (2026-09-11)
1330
+
1331
+ Packed Qwen cache comparison moved to the [current benchmark reference](../../reference/benchmarks.md).
1332
+
1333
+ ### Released v0.4.0 standard registry comparison — M4 Pro 24 GB (2026-09-11)
1334
+
1335
+ Released standard registry comparison moved to the [current benchmark reference](../../reference/benchmarks.md).
1336
+
1337
+ ### Standard serve matrix — M4 Pro 24 GB (2026-09-08, incomplete acceptance)
1338
+
1339
+ Josh ran `bun scripts/bench-serve.ts all` at clean commit `86738ac` on
1340
+ `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, Bun 1.4.0, with the matching
1341
+ MLX 0.32.2 reference. Quiet preflight passed. There were no runtime overrides;
1342
+ the workload used `bench-serve-v2`, thinking enabled, five 192-token decode
1343
+ requests and a requested context target of 16,384. The actual context probes
1344
+ contained 9,062 MiniCPM tokens and 9,589 Gemma tokens. This is one ordered
1345
+ suite, not an alternating before/after optimization comparison.
1346
+
1347
+ | Model | Default mlx-bun decode tok/s | mlx-lm decode tok/s | Default mlx-bun request time | mlx-lm request time | Request-time reduction |
1348
+ |---|---:|---:|---:|---:|---:|
1349
+ | MiniCPM5-1B | 278.65 | 223.55 | 0.710 s | 0.936 s | 24.2% — output mismatch |
1350
+ | Gemma4-e4b | 57.86 | 53.63 | 3.402 s | 3.810 s | 10.7% |
1351
+ | Gemma4-12B | 26.14 | 25.40 | 7.576 s | 7.969 s | 4.9% |
1352
+ | Qwen3.8-27B 4/8-bit winner | 14.75 | 14.19 | 13.814 s | 14.523 s | 4.9% — output mismatch |
1353
+
1354
+ The table uses medians of the same five requests, all with exactly 192 output
1355
+ tokens. Request hashes, input/output counts and cached-token counts match
1356
+ between these arms. Both Gemma models also match all five timed output texts
1357
+ and both short parity probes. MiniCPM and Qwen differ on all five timed
1358
+ outputs despite matching counts; Qwen's separate 64-token probes match, while
1359
+ MiniCPM's chat probe diverges. Their timing rows remain observations pending
1360
+ the exact-token/logit investigation. The Gemma12B reference command invokes
1361
+ OptiQ's model registration before its mlx-lm serving path.
1362
+
1363
+ For Gemma e4b, cold/cached TTFT is 559/72 ms versus 707/212 ms in the
1364
+ reference, and the approximately 1K prefill estimate is 1,199 versus 947
1365
+ tok/s. For Gemma 12B those values are 2,531/157 ms versus 2,677/333 ms and
1366
+ 265 versus 250 tok/s. The serial controls finish the same short requests in
1367
+ 3.360 s and 7.514 s, respectively. Cached TTFT is one warm sample per cell.
1368
+
1369
+ Acceptance is incomplete. Qwen hits Metal out-of-memory errors in both the
1370
+ approximately 1K and context phases, in default and serial serving. Its
1371
+ reference recovers an initial 1K timeout, then fails the context phase and
1372
+ skips concurrency. MiniCPM and Gemma12B each report missing SSD snapshots on
1373
+ the first restart-flush attempt in default and mixed serving; retries succeed.
1374
+ Mixed-KV rows are not compared for L1 identity against bf16 KV. The complete
1375
+ report retains eleven phase-failure records, including recovered failures.
1376
+
1377
+ The Qwen artifact is the registry's 4/8-bit winner, not the required 12.14 GiB
1378
+ packed Trellis target. No MTP draft was configured. These numbers neither
1379
+ replace the Trellis/KV4/MTP measurements nor establish a Kanban task-time gain.
1380
+ Raw evidence: `reports/benchmarks-serve-2026-09-08-Joshs-MBP-2025.md` and its
1381
+ `.md.json` companion; source hashes are unchanged across the run.
1382
+
1383
+ The SSD follow-up at `f144516` fixes flush ordering: an ancestor removed from
1384
+ RAM can be covered by a longer trimmable snapshot written later in that same
1385
+ flush. After all writes settle, the coordinator checks committed coverage
1386
+ again and keeps uncovered prefixes dirty. The regression fails before the
1387
+ change and all 29 SSD tests pass afterward. The same M4 Pro repeats pass all
1388
+ phases on the first attempt for MiniCPM and Gemma12B in both default and mixed
1389
+ serving, restoring 9,061 and 9,588 tokens after restart. Source hashes stay
1390
+ fixed in both repeats. Default-arm timed request hashes and all ten output
1391
+ texts match the original run. The original failure records remain intact;
1392
+ this follow-up does not resolve their separate cross-oracle output differences.
1393
+ Evidence: `reports/qwen38-rd/pr47-ssd-followup.md.json` and
1394
+ `reports/qwen38-rd/pr47-ssd-followup-mixed.md.json`.
1395
+
1396
+ The subsequent boundary investigation identifies the timed-output difference
1397
+ on MiniCPM and Qwen. For each model's first saved request, Bun and Python match all 192
1398
+ complete native logit vectors. Stock Python HTTP instead splits at the
1399
+ thinking marker: MiniCPM uses prefill lengths 29, 1, 1 instead of 30, 1;
1400
+ Qwen uses 75, 1, 1 instead of 76, 1. Those segmented native Python runs
1401
+ reproduce the original reference responses after HTTP thinking-tag removal.
1402
+ The explicit unsplit reference control then reproduces all ten saved Bun
1403
+ decode responses, with identical output counts and finish reasons. Request
1404
+ hashes match. The first MiniCPM replay reuses zero tokens versus four in the
1405
+ original run; the other nine cache counts match. These are M4 Pro correctness
1406
+ diagnostics, not a replacement timing cohort or a speed claim. Qwen's Metal
1407
+ prefill failures and quiet paired timing acceptance remain open. Evidence:
1408
+ `reports/qwen38-closeout/prefill-segmentation-review.json` and its hashed
1409
+ native/HTTP companions. The initial invalid-model-ID replay is retained on
1410
+ the M4 Pro as `cpm5-replay-invalid-model-id.json`.
1411
+
1412
+ The Qwen memory follow-up on the same M4 Pro distinguishes a fresh-process
1413
+ control from the suite's retained state. The saved “1K” request actually has
1414
+ 757 prompt tokens and succeeds after a fresh warmup. Replaying the preceding
1415
+ warmup, completion/chat parity probes and five decode requests with SSD cache
1416
+ enabled reproduces the Metal OOM on the original source. An isolated
1417
+ per-layer prefill-evaluation prototype passes the fresh control; its full
1418
+ history replay completes warmup and the raw completion probe, then times
1419
+ out before the parity chat finishes. SSH subsequently became unavailable
1420
+ and recovered without a reboot. The timeout has no resolved cause, and the
1421
+ prototype is not integrated. Raising the fit estimate alone does not resolve
1422
+ the observed OOM. Local fresh controls and recovered history trials are
1423
+ `reports/qwen38-closeout/qwen27b-memory-{server,barrier}-{fresh,history}.json`;
1424
+ the M4 keeps the history trials under the unsuffixed names. Preflight still
1425
+ rejects retained swap. No speed or memory improvement is accepted from
1426
+ these trials.
1427
+
1428
+ After the M4 reboot and unlock, the frozen candidate still fails the 1K
1429
+ prefill phase on both attempts. Layer evaluation gets all four cold/warm 1K
1430
+ requests through with the seven preceding outputs and usage unchanged, but
1431
+ four-request serving then fails with a Metal OOM. Reserving successor state
1432
+ for all batch rows gets all 15 requests through. Both changes are now in the
1433
+ working candidate. Twelve same-version oracle cases (prefix lengths 0/64,
1434
+ forward lengths 1/4/8/16/128/757) preserve complete logits, recurrent state
1435
+ and continuation exactly. A longer replay completes 38 requests across
1436
+ continuous and serial serving, including a 2,679-token context and SSD
1437
+ restart restoring 2,678 tokens. All 15 individually issued requests match
1438
+ across lanes in output and usage; the four concurrent responses differ and
1439
+ are excluded from cross-lane speed comparisons.
1440
+
1441
+ These remain correctness diagnostics under their original run policy.
1442
+ A subsequent control removes per-token memory polling from continuous
1443
+ decode and reserves at batch joins. It completes 19 requests with a
1444
+ 5,239-token context and restores 5,238 tokens from SSD. The integrated
1445
+ reservation also accounts for cache growth to the requested output caps;
1446
+ its repeat preserves all 19 request identities, outputs and usage counts.
1447
+ Josh then clarified that the isolated audio CPU load is acceptable with
1448
+ memory and GPU availability; new acceptance runs record the explicit
1449
+ allowance described above. Earlier diagnostics are not relabeled.
1450
+ Evidence under `reports/qwen38-closeout/`:
1451
+ `m4-{candidate,layer-eval,layer-batch}-memory.md.json`,
1452
+ `m4-memory-review.json`, `m4-layer-state-{bun,reference,review}.json`,
1453
+ `m4-memory-context{.md,-review}.json`,
1454
+ `m4-{join-only,reserved-growth}-memory.md.json` and
1455
+ `m4-join-reservation-review.json`; artifact hashes are in
1456
+ `m4-candidate-preparation.json`. No speed default is promoted.
1457
+
1458
+ The first CPU-allowance R0 block (same M4 Pro, candidate on `0c355f4`,
1459
+ Bun 1.4.0, MLX 0.32.2, stock GPU ceiling, explicit unsplit reference)
1460
+ passes preflight before and after on fixed source. All five decode requests
1461
+ match across continuous Bun, serial Bun and Python in complete output,
1462
+ prompt/generated/reused tokens and finish reason. Within-arm decode spread
1463
+ is 0.49%, 1.05% and 0.78%, respectively; this is one block, not a paired
1464
+ speed verdict. Continuous serving completes all phases. Without the earlier
1465
+ context leg's server restart, serial serving fails the fourth queued request
1466
+ with Metal OOM. Python's 1K timeout and final aggregate failure also contain
1467
+ Metal OOM tracebacks, at prompt-state evaluation and pipelined decode.
1468
+ The earlier longer replay therefore does not close retained-history pressure.
1469
+ A focused allocation trace reproduces the fourth-request failure with
1470
+ 18,783,888,604 active bytes, a four-byte allocator pool, 2,485,518,336 bytes
1471
+ of RAM prefixes and a 199,133,984-byte reservation against the
1472
+ 19,069,665,280-byte GPU ceiling. The pool is not the missing memory; the
1473
+ remaining 86,642,692 bytes do not establish room for overlapping asynchronous
1474
+ state updates. A two-successor boundary reservation then completes all 30
1475
+ requests across both Bun lanes without failures. The 29 successful requests
1476
+ from R0 match output and usage; the formerly failed serial request matches
1477
+ the earlier context/restart control. Full-output reservation and longer
1478
+ generation are the next gates. Evidence:
1479
+ `m4-serial-allocation-probe.md.json`, `m4-serial-allocation-review.json`,
1480
+ `m4-two-state-memory.md.json` and `m4-two-state-memory-review.json` in
1481
+ `reports/qwen38-closeout/`.
1482
+ Raw: `reports/qwen38-closeout/m4-r0-audio-allowed-01.md.json` and
1483
+ `m4-r0-audio-allowed-01-review.json`.
1484
+
1485
+ ### Fresh Kanban candidate generation — M4 Pro (2026-09-09)
1486
+
1487
+ The frozen optimized candidate completed the pinned Luke Kanban prompt on
1488
+ Joshs-MBP-2025.local (M4 Pro 24 GB, Bun 1.4.0, MLX 0.32.2, Pi 0.85.1)
1489
+ in **5,085.387 seconds (1h 24m 45.387s)** from prompt submission to completion.
1490
+ It generated 68,958 output tokens across 15 requests, with zero Pi retries,
1491
+ compactions or tool errors. Pi and the server exited zero; the outcome parser
1492
+ confirmed completion, profile requests were valid, and source hashes stayed fixed.
1493
+ The run used packed interleave2, variant 13, KV4, MTP depth 2 and paired RAM
1494
+ prefixes, with the authorized audio CPU allowance. R17 generated-history
1495
+ checkpointing was not implemented in this candidate.
1496
+
1497
+ The untouched generated app passes all 18 required browser acceptance categories,
1498
+ including native card/column dragging, combined filters, archive/restore,
1499
+ keyboard operation and persistence in both themes. Source hashes are unchanged. The earlier successful task generated a different number of tokens
1500
+ and tool turns, so this duration does not establish an engine-only speedup.
1501
+ The first/new runs used 75/21 tool calls, 7/0 tool errors and 1/0 compactions.
1502
+ Summed pre-first-output time is 3,399.895/814.988 seconds. New task time is
1503
+ 60.2% lower and output count 47.2% lower, without an engine-only attribution.
1504
+ The sole initial-request difference is Pi's working-directory suffix:
1505
+ `kanban-final-workspace` versus `kanban-closeout-candidate-r1-workspace`,
1506
+ verified as five additional tokens by the model tokenizer. Both used batch 1
1507
+ and MTP depth 2. Detailed acceptance and comparison:
1508
+ `reports/qwen38-closeout/kanban-run-comparison.md`; raw evidence:
1509
+ `reports/qwen38-closeout/kanban-final-candidate-r1/`.
1510
+
1511
+ ### Direct scheduler B=1 versus serial — both machines (2026-09-08)
1512
+
1513
+ Josh's September 8 standard suites include both default scheduling and strict
1514
+ serial controls. M1 Max 32 GB used clean commit `1ac8f61`; M4 Pro 24 GB used
1515
+ clean commit `86738ac`. Both used Bun 1.4.0, no runtime overrides, and passed
1516
+ quiet preflight. Compare arms within each machine; the machines have different
1517
+ source commits. These are single ordered suites, not alternating repeat blocks.
1518
+
1519
+ Median short-decode SSE rates from five 192-token requests per arm:
1520
+
1521
+ | Model | M1 default / serial tok/s | M4 default / serial tok/s |
1522
+ |---|---:|---:|
1523
+ | MiniCPM5-1B | 268.79 / 267.81 | 278.65 / 275.86 |
1524
+ | Gemma4-e4b | 63.85 / 64.01 | 57.86 / 59.03 |
1525
+ | Gemma4-12B | 30.33 / 30.33 | 26.14 / 26.44 |
1526
+ | Qwen3.8-27B 4/8-bit winner | 18.58 / 18.56 | 14.75 / 14.66 |
1527
+
1528
+ All 40 paired timed responses match between default and serial in request hash,
1529
+ output text, prompt/cached/generated token counts, finish reason and DONE status.
1530
+ Completion and chat parity probes also match for all eight model/machine cells.
1531
+ This comparison is between our two executors; it does not erase the separate
1532
+ Python-reference differences recorded in the M4 section above. Default B=1
1533
+ short-decode rates are within 0.4% of serial on M1 and within 2.0% on M4.
1534
+ The M1 suite has no phase failures. The M4 suite retains its recorded SSD retry
1535
+ and Qwen prefill OOM failures; short-decode agreement is not whole-suite acceptance.
1536
+
1537
+ The M1 four-request aggregate rates, default versus serial, are 408.12/243.14
1538
+ (MiniCPM), 101.60/60.91 (e4b), 41.32/27.95 (12B), and 20.08/15.72 (Qwen),
1539
+ in tok/s. These measure aggregate throughput, not single-request latency.
1540
+ The results support sharing a scheduler with a B=1 case; they do not establish
1541
+ feature completeness for replacing the dedicated executor, including MTP.
1542
+ Raw reports: `reports/benchmarks-serve-2026-09-08-Joshs-MacBook-Pro.md.json`
1543
+ and the M4's `reports/benchmarks-serve-2026-09-08-Joshs-MBP-2025.md.json`
1544
+ (local preserved copy: `reports/qwen38-closeout/m4-standard-20260908-original.json`).
1545
+
1546
+ ### Batched logprob composition — M4 Pro, acceptance open (2026-09-09)
1547
+
1548
+ Two ordered/reversed `bench-serve.ts all` blocks use the packed interleave2
1549
+ Qwen artifact on Joshs-MBP-2025.local, M4 Pro 24 GB, Bun 1.4.0 and MLX
1550
+ 0.32.2. Both pass preflight with the authorized audio CPU allowance. The
1551
+ frozen sampler candidate uses selected logprobs plus top-3 capture, unchanged
1552
+ kernels, five 192-token decode requests and the short-context suite with SSD
1553
+ caching. Its source predates the subsequent explicit-seed placement change;
1554
+ these benchmark requests have no explicit seed. Neither block has a failure.
1555
+
1556
+ | Block/order | Median decode request ms, serial / batch B=1 | Cached TTFT ms, serial / batch B=1 | Cached request ms, serial / batch B=1 |
1557
+ |---|---:|---:|---:|
1558
+ | 0, serial then batch | 17,833.47 / 17,785.57 | 261.16 / 307.45 | 800.68 / 846.69 |
1559
+ | 1, batch then serial | 17,840.70 / 17,771.87 | 272.90 / 319.81 | 812.66 / 858.99 |
1560
+
1561
+ All 22 single-request pairs match request/output hashes, token counts, finish
1562
+ reason and DONE status. Only three of eight concurrent pairs match complete
1563
+ outputs across serial and batch execution, so their timing does not establish
1564
+ an identical-work speedup. The cached response regression keeps performance
1565
+ acceptance open. Existing ordinary-execution M1/M4 baselines above remain valid.
1566
+
1567
+ Raw reports and review: `reports/qwen38-closeout/composition-baseline/`
1568
+ `logprobs-composition-{0,1}.md.json` and `logprobs-performance-review.json`.
1569
+ A third block enables `MLX_BUN_EARLY_FIRST_TOKEN=1` in both arms using
1570
+ block 0's requests. Source hashes remain fixed and no phase fails. Serial /
1571
+ batch B=1 median decode request time is 17,847.38 / 17,782.37 ms, cached
1572
+ TTFT 194.87 / 242.19 ms, and cached request time 809.63 / 860.77 ms. All
1573
+ 15 within-block response pairs match, including the four concurrent requests.
1574
+ All 11 single-request outputs also match block 0; two concurrent batch outputs
1575
+ change with the different admission timing. Early output improves delivery in
1576
+ both arms but leaves the cached-request regression open. It is not a default
1577
+ promotion. Raw: `logprobs-early-composition-0.md.json` and
1578
+ `logprobs-early-performance-review.json` in the same directory.
1579
+
1580
+ Bounded P2R diagnostics there separate recurrent-boundary SSD persistence
1581
+ from output-delivery delay. Traced timings are diagnostic only.
1582
+
1583
+ ### Shared uniform KV4 composition — M4 Pro, acceptance open (2026-09-09)
1584
+
1585
+ One ordered serial/default block uses the packed interleave2 artifact with
1586
+ uniform KV4, selected logprobs and top-3 capture on M4 Pro 24 GB, Bun 1.4.0,
1587
+ MLX 0.32.2. Both commands receive identical KV options. Preflight passes with
1588
+ the authorized audio allowance, source hashes stay fixed, and no phase fails.
1589
+ Serial / shared B=1 median decode request time is 17,866.95 / 17,814.16 ms;
1590
+ median SSE decode rate is 11.5556 / 11.5569 tok/s. Cached TTFT is 271.67 /
1591
+ 292.97 ms and cached request time 813.85 / 834.49 ms. The cached latency gap
1592
+ keeps acceptance open; this single ordered block cannot establish stability.
1593
+ All 11 single-request pairs match complete responses. Only one of four
1594
+ concurrent pairs matches, so the aggregate timings do not establish an
1595
+ identical-work speedup. The frozen candidate includes the shared KV conversion
1596
+ and uniform placement change; later removal of an obsolete startup warning is
1597
+ not part of this source snapshot.
1598
+
1599
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1600
+ `uniform-kv4-composition-0.md.json` and `uniform-kv4-performance-review.json`.
1601
+
1602
+ ### Immutable RAM prefix prototype — M4 Pro (2026-09-09)
1603
+
1604
+ The first borrowed-prefix prototype uses the same packed artifact, selected
1605
+ logprobs/top-3, SSD cache and workload as logprob block 0 above. On M4 Pro
1606
+ 24 GB, Bun 1.4.0, MLX 0.32.2, preflight passes with the authorized audio CPU
1607
+ allowance. Source hashes remain fixed and no phase fails. Serial / shared
1608
+ B=1 median decode request time is 17,874.77 / 17,758.63 ms, cached TTFT
1609
+ 256.93 / 168.77 ms and cached request time 796.78 / 707.51 ms.
1610
+
1611
+ All 11 single-request pairs match. Every output within each arm also matches
1612
+ that arm in original logprob block 0. Two of four concurrent pairs match
1613
+ across arms; aggregate timings do not establish identical-work performance.
1614
+ This prototype still makes serial requests flush durability before generation.
1615
+ The later removal of that flush must be measured in both arms before claiming
1616
+ that shared B=1 dominates the best serial implementation.
1617
+
1618
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1619
+ `borrowed-prefix-composition-0.md.json` and
1620
+ `borrowed-prefix-performance-review.json`.
1621
+
1622
+ ### Eventual SSD persistence — M4 Pro, acceptance open (2026-09-09)
1623
+
1624
+ The next frozen candidate retains immutable RAM prefixes and removes the
1625
+ serial request-time durability flush. It uses the same machine, toolchain,
1626
+ artifact, capture settings and block-0 workload as the prototype above.
1627
+ Preflight passes with the audio allowance, source hashes remain fixed and
1628
+ there are no failures. Serial / shared B=1 median decode request time is
1629
+ 17,768.44 / 17,787.02 ms, cached TTFT 163.57 / 168.03 ms and cached request
1630
+ time 703.55 / 706.67 ms. All 11 single-request pairs match, and every output
1631
+ within each arm matches original logprob block 0. Two of four concurrent
1632
+ pairs match across arms.
1633
+
1634
+ This removes the large cached-request regression in the earlier logprob
1635
+ comparisons. One ordered block does not establish that the remaining small
1636
+ difference is stable or that shared B=1 dominates serial. A subsequent change
1637
+ makes background writes acquire idle ownership without requesting a batch
1638
+ drain; its balanced serving comparisons are separate acceptance work.
1639
+
1640
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1641
+ `eventual-cache-composition-0.md.json` and
1642
+ `eventual-cache-performance-review.json`.
1643
+
1644
+ ### Idle persistence queue on Bun 1.4.2 — M4 Pro (2026-09-09)
1645
+
1646
+ Two ordered/reversed blocks measure immutable RAM reuse, removal of the
1647
+ request-time flush, and background writes that acquire the engine only when
1648
+ idle. Both use the packed Qwen artifact, bf16 KV, selected logprobs/top-3,
1649
+ SSD caching and the same block-0 requests. M4 Pro 24 GB, Bun 1.4.2, MLX
1650
+ 0.32.2; preflight passes under the audio allowance. The source hash is identical
1651
+ across both blocks and remains fixed; neither block has a failure.
1652
+
1653
+ | Order | Median decode request ms, serial / shared B=1 | Cached TTFT ms, serial / shared B=1 | Cached request ms, serial / shared B=1 |
1654
+ |---|---:|---:|---:|
1655
+ | Serial then batch | 17,772.00 / 17,750.51 | 163.13 / 167.44 | 703.25 / 706.08 |
1656
+ | Batch then serial | 17,746.81 / 17,757.96 | 162.87 / 167.51 | 701.86 / 706.03 |
1657
+
1658
+ All 22 single-request pairs match complete response identity. Every output
1659
+ within each arm also matches original logprob block 0. Four of eight concurrent
1660
+ pairs match across arms, so aggregate timing does not establish identical-work
1661
+ performance. Decode request time differs by less than 0.13%, while shared B=1
1662
+ retains a consistent 4.3–4.6 ms cached first-output gap. Strict dominance is
1663
+ still unproven. The later correction to the batch's reported first-token
1664
+ clock is not included; these numbers come from client-observed timings.
1665
+
1666
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1667
+ `idle-persistence-bun142-composition-{0,1}.md.json` and
1668
+ `idle-persistence-bun142-performance-review.json`.
1669
+
1670
+ ### First-admission device pipeline — M4 Pro (2026-09-09)
1671
+
1672
+ The first ordinary row now enters the existing pending GPU-token register,
1673
+ allowing the next forward to overlap its first readback. This also includes
1674
+ the corrected first-token metric timestamp. The frozen candidate was measured
1675
+ in both arm orders on M4 Pro 24 GB, Bun 1.4.2 and MLX 0.32.2, using the same
1676
+ packed artifact, bf16 KV, logprobs/top-3, SSD and block-0 requests as the
1677
+ idle-persistence comparison. Both preflights pass with the audio allowance,
1678
+ source stays fixed across both blocks and no phase fails.
1679
+
1680
+ | Arm order | Decode request median ms, serial / shared B=1 | Cached TTFT ms, serial / shared B=1 | Cached request ms, serial / shared B=1 |
1681
+ |---|---:|---:|---:|
1682
+ | Serial first | 17,759.74 / 17,745.59 | 163.25 / 163.38 | 703.29 / 701.71 |
1683
+ | Shared first | 17,754.03 / 17,746.97 | 162.61 / 163.53 | 701.91 / 702.64 |
1684
+
1685
+ All 22 single-request pairs match, and every output within each arm matches
1686
+ the idle-persistence baseline. Four of eight concurrent pairs match across
1687
+ arms; these do not support an identical-work aggregate speed claim. The
1688
+ change reduces the prior cached-TTFT gap to 0.12–0.91 ms and is adopted in
1689
+ the working tree. Shared B=1 does not strictly dominate every measured
1690
+ latency, and this composition does not close the full feature matrix.
1691
+
1692
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1693
+ `first-row-pipeline-composition-{0,1}.md.json` and corresponding
1694
+ `first-row-pipeline-composition-{0,1}-review.json`. Both blocks identify source
1695
+ `5cd1cb0668b743303cd6b05ba8779fd9075280d97585b008ac2da9d03f462c7f`.
1696
+
1697
+ ### Batched sliding-window correctness — M1 Max and M4 Pro (2026-09-09)
1698
+
1699
+ The shared executor passes the live, pinned same-B MLX-LM oracle on Gemma
1700
+ 12B and e4b on both M1 Max 32 GB and M4 Pro 24 GB, with Bun 1.4.2 and
1701
+ MLX 0.32.2. Each cell compares 48 complete float32 logit vectors exactly.
1702
+ Three unequal prompt lengths straddle the configured sliding window: two
1703
+ cross it during decode and one starts beyond it. The two arrival schedules
1704
+ include staggered retirement and a late join. This closes Phase 18's ordinary
1705
+ Gemma ring-wrap gate; it does not qualify quantized layouts or other methods.
1706
+
1707
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1708
+ `m1-gemma12b-batch-ring-wrap.log`,
1709
+ `m4-gemma12b-batch-ring-wrap-complete-inputs.log`,
1710
+ `m1-gemmae4b-batch-ring-wrap.log`, and
1711
+ `m4-gemmae4b-batch-ring-wrap.log`. The first M4 launch failed before model
1712
+ loading because its scratch checkout lacked test support files; the complete
1713
+ input rerun is the accepted result. No performance conclusion uses test time.
1714
+
1715
+ ### Compatible adapter groups — M4 Pro (2026-09-09)
1716
+
1717
+ Gemma e4b OptiQ snapshot `98d7dc6`, `fixtures/adapters/upper`, bf16 KV and
1718
+ SSD cache, on M4 Pro 24 GB with Bun 1.4.2 and MLX 0.32.2. The configured
1719
+ adapter and block-0 requests are identical across the serial and shared arms.
1720
+ Both arm orders pass preflight with the recorded audio allowance, retain a
1721
+ fixed source, and finish every phase.
1722
+
1723
+ | Arm order | Decode request median ms, serial / shared B=1 | Cached TTFT ms, serial / shared B=1 | Cached request ms, serial / shared B=1 | Observed four-request throughput tok/s, serial / shared |
1724
+ |---|---:|---:|---:|---:|
1725
+ | Serial first | 3,654.29 / 3,671.12 | 36.88 / 37.66 | 162.18 / 161.73 | 51.76 / 161.42 |
1726
+ | Shared first | 3,678.68 / 3,675.22 | 37.58 / 37.96 | 162.13 / 161.98 | 51.82 / 161.27 |
1727
+
1728
+ All 22 single-request output/usage pairs match. Six of eight concurrent
1729
+ pairs match across arms; every output is stable within its own arm across
1730
+ orders. The concurrent throughput figures therefore are observed workload
1731
+ results, not an identical-output speedup. Single-request decode changes winner
1732
+ with order; cached first output remains slightly slower on the shared path.
1733
+ Strict serial-dominance acceptance remains open.
1734
+
1735
+ Native adapter B=1 control, compatible B=2, mixed queues, callback failure,
1736
+ separate prefix reuse and queued adapter replacement pass on M1/M4. Both
1737
+ machines match 48 full logit vectors against the pinned same-B adapter oracle.
1738
+ KV4 plus logprobs also passes the native composition checks on both machines;
1739
+ this is not an external quantized-batch oracle claim.
1740
+
1741
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1742
+ `adapter-composition-{0,1}.md.json` and
1743
+ `adapter-composition-performance-review.json`. Frozen source:
1744
+ `e92487827cbb4755f5bd0cb4880999b2aa1d1aba64a86b7bfc6042b0b458723c`.
1745
+ Native logs: `m1-batch-adapters-replacement.log`,
1746
+ `m1-batch-adapter-oracle.log`, `m4-batch-adapters-oracle.log`, and
1747
+ `{m1,m4}-batch-adapters-kv4-logprobs.log`.
1748
+
1749
+
1750
+ ### State-only recurrent replay experiment — M4 Pro (2026-09-09)
1751
+
1752
+ Packed Qwen 27B with its folded RTN4 MTP companion, depth four and KV4,
1753
+ Bun 1.4.2 and MLX 0.32.2 on the M4 Pro 24 GB. Both versions use the same
1754
+ serial serving control and shared prefill cache. Only recurrent prefix replay
1755
+ changes. The existing serving suite ran reference/candidate, then
1756
+ candidate/reference, with matched requests within each block. Preflight passed
1757
+ under Josh's audio-daemon CPU allowance; raw reports retain `canonical:false`.
1758
+
1759
+ | Block/order | Five decode requests, reference → candidate | Sum of four queued request times, reference → candidate | Cached TTFT, reference → candidate |
1760
+ |---|---:|---:|---:|
1761
+ | 0, reference/candidate | 135,674.99 → 135,614.72 ms | 176,655.25 → 176,192.41 ms | 94.03 → 94.10 ms |
1762
+ | 1, candidate/reference | 130,083.45 → 129,893.97 ms | 189,279.10 → 189,066.15 ms | 93.98 → 93.78 ms |
1763
+
1764
+ All 30 recorded responses match in text, counts, cached coverage and finish
1765
+ reason; both completion/chat probes match and no phase failed. The five-request
1766
+ decode totals improve by only 0.044% and 0.146%. Warmup complete time regresses
1767
+ in both blocks, by 8.41% and 0.32%. This is **inconclusive for default promotion**.
1768
+ The independently required batched recurrence can use its row-length-aware
1769
+ kernel; uniform replay retains its existing kernel pending a demonstrated win.
1770
+
1771
+ Raw files: `reports/qwen38-closeout/composition-baseline/`
1772
+ `state-replay-{reference,candidate}-{0,1}.md.json` and
1773
+ `state-replay-performance-review.json`. Both sources stay fixed across blocks:
1774
+ reference `a01bee0b7e1962c8211f1ffd845d95f7923d6c04bddb18cf06f07483cab9e7e8`,
1775
+ candidate `9ea170f63a70b143a978fd2f8519c265a363760fcc5921ab7fe7c51f6ff2a173`.
1776
+ These reports measure the isolated replay experiment, not the subsequent
1777
+ attention-cache and draft-interface work.
1778
+
1779
+
1780
+ ### Shared MTP drafting candidate — M4 Pro (2026-09-09)
1781
+
1782
+ Packed Qwen 27B, folded RTN4 companion, MTP depth two, KV4, Bun 1.4.2 and
1783
+ MLX 0.32.2 on the M4 Pro 24 GB. The candidate replaces the request-local
1784
+ draft/commit loop with the shared row method at B=1. Both use the existing
1785
+ serving control and shared prefill cache. The official serving suite ran in
1786
+ both orders with 192-token decode requests. Preflight passed under Josh's
1787
+ audio-daemon CPU allowance; reports retain `canonical:false`.
1788
+
1789
+ | Block/order | Five decode requests, reference → candidate | Sum of four queued request times, reference → candidate |
1790
+ |---|---:|---:|
1791
+ | 0, reference/candidate | 53,764.24 → 53,884.42 ms | 80,319.89 → 81,191.39 ms |
1792
+ | 1, candidate/reference | 56,025.69 → 56,363.44 ms | 78,935.80 → 81,001.15 ms |
1793
+
1794
+ All 30 recorded request hashes, response hashes, token counts, cached coverage
1795
+ and finish reasons match, with no failures and unchanged source snapshots.
1796
+ Decode complete time regresses by 0.22% and 0.60%; summed queued-request time
1797
+ regresses by 1.09% and 2.62%. The four-request 1k-context phase also regresses,
1798
+ by 2.09% and 3.04%. This candidate has not established equal-or-better serving
1799
+ performance and is not adopted. Native before/after prefix continuations match
1800
+ on both Macs; those correctness results do not close the timing gate.
1801
+
1802
+ Raw: `reports/qwen38-closeout/composition-baseline/`
1803
+ `mtp-row-{reference,candidate}-{0,1}.md.json` and
1804
+ `mtp-shared-draft-performance-review.json`. Frozen source hashes:
1805
+ reference `a0f66ee4bbf357cdd7ace981e31c4f21d8e1705b7f052e5bd6ce0b8bccf68ab5`,
1806
+ candidate `dcaf122ce30b38e60847af6c0fd4df59232ccb2552ec7fb98019d231e1757b75`.
1807
+ Four queued requests here still execute one at a time; this is not B=4 MTP
1808
+ serving acceptance.
1809
+
1810
+ The subsequent candidate replaces the B=1 hidden gather with a slice of the
1811
+ same verification context. On the same machine/toolchain and settings, two
1812
+ new matched blocks preserve all 30 responses, counts, cached coverage and
1813
+ finish reasons, plus both parity probes, with no failures or source changes.
1814
+
1815
+ | Block/order | Five decode requests, reference → slice candidate | Sum of four queued request times, reference → slice candidate | Cached TTFT, reference → slice candidate |
1816
+ |---|---:|---:|---:|
1817
+ | 0, candidate/reference | 56,802.25 → 56,806.30 ms | 83,579.51 → 82,931.12 ms | 93.85 → 93.78 ms |
1818
+ | 1, reference/candidate | 55,672.47 → 56,315.67 ms | 80,785.87 → 82,545.85 ms | 93.54 → 94.80 ms |
1819
+
1820
+ The first block's decode time is essentially flat; the reverse-order block
1821
+ regresses by 1.16%. Queued-request gains also reverse, and the 1k-context phase
1822
+ changes by -0.57% then +2.34%. This does not close the performance gate. The
1823
+ source replacement and slice specialization remain isolated. Do not attribute
1824
+ the full variation to the gather or claim a speedup from the first block.
1825
+
1826
+ Raw: `mtp-slice-{reference,candidate}-{0,1}.md.json` and
1827
+ `mtp-slice-performance-review.json` in the same report directory. Reference
1828
+ hash is unchanged; slice candidate hash is
1829
+ `665acf5432f5cde64207a475edff0f999215f2fb9df014fce8db295e6cc20bd9`.
1830
+
1831
+ ### Concurrent MTP serving candidate — M4 Pro (2026-09-09)
1832
+
1833
+ Packed Qwen 27B, folded RTN4 companion, MTP depth two and KV4, Bun 1.4.2
1834
+ and MLX 0.32.2 on the M4 Pro 24 GB. The existing serving suite compares
1835
+ strict serial with shared execution in both arm orders. Each block uses
1836
+ matched requests and a fixed source, with 192-token decode requests and no
1837
+ long-context leg. Preflight passes under the recorded audio CPU allowance.
1838
+
1839
+ | Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
1840
+ |---|---:|---:|---:|
1841
+ | Serial first | 56,130.19 / 55,549.00 ms | 93.58 / 214.00 ms | 15.88 / 16.18 tok/s |
1842
+ | Shared first | 54,137.25 / 53,914.05 ms | 93.63 / 218.90 ms | 16.08 / 16.41 tok/s |
1843
+
1844
+ All 22 single-request output/usage pairs and both parity probes match, with
1845
+ no phase failures. Single-request decode totals improve by 1.04% and 0.41%,
1846
+ but cached first output regresses in both orders. This does not meet serial
1847
+ dominance and is not adopted. Seven of eight concurrent outputs differ across
1848
+ arms, so aggregate throughput is an observed result, not an identical-output
1849
+ speed ratio. The separate native/HTTP gate confirms real B=4 MTP verification.
1850
+
1851
+ The next revision exposes preparation output through the shared scheduling
1852
+ readiness interface. Scheduling yields after admission completes, before the
1853
+ next graph. The same two arm orders give:
1854
+
1855
+ | Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
1856
+ |---|---:|---:|---:|
1857
+ | Serial first | 56,583.61 / 55,563.91 ms | 93.64 / 98.28 ms | 15.52 / 16.21 tok/s |
1858
+ | Shared first | 54,175.23 / 53,514.51 ms | 93.48 / 99.70 ms | 16.09 / 16.19 tok/s |
1859
+
1860
+ All 22 single-request pairs match, with no phase failures. Decode totals
1861
+ improve by 1.80% and 1.22%. The remaining cached TTFT gap is 4.64 and 6.22 ms,
1862
+ so strict serial dominance remains open. Seven of eight concurrent outputs
1863
+ again differ, preventing an identical-output aggregate speed claim.
1864
+ Moving publication ahead of the remaining state admission gives these results:
1865
+
1866
+ | Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
1867
+ |---|---:|---:|---:|
1868
+ | Serial first | 56,139.21 / 55,564.02 ms | 93.64 / 97.75 ms | 15.76 / 16.24 tok/s |
1869
+ | Shared first | 54,122.55 / 54,352.40 ms | 93.60 / 100.76 ms | 16.09 / 15.89 tok/s |
1870
+
1871
+ All 22 single-request pairs still match, with no failures. Decode totals change
1872
+ by -1.02% and +0.42%; the cached first-output gap remains. Seven concurrent
1873
+ outputs differ. This revision also does not establish dominance. The next
1874
+ candidate removes allocator cache clearing from shared output delivery while
1875
+ preserving the methods' own maintenance. It also fixes cleanup after state
1876
+ admission. Its two arm orders produce:
1877
+
1878
+ | Arm order | Five decode requests, serial / shared | Cached TTFT, serial / shared | Observed four-request throughput, serial / shared |
1879
+ |---|---:|---:|---:|
1880
+ | Serial first | 56,857.65 / 55,535.73 ms | 94.48 / 99.33 ms | 15.50 / 16.24 tok/s |
1881
+ | Shared first | 54,107.37 / 53,587.76 ms | 93.70 / 98.99 ms | 16.09 / 16.16 tok/s |
1882
+
1883
+ All 22 single-request pairs and parity probes match, with no failures. Decode
1884
+ totals improve by 2.32% and 0.96%, but cached TTFT trails serial by 4.85 and
1885
+ 5.28 ms. Seven concurrent outputs differ. Allocator maintenance separation
1886
+ therefore does not resolve the latency gap or qualify serial removal.
1887
+
1888
+ Raw reports and reviews in
1889
+ `reports/qwen38-closeout/composition-baseline/`:
1890
+ `mtp-serving-serial-shared-0.md.json`, `mtp-serving-shared-serial-1.md.json`,
1891
+ `mtp-serving-performance-review.json`, `mtp-serving-output-yield-0.md.json`,
1892
+ `mtp-serving-output-yield-1.md.json` and
1893
+ `mtp-serving-output-yield-performance-review.json`, `mtp-serving-staged-0.md.json`,
1894
+ `mtp-serving-staged-1.md.json`, `mtp-serving-staged-performance-review.json`,
1895
+ `mtp-serving-method-maintenance-0.md.json`, `mtp-serving-method-maintenance-1.md.json`
1896
+ and `mtp-serving-method-maintenance-performance-review.json`.
1897
+ Initial frozen source:
1898
+ `4799c307be193a2cd53c91d95940c40e7294f41b13a07693ab4a45097be60d25`.
1899
+ First readiness revision:
1900
+ `e7d6955ea0ae8133b6445a5180fd68a784c8913072a13579f08392896cff8904`.
1901
+ Staged admission revision:
1902
+ `309d671bdcdd4830765d6af2341fe3b68a04c2eb9795929f9d6bcfb12f55e04d`.
1903
+ Method-owned maintenance revision:
1904
+ `311043d3a1add4bebffffc820a96f83dc415ad3ac6d6a17133e75540909ff273`.
1905
+
1906
+ The subsequent combined source includes the TurboQuant codec/row components.
1907
+ The first matched block keeps KV4/MTP2, so it measures overhead in the existing
1908
+ workload rather than TurboQuant serving. Compared directly with the previous
1909
+ method-maintenance block on the same M4:
1910
+
1911
+ | Metric | Previous shared | Combined shared |
1912
+ |---|---:|---:|
1913
+ | Five decode requests, complete time | 55,535.73 ms | 55,560.29 ms |
1914
+ | Median decode | 19.211 tok/s | 19.196 tok/s |
1915
+ | Cached TTFT | 99.33 ms | 99.55 ms |
1916
+ | Four concurrent requests | 16.238 tok/s | 16.241 tok/s |
1917
+
1918
+ All 15 shared request/output/usage pairs match, as do all 15 serial-control
1919
+ pairs. Shared decode time changes by +0.044%; this is effectively unchanged,
1920
+ not a demonstrated speed gain. The serial control changes by -0.94%. No phase
1921
+ fails and the combined source stays fixed. This is one arm-order block;
1922
+ the reverse-order repeat remains open. The first settings sweep follows.
1923
+ Raw report: `decode-composition-combined-0.md.json`; review:
1924
+ `decode-composition-previous-run-review.json`, in the same reports directory.
1925
+ Combined source:
1926
+ `2b7b258c983729be4dc723493ad6a14eea853c0166df9f2a36a4a3b27344f51c`.
1927
+
1928
+ The first settings sweep uses that same frozen source, the same block-0
1929
+ requests and the shared server. Each row includes five 192-token decode
1930
+ requests, short cold/cached prompts and four concurrent requests. Long-context
1931
+ and restart benchmark legs are excluded. Every report has zero failed phases
1932
+ and a stable source snapshot; the audio CPU allowance remains recorded.
1933
+
1934
+ | KV / draft depth | Five decode requests | Median decode | Cached TTFT | Four concurrent requests |
1935
+ |---|---:|---:|---:|---:|
1936
+ | Affine 4 / MTP2 | 55.560 s | 19.196 tok/s | 99.55 ms | 16.241 tok/s |
1937
+ | Affine 8 / MTP2 | 55.067 s | 19.442 tok/s | 98.96 ms | 16.329 tok/s |
1938
+ | Affine 4 / MTP4 | 136.714 s | 7.493 tok/s | 97.23 ms | 14.522 tok/s |
1939
+ | Affine 8 / MTP4 | 131.855 s | 7.683 tok/s | 97.48 ms | 15.170 tok/s |
1940
+
1941
+ MTP2 leads this first sweep. Changing precision or draft depth can change the
1942
+ continuation; these are observed configuration rates, not identical-output
1943
+ engine speedup ratios. The small KV8/MTP2 lead needs repetition. The expanded
1944
+ screen below adds async weight expansion, no-MTP controls and TurboQuant
1945
+ serving. No default changes are justified by this single block. Raw settings reports are
1946
+ `decode-settings-{kv8-mtp2,kv4-mtp4,kv8-mtp4}-0.md.json`; the summary is
1947
+ `decode-settings-first-sweep-review.json` in the same reports directory.
1948
+
1949
+ ### Integrated settings screen and context repeat — M4 Pro (2026-09-09)
1950
+
1951
+ The isolated shared-serving candidate now includes TurboQuant ordinary/MTP
1952
+ groups. All 20 reports below use stable source
1953
+ `6e293a0efeb2f22e2557bf0e39373774545dc0737496c07e7bbe8cfbf6cd3939`,
1954
+ the same packed Qwen artifact and folded RTN4 companion, Bun 1.4.2,
1955
+ MLX 0.32.2 and the M4 Pro 24 GB. Preflight passes with Josh's audio-CPU
1956
+ allowance. The server's batch capacity is eight; the aggregate leg submits
1957
+ four requests. Separate native serving gates establish actual four-row MTP
1958
+ verification. These reports retain `canonical:false`.
1959
+
1960
+ Short-context block 0 uses matching requests and five 192-token decode
1961
+ samples. Fused TurboQuant decode is enabled; async Trellis expansion is off
1962
+ unless labeled. No report has a failed phase.
1963
+
1964
+ | KV / method | Five requests, complete ms | Median decode tok/s | Cached TTFT ms | Aggregate ×4 tok/s |
1965
+ |---|---:|---:|---:|---:|
1966
+ | bf16 / ordinary | 88,763.10 | 11.593 | 163.76 | 25.776 |
1967
+ | bf16 / MTP2 | 54,064.81 | 19.793 | 96.49 | 16.822 |
1968
+ | bf16 / MTP3 | 53,904.19 | 20.089 | 98.79 | 16.952 |
1969
+ | Affine 4 / ordinary | 89,551.02 | 11.521 | 164.78 | 25.689 |
1970
+ | Affine 4 / MTP1 | 61,737.80 | 17.170 | 96.91 | 15.695 |
1971
+ | Affine 4 / MTP2 | 55,544.22 | 19.200 | 99.49 | 16.247 |
1972
+ | Affine 4 / MTP3 | 61,344.01 | 17.198 | 98.07 | 16.208 |
1973
+ | Affine 4 / MTP2, async | 55,282.33 | 19.167 | 99.02 | 16.243 |
1974
+ | Affine 4 / MTP4, async | 136,386.37 | 7.487 | 97.26 | 14.559 |
1975
+ | Affine 8 / ordinary | 88,955.50 | 11.571 | 167.18 | 25.679 |
1976
+ | Affine 8 / MTP1 | 62,207.00 | 17.003 | 97.45 | 15.510 |
1977
+ | Affine 8 / MTP3 | 56,289.15 | 18.991 | 99.90 | 16.664 |
1978
+ | TQ K8V3 / ordinary | 90,881.00 | 11.403 | 174.53 | 25.308 |
1979
+ | TQ K8V3 / MTP2 | 56,578.08 | 19.242 | 102.53 | 16.429 |
1980
+ | TQ K8V3 / MTP3 | 56,923.87 | 19.065 | 102.78 | 16.046 |
1981
+ | TQ K8V3 / MTP4 | 131,849.48 | 7.593 | 101.34 | 14.481 |
1982
+
1983
+ The affine-4/MTP2 integration control preserves all 15 request/output pairs
1984
+ against the preceding `2b7b…` source; complete decode time changes by -0.029%,
1985
+ effectively unchanged. Its async arm also preserves all 15 outputs, with
1986
+ complete time -0.47% in this one block. Async expansion does not remove the
1987
+ MTP4 decode cliff. MTP3 uses its third proposal: affine-4 accepts 109 of 386
1988
+ third-position drafts, affine-8 accepts 114 of 373. Acceptance alone does not
1989
+ make the extra work profitable.
1990
+
1991
+ The four leading comparison profiles then run full `bench-serve all` with
1992
+ block-1 inputs and `--context 16384`. The rendered prompt actually contains
1993
+ **10,398 tokens**. Each context leg has a cold request and two RAM-cached
1994
+ repeats, followed by an explicit durable flush and SSD restart.
1995
+
1996
+ | KV / method | Five short requests, complete ms | Short decode tok/s | Context decode tok/s | Cold context TTFT ms | SSD restart TTFT ms |
1997
+ |---|---:|---:|---:|---:|---:|
1998
+ | bf16 / MTP3 | 56,107.03 | 19.179 | 23.130 | 80,060.42 | 2,026.44 |
1999
+ | TQ K8V3 / MTP3 | 58,195.34 | 18.350 | 19.580 | 79,777.84 | 1,936.05 |
2000
+ | Affine 4 / MTP2 | 53,548.41 | 20.133 | 22.184 | 79,860.36 | 1,919.74 |
2001
+ | Affine 4 / MTP3 | 56,923.65 | 18.999 | 22.826 | 79,912.94 | 1,930.17 |
2002
+
2003
+ Within each profile the three context responses match exactly. Every restart
2004
+ restores 10,397 cached tokens, with zero pending, dropped or failed spills
2005
+ after flush. Across settings, continuations can differ; these rates do not
2006
+ establish an identical-output engine speedup. MTP2 leads affine-4 short
2007
+ requests, while MTP3 has a small context-decode lead. Ordinary batching has
2008
+ the strongest aggregate throughput in the short screen. The choice of one
2009
+ default for typical single-user multi-turn/tool use remains open pending
2010
+ late-task context measurements and balanced repeats; user overrides remain.
2011
+
2012
+ Raw files in `reports/qwen38-closeout/composition-baseline/`:
2013
+ `decode-integrated-*-0.md.json`, `decode-default-*-context-1.md.json` and
2014
+ `decode-integrated-settings-review.json`. Source archives remain frozen on
2015
+ the M4; no candidate default has been promoted.
2016
+
2017
+ The subsequent late-context control uses the same frozen source and
2018
+ `--context 125000`. KV4/MTP2 fails the context phase, including its retry,
2019
+ with Metal command-buffer out-of-memory at the default 2,048-token prefill
2020
+ chunk. It supplies no context decode or restart result. Preflight passed
2021
+ with 96 MB retained swap and 93% free memory; swap remained 96 MB afterward.
2022
+ Raw: `decode-default-kv4-mtp2-late-context-0.md.json` in the same directory.
2023
+ The next depth-3 attempt was stopped before the context leg to avoid repeating
2024
+ the same oversized configuration. A separate depth-2/3/1 comparison uses
2025
+ `MLX_BUN_RD_PREFILL_CHUNK=256`, matching the published Kanban prefill profile;
2026
+ depth 2 now completes at **78,678 actual prompt tokens**. Cold first-output time
2027
+ is 884.14 seconds, context decode median is 12.828 tok/s, cached repeat
2028
+ first-output time is 237.45 ms and fresh-process SSD restart first-output time
2029
+ is 2,229.68 ms with 78,677 cached tokens. All three context outputs match;
2030
+ the eight-token restart output matches their beginning. Flush is durable with
2031
+ zero pending, dropped or failed writes, and the source hash remains unchanged.
2032
+ Depth 3 also completes on unchanged source. Its cold first-output time is
2033
+ 884.68 seconds, context decode median 11.718 tok/s, cached first-output time
2034
+ 187.75 ms and SSD restart first-output time 2,235.34 ms with 78,677 tokens
2035
+ restored. Its three context outputs match each other, but differ from depth 2;
2036
+ these are settings comparisons, not identical-output engine comparisons.
2037
+ Durability also passes with no pending, dropped or failed writes. Depth 1
2038
+ completes at 10.582 tok/s context decode, with 884.59 seconds cold first-output
2039
+ time, 189.69 ms cached first-output time and 2,243.35 ms after SSD restart.
2040
+ It restores 78,677 tokens; all three context outputs match depth 2. Source
2041
+ hashes are stable, both preflights pass and there are no phase failures or
2042
+ pending, dropped or failed writes. These single profiles do not select a
2043
+ default. Raw: `decode-default-kv4-mtp{1,2,3}-late-context-chunk256-0.md.json`.
2044
+ Ordinary shared prefill in the frozen benchmark source does not read that
2045
+ control. The adopted policy fix makes ordinary and speculative prefill use the group's
2046
+ captured default and preserves the library request override. Its M1 seeded
2047
+ native and MTP RAM/SSD gates, complete model-free suite and typecheck pass; a matched M4
2048
+ ordinary late-context arm remains open.
2049
+
2050
+ The composed ownership/prefill-policy short control is complete on the M4
2051
+ Pro, with source `04f518534d568d10cd570e3ecd671a69ccbe97513f803d3a29ac250269416a0d`.
2052
+ It uses the same block-0 requests, KV4/MTP2, default prefill chunk and runtime
2053
+ settings as the frozen `6e293a0...` arm. All 14 measured request hashes,
2054
+ response texts, generated counts and cached counts match. Five decode requests
2055
+ take 55,619.41 ms versus 55,544.22 ms, a 0.14% increase; median decode is
2056
+ 19.195 versus 19.200 tok/s. Cached first-output time is 97.56 versus 99.49 ms,
2057
+ and four-request aggregate throughput is 16.203 versus 16.247 tok/s. This
2058
+ single comparison is effectively unchanged, with no performance win claimed.
2059
+ There are no phase failures and source hashes remain stable. The arm includes
2060
+ the Gemma ownership fix and captured prefill policy, but not generated-output
2061
+ publication. Raw: `composition-baseline/decode-prefill-policy-kv4-mtp2-short-0.md.json`
2062
+ under `reports/qwen38-closeout/`.
2063
+
2064
+ The same composed source also completes the 78,678-token KV4/MTP2 context
2065
+ control with 256-token chunks. All 19 request hashes, response texts,
2066
+ generated counts and cached counts match the frozen arm. Cold first-output
2067
+ time is 884.12 versus 884.14 seconds; context decode median is 12.918 versus
2068
+ 12.828 tok/s. Cached first-output time is 188.35 versus 237.45 ms and restart
2069
+ time is 2,230.56 versus 2,229.68 ms, with 78,677 tokens restored. Durability
2070
+ has no pending, dropped or failed writes; source hashes and both preflights
2071
+ pass. This single comparison does not establish a latency or throughput win.
2072
+ Raw: `composition-baseline/decode-prefill-policy-kv4-mtp2-late-context-chunk256-0.md.json`.
2073
+ The wrapper failed before launching the ordinary arm because macOS Bash 3
2074
+ rejects its empty-array expansion under `set -u`. That arm was resumed alone;
2075
+ the completed MTP report was preserved.
2076
+
2077
+
2078
+ The subsequent ordinary KV4 late-context arm on the same M4 Pro source did
2079
+ **not** pass clean acceptance. Its first 78,678-token cold request completed
2080
+ with 881,941 ms to first output, but the cached repeat failed with Metal
2081
+ `kIOGPUCommandBufferCallbackErrorOutOfMemory`. The benchmark's built-in retry
2082
+ restarted the phase with a different request hash and 78,677 prompt tokens.
2083
+ That retry completed at 7.319 tok/s median context decode, 292.54 ms cached
2084
+ first output and 2,262.76 ms after SSD restart, reusing 78,676 tokens. These
2085
+ are recovery diagnostics, not a matched successful ordinary/MTP comparison.
2086
+ Both machine checks passed and source stayed fixed; final swap was 294.69 MB.
2087
+ The final flush retained 17 entries with no pending, dropped or failed spills.
2088
+ The initial failure and both attempts remain in
2089
+ `reports/qwen38-closeout/composition-baseline/decode-prefill-policy-kv4-plain-late-context-chunk256-0.md.json`.
2090
+ The cached-repeat allocation failure needs investigation before repeating
2091
+ ordinary late-context acceptance. Independent output-cache/prefill correctness
2092
+ resumed without rerunning or reclassifying this failed benchmark.
2093
+
2094
+
2095
+ The final generated-output/prefill composition also passes M4 native and
2096
+ HTTP bf16/KV4/fused-TQ cache continuation, parser/template replay, full-suite
2097
+ and typecheck gates. Its short KV4/MTP2 block-0 benchmark uses source
2098
+ `af91e6a64649df5af9eb73e4a35739109f6799a5c8ba7ddc47c3543876cb19c0`.
2099
+ All 14 measured requests plus warmup match the prefill-policy control's
2100
+ request hashes, response text, prompt/generated counts and cached counts.
2101
+ Five decode requests take 55,636.28 versus 55,619.41 ms, a 0.03% increase;
2102
+ median decode is 19.171 versus 19.195 tok/s. Cached first output is 99.06
2103
+ versus 97.56 ms, and aggregate throughput is 15.859 versus 16.203 tok/s.
2104
+ Source and preflights are stable with no failures. This is one matched
2105
+ composition check with flat decode; it establishes no overall speed win or
2106
+ strict serial-domination result. Long Kanban and pressure acceptance remain.
2107
+ Raw: `composition-baseline/decode-output-prefill-kv4-mtp2-short-0.md.json`.
2108
+
2109
+
2110
+ The isolated variable-proposal verifier passes M4 uniform/variable bf16/KV4
2111
+ native controls, the full suite and typecheck. Its first short KV4/MTP2
2112
+ block-0 comparison is slower: five decode requests take 58,907.66 versus
2113
+ 55,636.28 ms, a 5.88% increase; median decode is 17.936 versus 19.171 tok/s.
2114
+ Cached first output is 97.51 versus 99.06 ms and aggregate throughput is
2115
+ 15.911 versus 15.859 tok/s. All measured requests plus warmup preserve
2116
+ request hashes, responses, prompt/generated/cache counts and speculation
2117
+ statistics. Source `885f542f07ea48e119a6bdaf533b4e2605ff293c3d7eb373ac202410032e24dd`
2118
+ and both preflights are stable, with no failures. This single ordered
2119
+ comparison does not distinguish a code regression from machine drift.
2120
+ Alternating frozen control/candidate repeats below test whether that slowdown
2121
+ follows the source.
2122
+ Raw: `composition-baseline/decode-variable-proposals-kv4-mtp2-short-0.md.json`.
2123
+
2124
+ The subsequent M4 Pro 24 GB A/B/B/A repeats use the same two frozen sources,
2125
+ KV4, MTP2, 192-token limit, block-0 workload and runtime environment. All 15
2126
+ requests per arm, including warmup, match request/output hashes, token counts,
2127
+ finish reasons and complete usage/speculation records. Both preflights pass
2128
+ and each source remains unchanged, with no request or phase failures.
2129
+
2130
+ | Arm | Five decode requests, total ms | Median decode tok/s | Cached first output ms | Aggregate tok/s |
2131
+ |---|---:|---:|---:|---:|
2132
+ | Control 1 | 55,559.96 | 19.154 | 98.90 | 15.853 |
2133
+ | Candidate 1 | 55,618.37 | 19.152 | 97.29 | 15.674 |
2134
+ | Candidate 2 | 55,566.01 | 19.189 | 97.23 | 15.880 |
2135
+ | Control 2 | 55,604.33 | 19.166 | 99.06 | 15.917 |
2136
+
2137
+ Combined candidate decode wall time is **0.018% higher**. The initial 5.88%
2138
+ slowdown does not reproduce; this screen supports preserving fixed-MTP decode
2139
+ performance while adding variable proposals. Aggregate throughput varies and
2140
+ establishes no gain. This does not qualify actual prompt-lookup performance,
2141
+ long contexts or serial deletion. The verifier patch is adopted in the working
2142
+ tree after the both-machine correctness gates; the main suite and typecheck pass.
2143
+ Raw reports and derived identity/timing comparison:
2144
+ `composition-baseline/variable-proposals/decode-variable-alternating-*.md.json`
2145
+ and `composition-baseline/variable-proposals/alternating-comparison.json`.
2146
+
2147
+ The prompt-lookup integration's fixed-MTP regression screen uses the same M4
2148
+ Pro 24 GB, KV4/MTP2, block-0 requests and runtime settings. Frozen source
2149
+ `3df52152aac2289b9ed860c2789141acb5e8d6ce7a6170899f34bd9ef1ac9a39`
2150
+ retains all 15 request/output hashes and complete usage/speculation records
2151
+ against variable-verifier candidate2 above. Five decode requests take
2152
+ 55,620.03 versus 55,566.01 ms, a 0.097% increase; median decode is 19.176
2153
+ versus 19.189 tok/s, cached first output 97.56 versus 97.23 ms, and aggregate
2154
+ throughput 15.778 versus 15.880 tok/s. Source/preflights are stable with no
2155
+ request or phase failures. This one short screen establishes no speedup;
2156
+ actual prompt-lookup serial/shared comparisons remain separate.
2157
+ Raw and comparison: `composition-baseline/ngram-group/decode-ngram-group-kv4-mtp2-short-0.md.json`
2158
+ and `composition-baseline/ngram-group/fixed-mtp-comparison.json`.
2159
+
2160
+ The subsequent delayed-TQ/method composition passes M4 fused/unfused native,
2161
+ SSD, complete-suite, typecheck and hygiene checks. Its short fixed-KV4/MTP2
2162
+ screen, source `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`,
2163
+ preserves all 15 request/output hashes and complete usage/speculation records
2164
+ against the frozen lookup base. Five decode requests take 55,812.61 versus
2165
+ 55,620.03 ms, a 0.35% increase. Median decode is 19.123 versus 19.176 tok/s,
2166
+ cached first output 98.72 versus 97.56 ms, and aggregate throughput 15.724
2167
+ versus 15.778 tok/s. Source/preflights pass with no failures. This single
2168
+ short composition screen establishes no gain and does not measure delayed
2169
+ TurboQuant performance, since the workload uses KV4.
2170
+ Raw: `composition-baseline/method-composed/decode-tq-method-composed-kv4-mtp2-short-0.md.json`
2171
+ and `composition-baseline/method-composed/fixed-mtp-comparison.json`.
2172
+
2173
+ Two M4 Pro 24 GB prompt-lookup comparisons use KV4, draft depth 3,
2174
+ 192-token decode requests, and reversed arm order on two workload seeds.
2175
+ Source is the same frozen lookup candidate above; both preflights and source
2176
+ checks pass with no request or phase failures. All single-request response
2177
+ pairs match, including their generated counts and finish reasons.
2178
+
2179
+ | Arm order | Five decode requests, serial / shared ms | Cached first output, serial / shared ms | Observed aggregate tok/s, serial / shared |
2180
+ |---|---:|---:|---:|
2181
+ | Serial first | 92,140.46 / 91,472.96 | 5,843.26 / 126.77 | 10.213 / 9.430 |
2182
+ | Shared first | 89,953.79 / 89,279.30 | 5,863.21 / 126.66 | 10.798 / 9.608 |
2183
+
2184
+ Single-request decode totals improve by 0.72% and 0.75%. Shared prompt lookup
2185
+ restores 758 and 757 tokens on the cached repetitions; serial restores zero.
2186
+ That is an actual new cache benefit, with different prefill work. All eight
2187
+ concurrent output pairs differ, and observed shared throughput is lower in
2188
+ both orders. An identical-output aggregate comparison and shared-execution
2189
+ dominance remain unproven. Wider verification cost and acceptance need further
2190
+ measurement; the result does not qualify deleting serial. Default-depth-10
2191
+ KV4 serving correctness subsequently passes 219 assertions on each Mac, with
2192
+ all ten proposal positions exercised; this is not depth-10 timing acceptance.
2193
+ Raw: `composition-baseline/ngram-group/decode-ngram-group-kv4-serial-shared-{0,1}.md.json`
2194
+ and `composition-baseline/ngram-group/lookup-paired-comparison.json`.
2195
+
2196
+ A separate M1 Max first-output diagnostic uses a 758-token prompt, KV4/MTP2
2197
+ and eight generated tokens through direct serial/shared execution. All eight
2198
+ outputs match and warm requests restore 757 tokens. Draft seeding accounts
2199
+ for roughly 93 ms on the warm traces; cache lookup is about 0.3–0.6 ms.
2200
+ Instrumenting the native allocator cleanup then identifies 0–6.8 ms inside
2201
+ `clearCache()` after the one-token target forward, on both execution paths.
2202
+ The shared path does not consistently trail serial in this loaded diagnostic;
2203
+ it does not explain the M4 gap by itself. A bounded candidate will skip this
2204
+ cleanup for one-token prefill work while retaining larger-chunk cleanup, with
2205
+ numerical, allocation and M4 request-time checks before adoption. Raw traces:
2206
+ `composition-baseline/mtp-first-output-diagnostic-m1.jsonl` and
2207
+ `composition-baseline/mtp-clear-diagnostic-m1.jsonl`.
2208
+
2209
+ The one-token maintenance candidate also completes a separate-process M1 Max
2210
+ allocation comparison at 8,195 prompt tokens, MTP2/KV4, chunk256, eight output
2211
+ tokens and a 4 GiB RAM cache without SSD. All three paired outputs, cache counts
2212
+ and speculation records match. Both warm repeats restore 8,194 tokens.
2213
+ Warm peak live allocation above the starting live state is 544.717 MiB for
2214
+ control and 544.732 MiB for candidate, a 16,208-byte increase. Final live
2215
+ allocation is effectively unchanged; the candidate's final allocator pool is
2216
+ 845.54 versus 709.29 MiB, so it retains about 136 MiB more unused capacity in
2217
+ this run. This loaded M1 diagnostic establishes no speedup and does not replace
2218
+ M4 long-context/SSD pressure coverage. Raw and derived records:
2219
+ `composition-baseline/single-token-maintenance/m1-allocation-{control,candidate}.jsonl`
2220
+ and `composition-baseline/single-token-maintenance/m1-allocation-comparison.json`.
2221
+
2222
+ Four alternating M4 Pro 24 GB fixed-MTP2/KV4 short runs compare the one-token
2223
+ maintenance candidate against the composed source above. Bun is 1.4.2,
2224
+ MLX is 0.32.2, fused TQ decode is enabled and asynchronous Trellis expansion
2225
+ is disabled. Both arms use seed `mtp-serving-block-0`, 192 output tokens,
2226
+ a 4 GiB prompt cache and the same packed target/RTN4 companion. Control source
2227
+ is `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`;
2228
+ candidate is `c12b60c1c7f39bf4ccdeaa7cdd16795a04d6ca2246eeb7609ec97cb9eee65315`.
2229
+ All four source snapshots and preflights pass under the recorded audio-CPU
2230
+ allowance. All 60 requests preserve request hashes, output text, complete
2231
+ usage/acceptance records and finish reasons, with no failures.
2232
+
2233
+ | Order | Five decode requests, total ms | Cached first output, ms | Median decode, tok/s | Aggregate tok/s |
2234
+ |---|---:|---:|---:|---:|
2235
+ | Control 1 | 56,424.69 | 98.097 | 18.722 | 15.591 |
2236
+ | Candidate 1 | 55,595.29 | 96.483 | 19.198 | 15.799 |
2237
+ | Candidate 2 | 55,588.63 | 96.517 | 19.171 | 15.916 |
2238
+ | Control 2 | 55,581.64 | 98.214 | 19.174 | 15.959 |
2239
+
2240
+ Cached latency averages 98.156 versus 96.500 ms, a 1.69% reduction. The
2241
+ first control also has slower cold prefill and decode; both candidate decode
2242
+ totals are effectively flat against the second control. This screen supports
2243
+ the narrow cached-latency improvement, not a general throughput gain or
2244
+ serial/shared dominance. The candidate remains isolated pending the direct
2245
+ serial/shared comparison and pressure review. Raw and derived records:
2246
+ `composition-baseline/single-token-maintenance/decode-single-token-maintenance-{control1,candidate1,candidate2,control2}.md.json`
2247
+ and `composition-baseline/single-token-maintenance/alternating-comparison.json`.
2248
+
2249
+ The direct M4 Pro serial/shared follow-up uses that same candidate source,
2250
+ MTP2/KV4 and two seeds with reversed arm order. All 22 single-request pairs
2251
+ preserve output, usage except the lane label, and cache coverage; all request
2252
+ hashes and generated budgets match. Source/preflights pass with no failures.
2253
+
2254
+ | Arm order | Five decode requests, serial / shared ms | Cached first output, serial / shared ms | Observed aggregate tok/s, serial / shared |
2255
+ |---|---:|---:|---:|
2256
+ | Serial first | 56,220.90 / 55,568.01 | 93.761 / 96.858 | 15.734 / 16.003 |
2257
+ | Shared first | 54,119.93 / 54,093.31 | 93.782 / 95.060 | 16.111 / 15.925 |
2258
+
2259
+ The allocator change does not remove the B1 cached-latency regression. Seven
2260
+ of eight concurrent output pairs differ, and observed aggregate throughput
2261
+ moves in opposite directions across the two orders. These results do not
2262
+ qualify shared dominance or serial deletion. The cleanup candidate remains
2263
+ isolated; its narrow improvement against the prior shared implementation is
2264
+ recorded separately above. Raw and derived records:
2265
+ `composition-baseline/single-token-maintenance/decode-maintenance-serial-shared-{0,1}.md.json`
2266
+ and `composition-baseline/single-token-maintenance/serial-shared-comparison.json`.
2267
+
2268
+ Four alternating M4 Pro 24 GB prompt-lookup runs compare wider packed
2269
+ down-projection eligibility against the unchanged operation. Settings are
2270
+ KV4, lookup depth3, 192 output tokens, seed `ngram-serving-block-0`, Bun 1.4.2
2271
+ and MLX 0.32.2. Control source is
2272
+ `88da0dca100cdb012cbd4330638cc43b727dbb853a5b1ef6aded60bc6fe1eb0d`;
2273
+ candidate is `c399a3e7fa4d8e61d720476a53a3abb5055944dccfd32684a99157373a288343`.
2274
+ All 60 requests preserve request hashes, response text, complete usage and
2275
+ finish reasons. Source/preflights pass under the audio-CPU allowance, with no
2276
+ failures. Both-machine projection and full-model B1/B2/B4/B8 state checks pass,
2277
+ including every new projection width and the artifact's three bit widths.
2278
+
2279
+ | Order | Five decode requests, total ms | Cached first output, ms | Aggregate tok/s |
2280
+ |---|---:|---:|---:|
2281
+ | Control 1 | 91,973.51 | 126.671 | 9.456 |
2282
+ | Candidate 1 | 92,261.32 | 129.677 | 9.305 |
2283
+ | Candidate 2 | 91,413.34 | 126.650 | 9.324 |
2284
+ | Control 2 | 91,750.52 | 126.872 | 9.473 |
2285
+
2286
+ Combined single-request time is effectively unchanged, decreasing 0.027%,
2287
+ while aggregate throughput decreases 1.58%. Both candidate aggregate results
2288
+ trail both controls. The wider eligibility is not adopted: exact arithmetic
2289
+ and avoiding dense weight expansion do not establish a serving benefit.
2290
+ Any further kernel tuning needs workload dispatch/cost attribution first.
2291
+ Raw and comparison:
2292
+ `composition-baseline/trellis-batch-width/decode-trellis-width-ngram-{control1,candidate1,candidate2,control2}.md.json`
2293
+ and `composition-baseline/trellis-batch-width/alternating-comparison.json`.
2294
+
2295
+ A bounded M1 Max allocation diagnostic follows the ordinary M4 cached-repeat
2296
+ OOM. At 8,195 prompt tokens, KV4, 12 generated tokens and a 4 GiB RAM cache
2297
+ without SSD, normal pipelining, early first output and disabled pipelining
2298
+ all retain two entries and add the same 375.28 MiB peak allocator demand
2299
+ above the pre-request live allocation on warm repeats. All nine outputs
2300
+ match. This loaded-machine native probe is not a speed benchmark, does not
2301
+ reproduce the 78k failure, and supplies no evidence that pipeline overlap is
2302
+ its allocation cause. Large-context retention and concurrent SSD persistence
2303
+ remain untested by this probe.
2304
+ Raw: `composition-baseline/ordinary-cached-allocation-m1.jsonl`.
2305
+
2306
+ ### Current MTP depth two versus four — M4 Pro (2026-09-09)
2307
+
2308
+ Same packed artifact, RTN4 companion, KV4, Bun 1.4.2, MLX 0.32.2 and frozen
2309
+ reference source as the replay experiment above. The source hash is
2310
+ `a01bee0b7e1962c8211f1ffd845d95f7923d6c04bddb18cf06f07483cab9e7e8`.
2311
+ Only the draft depth changes. Each block uses matching request hashes and
2312
+ 192 output tokens. Both depth-four blocks precede both depth-two blocks, so
2313
+ this depth comparison is not balanced in execution order. Preflight passes
2314
+ with the recorded audio-CPU allowance; reports retain `canonical:false`.
2315
+
2316
+ | Block | Depth two median decode | Depth four median decode | Five-request complete time, depth two / four | Matching responses |
2317
+ |---|---:|---:|---:|---:|
2318
+ | 0 | 19.33 tok/s | 7.36 tok/s | 56,275.71 / 135,674.99 ms | 6 / 15 |
2319
+ | 1 | 18.31 tok/s | 7.60 tok/s | 57,859.37 / 130,083.45 ms | 6 / 15 |
2320
+
2321
+ Counts, cached coverage and finish reasons match for every request. All five
2322
+ decode and four queued-concurrency responses differ in each block; no phase
2323
+ fails. These are observed results from different continuations, not an
2324
+ identical-output speed ratio or a depth-four acceptance. Depth two remains the
2325
+ current choice. A depth-four verify processes five tokens including the pending
2326
+ token, crossing the existing four-row packed-kernel boundary. R7 already records
2327
+ that boundary's cost and arithmetic difference; the current runs do not isolate
2328
+ its contribution from the changed continuation/acceptance trajectory.
2329
+
2330
+ Raw: `reports/qwen38-closeout/composition-baseline/mtp-depth2-{0,1}.md.json`,
2331
+ `state-replay-reference-{0,1}.md.json` and `mtp-depth-performance-review.json`.
2332
+ All requests here use the one-active-request control; four queued requests do
2333
+ not establish actual batched MTP. Compare fixed-input verification at both
2334
+ window sizes before changing the dispatch policy or promoting depth four.
2335
+
2336
+ ### Current standard serve matrix — M1 Max 32 GB (2026-08-22)
2337
+
2338
+ Real-server HTTP matrix on commit `4103ae1`, with the canonical preflight
2339
+ passing at the start of both runs: zero swap, ample free memory, and no large
2340
+ foreign process. The Qwen extension ended with 944 MiB of inactive swap,
2341
+ below the harness's 3 GiB mid-run rejection threshold. No benchmark phase
2342
+ failed. Raw gitignored reports:
2343
+ `benchmarks-serve-2026-08-22-Joshs-MacBook-Pro-2.md` and
2344
+ `benchmarks-serve-2026-08-22-Joshs-MacBook-Pro-2-qwen27b.md`.
2345
+
2346
+ | model | arm | short decode tok/s | decode @ ~15.8k tok/s | aggregate ×4 tok/s | restart TTFT ms (cached tokens) |
2347
+ |---|---|---:|---:|---:|---:|
2348
+ | MiniCPM5-1B | mlx-bun | **267.7** | 122.0 | **420.1** | 207 (15,817) |
2349
+ | | mlx-bun serial | 266.4 | 124.6 | 245.9 | 182 (15,889) |
2350
+ | | mlx-lm | 179.7 | 96.2 | 181.4 | 10,355 (0) |
2351
+ | | mlx-bun mixed | 194.2 | **127.0** | 397.5 | **130 (15,815)** |
2352
+ | gemma-4-e4b | mlx-bun | **61.5** | 43.7 | 20.7 | 18,863 (4) |
2353
+ | | mlx-bun serial | **61.5** | 43.1 | 59.7 | **661 (15,940)** |
2354
+ | | mlx-lm | 52.8 | 42.8 | 72.3 | 20,187 (0) |
2355
+ | | mlx-bun mixed | 57.3 | **49.0** | **97.4** | 20,510 (0) |
2356
+ | gemma-4-12B | mlx-bun | **29.6** | 28.3 | 5.6 | 85,180 (4) |
2357
+ | | mlx-bun serial | **29.6** | **28.4** | 27.5 | **1,338 (15,866)** |
2358
+ | | mlx-lm | 27.1 | 25.8 | 32.5 | 89,504 (0) |
2359
+ | | mlx-bun mixed | 28.7 | 24.4 | **38.7** | 93,068 (6) |
2360
+ | Qwen3.8-27B winner | mlx-bun | **18.5** | 16.5 | 19.3 | 173,215 (0) |
2361
+ | | mlx-bun serial | **18.5** | **16.7** | 15.8 | 172,400 (0) |
2362
+ | | mlx-lm | 16.5 | 14.9 | 18.3 | 177,066 (0) |
2363
+ | | mlx-bun mixed | 18.1 | 14.9 | **19.4** | **3,328 (15,112)** |
2364
+
2365
+ - All four models passed 64-token greedy completion and chat parity for
2366
+ mlx-bun bf16 versus mlx-lm, and unified scheduling versus `--batch 1`.
2367
+ - Qwen's standard mlx-bun arm beat mlx-lm by 12.1% at short decode and
2368
+ 10.7% at long-context decode. The mixed arm did not beat bf16 on decode;
2369
+ its useful result was restoring the full 15,112-token cache after restart.
2370
+ - The e4b and 12B unified arms restored only four cached tokens after restart,
2371
+ while their serial controls restored the full cache. This is a real
2372
+ scheduler/SSD-persistence regression and explains their poor aggregate rows.
2373
+ Qwen bf16 restored no cache in either scheduler mode.
2374
+ - Qwen mixed KV is a Lab characterization, not an L2 correctness claim. Its
2375
+ policy is copied from the official same-topology Qwen3.6 OptiQ artifact;
2376
+ Qwen3.8 has no model-specific mixed-KV oracle yet. Its 15,278 MB sampled peak
2377
+ RSS also failed the harness's `mixed < bf16` diagnostic, so the run proves
2378
+ that the policy loads and serves, but not that KV quantization was effective.
2379
+
2380
+ #### Bun 1.4.0 repeat
2381
+
2382
+ The full matrix repeated after upgrading from Bun 1.3.14 to 1.4.0. Starting
2383
+ state was 401 MiB inactive swap, 93% free memory, load 3.7, and no large
2384
+ foreign process, which passed the canonical preflight. All completion, chat,
2385
+ and unified-versus-serial parity probes passed again. Core mlx-bun performance
2386
+ was stable; the largest one-run movements were MiniCPM aggregate +5.0% and
2387
+ Qwen long-context decode +3.0%, neither promoted as a Bun speed claim without
2388
+ repeats.
2389
+
2390
+ | model | engine | short decode tok/s | short prefill tok/s | long decode tok/s | warm TTFT ms | aggregate ×4 tok/s |
2391
+ |---|---|---:|---:|---:|---:|---:|
2392
+ | MiniCPM5-1B | mlx-bun | **265.8** | **2,576** | **124.2** | **26** | **441.3** |
2393
+ | | mlx-lm | 177.0 | 1,907 | 96.5 | 86 | 185.8 |
2394
+ | gemma-4-e4b | mlx-bun | **61.7** | **868** | **43.1** | **39** | 21.2 |
2395
+ | | mlx-lm | 52.4 | 676 | 42.5 | 268 | **72.4** |
2396
+ | gemma-4-12B | mlx-bun | **29.7** | **191** | **28.4** | **77** | 6.0 |
2397
+ | | mlx-lm | 26.7 | 181 | 25.3 | 388 | **33.4** |
2398
+ | Qwen3.8-27B winner | mlx-bun | **18.6** | 64 | **17.0** | **116** | **19.5** |
2399
+ | | mlx-lm | 16.5 | **85** | 14.8 | 284 | 18.6 |
2400
+
2401
+ The e4b and 12B aggregate losses remain contaminated by the SSD durability
2402
+ race. Their unified arms restored 2 and 4 tokens; serial restored 15,939 and
2403
+ 15,794. Qwen's short-prefill loss is different: both mlx-bun schedulers lose
2404
+ at the roughly 754-token shape, while sustained prefill reaches 87 tok/s at
2405
+ 15.1k versus mlx-lm's 88. This points to fixed graph-build or shape overhead,
2406
+ not a slower sustained prefill kernel. Split timing is still required before
2407
+ assigning the cause.
2408
+
2409
+ ### Colibri G1/G3 component matrix — M1 Max 32 GB
2410
+
2411
+ Cleared-machine run on 2026-07-30, commit `47c4d6d`, Bun 1.3.14, pinned
2412
+ Colibri `44e489b`, public artifact revision `3cc8db9`, ten warmups and fifteen
2413
+ measured samples. Values are synchronized median milliseconds at identical
2414
+ production shapes; every arm passed its correctness oracle. These are
2415
+ component timings, not end-to-end generation claims.
2416
+
2417
+ | production-shape cell | direct Colibri Metal | selected mlx-bun path | decision |
2418
+ |---|---:|---:|---|
2419
+ | Q4 dense decode M=1 | 0.302 | 1.372 stock MLX | stock MLX (only mlx-bun dense candidate) |
2420
+ | Q4 dense prefill M=32 | 1.286 | **1.030 stock MLX** | stock MLX |
2421
+ | routed SwiGLU decode, top-8 M=1 | **1.401** | 4.282 custom Metal | custom Metal; 16.0% faster than stock MLX's 5.099 ms |
2422
+ | routed SwiGLU ragged M=11/23 experts | **10.851** | 18.100 stock MLX | stock MLX |
2423
+ | routed SwiGLU prefill M=32/64 experts | **32.906** | 45.558 stock MLX | stock MLX |
2424
+ | absorbed MLA decode, position 128 | **1.014** | 11.506 stock MLX | stock MLX; largest remaining component gap |
2425
+
2426
+ For the selected custom decode path, max absolute delta versus stock is
2427
+ `2.33e-9`, relative RMSE `5.56e-7`, and cosine
2428
+ `0.9999999999998354`. A separate three-warmup/eleven-sample run also selected
2429
+ custom Metal by 5.4%. Swap was unchanged at 339.25 MiB. Matched idle-power
2430
+ arms (baseline, 1, 2, and 4 native workers, repeated in reverse order) show no
2431
+ monotonic CPU/GPU/package-power increase, proving the condition-variable
2432
+ workers are passive; two workers remain the default. Raw gitignored reports:
2433
+ `runs/colibri-g1/*matrix*-2026-07-30.json` and
2434
+ `runs/colibri-g1/passive-worker-power*-2026-07-30.json`.
2435
+
2436
+ ### Colibri G4 serial native MTP — M1 Max 32 GB
2437
+
2438
+ Production-artifact separate-process A/B on 2026-07-30, Bun 1.3.14, pinned
2439
+ Colibri `44e489b`, public artifact revision `3cc8db9`, greedy gamma=3, 32-token
2440
+ prompt and 64 generated tokens. Both arms reproduced the same direct-Colibri
2441
+ 64/64 target-token trajectory. Generation wall time is the comparison metric;
2442
+ the probe's prefill/decode sub-buckets place the first sample on different
2443
+ sides of that boundary and are therefore not compared.
2444
+
2445
+ | arm | generation wall | wall throughput | target/verify forwards | draft acceptance |
2446
+ |---|---:|---:|---:|---:|
2447
+ | MTP off | 834.172 s | 0.0767 tok/s | 63 continuation | — |
2448
+ | MTP on | **675.654 s** | **0.0947 tok/s (1.235x)** | **31 verify (32 saved)** | 32/92 |
2449
+
2450
+ MTP-on emitted 2.065 tokens per verify forward and reduced end-to-end
2451
+ generation time by 19.0%. Its direct-oracle acceptance prefix was exact for
2452
+ the tie-free first four rounds `[1,1,1,0]` (eight emitted tokens; minimum
2453
+ first-draft margin 3.5675). Later acceptance is intentionally non-gating
2454
+ across engines because direct Colibri's float64 RMSNorm reduction and MLX's
2455
+ float32 graph produce different recurrent MTP hidden states while preserving
2456
+ all target tokens. The machine was not swap-cleared, so the
2457
+ 14,679,224,320-byte completed MTP-on physical footprint is not a G5 memory
2458
+ claim. Stable record:
2459
+ `fixtures/colibri-glm52/g4-native-mtp-e2e.json`.
2460
+
2461
+ ### Colibri G5–G7 full-model productization — M1 Max 32 GB
2462
+
2463
+ Final curated result for the streamed runtime. Bun 1.3.14, 32 GiB unified
2464
+ memory, 25 GiB process ceiling, batch 1, 4,096-token supported context, 128
2465
+ generated tokens, greedy decoding, true top-8, and quality-preserving defaults.
2466
+ The G5 before/after run is 2026-08-15; G6 learning telemetry is a three-repeat
2467
+ paired run on 2026-08-16; the DSA and API gates are 2026-08-17.
2468
+
2469
+ #### Resource contract
2470
+
2471
+ The current artifact-aware preflight, including the locally installed stock
2472
+ DSA indexer overlay, reports:
2473
+
2474
+ | resource | bytes | GiB |
2475
+ |---|---:|---:|
2476
+ | full artifact on disk (streamed, not resident) | 383,739,826,712 | 357.39 |
2477
+ | resident non-expert weights + DSA indexers | 11,074,469,760 | 10.31 |
2478
+ | main Q4 expert slab (139 slots) | 2,632,646,656 | 2.45 |
2479
+ | MTP Q8 expert slab (25 slots) | 945,356,800 | 0.88 |
2480
+ | target + MTP compressed KV | 789,577,728 | 0.74 |
2481
+ | reconstructed KV + verify + allocator/Bun/safety reserves | 5,910,612,992 | 5.50 |
2482
+ | **planned process** | **21,352,663,936** | **19.89 / 25.00** |
2483
+ | **process/macOS headroom** | **5,490,881,664** | **5.11** |
2484
+
2485
+ The original G5 measurement preceded the 197,202,400-byte stock indexer
2486
+ overlay and planned 21,111,440,128 bytes. The overlay raises the current
2487
+ preflight by 241,223,808 bytes but does not alter the short-context trajectory
2488
+ or the observed G5 footprints below.
2489
+
2490
+ > **Measurement outcome:** the requested before/after observation closed the
2491
+ > 32 GB fit question, but did **not** satisfy the harness's stricter
2492
+ > zero-compression/zero-swap contract. Peak physical footprint stayed at or
2493
+ > below 14,807,789,616 bytes (13.791 GiB), while maximum system/task compressor
2494
+ > growth was 4,402,905,088 / 1,939,537,920 bytes; MTP-off observed 7,143,424
2495
+ > bytes of swapout and MTP-on observed zero. The source result is correctly
2496
+ > labeled `observed`, not `pass`.
2497
+
2498
+ #### Cold/warm MTP and memory
2499
+
2500
+ | arm / turn | decode tok/s | end-to-end tok/s | final physical footprint |
2501
+ |---|---:|---:|---:|
2502
+ | MTP off · cold | 0.1330 | 0.1274 | 13,490,515,008 B |
2503
+ | MTP off · warm | 0.1190 | 0.1139 | 13,510,634,560 B (+19.2 MiB) |
2504
+ | MTP on · cold | 0.1557 | 0.1456 | 14,673,342,512 B |
2505
+ | MTP on · warm | **0.1577** | **0.1487** | 14,697,574,448 B (+23.1 MiB) |
2506
+
2507
+ MTP-on accepted 72/166 drafts over 56 verify forwards on each turn. Warm
2508
+ end-to-end throughput was 1.306x MTP-off. It is also only 55% of the rounded
2509
+ same-machine direct-Colibri MTP-on control (0.27 tok/s), and 0.1487 tok/s is
2510
+ 7.43% of the aspirational 2 tok/s target—a **13.45x** remaining gap. The
2511
+ aspiration is not a release gate or a `fit` prediction.
2512
+
2513
+ #### Expert delivery and policy decisions
2514
+
2515
+ The replicated G6 control's median warm turn read exactly
2516
+ 1,974,949,363,712 logical bytes from the expert artifact, or
2517
+ 15.429291904 decimal GB per generated token. Its hit rate was 1.6597%; median
2518
+ main-tier disk-service p95 was 90.98 ms, foreground-wait p95 92.66 ms, and
2519
+ expert-layer-forward p95 167.84 ms. This is the measured reason the runtime is
2520
+ disk/serialization-bound rather than compute-bound.
2521
+
2522
+ | MTP-on policy (three paired repeats) | warm hit rate | disk GB/token | warm e2e tok/s | decision |
2523
+ |---|---:|---:|---:|---|
2524
+ | control | 1.66% | 15.429 | **0.149** | default |
2525
+ | startup auto-pin | 9.62% | 14.191 | 0.143 | off: 4.06% slower, +3.337 GiB footprint |
2526
+ | auto-pin + live LFRU | 9.62% | 14.191 | 0.148 | off: zero swaps; no benefit beyond run-order noise |
2527
+
2528
+ PILOT measurement found 69.90% next-layer top-8 precision/recall, but advisory
2529
+ `PILOT_K=4` left demand bytes unchanged and reduced warm throughput to 0.9746x.
2530
+ Two-step correction improved recall to 73.01% while reducing warm throughput
2531
+ 10.13%. All learning/prediction/hint policies therefore remain off by default.
2532
+
2533
+ #### DSA and served API
2534
+
2535
+ The paired DSA matrix measured 24 eligible fresh-process cells (2K/8K × DSA
2536
+ off/on × MTP off/on × three repeats), all with exact cold/warm/repeat/MTP
2537
+ tokens. Positive decode delta means DSA was faster; negative wall delta means
2538
+ less total time.
2539
+
2540
+ | context | MTP | paired median decode delta | paired median wall delta | decision |
2541
+ |---:|---|---:|---:|---|
2542
+ | 2,048 | off | -2.80% | +4.14% | no speed claim |
2543
+ | 2,048 | on | -32.90% | +20.95% | regression |
2544
+ | 8,192 | off | +12.38% | -1.89% | below 5% total-wall win gate |
2545
+ | 8,192 | on | -34.33% | +8.19% | regression |
2546
+ | 32,768 | off/on | not run | not run | ineligible: 27.320/28.540 GiB exceeds 25 GiB |
2547
+
2548
+ The checkpoint's 21-full/57-shared schedule remains a semantic requirement,
2549
+ but no DSA product-speed claim is made. Stage-2 manifest SHA-256:
2550
+ `90b3fe4ed53714604b7a747991b3bb1b87aedbf57a139915065f5b4be42cda38`.
2551
+
2552
+ Finally, the fresh real-artifact G7 smoke returned HTTP 200 with correct
2553
+ envelopes for chat completions, text completions, Anthropic Messages, and
2554
+ OpenAI Responses; SSE used `text/event-stream`, emitted four events, ended in
2555
+ `[DONE]`, and reported the truthful `serial+spec` lane. Health, discovery,
2556
+ exact-plan stats, and post-run idle rows also passed. This is protocol/API
2557
+ evidence, not a throughput benchmark.
2558
+
2559
+ Primary raw records: machine-local `runs/colibri-g5/{summary,mtp-on,mtp-off}.json`,
2560
+ `runs/colibri-g6-learning-shakeout-2026-08-15/summary.json`, and
2561
+ `~/.cache/mlx-bun/evidence/glm52-dsa-stage2-2026-08-17/`.
2562
+
2563
+ ### Served (warm) — the path agents actually use
2564
+
2565
+ decode tok/s · TTFT ms · server-ready s · steady RSS GB
2566
+
2567
+ | model | mlx-bun (mixed) | mlx-bun (bf16) | mlx-lm (bf16) | optiq (mixed)† |
2568
+ |---|---|---|---|---|
2569
+ | MiniCPM5-1B | **252.9** · 34 · 0.17 · 1.22 | — | — | 223.6 · 64 · 0.84 · 1.82 |
2570
+ | gemma-4-e4b | 55.7 · 44 · 0.36 · 7.14 | **57.3** · 48 · 0.36 | 53.5 · 218 · 0.98 · 7.55 | 53.4 · 221 · 0.78 · 7.53 |
2571
+ | gemma-4-12B | **25.9** · 85 · 0.38 · 9.46 | — | — | 25.5 · 326 · 1.24 · 9.86 |
2572
+ | gemma-4-26B | 54.2 · **45** · 0.47 · 18.25 | **55.0** · 44 · 0.47 | 52.3 · 228 · 0.77 · 4.87 | — |
2573
+
2574
+ † **The served `optiq (mixed)` cells are effectively bf16** — optiq's
2575
+ KV-quant patch is inert on mlx-lm 0.31.3's batched server path:
2576
+ `install_mixed_kv` hooks `mlx_lm.generate.maybe_quantize_kv_cache` and
2577
+ `mlx_lm.server.stream_generate`, but the server routes every *seedless*
2578
+ text chat request through `BatchGenerator`, which calls neither hook, and
2579
+ the h2h harness's server requests carry no `seed`. See
2580
+ `lab/repro/optiq-mixed-kv-inert/` for the mechanism + repro. The data
2581
+ fingerprint agrees: e4b optiq-mixed served 53.4 tok/s · 7.53 GB RSS ≡
2582
+ mlx-lm bf16's 53.5 · 7.55. Same caveat applies to any serve-mode
2583
+ optiq-mixed cell in raw `benchmarks-serve-*` artifacts dated ≤ 2026-07-06.
2584
+ The **Direct** and **Long context** optiq (mixed) rows below DID measure
2585
+ real quantized-KV execution (the legs passed `kv_bits=8` straight into
2586
+ `mlx_lm.generate.stream_generate` — old `bench.ts --baseline-kv config` —
2587
+ so the 64k collapse and the lower peaks are genuine quantized-KV
2588
+ behavior), but a second installer defect means the scheme was **uniform
2589
+ 8-bit, not the per-layer map**: `install_mixed_kv`'s hook patch lands on
2590
+ the `generate` *function* that shadows `mlx_lm.generate` in mlx-lm's
2591
+ package namespace, never on the module, so mlx-lm's stock uniform
2592
+ `maybe_quantize_kv_cache` is what ran (empirically proven in the repro
2593
+ dir). Read "optiq (mixed)" in those two tables as "optiq (uniform kv8)".
2594
+ mlx-bun (mixed) columns are unaffected — our engine implements the
2595
+ per-layer scheme natively — and the L2 parity goldens stay valid: every
2596
+ `regen-*` oracle script applies the scheme explicitly (direct per-layer
2597
+ `to_quantized`, or calling optiq's patched hook by name), never through
2598
+ the dead serve-path indirection.
2599
+
2600
+ Across every served model: mlx-bun has the fastest decode and the fastest
2601
+ TTFT/startup (2–5×), at ~0% server tax vs its own direct engine.
2602
+
2603
+ ### Served h2h post-consolidation (2026-08-22, e4b, single pass — directional)
2604
+
2605
+ Real servers via `bench-serve.ts` on merged main `4103ae1`; loaded machine
2606
+ (ambient loadavg ~3), so treat as directional until a quiet-box pass. Full
2607
+ findings + root-cause sweep: PLAN.md "Prefill vs mlx-lm (2026-08-22)".
2608
+
2609
+ | arm | prefill@1k tok/s | ttft cold/warm ms | decode tok/s | parity |
2610
+ |---|---:|---|---:|---|
2611
+ | mlx-bun | **1143** | 578 / **39** | **53.9** | ✓✓ byte-identical |
2612
+ | mlx-lm | 866 | 772 / 230 | 50.3 | (oracle) |
2613
+
2614
+ Served prefill stays a decisive mlx-bun win (+32% @1k, warm TTFT 5.9×)
2615
+ after the serving-architecture merge. Engine-direct prefill is
2616
+ parity-within-noise elsewhere (cpm5/12B/26B; e4b@256 fresh-process −12%
2617
+ is the one reproducible engine-level residual). Chunk-size tuning below
2618
+ the 2048 convention is NOT L1-safe: logits are convention-pinned in BOTH
2619
+ stacks (mlx reduction-order sensitivity; python drifts more than we do).
2620
+ Open lead from this pass: e4b agg×4 read 26.6 vs mlx-lm 107.3 — RESOLVED
2621
+ same day as a `443f333` regression (bf16 BatchedRotatingCache lost its
2622
+ signature-based route in the join merge → whole-batch drop on joiners;
2623
+ PLAN.md "agg×4 regression"). Post-fix: 122-126 tok/s aggregate, matching
2624
+ pre-merge.
2625
+
2626
+ ### Direct (engine only)
2627
+
2628
+ decode tok/s · prefill tok/s · gen-peak GB
2629
+
2630
+ | model | mlx-bun (bf16) | mlx-bun (mixed) | mlx-lm (bf16) | optiq (mixed) |
2631
+ |---|---|---|---|---|
2632
+ | MiniCPM5-1B | 268.6 · 1817 · 1.01 | 241.9 · 1651 · 1.01 | **271.0** · 800 · 1.03 | 249.5 · 706 · 1.03 |
2633
+ | gemma-4-e4b | **57.1** · 304 · 6.61 | 55.7 · 283 · 6.61 | 56.5 · 373 · 6.65 | 56.1 · 368 · 6.65 |
2634
+ | gemma-4-12B | **26.0** · 168 · 8.99 | 25.8 · 166 · 8.99 | 25.9 · 141 · 9.10 | 25.7 · 137 · 9.00 |
2635
+ | gemma-4-26B | 55.0 · 206 · 17.71 | 53.9 · 208 · 17.71 | **55.6** · 187 · 17.78 | 55.0 · 190 · 17.72 |
2636
+
2637
+ Direct decode is at parity-to-slightly-behind mlx-lm (the residual host
2638
+ overhead per step); prefill leads on the larger models. See PLAN.md
2639
+ "Decode gap RESOLVED" for the root-cause/fix history.
2640
+
2641
+ ### Logprob metadata readback (2026-07-29)
2642
+
2643
+ Paired internal before/after measurement on the M1 Max 32 GB,
2644
+ Qwen2.5-0.5B-Instruct-4bit, Bun 1.3.14: 256 generated tokens, two warmups,
2645
+ five randomized measured rounds. This isolates mlx-bun's API metadata
2646
+ readback; it is **not** a Bun-versus-Python FFI comparison.
2647
+
2648
+ | arm | before total / decode | after total / decode | overhead vs off, before → after |
2649
+ |---|---:|---:|---:|
2650
+ | off | 802.75 ms / 328.92 tok/s | 803.94 ms / 328.81 tok/s | control |
2651
+ | `logprobs` | 1,185.89 ms / 220.52 tok/s | 802.77 ms / 329.18 tok/s | +47.7% → −0.1% |
2652
+ | `top_logprobs=5` | 1,354.21 ms / 192.69 tok/s | 856.24 ms / 307.63 tok/s | +68.7% → +6.5% |
2653
+
2654
+ The fix reads uint32 IDs directly and expands the few bf16/f16 values on the
2655
+ host instead of queueing `astype(float32)` behind the already-dispatched next
2656
+ decode step. The off control stayed flat; all 40 parity checks and all 1,280
2657
+ selected/top-k comparisons were exact. Clean commits: before `00e597e`, after
2658
+ `b1cb7cb`. Raw artifacts are recorded in the Phase 22 ledger in
2659
+ `docs/archive/investigations/pre-colibri-stabilization.md`.
2660
+
2661
+ ### Long context (gemma-4-12B) — where the gap opens
2662
+
2663
+ decode tok/s · gen-peak GB
2664
+
2665
+ | context | mlx-bun (bf16) | mlx-bun (mixed) | mlx-lm (bf16) | optiq (mixed) |
2666
+ |---|---|---|---|---|
2667
+ | 16k | 23.9 · 11.82 | 23.5 · 10.61 | 23.9 · 11.72 | 21.6 · 11.19 |
2668
+ | 64k | **20.9** · 15.77 | 18.7 · 10.46 | 20.9 · 15.91 | 12.3 · 14.89 |
2669
+
2670
+ At 64k mlx-bun holds parity with mlx-lm on bf16 while optiq collapses to
2671
+ 12.3 tok/s; mlx-bun's mixed-KV trades ~2 tok/s for ~5 GB lower peak.
2672
+
2673
+ ### Attempted but failed (2026-06-14)
2674
+
2675
+ - `gemma-4-12B/optiq/kv=config`: `quantized_matmul` weight/scales
2676
+ shape mismatch (upstream optiq bug; tracked). _(Relabeled from the
2677
+ old-legend name "e4b" = hash `5b…` = 12B; no gen-peak was recorded for
2678
+ this failed run, so the model id here is inferred from the legend, not
2679
+ fingerprinted.)_
2680
+
2681
+ ---
2682
+
2683
+ ## 3. Quality — for non-bit-exact (Lab) optimizations only
2684
+
2685
+ When a custom path trades bit-exactness for speed, quantify the cost so a
2686
+ perf win is only claimed with its quality delta — e.g. *"+23% tok/s while
2687
+ holding ±5% on the 6-test mean."*
2688
+
2689
+ - **6-test mean** — mean score across `src/eval/tasks/`: bfcl, gsm8k,
2690
+ hashhop, humaneval, ifeval, mmlu — optimized path vs the compatible
2691
+ upstream.
2692
+ - **KL divergence** — optimized vs compatible token distribution.
2693
+
2694
+ This section is the home for a Lab experiment's quality measurements
2695
+ when it's promoted (the bar: paired-A/B win vs L1 on a stable pass +
2696
+ KL PASS — see docs/design/unified-engine-frontier-plan.md §6-7).
2697
+
2698
+ ### TurboQuant KV quality-vs-bpw (2026-07-06, M1 Max 32 GB, MiniCPM5-1B)
2699
+
2700
+ > Note: measured on an M1 Max 32 GB, not this file's M4 Pro reference
2701
+ > box — valid as a paired quality/KL measurement (machine-independent),
2702
+ > not as a perf number.
2703
+
2704
+ Opt-in memory/context scheme (`--kv-quant turbo[:k<bits>v<bits>]`), not a
2705
+ speed lever. Teacher-forced serving-decode KL vs bf16 KV (8×128 tokens, 32
2706
+ decode steps, `eval-turboquant-curve.ts (deleted; git history)`); affine rows same harness:
2707
+
2708
+ | scheme | effective KV bits | KV compression | mean KL vs bf16 |
2709
+ |---|---|---|---|
2710
+ | uniform kv8 (g64) | 8.50 | 1.88× | 0.00246 |
2711
+ | turbo k8v8 | 8.75 | 1.83× | 0.00214 |
2712
+ | turbo k8v4 | 6.75 | 2.37× | 0.00936 |
2713
+ | **turbo k8v3 (default)** | **6.25** | **2.56×** | **0.0325** |
2714
+ | uniform kv4 (g64) | 4.50 | 3.56× | 0.0516 |
2715
+ | turbo k4v3 | 4.25 | 3.76× | 0.0622 |
2716
+ | turbo k4v2 | 3.75 | 4.27× | 0.205 |
2717
+
2718
+ Read: turbo k8v3 beats uniform kv4's KL at 2.56× compression; k4v3 is
2719
+ on-curve with affine at matched bits; 2-bit values are the cliff (matches
2720
+ the TurboQuant paper's law). Codec is bit-exact vs the vendored vllm-metal
2721
+ reference (goldens/turboquant.json); details in
2722
+ docs/design/turboquant.md.
2723
+
2724
+ ## 4. Composition — feature-default decisions (measured, per pair)
2725
+
2726
+ The doctrine (docs/design/speculative-decoding.md Phase 4e): a feature is ON by
2727
+ default for a (model, config) pair only when it WINS a clean-machine
2728
+ paired A/B on that pair; losing configs stay documented default-off
2729
+ levers. This section records the decisions and the numbers behind them.
2730
+
2731
+ ### Packed Trellis with KV4/MTP and paired prefixes, M4 Pro, 2026-09-08
2732
+
2733
+ The configured serial suite passes every phase on the required 12.14 GiB
2734
+ packed Trellis artifact at clean commit `1a80401`, with unchanged source
2735
+ hashes throughout. Machine: `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB,
2736
+ Bun 1.4.0, bundled MLX 0.32.2. Quiet preflight passes. This is one run,
2737
+ not a matched original/final performance claim or a new Kanban task.
2738
+
2739
+ | Metric | Result |
2740
+ |---|---:|
2741
+ | Short-prompt decode, median of five 192-token samples | **18.806 tok/s** |
2742
+ | Short complete-request time, median | **11.389 s** |
2743
+ | Output / complete-request time, median | 16.859 tok/s |
2744
+ | Cold TTFT, median of three approximately 1K probes | 6.537 s |
2745
+ | Warm TTFT, 754 cached tokens | **94.586 ms** |
2746
+ | Approximately 1K prefill estimate, median | 115.747 tok/s |
2747
+ | Context probe, actual input tokens | 2,677 |
2748
+ | Context prefill estimate | 116.808 tok/s |
2749
+ | Context decode, median of three samples | 22.763 tok/s |
2750
+ | Cached context TTFT | 95.434 ms |
2751
+ | Peak sampled process RSS | 11,973.656 MiB (11.693 GiB) |
2752
+ | Phase failures | 0 |
2753
+
2754
+ Arguments are `--draft-kind mtp --num-draft-tokens 2 --kv-quant 4
2755
+ --prompt-cache 4`, with the folded RTN4 MTP draft. Runtime overrides select
2756
+ Trellis variant 13, uniform KV4 speculation, paired MTP prefixes and prefill
2757
+ chunks of 256. Async Trellis expansion, early-first-token and structural fill
2758
+ are off. Workload seed is `pr47-block-0`, thinking is enabled, and the
2759
+ requested context target is 4,096; the table reports the actual token count.
2760
+ All five short samples emit exactly 192 tokens with no reused prefix.
2761
+
2762
+ The speculative prefix store is RAM-only. Restarting restores zero cached
2763
+ tokens and the context request takes 24.404 seconds to first output. The
2764
+ ordinary SSD flush returns durable with zero entries; this is not proof of
2765
+ speculative SSD persistence. No stock mlx-lm arm supports this packed artifact.
2766
+ The faster context decode sample reflects a different prompt and MTP acceptance
2767
+ workload; it does not establish that increasing context makes inference faster.
2768
+
2769
+ Raw evidence: `reports/qwen38-rd/pr47-trellis-kv4-mtp-serve.md` and its `.md.json`
2770
+ companion. These serving timings are separate from the completed fresh Pi
2771
+ Kanban measurement below.
2772
+
2773
+ ### Original and optimized serving diagnostics, M4 Pro, 2026-09-07
2774
+
2775
+ Machine: `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, Bun 1.4.0.
2776
+ `bench-serve.ts all` used workload seed `kanban-final-0`, thinking enabled,
2777
+ 192 requested output tokens and five decode samples. These are earlier
2778
+ diagnostic runs, with existing swap, rather than final-PR quiet acceptance.
2779
+ All columns below use the serial serving lane and the required packed target
2780
+ weights. Baseline uses `673b43f`, Trellis variant 6 and the older native library;
2781
+ optimized arms use variant 13, the lossless interleaved artifact and the local
2782
+ MLX 0.32.2 candidate. Each run's source stayed fixed.
2783
+
2784
+ All three serving arms use **bf16 KV**, with `--kv-quant off`. The MTP arm
2785
+ adds two drafts and paired RAM prefixes. This differs from the completed
2786
+ long Kanban task's KV4 configuration. These runs predate the later ownership
2787
+ and bounded-range fixes, so they do not measure the exact final task revision.
2788
+
2789
+ | Serial serving metric | Original | Optimized, ordinary decode | Optimized, MTP + RAM cache |
2790
+ |---|---:|---:|---:|
2791
+ | Median decode, tok/s | 10.140 | 11.712 | 19.426 |
2792
+ | Cold-request TTFT, ms | 5,923.576 | 6,164.498 | 5,801.504 |
2793
+ | Cached TTFT, ms | 190.841 | 436.308 | 91.916 |
2794
+ | 1K prefill, tok/s | 127.963 | 122.962 | 130.522 |
2795
+ | Peak process RSS, reported MB | 11,958.984 | 13,859.828 | 12,061.219 |
2796
+
2797
+ Ordinary decode improves **15.5%**. The MTP configuration improves decode
2798
+ **91.6%** relative to the original, with cached TTFT **51.8% lower**.
2799
+ Its cold TTFT changes by -2.1%, prefill by +2.0%, and sampled RSS by +0.9%.
2800
+ Ordinary decode's gain does not extend to every metric: its cached TTFT and
2801
+ RSS regress in this diagnostic. The percentages describe these specific
2802
+ serving configurations; they are not a measured Kanban task-time reduction.
2803
+
2804
+ The baseline context phase crashed and recovered on retry; no context-phase
2805
+ speedup is claimed here. MTP prefix state is RAM-only: the restart probe
2806
+ restored zero tokens and does not establish SSD persistence. Stock mlx-lm
2807
+ cannot read this packed Trellis artifact, so it supplies no same-artifact
2808
+ serving baseline for these rows.
2809
+
2810
+ Raw evidence: `reports/qwen38-rd/kanban-final/suite-driver.json`,
2811
+ `baseline-suite.md.json`, `optimized-ordinary-suite.md.json`, and
2812
+ `optimized-mtp-cache-suite.md.json`. The driver records all commands,
2813
+ environments, source hashes and exits. The completed task and its separate
2814
+ acceptance are recorded below.
2815
+
2816
+ ### Fresh Pi kanban diagnostic, M4 Pro, 2026-09-07
2817
+
2818
+ Machine: `Joshs-MBP-2025.local`, M4 Pro, 24 GB; Bun 1.4.0, Pi 0.85.1,
2819
+ MLX 0.32.2. These are task diagnostics with existing swap. The first attempt
2820
+ also had a brief background browser-test CPU burst. Neither is a quiet-machine
2821
+ speed claim.
2822
+ The model is the required 12.14 GiB packed Qwen3.8-27B Trellis artifact with
2823
+ lossless interleaving. The selected Luke profile is
2824
+ `qwen3.8-27b-q3_k_xl-coding-128k`, pinned at repository commit
2825
+ `3288d1918fa6140c10f3b2de2d37f9d717a5ab75`. It uses the unchanged prompt,
2826
+ xhigh thinking, temperature 0.6, seed 42 and 131072 context. The MLX mapping
2827
+ uses target affine KV4 group64, two MTP drafts, paired RAM prompt prefixes
2828
+ and 256-token prefill chunks.
2829
+
2830
+ | Attempt | Time until Pi stopped | Output tokens | Overall tok/s | First-turn tok/s, including prefill | First reasoning TTFT | Peak server + Pi RSS | Result |
2831
+ |---|---:|---:|---:|---:|---:|---:|---|
2832
+ | History fixed; original tool-value parser | 65m 30.245s | 53,631 | 13.646 | 15.965 | 22.869s | 12.042 GiB | Failed: only HTML and two JS modules; final edit call remained assistant text |
2833
+ | History and tool-value parsing fixed | 106m 6.531s | 82,015 confirmed | 12.882 | 16.154 | 22.892s | 13.795 GiB | Failed inference: Metal out of memory at the 85,238-token request; Pi did not finish |
2834
+
2835
+ All four request prompt counts matched independent renders. Later requests
2836
+ reused 2,549, 53,174 and 54,859 prompt tokens, with MTP active. Pi had no
2837
+ automatic retries or compactions. Its clean process exit did not mean the
2838
+ app was complete: the mandatory README was absent and most app files were
2839
+ never written. The untouched output fails acceptance. No successful task
2840
+ completion time or matched task-time speedup is established by this row.
2841
+
2842
+ The saved final edit parameter is valid JSON. The engine decoded XML
2843
+ entities before JSON parsing and its repair pass misidentified the nested
2844
+ array as the outer call. The corrected parser preserves the complete argument
2845
+ array through the actual tokenizer and streaming path.
2846
+
2847
+ The fresh attempt with both fixes completed ten requests. Every completed
2848
+ prompt count matched the independent render and every response used MTP.
2849
+ The aggregate accepted/drafted ratio was 80.038%. The first tool transition
2850
+ took 524.244 seconds to first output while processing newly generated history.
2851
+ Later requests reused progressively longer prompt prefixes. The cache still
2852
+ captures prompt boundaries rather than the newly generated history.
2853
+
2854
+ The eleventh request reached a Metal allocation failure after its first
2855
+ reasoning fragment. Its terminal usage was unavailable, so the output total
2856
+ counts only completed responses. The wall-clock interval includes that failed
2857
+ request, prefill, tools and agent overhead. Ten completed response intervals,
2858
+ excluding TTFT, average 15.270 output tokens/s. This is distinct from both
2859
+ overall task throughput and the short-context serving-suite decode rate.
2860
+ There were no retries, compactions or tool errors. Engine source hashes stayed
2861
+ fixed. All inference processes exited during bounded cleanup.
2862
+
2863
+ The untouched app has HTML, CSS, twelve JavaScript modules and package.json,
2864
+ but no README. Syntax checks pass. A separate browser smoke test after server
2865
+ shutdown shows the default columns and keyboard card creation work, but opening
2866
+ the editor throws `ReferenceError: renderLabels is not defined`. Remaining UI
2867
+ checks were not run after that blocking failure. No app edits or repair prompts
2868
+ were supplied. These are findings about an incomplete artifact, not a completed
2869
+ model submission. No successful completion time or matched task-time gain exists.
2870
+
2871
+ Process RSS does not measure all Metal allocations. The out-of-memory failure
2872
+ does not establish the model's architectural context limit; the tested KV4,
2873
+ MTP and retained-prefix combination needs a separate memory diagnosis.
2874
+
2875
+ Protocol and design: [decode-speed-program §7.7](../../design/decode-speed-program.md#77-gates-scheduling-and-completion).
2876
+ Raw evidence: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-history-fixed/`
2877
+ and `luke-q3-128k-xhigh-tool-values-fixed/`, including `quality-static.json`,
2878
+ `quality-browser.json` and screenshots. Portable report:
2879
+ `reports/qwen38-rd/kanban-final/comparison.html`.
2880
+
2881
+ ### Kanban capacity diagnosis, M4 Pro, 2026-09-08
2882
+
2883
+ Native Bun screen on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, using the
2884
+ same 12.14 GiB target, MTP head, MLX 0.32.2 candidate and KV4/prefix settings
2885
+ as the failed Pi attempt above. The saved failing history renders to 85,238
2886
+ tokens. Fixed text tokens extend it to 110,000 for this capacity screen.
2887
+ No Pi task runs in this screen. Sampling follows the selected profile, but
2888
+ EOS stopping is disabled to require a short continuation. This is neither
2889
+ a fresh task result nor a quiet-machine performance claim.
2890
+
2891
+ The unchanged control finished target prefill and emitted one token, then
2892
+ failed with Metal out of memory in the first MTP draft round. Its wall time
2893
+ was 1,482.497 seconds. Peak active Metal allocation reached 19,451,721,310
2894
+ bytes against a recommended working set of 19,069,665,280 bytes. Immediately
2895
+ before draft prefill, active allocation was 14,593,938,440 bytes; at the
2896
+ first emitted token it was 17,494,527,842 bytes. The retained prefix reported
2897
+ 2,633,836,544 logical bytes. These counters measure different things from
2898
+ process RSS and do not establish a model context limit. Source hashes stayed
2899
+ fixed; the worker exited with failure and bounded cleanup completed.
2900
+
2901
+ Raw control: `reports/qwen38-rd/kanban-capacity-110k-control.json` and its
2902
+ allocation event log. A focused small ownership regression retains 8,405,016
2903
+ bytes before the fix, despite requiring only small KV state and one hidden
2904
+ row. The isolated candidate now evaluates draft KV at each existing prefill
2905
+ chunk and materializes the retained final hidden row. The ownership,
2906
+ prefix-position and provider-disposal tests pass. Full-model exactness and
2907
+ large-context acceptance are checked separately. A sampling-failure
2908
+ regression retains 524,288 bytes before scoped disposal; it now passes the
2909
+ under-4-KiB cleanup guard without running GC after the failure.
2910
+
2911
+ The final-source small native comparison uses the same first 8,192 history
2912
+ tokens and generates 32 tokens twice. Before and after the ownership changes,
2913
+ both responses and all MTP acceptance decisions match exactly. Each process
2914
+ first prefills from zero, then restores 8,191 cached tokens. Peak active
2915
+ allocation is 13,330,783,014 bytes before and 13,105,695,458 after. Both source
2916
+ manifests stay fixed. This is one correctness/allocation comparison, not a
2917
+ request-time speed claim. Typechecks pass. Evidence: `kanban-capacity-8k-final-comparison.json`
2918
+ and its two referenced control/candidate reports in `reports/qwen38-rd/`.
2919
+
2920
+ The final native capacity screen passes at 110,000 prompt tokens. It completes
2921
+ three identical 256-token continuations, with 109,999 tokens restored on each
2922
+ cached request. Between the latter two, an intentional output-sink error after
2923
+ eight emitted tokens exercises request cleanup. Retained active allocation is
2924
+ 14,911,641,794 bytes after every completed or intentionally failed request.
2925
+ The next request recovers in the same process and reproduces the continuation.
2926
+ Peak active allocation is 17,981,018,362 bytes, 1,470,702,948 bytes below the
2927
+ failing control, despite the longer continuation. The first request takes
2928
+ 1,525.095 seconds including full prefill; the two complete cached requests take
2929
+ 33.148 and 33.175 seconds. Instrumented synthetic-context timings are not
2930
+ Kanban completion estimates. Final provider/weight disposal leaves 101,892,102
2931
+ active bytes; the equal per-request counters establish no incremental retention
2932
+ from the injected failure, not zero global runtime allocation. The worker exits
2933
+ successfully, its source hashes stay fixed and its deadline is not reached.
2934
+
2935
+ The main source has the same ownership fixes. Its focused memory/provider tests
2936
+ and a real-target MTP/non-MTP short greedy identity gate pass, as do all
2937
+ typechecks.
2938
+ Native evidence: `reports/qwen38-rd/kanban-capacity-110k-owned-final.json`.
2939
+
2940
+ The saved-history HTTP gate also passes on the isolated candidate. It first
2941
+ replays the exact failed request, then appends that response and synthetic
2942
+ tool/user history to test growth. Tool calls are recorded but never executed
2943
+ by this diagnostic. Each response allows up to 512 output tokens and stops
2944
+ naturally. Both repeated responses preserve all text, tool arguments, output
2945
+ counts and MTP acceptance decisions.
2946
+
2947
+ | Prompt tokens | Cached tokens | Output tokens | Complete request, s | TTFT, s |
2948
+ |---:|---:|---:|---:|---:|
2949
+ | 85,238 | 0 | 42 | 988.103 | 984.951 |
2950
+ | 85,238 | 85,237 | 42 | 3.283 | 0.225 |
2951
+ | 110,014 | 85,237 | 92 | 401.843 | 393.126 |
2952
+ | 110,014 | 110,013 | 92 | 8.931 | 0.255 |
2953
+
2954
+ Source hashes stay fixed and server cleanup exits successfully. This validates
2955
+ serving capacity and cache reuse, not a completed Kanban task. Raw evidence:
2956
+ `reports/qwen38-rd/kanban-memory-http-owned.json` and the saved request/response
2957
+ files beside it. These checks exercise short continuations. The fresh Pi
2958
+ retry below still fails during sustained generation.
2959
+
2960
+ During the saved-history HTTP prefill, simultaneous read-only `/health` and
2961
+ `/stats` requests both returned 200, taking 4,776.475 and 4,776.682 ms. This
2962
+ single busy-server observation does not establish an idle baseline or latency
2963
+ distribution. It identifies responsiveness during native prefill for a separate
2964
+ serving check. Evidence: `reports/qwen38-rd/kanban-memory-http-responsiveness.json`.
2965
+
2966
+ ### Fresh Pi Kanban after MTP ownership fixes, M4 Pro, 2026-09-08
2967
+
2968
+ The fresh retry on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, failed with
2969
+ Metal out of memory after **106m 5.416s**. It used the same 12.14 GiB target,
2970
+ published Luke Q3 128K xhigh profile and unchanged prompt as the preceding
2971
+ attempt. The source and every saved request's profile pass the post-run audit.
2972
+ The first request body is byte-identical to the preceding attempt; its entire
2973
+ response and MTP acceptance trace also match. Later history includes actual
2974
+ tool results, including changed directory timestamps.
2975
+
2976
+ Eight requests completed, reporting **73,831 output tokens**. The ninth
2977
+ request started with **77,077 prompt tokens**, emitted its first output after
2978
+ 26.415 seconds and failed after 780.891 seconds, during sustained decode.
2979
+ Its terminal usage is missing. Retokenizing delivered reasoning estimates
2980
+ another 5,659 tokens, but excludes buffered tool arguments, so the full
2981
+ generation count is unknown. The completed-response rate after first output
2982
+ is 15.658 tok/s; this excludes prefill, tool time and the failed response.
2983
+ Peak combined server/Pi RSS is **13.836 GiB**. Completed requests report
2984
+ 79.911% MTP acceptance. There were no retries, compactions or tool execution
2985
+ errors. Pi exited with code zero but reported a terminal error; the task
2986
+ therefore failed. No successful completion time or task-time speedup is
2987
+ established.
2988
+
2989
+ The untouched app supplies its README and passes syntax, basic card creation,
2990
+ board/theme persistence, column creation/rename and between-column card drag
2991
+ checks. The card editor throws `ReferenceError: renderLabels is not defined`;
2992
+ the archive panel throws `TypeError: K.render.renderArchive is not a function`.
2993
+ Required functional acceptance fails. Reorder interaction probes remain
2994
+ unconfirmed because their input simulation needs validation. Independent UI
2995
+ checks ran only after inference exited. No app code was edited and no repair
2996
+ prompts were supplied.
2997
+
2998
+ The short native and HTTP capacity checks above did not reproduce this long
2999
+ decode failure. It motivated the sustained allocation check below. Raw result,
3000
+ source/profile audit and untouched
3001
+ app checks: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-mtp-memory-fixed/`
3002
+ contains `result.json`, `measurement-audit.json`, `quality.json` and its
3003
+ referenced evidence.
3004
+
3005
+ ### Sustained Kanban decode allocation diagnosis, M4 Pro, 2026-09-08
3006
+
3007
+ A fresh native process loaded the failed task's saved **77,077-token** request
3008
+ and generated **12,288 tokens** with the same model, MTP, KV and sampling
3009
+ settings. EOS stopping was disabled for this bounded diagnostic; no tools
3010
+ were executed. The unchanged control completed in 2,408.753 seconds including
3011
+ 923.348 seconds to first output. Decode was 8.272 tok/s. Peak active MLX
3012
+ allocation was **18,204,808,450 bytes**; **1,593,360,390 bytes** remained active
3013
+ after provider/weights disposal and allocator-cache clearing. Source hashes
3014
+ stayed fixed. This is a saved-history diagnostic, not a fresh task result or
3015
+ a quiet-machine speed claim.
3016
+
3017
+ The large-range cache retained every distinct causal-mask range above 65,536
3018
+ elements. Early comparable rounds each added **311,296 bytes**, matching the
3019
+ page-rounded int32 range allocation. A focused regression with 256 changing
3020
+ context lengths retained **79,790,080 bytes** in the old implementation and
3021
+ **7,258,112 bytes** after bounding cached array data to 8 MiB. Three oversized
3022
+ ranges retained **37,748,736 bytes** before and **zero additional bytes** after.
3023
+ The regression fails before the change and passes after it, including exact
3024
+ range values, vocabulary reuse and lazy-view ownership after eviction. Eight
3025
+ focused main-source tests, the candidate regression and both workspace
3026
+ typechecks pass.
3027
+
3028
+ Reconstructing the target prefill lengths and verification windows from the
3029
+ control's acceptance trace predicts 4,685 distinct large mask ranges occupying
3030
+ 1,592,344,576 page-rounded bytes. That accounts for more than 99.9% of the
3031
+ observed allocation left after model disposal. This is allocation attribution
3032
+ from the recorded execution and source, not a measurement of every cache entry.
3033
+
3034
+ The bounded-cache full-model repeat passes: all **12,288 output tokens** and
3035
+ all **4,638 MTP acceptance decisions** are identical. Source and harness hashes
3036
+ stay fixed, with `src/mlx/ops.ts` the only engine difference between arms.
3037
+ Both runs exit normally without cleanup errors.
3038
+
3039
+ | Native diagnostic metric | Unbounded cache | Bounded cache |
3040
+ |---|---:|---:|
3041
+ | Complete request time | 2,408.753 s | 2,461.051 s |
3042
+ | Time to first output | 923.348 s | 939.902 s |
3043
+ | Decode rate | 8.272 tok/s | 8.078 tok/s |
3044
+ | Peak active MLX allocation | 18,204,808,450 B | 16,622,195,970 B |
3045
+ | Active MLX allocation after model disposal | 1,593,360,390 B | 8,224,774 B |
3046
+ | Observed peak process RSS | 14,324,711,424 B | 12,745,523,200 B |
3047
+ | OS lifetime peak process footprint | 18,969,882,768 B | 18,826,963,720 B |
3048
+
3049
+ Peak active allocation falls by **1,582,612,480 bytes**. The single diagnostic
3050
+ pair takes **2.171% longer**, so it establishes a memory/ownership correction,
3051
+ not a throughput gain. RSS, active allocation and physical footprint remain
3052
+ distinct measurements. The process monitor started during control prefill
3053
+ and before candidate prefill; native allocation instrumentation is identical.
3054
+ The fresh Pi task with this correction completed; its separate task result
3055
+ and functional acceptance are recorded below.
3056
+
3057
+ Raw evidence: `reports/qwen38-rd/kanban-sustained-77k-owned-control.json`, its
3058
+ allocation/process-memory traces, `kanban-arange-allocation-evidence.json`,
3059
+ `kanban-arange-regression.json`, `kanban-arange-micro-memory.json` and
3060
+ `kanban-arange-reconstruction.json`. Full-model comparison:
3061
+ `kanban-sustained-arange-comparison.json`, with both raw runs and their traces.
3062
+
3063
+ ### Completed fresh Pi Kanban with bounded range cache, M4 Pro, 2026-09-08
3064
+
3065
+ The untouched app passes the required functional checks after a fresh Pi run
3066
+ on `Joshs-MBP-2025.local`, Apple M4 Pro, 24 GB, using the required 12.14 GiB
3067
+ Trellis target. The published Luke Q3 coding 128K profile, unchanged prompt,
3068
+ xhigh thinking, sampling and seed 42 remain fixed. The candidate uses MLX
3069
+ 0.32.2, target KV4, MTP depth 2 and paired RAM prefixes. Processes, application
3070
+ caches, Pi session and task workspace started fresh; OS file cache was not purged.
3071
+
3072
+ | Completed task metric | Result |
3073
+ |---|---:|
3074
+ | Prompt submitted to Pi settled | **3h 33m 7.685s** |
3075
+ | Including server startup | 3h 33m 8.581s |
3076
+ | First request time to first output | 23.145 s |
3077
+ | Reported output tokens, including reasoning and compaction | **130,494** |
3078
+ | Completed inference requests | 62 |
3079
+ | Output / whole task elapsed time | 10.205 tok/s |
3080
+ | Completed-response rate after first output | 13.904 tok/s |
3081
+ | Sum of request time before first output | 56.665 min |
3082
+ | MTP draft-token acceptance | 79.706% |
3083
+ | Peak sampled combined server/Pi RSS | 11.916 GiB |
3084
+
3085
+ All 443 source, profile, request, usage and timing audit checks pass. Every
3086
+ response has terminal usage; the output total is exact. Pi and the server
3087
+ exit normally, with no inference error or automatic retry. Pi encounters
3088
+ seven tool execution errors during its own debugging and completes the task
3089
+ without external repair prompts.
3090
+
3091
+ One context compaction is included in the total. Its summary request uses
3092
+ 90,214 input tokens, reports 1,404 output tokens, and takes **19m 42.705s**,
3093
+ including 17m 37.551s before first output. The following coding request has
3094
+ 28,126 input tokens and takes another 4m 22.552s before first output.
3095
+ Both prompts have zero cached tokens because the summary changes the exact
3096
+ serialized prefix. The first ordinary tool turn separately takes 8m 53.415s
3097
+ before first output after the initial 50,533-token response; its cached prefix
3098
+ contains only 2,549 tokens. These are measured targets for reducing repeated
3099
+ prefill, not claimed savings. The frozen outcome helper recorded zero
3100
+ compactions because it recognized only `auto_compaction_start`; derived
3101
+ reports count the observed `compaction_start` while preserving the raw result.
3102
+
3103
+ The server's last observed OS lifetime peak physical footprint is
3104
+ **18,913,094,336 bytes**. The external monitor began during the task and
3105
+ sampled through five seconds before exit; lifetime counters include earlier
3106
+ process history but may miss the final interval. Physical footprint and the
3107
+ runner's sampled combined RSS are different measurements. Separate process
3108
+ lifetime peaks are not added as though they were concurrent.
3109
+
3110
+ After inference exited, independent browser checks passed card creation,
3111
+ required-title editing, description/labels/assignee fields, combined filters,
3112
+ archive/restore, column creation/rename/safe deletion/restore, native card
3113
+ and column reordering, the Done indicator, and persisted theme/board/order.
3114
+ The app supplies run instructions and modular vanilla code. No generated
3115
+ source was edited. Earlier automated reorder probes remain recorded; native
3116
+ mouse motion with dragover before release confirms both reorder operations.
3117
+
3118
+ This establishes a completed task on the frozen candidate. There is no
3119
+ matched successful original baseline, so it establishes no task-time speedup
3120
+ percentage. The complete first response and every MTP acceptance decision
3121
+ match the preceding failed attempt; its time changes from 3,152.595 to
3122
+ 3,147.633 seconds, effectively flat in one pair. The bounded range cache's
3123
+ measured benefit remains retained-memory correction and successful completion.
3124
+
3125
+ Raw evidence: `reports/qwen38-rd/kanban-final/luke-q3-128k-xhigh-arange-bounded/`
3126
+ contains `result.json`, `measurement-audit.json`, `quality.json`, referenced
3127
+ browser evidence, `memory-summary.json`, the untouched app and saved sources.
3128
+ The derived HTML report is `reports/qwen38-rd/kanban-final/comparison.html`.
3129
+
3130
+ Offline analysis of this successful trace reconciles all 62 terminal usage
3131
+ records to 130,494 output tokens, including the 1,404-token compaction. The
3132
+ server reports 3,980,688 cumulative prompt tokens and 3,701,542 cached tokens
3133
+ through the enabled paired target/draft RAM prefix cache; these are repeated
3134
+ request counts, not unique text or a measured time-saving percentage. An
3135
+ exact-substring analysis of 593,994 Unicode characters from 380 original
3136
+ input/output segments finds 2,830 maximal repeats of at least 32 characters
3137
+ (after excluding separator noise). The longest is 10,304 characters, a file
3138
+ write followed by a read. Replayed history and duplicated log events are
3139
+ excluded; nested/overlapping repeat families remain, so counts do not imply
3140
+ removable work. Local derived evidence and methodology:
3141
+ `~/.cache/mlx-bun/analysis/kanban-success/{analysis,duplicates}/report.md`,
3142
+ with the hashed source snapshot, per-request counts and repeat locations.
3143
+ Token-ID analysis of those same independently retokenized segments contains
3144
+ 160,352 tokens and 2,756 maximal repeats of at least eight tokens after the
3145
+ same noise filter; the longest is 2,732 tokens, occurring twice. This is
3146
+ reconstructed-text tokenization, not the sampled-token stream. Methodology,
3147
+ source/tokenizer hashes, all matches and histogram are retained alongside
3148
+ that evidence under `kanban-success/token-duplicates/`.
3149
+ Counting only later generated positions matching earlier generated content,
3150
+ with first occurrences retained and overlapping intervals merged, gives
3151
+ 48,932 duplicated retokenized positions at the eight-token cutoff, including
3152
+ 26,965 tool-argument positions matching prior reasoning. At a 32-token cutoff
3153
+ the total is 26,602. These are approximate 37.50%/20.39% shares of the 130,494
3154
+ reported output tokens: the normalized generated corpus has 127,905 tokens
3155
+ and excludes wire framing/escaping. They are not measured time savings.
3156
+ Method and interval evidence: `generated-duplicate-report.md` and its JSON
3157
+ companions in the same token-analysis directory.
3158
+
3159
+ A narrative reconstruction with an embedded source browser is saved at
3160
+ `~/.cache/mlx-bun/analysis/kanban-success/timeline/kanban-story.html`.
3161
+ Its clock uses cumulative completion tokens and places external actions at
3162
+ completed assistant-response boundaries: the first tool action follows
3163
+ 50,533 generated tokens. The account distinguishes code drafted in reasoning, file writes,
3164
+ repairs to the synthetic DOM test harness, and concrete application fixes.
3165
+ The trace identifies candidates for shortening the run; it does not establish
3166
+ which reasoning could be removed while preserving the successful outcome.
3167
+
3168
+ ### Speculative decoding — "should spec be on?" (decision pending Phase 0/1 runs)
3169
+
3170
+ Decision rule: spec defaults ON for a (target, drafter) pair iff
3171
+ serve-path decode ≥ 1.3× serial at the recommended γ, clean-machine
3172
+ paired (`scripts/bench-serve.ts all` preflight, `bench-feature-matrix.ts --cells
3173
+ serial,spec`), with acceptance within 3 pts of the bf16-drafter baseline
3174
+ (`scripts/dspark.ts ab`). Prediction to test: ON for
3175
+ 12B + quantized DeepSpec drafter, OFF for e4b + anything.
3176
+
3177
+ | target | drafter | γ | acceptance | τ | spec tok/s | serial tok/s | verdict |
3178
+ |---|---|---|---|---|---|---|---|
3179
+ | 12B-OptiQ-4bit | DeepSpec bf16 (6.9 GB) | 7 | 26–33% | ≈2.8 | 14.6 agg | 49.8 agg | **OFF** — drafter tax −3.4× (2026-07-07 first live run, loaded box, conc-4; directional) |
3180
+ | 12B-OptiQ-4bit | DeepSpec affine-q4-g64 (1.8 GB, built 2026-07-07) | best-of-0b | _1d run_ | _1d run_ | _0b/6 run_ | _0b/6 run_ | _pending_ |
3181
+ | e4b-OptiQ-4bit | (expected-negative control) | — | — | — | — | — | _pending_ |
3182
+
3183
+ Runbook (Josh's shell; directional passes fine loaded, the FINAL pair
3184
+ clean-machine per the house rule):
3185
+ 1. **1d acceptance A/B** (no server): `bun scripts/dspark.ts ab
3186
+ --target gemma-4-12B-it-OptiQ-4bit --drafter-a <bf16-snap>
3187
+ --drafter-b <q4-snap> --json ab-q4.json` — gate: drop ≤ 3 pts AND
3188
+ wall-clock strictly improves.
3189
+ 2. **0b γ sweep** (server): serve 12B `--draft-model <q4-snap>
3190
+ --num-draft-tokens {2,3,5,7}` × `bun scripts/bench-matrix.ts features
3191
+ --concurrency 1 --cells serial,spec` — pick best-γ by per-request tok/s.
3192
+ 3. **Phase 6 decision pair** (clean machine: reboot + `sudo purge`):
3193
+ best-γ config, `--cells serial,spec` at conc 1 AND agg×4 — fill the
3194
+ table, flip the features-matrix default cell if ≥ 1.3×.
3195
+
3196
+ ### TurboQuant KV — decided OFF (2026-07-06, re-affirmed post-leak-fix)
3197
+
3198
+ Opt-in memory/context lever, not a speed feature (v1 dequant-on-fetch is
3199
+ slower per step at long context; no speed claim made). The KL-vs-bpw
3200
+ curve above is the quality evidence. NOTE: any turbo perf/RSS impression
3201
+ formed before 2026-07-07 is invalid — the pre-fix build leaked
3202
+ window-scale buffers per decode step (PLAN Phase 13 post-merge fix).
3203
+
3204
+
3205
+ ### Shared Gemma assistant drafting, M4 Pro 24 GB, 2026-09-10
3206
+
3207
+ Four `bench-serve.ts all` arms in control/candidate/candidate/control order,
3208
+ Bun 1.4.2, MLX 0.32.2. Gemma4 12B OptiQ4 target with its bf16 assistant,
3209
+ draft depth 2, bf16 target KV, 2 GiB RAM cache plus temporary SSD, 192 decode
3210
+ tokens, four concurrent requests and default capacity eight. Workload seed
3211
+ `assistant-spec-0`; diagnostic mode under Josh's CPU/swap policy. Source snapshots
3212
+ `c8213540beb87f438fbafad7115b49f494e92526c28acca930f134883d5cfdcf`
3213
+ → `db38e64dbc3421ba5750485d8d6328afad63b64883bae8b945ff76e0ae6f1f21`.
3214
+ The candidate includes the shared assistant graph/provider, hidden companions,
3215
+ donor validity ports and the oracle-aligned strided weight views.
3216
+
3217
+ | Metric, mean of two arms | Previous implementation | Shared assistant | Change |
3218
+ |---|---:|---:|---:|
3219
+ | Median single-request decode, tok/s | 25.637 | 26.583 | +3.69% |
3220
+ | Four-request aggregate, tok/s | 24.815 | 34.129 | +37.53% |
3221
+ | Four-request wall time, ms | 20,632.8 | 15,002.1 | −27.29% |
3222
+ | Cached prefill, ms | 2,573.4 | 116.7 | −95.47% |
3223
+ | Cold prefill, ms | 2,581.1 | 2,527.6 | −2.08% |
3224
+ | Server readiness, ms | 723.5 | 1,016.1 | +40.45% |
3225
+ | Cold start, ms | 2,244.1 | 2,094.7 | −6.66% |
3226
+ | Peak RSS, MiB | 9,744.6 | 10,042.8 | +3.06% |
3227
+
3228
+ All 60 requests complete without failures with matching request bodies and token
3229
+ budgets. Single-request text and raw completion/chat probes match. Three of four
3230
+ concurrent responses differ across implementations; each implementation repeats
3231
+ exactly, including usage. Shared cached requests reuse 668 tokens, versus zero.
3232
+ Mean cold-start improvement is within substantial variation: candidate arms are
3233
+ 1.712 and 2.478 seconds. Readiness regresses by 293 ms; strict startup dominance
3234
+ remains open. These numbers compare implementations with the same assistant,
3235
+ not assistant speculation versus ordinary decoding. Defaults are unchanged.
3236
+
3237
+ Both-machine e4b/12B graph and serving/cache tests pass; e4b matches unmodified
3238
+ optiq `spec_generate` end to end. The pinned 12B loader lacks tensor-presence head
3239
+ detection, so its numerical test explicitly binds the artifact's tied embedding
3240
+ head while retaining upstream layers. Both-machine Qwen MTP/TQ regressions, full
3241
+ suites and all typechecks pass. Evidence:
3242
+ `reports/qwen38-closeout/composition-baseline/assistant-batch/`.
3243
+
3244
+
3245
+ ### Shared DeepSpec drafting, M4 Pro 24 GB, 2026-09-10
3246
+
3247
+ Four `bench-serve.ts all` arms in control/candidate/candidate/control order,
3248
+ Bun 1.4.2, MLX 0.32.2. Gemma4 12B OptiQ4 target with the DeepSpec affine-q4-g64
3249
+ drafter, trained depth seven, bf16 target KV, 2 GiB RAM cache plus temporary SSD,
3250
+ 192 decode tokens, four concurrent requests and default capacity eight. Seed
3251
+ `deepspec-spec-0`; diagnostic mode under Josh's CPU/swap policy. Frozen sources
3252
+ `db38e64dbc3421ba5750485d8d6328afad63b64883bae8b945ff76e0ae6f1f21`
3253
+ → `39b289a30244e8f37bc8457c7e8f4e36deae428340157cd90c3a4c2287610dda`.
3254
+ The candidate adds shared context projections, batched proposals and persisted
3255
+ method companions. Both arms use the same target, drafter and settings.
3256
+
3257
+ | Metric, mean of two arms | Previous implementation | Shared DeepSpec | Change |
3258
+ |---|---:|---:|---:|
3259
+ | Median single-request decode, tok/s | 25.288 | 25.950 | +2.62% |
3260
+ | Four-request aggregate, tok/s | 25.191 | 53.187 | +111.14% |
3261
+ | Four-request wall time, ms | 20,326.0 | 9,626.5 | −52.64% |
3262
+ | Cached prefill, ms | 2,724.6 | 345.1 | −87.33% |
3263
+ | Cold prefill, ms | 2,715.1 | 2,737.0 | +0.81% |
3264
+ | Server readiness, ms | 612.5 | 1,319.1 | +115.37% |
3265
+ | Cold start, ms | 2,509.8 | 2,918.0 | +16.26% |
3266
+ | Peak RSS, MiB | 10,772.8 | 11,057.6 | +2.64% |
3267
+
3268
+ All 60 requests complete without failures and use matching request bodies and
3269
+ budgets. Single-request text and raw completion/chat probes match. One of four
3270
+ concurrent responses differs; both implementations repeat exactly, including
3271
+ usage. Cached requests reuse 671 tokens versus zero. Decode samples within each
3272
+ arm span roughly 15–16%, although the repeated medians agree. The small B1 gain
3273
+ should be read with that variation. Readiness regresses by 707 ms and cold start
3274
+ by 408 ms on average; strict startup dominance remains open. Defaults are unchanged.
3275
+
3276
+ Both-machine bf16/4-bit graph controls, depth-seven serving/generated RAM/SSD,
3277
+ regression suites and all typechecks pass. The graph comparisons preserve the
3278
+ frozen implementation; they are not a new external DeepSpec oracle. Real-window
3279
+ checks confirm active shared speculation across wrap. Evidence:
3280
+ `reports/qwen38-closeout/composition-baseline/deepspec-batch/`.
3281
+
3282
+
3283
+ ### Shared projected-context extraction, M4 Pro 24 GB, 2026-09-10
3284
+
3285
+ Four `bench-serve.ts all` arms, control/candidate/candidate/control, use the same
3286
+ Gemma4 12B OptiQ4 target, trained DeepSpec q4-g64 drafter, depth seven, bf16 target
3287
+ KV, 2 GiB RAM plus temporary SSD, 192 decode tokens, four concurrent requests,
3288
+ default capacity eight and seed `deepspec-spec-0`. Bun 1.4.2, MLX 0.32.2,
3289
+ diagnostic mode under Josh's CPU/swap policy. Frozen sources
3290
+ `39b289a30244e8f37bc8457c7e8f4e36deae428340157cd90c3a4c2287610dda`
3291
+ → `9f8484fa9dca140b31ad685a2701563ed5a1e0a2638d27f48e31d1df4160f4ab`.
3292
+ The candidate extracts context ownership for reuse by DSpark/DFlash and DeepSpec.
3293
+ This measures the extraction with a trained DeepSpec drafter; no trained DSpark
3294
+ checkpoint was available for its own performance comparison.
3295
+
3296
+ | Metric, mean of two arms | DeepSpec-specific owner | Shared context owner | Change |
3297
+ |---|---:|---:|---:|
3298
+ | Median single-request decode, tok/s | 25.800 | 25.695 | −0.41% |
3299
+ | Four-request aggregate, tok/s | 53.597 | 52.229 | −2.55% |
3300
+ | Four-request wall time, ms | 9,552.8 | 9,805.0 | +2.64% |
3301
+ | Cached prefill, ms | 342.2 | 348.3 | +1.79% |
3302
+ | Cold prefill, ms | 2,722.4 | 2,778.2 | +2.05% |
3303
+ | Server readiness, ms | 1,318.4 | 1,421.7 | +7.84% |
3304
+ | Cold start, ms | 2,943.2 | 3,321.3 | +12.85% |
3305
+ | Peak RSS, MiB | 11,070.5 | 11,068.2 | −0.02% |
3306
+
3307
+ All 60 requests complete without failures; every request body, response and usage
3308
+ record matches across all four arms. Cached requests reuse 671 tokens in both.
3309
+ The first control cold start is 2.615 seconds; the other three arms range from
3310
+ 3.272 to 3.337 seconds. Candidate aggregate arms are 52.99 and 51.47 tok/s versus
3311
+ 53.75 and 53.44 controls. The measured cost is retained; this is not a speed win
3312
+ or strict dominance. Defaults are unchanged. Both-machine pinned Markov/RNN and
3313
+ independent confidence/sampling tests, seeded real-Gemma serving/generated RAM/SSD,
3314
+ trained DeepSpec regressions, full suites and typechecks pass. Evidence:
3315
+ `reports/qwen38-closeout/composition-baseline/dflash-batch/`.
3316
+
3317
+
3318
+ ### Reused artifact identity, M4 Pro 24 GB, 2026-09-10
3319
+
3320
+ Four `bench-serve.ts all` arms, control/candidate/candidate/control, use Gemma4 12B
3321
+ OptiQ4, trained DeepSpec q4-g64, depth seven, bf16 target KV, 2 GiB RAM plus temporary
3322
+ SSD, 192 decode tokens, four concurrent requests, default capacity eight and seed
3323
+ `deepspec-spec-0`. Bun 1.4.2, MLX 0.32.2, diagnostic mode under Josh's CPU/swap
3324
+ policy. Frozen sources `9f8484fa9dca140b31ad685a2701563ed5a1e0a2638d27f48e31d1df4160f4ab`
3325
+ → `e17613b8496e5820bb8f4a193e735a4d9129b5333c851886bb22cbd0c9c41bed`.
3326
+ The candidate resolves the same full configuration/name/byte SHA-256 through a
3327
+ shared artifact-identity store. Its unchanged-file memo was populated during
3328
+ native validation. These fresh server starts hit the identity memo; first-ever
3329
+ identity calculation still reads all shard bytes. Memo writes are queued.
3330
+
3331
+ | Metric, mean of two arms | Rehash each load | Reuse unchanged identity | Change |
3332
+ |---|---:|---:|---:|
3333
+ | Median single-request decode, tok/s | 25.881 | 25.975 | +0.37% |
3334
+ | Four-request aggregate, tok/s | 52.449 | 52.831 | +0.73% |
3335
+ | Four-request wall time, ms | 9,761.8 | 9,691.3 | −0.72% |
3336
+ | Cached prefill, ms | 350.0 | 346.1 | −1.12% |
3337
+ | Cold prefill, ms | 2,783.3 | 2,763.5 | −0.71% |
3338
+ | Server readiness, ms | 1,422.2 | 713.1 | −49.86% |
3339
+ | Cold start, ms | 3,332.1 | 2,709.7 | −18.68% |
3340
+ | Peak RSS, MiB | 11,072.1 | 10,784.0 | −2.60% |
3341
+
3342
+ All 60 requests complete without failures; every request body, response and usage
3343
+ record matches across all four arms. Cached requests reuse 671 tokens in both.
3344
+ Candidate readiness is 610/816 ms versus 1,422/1,422 ms; cold start is 2,590/2,829 ms
3345
+ versus 3,345/3,319 ms. Peak RSS decreases by 288.1 MiB on average. Throughput changes
3346
+ are small; the material gain is repeat loading. Sampling, draft-depth and KV
3347
+ defaults are unchanged. Both-machine Qwen MTP/TurboQuant and DeepSpec serving and
3348
+ generated RAM/SSD, complete suites and typechecks pass. Identity tests cover the
3349
+ previous digest, zero weight reads on memo hits, file/config/symlink mutation and
3350
+ failed persistence. Existing KV namespaces remain compatible. Evidence:
3351
+ `reports/qwen38-closeout/composition-baseline/artifact-identity/`.
3352
+
3353
+
3354
+ ### Affine rotating speculation, M4 Pro 24 GB, 2026-09-11
3355
+
3356
+ Six `bench-serve.ts all` arms run control/candidate/KV4/KV4/candidate/control.
3357
+ All use Gemma4 12B OptiQ4 weights, trained DeepSpec q4-g64 at depth seven,
3358
+ 2 GiB RAM plus temporary SSD, 192 decode tokens, four concurrent requests,
3359
+ default capacity eight and seed `deepspec-spec-0`. Bun 1.4.2 and MLX 0.32.2;
3360
+ diagnostic mode follows Josh's background-CPU/swap policy. Control and candidate
3361
+ use bf16 target KV; KV4 changes only that setting on the candidate source.
3362
+ Frozen source hashes are
3363
+ `e17613b8496e5820bb8f4a193e735a4d9129b5333c851886bb22cbd0c9c41bed`
3364
+ and `9f8819cce7c759eab2e86f5ba35e20d99e436491fd46c39966c59048ab44e60d`.
3365
+ Every arm retains its source hash through completion.
3366
+
3367
+ | Metric, mean of two arms | Control bf16 | Candidate bf16 | Candidate KV4 |
3368
+ |---|---:|---:|---:|
3369
+ | Median single-request decode, tok/s | 25.778 | 25.895 | 25.880 |
3370
+ | Four-request aggregate, tok/s | 52.947 | 52.995 | 55.398 |
3371
+ | Four-request wall time, ms | 9,671.7 | 9,661.4 | 9,242.3 |
3372
+ | Cached prefill, ms | 345.7 | 346.5 | 352.9 |
3373
+ | Cold prefill, ms | 2,749.7 | 2,748.8 | 2,814.0 |
3374
+ | Server readiness, ms | 611.5 | 611.7 | 612.1 |
3375
+ | Cold start, ms | 2,600.5 | 2,427.5 | 2,424.3 |
3376
+ | Peak RSS, MiB | 10,775.3 | 10,767.2 | 10,802.8 |
3377
+
3378
+ The source-only comparison is effectively flat: decode +0.45%, aggregate +0.09%,
3379
+ cached prefill +0.22%, cold prefill −0.03%. All 60 bf16 requests have identical
3380
+ request bodies, responses and usage records. Each setting repeats exactly.
3381
+ All 90 requests complete without benchmark failures and reuse 671 cached tokens.
3382
+
3383
+ KV4 reaches +4.63% aggregate throughput versus the bf16 control, with +2.07%
3384
+ cached and +2.34% cold prefill time. Ten of fifteen responses per KV4 arm differ
3385
+ from bf16, and accepted draft tokens total 1,042 versus 1,032. This is a measured
3386
+ precision/configuration tradeoff, not an isolated engine speed gain. Short-run
3387
+ RSS does not establish a memory saving; startup varies within the candidate
3388
+ arms. Defaults remain unchanged. Context/pressure and strict serial-dominance
3389
+ acceptance are not covered by this short comparison. Native tests separately
3390
+ cover generated RAM/SSD restoration, real-window rollback and KV4/KV8 provider
3391
+ composition on both Macs. Evidence:
3392
+ `reports/qwen38-closeout/composition-baseline/rotating-spec-quant/`.
3393
+
3394
+
3395
+ ### TurboQuant provider composition and centroid correction, M4 Pro 24 GB, 2026-09-11
3396
+
3397
+ Two six-arm `bench-serve.ts all` comparisons use
3398
+ control/candidate/TQ/TQ/candidate/control. Both use Bun 1.4.2, MLX 0.32.2,
3399
+ 192 decode tokens, four concurrent requests, capacity eight, 2 GiB RAM plus
3400
+ temporary SSD and fused TQ decoding enabled. Control/candidate target KV is
3401
+ bf16; the TQ arms select K8/V3 on the candidate. The CLI keeps start zero;
3402
+ sliding layers remain bf16. Diagnostic mode follows Josh's CPU/swap policy.
3403
+ Sources stay fixed through every arm:
3404
+ `9f8819cce7c759eab2e86f5ba35e20d99e436491fd46c39966c59048ab44e60d`
3405
+ → `f4c9fe17c9f0a691907ded7777e7814cc5eaed7811ac9941b4d1528ad75070bd`.
3406
+
3407
+ The candidate adds owned TQ donor attention and capability-based grouped draft
3408
+ selection, captures immutable numerical options and distinct per-layer cache
3409
+ identities, and corrects the small assistant's centroid head to the pinned
3410
+ bf16 multiply/sum arithmetic and lowest-token-ID tie rule. The independent M1
3411
+ oracle exposed the previous matmul shortcut; its decoded KV and hidden state
3412
+ were exact but its selected token differed. This correction applies at every B.
3413
+
3414
+ #### Gemma4 12B + trained DeepSpec
3415
+
3416
+ OptiQ4 target weights, q4-g64 DeepSpec block7, draft depth seven and seed `deepspec-spec-0`.
3417
+
3418
+ | Metric, mean of two arms | Control bf16 | Candidate bf16 | Candidate K8/V3 |
3419
+ |---|---:|---:|---:|
3420
+ | Median single-request decode, tok/s | 25.912 | 25.428 | 26.749 |
3421
+ | Four-request aggregate, tok/s | 53.635 | 51.962 | 54.258 |
3422
+ | Four-request wall time, ms | 9,546.956 | 9,854.496 | 9,436.373 |
3423
+ | Cached prefill, ms | 341.823 | 343.041 | 352.446 |
3424
+ | Cold prefill, ms | 2,688.505 | 2,758.072 | 2,772.306 |
3425
+ | Server readiness, ms | 616.147 | 616.509 | 610.971 |
3426
+ | Cold start, ms | 2,604.734 | 2,604.987 | 2,612.562 |
3427
+ | Peak RSS, MiB | 10,784.125 | 10,762.719 | 10,780.617 |
3428
+
3429
+ Source-only bf16 decode decreases 1.87% and aggregate throughput decreases
3430
+ 3.12%; cached prefill is +0.36%, cold prefill +2.59%. All 60 bf16 requests have
3431
+ identical bodies, responses and usage. The cost remains recorded and is under
3432
+ separate attribution testing. It is not a refactor speed win.
3433
+
3434
+ K8/V3 increases decode 3.23% and aggregate throughput 1.16% versus the old bf16
3435
+ control, with cached and cold prefill each about 3.1% slower. Nine of fifteen
3436
+ responses per TQ arm differ from bf16. Accepted draft tokens total 1,044 versus
3437
+ 1,032. Each TQ repeat matches its own responses and usage exactly.
3438
+
3439
+ #### Gemma4 e4b + assistant
3440
+
3441
+ OptiQ4 target weights, bf16 assistant, draft depth three and seed `assistant-spec-0`.
3442
+
3443
+ | Metric, mean of two arms | Control bf16 | Candidate bf16 | Candidate K8/V3 |
3444
+ |---|---:|---:|---:|
3445
+ | Median single-request decode, tok/s | 55.374 | 55.106 | 57.532 |
3446
+ | Four-request aggregate, tok/s | 94.152 | 93.340 | 91.267 |
3447
+ | Four-request wall time, ms | 5,438.005 | 5,485.344 | 5,609.896 |
3448
+ | Cached prefill, ms | 88.692 | 89.947 | 92.351 |
3449
+ | Cold prefill, ms | 962.402 | 960.880 | 967.007 |
3450
+ | Server readiness, ms | 621.475 | 610.243 | 611.252 |
3451
+ | Cold start, ms | 1,309.033 | 894.498 | 906.810 |
3452
+ | Peak RSS, MiB | 6,880.625 | 6,889.672 | 6,929.180 |
3453
+
3454
+ The centroid correction and interface changes decrease bf16 decode 0.49%
3455
+ and aggregate throughput 0.86%. All bf16 response text is unchanged, while
3456
+ draft-acceptance usage changes: 530 accepted tokens per candidate arm versus
3457
+ 532 in each control. Each arm repeats its own response and usage exactly.
3458
+ The first control cold start is 1,726 ms; all later arms are 888–914 ms, so
3459
+ the mean startup difference is not attributed to this change.
3460
+
3461
+ K8/V3 increases decode 3.90% versus the old bf16 control but decreases aggregate
3462
+ throughput 3.06%; cached prefill is +4.13%, cold prefill +0.48%. Nine of fifteen
3463
+ responses per TQ arm differ from bf16, and draft acceptance totals 557.
3464
+ The TQ arms repeat exactly. This setting benefits single-request decode on
3465
+ this workload and loses concurrent throughput.
3466
+
3467
+ All 180 requests complete without benchmark failures. Cached requests retain
3468
+ 671 tokens for 12B and 668 for e4b. These are short configuration tradeoffs, not
3469
+ long-context memory or pressure acceptance. Defaults remain unchanged and strict
3470
+ serial dominance stays open. Both-machine native coverage includes assistant,
3471
+ DeepSpec, standalone and lookup serving/generated RAM/SSD, delayed conversion,
3472
+ independent assistant codec/graph controls, seeded DSpark heads and Qwen MTP
3473
+ regressions; the final suites and typechecks pass. Evidence and source manifests:
3474
+ `reports/qwen38-closeout/composition-baseline/turboquant-donor/`.
3475
+
3476
+ ### TurboQuant option-capture attribution (M4 Pro, 2026-09-11)
3477
+
3478
+ Same Gemma4-12B/DeepSpec7 workload and settings as the TurboQuant composition comparison above, all using bf16 KV. The sequence isolates request-option capture from numerical kernels. Frozen integrated source `f4c9fe17…` is unchanged; the key-restored variant is `cb063841…`, and the shallow-clone/conditional-assignment variant is `09e02ca6…`.
3479
+
3480
+ | Arm, in execution order | Decode median tok/s | Aggregate tok/s | Cached TTFT ms | Cold TTFT ms |
3481
+ |---|---:|---:|---:|---:|
3482
+ | deep-key-ablation-1 | 25.898 | 53.222 | 343.92 | 2728.18 |
3483
+ | deep-candidate-attribution-1 | 25.899 | 52.984 | 346.27 | 2748.01 |
3484
+ | deep-options-capture-1 | 25.910 | 53.942 | 339.04 | 2640.71 |
3485
+ | deep-candidate-attribution-2 | 25.897 | 53.063 | 346.38 | 2752.70 |
3486
+ | deep-options-capture-2 | 25.895 | 52.690 | 350.81 | 2769.67 |
3487
+
3488
+ The unchanged integrated build recovered the original decode rate on both repeats. Neither key restoration nor the option-copy variant establishes a repeatable speed benefit; retain the integrated implementation. The earlier measured source-only costs remain recorded, but attributing them to a code regression is not supported by these repeats. All five arms retain five distinct decode samples (reported within-arm spread about 1.15–1.16); these medians are comparisons of that fixed workload, not five identical requests. Raw requests, source identities and comparison: `reports/qwen38-closeout/composition-baseline/turboquant-donor/{m4,performance-attribution.json}`.
3489
+
3490
+ ### Delayed/per-layer affine rotating speculation (M4 Pro, 2026-09-11)
3491
+
3492
+ Gemma4-12B OptiQ-4bit with the q4 DeepSpec block-7 drafter, depth seven, Bun 1.4.2/MLX 0.32.2, 192 decode tokens, four concurrent requests, scheduler capacity eight, 2 GiB RAM prompt cache plus temporary SSD. Same `deepspec-spec-0` workload as the previous composition comparison. Order: control bf16, candidate bf16, candidate per-layer, candidate per-layer, candidate bf16, control bf16. The control source is `f4c9fe17…`; candidate `072bf3ca…`. All six source snapshots remain fixed through completion.
3493
+
3494
+ | Setting (mean of two arms) | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Ready ms | Startup ms | Peak RSS MiB |
3495
+ |---|---:|---:|---:|---:|---:|---:|---:|---:|
3496
+ | control | 25.898 | 53.455 | 9579.865 | 344.315 | 2696.925 | 616.786 | 2603.127 | 10795.445 |
3497
+ | candidate | 25.713 | 53.643 | 9545.352 | 339.185 | 2680.571 | 614.743 | 2544.107 | 10775.914 |
3498
+ | per-layer | 27.430 | 52.456 | 9760.580 | 353.531 | 2655.698 | 616.945 | 2544.832 | 10816.516 |
3499
+
3500
+ Source-only bf16 comparison: decode −0.716%, aggregate +0.353%, cached TTFT −1.490%, cold TTFT −0.606%. Every bf16 request, response and usage record matches. The first candidate decode median is lower than its second repeat; the small source-only cost remains recorded and does not satisfy strict B1 dominance.
3501
+
3502
+ Model-defined mixed per-layer affine KV versus control bf16: decode +5.916%, aggregate −1.868%, cached TTFT +2.677%, cold TTFT −1.529%. Ten of fifteen responses differ from bf16; each configuration repeats exactly, including usage. All ninety requests complete with no phase failures. Precision changes affect the numerical trajectory and draft acceptance, so this setting comparison is not an engine-only same-output speedup. Defaults remain unchanged.
3503
+
3504
+ Both-machine native serving/generated RAM/SSD, delayed transition and real-window hidden/logit controls pass for the qualified providers. Seeded DSpark fixtures establish Markov/RNN execution and state contracts, not trained quality or acceptance. Raw arms and exact pair comparisons: `reports/qwen38-closeout/composition-baseline/delayed-rotating-spec/{m4,benchmark-comparison.json}`.
3505
+
3506
+
3507
+ ### Paged storage in the shared executor (M4 Pro, 2026-09-11)
3508
+
3509
+ Gemma4-12B OptiQ-4bit, bf16 KV, Bun 1.4.2/MLX 0.32.2, 192 decode tokens, four concurrent requests, 2 GiB RAM cache plus temporary SSD, workload `paged-compose-0`. Paged storage uses 256-token blocks and bypasses both cache tiers. The ordinary source comparison keeps continuous scheduling on both sides. The paged comparison uses the old serial executor versus the candidate shared executor (capacity eight). Frozen source: control `db451918…`, candidate `a9fe941c…`; both include identical benchmark argument plumbing. Each configuration runs twice, with reversed control/candidate order. All source snapshots remain fixed.
3510
+
3511
+ | Configuration (mean of two arms) | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Repeated-prompt TTFT ms | Cold TTFT ms | Ready ms | Startup ms | Peak RSS MiB |
3512
+ |---|---:|---:|---:|---:|---:|---:|---:|---:|
3513
+ | Ordinary control | 26.455 | 72.894 | 7023.933 | 153.036 | 2436.522 | 616.814 | 1452.364 | 8936.141 |
3514
+ | Ordinary candidate | 26.480 | 72.913 | 7022.101 | 154.218 | 2437.542 | 613.202 | 1588.357 | 8946.594 |
3515
+ | Paged serial control | 26.310 | 24.832 | 20618.569 | 2462.690 | 2443.653 | 613.156 | 1425.283 | 8915.117 |
3516
+ | Paged shared candidate | 26.289 | 70.240 | 7289.413 | 2490.439 | 2479.725 | 611.401 | 1218.411 | 8940.664 |
3517
+
3518
+ Ordinary source cost is effectively flat: decode +0.094%, aggregate +0.026%, cold TTFT +0.042% and cached TTFT +0.772%. Every paired response and usage record is identical. Startup varies more (+9.36% in the two-arm mean); this short comparison does not establish startup dominance.
3519
+
3520
+ Shared paged execution increases four-request throughput **182.86% (2.83×)** and reduces task wall time **64.65%**. Single-request decode changes −0.081%; cold TTFT increases 1.48% and repeated-prompt TTFT 1.13%. The first concurrent request reaches output in 365.84 versus 365.86 ms. Peak RSS increases 25.55 MiB. Two concurrent responses differ from serial in each pair; all single-request responses and token counts match. Every configuration repeats its own text and usage exactly. The repeated paged prompt restores zero tokens, as expected; ordinary restores 669. This is concurrent execution scaling, not a single-request decode-kernel speedup.
3521
+
3522
+ Eight successful arms complete 120 requests without phase failures. Four earlier paged setup attempts failed before readiness because the harness enables SSD while `--prompt-cache 0` disables its required RAM tier; those reports remain in the evidence, and both paged sides were rerun with the same 2 GiB setting. The machine retained about 1.65 GiB swap with 91% free memory and no competing GPU job; diagnostic mode follows Josh's campaign policy.
3523
+
3524
+ The long native comparison initially allowed ordinary cache snapshots to change prefill cohort/query boundaries while paging bypassed them. Holding arrivals alone did not equalize that graph. The corrected storage comparison holds arrivals and disables snapshot splitting on both sides; it checks full logits and tokens beyond the default block boundary. Separate HTTP coverage checks sampling, logprobs and grammar. Raw arms, source manifest, setup failures and exact request comparisons: `reports/qwen38-closeout/composition-baseline/paged-rows/`. Direct paged attention, block sharing and composed quantized/speculative paging remain open; defaults are unchanged.
3525
+
3526
+
3527
+ ### Adapter-qualified prompt lookup (M4 Pro, 2026-09-11)
3528
+
3529
+ Gemma4 e4b OptiQ-4bit with the existing `upper` LoRA adapter (weights SHA-256 `94f83569ba85df9e05557238809101cd19f9eabd0149c7931904e2a58774a05b`), bf16 KV, Bun 1.4.2/MLX 0.32.2, scheduler capacity eight, 192 decode tokens, four concurrent requests, 2 GiB RAM cache plus temporary SSD. Same `adapter-lookup-0` request bodies in every arm. Frozen control `a9fe941c…` and candidate `cce6e1e6…`; two repetitions per configuration in reversed control/candidate order.
3530
+
3531
+ The ordinary arms omit draft flags and isolate source cost. The lookup arms request ngram depth three: the old control disables speculation for adapters, while the candidate honors it through the grouped provider capability. This second comparison therefore measures newly enabled behavior.
3532
+
3533
+ | Configuration (mean of two arms) | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Ready ms | Startup ms | Peak RSS MiB |
3534
+ |---|---:|---:|---:|---:|---:|---:|---:|---:|
3535
+ | ordinary-control | 53.888 | 159.078 | 3218.551 | 38.040 | 526.635 | 610.894 | 893.690 | 6751.648 |
3536
+ | ordinary-candidate | 53.800 | 158.943 | 3221.290 | 38.246 | 523.882 | 610.938 | 893.021 | 6763.688 |
3537
+ | lookup-control | 53.746 | 159.064 | 3218.837 | 38.244 | 524.087 | 611.516 | 951.899 | 6731.523 |
3538
+ | lookup-candidate | 53.136 | 78.537 | 6519.231 | 30.925 | 518.250 | 611.589 | 945.210 | 6766.641 |
3539
+
3540
+ Ordinary source cost is effectively flat: decode −0.163%, aggregate −0.085%, cold TTFT −0.523% and cached TTFT +0.543%. Every ordinary response and usage record matches across source versions.
3541
+
3542
+ Enabling lookup decreases single-request decode 1.14% and four-request throughput **50.63%**, increasing aggregate wall time **102.53%**. It lowers cached TTFT 19.14%. Each concurrent block accepts only 26 of 444 proposed tokens (5.86%); repeated rejection makes this configuration a poor throughput choice. Concurrent cached prefixes also change from 11 tokens under ordinary execution to zero under the paired lookup namespace. That small prefill difference does not establish the cause of the decode cost.
3543
+
3544
+ Eight of fifteen responses change with the enabled method, including five single-request decode probes and three concurrent responses; token counts and finish reasons match. Each configuration repeats its own responses and usage exactly. All 120 requests complete without phase failures. This is not a same-output speed gain and does not justify a default change. A stricter ngram-match screen follows separately.
3545
+
3546
+ Native composition checks cover bf16/KV4 and TurboQuant, compatible adapter cohorts, seeded logprobs, namespace replacement, callback failure and generated RAM/SSD restart identity on both Macs. The HTTP fixture explicitly checks token alignment with the generated SSD header: appending an extra newline changes the M4 KV4 boundary, so the original fixture correctly reused an earlier prompt checkpoint. Preserving the generated newline restores the complete generated boundary; no cache assertion was relaxed. Raw arms, source manifest and request comparison: `reports/qwen38-closeout/composition-baseline/adapter-lookup/`.
3547
+
3548
+
3549
+ ### Ngram match-length screen with the upper adapter (M4 Pro, 2026-09-11)
3550
+
3551
+ Same e4b/upper-adapter artifact, bf16 KV, depth three, cache settings and `adapter-lookup-0` workload as above. Source `ef832276…` differs only by adding benchmark forwarding for the existing `--ngram-min`/`--ngram-max` flags. Order is 1–3, 2–3, 3–3, 5–5, then the reverse. Each arm retains five decode samples; table values are means of the two arm medians for decode and means for other timings.
3552
+
3553
+ | Minimum–maximum match | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Aggregate accepted/proposed, arm A |
3554
+ |---|---:|---:|---:|---:|---:|---:|
3555
+ | min1-max3 | 53.949 | 78.566 | 6516.923 | 30.535 | 529.999 | 39/455 |
3556
+ | min2-max3 | 56.532 | 115.274 | 4442.253 | 47.959 | 537.508 | 26/90 |
3557
+ | min3-max3 | 53.552 | 130.850 | 3913.573 | 47.439 | 533.417 | 17/30 |
3558
+ | min5-max5 | 50.495 | 134.898 | 3796.100 | 47.561 | 525.433 | 20/24 |
3559
+
3560
+ Requiring longer matches avoids many rejected proposals. Minimum two has the highest single-request decode in this screen; minimum five has the highest aggregate throughput. Neither dominates ordinary execution from the adjacent matched campaign (about 53.8 decode and 159 aggregate tok/s). Minimum two improves single-request decode but still gives up concurrent throughput; minimum five lowers both decode and aggregate throughput versus ordinary. Lookup stays opt-in; these results do not establish a global match-length default.
3561
+
3562
+ Three concurrent responses/usage records differ between the minimum-one repeats (39/455 versus 26/444 accepted/proposed); their aggregate timings remain close. The other settings repeat their own responses and usage exactly. Different match thresholds change response trajectories, so the timing differences are configuration results, not same-output engine speedups. All eight arms complete 120 requests without phase failures. Raw commands, request hashes, source identity and comparisons: `reports/qwen38-closeout/composition-baseline/ngram-settings/`.
3563
+
3564
+
3565
+ ### Independent greedy sampling across verification positions (M4 Pro, 2026-09-11)
3566
+
3567
+ Apple M4 Pro, 24 GB, Bun 1.4.2, MLX 0.32.2. Twelve matched `bench-serve.ts all` arms compare frozen control `ef832276f7a43d2a203e8d8e4b41c362459bf55d7389803af18ca8e995c83838` with candidate `22d1a38a761ea28c0dcd3ec90374a6a6931bbd9d2965bb7c64a65458aae45398`. Gemma e4b OptiQ with the upper adapter, bf16 KV, scheduler capacity eight, four concurrent requests, 192 decode tokens, 2 GiB prompt cache plus SSD, workload seed `adapter-lookup-0`. Each setting runs control/candidate/candidate/control. Diagnostic mode follows Josh's CPU/swap policy; retained swap and background App Store CPU activity are recorded in raw reports.
3568
+
3569
+ The sampler exposes a stateless operation for compatible greedy rows. Ordinary decode and speculative verification share normalized-score argmax; verification reads its independent token rectangle once. Grammar, processors, stochastic sampling, logprobs and custom sampler functions retain request-local sampling. Tests include rounding-created ties where raw-logit argmax would choose a different token.
3570
+
3571
+ Means of the two arm medians for single-request decode/cold latency; means of the two measured aggregate/cached values:
3572
+
3573
+ | Method | Decode control → candidate, tok/s | Aggregate control → candidate, tok/s | Aggregate change | Cached TTFT control → candidate, ms | Cold TTFT control → candidate, ms |
3574
+ |---|---:|---:|---:|---:|---:|
3575
+ | Ordinary | 54.198 → 54.278 | 162.724 → 162.721 | −0.002% | 38.378 → 37.283 | 530.258 → 522.210 |
3576
+ | Lookup depth 3, min/max 1/3 | 55.101 → 54.898 | 79.716 → 80.779 | +1.334% | 30.760 → 30.517 | 518.664 → 516.427 |
3577
+ | Lookup depth 3, min/max 5/5 | 51.405 → 51.712 | 136.141 → 138.956 | +2.067% | 47.652 → 47.348 | 539.549 → 536.417 |
3578
+
3579
+ Ordinary decode changes +0.148%; lookup 1/3 changes −0.368%, and lookup 5/5 changes +0.598%. Aggregate wall time changes +0.002%, −1.319% and −2.025%, respectively. Startup changes +0.045%, +10.505% and −7.777%, while ready time stays within 0.3%; the small source change does not establish startup dominance. Peak RSS changes −0.321%, −0.248% and +0.413%.
3580
+
3581
+ All 180 requests succeed and every arm retains its source hash. The first paired comparisons preserve every response and usage record. Ordinary and 5/5 repeats are exact, as are both candidate 1/3 runs. The 1/3 control repeat changes three concurrent responses and speculation usage; it is not an exact repeated trajectory. The stricter lookup setting still loses aggregate throughput to ordinary decoding, so no lookup default changes. Both-machine numerical, full-suite/typecheck and adapter native/generated RAM/SSD checks pass. Raw commands, source inventories, results and response comparisons are under `reports/qwen38-closeout/composition-baseline/independent-sampling/`.
3582
+
3583
+
3584
+ ### Shared ordinary checkpoints and queued persistence (M4 Pro, 2026-09-11)
3585
+
3586
+ Apple M4 Pro, 24 GB, Bun 1.4.2, MLX 0.32.2. Ten matched `bench-serve.ts all` arms compare frozen control `6ab45ad7bda4adf9760eb69312bbf1dacdb8fe17592df9bc8f5699e7c8b692a9` with candidate `4dcf90668b7a319538ba648de196b72d81a8a26aa1bcef7d45ba5ce4f393c6e8`. Gemma e4b OptiQ, bf16 KV, no adapter, 192 decode tokens, four concurrent requests, 2 GiB prompt cache plus SSD, workload seed `ordinary-continuation-0`. Shared scheduler capacity is eight. Ordinary arms run control/candidate/candidate/control; checkpoint interval 64 runs old serial/new serial/new shared/new shared/new serial/old serial. Diagnostic mode follows Josh's CPU/swap policy; retained swap and background App Store CPU activity are recorded.
3587
+
3588
+ The candidate shares ordinary restore/capture through a checkpoint-policy interface and queues owned SSD snapshots through the existing idle gate. Completion invalidates the checkpoint immediately and queues ordered disk cleanup. Means of the two arm medians for decode/cold latency; means of aggregate/cached measurements:
3589
+
3590
+ | Execution | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms |
3591
+ |---|---:|---:|---:|---:|---:|
3592
+ | Ordinary control | 59.401 | 169.043 | 3028.808 | 67.649 | 551.692 |
3593
+ | Ordinary candidate | 59.258 | 168.873 | 3031.856 | 67.720 | 553.158 |
3594
+ | Checkpoint, old serial | 58.702 | 57.265 | 8940.938 | 67.800 | 559.996 |
3595
+ | Checkpoint, queued serial | 59.011 | 57.458 | 8910.919 | 67.758 | 565.658 |
3596
+ | Checkpoint, queued shared | 58.905 | 168.159 | 3044.730 | 67.975 | 566.320 |
3597
+
3598
+ The ordinary source comparison changes decode −0.241%, aggregate throughput −0.101%, cached TTFT +0.105%, cold TTFT +0.266%, startup +0.480% and peak RSS +0.084%. Queuing serial persistence changes decode +0.526%, aggregate +0.337%, cold TTFT +1.011% and peak RSS −1.141% versus old serial. Moving checkpoint-enabled requests from queued serial to shared execution raises aggregate throughput **192.667% (2.927×)** and reduces aggregate wall time **65.831%**; single-request decode changes −0.179%, cached TTFT +0.321%, cold TTFT +0.117%, startup +0.648% and peak RSS +0.239%. This establishes concurrent throughput improvement on this workload, with the small single-request costs recorded.
3599
+
3600
+ All 150 requests succeed, source hashes stay fixed, and each arm repeats its own response/usage records exactly. Ordinary source and queued-serial comparisons preserve all responses and usage. Shared versus queued serial changes one concurrent response; all 15 usage records report the different execution lane and three concurrent requests reuse 11 rather than 13 prompt tokens. Other usage fields match. These timed requests complete normally; separate both-machine native and HTTP interruption/flush/fresh-server checks establish exact checkpoint restoration at matching batch geometry, including compiled and mixed-grammar bf16 controls. Those checks found a resumed shared cached-token counter could include replayed output; its clamp is under validation in the subsequent quantized candidate and is not part of this frozen timing source. This is not a process-crash durability or full Kanban acceptance result. Raw commands, source inventory and comparisons: `reports/qwen38-closeout/composition-baseline/ordinary-continuation-composition/`.
3601
+
3602
+ ### Shared ordinary continuation composition (M4 Pro, 2026-09-11)
3603
+
3604
+ Eight completed `bench-serve.ts all` arms on the Apple M4 Pro, 24 GB, Bun 1.4.2 and MLX 0.32.2. Gemma e4b OptiQ, no adapter, 192 decode tokens, four concurrent requests, scheduler capacity eight, 2 GiB RAM cache plus temporary SSD, checkpoint interval 64 and workload seed `ordinary-continuation-0`. Diagnostic mode follows Josh's campaign policy. Frozen control `4dcf90668b7a319538ba648de196b72d81a8a26aa1bcef7d45ba5ce4f393c6e8` and candidate `c918d6e76e702f86d66f17095f33f0aa00d912e8c7f4a469e9992dfbe90a03a0` run control/candidate/KV4/TurboQuant, then the reverse. Context sweeps are omitted in this short comparison.
3605
+
3606
+ The candidate composes ordinary continuation with shared cache layouts, fixes resumed cached-token accounting and the pending-token dtype, and materializes Gemma's model constants before compiler capture. Separate native/HTTP tests cover actual interruption and restoration; the timed requests complete normally. Decode and cold latency are means of arm medians; other columns are means of the two arms.
3607
+
3608
+ | Shared checkpoint configuration | Decode tok/s | Aggregate tok/s | Aggregate wall ms | Cached TTFT ms | Cold TTFT ms | Startup ms | Peak RSS MiB |
3609
+ |---|---:|---:|---:|---:|---:|---:|---:|
3610
+ | Control, bf16 KV | 59.186 | 168.196 | 3044.070 | 67.724 | 556.523 | 904.388 | 6751.820 |
3611
+ | Candidate, bf16 KV | 59.034 | 168.304 | 3042.116 | 67.836 | 558.943 | 908.403 | 6738.312 |
3612
+ | Candidate, affine KV4 | 58.286 | 164.636 | 3109.894 | 70.515 | 564.785 | 916.674 | 6768.227 |
3613
+ | Candidate, TurboQuant k8v3 | 57.197 | 165.002 | 3102.993 | 71.260 | 559.206 | 899.109 | 6744.930 |
3614
+
3615
+ At unchanged bf16 settings, decode changes −0.256%, aggregate throughput +0.064%, cached TTFT +0.166% and cold TTFT +0.435%. This is effectively flat performance. All source-comparison responses and usage records match. All four configurations repeat their own responses and usage exactly, all 120 requests succeed without phase failures, and every source hash remains fixed.
3616
+
3617
+ Compared with candidate bf16, KV4 changes decode −1.267% and aggregate throughput −2.179%; TurboQuant changes decode −3.112% and aggregate throughput −1.962%. KV4 changes ten response texts and TurboQuant nine, with unchanged usage records. These short-context settings do not improve speed or establish a memory advantage from peak RSS. They remain configuration tradeoffs rather than new defaults. Raw arms and derived response/timing comparisons: `reports/qwen38-closeout/composition-baseline/ordinary-continuation-final/`.