mlx-bun 0.0.4

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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +362 -0
  3. package/THIRD_PARTY_LICENSES.md +41 -0
  4. package/bin/mlx-bun.mjs +32 -0
  5. package/docs/curve-designer.html +303 -0
  6. package/docs/design/adapters-end-to-end.md +201 -0
  7. package/docs/design/compat-cli-surface-design.md +227 -0
  8. package/docs/design/docs-reorg-plan.md +152 -0
  9. package/docs/design/hlg-sampling.md +340 -0
  10. package/docs/design/memory-system.md +339 -0
  11. package/docs/design/optimization_plan.md +344 -0
  12. package/docs/design/parallel-slots.md +515 -0
  13. package/docs/design/runtime-isolation.md +247 -0
  14. package/docs/design/segmented-backward-training.md +508 -0
  15. package/docs/investigations/chunk-finetune-experiment.md +84 -0
  16. package/docs/investigations/curve-bisector-routing.md +123 -0
  17. package/docs/investigations/curve-runs/bisector-route.json +98 -0
  18. package/docs/investigations/curve-runs/bisector-trace.json +1393 -0
  19. package/docs/investigations/curve-runs/curve-terrain.json +1179 -0
  20. package/docs/investigations/curve-runs/curve-terrain.svg +42 -0
  21. package/docs/investigations/curve-terrain.html +105 -0
  22. package/docs/investigations/expert-offload-single-user-moe.md +292 -0
  23. package/docs/investigations/hlg-ab.html +34 -0
  24. package/docs/investigations/hlg-explorer.html +238 -0
  25. package/docs/investigations/hlg-figs/cliff.svg +1 -0
  26. package/docs/investigations/hlg-figs/cross.svg +1 -0
  27. package/docs/investigations/hlg-figs/edges.svg +1 -0
  28. package/docs/investigations/hlg-figs/k20-grids.svg +1 -0
  29. package/docs/investigations/hlg-figs/k20-peaks.svg +1 -0
  30. package/docs/investigations/hlg-figs/lw-curve.svg +1 -0
  31. package/docs/investigations/hlg-figs/terrain.svg +1 -0
  32. package/docs/investigations/hlg-report.html +262 -0
  33. package/docs/investigations/hlg-runs/hlg-ab.json +149 -0
  34. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +87 -0
  35. package/docs/investigations/hlg-runs/hlg-blind.json +107 -0
  36. package/docs/investigations/hlg-runs/hlg-cliff.json +197 -0
  37. package/docs/investigations/hlg-runs/hlg-cross.json +505 -0
  38. package/docs/investigations/hlg-runs/hlg-edge.json +388 -0
  39. package/docs/investigations/hlg-runs/hlg-eval1.json +25 -0
  40. package/docs/investigations/hlg-runs/hlg-frontier.json +86 -0
  41. package/docs/investigations/hlg-runs/hlg-grid.json +242 -0
  42. package/docs/investigations/hlg-runs/hlg-grid2.json +343 -0
  43. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +110 -0
  44. package/docs/investigations/hlg-runs/hlg-map.json +383 -0
  45. package/docs/investigations/hlg-runs/run0-original.log +159 -0
  46. package/docs/investigations/hlg-runs/runA-recommended.log +131 -0
  47. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +26 -0
  48. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +18 -0
  49. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +25 -0
  50. package/docs/investigations/hlg-runs/runAD-ab-samples.log +8 -0
  51. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +51 -0
  52. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +10 -0
  53. package/docs/investigations/hlg-runs/runAG-eval-config2.log +16 -0
  54. package/docs/investigations/hlg-runs/runB-gain-variants.log +192 -0
  55. package/docs/investigations/hlg-runs/runC-pivots.log +162 -0
  56. package/docs/investigations/hlg-runs/runD-oetf.log +132 -0
  57. package/docs/investigations/hlg-runs/runE-eotf.log +162 -0
  58. package/docs/investigations/hlg-runs/runF-shaper-working.log +86 -0
  59. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +101 -0
  60. package/docs/investigations/hlg-runs/runH-wsweep.log +176 -0
  61. package/docs/investigations/hlg-runs/runI-asweep.log +176 -0
  62. package/docs/investigations/hlg-runs/runJ-knobmap.log +49 -0
  63. package/docs/investigations/hlg-runs/runK-frontier.log +19 -0
  64. package/docs/investigations/hlg-runs/runL-widemap.log +65 -0
  65. package/docs/investigations/hlg-runs/runM-frontier-emb.log +15 -0
  66. package/docs/investigations/hlg-runs/runN-verify.log +116 -0
  67. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +15 -0
  68. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +15 -0
  69. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +15 -0
  70. package/docs/investigations/hlg-runs/runR-blind-transcript.log +79 -0
  71. package/docs/investigations/hlg-runs/runS-cross-coherence.log +33 -0
  72. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +33 -0
  73. package/docs/investigations/hlg-runs/runU-cross-12b.log +33 -0
  74. package/docs/investigations/hlg-runs/runV-lw-e4b.log +22 -0
  75. package/docs/investigations/hlg-runs/runW-lw-12b.log +22 -0
  76. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +22 -0
  77. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +26 -0
  78. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +26 -0
  79. package/docs/investigations/hlg-sampling-investigation.md +970 -0
  80. package/docs/investigations/lab-build-journal.md +157 -0
  81. package/docs/investigations/pi-builtin-investigation.md +308 -0
  82. package/docs/investigations/starter-model-port-handoff.md +323 -0
  83. package/docs/planning/IDEAS.md +26 -0
  84. package/docs/planning/PRODUCT_ROADMAP.md +426 -0
  85. package/docs/planning/ResearchTopics.md +119 -0
  86. package/docs/planning/chunk-task-roadmap.md +77 -0
  87. package/docs/planning/journal.md +155 -0
  88. package/docs/reference/distribution.md +121 -0
  89. package/docs/reference/embedding.md +168 -0
  90. package/docs/reference/library-api.md +153 -0
  91. package/docs/reference/server-api.md +224 -0
  92. package/docs/reference/server-config.md +243 -0
  93. package/docs/segmented-backward-handoff.md +148 -0
  94. package/package.json +68 -0
  95. package/src/anthropic.ts +491 -0
  96. package/src/chat-template.ts +186 -0
  97. package/src/cli.ts +1075 -0
  98. package/src/config.ts +229 -0
  99. package/src/curve-sampler.ts +122 -0
  100. package/src/dataset/generators.ts +1087 -0
  101. package/src/dataset/index.ts +12 -0
  102. package/src/dataset/job.ts +81 -0
  103. package/src/dataset/llm.ts +71 -0
  104. package/src/dataset/registry.ts +528 -0
  105. package/src/download.ts +283 -0
  106. package/src/eval/README.md +86 -0
  107. package/src/eval/kl-prompts.ts +29 -0
  108. package/src/eval/kl.ts +294 -0
  109. package/src/eval/quality-db.ts +92 -0
  110. package/src/eval/runner.ts +102 -0
  111. package/src/eval/score.ts +49 -0
  112. package/src/eval/tasks/bfcl.ts +500 -0
  113. package/src/eval/tasks/gsm8k.ts +85 -0
  114. package/src/eval/tasks/hashhop.ts +109 -0
  115. package/src/eval/tasks/humaneval.ts +252 -0
  116. package/src/eval/tasks/ifeval.ts +354 -0
  117. package/src/eval/tasks/mmlu.ts +145 -0
  118. package/src/evaldb.ts +199 -0
  119. package/src/expert-offload-build.ts +77 -0
  120. package/src/expert-offload.ts +61 -0
  121. package/src/expert-trace.ts +67 -0
  122. package/src/fit.ts +254 -0
  123. package/src/generate.ts +451 -0
  124. package/src/harness-pi.ts +177 -0
  125. package/src/hf-push.ts +628 -0
  126. package/src/index.ts +22 -0
  127. package/src/jobs/db.ts +139 -0
  128. package/src/jobs/index.ts +29 -0
  129. package/src/jobs/job-entry.ts +106 -0
  130. package/src/jobs/runner.ts +304 -0
  131. package/src/jobs/sse.ts +114 -0
  132. package/src/jobs/types.ts +58 -0
  133. package/src/kv-store.ts +185 -0
  134. package/src/lora.ts +314 -0
  135. package/src/md-modules.d.ts +7 -0
  136. package/src/mlx/array.ts +237 -0
  137. package/src/mlx/autograd.ts +267 -0
  138. package/src/mlx/checkpoint.ts +116 -0
  139. package/src/mlx/compile.ts +158 -0
  140. package/src/mlx/custom-vjp.ts +140 -0
  141. package/src/mlx/ffi.ts +433 -0
  142. package/src/mlx/metal-kernel.ts +130 -0
  143. package/src/mlx/ops.ts +707 -0
  144. package/src/mmap.ts +90 -0
  145. package/src/model/batched-mask.ts +204 -0
  146. package/src/model/batched-rotating.ts +300 -0
  147. package/src/model/compiled-decode.ts +681 -0
  148. package/src/model/factory.ts +27 -0
  149. package/src/model/fingerprint.ts +33 -0
  150. package/src/model/flash-attention.ts +674 -0
  151. package/src/model/fused-decode-kernel.ts +305 -0
  152. package/src/model/fused-geglu-kernel.ts +87 -0
  153. package/src/model/gemma4-base.ts +1616 -0
  154. package/src/model/gemma4.ts +1012 -0
  155. package/src/model/generated/gemma4-12b.ts +526 -0
  156. package/src/model/generated/gemma4-26b.ts +500 -0
  157. package/src/model/generated/gemma4-e4b.ts +757 -0
  158. package/src/model/generated/index.ts +18 -0
  159. package/src/model/minicpm5.ts +278 -0
  160. package/src/model/qwen3-delta.ts +224 -0
  161. package/src/model/qwen3_5.ts +429 -0
  162. package/src/model/support.ts +46 -0
  163. package/src/native-pack.ts +152 -0
  164. package/src/pi-provider.ts +95 -0
  165. package/src/pi-terminal.ts +264 -0
  166. package/src/pi-web.ts +924 -0
  167. package/src/preflight.ts +123 -0
  168. package/src/prompt-cache.ts +113 -0
  169. package/src/quantize/allocator.ts +627 -0
  170. package/src/quantize/calibration.ts +180 -0
  171. package/src/quantize/config-writer.ts +132 -0
  172. package/src/quantize/index.ts +57 -0
  173. package/src/quantize/job.ts +136 -0
  174. package/src/quantize/quantizer.ts +462 -0
  175. package/src/quantize/safetensors-writer.ts +171 -0
  176. package/src/quantize/sensitivity.ts +234 -0
  177. package/src/registry.ts +336 -0
  178. package/src/responses.ts +774 -0
  179. package/src/safetensors.ts +158 -0
  180. package/src/sampler.ts +517 -0
  181. package/src/serve/batch-scheduler.ts +362 -0
  182. package/src/serve/generation-gateway.ts +160 -0
  183. package/src/server.ts +1891 -0
  184. package/src/spec/drafter.ts +261 -0
  185. package/src/spec/generate.ts +221 -0
  186. package/src/status-page.html +497 -0
  187. package/src/tokenizer.ts +38 -0
  188. package/src/tool-call.ts +242 -0
  189. package/src/train/dataset.ts +461 -0
  190. package/src/train/export.ts +32 -0
  191. package/src/train/forward.ts +229 -0
  192. package/src/train/index.ts +43 -0
  193. package/src/train/job.ts +148 -0
  194. package/src/train/lora-params.ts +194 -0
  195. package/src/train/loss.ts +342 -0
  196. package/src/train/merge.ts +195 -0
  197. package/src/train/optimizer.ts +176 -0
  198. package/src/train/rank.ts +101 -0
  199. package/src/train/segmented.ts +520 -0
  200. package/src/train/trainer.ts +600 -0
  201. package/src/tui.ts +161 -0
  202. package/src/vision/embedder.ts +168 -0
  203. package/src/vision/preprocess.ts +247 -0
  204. package/src/vision/prompt.ts +158 -0
  205. package/src/vision/siglip.ts +599 -0
  206. package/src/web/app.html +2471 -0
  207. package/src/web/skills/web-research/SKILL.md +44 -0
  208. package/src/web/skills.ts +59 -0
  209. package/src/web-tools.ts +426 -0
  210. package/src/weights.ts +91 -0
