diff --git a/.agents/model-matrix.md b/.agents/model-matrix.md
index c339fee66..d360a63df 100644
--- a/.agents/model-matrix.md
+++ b/.agents/model-matrix.md
@@ -121,7 +121,7 @@ Engaged architectures (the 55 non-`INVENTORIED` rows):
| π§ | `KimiLinearForCausalLM` | Kimi-Linear-48B-A3B | **PAGED-INCREMENTAL DECODE LANDS the 5Γ speed win (2026-08-07, Β§19, `row/KIMI-PAGED-INCREMENTAL` #113):** the Β§18 real lever (e) BUILT β `KimiDecodeCache` + `ForwardPrefillIncremental`/`ForwardDecodeStepIncremental` (`kimi_linear_device.cpp`): prefill-once (KDA recurrent+conv state carried via `vt::KdaGatedDeltaRule` state in/out + `vt::CausalConv1dFwd` tap-carry; NoPE-MLA latent-KV cached) + recurrent decode-step, MIRRORING vLLM `kimi_gdn_linear_attn._forward` (prefill=`chunk_kda_with_fused_gate` output_final_state / decode=`fused_recurrent_kda` initial_state, `vllm-src` `a4e3cb4`; divergences: host state vs paged slot cache, materialized-MHA MLA vs paged-FA2 β named residuals). CPU byte-exact state-carry gate `test_kimi_linear_forward` **15/15Β·875** (NEW case l: carried decode == fresh full-recompute byte-identical + greedy-identical). Full 48.9B GB10 (single-load/config, flock, drop_caches, min-avail 18-21 GiB, no reboot, Β§12 golden md5 `bfa5bdbf`): recompute 122/128 @ 4.23 tok/s (reproduces #111); incremental+recurrence 120/128 @ 16.63; **incremental+chunk-prefill 122/128 @ 18.87/19.03 tok/s (2 runs) β token-IDENTICAL to recompute (Gate A PASS, p7 `got` byte-exact) = 4.5Γ over recompute, 0.90Γ of vLLM ~21 (the 5Γ decode gap 0.20Γβ0.90Γ)**. Gate B STRICT NOT reached (122/128): chunk-prefill in the RIGHT vehicle reproduces recompute EXACTLY, does NOT close p7 β REFUTES the #111 "p7 in the right vehicle β STRICT" hypothesis; p7 intrinsic (Β§13/Β§14 f32-vs-bf16 near-tie at a comma). Decode decomposition (nsys, ours, 99 steps, same-tool): **~90% is the SAME cuBLAS `internal::gemvx::kernel` vLLM calls (batch-1 GEMV-parity)**, KdaScanKernel 2.3%, MoE glue 2.3%, CastBf16 3%; chunk kernels 20 inst = prefill only (prefill=chunk/decode=recurrent IN VIVO). Killing O(nΒ²) ALONE reaches parity-class; no lever load-bearing beyond it β residual = ~15% host-orchestration idle + 3% CastBf16 (a bf16 residual stream = the ONE lever ALSO closing the p7-STRICT near-tie) + paged-FA2 MLA decode. vLLM-live-nsys@0.82 NOT run (box-safety: 95-98 GiB reservation + nsys below the 15 GiB LIFE-CRITICAL floor). `--incremental` opt-in; `VT_KIMI_DEVICE_KDA`/`_CHUNK` STAY OFF (122/128 β STRICT). Row STAYS π§. **chunk_kda PREFILL PHASE-2 MEASURED β op CORRECT, chunk-EVERY-STEP REGRESSES 122β102 (2026-08-07, Β§18, `row/KIMI-CHUNK-KDA-P2` #111):** the `chunk_kda` prefill family regenerated + vendored for ALL 6 arches (reproducible β only new `kda_*`+MANIFEST; GDN cubins byte-identical; drift GREEN) + wired through the new op `vt::KdaChunkPrefill` (the 6-cubin `_chunk_kda_fwd_with_cumulative_g`; `cuda_gdn.cu.o` -Werror clean; RED-first unit `test_ops_kda_chunk_prefill` **2/2Β·4** on GB10 β chunk-vs-recurrence mean_abs **4.68e-5**, wrong-gate **72Γ**; GDN untouched 66/66Β·4242). Full 48.9B GB10 gate (flock, min-avail 21 GiB, no reboot): control device-KDA reproduces **122/128, 4.24 tok/s** EXACTLY; **+chunk-prefill (`VT_KIMI_DEVICE_KDA_CHUNK`) REGRESSES to 102/128, 4.08 tok/s** (p3 16β3, p6 16β11). Root cause: the island's O(nΒ²) recompute applies chunk EVERY decode step over the growing sequence β NOT vLLM's prefill=chunk/decode=recurrent split β so it coin-flips near-ties the recurrence-every-step (control) doesn't (the recurrence matches vLLM's DECODE; chunk only matches its PREFILL). vLLM speed arm (Β§12 recipe, util 0.82, triton MoE, eager, single-seq; min-avail 15 GiB, no reboot): **~21 tok/s median** 16-token aggregate (25.3 cold-discarded; TTFT not isolable in 0.25.0) vs ours **4.24** (recurrence) / **4.08** (chunk) STEADY decode β **ours/vLLM β 0.20** (vLLM ~5Γ faster on decode β the O(nΒ²)-recompute vs paged-incremental distance, = the coupled STRICT+speed lever). `VT_KIMI_DEVICE_KDA_CHUNK` STAYS OFF (a regression isn't a flip); device-KDA (122, OFF) still best. The op + regen are the validated prefill half of the named real lever (e) paged-incremental decode (chunk-prefill ONCE + recurrent-decode over PERSISTENT state β kills the O(nΒ²); the STRICT + speed lever, coupled). Row STAYS π§. **DEVICE-KDA GB10 122/128 + 4.24 tok/s (Β§15, #104); device NoPE-MLA lever MEASURED-NEGATIVE (2026-08-07, Β§16, `row/KIMI-STRICT-CLOSE` #107):** the per-channel-decay device recurrence `vt::KdaGatedDeltaRule` moves 106β**122/128** (p0-p6 16/16; sole p7 pos-6 comma near-tie) AND **1.35β4.24 tok/s (3.1Γ)** β vLLM's ACTUAL f32-on-bf16 arithmetic, beats Β§14's host-precision 120. The Β§15 residual (d) was attempted in device-COMPUTE form: `VT_KIMI_DEVICE_MLA` routes the 7 NoPE-MLA layers' softmax core through `vt::Attention` (pad-V: value zero-padded qk_nope+qk_rope=192 vs v=128, `out[:,:,:v]` byte-exact). CPU RED-first gate GREEN (`test_kimi_linear_forward` **14/14Β·825**, pad-V==f64 ref rtol 3e-3; perturbation fails 108). Full 48.9B GB10 gate (single-load, flock, min-avail 21 GiB, no reboot): control device-KDA reproduces **122/128, 4.24 tok/s** EXACTLY; **+device-MLA REGRESSES to 109/128 AND 3.89 tok/s** β `vt::Attention`'s f32 online-softmax is the right math but a DIFFERENT reduction order than vLLM's FA2, so it coin-flips near-ties (breaks p3 16β3 into Β§14's `163586Γ` repeat) and the per-(t,h) build slows the O(nΒ²) recompute. `VT_KIMI_DEVICE_MLA` STAYS OFF, kept as a documented-MEASURED-NEGATIVE A/B knob (Β§14 `ISLAND_F32ACC` precedent). MLA dims VERIFIED from the real config (nah=32, qk_nope=128, qk_rope=64, v=128, kv_lora=512, q_lora=None; 7 full-attn/20 KDA). Both device knobs default OFF (122 β STRICT, K=3-deterministic golden). STRICT residual, sharpened: needs vLLM's ACTUAL kernels β (c) chunk_kda prefill family (Triton-AOT regen for sm_121a) + (d) paged FA2 `mla::ForwardMlaAttentionBlock` (NOT the vt::Attention approximation) + (e) paged-incremental decode (needs a decode/paged-attn op, query_lenβ key_len; kills the O(nΒ²)) β each a substantial multi-kernel brick (Β§16). Row STAYS π§. **FULL-MODEL GB10 e2e RUNS β NEAR-TIE 106/128 (2026-08-06, `row/MODEL-KIMI-LINEAR-BF16`):** the bf16-resident path CLEARS the f32-loader block β the full 48.9B model now runs e2e on one GB10. dgx CUDA build (`-Werror` clean, 14 GDN AOT symbols nm-linked, `test_kimi_linear_forward` 13/13Β·656 in the CUDA binary); `kimi-linear-gen --gpu` greedy-decodes the Β§12 8-prompt battery x16 vs `greedy_ids.npy`. MEMORY: load 117.6s, host RSS PEAK **1.7 GiB** (stage-then-ReleaseHost), device peak 98.5 GiB, min-avail **21.6 GiB** (above the 15 GiB floor, matches the ~25 GiB pool-math headroom), NO OOM/reboot. TOKEN gate **NEAR-TIE 106/128 (82.8%)** β prompts 0,1,3,4,5,6 are 16/16 token-exact, p2/p7 diverge at punctuation/word near-ties; 96 consecutive exact tokens across 6 prompts prove the WIRING (a wiring bug can't). Root cause (honest): the f32 residual stream + host-f64 islands are MORE precise than vLLM's bf16 device kernels, so they flip the argmax where vLLM's deterministic bf16 top-1 has a small margin. STRICT path = the named W7-speed residuals (device GDN/MLA islands -> bf16 stream matching vLLM's rounding). 1.59 tok/s (recompute+island rate). `VT_KIMI_DEVICE_COMPUTE` STAYS OFF (parity-enablers: near-tie != token-exact). Row STAYS π§. **bf16-RESIDENT loader/forward IMPLEMENTED + CPU-gated (2026-08-06, `row/MODEL-KIMI-LINEAR-BF16`):** the Β§13 design is coded β `LoadKimiLinearResidentBf16Weights`/`StageKimiResidentBf16`/`BuildKimiResidentFromHost` (`kimi_linear_weights.cpp`; `LoadBf16Direct` -> `OwnedTensor`, per-tensor stage-to-`d_dev` + `ReleaseHost`, tiny vectors host f32), `KimiLinearResidentWeights` (`kimi_linear.h`), bf16 device forward `DeviceForwardBodyBf16` + `Gemm Bf16` cast-act at ~20 GEMM sites with the two host-fallback islands EXTRACTED+shared (`kimi_linear_device.cpp`), `ForwardDevice` resident-path dispatch (`kimi_linear.cpp`), and the `kimi-linear-gen` e2e harness. CPU **13/13Β·656** (12/12Β·614 f32 path UNTOUCHED + NEW tiny-config bf16-vs-f32 gate). PENDING: dgx CUDA build + full-model GB10 e2e vs the STRICT golden. Row STAYS π§. **bf16-RESIDENT brick POOL-MATH+DESIGN (2026-08-06, `row/MODEL-KIMI-LINEAR-BF16`):** pool math CLOSES (91.5 GiB bf16 device-resident + ~2.4 GiB act/norms/ctx β 94 GiB, ~25 GiB headroom); design grounded Β§13 (Laguna `GemmBf16` cast-act + `OwnedTensor::d_dev`, `LoadBf16Direct`, f32 `MaterializeHost` kept for the unit gate). Impl (loader/forward rewrite + gate + e2e) pending. Row STAYS π§. **Β§8 GOLDEN CAPTURED β STRICT (2026-08-06, `row/MODEL-KIMI-LINEAR-E2E`):** the Β§8 SACRED oracle golden is captured on GB10 (0.25.0-stage, util 0.82, moe=triton, min 15 GiB avail, NO reboot), **8/8 prompts DETERMINISTIC over K=3 β STRICT gate**, committed at `tests/parity/goldens/kimi_linear_greedy/`. Full our-engine e2e BLOCKED on OUR f32 loader (materializes ~183 GiB > 119 pool), the bf16-residency residual; row STAYS π§. **W7 GPU-VERIFY (2026-08-06, branch `row/MODEL-KIMI-LINEAR-GPU`):** the device compute runs **12/12Β·614 GREEN on GB10 sm_121a CUDA build**, BOTH arms (`VT_KIMI_DEVICE_COMPUTE=1` + host-ref); prod stack (CUTLASS-NVFP4 GEMM + FA2 ENABLED + Triton-AOT GDN, 14 cubins nm-verified); f32 device==W2 ref, no divergence, no DeepSeek-class trap. Oracle gateability re-confirmed (0.25.0-stage registers `KimiLinearForCausalLM`). e2e Β§8 SACRED golden STILL disk-blocked (91.5 GiB checkpoint absent, dgx root 100% full, 34G free). Row STAYS π§. **W7 DBuf-resident device COMPUTE landed, CPU-gated** (`CLAIM-KIMI-LINEAR-W7`): the real device compute (`ForwardDeviceCompute`, `kimi_linear_device.cpp`) composes the whole 27-layer KDA/NoPE-MLA + 256-expert-MoE hybrid over pooled f32 `DBuf`s through the SHARED `vt::` ops (embed/`FusedChain` add+RMSNorm/`MatmulBT` projections/`CausalConv1dFwd` convs/`L2Norm`/`RmsNormGated`/`MoeRouterTopK` sigmoid-`noaux_tc`/`MoeSiluMul`/`MoeCombine`/lm_head), returning DEVICE-RESIDENT logits; 2 documented HOST-FALLBACK islands (the KDA per-k-channel gated-delta recurrence + its exp/softplus decay gate β `vt::GdnDecode` carries only a per-HEAD scalar decay; the NoPE-MLA softmax core β the paged `mla::ForwardMlaAttentionBlock` device path is born-on-runner) are the W7-speed residuals. CPU-gated vs the W2 host reference (the CPU backend runs the SAME `vt::` dispatch): `test_kimi_linear_forward` **12/12Β·614** (per-op KDA/NoPE-MLA/MoE/dense device==ref within f32-accumulation tolerance; the whole `ForwardDeviceCompute` == ref logits + greedy-token-identical + device-resident). Runner opt-in via `VT_KIMI_DEVICE_COMPUTE=1` (default OFF keeps the CPU-verified W6 host-ref compose). GPU numerics (bf16 activations, GDN Triton-AOT cubins, paged het-KV, grouped-MoE slabs) + the e2e SACRED golden stay a NAMED pending (box down) β row STAYS π§. ON TOP OF **W6 DEVICE forward SEAM** (`CLAIM-KIMI-LINEAR-W6`): the born-on-the-runner `ForwardDevice` (the DEFAULT `gather_logits` runner path) no longer refuses β it composes the `[rows,vocab]` logits via the CPU reference and hands them back DEVICE-RESIDENT (a pooled `DBuf`, wrapped like deepseek_v2 `WrapDeviceLogits`; `on_device()==true` on CPU+CUDA) so the on-GPU sampler consumes them with NO host download. Kimi-Linear now ROUTES device-resident (`check-runner-routing-consistency` reclassifies it, refuse-skipped stubs 2β1, NO allowlist; `check-fusion-consistency` green); `test_kimi_linear_forward` **7/7Β·300** (adds the `ForwardDevice`==host-ref device-resident gate). The DBuf-resident device COMPUTE (KDA via the GDN family, NoPE-MLA via `mla::ForwardMlaAttentionBlock`, DeepSeek-V2 grouped-MoE over the paged het-KV; full plan in `kimi_linear.cpp`) is the GPU-verify-pending W7 residual. ON TOP OF **W2-W6 CPU REFERENCE forward** (`CLAIM-KIMI-LINEAR-W2`): the real host `KimiLinearModel::Forward` composes the whole 27-layer hybrid from the landed primitives (KDA layer via `vllm::kimi_kda` refs + the gated-delta recurrence; NoPE-MLA materialized-MHA ref; sigmoid `noaux_tc` MoE + shared expert; dense SwiGLU); loader now materializes host float weights; `test_kimi_linear_forward` 6/6Β·246 (per-op gates + finite whole forward + greedy decode). ON TOP OF **W1 scaffolding** (registry + `ParseKimiLinearParams` 20 KDA + 7 NoPE-MLA + index-verified name-map + het-KV spec). e2e-gateable (FITS one GB10, 0.77Γ pool). RESIDUAL = the DEVICE born-on-runner forward (KDA kernel/absorbed-MLA/grouped-MoE slabs) + the W0/W7 e2e SACRED golden. **ROW 7 RUNNER FOLD (2026-08-07, Β§21, #122): Kimi decode now runs THROUGH `ModelRegistry::Forward` on the runner's paged state (B1 config synthesis, B2 KDA-paged via `KdaChunkPrefill`/`KdaGatedDeltaRule` over `gdn_state`, B3 paged NoPE-MLA with `mla::ForwardMlaAttentionBlock` default-ON, B4 `vllm_complete_tokens` ABI v13 + thin-client example). GB10: engine==CLI 128/128 byte-identical, vs golden 122/128 (the intrinsic near-tie profile), SACRED post-fold green (35B 315/315, 27B 235/235); server stream 19.0 tok/s wall vs vLLM ~21 (~0.90Γ) = the open speed residual.** Row stays `ACTIVE` on the speed thread | `MODEL-TEXT-kimi-linear-kimi-linear-for-causal-lm` |
| π | `MuseGlimmerForConditionalGeneration` | Muse Glimmer 30B (Meta, agentic multimodal; iRoPE + gated attn + perception encoder + DFlash) | **W0-W7 ON `row/MODEL-MUSE-GLIMMER` (PR #279, NOT merged): 52-layer text forward, 50-layer perception encoder, mm wiring, ATEM reasoning + tool parsers β the forward no longer refuses.** The evidence behind that is NARROW and says so: text agrees with a torch transcription of #51655 and with HF's own `muse_glimmer` on REAL 30B tensors at **reduced depth 4/52 only** (5 prefill argmax positions, no generated tokens); full depth never ran, multi-step decode is untested, the perception encoder has NO reference check, nothing has run through the server, and the ATEM parsers' channel scoping does not work at server defaults (the seam has no `adjust_request` dispatch site and `skip_special_tokens` defaults true, so the framing is stripped first). The lifecycle token stays `SPIKE`/π deliberately: advancing it owes `docs/STATUS.md` and `.agents/NOW.md` rows, and both are byte-exactly at their shrink-only ratchet/budget, so the advance belongs to the landing commit that can pay for them. Released 2026-08-08, **BEYOND-PIN**: no Muse code at `555967922` nor on vLLM `main`; the only upstream impl is the OPEN PR [#51655](https://github.com/vllm-project/vllm/pull/51655) head `075d645af` (approved, 3/20 CI red), ported from on explicit developer direction as a tracked exception (porting-inventory Β§9 deviation 16). **No oracle β no speed axis is claimable**; correctness gates against the HF reference. Text tower fully traced (Gemma-style sandwich norms w/ baked +1 offset + split eps, Llama-4-style iRoPE NoPE/full vs RoPE/sliding, weightless pre-RoPE QK-norm, ~3.87 query pre-scale w/ dual config schema, Qwen3.5-style attn output gate reading the LAYER INPUT); 50-layer perception encoder (linear patchify, bilinear pos-emb interp, width-first 2D RoPE, block-windowed attn, pixel-shuffle merge) reuses the Qwen3-VL vision seam; DFlash is recognition + `is_neox_style` threading on the existing speculator, not a new drafter | `MODEL-MM-muse-glimmer-muse-glimmer-for-conditional-generation` |
| π | `KimiK3ForConditionalGeneration` | Kimi K3 (2.8T MoE + MoonViT-V2, DERIVE-AND-SHIP) | **W2/W5 CPU scaffolding landed** (registry stub + nested text/vision/quant config descent + text-backbone structural name-map + REFUSE-by-name forward + MXFP4-refuse loader; clean CPU build, scaffold gate 6/6). text backbone IS `KimiLinearForCausalLM` (KDA+MLA+MoE hybrid, HEAVY reuse); **does NOT fit GB10 (~1.56 TB MXFP4, ~12Γ)** and NOT in the pinned oracle β no on-box golden β DERIVED, proxy-gated on Kimi-Linear-48B; forward + MXFP4 + KDA delta + MoonViT-V2 not implemented (NOT-YET-BUILDABLE) | `MODEL-MM-kimi-k3-kimi-k3-for-conditional-generation` |
-| π | `Dots3NoteForCausalLM` | dots3-note (280B-A16B multimodal MoE: DeepSeek-V3.2 text tower + sliding-window MLA, MoE ViT, `dots` audio encoder) | **W2 LANDED (the whole weight map): the complete released shard index read for real β 38006/38006 accounted, 35381 language / 2195 vision / 430 audio, every bucket asserted BY NUMBER, zero unaccounted, and the two tower files carried as NAMED W6/W7 deferral records rather than integer counters.** Headers only: 4770592 bytes over 133 safetensors headers, no tensor byte. It settled three things the W1 slice could not β the backbone has exactly FOUR distinct layer shapes so the 1/2 repeat holds, the full/sliding split derived from the shipped indexer tensors matches `config.layer_types` exactly, and the checkpoint carries 62 F32 tensors in TWO families (the 45 language `e_score_correction_bias` W1 predicted plus 17 vision `router_bias`, spec R5's shape). And it FOUND one: the index declares `indexer_rope_layout: "leading"` / `converted_from: "tail"`, which no upstream code reads ([#1846](https://github.com/mudler/vllm.cpp/issues/1846)); W3 owes the slice. **W1 LANDED (config + registry): the arch RESOLVES, parses the REAL released `config.json`, and accounts 1614/1614 tensors on a committed slice of the released shard index; load, GGUF and the forward each REFUSE BY NAME.** All six Β§4 config traps are gated RED-first (evidence table in spec Β§4.1), which matters more here than on any other row because spec Β§6.4 records that NO oracle runs on hardware we own, so no token gate exists downstream. W1 also RESOLVED Β§1.4 from the checkpoint: exactly ONE nextn layer (`model.layers.46.*`, 18 tensors) with the SLIDING geometry and a DENSE MLP, and no `shared_head.head.weight` (`has_own_lm_head=False`); and CORRECTED spec Β§4 item 6 ([#1804](https://github.com/mudler/vllm.cpp/issues/1804)) β BOTH MLA ropes are GPT-J (`deepseek_v2.py:1093-1098` for the full class), the geometries differ on the THETA (5e4 vs 8e7), not the layout. Memory format recorded: `mlp.gate.e_score_correction_bias` ships F32 in an otherwise BF16 tower. Row stays `SPIKE` deliberately β making an arch resolve is not porting a model, and the Β§8.1 heading restructure `ACTIVE` requires belongs to the brick where the forward stops refusing. W0 scope, unchanged below. Upstream subclasses DeepSeek (`Dots3NoteModel(DeepseekV32Model)`, `Dots3NoteMoE(DeepseekV2MoE)`), so our gated MLA + DSA indexer + `noaux_tc` router + Qwen3-VL vision + Voxtral audio carry most of it; net-new is windowed MLA over 33 of 46 layers with a second latent geometry (576 vs 1088 rows), the padded/heterogeneous MLA KV spec, the headwise attention gate, the MoE ViT and the `dots` audio stem. **BEYOND-PIN** (vLLM `main` only, `#51255`, still being patched) and **oracle-memory-infeasible**: ~576 GB bf16 / ~290 GB fp8 against a 119-122 GiB ceiling on every host we own, so no performance axis is claimable and no token gate can bind until Β§6.4 of the spec is answered | `MODEL-MM-dots3-note-dots3-note-for-causal-lm` |
+| π | `Dots3NoteForCausalLM` | dots3-note (280B-A16B multimodal MoE: DeepSeek-V3.2 text tower + sliding-window MLA, MoE ViT, `dots` audio encoder) | **W6a LANDED (2026-09-01, [#2512](https://github.com/mudler/vllm.cpp/issues/2512)): the DENSE half of the VISION TOWER is SERVED end to end.** An `image_url` chat request travels `ApiServer::handle_chat_completions` -> the architecture-dispatched multimodal chat seam (`REGISTER_VLLM_MM_CHAT`, #2481) -> `GPUModelRunner::execute_mm_encoder` (#2398) -> `ModelRegistry::EmbedMm` -> `ModelRegistry::Forward`, and `kDots3NoteFactory` now carries `encode_mm`/`embed_mm` with `supports_multimodal` TRUE again. The arm is `patch_embed` -> blocks 0-24 (fused `attn.qkv`, per-head `q_norm`/`k_norm` BEFORE a 2-D vision RoPE, bidirectional attention, three-tensor SwiGLU through `layers::MlpGateUpMethodBase`) -> `post_trunk_norm` -> the `patch_merger` adapter folding 4x1536 to 5120, plus a dots3 image processor whose placeholder marker is the checkpoint's own image start/pad/end token triple rather than Qwen3-VL's. **The RELEASED checkpoint still REFUSES**, by name, at its first MoE ViT block: 17 of 42 vision blocks are MoE and 1960 of the 2195 `vision_encoder.*` tensors are W6b's β W3's polarity applied to the second tower, not a new exception. Ported from vLLM `vision.py` (677 lines) / `vision_attention.py` (477 lines) / `common/processor.py` read at `9035151d6`, which is BEYOND our pin `5559679229`; every anchor names that SHA because `vision_attention.py` is already 494 lines at vLLM `main` `7a100bb61`. Gate is a CONSISTENCY gate (spec Β§6.4 option B): an independent in-test double-precision reference sharing no helper with the implementation, RED-first, plus a served-request reachability suite whose load-bearing case is two DIFFERENT images compared on LOGPROBS. No performance number is claimable on any axis. Spec Β§7's vision FP8 formula and Β§8's R5 MOVED from W6 to W9 in the same change, because the W2 census below shows the bf16 checkpoint ships no scale tensor at all. **W5 LANDED: `Dots3NoteDeviceRefusal` returns "" for the RELEASED config** β the 45 MoE layers decode through `Dots3NoteMoeBlock` over the shared `RunMoePlaced` seam, and W5c ([#2176](https://github.com/mudler/vllm.cpp/issues/2176)) removed the nextn refusal, which was STRICTER THAN UPSTREAM. Representable is not runnable: the MoE alone is 545.82 GB of a 576.89 GB checkpoint. **W4b-3c LANDED: the DSA lightning indexer's SELECTION is on the decode path** β a step whose requests are all single-shot prefills is served SPARSELY; a step in which any request resumes is refused by name, because the indexer's own key cache is `KV-DSV4-MULTICACHE` ([#1925](https://github.com/mudler/vllm.cpp/issues/1925)). **W4b-2 LANDED: the SLIDING arm decodes over a PADDED 1088-wide MLA cache row** narrowed per layer, its two windowed CUDA ops compiled and run on `orin:gpu0` (sm_87) under an `rc` lease. **W4b-1 LANDED** the sliding host maths, **W4a LANDED** the full-attention layer on the decode path with dots3's two LoRA rescales, its `k_rope_only_layernorm` and its headwise gate, and **W3 LANDED** the first host reference on this row. **W2 LANDED (the whole weight map): the complete released shard index read for real β 38006/38006 accounted, 35381 language / 2195 vision / 430 audio, every bucket asserted BY NUMBER, zero unaccounted, and the two tower files carried as NAMED W6/W7 deferral records rather than integer counters.** Headers only: 4770592 bytes over 133 safetensors headers, no tensor byte. It settled three things the W1 slice could not β the backbone has exactly FOUR distinct layer shapes so the 1/2 repeat holds, the full/sliding split derived from the shipped indexer tensors matches `config.layer_types` exactly, and the checkpoint carries 62 F32 tensors in TWO families (the 45 language `e_score_correction_bias` W1 predicted plus 17 vision `router_bias`, spec R5's shape). And it FOUND one: the index declares `indexer_rope_layout: "leading"` / `converted_from: "tail"`, which no upstream code reads ([#1846](https://github.com/mudler/vllm.cpp/issues/1846)); W3 owes the slice. **W1 LANDED (config + registry): the arch RESOLVES, parses the REAL released `config.json`, and accounts 1614/1614 tensors on a committed slice of the released shard index; load, GGUF and the forward each REFUSE BY NAME.** All six Β§4 config traps are gated RED-first (evidence table in spec Β§4.1), which matters more here than on any other row because spec Β§6.4 records that NO oracle runs on hardware we own, so no token gate exists downstream. W1 also RESOLVED Β§1.4 from the checkpoint: exactly ONE nextn layer (`model.layers.46.*`, 18 tensors) with the SLIDING geometry and a DENSE MLP, and no `shared_head.head.weight` (`has_own_lm_head=False`); and CORRECTED spec Β§4 item 6 ([#1804](https://github.com/mudler/vllm.cpp/issues/1804)) β BOTH MLA ropes are GPT-J (`deepseek_v2.py:1093-1098` for the full class), the geometries differ on the THETA (5e4 vs 8e7), not the layout. Memory format recorded: `mlp.gate.e_score_correction_bias` ships F32 in an otherwise BF16 tower. Row stays `SPIKE` deliberately β making an arch resolve is not porting a model, and the Β§8.1 heading restructure `ACTIVE` requires belongs to the brick where the forward stops refusing. W0 scope, unchanged below. Upstream subclasses DeepSeek (`Dots3NoteModel(DeepseekV32Model)`, `Dots3NoteMoE(DeepseekV2MoE)`), so our gated MLA + DSA indexer + `noaux_tc` router + Qwen3-VL vision + Voxtral audio carry most of it; net-new is windowed MLA over 33 of 46 layers with a second latent geometry (576 vs 1088 rows), the padded/heterogeneous MLA KV spec, the headwise attention gate, the MoE ViT and the `dots` audio stem. **BEYOND-PIN** (vLLM `main` only, `#51255`, still being patched) and **oracle-memory-infeasible**: ~576 GB bf16 / ~290 GB fp8 against a 119-122 GiB ceiling on every host we own, so no performance axis is claimable and no token gate can bind until Β§6.4 of the spec is answered | `MODEL-MM-dots3-note-dots3-note-for-causal-lm` |
| π§ | `MiniMaxH3DiTModel` | MiniMax-H3 (33.1B omni-modal video+audio DiT, DERIVE-AND-SHIP) | **W1/W2 landed**: packed layout (fl2va + ref2va, fp64 position grid BIT-EXACT), latent packing, euler-ancestral eta0 scheduler, and the full DiT forward all parity-gated against the UPSTREAM vLLM-Omni modules executed at reduced dimensions (**max abs diff 1.6e-7**, 10/10 cases / 2539 assertions). NOT autoregressive (no KV cache, no sampler, no logits) and **e2e HW-BLOCKED** (~354 GB checkpoint, ~133 GB/rank on 4x B300 vs 119 GiB unified); bf16 production stream + request planning + the ComfyUI-GGUF arm also landed (535 REAL tensors resolve onto our contract, geometry from shapes alone). **HW verdict CORRECTED: quantized arms FIT (~41 GB in 119 GiB)**, so e2e + speed are reachable; encoder/VAEs/audio VAE DONE (4.2e-9 vs the checkpoint's remote code); NVFP4 layout GATED as identical to ours (speed path is loader wiring); BOTH VAE DECODERS done (audio 4.2e-9, video ViT3D 8.9e-8); video tiling + 3D-CNN encoder (conditioning only) pending; encoder TEXT tower done (1.2e-7); **serving `/v1/videos` DONE and the DEVICE-RESIDENT forward (W2b, f32) LANDED + GPU-VERIFIED on Thor sm_110 at video 1.49e-7 / audio 8.94e-8**; bf16 stream + fusion folds + the FP4 path (needs sm_121a) + a real-checkpoint run pending. **2026-08-05: the AUDIO-VAE ENCODER is ported** (DAC analysis stack + `pre_block` AttnProjection + `mean_proj`, gated stage by stage vs the checkpoint's own remote code at 2.98e-8 / 1.64e-7 / 1.86e-8) with its own checkpoint loader gated on the real 1087-tensor manifest β so **ref2va AUDIO and VIDEO+AUDIO references are now WIRED** (audio rows move by 0.51 / 0.71; a different waveform still moves them by 7.1e-4). Both VAEs are now complete in both directions. **bf16 13-SHARD RELEASE INDEXES 2026-08-07 (`row/H3-BF16-SHARDED-DIT`)**: `MiniMaxH3ShardedCheckpoint` resolves the ORIGINAL 66.3 GB release through its own `model.safetensors.index.json` (a tensor named in the index but missing from its shard throws BY NAME), `EnumerateMiniMaxH3ShardedTensors` feeds the shared shapes-only geometry parser, and `LoadMiniMaxH3DitFromShards` is the host-f32 reference loader. Gated CPU-only at 72/72/54497 (post-rebase): every tensor resolves to the shard the index named AND to the bytes written there, the derived geometry equals the single-file path field for field, and a SPARSE 13-shard release with the REAL 535 tensors at REAL shapes (66.3 GB declared, 144 KB on disk) derives the SHIPPED geometry (50/5376/56/128/14336/24/32/1x2x2/5120). **STREAMS 2026-08-07 (`row/H3-BF16-SHARDED-STREAM`)**: `StreamMiniMaxH3ShardedToDeviceBf16` uploads it one tensor at a time β a BF16 tensor bound for a bf16 device slot goes straight from the mmap with ZERO host buffer, so peak host is bounded by ONE tensor (observed `host_peak=8192`, `direct=37 converted=9`); bit-exact vs the non-streamed `StageMiniMaxH3DitWeights` reference over all 46 views with identical logits, rope.inv_freq host-resident, 73/73/55203. Spec Β§8.14. **bf16 TEXT ENCODER + THE CONDITIONING NUMBER 2026-08-07 (`row/H3-ENC-BF16-COND-DIFF`)**: the 14-shard 63 GB bf16 Qwen3-VL-32B encoder streams to device too (`StreamMiniMaxH3EncoderShardsToDevice`, q/k/v and gate/up fused ON DEVICE), `--encoder-only` runs the tower alone (peak ~96 -> ~49 GiB by not loading the DiT first), and the widening is gated BIT-IDENTICAL vs an f32-staged tower so the A/B cannot be confounded. MEASURED on Thor over 233 tokens: Q4_K_M vs bf16 conditioning is cos 0.99745 mean / 0.909 min, rel RMS 6.85% excluding the attention sink, median rotation 3.5 deg β same energy as a ONE-WORD prompt edit but DIFFUSE (232/233 tokens rotate vs 172/233). Whether the RENDER changes is NOT established. 75/75/55609. Spec Β§8.15. This UNBLOCKS the quantization-quality question; no bf16-vs-quant render or speed number is claimed. Spec Β§8.13. **W-FP4a LANDED (CPU) 2026-08-06 (`row/H3-FP4-SPEED`)**: the device DiT forward now routes the NVFP4 projections through the shared Marlin W4A16 dispatcher (fp4 kept packed; no new quant code), fp4-vs-bf16 wiring gate GREEN (62/62Β·30039). **W-FP4a GB10 leg LANDED 2026-08-06 (`row/H3-FP4-GPU-E2E`, PR #64):** on sm_121a the Marlin W4A16 path RAN for all 11 projections (`dense_gemms==11` default β VT_MARLIN_DENSE is default-ON β vLLM's own DENSE Marlin GEMM, not the grouped route; `marlin_gemms==11` under VT_MARLIN_DENSE=0; `fallback_gemms==0`), fp4-vs-bf16 BYTE-EXACT (max\|diff\|=0), and the fp4 arm is a MEMORY win not a diffusion-forward speed win (per-forward bf16/fp4 3.47Γ @seq64 β 0.79β0.83Γ @seq4224β7040; ~16 vs ~66 GB device). Real-checkpoint fp4-resident t2va e2e RUNS (real 18.75 GB NVFP4 DiT + VAEs + GGUF Qwen3-VL-32B encoder β valid mp4/wav; DiT s/step 5.45/20.0/209 s @512/768/REF-209f) but frames are a non-scene patch-grid at 12/20/50 steps β OPEN render bug (device VAE/denoise). vLLM-Omni has no quantized H3 arm (BF16-only) so any comparison is HW/loader-forced-indirect β spec Β§8. **ONE-SURFACE ROW 2 LANDED 2026-08-08 (`row/H3-VIDEO-ABI`)**: the whole assembly pipeline is library-owned (`vllm::multimodal::MiniMaxH3VideoEngine`, `minimax_h3_video.cpp`) behind the ABI v12 `vllm_video_*` entry points; `/v1/videos` routes through the SAME seam; `minimax_h3_gen`+`minimax_h3_mux` are thin `vllm.h` clients, frames+WAV byte-identical to the pre-fold binary on the committed fold fixture (`test_minimax_h3_video_fold` 3-arm gate + the v12 `test_capi` section); GB10 real-video re-verify via the v12 ABI = named residual. **ROW 2 DEVICE-SEAM FOLLOW-UP (#135; replaces #134):** ABI 0/1 maps once to `vt::DeviceType`; shared code dispatches through `GetBackend(device_type)`, restoring DSR 34β32 without a baseline/allowlist change; CPU compile/fold test pending in CI due shared-disk pressure **PRUNED CHECKPOINTS LOAD AND RUN 2026-08-10 (`row/H3-PRUNED`, #241, spec Β§8.21):** the community `pruned` variants (`unsloth/MiniMax-H3-GGUF` Q2_K..Q8_0, `lilcheaty/MiniMax-H3-NVFP4` `*_pruned_nvfp4`) are not lossily pruned but ComfyUI's AdaLN timestep-CURVE refactor (`comfy/ldm/minimax/model.py:419-432,610-615`): an `adaln_t_table` [1025, 8] lerp replaces the sinusoidal+MLP time embedder, no SiLU before the AdaLN linear, and its in_features drop 2688 -> 8, collapsing `adaln_proj` from 13.04B of 33.12B to 0.04B and the DiT to 20.11B β so a pruned Q8_0 (21.4 GB) costs what our unpruned Q4_K_M (19.9 GB) costs. Gated on the REAL 532-tensor pruned GGUF manifest (532 = 535 - 4 `time_embedder.*` + 1 table, header-only), the clamped-lerp golden, and a CONSTRUCTED-curve test proving the pruned forward is numerically identical to the unpruned one; 79/79/57299. | `MODEL-DIFFUSION-minimax-h3-mini-max-h3-dit` |
| π§ | `MiniMaxMusic3ForConditionalGeneration` | MiniMax-Music3 (text-to-music: ~8.6B Qwen3 global LLM + 0.646B 8-codebook RVQ depth decoder + 2.4B fp32 flow-matching DiT + 0.054B DAC Flow-VAE) | **W0 DONE + W1 LANDED (#672, [spec](specs/minimax-music3.md)).** Diffusers oracle gateable with committed per-stage goldens (#708); modular loader in the tree, 1413/1413 assertions against the real checkpoint (#714). Geometry MEASURED from every component `config.json` plus safetensors headers by range request. First row to exercise the fallback-oracle rule (#647): absent from vLLM AND vLLM-Omni, so its primary oracle is the OPEN diffusers PR #14456 head `c6da9936` with SGLang-Omni `748a0b43` as the e2e cross-check. **W2/W3 LANDED**: the AR half computes and is gated. **W4/W5 LANDED**: the ACOUSTIC half β flow-matching DiT, `FlowMatchEulerDiscreteScheduler` with `invert_sigmas`, the CFG mix, the denoise loop's window bookkeeping and the DAC Flow-VAE vocoder over the shared `vocoder1d` primitives β gated at reduced dimensions (27 cases / 265 assertions, no checkpoint) AND at full scale against the committed capture (scheduler BIT-EXACT 22 016/22 016; waveform 88 064 samples, 0 outside a tolerance calibrated against torch reproducing its own goldens). **W6 LANDED**: registered as a `SpeechRegistry` family (`minimax-music3`, detection INSPECTS `modular_model_index.json`), `SpeechGenParams` extended ADDITIVELY with `lyrics`/`description` plus three generation controls (IndexTTS-2.5 byte-identical, 0 lines changed), the new `vllm_speech_*` C-ABI surface at v20, and `POST /v1/audio/speech` on the example server as a thin ABI client. The denoise + decode composition reproduces the capture's `waveform.npy` β 88 064 values, 0 outside tolerance, max abs-diff 4.52e-06 β and the WAV payload is BIT-EXACT against the quantization of that golden. **W7 LANDED: ONE ARM IMPLEMENTED AND VALUE-GATED, the rest refused.** The RVQ depth decoder loads from GGUF Q4_K (`audio-cpp/MiniMax-Music3-GGUF`@`c36aaeed`, `rvq_depth_decoder_q4_k.gguf`, 405 752 480 B, sha256 `4c5d41b2...c70cbdd0` β pinned because an unpinned quantized checkpoint is not reproducible): 47 tensors as 36 Q4_K + 9 BF16 + 2 F16, dequantized to bf16 through the SHARED `gguf_dequant.h` seam, lineage keyed on `audiocpp.model_spec.family` because `general.architecture` reads `audiocpp`/`mm3`/`qwen3`/`wan` for this ONE model and `wan` collides with real Wan video GGUFs. Gated 6 cases / 319 assertions against the W3 golden's 716 800 values at a bound DERIVED rather than chosen: worst per-tensor relative L2 0.0742 (bound 0.10), full-scale mean abs-diff 0.0324 / max abs-diff 0.3125 / 2.84% bit-identical. **THE GATE-DESIGN FINDING, which generalizes past this row: an upper-bound-only tolerance CANNOT distinguish a real quantized arm from a silent dequant fallback, because the fallback is CLOSER to the golden** β bf16 weights through the identical forward give mean abs-diff 0.00182, 17.8x nearer than the genuine Q4_K arm, so every plausible upper bound PASSES the failure. What catches it is a LOWER bound (5e-3, sitting between the two), gated by a positive control that actually runs the fallback and asserts the gate rejects it. Two further INDEPENDENT legs prove the quantized path was taken rather than inferring it: the RESIDENT ggml type of every tensor (loader bookkeeping β localizes a fault to a name, but a loader that lied about its tallies would pass it, which is why mutation QM2 exists) and the Q4_K LATTICE (a property of the DATA needing no loader cooperation β 0 of 524 288 32-element windows exceed 16 distinct values, against a bf16 control from the same file at 127 of 128). Second finding: the 2 F16 islands do NOT round-trip exactly (rel 3.23e-08 / 2.36e-08) because the quantizer re-encoded them BF16->F16 and F16's exponent range is NARROWER, flushing weights below ~6e-08 to zero β so the gate splits the islands, BF16 bit-exact and F16 bounded; asserting "unquantized means exact" for all 11 REDS a correct reader. 18 mutations across both layers all fire, one of them (QM4, the lineage guard) only after a COVERAGE HOLE it exposed was closed with synthetic GGUF fixtures. The 4 OTHER components' GGUF arms, the `mm3` and ComfyUI lineages, and every non-GGUF format are REFUSED BY NAME and owed. Quantized MiniMax-Music3 checkpoints DO exist β a HuggingFace survey on 2026-08-14 found 14 community repositories in 5 formats (GGUF of all five components, int8/w4a8, MLX, plus a proprietary Cortiq arm), recorded query-by-query with result counts in spec Β§9.1. `minimax_music3_quant.{h,cpp}` is a SEPARATE translation unit per porting-a-model.md that diagnoses 8 formats at the THREE places a quantized checkpoint announces itself (tree `.gguf`, manifest sidecars plus the dtype-only fp8/int8 cases, and `quantization_config`/MLX `quantization`) and refuses each BY NAME with the evidence, the missing piece, the supported arm, the phase and the issue. 29 cases / 125 assertions without a checkpoint plus 6 cases / 319 assertions against the pinned artifact, RED first at 8/8 probe checks, 18 of 18 mutations fire; every tolerance is DERIVED from a printed measurement rather than chosen, and no speed number is claimed. GGUF headers MEASURED by range request (56 MiB, no weight bytes): "the GGUF arm" is THREE MUTUALLY INCOMPATIBLE LINEAGES and `general.architecture` cannot separate them (`audiocpp`/`mm3`/`qwen3`/`wan`, and `wan` collides with real Wan video GGUFs), the ComfyUI lineage ships the DiT + condition encoder ONLY so it can never generate audio, and `comfy.gguf.orig_shape.*` is absent from all ten files. The 8.6B **W2's remainder LANDED (this PR): the 8.6B `Qwen3ForCausalLM` forward runs.** `Qwen3DenseModel::ForwardEmbeds` gives the landed dense path the `inputs_embeds` entry its multimodal siblings already had (`qwen3_vl.h:145,159`, `gemma4.h:210-218`, `muse_glimmer.h:369-380`), additively and proved BIT-IDENTICAL to the token-id `Forward` in logits AND in the paged KV it writes. Teacher-forced on the capture's own codes, 25 steps reproduce `frame_hiddens[:, :4096]` - 102 400 values, 9337 bit-identical, mean abs-diff 1.763e-02 - INSIDE a matched control (upstream's own model under `sdpa_kernel(MATH)`: 12 036 bit-identical, mean abs-diff 1.475e-02), with the per-step error FLAT rather than compounding. The oracle's OWN sampled semantic codes rank 2.48 on average under our guided logits where chance is 8191.5, and the gate carries its own NEGATIVE CONTROL: a one-step-shifted alignment reads mean abs-diff 0.803, 46x outside. **The e2e case at `POST /v1/audio/speech` is OBSERVED TO PASS (2026-08-15, #852)**: 200 `audio/wav`, 12332 bytes, 2 AR frames -> 6 latent frames -> 3072 samples/channel of 44100 Hz stereo, 6144 int16 samples all non-zero, 0 clipped, 2818 of 3072 positions differing between L and R; 21 assertions in 7:54, and 5 cases / 535 assertions for the whole file in 31:14. It had never been seen because the request body posted `audio_duration_s`, the FIELD name, where `ParseSpeechRequest` reads `audio_duration` - so the key was silently dropped and the family's 60 s default substituted, making every run a ~750x job (1500 AR frames not 2, 8 denoise windows not 1, 5167 vocoder latents not 6) that could never have passed its own payload assertion. The near-miss key is now REFUSED (#925). **The earlier diagnosis was wrong and the way it was wrong generalizes**: open LM shard fds do NOT locate the program counter, because `LoadBf16Direct` BORROWS the mapping and a borrowed `OwnedTensor` keeps it alive for the whole request, while the depth decoder's tensors are COPIED so its fd closes on return. A symbol-resolved profile puts the LM weight load at 180 s (1 thread, state `D`, ~92 MB/s off the NAS) in BOTH binaries, and the cost in `LinearNoBias` 42-57% / `Threadpool::Barrier` 25% / `vocoder1d::ConvTranspose1d` 88.5%; the suspected 200000 x 4096 `lm_head` transpose is 1.388 s. The GGUF k-quant ARM for the remaining components is still owed; spec Β§5's token-exact gate is WITHDRAWN because upstream's AR stage has no greedy path **PARITY SWEEP + MUSIC-ONLY SERVER LANDED (#672, #953)**: upstream's whole user-facing surface was enumerated field by field (SGLang-Omni `748a0b43` `models/minimax_music3/`, diffusers `c6da9936` `modular_pipelines/minimax_music3/`) and recorded with `file:line` in spec Β§10.1. **`--model` is now OPTIONAL when `--speech-model` is given**, so `vllm-server --speech-model
` serves `/v1/audio/speech` and registers NOTHING else β upstream's own shape (`sgl-omni serve --model MiniMaxAI/MiniMax-Music3`, `config.py:29-63`: three stages, no chat LLM), and the third instance of the task-conditional dispatch already in `server_main.cpp` for pooling and transcription-only checkpoints (vLLM `api_server.py:255-265`). ADDITIVE and proved: the ONLY case whose verdict changes is BOTH flags absent, which was an error and remains one with a message naming both options; the route table is gated in BOTH directions over a REAL SOCKET. New `examples/minimax_music3_gen` β the music family was the one generative family in this tree with NO example β a THIN C-ABI client (`vllm_speech_engine_load` + `vllm_synthesize`, `include/vllm.h` only). **Five keys upstream refuses BY NAME were SILENT here** and are now refused (#953): `temperature`/`top_p`/`top_k`/`repetition_penalty` (`request_builders.py:14-19,109-114`; the AR stage has ONE sampler, a fixed top-50 draw) and `max_new_tokens` (`request_builders.py:56-68`; upstream's length spelling in 25 Hz FRAMES, not seconds) β the #925 class exactly. **The e2e gate no longer reports a SKIP WEARING A PASS**: it read 5 cases / 5 passed with `assertions: 0` when the checkpoint was absent, the same shape that fooled this project on `test_qwen3_paged_engine`. Split into a CHECKPOINT-FREE half that runs unconditionally in CI (request contract, both ceilings, the speech-only route table over a real socket with a stub synthesizer) and the env-gated checkpoint half, whose HTTP case now runs over a REAL SOCKET against the music-only server shape rather than calling `handle_audio_speech`; a coverage-report case prints which arms ran every run. No-env arm 9 cases / 37 assertions where it was 5 / 0. **The WEIGHTS are documented** per `porting-a-model.md` Β§2.1: `docs/USAGE.md` carries component-by-component tables for the diffusers arm at `MiniMaxAI/MiniMax-Music3`@`fbdf52fbaaca799592917417eb05f1899f1255ec` (**28.5 GB resident, 28 517 617 303 B MEASURED**, out of a 57.4 GB repository, and why they differ), the native `.pth` arm we refuse and SGLang-Omni serves, the one implemented GGUF Q4_K artifact with its sha256, and the 14 THIRD-PARTY quantized repositories in 5 formats each marked refused. The revision is VERIFIED not copied: `condition_encoder/diffusion_pytorch_model.safetensors` on disk hashes to `83179c5eβ¦a202c2a4d`, that revision's own LFS record. OWED and named rather than discovered: the non-`wav` response formats (no encoder vendored; note upstream DOWNMIXES TO MONO for every non-wav format, `client/audio.py:328-334`), request batching and `/v1/audio/speech/batch` (SGLang runs continuous batching at 16 with TWO engine rows per request for the CFG twin, `engine_builder.py:74-77`), and the 32 kHz delivery resample. Streaming is a PERMANENT refusal, not a debt: neither upstream arm has it (`supports_streaming_vocoder=False`). One place we are AHEAD of both arms: `guidance_scale` is a real per-request control here, where diffusers freezes it at 1.7 into the guider component (`denoise.py:180`) and SGLang exposes it only as a serve-time knob. **DEVICE ARM LANDED (#672, this PR) β PARTIAL, and the split is the point.** `SpeechModelParams` grew `device` (0 = CPU, 1 = the accelerator this build resolves; the `VideoModelParams::device` polarity, NOT `vllm_model_params.device`'s 0=auto, because every Music3 gate was taken on the CPU arm and `auto` would move every zero-filled caller off it), resolved through a NEW SHARED `multimodal::SpeechEngineDeviceType` rather than a third copy of a mapping the tree already carried twice (`minimax_h3_video.cpp:255`, `ltx2_video.cpp:706`). The engine's `vt::Queue` was a COMPILE-TIME CONSTANT (`minimax_music3_speech.cpp:492`, whose own comment said "a device arm is a queue, not a fork"); it is now that queue, built once in the constructor BEFORE any weight is read (the unified-memory recipe). `Music3LmSession` allocates its 36-layer paged KV on the queue's device, because `dense_attn::KvSlice` labels the pointer with `d.q.device` and a host `std::vector` handed to a CUDA forward is a host pointer wearing a device tensor's label. C ABI **v21**: `vllm_speech_model_params.device` + `vllm_speech_engine_device`, which reports what was GRANTED not what was requested; `--speech-device` on the server, `--device` on `minimax-music3-gen`. **WHAT MOVES is the 8.6B `Qwen3ForCausalLM` half and nothing else**: it already rides the shared `Qwen3DenseModel::ForwardEmbeds` five text registrations use, so no model was forked. **WHAT DOES NOT, named rather than implied**: the 0.646B RVQ depth decoder and the 2.4B fp32 DiT are host `std::vector` scalar loops under `-ffp-contract=off` (kept reproducible against torch by W2-W5) and are OWED; the DAC Flow-VAE vocoder needs `ConvTranspose1d`, and **`vt` HAS NO SUCH OP** β `vt::Conv2d` and `vt::DepthwiseConv1d` exist but are registered for the **CPU only** and neither expresses a transposed convolution β so it is recorded as owed rather than hand-rolled outside the seam. The CPU arm is BIT-IDENTICAL: it takes the same host code with the same `std::vector` KV, and every Music3 gate is unchanged. | `MODEL-MUSIC-minimax-music3-mini-max-music3-for-conditional-generation` |
| π | `LTX2VideoTransformer3DModel` | LTX-2.5 (21.00B joint video+audio flow-matching DiT, Lightricks) | **L0 spec committed 2026-08-11 (#435, [spec](specs/ltx-2-5.md)).** Geometry MEASURED from the FP8 checkpoint's own safetensors header by HTTP range request (6124 tensors, 881,048-byte header, no payload downloaded): **21.00B** params β 48 blocks @ 386.7M = 18.560B, audio embeddings connector 2.016B, global 0.427B. The filename says `22b` and the Diffusers card says ~19B; the MEASURED count is what this row uses. Video stream 4096 (32 heads x 128), audio stream 2048 (32 heads x 64), in/out channels 128 both. Per block SIX attentions β `attn1` (video self), `attn2` (video<->text, cross 4096), `audio_attn1`, `audio_attn2` (cross 2048), and the two CROSS-MODAL `audio_to_video_attn` / `video_to_audio_attn` β which is the structural break from MiniMax-H3: H3 packs every modality into ONE sequence with per-row token tags, LTX runs TWO streams coupled by explicit cross-attention. **Per-head gated attention on every attention** (`to_gate_logits` = `Linear(query_dim, heads, bias=True)`, `attention.py:513-514`, applied AFTER the attention output at `:577`) β H3 has no analogue and getting it wrong renders plausibly-wrong rather than erroring. FFN is gelu-approximate 4096->16384->4096 with **NO bias** while `audio_ff` 2048->8192->2048 **HAS** bias, which independently confirms `ff_bias=false` / `audio_ff_bias=true` from `model_configurator.py:78-80` β checkpoint and source agreeing, not either alone. **RETRACTED 2026-08-12, was billed as a FREE WIN.** The spec claimed 2.5 sets `use_prompt_adaln_single=false` so the cross-attention K/V are timestep-free and cacheable. The shipped checkpoint DISPROVES it: it carries 12 `prompt_adaln_single`/`audio_prompt_adaln_single` tensors including a `timestep_embedder.linear_1 [4096, 256]` (256 = the sinusoidal timestep width), and `model.py:223-227` builds that module ONLY when the flag is TRUE. `transformer.py:441` was quoted as proof of no timestep term, but `:442-443` add one whenever `prompt_timestep` is not None, and the comment above them says exactly that. NO SHIPPED DEFECT: `ltx2_dit.cpp:672` refuses the cache by name when the flag is on, so the feature is correct-and-inapplicable rather than silently wrong, and stays gated bit-identical and prompt-bound for any checkpoint that does set it false. **ORACLE:** vLLM-Omni does NOT support 2.5 β `resolve_ltx_pipeline_recipe` keys on 2 / 2.3 only and RAISES otherwise (`ltx2_recipes.py:162-166`), with upstream [vllm-omni#6066](https://github.com/vllm-project/vllm-omni/issues/6066) filed 2026-08-11 β but its `DiffusersAdapterPipeline` is generic (`DiffusionPipeline.from_pretrained`, `pipeline_diffusers_adapter.py:116`), so vLLM-Omni CAN execute 2.5 via `--load-format diffusers`. Binding oracle = that adapter; immediate cross-check = Lightricks `ltx-pipelines`. **HW: FITS ONE GB10** at ~29 GB (NVFP4 DiT 18.72 + NVFP4 Gemma-4 TE 7.40 + VAEs 1.83 + upscaler 1.00) vs H3's ~41 GB. **OWED UP FRONT, not to be discovered later:** the speed axis lands `PENDING` because the adapter is a black box (`supports_step_execution=False`, `supports_request_batch=False`) and therefore NOT vLLM's production configuration, which AGENTS.md requires as the denominator; DiffVAE (`NADiffusionDecoder`, neighborhood attention) is REFUSED BY NAME until its own row rather than silently downgraded to the Conv VAE; and no render-quality claim is made from structural e2e. | `MODEL-DIFFUSION-ltx-2-5-ltx2-video-transformer-3d-model` |
diff --git a/.agents/specs/dots3-note.md b/.agents/specs/dots3-note.md
index a75bfa9f5..bbeabdb3e 100644
--- a/.agents/specs/dots3-note.md
+++ b/.agents/specs/dots3-note.md
@@ -3967,6 +3967,357 @@ widening it. Stop if the nearest mechanism cannot be pushed above the residue by
fixture design. Stop if W5c needs more than the classifier-deferral shape. Stop
and return `NEEDS_DECISION` if the seam needs a new `vt` op.
+### 4.11 W6a puts the DENSE vision tower on a SERVED request, and refuses the pyramid by name
+
+W6a is the first brick on this row whose output a client can ask for. Every
+brick before it ended at a `ctest` binary: W3 wrote host maths, W4a/W4b put the
+two attention geometries on the decode path, W5 put the MoE layers there. None
+of them could be reached from `ApiServer::handle_chat_completions`, because
+until #2398 and #2481 landed there was no engine path by which a vision tower
+could be fed from a production entry point at all. Both are on `main` now, so
+the remaining work was this model's own half: a tower, a processor, a chat
+registration and the two `ModelFactory` hooks.
+
+**The oracle, and the SHA every anchor here was read at.** vLLM is the oracle
+and no secondary oracle is admissible, because vLLM implements this tower. It is
+BEYOND our parity pin: `5559679229bc961848b121ccdeaa8fa5d79bec98` has no
+`dots3_note` directory at all. The sources were read in the local clone
+`~/_git/vllm` at **`9035151d6`**, the merge of
+[vllm#51255](https://github.com/vllm-project/vllm/pull/51255) that added them:
+
+| Upstream | Lines at `9035151d6` | What W6a ported from it |
+|---|---|---|
+| `vllm/models/dots3_note/nvidia/vision.py` | 677 | `DotsMoEVitConfig:27`, `RMSNorm:107`, `DotsSwiGLUFFN:126`, `DotsPatchEmbed:302`, `MoEVisionBlock:334`, `PatchMergerAdapter:441`, `DotsMoEVitModel:492` (`get_pos_ids_by_grid:566`, `rot_pos_emb:604`, `_build_single_temporal_cu_seqlens_from_grid:625`, `forward:634`) |
+| `vllm/models/dots3_note/nvidia/vision_attention.py` | 477 | `rotate_half:33`, `apply_rotary_pos_emb_vision:39`, `VisionRotaryEmbedding:52`, `_RMSNorm:97`, `_VisionAttentionBase:134` (`_qkv_with_rope:149`), `VisionAttentionV2:207`, `apply_vision_attention_residual:436` |
+| `vllm/models/dots3_note/common/processor.py` | 811 | `IMAGE_START/PAD/END:41-43`, `Dots3NoteImageProcessor:63` (`resized_size:97`, `preprocess:147`) |
+| `vllm/models/dots3_note/nvidia/multimodal.py` | 304 | `hf_to_vllm_mapper:54-62` (`vision_encoder.` -> `visual.`), `get_placeholder_str:65`, `_process_image_input:144` |
+| `vllm/models/dots3_note/nvidia/vision_moe.py` | 149 | NOTHING. It is the W6b/W9 arm and is refused by name. |
+
+**Every anchor above names the SHA it was read at, because upstream has already
+moved.** `vision_attention.py` is 477 lines at `9035151d6` and 494 lines at vLLM
+`main` `7a100bb61`. An anchor read in the wrong tree is a recorded failure mode
+on this project, and a `file:line` with no revision beside it is one.
+
+#### 4.11.1 The geometry, and one word in #2512 that the fixture corrects
+
+Every number below was read from the COMMITTED fixture
+(`tests/vllm/models/fixtures/dots3_note_prev/config.json` and
+`index_full.json`), not from the issue text:
+
+| `vision_config` key | Released value | Consequence |
+|---|---|---|
+| `embed_dim` | 1536 | tower width; `head_dim` = 1536/24 = 64 |
+| `num_attention_heads` | 24 | |
+| `num_hidden_layers` | 42 | 25 dense + 17 MoE |
+| `intermediate_size` | 4224 | the DENSE SwiGLU width |
+| `moe_intermediate_size` | 2112 | W6b's, unread here |
+| `patch_size` | 14 | patch row is 3*1*14*14 = 588 wide |
+| `temporal_patch_size` | 1 | `DotsPatchEmbed.forward` takes `[:, :, 0]` of a one-deep temporal axis |
+| `spatial_merge_size` | 2 | |
+| `rms_norm_eps` | 1e-05 | |
+| `use_bias` | false | `attn.qkv`, `attn.proj` and every `mlp.fc*` carry NO bias |
+| `use_qk_norm` | true | `q_norm`/`k_norm` [64], per head, BEFORE rope |
+| `is_causal` | false | the attention is bidirectional |
+| `post_norm` | true | `post_trunk_norm` exists |
+| `pre_pixel_shuffle` | true | the PREPROCESSOR emits 2x2-grouped patch rows and RoPE regroups to match |
+| `adapter_type` | `"patch_merger"` | `PatchMergerAdapter`, NOT `PixelShuffleAdapter` |
+| `adapter_in_dim` / `adapter_out_dim` | 1536 / 5120 | 4x1536 = 6144 folded to the text tower's 5120 |
+| `pyramid_num_routed` | `[-1 x 25, 4, 8, ..., 60, 64, 64]` | `is_moe` is `pyramid_num_routed[i] > 0` (vision.py:346-350), so -1 is DENSE |
+
+**One word in #2512 needs correcting, and the fixture is what corrects it.** The
+issue's scope prose says the dense arm is "`post_trunk_norm` -> pixel shuffle ->
+`adapter`". The released `vision_config` sets `adapter_type: "patch_merger"`,
+and `PatchMergerAdapter` is upstream's own name for the arm that **skips the
+pixel-shuffle permutation** and instead views every 4 consecutive 2x2-grouped
+tokens as one row (`vision.py:441-449`, its docstring). The 2x2 regrouping has
+not disappeared; `pre_pixel_shuffle: true` moved it into the PREPROCESSOR
+(`processor.py:185-197`, the nine-way reshape and the `(0,3,6,4,7,2,1,5,8)`
+transpose) and into the RoPE position builder
+(`get_pos_ids_by_grid:566-575`, `rope_merge_size = spatial_merge_size`).
+
+This is not a disagreement about geometry, and it did not need escalating.
+#2512's own tensor inventory says `adapter.{ln_q, mlp.0, mlp.2}`, which is
+`PatchMergerAdapter`'s state dict and nothing else β `PixelShuffleAdapter`
+spells its parameters `proj.0` / `proj.1` / `proj.3` (`vision.py:397-406`). The
+inventory is right and the prose word is loose. W6a implements
+`patch_merger`, and `pixel_shuffle_mlp` is REFUSED BY NAME rather than
+silently mapped onto it, because the two produce different token orders from
+the same pixels and neither shape-checks against the other.
+
+#### 4.11.2 The 235 dense tensors, counted
+
+Of the 2195 `vision_encoder.*` tensors in the released index, W6a's arm claims
+**235** and refuses **1960**:
+
+```
+dense blocks 0..24, 9 each 225 norm_1, norm_2, attn.{qkv,proj,q_norm,k_norm},
+ mlp.{fc1,fc2,fc3} (all BF16)
+patch_embed 3 proj.weight [1536,3,14,14], proj.bias [1536],
+ norm.weight [1536]
+post_trunk_norm 1
+adapter 6 ln_q.{weight,bias} [1536],
+ mlp.0.{weight,bias} [6144,6144]/[6144],
+ mlp.2.{weight,bias} [5120,6144]/[5120]
+ ----
+ 235
+MoE blocks 25..41 (W6b) 1960 17 x {norm_1, norm_2, attn x4, gate_weight,
+ router_bias} = 136, plus 608 experts x 3 = 1824
+ ----
+ 2195
+```
+
+The 608 is the sum of `pyramid_num_routed[25..41]`, and it is what makes the
+released checkpoint still refuse.
+
+#### 4.11.3 What W6a refuses, BY NAME
+
+The released `dots-studio/dots3-note-prev` has 17 MoE ViT blocks, so a load of
+it REFUSES at the vision tower and names W6b. **That is correct and it is this
+row's established pattern rather than a new exception.** W3 refused the language
+tower's MoE layers by name for four bricks before W5 lifted it; the vision
+tower is at W3's stage, not at W5's. Refusing is what stops the port from
+serving a tower whose pyramid it silently skipped, on a row that Β§6.4 records as
+having no oracle to catch it.
+
+| Refused | Named brick | Where |
+|---|---|---|
+| any block with `pyramid_num_routed[i] > 0` | **W6b** | `Dots3NoteVisionRefusal` |
+| `quantization_config.weight_block_size` on the vision tower | **W9** | `Dots3NoteVisionRefusal` |
+| `video` modality | **W7** | `EncodeMmDots3Note`, and the chat seam's `allowed_limits` |
+| `audio` modality | **W8** | same |
+| `adapter_type == "pixel_shuffle_mlp"` | W6b | `ParseDots3NoteVisionParams` |
+| `post_norm == false` | W6b | `ParseDots3NoteVisionParams` |
+| `use_bias == true` | W6b | `ParseDots3NoteVisionParams` |
+| `temporal_patch_size != 1` | W7 (video) | `ParseDots3NoteVisionParams` |
+| `adapter_out_dim != config.hidden_size` | none β unservable | `Dots3NoteVisionRefusal` |
+| `adapter_merge_size != spatial_merge_size` | none β unservable | `Dots3NoteVisionRefusal` |
+
+**The last two rows name no brick, and that is the point of them.** They are not
+capabilities owed to a later brick; they are configs no dots3-note tower can be
+served under at all. They are here because the fresh review of #2523 measured
+the refusal predicate to be a strict SUBSET of the `VT_CHECK`s
+`EncodeMmDots3NoteForCausalLM` makes on a served request. Three of those checks
+β the adapter width against the text width
+(`dots3_note_registry.cpp`), the emitted row count against the placeholder span,
+and `L % merge_unit` inside the tower β were reachable from an all-dense config
+the seam ACCEPTED. Reaching any of them throws inside the engine's busy loop,
+which sets `AsyncLLM::errored_` permanently (`async_llm.cpp:584-601`), so the
+server starts, text works, the first image request 500s, and every later
+request is dead for the life of the process. That is the exact cascade the
+factory-side refusal was introduced to remove, still reachable through a
+narrower door. **A refusal and its route predicate must be the SAME predicate**,
+which is this row's second recurrence of the finding: the W4b-3c review made it
+about sparse routing, recorded in the first `## Owed` entry.
+
+A tautology went with them. `adapter_merge_size**2 * adapter_in_dim !=
+merged_dim()` read as a cross-key check and was `x != x` β `merged_dim()` is
+that product, reordered (`dots3_note_vision.h`) β so it could never fire, and it
+was the only refusal in the table that named no brick because it stood for no
+condition. The `adapter_merge_size` row above is the real cross-key check that
+belongs in its place.
+
+A refused tower leaves the 2195 `vision_encoder.*` tensors in the accounting's
+existing `vision` bucket as a NAMED deferral, exactly as before, so every W2
+count assertion is byte-for-byte unchanged. What moved is the deferral's
+`brick` field: `W6` -> `W6b`, because W6a is landed and W6b is what is owed.
+
+#### 4.11.4 The gate is a CONSISTENCY gate, and says so
+
+Β§6.4's option B stands. The checkpoint is 298.67 GB fp8 / 576.89 GB bf16 against
+119-122 GiB hosts, so vLLM cannot be run on it here and no denominator exists.
+Correctness for the tower is therefore argued by an **independent in-test
+double-precision reference** written from `vision.py` / `vision_attention.py` at
+`9035151d6`, sharing NO helper with the implementation, with RED-first mutation
+proof.
+
+**That establishes two implementations agree. It does not establish that either
+matches vLLM.** No performance number is claimable on any axis while B holds,
+and none is claimed. The reference and the implementation differ deliberately at
+every step that has a choice: the reference is a scalar `double` loop with its
+own softmax, its own rope and its own norms; the implementation is
+`vt::MatmulBT` / `vt::RmsNorm` / `vt::RopeFromCache` / `vt::AttentionDenseFlash`
+over bf16 device buffers through the shared seams.
+
+**One formula difference is deliberate and is recorded rather than hidden.**
+Upstream's vision `RMSNorm.forward` (`vision.py:112-114`) casts the normalized
+value back to the activation dtype BEFORE multiplying by the weight; `vt::RmsNorm`
+keeps f32 through the weight multiply and rounds once on the store (its own
+header says so). Using the shared op is the seam rule. The reference does NOT
+copy the cast: at infinite precision the two are the same function, so a double
+reference is the algebra BOTH implement, and the gate's tolerance covers our
+bf16 storage and upstream's intermediate cast together. Copying the cast into
+the reference would make the reference agree with a rounding choice instead of
+with the maths. Β§4.11.6 records the measured deviation, the bound, and the
+mutation that proves the bound is not a mute switch.
+
+**The discrete-selection rule does not bind W6a and that is a fact about the
+arm, not an omission.** The dense blocks have no top-k anywhere: routing is
+W6b's. When W6b lands it owes a SET-equality assertion on the router's top-k
+plus the printed minimum decision margin, because a tolerance alone cannot see a
+bimodal selection flip.
+
+**The memory format is asserted against upstream explicitly** (porting.md), and
+this row has already been bitten on that axis: W2's F1 fixture row proves a
+re-typed `router_bias` fires. Every dense vision tensor is BF16 on disk and BF16
+in the resident tower, and the gate asserts the tower's stored dtype rather than
+only its values β a token gate cannot see a dtype that is too wide.
+
+#### 4.11.5 Reachability β the production entry point, and what it costs to fake
+
+The production entry point is `ApiServer::handle_chat_completions` on the
+server's default configuration. The smallest failing test enters THROUGH it, over
+a synthetic in-memory checkpoint at tiny geometry with a generated tokenizer
+fixture whose added tokens are `<|img|>` / `<|imgpad|>` / `<|endofimg|>`. A unit
+test that constructs the tower by hand proves the class works, never that
+anything reaches it.
+
+The load-bearing case is **two DIFFERENT images, one prompt, compared on
+LOGPROBS**. It is the only one that survives a tower replaced by a correctly
+SHAPED constant: every text-only assertion β status 200, `prompt_tokens`,
+`completion_tokens` β passes under that mutation, and the logprobs of the first
+generated token do not.
+
+#### 4.11.6 Evidence, measured 2026-09-01
+
+Host: the developer's x86-64 Linux box, CPU queue, `-DVLLM_CPP_SERVER=ON
+-DVLLM_CPP_BUILD_TESTS=ON -DVLLM_CPP_CUDA=OFF -DCMAKE_BUILD_TYPE=Release`. No
+GPU lease was taken and no number below is a performance number.
+
+| Suite | Result |
+|---|---|
+| `test_dots3_note_vision` (new) | 8 cases, **4996 assertions**, 0 failed |
+| `test_openai_api_server_dots3_mm_forward` (new) | 9 cases, **68 assertions**, 0 failed |
+| `test_dots3_note_scaffold` | 26 cases, **110835 assertions**, 0 failed |
+| `test_dots3_note_attn` | 51 cases, **6888 assertions**, 0 failed |
+| `test_openai_api_server_mm_forward` (Qwen3-VL, untouched) | 9 cases, **73 assertions**, 0 failed |
+| `test_model_registry` (repaired here) | 24 cases, **993 assertions**, 0 failed |
+| **the FULL gate** β `ninja` all 1381 targets then `ctest -j 2` | **702/702, 0 failed**, 7 skipped for absent checkpoints, `NINJA_RC=0`, `CTEST_RC=0`, 158.06 s of `ctest` (rerun 2026-09-02 for the fresh-review repair) |
+| `scripts/agent-preflight.sh` | rc 0 |
+| `check-commit-style.py` / `check-commit-trailers.py` over `$(git merge-base origin/main HEAD)..HEAD` | rc 0 / rc 0 |
+
+**The full gate found one thing reading did not.** `test_model_registry`'s
+`registry_model_property` partitions every registration into hybrid,
+multimodal-non-hybrid and text-only and asserts `supports_multimodal` per branch;
+W5 had moved `Dots3NoteForCausalLM` into the text-only branch, and W6a's flag flip
+made it red. It is repaired here, and its comment records the true -> false ->
+true round trip rather than erasing it.
+
+**The consistency measurement.** The tower against the independent
+double-precision reference: `max |diff| 0.0533141 over a scale of 6.31441 =>
+relative 8.44e-3`. The gate's bound is **0.02**, a 2.4x margin β wide enough that
+a different libm or a different GEMM reduction order does not red it, tight
+enough that M5 below (relative 5.9e-2) exceeds it by 2.95x. A bound at the round
+0.05 a first draft carried would have cleared M5 by only 1.18x, which is one
+compiler from a mute switch.
+
+**WHAT THE 0.02 BOUND CANNOT SEE.** On a row with no oracle the honest statement
+of what the gate does NOT detect is part of its evidence, not a caveat outside
+it. Both numbers below were measured by the fresh review of #2523, on this
+tree's own gate:
+
+- **A uniform scale error passes until about 1.5%.** Multiplying the tower's
+ output by 1.01 reads relative **0.0152** against the 0.02 bound, and the gate
+ stays GREEN. The detection floor for a systematic MULTIPLICATIVE error is
+ therefore ~1.5%: a missing or doubled scalar smaller than that is invisible
+ here, and no assertion in the suite bounds the output's SCALE independently of
+ its shape.
+- **A named formula choice is below the gate's resolution.** Replacing the
+ exact-erf GELU with the tanh approximation leaves the measurement
+ BYTE-IDENTICAL to the baseline β the same printed digits, max |diff|
+ **0.0533141** β because the bf16 store of `fc1` absorbs the whole difference.
+ The gate cannot tell the two formulas apart at this geometry, so "we use
+ upstream's GELU" is a claim the CODE and the upstream anchor carry, never one
+ this measurement supports.
+
+Neither weakens the two claims above: the 8.44e-3 agreement and M5's 5.9e-2 red
+both stand. What they bound is the CLASS of defect the gate detects β a change
+to the ORDER or the STRUCTURE of the arithmetic, which is what M5 is β and not a
+small uniform rescale, and not a rounding-equivalent formula swap.
+
+**Mutations.** Each was applied to the tree, REBUILT, and its test binary's
+sha256 compared against the green baseline β a mutation that never reached the
+binary reads as a passing test. Each file was then restored and `cmp` reported
+byte-for-byte identity, and the rebuilt binaries hashed back to the EXACT green
+baselines (`c6e83b90...` served, `b03f59e3...` tower).
+
+**A CHANGED SHA IS NECESSARY AND NOT SUFFICIENT, and the argument below
+originally overstated it.** The sha proves the build was not STALE, which is the
+trap it was chosen for. It does not prove the mutation reached the code under
+test: M4 changed the TOWER gate's binary sha purely by relinking a translation
+unit that gate does not exercise, while that binary's behaviour was unchanged β
+8/8, 4981 assertions, as the paragraph after the table records. The evidence
+that a mutation was DETECTED is the CASE COUNT in the Result column, and nothing
+else in this table can carry that weight.
+
+| # | Mutation | Binary sha256 (served gate) | Result |
+|---|---|---|---|
+| β | green baseline | `c6e83b90359f1402β¦` | 7/7, 55 assertions |
+| M1 | the `Dots3NoteVisionForward` call inside `encode_mm` DELETED | `936574cab156b69bβ¦` | **RED** β 3 of 7 cases, 43 assertions reached |
+| M2 | the tower REPLACED by a correctly-SHAPED constant | `5664578c254c8fa4β¦` | **RED β and only ONE case: "two DIFFERENT images give two different forwards".** 6 of 7 pass, including status 200, `prompt_tokens` and `completion_tokens`. This is the measurement behind Β§4.11.5: without the logprob case this mutation is invisible |
+| M3 | the `.mm` read in `Dots3NoteModel::ForwardDevice` DELETED (`have_mm_embeds = false`) | `7285bd3e44221bcbβ¦` | **RED** β the same single case, for the same reason: the vision rows never reach the residual stream |
+| M4 | the production `MaterializeDots3NoteVision` call site in the LOADER deleted | `80901ec80645b598β¦` | **RED** β 3 of 7 cases |
+| M5 | the per-head `q_norm`/`k_norm` moved from BEFORE the rope to AFTER it | tower gate `b39c3e36a0abbfadβ¦` | **RED** β relative 5.9e-2 against the 2.0e-2 bound, a 7x jump from the green 8.4e-3 |
+
+**THE REFUSAL REPAIR IS RED-FIRST, and its RED is the CASCADE rather than a
+missing message.** The two served cases were written and built BEFORE the
+refusal was widened, on binary `05848d1f4226e416β¦` (tower gate
+`2d2dc86de602c004β¦`). Both failed at the install assertion β `kInstalled` where
+`kRefusing` is required β so to show what that install then costs, the two
+`REQUIRE`s were downgraded to `CHECK` in a scratch build (`34ff9a39094e0e18β¦`)
+and the cases ran to the end. Verbatim, from that run:
+
+```text
+engine-fatal: EngineCore busy loop threw: vt: Dots3NoteForCausalLM encoder: the
+ vision adapter emits 24-wide rows but the text tower is 16 wide
+ (`adapter_out_dim`, vision.py:461 @ 9035151d6) at dots3_note_registry.cpp:202
+async-llm: output handler saw engine death: EngineCore encountered an issue.
+ CHECK( r.status == 400 ) is NOT correct! values: CHECK( 500 == 400 )
+ ...the TEXT request sent AFTERWARDS on the same server:
+ {"error":{"code":500,"message":"EngineCore encountered an issue. ...
+ [request submitted to a stopped AsyncLLM]"}}
+ CHECK( t.status == 200 ) is NOT correct! values: CHECK( 500 == 200 )
+```
+
+The merge-size case reaches the OTHER assert on the same path
+(`dots3_note_registry.cpp:221`, "the tower produced 16 embedding rows for a
+placeholder span of 4 tokens") and ends in the same
+`request submitted to a stopped AsyncLLM`. The tower gate's own RED was 11
+failed assertions over 4996 in 1 of 8 cases. The scratch file was restored and
+`cmp` reported byte-for-byte identity before the fix was applied.
+
+| # | State | Served-gate sha256 | Tower-gate sha256 | Result |
+|---|---|---|---|---|
+| β | new cases, refusal NOT widened | `05848d1f4226e416β¦` | `2d2dc86de602c004β¦` | **RED** β 2 of 9 cases; 11 of 4996 tower assertions |
+| β | the same, `REQUIRE` -> `CHECK` so the cases run on | `34ff9a39094e0e18β¦` | β | **RED**, and the 500 + `stopped AsyncLLM` above is why |
+| β | refusal widened (this repair) | `c8d9573ef3d605a7β¦` | `8f2b81436dcdac81β¦` | **GREEN** β 9/9, 68 assertions; 8/8, 4996 assertions |
+
+**M4 leaves the TOWER GATE GREEN, and that is the point of having two files.**
+`test_dots3_note_vision` materializes the tower itself, so deleting the
+production call site does not move it: 8/8, 4981 assertions, on a tree where
+nothing in the loader builds a vision tower at all. Only the served-request gate
+sees it. That is AGENTS.md's "a unit test that constructs the type by hand proves
+that the class works, never that anything reaches it", demonstrated rather than
+argued.
+
+**M5's first attempt did not compile** (`-Werror=unused-but-set-variable` on the
+two tensor views the move orphaned) and the stale binary printed the GREEN
+result. A build failure reading as a passing test is a recorded trap in this
+tree; the row above is the SECOND attempt, whose `RC=0` and changed sha256 are
+what make it evidence.
+
+**One behaviour changed under measurement, and it is recorded rather than
+smoothed over.** The first version refused a MoE tower only inside
+`EncodeMmDots3NoteForCausalLM`. That throw happens in the engine's busy loop: it
+stopped `AsyncLLM`, and every LATER request β TEXT ones included β came back 500.
+The served-request gate caught it. The refusal now also runs in the chat
+FACTORY, which turns it into a REFUSING seam: HTTP 400 naming the architecture
+and the block, with the text path still answering afterwards. The encoder check
+stays as defence in depth, on the same polarity Qwen3-VL's carries ("reaching
+this point is a defect"). The gate asserts BOTH halves: 400 on the image, 200 on
+a text request sent after it.
+
+---
+
## 5. Gates
**Correctness first, and the gate form is chosen by measurement, not in advance**
@@ -4447,14 +4798,38 @@ dispatchable in order, under the constraints that answer imposes.
`Dots3NoteDeviceRefusal(released_params)` EMPTY. What that does NOT mean is
recorded in Β§4.10 and in the row header: the MoE is 94.62% of a 576.89 GB
checkpoint and nothing here can hold it.
-- **W6 β vision tower.** Dense ViT half first, then the pyramid MoE and the
- FP32-scale FP8 formula. Reuses `qwen3_vl_vision` structure.
+- **W6a β the DENSE vision tower, SERVED. LANDED** (evidence Β§4.11,
+ [#2512](https://github.com/mudler/vllm.cpp/issues/2512)). `patch_embed` ->
+ blocks 0-24 (`attn.qkv` + per-head `q_norm`/`k_norm` + 2-D vision RoPE +
+ bidirectional attention, then the three-tensor SwiGLU) -> `post_trunk_norm` ->
+ the `patch_merger` adapter, reached from
+ `ApiServer::handle_chat_completions` through the model's `encode_mm` /
+ `embed_mm` hooks and its own `REGISTER_VLLM_MM_CHAT` translation unit.
+ Structurally reuses `qwen3_vl_vision`'s outline; shares no code with it,
+ because the two towers agree on almost nothing below that outline (RMSNorm vs
+ LayerNorm, no bias, qk-norm, a three-tensor SwiGLU, a patch-merger adapter, no
+ DeepStack, no position-embedding table, no M-RoPE).
+- **W6b β the pyramid MoE ViT.** Blocks 25-41: `mlp.gate_weight` +
+ `mlp.router_bias`, sigmoid scoring, `capacity_factor`-derived top-k, and the
+ `moe_intermediate_size` experts. It OWES a SET-equality assertion on the top-k
+ plus the printed minimum decision margin; a tolerance alone cannot see a
+ bimodal selection flip. The RELEASED checkpoint has 17 such blocks, so its
+ vision tower still refuses BY NAME until this lands, which is W3's polarity
+ applied to the second tower rather than a new exception.
- **W7 β audio tower.** The `dots` stem deltas over our Whisper encoder.
- **W8 β MM front end + ABI.** Processor, video sampling, placeholder expansion,
`<|audio_comp_*|>`, `include/vllm.h` surface, the example server as a thin
client.
- **W9 β quantized arms.** Blockwise FP8 and the owed GGUF k-quant arm +
- converter.
+ converter. **The vision MoE's FP32-scale FP8 formula belongs HERE, not to W6**
+ (moved 2026-09-01 with W6a, [#2512](https://github.com/mudler/vllm.cpp/issues/2512)).
+ The evidence that moved it is the row's own W2 census: the released bf16
+ `dots-studio/dots3-note-prev` carries 37944 BF16 + 62 F32 tensors and NO scale
+ tensors at all (Β§4.4), so there is no FP8 formula anywhere in the arm W6
+ loads; `MoESwiGLUFFNFP8.process_weights_after_loading` (`vision.py:226-268` @
+ `9035151d6`) CASTS bf16 experts to block-FP8 at load, which is a quantized
+ path this port does not take, and the `-fp8` sibling that ships those scales
+ is already refused BY NAME as W9. **R5 moved with it** (Β§8).
- **W10 β MTP.** `Dots3NoteMTPModel` over the existing speculator seam.
- **W11 β gates.** Whatever Β§6.4 permits: full SACRED if A, the recorded-gap
form if B.
@@ -4476,7 +4851,15 @@ dispatchable in order, under the constraints that answer imposes.
- **R5 β the vision MoE's FP32 activation scales** (Β§2.4) are the exact shape of
a too-wide/too-narrow dtype defect that a token gate cannot see. Check the
memory format against upstream explicitly, per
- [porting.md](../porting.md).
+ [porting.md](../porting.md). **FILED AGAINST W9, not W6** (moved 2026-09-01
+ with W6a, [#2512](https://github.com/mudler/vllm.cpp/issues/2512)). It was
+ filed against W6 when this section was written, and the row's own W2 census
+ (Β§4.4) contradicts that: the released bf16 checkpoint ships 37944 BF16 + 62
+ F32 tensors and no scale tensor at all, so W6's arm has no activation scale to
+ get wrong, while the `-fp8` sibling that does ship them is refused BY NAME as
+ W9. The RISK is unchanged and is not waived; only its owner moved. The
+ memory-format obligation it names still binds every brick, and W6a discharged
+ its own share of it in Β§4.11.4.
- **R6 β no llama.cpp comparison** for the GGUF arm, so the quantized floor has
no external reference. Record it as a gap rather than substituting a different
model's number.
@@ -4497,6 +4880,35 @@ change as the lifecycle move, not afterwards.
Carried openly under option B (Β§6.4), not waived:
+- **The image processor REFUSES instead of resizing, so no non-conformant image
+ is servable.** `Dots3NoteImageProcessor::ProcessImage`
+ (`src/vllm/multimodal/dots3_note_processor.cpp`) computes the resized size and
+ then throws when it differs from the input size, rather than performing the
+ `Image.Resampling.BICUBIC` resample upstream always performs
+ (`common/processor.py:174` @ `9035151d6`). `Dots3NoteResizedSize` itself is
+ ported and correct, including the `min_pixels`/`max_pixels` rebalance
+ (`processor.py:97`); it is the resample AFTER it that is missing. **This is a
+ capability gap and not only a bookkeeping one.** `factor` is
+ `patch_size * merge_size`, which on the released `dots-studio/dots3-note-prev`
+ is 28, so an image is servable only when BOTH dimensions are already multiples
+ of 28 and the pixel count already sits inside the bounds β which almost no
+ real photograph or screenshot does. W6a never reaches the throw because its
+ fixture image is conformant by construction, and once W6b lifts the MoE ViT
+ refusal this becomes what a user hits instead. Refusing remains the right
+ INTERIM behaviour: patchifying at the wrong grid changes the placeholder count
+ and serves a well-shaped wrong prompt, which Β§6.4 records as having no oracle
+ to catch it. Closing it needs the resample matched to PIL's kernel
+ (`a = -0.5`, its support radius, its per-axis two-pass order and its clamping),
+ a gate that measures the resampler against a reference on a NON-conformant
+ image rather than only checking that the placeholder count comes out right,
+ and the refusal deleted in the same change so message and behaviour cannot
+ drift. **The record it claimed did not exist.** The code comment and the
+ runtime message both said "Recorded under `## Owed` in
+ `.agents/specs/dots3-note.md`" while this section named it nowhere and no
+ issue tracked it; the fresh review of #2523 found that, and this entry and
+ the issue below are the repair. Owner: this row, W8 (the MM front end brick
+ that owns the processor, Β§7). Issue
+ [#2537](https://github.com/mudler/vllm.cpp/issues/2537).
- **PER-REQUEST sparse routing for a MIXED step, and the refusal that stands in
for it.** The W4b-3c review found the route predicate and the refusal
predicate to be different predicates with a reachable gap between them, and
@@ -5180,8 +5592,34 @@ released config becoming loadable made a claim this port cannot honour: the
2195 vision and 430 audio tensors are named W6/W7 deferrals and the multimodal
front end (W8) does not exist. W8 flips it back.
-**Next dispatchable: W6 β the vision tower**, or W9 for the quantized arms if
-the fp8 sibling is wanted before the towers. `## Owed` is unchanged except that
-`vt::QuantFp8Group`'s missing `use_ue8m0` rounding is now recorded against W9
-with the reason, because upstream's blockwise-fp8 MoE routes through DeepGEMM
-with e8m0 scales.
+**W6a β LANDED, and this row can now be asked for something over HTTP.**
+([#2512](https://github.com/mudler/vllm.cpp/issues/2512), evidence Β§4.11.) The
+DENSE half of the vision tower β `patch_embed`, blocks 0-24, `post_trunk_norm`
+and the `patch_merger` adapter β runs on a served `image_url` chat request
+through `ApiServer::handle_chat_completions` -> the architecture-dispatched chat
+seam -> `GPUModelRunner::execute_mm_encoder` -> `ModelRegistry::EmbedMm` ->
+`ModelRegistry::Forward`. `supports_multimodal` went FALSE -> TRUE, which is the
+second half of the true -> false -> true trail W5 predicted, and this time the
+flag is backed: `kDots3NoteFactory` sets `encode_mm` and `embed_mm`, and
+`Dots3NoteForCausalLM` has its own `REGISTER_VLLM_MM_CHAT` translation unit.
+
+**Say the other half in the same breath, again.** The RELEASED checkpoint STILL
+REFUSES, at its first MoE ViT block. 17 of its 42 vision blocks are MoE, so 1960
+of the 2195 `vision_encoder.*` tensors are W6b's and the tower refuses BY NAME
+before it loads one of them. That is W3's polarity applied to the second tower,
+not a new exception. What W6a changed is that a config whose vision blocks are
+all DENSE is now served end to end rather than refused, and that the seam every
+future arm plugs into exists and is gated.
+
+**The gate is a CONSISTENCY gate and nothing more** (Β§6.4 option B, Β§4.11.4):
+an independent in-test double-precision reference written from `vision.py` and
+`vision_attention.py` at `9035151d6`, sharing no helper with the implementation.
+It establishes that two implementations agree. It does not establish that either
+matches vLLM, and no performance number is claimed on any axis.
+
+**Next dispatchable: W6b β the pyramid MoE ViT**, which is what the released
+checkpoint's vision tower is waiting on, or W7 for the audio tower, or W9 for
+the quantized arms. `## Owed` is unchanged except that `vt::QuantFp8Group`'s
+missing `use_ue8m0` rounding is now recorded against W9 with the reason, because
+upstream's blockwise-fp8 MoE routes through DeepGEMM with e8m0 scales, and that
+R5 and the vision FP8 formula moved from W6 to W9 (Β§7, Β§8).
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c5b849779..49f495784 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -808,6 +808,7 @@ add_library(vllm STATIC
src/vllm/model_executor/models/dots3_note.cpp
src/vllm/model_executor/models/dots3_note_attn.cpp
src/vllm/model_executor/models/dots3_note_device.cpp
+ src/vllm/model_executor/models/dots3_note_vision.cpp
src/vllm/model_executor/models/dots3_note_registry.cpp
src/vllm/model_executor/models/qwen4_exp_ple.cpp
src/vllm/model_executor/models/qwen4_exp.cpp
@@ -1080,6 +1081,7 @@ add_library(vllm STATIC
# Per-modality input-count limits and the refusal they carry
# (ENG-MM-INPUT-PIPELINE L1, #607).
src/vllm/multimodal/processing/context.cpp
+ src/vllm/multimodal/dots3_note_processor.cpp
src/vllm/multimodal/qwen3vl_processor.cpp
src/vllm/multimodal/audio_processor.cpp
# Parakeet / FastConformer audio encoder + CTC head + its log-mel front end
@@ -1243,6 +1245,7 @@ add_library(vllm STATIC
# registry, and Qwen3-VL's registration into it. The registration TU is
# SELF-REGISTERING and is reached through vllm's INTERFACE --whole-archive.
src/vllm/entrypoints/openai/mm_chat_registry.cpp
+ src/vllm/entrypoints/openai/mm_chat_dots3note.cpp
src/vllm/entrypoints/openai/mm_chat_qwen3vl.cpp
src/vllm/entrypoints/openai/serving_utils.cpp
src/vllm/entrypoints/openai/serving_completion.cpp
diff --git a/docs/FEATURES.md b/docs/FEATURES.md
index 7ef7009e4..6db42f8c8 100644
--- a/docs/FEATURES.md
+++ b/docs/FEATURES.md
@@ -155,7 +155,7 @@ speed-pending, which [BENCHMARKS.md](BENCHMARKS.md) tracks.
| `LagunaForCausalLM` | poolside/Laguna-S-2.1-NVFP4, GGUF-Q4_K, Laguna-XS | byte-exact near-tie (distributional vs vLLM) | vLLM parity+ 1.03x, default on, via the `laguna-gen` CLI; the registered engine forward VT_CHECKs non-bf16 (`ARCH-ONE-SURFACE` fold) |
| `KimiLinearForCausalLM` | Kimi-Linear-48B-A3B (KDA + NoPE-MLA + MoE) | **Folded onto the shared paged runner (ROW 7 Β§21, #122): engine==CLI 128/128 byte-identical; vs golden 122/128 (the intrinsic near-tie profile); FA2 paged MLA default-ON; SACRED post-fold green** | Served via `vllm_engine_load` + `vllm_complete_tokens` (ABI v13); server 19.0 tok/s wall vs vLLM ~21 (~0.90Γ), speed residual open |
| `KimiK3ForConditionalGeneration` | Kimi-K3 (2.8T MoE) | scaffold: registry+config+enumeration gated, forward refuses | HW-infeasible (~1.56 TB); no run |
-| `Dots3NoteForCausalLM` | `dots-studio/dots3-note-prev` @`1e1e7b0c` (280B-A16B multimodal MoE, 576,886,825,984 bytes bf16; the `-fp8` sibling `dots-studio/dots3-note-prev-fp8` @`7c14222e` is 298,673,280,504 bytes = 298.67 GB decimal / 278.16 GiB binary). Headers only β no tensor byte downloaded | W1+W2 scaffold: registry + config gated off the REAL released `config.json`, with one assertion per Β§4 config trap (ungrouped 1/1 router, GPT-J indexer RoPE, one nextn layer, the two LoRA rescales, the sliding theta); name map accounted **38006/38006** over the WHOLE released index β at W2 that split read 35381 language / 2195 vision / 430 audio, and W5c re-bucketed it (see below) β with the two tower files carried as named W6/W7 deferrals rather than dropped; W4a+W4b-2 put BOTH attention geometries on the DECODE PATH, reached through `ModelRegistry::Forward`: the 13 full-attention layers with the two LoRA rescales, `k_rope_only_layernorm` and the headwise gate, and the 33 sliding-window layers over a PADDED 1088-wide MLA cache row that each layer narrows to its own logical width on read; `vt::MlaDecodeAttention` and `vt::MlaPrefillAttention` grew an optional window whose absent state is bit-identical to no window; W4b-3c put the DSA lightning indexer's SELECTION on the same path, so a SINGLE-SHOT prefill longer than `index_topk` is now served sparsely instead of refused β `vt::MlaDecodeAttention` grew an optional selected-slot arm whose absent state is bit-identical to no selection and whose FULL selection reproduces the dense answer byte for byte, beside a new `vt::DsaIndexerLogits` / `vt::DsaTopkSelect` pair on CPU and CUDA. A STEP in which any request has CACHED CONTEXT and any request is past `index_topk` still REFUSES BY NAME β the sparse route is a property of the step, not of one request β because the indexer's own key cache is a second attention group owned by `KV-DSV4-MULTICACHE` (#1925). W5 put the 45 MoE layers on the same path through `Dots3NoteMoeBlock` over the shared `RunMoePlaced` seam β the UNGROUPED (n_group=1 / topk_group=1) noaux_tc router at 256/8 with the F32 `e_score_correction_bias` feeding the SELECTION and the unbiased scores feeding the routing weights, plus one shared expert at `moe_intermediate_size * n_shared_experts` = 1536 and NOT `intermediate_size` = 13824 β with no `vt` op changed. W5c removed the last refusal, and that one was a DEFECT rather than a gap: the nextn branch was STRICTER THAN UPSTREAM, which drops `model.layers.46.*` and `model.mtp.*` from the main model instead of refusing (`utils.py:542` -> `deepseek_v2.py:1618-1620`; `models/dots3_note/nvidia/model.py:624`), so those 19 tensors are now a NAMED W10 deferral with their own accounting bucket ([#2176](https://github.com/mudler/vllm.cpp/issues/2176)) and the split reads 35362 language / 19 nextn / 2195 vision / 430 audio. **So `Dots3NoteDeviceRefusal` is EMPTY for the released `config.json`, and that is representable rather than runnable**: the MoE alone is 545.82 GB of a 576.89 GB checkpoint (94.62%), which no host this project reaches can hold. What still refuses BY NAME is the blockwise-FP8 sibling (W9 β `weight_block_size [128, 128]` with a `weight_scale_inv` per projection, which this port's bf16 loaders cannot read), GGUF k-quants (W9), and both towers (W6/W7). `supports_multimodal` went TRUE -> FALSE at W5 because the released config became loadable while the vision tower, the audio tower and the multimodal front end are still W6/W7/W8; W8 flips it back | **No oracle, on any host we own** (298.67 GB fp8 against a 122 GiB ceiling), so NO number is claimable on any axis and the e2e gate is an open gap by construction ([spec](../.agents/specs/dots3-note.md) Β§6.4, #699) |
+| `Dots3NoteForCausalLM` | `dots-studio/dots3-note-prev` @`1e1e7b0c` (280B-A16B multimodal MoE, 576,886,825,984 bytes bf16; the `-fp8` sibling `dots-studio/dots3-note-prev-fp8` @`7c14222e` is 298,673,280,504 bytes = 298.67 GB decimal / 278.16 GiB binary). Headers only β no tensor byte downloaded | W1+W2 scaffold: registry + config gated off the REAL released `config.json`, with one assertion per Β§4 config trap (ungrouped 1/1 router, GPT-J indexer RoPE, one nextn layer, the two LoRA rescales, the sliding theta); name map accounted **38006/38006** over the WHOLE released index β at W2 that split read 35381 language / 2195 vision / 430 audio, and W5c re-bucketed it (see below) β with the two tower files carried as named W6/W7 deferrals rather than dropped; W4a+W4b-2 put BOTH attention geometries on the DECODE PATH, reached through `ModelRegistry::Forward`: the 13 full-attention layers with the two LoRA rescales, `k_rope_only_layernorm` and the headwise gate, and the 33 sliding-window layers over a PADDED 1088-wide MLA cache row that each layer narrows to its own logical width on read; `vt::MlaDecodeAttention` and `vt::MlaPrefillAttention` grew an optional window whose absent state is bit-identical to no window; W4b-3c put the DSA lightning indexer's SELECTION on the same path, so a SINGLE-SHOT prefill longer than `index_topk` is now served sparsely instead of refused β `vt::MlaDecodeAttention` grew an optional selected-slot arm whose absent state is bit-identical to no selection and whose FULL selection reproduces the dense answer byte for byte, beside a new `vt::DsaIndexerLogits` / `vt::DsaTopkSelect` pair on CPU and CUDA. A STEP in which any request has CACHED CONTEXT and any request is past `index_topk` still REFUSES BY NAME β the sparse route is a property of the step, not of one request β because the indexer's own key cache is a second attention group owned by `KV-DSV4-MULTICACHE` (#1925). W5 put the 45 MoE layers on the same path through `Dots3NoteMoeBlock` over the shared `RunMoePlaced` seam β the UNGROUPED (n_group=1 / topk_group=1) noaux_tc router at 256/8 with the F32 `e_score_correction_bias` feeding the SELECTION and the unbiased scores feeding the routing weights, plus one shared expert at `moe_intermediate_size * n_shared_experts` = 1536 and NOT `intermediate_size` = 13824 β with no `vt` op changed. W5c removed the last refusal, and that one was a DEFECT rather than a gap: the nextn branch was STRICTER THAN UPSTREAM, which drops `model.layers.46.*` and `model.mtp.*` from the main model instead of refusing (`utils.py:542` -> `deepseek_v2.py:1618-1620`; `models/dots3_note/nvidia/model.py:624`), so those 19 tensors are now a NAMED W10 deferral with their own accounting bucket ([#2176](https://github.com/mudler/vllm.cpp/issues/2176)) and the split reads 35362 language / 19 nextn / 2195 vision / 430 audio. **So `Dots3NoteDeviceRefusal` is EMPTY for the released `config.json`, and that is representable rather than runnable**: the MoE alone is 545.82 GB of a 576.89 GB checkpoint (94.62%), which no host this project reaches can hold. What still refuses BY NAME is the blockwise-FP8 sibling (W9 β `weight_block_size [128, 128]` with a `weight_scale_inv` per projection, which this port's bf16 loaders cannot read), GGUF k-quants (W9), and both towers (W6/W7). **W6a ([#2512](https://github.com/mudler/vllm.cpp/issues/2512)) puts the DENSE half of the VISION TOWER on a SERVED request**: an `image_url` chat request travels `ApiServer::handle_chat_completions` -> the architecture-dispatched multimodal chat seam (a `REGISTER_VLLM_MM_CHAT` translation unit of its own, #2481) -> `GPUModelRunner::execute_mm_encoder` (#2398) -> `ModelRegistry::EmbedMm` -> `ModelRegistry::Forward`, and `kDots3NoteFactory` now carries `encode_mm` and `embed_mm`. The arm is `patch_embed` -> blocks 0-24 (fused `attn.qkv` with no bias, per-head `q_norm`/`k_norm` applied BEFORE a 2-D vision RoPE, bidirectional attention, and the three-tensor SwiGLU routed through `layers::MlpGateUpMethodBase`) -> `post_trunk_norm` -> the `patch_merger` adapter folding 4x1536 to 5120, plus a dots3 image processor with its own per-channel normalization, its own `resized_size` and its own marker. **The RELEASED checkpoint still refuses**: 17 of its 42 vision blocks are pyramid MoE (608 routed experts, 1960 of the 2195 `vision_encoder.*` tensors), so the tower refuses at block 25 naming W6b, the chat seam installs REFUSING, and an image request is HTTP 400 while text keeps serving. That is W3's polarity applied to the second tower, not a new exception. Ported from vLLM `nvidia/vision.py` (677 lines) / `nvidia/vision_attention.py` (477 lines) / `common/processor.py` read at `9035151d6`, which is BEYOND our pin `5559679229`; every anchor names that SHA because `vision_attention.py` is already 494 lines at vLLM `main` `7a100bb61`. The gate is a CONSISTENCY gate (spec Β§6.4 option B): an independent in-test double-precision reference sharing no helper with the implementation, plus a served-request reachability suite whose load-bearing case is two DIFFERENT images compared on logprobs. `supports_multimodal` went TRUE -> FALSE at W5 and FALSE -> TRUE at W6a, and the trail is the honest record of what this port could back at each point; W7 (audio) and W8 (the video/audio front end) are still owed | **No oracle, on any host we own** (298.67 GB fp8 against a 122 GiB ceiling), so NO number is claimable on any axis and the e2e gate is an open gap by construction ([spec](../.agents/specs/dots3-note.md) Β§6.4, #699) |
| `NemotronHForCausalLM` | Nemotron-3.5-Lightning-30B-A3B-NVFP4 (`nvidia` @`29f2d174`) | config+enumeration+KV-shape gated; hybrid forward COMPUTES; loader materializes 18487/18487 as SHIPPED; A3 e2e gate 96/96 `STRICT PASS` on GB10 at `0ea5d249f` (#1221); NO run against current `main` | **PAGED (#810 A2-P): K/V go to the runner's pages; conv+SSM rows carry at the metadata's state indices.** G-SAFE: `num_reqs <= 1`. Device `lm_head` (A2-Q2b), UNMEASURED. Owed: FP8 mamba (A2-Q1), MTP, GGUF |
| `MuseGlimmerForCausalLM` | real tensors, **bf16 depth 4/52 only**: 5 prefill argmax positions match a torch transcription of vllm#51655 and HF. GGUF full depth generates coherently (#347, #359) but is **NOT token-exact** | text forward + loader vs an fp32 reference, per-mechanism property tests, scaffold 11/11, GGUF gate 17/17. An ABSENT config key now takes the architecture's constant (#412): GGUF post-norms ran at 1e-5, not 1e-8 | no vLLM denominator (pin cannot load it); SECONDARY llama.cpp, same GGUF, GB10 CPU: prefill tie **0.997x**, decode 0.232x, RSS 1.92x (#333) |
| `MuseGlimmerForConditionalGeneration` | vision: **no reference run of any kind**; enumeration gated vs the released 30B index (1436/1436). Image/video need bf16 safetensors: `mmproj-kquant.gguf` is refused by name | perception encoder loaded and wired, so an image or video prompt runs; `perception_emb_norm` now armed by default (#405). Reachability plus placeholder scatter only, no image or video correctness | not measurable; anchored to open vllm#51655 |
diff --git a/docs/USAGE.md b/docs/USAGE.md
index 5f98194f6..5aa091e08 100644
--- a/docs/USAGE.md
+++ b/docs/USAGE.md
@@ -647,7 +647,7 @@ repository in this project's history.
| GLM-5.3 config | `config.json` | 29,464 bytes | `zai-org/GLM-5.3` @ `935644c05e76fc198714f4cca449fd8b970ff6d7` | Committed verbatim in-tree as `tests/vllm/models/glm_moe_dsa_config_glm53.inc`, so the config layer is gated against what the checkpoint says rather than against what a port's author believed it says | It is the ONLY authoritative source of the 78-entry `indexer_types` list β 21 `full`, at layers {0,1,2} and every fourth from 6 to 74 β which three independent derivations agree on bit for bit (the list itself, vLLM's rule at `deepseek_v2.py:1097-1101`, and llama.cpp's `GLM_5_2_DEFAULT_INDEXER_TYPES`) | The GGUF above does not carry this list, which is why it cannot be fed as published |
| Qwen3.5-0.8B (Tenstorrent P150 arm) | `model.safetensors-00001-of-00001.safetensors` | 1,746,942,600 bytes | `Qwen/Qwen3.5-0.8B` @ `2fc06364715b967f1860aea9cf38778875588b17`, authorized 2026-08-23 | `04b1c301231dd422b8860db31311ab2721511346a32cb1e079c4c4e5f1fe4696` (non-quantized; hashed anyway from the local bytes the gates and the eager profile consumed) | bf16 on the Tenstorrent P150: the sacred greedy pair, both ambient legs, and the #1715/#2107 profile legs all ran from this snapshot | **Arms refused by name:** GGUF k-quant arms on TT β no TT kernels exist for them, refused at load; Qwen3.8-27B on TT β no arm fits the P150 (bf16 53.8 GB), refused at load |
| dots3-note bf16 language tower | `model-000{01..131}-of-00131.safetensors` | 561,371,869,568 bytes total (522.82 GiB), of which the MoE is 545,823,175,680 | `dots-studio/dots3-note-prev` @ `1e1e7b0cd37a3a48a6c8d7fa55d5f9d14377006b` | Owed: **no tensor byte has been fetched**, so no local hash exists to state, and an unauthenticated tree hash is not a pin here | The bf16 text tower this port loads: 46 backbone layers, both MLA geometries, and since W5 the 45 MoE layers β the ungrouped noaux_tc router at 256/8 plus one shared expert at `moe_intermediate_size * n_shared_experts` = 1536. Everything except `mlp.gate.e_score_correction_bias` is BF16; that one is F32, on both sides | **Nothing has ever loaded these bytes.** The tower alone is 522.82 GiB against a 122 GiB ceiling on the largest host this project reaches (spec Β§6.2), so the arm is representable and unfeedable, and the e2e gate is an OPEN GAP by construction. GGUF k-quants are refused by name (W9). The 19-tensor nextn tail is a NAMED W10 deferral rather than a refusal since #2176 |
-| dots3-note vision tower | `model-vision.safetensors` | 13,742,557,056 bytes | `dots-studio/dots3-note-prev` @ `1e1e7b0cd37a3a48a6c8d7fa55d5f9d14377006b` | Owed, as above | none | **Refused as a NAMED W6 deferral**: 2195 `vision_encoder.*` tensors, accounted for by number and loaded by nothing. The MoE ViT and its pyramid schedule are W6 |
+| dots3-note vision tower | `model-vision.safetensors` | 13,742,557,056 bytes | `dots-studio/dots3-note-prev` @ `1e1e7b0cd37a3a48a6c8d7fa55d5f9d14377006b` | Owed, as above | none | **W6a ports the DENSE half; this checkpoint's tower still REFUSES BY NAME.** Of its 2195 `vision_encoder.*` tensors, 235 are the dense arm W6a loads β `patch_embed`, blocks 0-24 and the `patch_merger` adapter β and 1960 are the PYRAMID MoE half (17 blocks, 608 routed experts) that belongs to W6b. Because 17 of the 42 blocks are routed, a load of THIS checkpoint refuses at block 25 naming W6b, the tensors stay a named deferral, and a served image request is answered HTTP 400 at the entrypoint rather than taking the engine down. A checkpoint whose vision blocks are all dense is served end to end |
| dots3-note audio tower | `model-audio.safetensors` | 1,772,399,360 bytes | `dots-studio/dots3-note-prev` @ `1e1e7b0cd37a3a48a6c8d7fa55d5f9d14377006b` | Owed, as above | none | **Refused as a NAMED W7 deferral**: 430 `audio_encoder.*` tensors. The `dots` Whisper-variant stem is W7 |
| dots3-note blockwise-FP8 sibling | `model-000{01..131}-of-00131.safetensors` plus the two tower files | 298,673,280,504 bytes total (278.16 GiB) across 133 safetensors, read 2026-08-28 | `dots-studio/dots3-note-prev-fp8` @ `7c14222e22423d6df6848eb0d1c5c3a88a00311a` | Owed: only `config.json` and `model.safetensors.index.json` were read | none | **Refused BY NAME at the forward, naming W9.** Its `quantization_config` is `{"quant_method": "fp8", "fmt": "e4m3", "activation_scheme": "dynamic", "weight_block_size": [128, 128]}` and its index (73,029 entries) ships a `weight_scale_inv` beside every projection β at the routed experts' `[1536, 5120]` that scale is `[12, 40]`. This port's bf16 loaders read a per-tensor or per-output-ROW `_scale` and nothing else, so without the named refusal the load would fail with a bare "tensor not found". It does not fit either: 278.16 GiB against the same 122 GiB ceiling |
| Qwen3.8-Flash-Next GGUF | `Qwen3.8-Flash-Next-UD-IQ1_S-0000{1..3}-of-00003.gguf` | 72,546,461,344 bytes total (67.564 GiB) across three shards (10,946,624 + 49,990,818,368 + 22,544,696,352); 1224 tensors | `unsloth/Qwen3.8-Flash-Next-GGUF` @ `8bdc666649440e9bdc97e16f3f75782c98478ff5`, path `UD-IQ1_S` | `88a1420825a9304063e882ada29d438263617f51ac8923d438d927496693bafd` (shard 1); `3a62e35bbf9add4733bd1438ebd3a67649d5edd6cb0e72bb78e33c913992b2b6` (shard 2); `0e25ceaeb89b8a80aa973c6c0c7448943682f7408c2855b2ebd016b7643a861a` (shard 3). Shard 1's digest was recomputed TWICE for this row -- on the development box and again INSIDE the `thor` lease against the bytes the server actually opened. Shards 2 and 3 carry the digests recorded in [the ladder-arm evidence file](bench-evidence/qwen4exp-llamacpp-ladder-arm-20260829.md), which recomputed all three on the staged copy on 29 August 2026; **this wave did not re-derive those two**, because the hash was killed mid-run for reading the same CIFS share as the load being measured | **LOADS on `--device cpu`, and the server LISTENS -- it produces NO TOKEN.** Measured on `thor:gpu0` 2026-08-30 (`rc` job `0f188dd1`, [evidence](bench-evidence/qwen4exp-released-checkpoint-serve-20260830.md)): all three shards load through `LoadedEngine::FromModelDir`, the engine sizes all three published cache groups, the tokenizer and the 9993-character chat template come out of the GGUF's own metadata, and `examples/server` answers on `/health`. **Load wall time 4446 s (74.1 min); peak RSS `VmHWM` 69.206 GiB against a 67.564 GiB artifact.** Residency is keep-quant: anonymous memory moved 4 -> 11 GiB across a load whose n-gram table alone would have added 95.368 GiB there, so all nine encodings in the file (F32, Q8_0, Q4_K, Q5_K, Q6_K, IQ2_XXS, IQ1_S, IQ4_NL, BF16) keep their blocks. `POST /v1/completions` then returns **500** and zero tokens | **THE FORWARD REFUSED THIS ARTIFACT BY NAME ON THAT RUN, AND W5p REMOVED THE REFUSAL**: `vt: qwen4_exp_gated_residual: input_mix_weight_down must be float (f32/bf16 for outputs)`. The file stores all **194** hyper-connection mix weights (`blk.N.hc_{attn,ffn}_{down,up}.weight` and `output_hc_{down,up}.weight`) as **Q8_0**; our loader correctly keeps them quantized (`qwen4_exp_weights.cpp` -> `LoadMatmul`), and `vt::Qwen4ExpGatedResidual` accepted only float, while every arm of the synthetic fixture wrote those same names as ggml type 0 (F32) -- so every prior wave gated the float case only and none could see this. Since W5p the three PROJECTION operands (`mix_down`, `mix_up`, `block_inject`) accept a block-quantized `[N,K]` weight and route through `vt::MatmulBT`/`kMatmulBTQuant`, mirroring llama.cpp, which merged this architecture on 2026-08-27 (`6c84c7d5d`, first tag `b10660`) and declares all six of them `GGML_OP_MUL_MAT`; the ELEMENTWISE `hc_*_norm` gamma is still refused by name, which is llama.cpp's own split. `FixtureOpts::hc_mix_q8_0` is the fixture arm that was missing. **W5q RE-RAN THIS ARTIFACT ON 2026-08-31** ([evidence](bench-evidence/qwen4exp-released-checkpoint-serve-20260831.md)): staged to worker-local disk it loads in **61 s** rather than 4446 s, `VmHWM` 73.935 GiB, the prefill and eight decode steps complete with nothing thrown, and `POST /v1/completions` returns **200** with 8 tokens. **Every token was id 0 (`!`) and two different prompts returned a byte-identical answer.** **W5s RE-RAN IT ON 2026-08-31 ON `origin/main` `52f7ccbfc`, WHICH CARRIES W5r, AND THE TOKENS ARE REAL** ([evidence](bench-evidence/qwen4exp-released-checkpoint-tokens-20260831.md)): `"The capital of France is"` -> `" Paris. Given this fact, what is"` and `"Water boils at"` -> `" 100Β°C at sea level"`, eight distinct token ids none of them 0, loaded in 60 s from the staged copy at `VmHWM` 73.93 GiB with system `used` flat at 11 GiB. **The cause of W5q's degeneracy was the dropped repack marker W5r fixed**: on this aarch64 i8mm box `kMatmulBTQuant` had been reading `block_q8_0x4` buffers as flat `q8_0`, putting a NaN in layer 0 that collapsed to an all-zero logit row, and `argmax` over a row with no maximum returns index 0. `VT_CPU_QUANT_REPACK=0` now gives byte-identical output to the default. **WHAT RUNS IS EXACTLY THIS AND NO MORE: `--device cpu`, ONE SEQUENCE AT A TIME, the UD-IQ1_S arm.** It is **NOT a token gate** β no oracle decoded these prompts, and there is no speed number. ISSUE OWED (this account is suspended for GitHub **API** writes -- `gh issue create` returns `HTTP 403: Sorry. Your account was suspended`, while `git push` over SSH succeeds, which is how this row reached `main`); scoped under `## Owed` in [the spec](../.agents/specs/qwen4-exp-flash-next.md). **Also refused or absent:** the other six published quants (UD-IQ1_M, UD-Q2_K_XL, UD-IQ3_XXS, UD-Q3_K_XL, UD-IQ4_XS, UD-Q4_K_XL) are staged but **none has been run**; every safetensors artifact (~360 GB bf16, ~180 GB FP8, ~128 GB NVFP4) exceeds the 122.80 GiB of the largest box in this fleet; any non-CPU device refuses by name ahead of tensor I/O, because `DeviceQuantGatherSupported` is true for `kCPU` alone and the n-gram table would expand from 26.822 GiB to 95.368 GiB ([#2083](https://github.com/mudler/vllm.cpp/issues/2083)), and although W6-CUDA and W6-CUDA-B between them gave ALL SIX `qwen4_exp` ops plus `vt::RmsNormGroup` a CUDA arm, the block-decoding n-gram gather still has none (`EmbeddingKernelCuda` refuses a block-quantized table by name) and `ModelRegistry::Forward` is all-or-nothing, so no `qwen4_exp` step reaches a CUDA queue; `num_reqs > 1` is refused by name; MTP is absent (**zero** `nextn`/`mtp` tensors of 1224 against 31 in the safetensors repo, [#1993](https://github.com/mudler/vllm.cpp/issues/1993)); and the file is TEXT-ONLY (no `v.blk.*`), so the multimodal arm has no artifact |
diff --git a/include/vllm/multimodal/dots3_note_processor.h b/include/vllm/multimodal/dots3_note_processor.h
new file mode 100644
index 000000000..f6155e008
--- /dev/null
+++ b/include/vllm/multimodal/dots3_note_processor.h
@@ -0,0 +1,120 @@
+// dots3-note IMAGE processor (W6a, #2512).
+//
+// Ported from `vllm/models/dots3_note/common/processor.py` read in `~/_git/vllm`
+// at **`9035151d6`** β the merge of vllm#51255. `dots3_note` does not exist at
+// our parity pin `5559679229bc961848b121ccdeaa8fa5d79bec98`, so every anchor
+// here names that SHA; upstream has already moved under this row once.
+//
+// IMAGE_START / IMAGE_PAD / IMAGE_END :41-43
+// Dots3NoteImageProcessor.__init__ :63-79
+// .factor :83-84
+// ._round_by_factor / _ceil / _floor :86-96
+// .resized_size :97-146
+// .preprocess :147-218
+//
+// WHY THIS IS NOT `Qwen3VLImageProcessor` WITH DIFFERENT NUMBERS. Three things
+// differ and each is silent when wrong:
+//
+// 1. `resized_size` is NOT `smart_resize`. Upstream dots3 rounds each side
+// INDEPENDENTLY to a multiple of `factor` and only then applies the pixel
+// budget (`processed.py:139-146`), where `smart_resize`
+// (transformers `image_processing_qwen2_vl.py:62`) does the same rounding
+// but with different guards and a different min-pixel branch. The two
+// agree on many images and disagree on some, and a disagreement moves the
+// GRID, which moves the placeholder count, which changes the prompt.
+// 2. `image_mean` / `image_std` are PER-CHANNEL lists, not the single scalar
+// Qwen3-VL's 0.5/0.5 collapses to.
+// 3. The patch row order is selected by `pre_pixel_shuffle`. TRUE is the
+// 2x2-grouped order (which happens to be byte-identical to Qwen3-VL's
+// merge-grouped patchify); FALSE is plain row-major. The released
+// checkpoint sets TRUE, and the tower's RoPE position builder reads the
+// SAME flag β so a processor and a tower that disagree on it produce a
+// well-shaped, wrong answer.
+//
+// The placeholder EXPANSION is shared rather than re-written:
+// `multimodal::ExpandImagePlaceholders` already takes the image token id, the
+// merge size and the grids, and dots3's rule is upstream's same
+// `grid.prod(-1) // merge_size**2` (`multimodal.py:151-155` @ `9035151d6`).
+#ifndef VLLM_MULTIMODAL_DOTS3_NOTE_PROCESSOR_H_
+#define VLLM_MULTIMODAL_DOTS3_NOTE_PROCESSOR_H_
+
+#include
+#include
+#include
+#include
+
+#include "vllm/multimodal/inputs.h"
+
+namespace vllm::multimodal {
+
+// The subset of `preprocessor_config.json` + `config.json` the image path
+// needs. Defaults are upstream's own where upstream has one; the three token
+// ids have none upstream (they come from `added_tokens.json`, read at
+// `multimodal.py:82-90` @ `9035151d6`) and are therefore REQUIRED by the
+// loader below rather than defaulted to a number this port invented.
+struct Dots3NoteProcessorConfig {
+ int patch_size = 14;
+ int temporal_patch_size = 1;
+ int merge_size = 2; // == vision_config.spatial_merge_size
+ bool pre_pixel_shuffle = true;
+ // Per channel, in the checkpoint's own order (R, G, B).
+ std::array image_mean{0.5, 0.5, 0.5};
+ std::array image_std{0.5, 0.5, 0.5};
+ double rescale_factor = 1.0 / 255.0;
+ int64_t min_pixels = 3136;
+ int64_t max_pixels = 12845056;
+
+ // `<|img|>` / `<|imgpad|>` / `<|endofimg|>` in the checkpoint's tokenizer.
+ int32_t image_token_id = -1;
+ int32_t image_start_token_id = -1;
+ int32_t image_end_token_id = -1;
+
+ std::string model_id = "dots-studio/dots3-note-prev"; // for the mm-hash
+};
+
+// Load from the two HF json documents. THROWS BY NAME when the three image
+// token ids cannot be resolved: a processor that guessed them would inject a
+// marker the tokenizer maps to something else, and the request would be served
+// as text with the image dropped.
+Dots3NoteProcessorConfig LoadDots3NoteProcessorConfig(
+ const std::string& preprocessor_config_json_path,
+ const std::string& config_json_path, const std::string& model_id);
+
+// `Dots3NoteImageProcessor.resized_size` (`common/processor.py:97-146` @
+// `9035151d6`) β the height/width both divisible by `factor` whose product lies
+// in `[min_pixels, max_pixels]`. Throws upstream's two refusals: a side under
+// `factor / 4`, and an aspect ratio over 200.
+std::array Dots3NoteResizedSize(int64_t height, int64_t width,
+ int64_t factor, int64_t min_pixels,
+ int64_t max_pixels);
+
+class Dots3NoteImageProcessor {
+ public:
+ explicit Dots3NoteImageProcessor(Dots3NoteProcessorConfig cfg)
+ : cfg_(std::move(cfg)) {}
+
+ const Dots3NoteProcessorConfig& config() const { return cfg_; }
+
+ int64_t factor() const {
+ return static_cast(cfg_.patch_size) * cfg_.merge_size;
+ }
+
+ // Preprocess ONE RGB image (HWC uint8, height*width*3) into
+ // `pixel_values [num_patches, channel*temporal*patch*patch]` +
+ // `image_grid_thw`. A genuine bicubic RESIZE is a NAMED residual, exactly as
+ // it is on the Qwen3-VL processor beside this one: an image whose dimensions
+ // `Dots3NoteResizedSize` would change is REFUSED with both sizes in the
+ // message rather than silently patchified at the wrong grid.
+ ImageKwargs ProcessImage(const uint8_t* rgb, int64_t height,
+ int64_t width) const;
+
+ std::string HashImage(const uint8_t* rgb, int64_t height,
+ int64_t width) const;
+
+ private:
+ Dots3NoteProcessorConfig cfg_;
+};
+
+} // namespace vllm::multimodal
+
+#endif // VLLM_MULTIMODAL_DOTS3_NOTE_PROCESSOR_H_
diff --git a/src/vllm/entrypoints/openai/mm_chat_dots3note.cpp b/src/vllm/entrypoints/openai/mm_chat_dots3note.cpp
new file mode 100644
index 000000000..631d122c8
--- /dev/null
+++ b/src/vllm/entrypoints/openai/mm_chat_dots3note.cpp
@@ -0,0 +1,272 @@
+// dots3-note's multimodal CHAT seam, registered on its own architecture
+// (W6a, #2512).
+//
+// This is the SECOND architecture to reach the registry #2481 built, and it is
+// what that row was for: adding a multimodal model is a NEW translation unit
+// plus one `REGISTER_VLLM_MM_CHAT` line, with ZERO edits to any shared table.
+// Before #2481 the server decided whether it could serve images by asking
+// whether `/preprocessor_config.json` existed and then built
+// Qwen3-VL's processor unconditionally β so this model would have been served
+// Qwen3-VL's patch geometry, its merge size and its token ids, against its own
+// `vision_config`, and answered 200.
+//
+// Ported from vLLM read in `~/_git/vllm` at **`9035151d6`**:
+// `Dots3NoteForCausalLM.get_placeholder_str` (`nvidia/multimodal.py:65-72`)
+// image -> f"{IMAGE_START}{IMAGE_PAD}{IMAGE_END}"
+// `IMAGE_START` / `IMAGE_PAD` / `IMAGE_END` (`common/processor.py:41-43`)
+// "<|img|>" / "<|imgpad|>" / "<|endofimg|>"
+// `_process_image_input` (`nvidia/multimodal.py:144-155`)
+// the placeholder run is `grid.prod(-1) // merge_size**2`
+// `MULTIMODAL_REGISTRY.register_processor` (`nvidia/multimodal.py:44-48`)
+// the registration sits ON THE MODEL and edits no shared table β the
+// mechanism this file mirrors.
+//
+// WHY THE MARKER IS BUILT HERE AND NOT TAKEN FROM `chat_mm.h`. That header's
+// `ImagePlaceholderString()` returns Qwen3-VL's
+// "<|vision_start|><|image_pad|><|vision_end|>" (`qwen3_vl.py:1716`), and
+// `BuildMarkerInjectedContent` dispatches through it. Those are one
+// architecture's markers, which is exactly the coupling #2475 removed from the
+// install path; reaching for them here would put it back one layer down. What
+// IS shared is everything that is not per-architecture: `ValidateChatMmLimits`
+// (the per-item limit walk), `DecodeImageUrlPart` (the data-URI decode),
+// `BaseProcessingInfo` (the `--limit-mm-per-prompt` fold) and
+// `multimodal::ExpandImagePlaceholders` (the expansion rule, which is upstream's
+// same `prod(grid) // merge**2` for both models).
+#include
+#include