Repository navigation
First-party dogfood: Qwen3.5 at a Pareto-optimal size — publish the selection rule and the evidence a consumer re-derives it from #3558
Description
Operator requirement (2026-09-20): first-party internal projects — arbiter, RAH, apex — dogfood aprender Qwen3.5 from here on. This issue states what aprender must provide. The consuming projects are internal, this repository is public, and their internal details are deliberately not reproduced here; they are irrelevant to what we owe.
The requirement
- Qwen3.5 is the dogfood model family for first-party internal consumers. Not "a Qwen model" — Qwen3.5, the family 0.68.2 shipped on CPU and CUDA for 0.8B/2B/4B/9B/27B.
- Size selection is Pareto-optimal: prefer the smallest size that works, where "works" is measured, not assumed. Bigger is not safer; a larger model that clears the bar with headroom nobody needs costs VRAM, latency and fleet time that other work needs.
- The selection must be reproducible from committed evidence, so a consumer can re-derive "which size should I use" without asking a person.
What "Pareto-optimal" has to mean to be checkable
A size is admissible when it clears the capability bar for the task class, and selected when no smaller admissible size exists. The frontier is over:
- quality — the capability-ladder rungs for that task class, plus CPU-vs-CUDA parity at the serving shape (Name the Qwen model 0.69 blesses and commit its parity receipt at the SERVING shape — our gates are all single-stream #3555): a size whose parity receipt was taken at m=1 is not admissible for a batched consumer
- cost — peak VRAM, model bytes, and measured latency/throughput at the serving shape on each fleet GPU (sm_89 and sm_121 differ; 27B fits a GB10 very differently from a 24 GB 4090)
Any size on that frontier is defensible; a size above the frontier — a larger one where a smaller admissible size exists — must be justified in writing or replaced.
Acceptance
- A committed selection table per task class:
{task_class, admissible_sizes[], selected_size, frontier_evidence}, derived from the ladder and parity receipts already inevidence/, not hand-written. aprcan answer it: a command that, given a task class and a host, prints the selected size and the receipt paths behind it. A consumer that has to read a wiki has not been given a Pareto rule, it has been given folklore.- Re-derivable: re-running the derivation on the committed evidence reproduces the table byte-for-byte.
- The selection is re-derived per release, not frozen — 0.69's decode fixes (P0: batched CUDA decode emits garbage for every m>1 — PERF-001's 3.32x aggregate is throughput of garbage tokens #2753, cuBLAS decode route diverges at m>=4: coherent but different continuation, so c=4 fails parity while c=2 passes #2770) can move the frontier, and a stale table is worse than none.
Priority
Equal to the ontology/SHACL work (see #3080). Both are release-blocking for 0.69.
Refs #3080, #3555, #2753, #2770
Measured facts for whoever takes this, so the selection starts from evidence
Added by the cop 2026-09-20. All measured today on noah-Lambda-Vector (RTX 4090, sm_89) with GPU occupancy recorded at start, unless stated.
1. Every validated Qwen3.5 rung is Q4_K_M. 0.8B / 2B / 4B / 9B / 27B, sha256 in contracts/model-capability-ladder-v1.yaml. The "20/20 CPU+CUDA correct" behind 0.68.2 is a Q4_K_M result and it was published without that qualifier.
2. The GPU quant whitelist is exactly F32, Q4_0, Q4_1, Q5_0, Q8_0, Q4_K, Q5_K, Q6_K (crates/aprender-serve/src/gguf/dtype.rs:46). Every IQ* type, plus F16, Q2_K, Q3_K and BF16, is gated to CPU. Unsloth UD-* builds are mixed-precision and keep sensitive tensors at F16, so they run CPU-only — silently. A user hit this today and concluded his own files were wrong (#3077, raised to P1 on that evidence).
3. Decode is ~370 tok/s against llama.cpp's 179–189 on the same box and file — roughly 2× faster. The published parity headline understates it.
4. Time-to-first-token is 14–16 s against llama.cpp's 1.8–2.9 s, and 67 % of that is one guard. f2_validate_qwen35 runs a full CPU reference forward before the user's first token, on every invocation, saturating at ~9.5 s because QWEN35_F2_PROBE_MAX = 64. Split measured: 90–93 % CPU reference, 6–9 % GPU probe. #3604 caches it per (model sha256, apr version, device).
5. On the dense path, --gpu is currently 2–3× SLOWER than --no-gpu — the GPU result fails its own cosine check (0.4153@1) and falls back to CPU after the user has paid for the attempt (#3602, P0).
The constraint that matters most to a Pareto selection, and it is not parameter count
Say which TTFT regime you measured in. "Smallest that works" chosen against a 14 s TTFT is a different answer than against a 2 s one, and #3604 moves that number by ~9 s without touching a kernel. A size selected today inverts when it lands.
That is the difference between a selection rule and a snapshot, and it will be invisible to a fresh reader six weeks from now unless the receipt states the regime explicitly. The rule should be expressed so it survives #3604 — e.g. against decode throughput and quality at a stated TTFT budget, not against measured wall clock.
Ownership
Not apex. Routed there on 2026-09-20 and correctly declined on a fact: apex runs no local model — its only aprender dependency is aprender-viz, a plotting crate, and APEX-001 §1 states "Not an LLM wrapper. The LLM writes one file (study.toml) and is absent from the derive, adjudicate and render paths." The qualification this row needs — a consumer that runs the model in anger — is the one apex most clearly lacks.
This needs arbiter or RAH. Still unassigned.
Activity
noahgift commentedon Sep 20, 2026
Goal A's floor is unreachable today, and the cause is #3571. The floor names
apr serve— andapr servecannot load Qwen3.5 at all (measured 2026-09-20:Architecture 'qwen35' … runs through Qwen35Model, with CUDA built in, on a fileapr runanswers correctly on 20/20 cells across two GPU hosts).Two consequences for the Pareto selection rule this issue defines:
apr runlatency and memory is a size chosen on a path no consumer uses. Peak VRAM under a long-lived server with a KV cache is a different number from a one-shot run, and the frontier moves with it.Provisional pick from the P0 chain is
Qwen3.5-9B-Q4_K_M; that remains provisional until the rule runs, and it should run onapr serve.noahgift commentedon Sep 20, 2026
Correction to my note above (operator, 2026-09-20). I wrote that goal A's floor is unreachable today because it names
apr serve. True, and it must not be read as permission to wait: consumers adopt the CLI now. The Pareto selection rule should be exercised againstapr runimmediately — with the axes pre-registered as this issue requires — and re-run on the serving path when #3571 lands, because peak VRAM and latency under a resident server differ from a one-shot run and the frontier moves with them.First receipted cell exists as of today: Qwen3.5-9B-Q4_K_M on the agent host, min cosine 0.9986588, PASS (#3574 / PR #3575). The provisional pick now has one measured cell behind it instead of none.
noahgift commentedon Sep 23, 2026
milestone → 0.71.0 per docs/roadmaps/milestone-triage-2026-09-23.md (#4024), operator approval 2026-09-23 (relayed by aprender-cf). Reason: first-party Qwen3.5 selection + evidence: part of the certified matrix (#3994)
noahgift commentedon Sep 25, 2026
MRS-08 (paiml/infra MRS-001 §4, epic paiml/infra#1083): the selection rule should include Qwen 3.6.
Falsifiable ask: the selection evidence for this issue names every candidate size tested. It must include Qwen3.6-27B and Qwen3.6-35B-A3B beside the Qwen 3.5 sizes (4B, 9B, 27B, 35B-A3B, and larger where the hardware allows).
For each candidate, record:
aprload it? Yes or no, with the exact version and weights sha. MRS-001 G9 marks this unknown[U].[X]". Vendor agentic-coding scores are design input only, never a threshold.This is why it matters: tier L (local
apr serve) is the start tier formechanicalandtriagephases under the routing cascade. The quorum's third lineage (R-5) also depends on the model this issue selects.feat(cli): apr capability --select <consumer> [--host] answers the Qw…
feat(release): re-derive the Qwen3.5 size selection on every bump (#3558
1 remaining item
noahgift commentedon Oct 14, 2026
P0 to P1 (2026-10-14 P0 triage): P0 now means it blocks the next release or carries the operator's own words on it; this issue does neither, so it stays on the 0.71.0 milestone at P1.
noahgift commentedon Oct 14, 2026
merged into #5317 (master ticket for epic #4381; triage rule 7b, 2026-10-14). It is a checklist row there; reopen this issue when work on it starts or its PR opens.