mlx-bun 0.0.13 → 0.2.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.
- package/README.md +31 -21
- package/bin/mlx-bun.mjs +1 -1
- package/docs/{design → archive}/hlg-sampling.md +3 -3
- package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
- package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
- package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
- package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
- package/docs/design/colibri-glm52-port.md +1 -1
- package/docs/design/compat-cli-surface-design.md +1 -1
- package/docs/design/decode-speed-program.md +1 -1
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dspark-serving-program.md +1 -1
- package/docs/design/dspark-speculative-decoding.md +53 -3
- package/docs/design/grammar-spec-batching-integration.md +1 -1
- package/docs/design/mlx-lm-serving-execution-seam.md +81 -0
- package/docs/design/orpo-dynamic-lambda.md +1 -1
- package/docs/design/orpo-future-enhancements.md +1 -1
- package/docs/design/orpo-training.md +2 -2
- package/docs/design/parity-tier-dag.md +1 -1
- package/docs/design/repo-cleanup-plan.md +46 -4
- package/docs/design/segmented-backward-training.md +2 -2
- package/docs/design/ssd-kv-cold-tier.md +127 -0
- package/docs/design/turboquant-weights.md +467 -0
- package/docs/design/w4a16-compute-precision-spike.md +1 -1
- package/docs/design/web-chat-redesign.md +5 -5
- package/docs/planning/chunk-task-roadmap.md +1 -1
- package/docs/planning/curve-sampler-research-plan.md +4 -4
- package/docs/planning/memory-docs-and-dag-plan.md +1 -1
- package/docs/planning/release-notes-v0.2.0.md +49 -0
- package/docs/planning/video-series.md +421 -0
- package/docs/reference/cli.md +15 -4
- package/docs/reference/distribution.md +1 -0
- package/docs/reference/features-matrix.md +3 -2
- package/docs/reference/library-api.md +41 -1
- package/docs/reference/models.md +33 -0
- package/docs/reference/server-api.md +69 -14
- package/docs/reference/server-config.md +57 -33
- package/package.json +2 -2
- package/src/anthropic.ts +92 -3
- package/src/cli.ts +131 -36
- package/src/eval/kl.ts +27 -20
- package/src/eval/runner.ts +23 -4
- package/src/eval/tasks/bfcl.ts +2 -1
- package/src/eval/tasks/gsm8k.ts +2 -1
- package/src/eval/tasks/hashhop.ts +2 -1
- package/src/eval/tasks/humaneval.ts +5 -4
- package/src/eval/tasks/ifeval.ts +2 -1
- package/src/eval/tasks/mmlu.ts +2 -1
- package/src/expert-io.ts +3 -1
- package/src/expert-offload.ts +3 -1
- package/src/expert-trace.ts +3 -1
- package/src/fit.ts +24 -43
- package/src/flags.ts +7 -9
- package/src/generate.ts +107 -92
- package/src/grammar.ts +2 -1
- package/src/harness-pi.ts +1 -1
- package/src/index.ts +20 -0
- package/src/jobs/job-entry.ts +3 -2
- package/src/kv-scheme.ts +199 -0
- package/src/kv-store.ts +370 -205
- package/src/media-fetch.ts +19 -3
- package/src/memory/model.ts +2 -1
- package/src/memory/vault.ts +2 -1
- package/src/memory-plan.ts +18 -0
- package/src/mlx/ffi.ts +8 -11
- package/src/mlx/ops.ts +31 -6
- package/src/model/batched-mask.ts +1 -1
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +43 -97
- package/src/model/batched-rotating-state.ts +73 -0
- package/src/model/batched-rotating.ts +56 -105
- package/src/model/batched-row-storage.ts +127 -0
- package/src/model/compiled-decode.ts +3 -2
- package/src/model/factory.ts +44 -49
- package/src/model/gemma4-base.ts +163 -10
- package/src/model/generated/gemma4-12b.ts +50 -146
- package/src/model/generated/gemma4-26b.ts +32 -92
- package/src/model/generated/gemma4-e4b.ts +26 -74
- package/src/model/glm52-cache.ts +19 -9
- package/src/model/glm52-memory.ts +28 -1
- package/src/model/minicpm5.ts +2 -1
- package/src/model/profile.ts +433 -0
- package/src/model/qwen3-delta.ts +98 -2
- package/src/model/qwen3-mrope.ts +252 -0
- package/src/model/qwen3_5.ts +217 -25
- package/src/native/frame_extract.swift +140 -0
- package/src/native-pack.ts +13 -6
- package/src/pi-web.ts +6 -5
- package/src/prompt-cache.ts +2 -2
- package/src/quantize/atomic-output.ts +38 -0
- package/src/quantize/calibration.ts +2 -1
- package/src/quantize/config-writer.ts +6 -0
- package/src/quantize/index.ts +28 -1
- package/src/quantize/job.ts +11 -0
- package/src/quantize/quantizer.ts +265 -100
- package/src/quantize/rotate.ts +603 -0
- package/src/quantize/safetensors-writer.ts +79 -1
- package/src/quantize/sensitivity.ts +41 -59
- package/src/quantize/weight-transform.ts +292 -0
- package/src/responses.ts +102 -2
- package/src/runtime-config.ts +67 -0
- package/src/sampler.ts +272 -0
- package/src/serve/admin-routes.ts +184 -0
- package/src/serve/aux-routes.ts +132 -0
- package/src/serve/batch-scheduler.ts +200 -87
- package/src/serve/completion-executor.ts +346 -0
- package/src/serve/completion-sink.ts +157 -0
- package/src/serve/discovery-routes.ts +205 -0
- package/src/serve/generation-gateway.ts +116 -109
- package/src/serve/kv-budget.ts +14 -0
- package/src/serve/lab-routes.ts +338 -0
- package/src/serve/model-admin-routes.ts +153 -0
- package/src/serve/prompt-response-trace.ts +147 -0
- package/src/serve/request-plan.ts +158 -0
- package/src/serve/static-routes.ts +101 -0
- package/src/server.ts +704 -1400
- package/src/spec/dflash-source.ts +2 -1
- package/src/spec/dspark/module-dflash.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +8 -0
- package/src/spec/qwen-mtp-source.ts +431 -0
- package/src/spec/serve-loop.ts +36 -68
- package/src/ssd-cache.ts +17 -14
- package/src/ssd-durability.ts +195 -0
- package/src/train/flash-cce.ts +12 -11
- package/src/train/forward.ts +32 -1
- package/src/train/loss.ts +2 -1
- package/src/train/segmented.ts +4 -3
- package/src/train/trainer.ts +3 -2
- package/src/vision/preprocess.ts +1 -1
- package/src/vision/prompt.ts +47 -1
- package/src/vision/qwen3vl-preprocess.ts +409 -0
- package/src/vision/qwen3vl-prompt.ts +196 -0
- package/src/vision/qwen3vl-tower.ts +513 -0
- package/src/vision/video-frames.ts +148 -0
- package/src/web/app.js +10 -3
- package/src/web/src/chat.ts +12 -5
- package/src/weights.ts +81 -26
- /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
- /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/bisector-route.json +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/bisector-trace.json +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/curve-terrain.json +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/curve-terrain.svg +0 -0
- /package/docs/{investigations → archive/investigations}/curve-terrain.html +0 -0
- /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
- /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-ab.html +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-explorer.html +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/cliff.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/cross.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/edges.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/k20-grids.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/k20-peaks.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/lw-curve.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/terrain.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-report.html +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-ab.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-blind-prompts.md +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-blind.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-cliff.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-cross.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-edge.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-eval1.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-frontier.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-grid.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-grid2.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-lw-coarse.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-map.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/run0-original.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runA-recommended.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAA-cliff-cpm5.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAB-grid2-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAC-peak-e4b-partial.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAD-ab-samples.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAE-edge-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAF-logit-calibration.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAG-eval-config2.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runB-gain-variants.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runC-pivots.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runD-oetf.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runE-eotf.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runF-shaper-working.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runG-shaper-sweep.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runH-wsweep.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runI-asweep.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runJ-knobmap.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runK-frontier.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runL-widemap.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runM-frontier-emb.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runN-verify.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runO-frontier-seed5000.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runP-grid-AxSm.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runQ-grid-tgW.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runR-blind-transcript.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runS-cross-coherence.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runT-cross-cpm5.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runU-cross-12b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runV-lw-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runW-lw-12b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runX-lw-cpm5.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runY-cliff-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runZ-cliff-12b.log +0 -0
- /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
- /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
- /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
- /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
- /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
- /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
- /package/docs/{planning → archive/planning}/journal.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
- /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
|
@@ -45,7 +45,7 @@ check). Untracked ≠ deleted ≠ unrunnable.
|
|
|
45
45
|
+ the two docs that reference `repro/` (grep first: `grep -rn "repro/"
|
|
46
46
|
docs/ *.md`).
|
|
47
47
|
- Also updated every path reference (CLAUDE.md, PLAN.md, PLAN-archive.md,
|
|
48
|
-
docs/investigations/lab-build-journal.md, docs/design/docs-reorg-plan.md,
|
|
48
|
+
docs/archive/investigations/lab-build-journal.md, docs/design/docs-reorg-plan.md,
|
|
49
49
|
and the `repro/`-pointing comments in src/mlx/{ffi,array,autograd,ops}.ts
|
|
50
50
|
+ tests/{ffi-jit,train-autograd}.test.ts + the repro's own ISSUE.md).
|
|
51
51
|
- `[x]` **A2. root strays** (all untracked; no git surgery): delete
|
|
@@ -168,12 +168,12 @@ suspenders until both machines are re-cloned.
|
|
|
168
168
|
threads). The closed `oMLX` phase (2026-07-02) and Phase 19 are
|
|
169
169
|
*newer* than 17, so they stay in PLAN.md as recent history per the
|
|
170
170
|
criterion. Revisit D1 when a <17 phase is confirmed closed.
|
|
171
|
-
- `[x]` **D2.** `docs/investigations/curve-runs/` + two untracked HTML
|
|
171
|
+
- `[x]` **D2.** `docs/archive/investigations/curve-runs/` + two untracked HTML
|
|
172
172
|
strays in docs/investigations: gitignore or move under `reports/`.
|
|
173
|
-
- Already satisfied: `docs/investigations/curve-runs/` is gitignored
|
|
173
|
+
- Already satisfied: `docs/archive/investigations/curve-runs/` is gitignored
|
|
174
174
|
(`.gitignore`), and the four HTML strays (`curve-terrain.html`,
|
|
175
175
|
`hlg-ab.html`, `hlg-report.html`, `hlg-explorer.html`) are gitignored
|
|
176
|
-
via `docs/investigations/*.html`. No action needed.
|
|
176
|
+
via `docs/archive/investigations/*.html`. No action needed.
|
|
177
177
|
- `[x]` **D3.** The CLAUDE.md doc-map lists are hand-maintained; add a
|
|
178
178
|
`scripts/check-hygiene.ts` assertion that every `docs/**/*.md` appears in
|
|
179
179
|
the map (same guardrail spirit as B1).
|
|
@@ -187,3 +187,45 @@ A and D anytime (safe, agent-executable solo) — DONE 2026-07-02. B gate
|
|
|
187
187
|
DONE 2026-07-02 (B2 adapter-untrack deferred to Josh — see B2 finding).
|
|
188
188
|
C executed 2026-07-02 on Josh's explicit go — only remaining tail is the
|
|
189
189
|
M4 Pro reset + deleting the backup tarball once both boxes are green.
|
|
190
|
+
|
|
191
|
+
## Phase D — work-artifact hygiene + rules (2026-08-18) — DONE
|
|
192
|
+
|
|
193
|
+
Trigger: Josh — "this is a software project; we should not be adding all
|
|
194
|
+
these random work things into it." Compared against ml-explore/mlx-lm's
|
|
195
|
+
root (9 files, 4 dirs, zero work artifacts).
|
|
196
|
+
|
|
197
|
+
- **D1 root sweep**: six tracked `benchmarks-serve-2026-07-0*.md` dumps
|
|
198
|
+
git-rm'd (they leaked past a gitignore pattern that only covered
|
|
199
|
+
`benchmarks-h2h-*`); seven untracked root bench artifacts moved to
|
|
200
|
+
`reports/bench-archive/`; `tmp/` deleted. `.gitignore` now blocks
|
|
201
|
+
`/benchmarks-*`, `/bench-*`, `/tmp/`, `/*.log` at root.
|
|
202
|
+
- **D2 guardrail**: `scripts/check-hygiene.ts` gained a third gate —
|
|
203
|
+
tracked ROOT files must be on an explicit allowlist (16 meta files).
|
|
204
|
+
- **D3 CONTRIBUTING.md**: the rules (what-goes-where table; no dated
|
|
205
|
+
artifacts; models → `~/models`; docs lifecycle; PLAN/STATUS discipline;
|
|
206
|
+
external oracle venv is not a repo).
|
|
207
|
+
- **D4 docs archive**: all 20 `docs/investigations/` →
|
|
208
|
+
`docs/archive/investigations/` (investigations document finished work);
|
|
209
|
+
5 release-notes + journal + 2 chat-ui visions + 2 pass-plans →
|
|
210
|
+
`docs/archive/planning/`; `hlg-sampling.md` (self-declared superseded) →
|
|
211
|
+
`docs/archive/`. All inbound links rewritten; docs-map gate green.
|
|
212
|
+
- **D5 journal trim (rule 4)**: STATUS.md 1648 → 106 lines (Colibri
|
|
213
|
+
gate-history + all "where we were" + the stale July ranked backlog →
|
|
214
|
+
PLAN-archive under "STATUS archive 2026-08-18"); PLAN.md 3815 → 2679
|
|
215
|
+
(8 closed `[x]` phase blocks → PLAN-archive with one-line pointers).
|
|
216
|
+
- Model artifacts moved out of the tree entirely (`~/models/`) earlier
|
|
217
|
+
the same day.
|
|
218
|
+
|
|
219
|
+
Remaining (curated, not mechanical — needs judgment per file):
|
|
220
|
+
- `docs/design/` still holds 46 docs; many describe LANDED work and
|
|
221
|
+
should archive under rule 3 (candidates: optimization_plan,
|
|
222
|
+
faithful-base superseded pair, diffusion/audio/omlx/dspark docs whose
|
|
223
|
+
phases closed). Do this per-doc with link fixes, not as a bulk move.
|
|
224
|
+
- `docs/planning/` leftovers (chunk-task-roadmap, curve-sampler-research-
|
|
225
|
+
plan, memory-docs-and-dag-plan, pi-integration-review) — keep-or-archive
|
|
226
|
+
per Josh.
|
|
227
|
+
- `scripts/experiments/` = 199 files; prune ones whose findings are fully
|
|
228
|
+
recorded in archived docs (keep regen/oracle scripts).
|
|
229
|
+
- `runs/` is 32 GB machine-local (Colibri evidence + quant lab arms) —
|
|
230
|
+
delete lab arms once the TQ/GPTQ program closes; Colibri evidence dirs
|
|
231
|
+
are cited from the archive and stay.
|
|
@@ -35,7 +35,7 @@ All committed-worthy, validated this session:
|
|
|
35
35
|
Baseline 11.89/100 → fine-tuned **91.70/100** on lucien's 25-case chunk holdout
|
|
36
36
|
(valid-JSON rate 12% → 100%). Full mlx-bun loop: train → save adapter (hot-swap
|
|
37
37
|
format) → `AdapterManager.mount` → generate. Writeup:
|
|
38
|
-
`docs/investigations/chunk-finetune-experiment.md`. Scripts: `scripts/chunk-eval.ts`,
|
|
38
|
+
`docs/archive/investigations/chunk-finetune-experiment.md`. Scripts: `scripts/chunk-eval.ts`,
|
|
39
39
|
`scripts/chunk-finetune.ts`, `scripts/chunk-filter.ts`. Adapter:
|
|
40
40
|
`~/.cache/mlx-bun-finetunes/minicpm5-chunk-final`.
|
|
41
41
|
|
|
@@ -69,7 +69,7 @@ active-after 8.66 + cache-after 6.61 = 15.27 > peak 14.90, impossible if peak we
|
|
|
69
69
|
total). MLX holds freed buffers in a **cache** (not returned to OS) so RSS overstates
|
|
70
70
|
live memory; use `activeMemory()` / `cacheMemory()` / `clearCache()` to separate
|
|
71
71
|
them (`src/mlx/ffi.ts`). Caveat from the MoE expert-offload work
|
|
72
|
-
(`docs/investigations/expert-offload-single-user-moe.md`): `clearCache()` does NOT
|
|
72
|
+
(`docs/archive/investigations/expert-offload-single-user-moe.md`): `clearCache()` does NOT
|
|
73
73
|
reliably return device-buffer RAM to the OS — only the mmap clean-page path does.
|
|
74
74
|
|
|
75
75
|
Facts established:
|
|
@@ -286,3 +286,130 @@ SIGINT/SIGTERM during (or within the debounce after) traffic loses queued
|
|
|
286
286
|
write-behind entries; restart survival degrades to whatever already
|
|
287
287
|
flushed. This is a best-effort cache tier; the cost of a lost entry is one
|
|
288
288
|
re-prefill. `SpillQueue.drain()` exists if a shutdown hook is ever wanted.
|
|
289
|
+
|
|
290
|
+
This acceptance was superseded by the 2026-08-22 durability fix below.
|
|
291
|
+
|
|
292
|
+
## Bug brief 2026-08-22: restart can outrun SSD write-behind
|
|
293
|
+
|
|
294
|
+
### User-visible failure
|
|
295
|
+
|
|
296
|
+
A completed long-context request can report a full RAM-cache hit on repeat,
|
|
297
|
+
then lose that prefix when the server restarts a few seconds later. The next
|
|
298
|
+
request pays a full prefill even though `--ssd-cache` was enabled.
|
|
299
|
+
|
|
300
|
+
The 2026-08-22 M1 Max serve matrix reproduced this with the standard restart
|
|
301
|
+
leg, which waits 2.5 seconds after the long request before sending SIGTERM:
|
|
302
|
+
|
|
303
|
+
| model and mode | cached tokens after restart | expected |
|
|
304
|
+
|---|---:|---:|
|
|
305
|
+
| MiniCPM5, unified bf16 | 15,817 | about 15.8k |
|
|
306
|
+
| e4b, unified bf16 | 4 | about 15.9k |
|
|
307
|
+
| e4b, serial bf16 | 15,940 | about 15.9k |
|
|
308
|
+
| 12B, unified bf16 | 4 | about 15.9k |
|
|
309
|
+
| 12B, serial bf16 | 15,866 | about 15.9k |
|
|
310
|
+
| Qwen3.8, unified bf16 | 0 | about 15.1k |
|
|
311
|
+
| Qwen3.8, serial bf16 | 0 | about 15.1k |
|
|
312
|
+
| Qwen3.8, unified mixed KV | 15,112 | about 15.1k |
|
|
313
|
+
|
|
314
|
+
The Bun 1.4 rerun reproduced the lane split before this brief was written:
|
|
315
|
+
e4b unified restored 2 of 15,942 tokens, while e4b serial restored 15,939.
|
|
316
|
+
The completed run also restored only 4 tokens for unified 12B versus 15,794
|
|
317
|
+
for serial 12B, and 5 for mixed-KV 12B. Qwen bf16 restored zero in both
|
|
318
|
+
lanes, while mixed-KV Qwen restored all 15,114 tokens. This is not a Bun
|
|
319
|
+
1.3-only result.
|
|
320
|
+
|
|
321
|
+
### Expected contract
|
|
322
|
+
|
|
323
|
+
After a request completes and the server has reported the cache durable, a
|
|
324
|
+
normal SIGTERM and restart must restore the longest compatible prefix. For
|
|
325
|
+
the benchmark's exact-repeat request, `cached_tokens` should be at least
|
|
326
|
+
`prompt_tokens - 1`. The server must never imply durability while a matching
|
|
327
|
+
snapshot is still waiting on its debounce timer or the spill queue.
|
|
328
|
+
|
|
329
|
+
### Evidence and current diagnosis
|
|
330
|
+
|
|
331
|
+
The read and reconstruction path works when the file reaches disk. MiniCPM,
|
|
332
|
+
serial e4b and 12B, and mixed-KV Qwen all restore a full prefix through the
|
|
333
|
+
same `PromptCache.take()` and `SsdCacheStore.restore()` path. That makes a
|
|
334
|
+
model-format or prefix-matching defect unlikely as the primary cause.
|
|
335
|
+
|
|
336
|
+
The likely failure is the durability boundary:
|
|
337
|
+
|
|
338
|
+
1. `PromptCache.onPut` schedules a snapshot with a one-second debounce.
|
|
339
|
+
2. A busy gateway re-arms that timer for five seconds.
|
|
340
|
+
3. The snapshot then joins a serial `SpillQueue`; large bf16 entries can still
|
|
341
|
+
be queued or in flight when the benchmark's 2.5-second wait expires.
|
|
342
|
+
4. SIGTERM stops the process without forcing pending timers to fire or awaiting
|
|
343
|
+
`SpillQueue.drain()`. The queue's own comment calls drain a future shutdown
|
|
344
|
+
hook.
|
|
345
|
+
|
|
346
|
+
Entry size explains the broad pattern. Small MiniCPM and smaller mixed-KV Qwen
|
|
347
|
+
files finish in time; large Qwen bf16 files do not. The remaining unified versus
|
|
348
|
+
serial split needs telemetry before assigning a second root cause. The unified
|
|
349
|
+
lane may enqueue more snapshots, take longer to extract row caches, or hit the
|
|
350
|
+
queue cap. The current report does not capture that state before termination.
|
|
351
|
+
|
|
352
|
+
### Fix plan
|
|
353
|
+
|
|
354
|
+
1. Expose `pending_snapshots`, `pending_spills`, `pending_spill_bytes`,
|
|
355
|
+
`dropped_spills`, and the longest durable prefix in `/stats.ssd_cache`.
|
|
356
|
+
`pending_snapshots` must include debounce and busy-rearm timers, not only
|
|
357
|
+
entries already placed in `SpillQueue`.
|
|
358
|
+
2. Add one async durability operation that cancels debounce timers, snapshots
|
|
359
|
+
matching RAM entries under the gateway lock, and awaits
|
|
360
|
+
`SpillQueue.drain()`. Return success only after the atomic rename completes.
|
|
361
|
+
3. Route graceful SIGINT/SIGTERM through that operation with a bounded timeout.
|
|
362
|
+
Stop new admission first. A timeout may drop the cache, but must log the
|
|
363
|
+
number of pending and dropped snapshots.
|
|
364
|
+
4. Change the benchmark restart leg to request or poll durability instead of
|
|
365
|
+
sleeping for 2.5 seconds. A fixed sleep measures SSD timing luck, not the
|
|
366
|
+
restart contract.
|
|
367
|
+
5. Capture pre-kill stats and the recovered entry count in every restart row so
|
|
368
|
+
a write miss cannot masquerade as a restore miss again.
|
|
369
|
+
|
|
370
|
+
### Implemented 2026-08-22
|
|
371
|
+
|
|
372
|
+
- `SsdDurabilityCoordinator` owns debounce, busy retry, queue completion, and
|
|
373
|
+
explicit flush as one state machine. A snapshot stays dirty until the atomic
|
|
374
|
+
store succeeds. Queue drops and write failures remain retryable.
|
|
375
|
+
- Dirty keys include the exact token sequence, so two conversations with the
|
|
376
|
+
same namespace and token count cannot cancel each other.
|
|
377
|
+
- `POST /admin/cache/flush` returns `200` only at the durability boundary and
|
|
378
|
+
exposes pending, dropped, failed, entry-count, and longest-prefix evidence.
|
|
379
|
+
- `mlx-bun serve` handles `SIGINT` and `SIGTERM` by stopping admission,
|
|
380
|
+
draining active requests, and awaiting the same flush, bounded by
|
|
381
|
+
`MLX_BUN_SHUTDOWN_TIMEOUT_MS`.
|
|
382
|
+
- The standard restart benchmark calls the endpoint instead of sleeping and
|
|
383
|
+
records its evidence in the Markdown report and eval database notes.
|
|
384
|
+
- Model-free regression coverage holds an atomic store open and proves flush
|
|
385
|
+
waits, forces the busy-rearm path, retries a failed write, preserves
|
|
386
|
+
equal-length conversations, and reports a missing RAM boundary honestly.
|
|
387
|
+
|
|
388
|
+
Focused real-server smoke on unified e4b passed the repaired path: a
|
|
389
|
+
4,026-token prompt flushed in 408 ms with `durable=true`, zero pending,
|
|
390
|
+
dropped, or failed work, then restored 4,025 cached tokens after SIGTERM and
|
|
391
|
+
respawn. The machine failed the clean-performance preflight, so this is cache
|
|
392
|
+
correctness evidence only, not a performance result. The full clean 16k
|
|
393
|
+
e4b/12B/Qwen matrix remains the acceptance run.
|
|
394
|
+
|
|
395
|
+
### Acceptance tests
|
|
396
|
+
|
|
397
|
+
- A deterministic coordinator test holds `storeAsync`, requests a flush,
|
|
398
|
+
releases the store, and proves the durability boundary waits for the atomic
|
|
399
|
+
file. The focused real-server smoke exercises the SIGTERM path through that
|
|
400
|
+
same operation before restart.
|
|
401
|
+
- A busy-gateway test forces the five-second re-arm path, then requests a flush
|
|
402
|
+
and proves the timer becomes an immediate queued snapshot without blocking an
|
|
403
|
+
active generation.
|
|
404
|
+
- Batch 8 and `--batch 1` both restore at least `prompt_tokens - 1` for e4b,
|
|
405
|
+
12B, and Qwen3.8 at roughly 16k context.
|
|
406
|
+
- The mixed-KV and SSM cache kinds retain their existing continuation parity.
|
|
407
|
+
- Steady-state decode remains unchanged because normal writes still pause while
|
|
408
|
+
the engine is busy. Queued clone memory stays within the spill cap.
|
|
409
|
+
|
|
410
|
+
Focused reproduction:
|
|
411
|
+
|
|
412
|
+
```sh
|
|
413
|
+
./benchmark.sh --models e4b,12B,qwen27b \
|
|
414
|
+
--arms mlx-bun,mlx-bun-serial,mlx-bun-mixed
|
|
415
|
+
```
|