@@ -0,0 +1,340 @@
1
+ # HLG sampling — a piecewise tone curve on the logits
2
+
3
+ Status: **design + phasing** (no code yet; this doc is the contract)
4
+ Owner: sampling layer (`src/sampler.ts`)
5
+ Default: **off** (`--hlg-sampling off` = today's temperature sampler, untouched)
6
+
7
+ > This is the canonical **design/rationale** for HLG sampling. Live
8
+ > **status/tracking** (checkboxes, findings) lives in PLAN.md under
9
+ > "Phase 19 — HLG sampling". The user-facing flag/param reference lives in
10
+ > [docs/reference/server-config.md](../reference/server-config.md) and
11
+ > [docs/reference/server-api.md](../reference/server-api.md) once shipped.
12
+
13
+ ## Goal
14
+
15
+ Add a sampling transform — gated entirely behind `--hlg-sampling on` and a
16
+ per-request `hlg` object — that replaces temperature's single global slope
17
+ with a **pivoted, region-aware contrast curve** on the per-token
18
+ log-probabilities.
19
+
20
+ The move is a **cross-domain transplant**: take a mathematical structure that is
21
+ standard in one field — a piecewise nonlinear transfer function — and apply it
22
+ in one that has never used it. HLG (Hybrid Log-Gamma) is the structure we lift:
23
+ where a plain gamma is one power curve, HLG is **piecewise**, shaping the low,
24
+ middle, and high range of a signal under separate constraints. A logit
25
+ distribution is another such signal. The hypothesis is that shaping its three
26
+ regions independently buys something a single global temperature cannot — and
27
+ that claim is settled by measurement in *this* domain, not by the structure's
28
+ track record in its original one.
29
+
30
+ This is a post-inference, **model-agnostic** transform — it operates on the
31
+ logits vector after the forward pass, so it applies identically to every model
32
+ (MiniCPM5 + the three Gemma-4 quants) and every lane (serial + `--batch N`)
33
+ with **zero per-model code**. It is the first sampling feature in the project
34
+ that has **no oracle ancestor** (neither mlx-lm nor optiq does this), so it is
35
+ gated by KL + quality + diversity, not parity — with one exception that makes
36
+ it safe to ship: see [Correctness](#correctness--evaluation).
37
+
38
+ ## Why temperature isn't enough (the thesis)
39
+
40
+ Temperature scales every logit by the same factor: `logit / T`. In tone-curve
41
+ terms it is a **single straight line through the origin** — one global slope.
42
+ Lower `T` steepens it everywhere (sharper, more confident); higher `T` flattens
43
+ it everywhere (more diverse).
44
+
45
+ Its limitation is a **coupling**: the only way temperature loosens the model's
46
+ grip on its top token is by raising `T`, which *simultaneously* lifts the tail.
47
+ You cannot, with one slope, reduce top-token dominance **and** keep a soft floor
48
+ under the tail. Raise the temperature to get novelty and you also import
49
+ low-probability noise; lower it to suppress noise and you re-collapse onto the
50
+ single most likely token. One number cannot move two regions independently.
51
+
52
+ The fix is structural, not a better choice of `T`: make the slope **depend on
53
+ the region of the distribution**. This is precisely what nonlinear transfer
54
+ functions do in signal and color encoding — a single piecewise curve shapes the
55
+ low, middle, and high range under separate constraints. The cross-domain idea
56
+ here is to transplant that apparatus onto a logit distribution, which is just
57
+ another value distribution. Mapped onto the three regions of a token
58
+ distribution, the curve's response is:
59
+
60
+ - **High-probability region** (the model's most confident tokens) →
61
+ **shoulder**: roll the slope off so the top values compress toward their
62
+ neighbours. The model stops being *so fixed* on its favourite answer.
63
+ - **Mid-probability region** (where novelty and interest live) → **gain > 1**:
64
+ steepen the slope. The local-contrast boost separates the
65
+ plausible-and-interesting from the merely-mediocre.
66
+ - **Low-probability tail** → **toe**: gently reduce the slope toward a soft
67
+ floor. Suppress the tail *smoothly* — unlike top-p/top-k, which hard-clip it
68
+ to `-inf`, and unlike high temperature, which inflates it.
69
+
70
+ The payoff is the **decoupling** temperature cannot achieve: roll off the high
71
+ end *and* hold a soft floor under the tail at the same time — a region of
72
+ sampling behaviour no single-knob method reaches. Whether that decoupling is
73
+ *useful* is an empirical question, settled in [Correctness](#correctness--evaluation),
74
+ not by the pedigree of the curve.
75
+
76
+ ## The transfer function
77
+
78
+ We operate in **log-probability space**, the natural "stops" axis for a
79
+ probability distribution (the sampler already computes `toLogprobs`,
80
+ [src/sampler.ts:127](../../src/sampler.ts)). Let `ℓ_i` be each token's log-prob
81
+ and `μ` the pivot (middle grey — see [Pivot](#the-pivot--middle-grey)). Define
82
+ the centered coordinate
83
+
84
+ ```
85
+ z_i = ℓ_i − μ
86
+ ```
87
+
88
+ and remap it with a **C¹ log-toe / linear-mid / log-shoulder** curve. The
89
+ piecewise form is deliberate — it honours HLG's own breakpoints (HLG literally
90
+ switches from a gamma segment to a log segment at E = 1/12):
91
+
92
+ ```
93
+ ⎧ −m·w − m·β_t·ln(1 + (−z − w)/β_t) z < −w (toe / shadows)
94
+ g(z) = ⎨ m·z |z| ≤ w (gain / mids)
95
+ ⎩ m·w + m·β_h·ln(1 + ( z − w)/β_h) z > w (shoulder / highlights)
96
+ ```
97
+
98
+ The remapped logits are `ℓ'_i = g(z_i)`. The `+μ` constant shift cancels under
99
+ softmax, so we drop it and feed `g(z_i)` straight to the existing
100
+ `randomCategorical` draw.
101
+
102
+ Properties that matter:
103
+
104
+ - **Slope** is `m` at the pivot and decays as `m·β / (β + d)` a distance `d`
105
+ past each knot — continuous at the knots (C¹), monotone, and always positive.
106
+ - **Monotone ⇒ ranking-preserving.** `g` never reorders tokens: it is a pure
107
+ contrast/tone operation, not a re-ranker. Pairwise orderings and the argmax
108
+ are invariant. (Tested — see [Correctness](#correctness--evaluation).)
109
+ - **`-inf` safe.** A token masked by top-p/top-k (`ℓ_i = -inf`) lands in the toe
110
+ branch and maps to `-inf` — masking survives the remap, no NaN.
111
+
112
+ ### Knobs → what each controls
113
+
114
+ | Param | Controls | Effect |
115
+ | --- | --- | --- |
116
+ | `pivot` μ | center of the curve | where the contrast boost is anchored in the distribution (see below) |
117
+ | `gain` m | mid-region slope | `m > 1` sharpens mid-probability tokens; folds temperature (`m = 1/T`) |
118
+ | `width` w | extent of the mid region | how many nats around the pivot count as "mids" |
119
+ | `shoulder` β_h | high-prob rolloff | small = compresses the top tokens fast → top-token diversity |
120
+ | `toe` β_t | low-prob rolloff | small = quick gentle fade of the tail; large = keep more tail |
121
+
122
+ All knobs are in **nats** (the log-prob unit), so they are scale-free across
123
+ models and contexts.
124
+
125
+ ### The degeneracies are the safety anchors
126
+
127
+ The curve is a **strict generalization of temperature**, and that is what makes
128
+ a no-oracle path safe to ship — the default and neutral paths reduce *exactly*
129
+ to today's sampler:
130
+
131
+ - `m = 1`, rolloff off (`w → ∞`, or `β → ∞`) ⟹ `g(z) = z` ⟹ **bit-exact the
132
+ current sampler at T = 1**.
133
+ - rolloff off (`w → ∞`), any `m` ⟹ `g(z) = m·z` ⟹ **bit-exact temperature
134
+ `T = 1/m`** (the existing `mulScalar(cur, 1/temperature)` step).
135
+
136
+ So there is a configuration in which HLG is provably identical to temperature,
137
+ down to the bit. That is the parity-equivalent gate (below).
138
+
139
+ ### Greedy is untouched
140
+
141
+ Under greedy decoding (`temperature === 0`) the sampler returns `argmax`
142
+ ([src/sampler.ts:78](../../src/sampler.ts)). Because `g` is monotone it cannot
143
+ change the argmax, so **HLG is a no-op at temperature 0 by construction** and is
144
+ only engaged for `temperature > 0`. The greedy parity gate is therefore
145
+ trivially preserved.
146
+
147
+ ## The pivot
148
+
149
+ Choosing the pivot is the genuinely interesting part: the curve's center has to
150
+ mean something across distributions as different as a near-deterministic next
151
+ token and a wide-open one. Three modes, all cheap, exposed as `pivot_mode`
152
+ (default **top-anchored**). The other two ship as documented opt-in modes —
153
+ losing experiments become flags, never deletions.
154
+
155
+ The pivot is computed from the **full, normalized log-prob vector before any
156
+ top-p/top-k masking**, so masked `-inf` entries never contaminate it.
157
+
158
+ 1. **`top` — top-anchored (DEFAULT).** `μ = ℓ_max − c`. The curve centers `c`
159
+ nats below the most-probable token. Predictable, scale-free, one `max`
160
+ reduction. `c` is the meaningful knob; default calibration-pending (Piece 5
161
+ sweep).
162
+ 2. **`entropy` — entropy-anchored.** `μ = Σ p_i ℓ_i = −H`, the distribution's
163
+ center of mass in tonal space. Auto-exposure: confident contexts (low
164
+ entropy) pull the pivot up near the top; flat contexts push it down. One
165
+ dot-product, information-theoretically natural, less predictable.
166
+ 3. **`median` — mass-median.** `μ` = the log-prob at the 50% cumulative-mass
167
+ boundary (literal auto-levels / histogram median). Most adaptive; reuses the
168
+ sort top-p already performs.
169
+
170
+ `width` may likewise be a fixed nat value or, in a later increment, auto-derived
171
+ from the log-prob spread (an "auto-contrast" mode). Default fixed for now.
172
+
173
+ ## Temperature semantics
174
+
175
+ When `hlg` is active, the request's `temperature` **folds into the mid gain**:
176
+ `m = 1 / T`. Temperature *is* the mid-tone contrast, and HLG adds the toe and
177
+ shoulder on top of it. This avoids double-applying a slope and preserves the
178
+ intuition that "temperature" still means "how punchy the mids are." With
179
+ rolloff off, `m = 1/T` and `g(z) = z/T` — exactly temperature, as above.
180
+
181
+ ## Where it lands in the code
182
+
183
+ Sampling is fully model-agnostic and shared by every model and lane
184
+ ([src/sampler.ts](../../src/sampler.ts), post-inference), so this is a single
185
+ transform with no per-model branches.
186
+
187
+ - **The transform** — a new `applyHlg(lp, params)` in
188
+ [src/sampler.ts](../../src/sampler.ts). HLG is a **replacement sampler**:
189
+ `makeSampler` branches `if (hlg.enabled)` → the curve is the *whole*
190
+ post-logits step (its toe does the tail control), `else` → exactly what we
191
+ used to do (top-p, top-k, then `mulScalar(cur, 1/temperature)`). The two are
192
+ mutually exclusive — when HLG is on, top-p/top-k are **not** applied, because
193
+ the smooth toe is their replacement, not a layer on top of them. Branchless:
194
+ compute the toe / mid / shoulder expressions and select on `z` vs `±w` with
195
+ `where`. Follows the file's strict `owned[]` → `dispose()` discipline (every
196
+ intermediate freed; only the chosen token id crosses to JS).
197
+ - **Sampler options** — extend `SamplerOptions`
198
+ ([src/sampler.ts:11](../../src/sampler.ts)) with an optional `hlg` sub-object;
199
+ `makeSampler` builds the HLG step when present, else the existing path
200
+ verbatim.
201
+
202
+ Three sampler **construction** sites pass the params through; the
203
+ degeneracy guarantees keep every existing parity gate green:
204
+
205
+ - **Serial** — `makeSampler(options)` in
206
+ [src/generate.ts:218](../../src/generate.ts).
207
+ - **Batched per-row** — `makeSampler(options)` in
208
+ [src/serve/generation-gateway.ts:127](../../src/serve/generation-gateway.ts).
209
+ Each row already owns its sampler closure, so `hlg` params batch per-request
210
+ for free; the draw site in
211
+ [src/serve/batch-scheduler.ts:276](../../src/serve/batch-scheduler.ts) is
212
+ unchanged beyond construction.
213
+
214
+ ### MLX op feasibility
215
+
216
+ All elementwise: `exp`, `sub`, `mul`/`mulScalar`, `where`, plus `log` / `log1p`.
217
+ The pivot needs one `max` (top), one dot-product (entropy), or the existing sort
218
+ (median). Cost is O(V) per token — the same order as the existing top-p step,
219
+ negligible against the forward pass, but measured (Piece 5). If `mlx_log1p`
220
+ isn't already bound, bind it from the header first — read the full signature to
221
+ avoid the trailing-stream-arg footgun (CLAUDE.md).
222
+
223
+ ## Flag, config, and API surface
224
+
225
+ Conventions per [docs/reference/server-config.md](../reference/server-config.md)
226
+ and `serverRuntimeFlags()` ([src/cli.ts](../../src/cli.ts)).
227
+
228
+ - **CLI**: `--hlg-sampling on|off` (default **off**), plus `--hlg-width`,
229
+ `--hlg-shoulder`, `--hlg-toe`, and the top-anchor offset `--hlg-pivot-offset`
230
+ (the `c` above). There is **no `--hlg-gain`**: the mid gain folds from
231
+ `--temperature` (`m = 1/T`), so temperature stays the one contrast knob and a
232
+ second one would be redundant. `--hlg-pivot top|entropy|median` arrives with
233
+ the alternate pivot modes in Piece 4 (top-anchored is the only mode until
234
+ then). Parsed with the existing `onOff` / `numFlag` helpers; validated (exit
235
+ on bad value); defaults onto `ServerOptions`.
236
+ - **ServerOptions** ([src/server.ts](../../src/server.ts)): an `hlg?` config
237
+ object, resolved in `toOptions` with the standard precedence
238
+ (request > CLI default > model config > built-in), exactly like the existing
239
+ sampling defaults.
240
+ - **Per-request**: an `hlg` object on `ChatRequest` (unknown fields are already
241
+ tolerated), so it works over OpenAI `/v1/chat/completions`, Anthropic
242
+ `/v1/messages`, and `/v1/responses` with no protocol-specific plumbing.
243
+ Example:
244
+ ```jsonc
245
+ {
246
+ "temperature": 0.7, // becomes the mid gain m = 1/T
247
+ "hlg": {
248
+ "enabled": true,
249
+ "pivot": "top", "pivot_offset": 6.0,
250
+ "width": 4.0, "shoulder": 4.0, "toe": 6.0
251
+ }
252
+ }
253
+ ```
254
+
255
+ ## Correctness & evaluation
256
+
257
+ This is a novel path with **no oracle ancestor**, so it is gated by KL +
258
+ quality + diversity rather than parity — except for the degeneracy gates, which
259
+ *are* parity gates and must be bit-exact.
260
+
261
+ 1. **Neutrality gate (bit-exact)** — `tests/hlg-sampling-parity.test.ts`:
262
+ - flag-off ⟹ the sampler code path is byte-identical to today's (`makeSampler`
263
+ unchanged when `hlg` absent);
264
+ - `hlg` in *identity config* (`gain = 1`, rolloff off) reduces to the current
265
+ sampler with `maxDiff === 0`;
266
+ - `hlg` rolloff-off, `gain = 1/T` reduces to temperature `T` bit-exact.
267
+ Run across **all four models** and **both lanes** (serial + batched) — the
268
+ param plumbing differs per lane, the math does not.
269
+ 2. **Monotonicity / ranking preservation** — property test over random logits:
270
+ `g` never reorders tokens; argmax invariant; every pairwise ordering held.
271
+ 3. **KL characterization** — reuse [src/eval/kl.ts](../../src/eval/kl.ts)
272
+ `evaluateKlSelfFlag` (env lever off vs on) to *characterize* (not pass/fail)
273
+ how far each knob moves the distribution from temperature-only. Output: a
274
+ KL-vs-knob curve per model, recorded for the design log. The distribution is
275
+ *supposed* to move; the point is to map the knob space, not to bound drift.
276
+ 4. **Capability guardrail** — `bun scripts/eval.ts capability --candidate e4b`
277
+ (and 12B, the reference target) with HLG on vs off. The six tasks
278
+ (GSM8K / MMLU / IFEval / BFCL / HumanEval / HashHop) are accuracy-shaped, so
279
+ they measure the **cost**: does shaping the distribution break reasoning or
280
+ tool-calling? That is the guardrail HLG must not regress materially.
281
+ 5. **Diversity lens (the benefit)** — the six tasks won't show the upside, since
282
+ the whole point is mid-tone novelty. Add a small open-ended eval
283
+ (`src/eval/tasks/diversity.ts`): distinct-n / self-BLEU / cross-sample
284
+ entropy on a creative-prompt set, **HLG vs temperature matched to the same
285
+ output entropy**. The thesis is confirmed iff, at equal entropy, HLG yields
286
+ higher diversity without the tail-garbage temperature would import.
287
+ 6. **Perf A/B** — a `bench-compat-vs-perf`-style env-lever A/B plus a
288
+ `./benchmark.sh` row: decode tok/s + TTFT, on vs off, to show ~0 decode
289
+ regression. Lands in [benchmarks/RESULTS.md](../../benchmarks/RESULTS.md) §3.
290
+
291
+ ## Phasing (the "piece N" increments)
292
+
293
+ 1. **Pure curve + neutrality tests** — `applyHlg(lp, params)` in `sampler.ts`,
294
+ top-anchored pivot only; degeneracy + monotonicity tests green across all
295
+ four models. (No flag wired yet — pure, fully-tested function.)
296
+ 2. **Serial wiring** — CLI flags + `ServerOptions` + `toOptions`; live on the
297
+ serial server; per-request `hlg`.
298
+ 3. **Batched wiring** — gateway/scheduler sampler construction; batched
299
+ neutrality test.
300
+ 4. **Pivot modes 2 & 3** — entropy + median, behind `--hlg-pivot`.
301
+ 5. **Eval + benchmark** — KL characterization, capability guardrail, diversity
302
+ lens, perf A/B; set shipped defaults from the sweep; RESULTS.md row.
303
+ 6. **Docs** — finalize this doc, the investigation write-up, PLAN/STATUS,
304
+ server-config / server-api / README, and a memory note.
305
+
306
+ ## Open questions / risks
307
+
308
+ - **Default knob values** are calibration-pending — set empirically by the
309
+ Piece 5 sweep, not guessed. Initial exploration points: `c ≈ 6`, `w ≈ 4`,
310
+ `β_h ≈ 4`, `β_t ≈ 6` nats; confirm or replace with measured values.
311
+ - **Pivot for very low-entropy distributions** (one token ~1.0): the curve has
312
+ almost nothing to shape; verify it degrades gracefully to "near-greedy" rather
313
+ than amplifying numerical noise in the tail.
314
+ - **HLG replaces top-p/top-k** (resolved, not a rail). When HLG is on it *is*
315
+ the sampler — no top-p/top-k underneath; the toe is the smooth cousin of
316
+ min-p and does the tail control. Open question is whether the soft toe
317
+ suppresses the tail *enough* on a 262k vocab to match the hard cutoffs, or
318
+ whether garbage leaks — exactly what the `hlg-compare` harness probes.
319
+ - **Does the benefit survive the capability tasks?** If HLG measurably helps
320
+ diversity but dents GSM8K/BFCL, it ships default-off with a documented
321
+ use-case (creative/open-ended), not as a global default — consistent with the
322
+ project's default-off-flags ethos.
323
+
324
+ ## Provenance — and why the source domain doesn't justify it
325
+
326
+ This is a **cross-domain transplant**. Nonlinear transfer functions are a mature
327
+ apparatus in signal and color encoding for reshaping a value distribution under
328
+ region-dependent constraints; a logit distribution is just another value
329
+ distribution, so the apparatus carries over. HLG (Hybrid Log-Gamma, ARIB
330
+ STD-B67 / ITU-R BT.2100) is the specific structure we lift — a gamma segment for
331
+ the lower range and a logarithmic segment for the upper range, joined at a
332
+ breakpoint — because its piecewise shape maps cleanly onto "boost the mids, roll
333
+ off the extremes."
334
+
335
+ The provenance is where the *structure* comes from; it is **not** the argument
336
+ for it. That a transfer function is standard practice in another domain says
337
+ nothing about whether it helps token sampling — that is decided only by
338
+ measurement (the KL characterization, the capability guardrail, and the
339
+ diversity lens in [Correctness](#correctness--evaluation)). The full empirical
340
+ write-up goes in `docs/investigations/hlg-sampling-investigation.md` once run.