Merge nucleic/eager-glass-wren-mrb5 into dev

This commit is contained in:
2026-07-29 18:58:02 -07:00
parent 34a808befc
commit 11a566fb00
+81 -25
View File
@@ -43,10 +43,12 @@ is a classic small-model problem.
classifier is exactly the energy bill this policy exists to avoid. Both shipped models classifier is exactly the energy bill this policy exists to avoid. Both shipped models
are *designed for accelerator eligibility from day one* (fixed shapes, fp16-friendly are *designed for accelerator eligibility from day one* (fixed shapes, fp16-friendly
ops — §4.2), and scheduling is verified, not assumed (§8). ops — §4.2), and scheduling is verified, not assumed (§8).
6. **Two model sizes, one contract:** a **light** classifier every machine can run, and a 6. **A model ladder, one contract:** a **light** classifier every machine can run, a
**deep** classifier (§4.3) that meaningfully exploits ANE/NPU headroom for higher **deep** classifier (§4.3) that exploits ANE/NPU headroom for higher accuracy on the
accuracy on the ambiguous prompts the light model gets wrong. Same labels, same ambiguous prompts the light model gets wrong, and a **max** classifier (§4.4) that
calibration semantics, same wire — machines differ only in which artifact answers. spends big-GPU headroom (RTX/Radeon-class, AC power only) on the best result the
hardware can deliver. Same labels, same calibration semantics, same wire — machines
differ only in which artifact answers.
7. **No architectural churn:** the classifier slots into the existing layer stack behind 7. **No architectural churn:** the classifier slots into the existing layer stack behind
`PurposeVerdict.Source`; routing, session plumbing, UI, and wire stay as shipped. `PurposeVerdict.Source`; routing, session plumbing, UI, and wire stay as shipped.
@@ -178,11 +180,12 @@ runs quantized **7B** LLMs at usable rates ([NPU comparison](https://localaimast
the ANE side routinely serves Apple's ~3B foundation model. So the deep model is sized by the ANE side routinely serves Apple's ~3B foundation model. So the deep model is sized by
*task saturation*, not by hardware: past roughly half a billion parameters, **encoder** *task saturation*, not by hardware: past roughly half a billion parameters, **encoder**
accuracy on a fixed 8-way task flattens, and the next meaningful step up is a 13B accuracy on a fixed 8-way task flattens, and the next meaningful step up is a 13B
generative decoder — rejected, because it reintroduces exactly what this plan removes generative decoder — rejected *as the default path*, because it reintroduces exactly what
(uncalibrated generation, hundreds of ms, GB-scale memory residency) for negligible this plan removes (uncalibrated generation, hundreds of ms, GB-scale memory residency)
classification gain. Target ship size: **large-class encoder, ~400M params**, decided by for negligible classification gain on ordinary machines. (§4.4 revisits the decoder under
ablation (below), with the older base size kept as a pipeline ablation rung rather than a strict constraints as the optional GPU-max tier.) Target ship size for deep: **large-class
shipping artifact. encoder, ~400M params**, decided by ablation (below), with the older base size kept as a
pipeline ablation rung rather than a shipping artifact.
- **Architecture:** ModernBERT-class encoder, **large size (~400M params; ~150M base - **Architecture:** ModernBERT-class encoder, **large size (~400M params; ~150M base
variant trained as an ablation rung)**, **512-token window** (the hard cases are long — variant trained as an ablation rung)**, **512-token window** (the hard cases are long —
@@ -212,16 +215,59 @@ shipping artifact.
- **Same export discipline as 4.2:** fixed 1×512-token shape, fp16 (+ int8-QDQ variant), - **Same export discipline as 4.2:** fixed 1×512-token shape, fp16 (+ int8-QDQ variant),
both ONNX and Core ML artifacts, same tokenizer spec, same threshold JSON schema. both ONNX and Core ML artifacts, same tokenizer spec, same threshold JSON schema.
- **Model selection at runtime** (per machine, decided once per launch and re-checked on - **Model selection at runtime** (per machine, decided once per launch and re-checked on
asset/hardware change): asset/hardware/power change):
- deep model present **and** verified accelerator-resident (§5/§6 checks) → **deep is - max model present **and** its §4.4 eligibility holds (verified GPU rung + memory
the L1 classifier**; lite stays loaded as the instant-answer for the first keystrokes floor + AC power) → **max is the L1 classifier**;
if deep's asset is still warming; - else deep model present **and** verified accelerator-resident (§5/§6 checks) →
**deep is L1**; lite stays loaded as the instant-answer for the first keystrokes
if the bigger asset is still warming;
- otherwise → lite is L1 (which is already ≥ the current AFM path). - otherwise → lite is L1 (which is already ≥ the current AFM path).
Power transitions re-run this ladder live: unplugging mid-session steps max → deep
seamlessly (next debounce tick answers on the smaller model).
A cascade variant (lite always answers; deep re-scores only low-margin drafts) is the A cascade variant (lite always answers; deep re-scores only low-margin drafts) is the
fallback posture if deep-everywhere measures worse on energy than expected — the fallback posture if deep-everywhere measures worse on energy than expected — the
layering makes either wiring a one-line change in `PromptPurposeService`. layering makes either wiring a one-line change in `PromptPurposeService`.
### 4.4 Artifacts, conversion, versioning ### 4.4 The GPU-max classifier (`purpose-max`) — spending real GPU headroom
§4.3's sizing argument stands: past ~0.5B parameters, a *bigger encoder* buys latency,
not accuracy. So the tier above deep-large is not a larger encoder — it is a **different
kind of model** that only RTX/Radeon-class (or big-unified-memory Apple GPU) headroom
makes viable: a small **instruction-tuned decoder used as a constrained classifier**.
This deliberately *revisits* §2's decoder rejection, which was a rejection for the
*default* path (uncalibrated free generation, hundreds of ms, GB-scale residency on
every machine). Under the max tier's constraints, each objection is answered rather than
waved off:
- **Architecture:** a 1.54B instruction-tuned decoder (Qwen/Phi-class), LoRA-fine-tuned
on the same dataset and merged. Classification is **not free generation**: one prefill
over the 512-token head + a single constrained step with the logits masked to the 8
label tokens — the masked-label distribution is the output, temperature-scaled on the
validation split exactly like the encoders (this restores the calibration story the §2
rejection was about). Secondary-purpose and difficulty ride the same masked readout.
- **What it buys beyond accuracy:** a short *generated* rationale (one clause, capped
tokens) for the chip tooltip — a per-prompt "why", where the encoders can only attach
canned per-cell copy. Generation of the rationale is optional, async after the label,
and never on any routing path.
- **Eligibility (all required):** a verified GPU rung per §5/§6 (NvTensorRT-RTX /
MIGraphX / OpenVINO-GPU on Windows, Apple GPU on macOS) **and** a memory floor
(≥ 6 GB dedicated VRAM, or ≥ 24 GB unified memory on Apple silicon) **and AC power**.
On battery the ladder drops to deep on the ANE/NPU automatically — max is a
wall-power luxury by definition, and the power-transition listener swaps tiers live
(mid-draft transitions just change which model answers the next debounce tick).
- **Artifacts:** int4/int8 quantized, ~12.5 GB — a separately downloaded optional asset
("best on this machine" offer in Settings Intelligence, never auto-downloaded).
Export uses the generative stacks (ONNX Runtime GenAI format for Windows ML's runtime;
a stateful Core ML model on macOS) — meaningfully more export complexity than the
encoders, which is why max is its own late work item and not on deep's critical path.
- **Budgets & gates:** label p95 ≤ 250 ms on the eligibility-floor GPU (still well inside
the debounce window; rationale generation excluded from the budget); ships only on a
**≥ +2-point hard-slice win over deep-large** — if constrained decoding can't beat the
large encoder where it matters, max doesn't exist and the doc's saturation argument was
simply right; idle-unload is mandatory (a multi-GB resident model must never outlive
composer attention, and must never keep a dGPU awake).
### 4.5 Artifacts, conversion, versioning
- **Canonical artifact: ONNX** (opset ≥ 17), one file, one tokenizer spec (exported - **Canonical artifact: ONNX** (opset ≥ 17), one file, one tokenizer spec (exported
vocab + normalization rules — no runtime HuggingFace dependency). vocab + normalization rules — no runtime HuggingFace dependency).
@@ -231,9 +277,10 @@ shipping artifact.
the frozen test set; label agreement ≥ 99.5% and identical accuracy-to-the-gate, or the the frozen test set; label agreement ≥ 99.5% and identical accuracy-to-the-gate, or the
conversion is rejected (this is what makes "one model, two runtimes" honest). conversion is rejected (this is what makes "one model, two runtimes" honest).
- **Windows runtime:** the ONNX artifact as-is, via Windows ML (§6). - **Windows runtime:** the ONNX artifact as-is, via Windows ML (§6).
- **Naming:** `purpose-lite-v<N>` / `purpose-deep-v<N>` with `.onnx` (canonical, per-EP - **Naming:** `purpose-lite-v<N>` / `purpose-deep-v<N>` / `purpose-max-v<N>` with `.onnx`
quantization variants) and `.mlmodelc` (converted) suffixes. (canonical, per-EP quantization variants; GenAI-format for max) and `.mlmodelc`
- **Versioning:** artifacts named `purpose-<lite|deep>-v<N>.<onnx|mlmodelc>`; the version (converted) suffixes.
- **Versioning:** artifacts named `purpose-<lite|deep|max>-v<N>.<…>`; the version
string rides `PurposeVerdict.reason` provenance and the session routing note, so field string rides `PurposeVerdict.reason` provenance and the session routing note, so field
behavior is attributable to a model version. Old artifact kept for one release for a fast behavior is attributable to a model version. Old artifact kept for one release for a fast
revert (`nucleic.purposeClassifierVersion` defaults key as the pin/kill switch). revert (`nucleic.purposeClassifierVersion` defaults key as the pin/kill switch).
@@ -396,11 +443,16 @@ path to the slider later, for free.
2. **Tier-drift invariant** re-run over *model* predictions (not just heuristics), for 2. **Tier-drift invariant** re-run over *model* predictions (not just heuristics), for
both models: every test-set misroute within one cost tier at all levels/lanes — and for both models: every test-set misroute within one cost tier at all levels/lanes — and for
deep's mixed-intent path, the primary+secondary blend rule proven to stay in-bound. deep's mixed-intent path, the primary+secondary blend rule proven to stay in-bound.
3. **Parity gates:** Core ML↔ONNX label agreement ≥ 99.5% per model (§4.4); C#↔Swift 3. **Parity gates:** Core ML↔ONNX label agreement ≥ 99.5% per model (§4.5); C#↔Swift
threshold config is one shared JSON so acceptance semantics can't fork. threshold config is one shared JSON so acceptance semantics can't fork. For max, the
4. **Latency:** lite p95 ≤ 20 ms; deep p95 ≤ 100 ms *on the accelerator it's gated to* masked-label readout must additionally pass a calibration bound (ECE ≤ lite's on the
(still several debounce ticks under the 700 ms window, and never on the send path). validation split) — a decoder that classifies better but *confides* worse would poison
Measured in eval.py and asserted loosely in a perf smoke test. the accept/corroborate/escalate contract.
4. **Latency:** lite p95 ≤ 20 ms; deep p95 ≤ 100 ms *on the accelerator it's gated to*;
max label-readout p95 ≤ 250 ms on the eligibility-floor GPU (rationale generation
excluded — async, off every routing path). All still several debounce ticks under the
700 ms window, and never on the send path. Measured in eval.py and asserted loosely in
a perf smoke test.
5. **Accelerator-residency gates** (goal #5 made falsifiable): 5. **Accelerator-residency gates** (goal #5 made falsifiable):
- macOS: `MLComputePlan` ANE-op share ≥ the per-artifact floor emitted at conversion, - macOS: `MLComputePlan` ANE-op share ≥ the per-artifact floor emitted at conversion,
checked at load on-device (rung fallbacks per §5 — the GPU retry must itself pass a checked at load on-device (rung fallbacks per §5 — the GPU retry must itself pass a
@@ -419,7 +471,9 @@ path to the slider later, for free.
cycle with A/B logging *locally* (both verdicts recorded in the routing note's reason); cycle with A/B logging *locally* (both verdicts recorded in the routing note's reason);
flip default on when disagreement analysis shows the model ≥ AFM on real drafts; remove flip default on when disagreement analysis shows the model ≥ AFM on real drafts; remove
the AFM layer (L2 demotion, §5) after two clean releases. Deep rolls out behind the the AFM layer (L2 demotion, §5) after two clean releases. Deep rolls out behind the
same telemetry one cycle after lite. same telemetry one cycle after lite; max one cycle after deep, and only if its §4.4
hard-slice-over-deep-large gate held on the frozen set (a tier that can't beat the one
below it is deleted, not shipped).
--- ---
@@ -476,8 +530,10 @@ path to the slider later, for free.
| 7 | Windows ML runtime (with the port's §7 renderer) | `PurposeClassifier.cs` (Windows App SDK 1.8.1+, power-source-aware policy ladder — `MAX_EFFICIENCY` on battery; NPU→GPU (NvTensorRT-RTX/MIGraphX/OpenVINO-GPU)→CPU on AC — explicit-EP validation path, AOT compile-at-first-use), shared threshold JSON, degradation ladder | | 7 | Windows ML runtime (with the port's §7 renderer) | `PurposeClassifier.cs` (Windows App SDK 1.8.1+, power-source-aware policy ladder — `MAX_EFFICIENCY` on battery; NPU→GPU (NvTensorRT-RTX/MIGraphX/OpenVINO-GPU)→CPU on AC — explicit-EP validation path, AOT compile-at-first-use), shared threshold JSON, degradation ladder |
| 8 | `purpose-deep` training + heads | ModernBERT-class multi-task checkpoints at base (~150M) *and* large (~400M), 512-token window, ≤ 850 MB fp16 / ≤ 450 MB int8 artifacts, hard-slice +5pt-over-lite and large-vs-base ablation gates, mixed-intent blend rule in router + tests | | 8 | `purpose-deep` training + heads | ModernBERT-class multi-task checkpoints at base (~150M) *and* large (~400M), 512-token window, ≤ 850 MB fp16 / ≤ 450 MB int8 artifacts, hard-slice +5pt-over-lite and large-vs-base ablation gates, mixed-intent blend rule in router + tests |
| 9 | Deep-model distribution + selection | on-demand asset download/verify/pin (macOS-VM base-image pattern), §4.3 runtime selection ladder, accelerator-residency gating on both platforms, Settings download affordance | | 9 | Deep-model distribution + selection | on-demand asset download/verify/pin (macOS-VM base-image pattern), §4.3 runtime selection ladder, accelerator-residency gating on both platforms, Settings download affordance |
| 10 | Rollout | dark-ship + local A/B logging, lite default flip, deep one cycle later, AFM layer retirement | | 10 | Rollout | dark-ship + local A/B logging, lite default flip, deep one cycle later, max one after that, AFM layer retirement |
| 11 | `purpose-max` (optional tier, after 89 prove out) | 1.54B LoRA-fine-tuned decoder, masked-label constrained readout + calibration, GenAI-format ONNX + stateful Core ML exports, GPU+memory+AC eligibility gating with live power-transition stepping, async rationale generation, idle-unload |
Items 15 are independent of the Windows port's schedule; 6 can land any time (additive); Items 15 are independent of the Windows port's schedule; 6 can land any time (additive);
7 rides the port's renderer milestone; 89 start once item 5's hard slice exists (deep's 7 rides the port's renderer milestone; 89 start once item 5's hard slice exists (deep's
gate is defined against it). gate is defined against it); 11 starts only after deep ships and holds its gates — max is
an *optional* crown, not a dependency of anything.