diff --git a/.agents/coordination.md b/.agents/coordination.md index 842151c2..1330153e 100644 --- a/.agents/coordination.md +++ b/.agents/coordination.md @@ -1327,6 +1327,7 @@ table, tests, CMake. Details in the state-log entry of the same date. | Claim | Row IDs | Agent | Worktree / remote dir | Branch | Owned scope | State | Last update | |---|---|---|---|---|---|---|---| +| `CLAIM-ENG-CHUNKED-PREFILL-SPIKE` | `ENG-CHUNKED-PREFILL` (`ANCHOR-BACKFILL` -> `SPIKE`; `ROAD-V1-A-CP` under the scheduler/performance track) | Codex (GPT-5) | isolated worktree `/home/mudler/_git/vllm.cpp-wt-eng-chunked-prefill`; CPU-only source audit + scheduler/record checks; no GPU, model, download, or runtime benchmark | branch `codex/eng-chunked-prefill-spike`, base `upstream/main` `1448e981` | Spike/backfill only. Owns NEW `.agents/specs/chunked-prefill.md`; the `ENG-CHUNKED-PREFILL` engine-matrix row and lifecycle rollups; this claim; narrow current-state updates in `.agents/roadmap_v1.md`, `docs/STATUS.md`, and `docs/BENCHMARKS.md`; one append-only `.agents/parity-ledger.md` row and `.agents/state.md` entry. No C/C++, CMake, test, fixture, model, kernel, generated artifact, README, or performance-number changes. | `SPIKE` | 2026-08-01 — selected after confirming the row and owned files are unclaimed and no open PR covers chunked prefill. The accepted deliverable is the full spike contract: pinned upstream chain, current local anchors/gaps, tests to port, CPU/GPU gates, dependencies, and row-sized follow-on work. | | `CLAIM-SERVE-CLI-CHAT-SPIKE` | `SERVE-CLI-CHAT` (`INVENTORIED` -> `SPIKE`) | Codex (GPT-5) | isolated worktree `/home/mudler/.cache/sdd/localai-org-maint-bot-vllm.cpp/codex-serve-cli-chat-spike`; CPU-only records/spec, no GPU/model/download | branch `codex/serve-cli-chat-spike`, base `upstream/main` `1448e981` | Owns only NEW `.agents/specs/cli-chat-complete.md`; the `SERVE-CLI-CHAT` engine-matrix row and rollup; matching feature-matrix, porting-inventory, roadmap, STATUS, BENCHMARKS, coordination, ledger, and append-only state entries. No source/header/CMake/test/README/model/kernel/fixture edits. | `SPIKE` | 2026-08-01 - pinned-source inventory corrected: vLLM does ship remote `chat`/`complete`; accepted dual-mode design preserves the existing local invocation. CPU record/doc checker suite is the closing gate. | | `CLAIM-LAGUNA-W1W2` | `MODEL-TEXT-laguna-laguna-for-causal-lm` (INVENTORIED→ACTIVE) | Claude Code (opus-4-8) | isolated worktree `.claude/worktrees/wf_2ae79b7a-246-1`; CPU-only `build-cpu` (`-DVLLM_CPP_CUDA=OFF` Release `-Werror`); NO GPU, NO 73 GB download — structural bring-up + oracle DECISION only | branch `spike/laguna-s21-w1w2`, base `main` `5c3da2f1` | Laguna-S-2.1 W1 oracle-decision + W2 structural bring-up. Owns ONLY: NEW `include/vllm/model_executor/models/laguna.h`, NEW `src/vllm/model_executor/models/{laguna_registry,laguna_weights,laguna}.cpp`, NEW `tests/vllm/models/test_laguna_scaffold.cpp`, NEW `.agents/specs/laguna-s21-w1w2-2026-07-30.md`, its two CMake registration lines (`CMakeLists.txt` source list + `tests/CMakeLists.txt`), the `LagunaForCausalLM` sorted-set + error-message insert in `tests/vllm/models/test_model_registry.cpp`, the `MODEL-TEXT-laguna-laguna-for-causal-lm` row (INVENTORIED→ACTIVE) + checklist rollup (ACTIVE 23→24 / INVENTORIED 285→284, engaged 42→43), and the record surfaces (this claim, roadmap breadth, docs/STATUS, docs/BENCHMARKS, parity-ledger, state). **NON-COLLISION:** additive TU + one REGISTER line ⇒ ZERO edit to any shared array; the forward is a `VT_CHECK(false)` W3 stub so no production path changes; MUST NOT touch README, Metal/SACRED/apex/darwin, or any other model/kernel source. | `DONE` | 2026-07-30 — **W1 oracle-decision + W2 structural bring-up LANDED (foreground, NOT pushed).** Registry (`laguna`/`LagunaForCausalLM`) + `ParseLagunaParams` (nested dual-rope + variable Q-head + ungrouped sigmoid-noaux MoE) + GGUF `blk.N.*` name-map + UD-Q4_K_XL quant-mix (ZERO new decode kernel) + KV-cache spec + per-layer forward-composition scaffold with reuse citations. `test_laguna_scaffold` 3/3·40 + `test_model_registry` 24/24; CPU full-library `-Werror` clean; record checkers rc=0. RESIDUALS (W3/W4): device materialization + real forward + the 3 new ops + strict dual-oracle gate on a fetched checkpoint. **SUPERSEDED by `CLAIM-LAGUNA-W3` (2026-07-31) which landed the real forward + the 3 new ops.** | | `CLAIM-LAGUNA-W3` | `MODEL-TEXT-laguna-laguna-for-causal-lm` (stays `ACTIVE`; W3 real forward + the 3 new ops landed; real-model dual-oracle gate still PENDING W4) | Claude Code (opus-4-8) | isolated worktree `.claude/worktrees/wf_43e61a78-0e2-1`; CPU-only `build-cpu` (`-DVLLM_CPP_CUDA=OFF` Release `-Werror`); NO GPU, NO 73 GB download — real forward CODE + unit gates only | branch `laguna-s21-w3`, base `main` `f2e463d5` (confirmed via `git rev-parse HEAD`) | Laguna-S-2.1 W3 — turn the W1/W2 `VT_CHECK(false)` forward stub into a REAL runnable host-reference composition + land the 3 genuinely-NEW small host ops. Owns ONLY: NEW `include/vllm/model_executor/models/laguna_ops.h` + `src/vllm/model_executor/models/laguna_ops.cpp` (softplus head-gate + ungrouped sigmoid-noaux router + dual per-layer RoPE cos/sin builders), the rewritten `src/vllm/model_executor/models/laguna.cpp` (`LagunaModel::Forward` real composition), the `LagunaParams` per-layer variable-Q-head helpers in `include/vllm/model_executor/models/laguna.h`, the new-op + forward unit cases appended to `tests/vllm/models/test_laguna_scaffold.cpp`, the `laguna_ops.cpp` line in `CMakeLists.txt`, NEW `.agents/specs/laguna-s21-w3-2026-07-31.md`, the `MODEL-TEXT-laguna-laguna-for-causal-lm` row cells + this claim, and docs/STATUS + docs/BENCHMARKS pointers. **NON-COLLISION:** file-disjoint from the concurrent MLA-fold lane (`mla_attention.cpp`/`deepseek_v2.cpp` untouched); additive `laguna_ops` TU + one CMake line; the loaders still `VT_CHECK(false)` so NO production/device path changes; MUST NOT touch README, Metal/SACRED/apex/darwin, or any other model/kernel source. | `ACTIVE` | 2026-07-31 — **W3 REAL forward + 3 new ops LANDED + UNIT-GATED (foreground, NOT pushed).** `laguna_ops.cpp`: `LagunaSoftplusHeadGate` (per-head softplus out-gate), `LagunaUngroupedRouterTopK` (sigmoid noaux_tc MINUS the group step + tie-break razor: lower index on equal choice, UNBIASED weights, renorm, routed_scaling), `BuildLaguna{FullYarn,Sliding}CosSin` (dual per-layer RoPE, reusing the pinned `compute_yarn_inv_freq` over the partial-64 dims). `LagunaModel::Forward` is now a REAL runnable f32 host-reference composition (variable-Q-head GQA + dual RoPE + sliding-window mask + softplus gate + dense L0 / ungrouped-MoE L1..47 + untied lm_head). `test_laguna_scaffold` **8/8·166** (softplus math; router selection + tie-break RED-first; dual-RoPE cos/sin bit-match vs hand ref; variable-Q-head shapes; forward composition on synthetic weights — RUNS, deterministic, gather==full-row, softplus gate wired) + `test_model_registry` 24/24; CPU full-library `-DVLLM_CPP_CUDA=OFF` `-Werror` clean; all record checkers rc=0. **HONEST residual (DEFERRED W4, needs the 73 GB checkpoint):** GGUF keep-quant tower materialization (loaders still LOUDLY throw) + device/paged production forward (runner variable-Q-head device wiring) + the strict dual-oracle greedy gate (llama.cpp-Q4_K token-exact + vLLM-NVFP4 near-tie). Risks: dual-RoPE numerics vs the fork on the real config; the reference forward is f32 whole-sequence (bf16 paged token-exactness is a W4 boundary); router tie-break vs the oracle's actual greedy selection. Row stays `ACTIVE`. | diff --git a/.agents/engine-matrix.md b/.agents/engine-matrix.md index 08ff9768..5deafe18 100644 --- a/.agents/engine-matrix.md +++ b/.agents/engine-matrix.md @@ -46,14 +46,14 @@ forensics: roadmap_v1.md and the parity ledger. | LoRA and adapters | 2 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | | Long context and attention | 10 | 0 | 0 | 0 | 1 | 5 | 1 | 0 | 3 | | Loading, tokenizer, config | 9 | 1 | 3 | 0 | 0 | 2 | 1 | 1 | 1 | -| **Total** | **131** | **8** | **16** | **5** | **4** | **48** | **8** | **9** | **32** | +| **Total** | **131** | **7** | **16** | **6** | **4** | **48** | **8** | **9** | **32** | ## Engine core and scheduling | ID | Item | Tier | Upstream code/tests | Our code | Our tests/evidence | Spike/spec | State | Owner | |---|---|---|---|---|---|---|---|---| | `ENG-SCHED-CORE` | Text-generation running-first unified scheduler, FCFS, token budget, output update; two budget-fitting prefills co-schedule into one step (c2 parity — mirrors upstream, no divergence) | T0 | `vllm/v1/core/sched/scheduler.py:396,640,1501` @ `e24d1b24`/`702f481`; `tests/v1/core/test_scheduler.py:86,847` | `src/vllm/v1/core/sched/scheduler.cpp:114,234,365` | `tests/vllm/v1/test_scheduler.cpp:143,205,241,416`; `tests/vllm/v1/test_engine_core.cpp:271` | `planned: specs/unified-scheduler.md`; verdict [scheduler-prefill-coschedule.md](specs/scheduler-prefill-coschedule.md) | `ANCHOR-BACKFILL` | - | -| `ENG-CHUNKED-PREFILL` | Basic token-budget chunked prefill | T0 | `vllm/config/scheduler.py:84`; `vllm/v1/core/sched/scheduler.py:835`; `tests/v1/core/test_scheduler.py:185,503,903` | `src/vllm/v1/core/sched/scheduler.cpp:225,548` | `tests/vllm/v1/test_scheduler.cpp:192`; `tests/vllm/models/test_qwen27_paged_forward.cpp:492` | `planned: specs/chunked-prefill.md` | `ANCHOR-BACKFILL` | - | +| `ENG-CHUNKED-PREFILL` | Basic token-budget chunked prefill. Existing code covers budget/threshold clipping, multi-step prompts, partial-prefill state, and the disabled-chunking gate; pin-era test backfill and the GPU performance gate remain open. Adjacent multimodal, Mamba-aligned, DP-throttled, pooling, and configurable multi-partial modes are explicitly split from this row by the accepted spike. | T0 | `vllm/config/scheduler.py:58-91,126-136,261-310`; `vllm/v1/core/sched/scheduler.py:427-561,640-930,1845-1900`; `tests/v1/core/test_scheduler.py:271-333,589-661,988-1020,1433-1517` @ `555967922` | `include/vllm/config/scheduler.h:91-158`; `src/vllm/config/scheduler.cpp:49-92`; `src/vllm/v1/core/sched/scheduler.cpp:280-404,431-550,945-982` | Existing `tests/vllm/v1/test_scheduler.cpp:205-227,315-336,713-735,1329-1369`; missing pin-era groups and exact commands inventoried in [chunked-prefill.md](specs/chunked-prefill.md) | [chunked-prefill.md](specs/chunked-prefill.md) | `SPIKE` | `CLAIM-ENG-CHUNKED-PREFILL-SPIKE` | | `KV-PREFIX-CACHE` | APC hashes, lookup, allocation, partial blocks, eviction, plus explicit/model-default cache policy. W0 ports arbitrary-group no-prefix coordination and makes hybrid/attention-free defaults cache-off. **Full-surface re-audit 2026-07-22 ([spike](specs/prefix-prompt-caching-parity.md)) — the ported core is DEEPER than this row read (chain hashing, pool, all three coordinators, the complete hybrid intersection and four single-type managers), and the residual gaps are narrower and DIFFERENT:** **`generate_block_hash_extra_keys`: W2 DONE 2026-07-27 (`CLAIM-ROADMAP-D4APC`)** — the hardcoded no-op is replaced by a 1:1 port of `kv_cache_utils.py:451-591` (`_gen_mm_extra_hash_keys` + LoRA name + `cache_salt`, fixed order lora->mm->salt; prompt_embeds deferred, no prompt-embeds path). `Request`/`EngineCoreRequest` carry `cache_salt` + `lora_name`; `FromEngineCoreRequest` sets them BEFORE the first hash (fixed a latent ordering bug: mm_features were assigned after the ctor already hashed). The latent correctness trap is CLOSED and RED-first proven: with the stub, a tenant-B request false-hits tenant-A's 48 cached tokens (`n1==48`); with extra keys `n1==0` (no false-share). This unblocks the MM + LoRA cache consumers. **prefix-cache statistics: CLOSED 2026-07-22** (W1) — `PrefixCacheStats`/`CachingMetrics` ported 1:1 with `log_stats` DEFAULTED ON, which unblocks the `BACKEND-GATE-CUDA-SGLANG-PREFIX` hit-proof requirement; first measured hit rate 0.75 on a repeated-prefix corpus; no `cache_salt`; 1 of upstream's 4 hash algos; `skip_reading_prefix_cache` absent; partial-block primitives throw (upstream's own are DEAD CODE — no caller in `vllm/` — so they are NOT owed as live behaviour). **Also cleared: the "blocked on a supported non-hybrid family" blocker is STALE** — dense models default APC ON and five have landed, yet NO gate has ever run cache-ON **MLA prefix-cache-hit assert fixed 2026-07-23** (`CLAIM-MLA-PREFIX-CACHE-ASSERT`): `FullAttentionManager::find_longest_cache_hit` asserted `kind()==kFullAttention`, aborting DeepSeek-V2 (MLA group, kind `kMlaAttention`, APC default-ON) under asserts-enabled builds — latent since `ec6f4be`, inert under Release/NDEBUG. Relaxed to upstream's precondition `isinstance(spec, FullAttentionSpec or ChunkedLocalAttentionSpec)` (single_type_kv_cache_manager.py:578-582; MLAAttentionSpec IS-A FullAttentionSpec) ⇒ accept `kFullAttention` / `kMlaAttention` / `kChunkedLocalAttention`; restores DeepSeek-V2 SACRED gate 8/8 asserts-on, full-attention byte-identical, new MLA prefix-cache-hit unit cases. | T0 | `vllm/config/model.py:1805-1860`; `vllm/engine/arg_utils.py:510,1160-1166,2473-2508`; `vllm/config/cache.py:39,93,95`; extra keys `vllm/v1/core/kv_cache_utils.py:539-574`; hasher factory `:673-730`; `vllm/v1/core/kv_cache_coordinator.py:377-425,782-834`; `tests/v1/core/test_prefix_caching.py:225,1475,2781` | hashes/managers `src/vllm/v1/core/kv_cache_utils.cpp:259,291`; **extra_keys** `generate_block_hash_extra_keys` + `_gen_mm_extra_hash_keys` `src/vllm/v1/core/kv_cache_utils.cpp`; `cache_salt`/`lora_name` on `include/vllm/v1/request.h` + `include/vllm/v1/engine/types.h`, copied in `src/vllm/v1/request.cpp` `FromEngineCoreRequest` (fields set before the first hash); `src/vllm/v1/core/kv_cache_manager.cpp:124`; no-prefix coordinator/factory `src/vllm/v1/core/kv_cache_coordinator.cpp:260,273,279,545`; model-default/hasher selection `src/vllm/entrypoints/model_loader.cpp:109,167,180,191`; CLI `examples/server/main.cpp:126`; **statistics** `include/vllm/v1/metrics/stats.h`, recorded `src/vllm/v1/core/kv_cache_manager.cpp:139-147`, reset flag `:270-276`, take-and-swap `make_prefix_cache_stats()`, per-step window fold at the end of `Scheduler::schedule()`, accessors `Scheduler`/`EngineCore`/`LLMEngine::prefix_cache_metrics()`; `Request::num_preemptions` un-deferred (`include/vllm/v1/request.h`, incremented in `Scheduler::preempt_request`) | existing APC primitives `tests/vllm/v1/test_kv_cache_utils.cpp:411,516,536`; no-prefix hybrid allocation/no-hit `tests/vllm/v1/test_kv_cache_coordinator.cpp:213`; default/override resolution `tests/vllm/entrypoints/test_loaded_engine_dense.cpp:343`; server help and online cache-off contracts `examples/CMakeLists.txt:34`; `tests/tools/test_online_gate_client.py:582,633`; statistics plus the first MEASURED hit rate `tests/vllm/v1/test_prefix_cache_stats.cpp` 12/12; **W2 extra_keys** — ported mm/lora/salt cases + ordering + hash-level no-false-share `tests/vllm/v1/test_kv_cache_utils.cpp` (29/29), manager-level salt-partition no-false-share (RED-proven `n1 48->0`) `tests/vllm/v1/test_kv_cache_manager.cpp` (10/10), CPU gate on dgx GB10. **W3 DONE 2026-07-27 (`CLAIM-ROADMAP-D4APC-W3`, dgx GB10, NOT pushed) — the FIRST-EVER cache-ON model gate:** `tests/parity/test_qwen3_apc_e2e.cpp` on `Qwen/Qwen3-4B` (dense, full-attention, APC-default-ON) 2/2 cases, 84/84 asserts — APC-ON hits 2240/2777 (rate 0.807) / APC-OFF 0; APC-ON == APC-OFF token-exact 5/6 (1 diff a vLLM-confirmed 0.125-nat near-tie); == vLLM-APC-ON teacher-forced (OFF 6/6 gap 0.0, ON 6/6 gap ≤0.125 nats, 0 outside top-20); TTFT 70.1→39.9 ms = 1.76×. NO engine code changed (gate-only over the already-shipped default-ON path); 4B SACRED 16/16 no-regression. Oracle vLLM 0.25.0. Ledger: [parity-ledger.md#L746](parity-ledger.md#L746) | [prefix-prompt-caching-parity.md](specs/prefix-prompt-caching-parity.md) (umbrella); [prefix-caching.md](specs/prefix-caching.md) (cache-policy leaf) | `DONE` (dense APC path; W4 events/W5 partial/W6 mamba-align/W7 reset endpoint tracked in `KV-EVENTS`/`KV-MAMBA-ALIGN`/own future rows) | `a41af480` | | `KV-PREFIX-MATCH-UNIT` | `--prefix-match-unit` (config `prefix_match_unit`): the finest token boundary a prefix-cache hit can land on == the `hash_block_size`/"prefix match unit" the block hasher uses. NEW in 0.26 (absent at the prior `e24d1b24`/0.25.0 pin). For a HYBRID/multi-group model the resolver `resolve_kv_cache_block_sizes` computes `hash_block_size = prefix_match_unit if set else gcd(group_block_sizes)` (scheduler block size = `lcm`), letting matching land FINER than a physical block (e.g. 16/32 tokens inside a 1024-token block) provided every group block size is divisible by it; single-group (dense) models ignore the knob. Backs off to the scheduler block size when no prefix-cache/connector consumer is active or a mamba group diverges from `cache_block_size` (mamba_cache_mode != "align"); throws on a non-divisible unit. **W0 spike + W1 resolver LANDED 2026-07-28 (`CLAIM-PREFIX-MATCH-UNIT`, NOT pushed):** `resolve_kv_cache_block_sizes` ported 1:1 (explicit-parameter signature vs upstream's `VllmConfig`, our config surface is threaded), RED-first unit-gated (default gcd `!=` `=16` override). `PARTIAL`: the config/CLI/ABI field (W2), the scheduler threading of a resolved `hash_block_size != block_size` + mamba partial-tail stop (W3, needs the `KV-BLOCK-POOL` align path that still throws), and the benchmark (W4) are deferred. Default path byte-identical (single-group inert; scheduler still passes `block_size`). | T1 | `vllm/engine/arg_utils.py:696,1222,1940`; `vllm/config/cache.py:56-67`; resolver `vllm/v1/core/kv_cache_utils.py:626-688`; hasher `:691-748`; call site `vllm/v1/engine/core.py:154`; scheduler `vllm/v1/core/sched/scheduler.py:76,268-270,282,312-318`; fine-grained view `vllm/v1/core/single_type_kv_cache_manager.py:683,697` | resolver `src/vllm/v1/core/kv_cache_utils.cpp:638` (`resolve_kv_cache_block_sizes`), decl `include/vllm/v1/core/kv_cache_utils.h`; hash_block_size already plumbed `get_request_block_hasher` `src/vllm/v1/core/kv_cache_utils.cpp:577`; DEFERRED align path throws `src/vllm/v1/core/block_pool.cpp:93,220` (shared with `KV-BLOCK-POOL`) | `tests/vllm/v1/test_prefix_match_unit.cpp:64,88,99,119,129,145,164,186` 8/8 (29 assertions): single-group inert + DCP scale, multi-group default=gcd, `=16` override finer-than-default (RED), finer-than-1024-block, non-divisible throws, no-consumer back-off + connector-alone re-enable, mamba non-align back-off vs align gcd, hasher-granularity RED (coarse 2 vs fine 4 hashes); [parity-ledger.md](parity-ledger.md) | [prefix-match-unit.md](specs/prefix-match-unit.md) | `PARTIAL` | `CLAIM-PREFIX-MATCH-UNIT` | | `ENG-PREEMPT-RECOMPUTE` | FCFS tail preemption with recompute | T0 | `vllm/v1/core/sched/scheduler.py:1142`; `tests/v1/core/test_scheduler.py:930` | `src/vllm/v1/core/sched/scheduler.cpp:102,157`; `src/vllm/v1/core/sched/request_queue.cpp:36` | `tests/vllm/v1/test_scheduler.cpp:247,295`; `tests/vllm/v1/test_request_queue.cpp:91` | `planned: specs/preemption.md` | `ANCHOR-BACKFILL` | - | diff --git a/.agents/parity-ledger.md b/.agents/parity-ledger.md index 1156d192..26f92859 100644 --- a/.agents/parity-ledger.md +++ b/.agents/parity-ledger.md @@ -886,3 +886,4 @@ Columns: | 2026-07-31 (`SERVE-C-ABI` W0 contract spike; `CLAIM-SERVE-C-ABI-SPIKE`; CPU-only records/docs) | Accepted `.agents/specs/c-api-library.md` for the already-shipped original C packaging layer: complete scope, vLLM semantic chain/deviation, ABI v10/19-symbol baseline, ownership/error/version/dispatch rules, exact code/test anchors, gates, dependencies, risks, and W1-W5 follow-ons. Also fixes the verified stale public `VLLM_ABI_VERSION 9` labels in README/USAGE to the source-of-truth v10 and adds the missing v10 usage-table entry. No production/test/CMake source changed. | Pinned vLLM `555967922` has no C ABI; behavior beneath the adapter remains owned by its vLLM-derived engine rows. The flat ABI is the recorded llama.cpp-style packaging deviation and may translate, never reimplement, policy. | **CPU/records gate only; benchmark NOT APPLICABLE.** Focused C11/C++/dlopen/export gate passed 3/3 after explicitly building `vllm_shared`; five record checkers pass. `check-agent-record` reports the base tree's same six missing closing-commit objects (`444ea9d7`, `7a3f04b2`, `164453a2`), none in this row/diff. Row stays `ANCHOR-BACKFILL` because all-symbol dlsym coverage (chat symbols currently omitted), historical-layout compatibility, allocation-failure no-throw proof, lifetime sanitizer stress, and a standalone real-model C consumer remain W1-W5. | | 2026-07-31 (`CLAIM-CPU-GCC12-WERROR-PORTABILITY`; maintenance, rows `QUANT-GGUF-KEEPQ-LOADER` + `KV-OFFLOAD`; lifecycle unchanged) | Removes two GCC 12 production-library `-Werror` blockers without suppressions: the GGUF prefault keeps the same one-byte-per-page volatile XOR but uses simple assignment, and the KV filesystem tier builds the identical `...tmp` suffix with append operations inside its thread-local initializer. No API, algorithm, default, CUDA, fixture, or golden change. | Behavior remains grounded in the accepted loader and KV-persistence leaf specs: llama.cpp mmap prefault intent and vLLM `tiering/fs/io.py` unique temporary-file publication. This is compiler portability, not a parity-surface change. | RED: GCC 12 failed first at `qwen3_5_gguf_weights.cpp:49` (`-Wvolatile`), then at `fs_io.cpp:66` (`-Wrestrict`). GREEN: production `vllm` and focused test targets build clean; focused CTest 2/2 (`test_gguf_keep_quant`, `test_kv_offload_fs`). Full all-target build is PARTIAL at 42% on unrelated test-only GCC 12 `-Wrestrict` diagnostics in `test_deepseek_v2_paged_engine.cpp` and `test_glm4_moe_lite_paged_engine.cpp`; no full-CTest claim. Benchmark NOT APPLICABLE. | | 2026-08-01 (`SERVE-CLI-CHAT` W0 contract spike; `CLAIM-SERVE-CLI-CHAT-SPIKE`; CPU-only records/spec) | Accepts `.agents/specs/cli-chat-complete.md`, corrects the inventory from “no direct commands” to the actual pinned `chat`/`complete` surface, and decomposes a dual-mode port: exact remote OpenAI HTTP/SSE commands plus preservation of the existing in-process invocation as a compatibility alias. No production, test, CMake, model, kernel, fixture, or generated file changes. | Pinned vLLM `5559679229`: command registration `vllm/entrypoints/cli/main.py:17-37,73-98`; model/auth resolution and stream shaping `vllm/entrypoints/cli/openai.py:30-100`; chat `:155-234`; complete `:237-312`. The local compatibility baseline is `examples/cli/main.cpp:1-207`. | CPU record/doc gates only; benchmark `NOT APPLICABLE`, `benchmark_binding=false`. Implementation remains absent and the row moves `INVENTORIED` -> `SPIKE`. W1-W5 name parse, transport, complete, chat, and packaging gates, including fake-server request/SSE transcript parity, Release `-Werror`, ASan+UBSan, and TSan. | +| 2026-08-01 (`ENG-CHUNKED-PREFILL` contract spike; `CLAIM-ENG-CHUNKED-PREFILL-SPIKE`; CPU-only records) | Accepts `.agents/specs/chunked-prefill.md` for the existing basic token-budget chunked-prefill slice. It inventories the pin-era scheduler/config chain, exact local code/tests, missing upstream cases, dependencies, gates, risks, and non-overlapping CP0-CP3 leaves. No runtime, test, build, model, kernel, fixture, or benchmark change. | Pinned vLLM `555967922`: `config/scheduler.py:58-91,126-136,261-310`; `v1/core/sched/scheduler.py:427-561,640-930,1845-1900`; `tests/v1/core/test_scheduler.py:271-333,589-661,988-1020,1433-1517`. Existing local anchors are reconciled in the engine row; adjacent MM/Mamba/DP/pooling/configurable-partial modes remain explicitly separate. | Records/CPU inspection only; benchmark NOT APPLICABLE (`benchmark_binding=false`). Row moves `ANCHOR-BACKFILL` -> `SPIKE`, not to supported/DONE. Next gate ports disabled-ordering and concurrent 400/400/224 CPU cases; GPU every-axis performance remains PENDING. | diff --git a/.agents/roadmap_v1.md b/.agents/roadmap_v1.md index ee8d437e..b313e3e9 100644 --- a/.agents/roadmap_v1.md +++ b/.agents/roadmap_v1.md @@ -491,6 +491,7 @@ models we already ship + benchmark. Full seam map + M0–M5 W-plan: | Order | Block | Big area / outcome | Canonical detailed table | Spike coverage | State | Next gate | |---:|---|---|---|---|---|---| +| 0a | `ROAD-V1-A-CP` | Backfill and gate basic token-budget chunked-prefill parity without folding in independently owned MM, Mamba, DP-throttling, pooling, or configurable-partial modes | [`ENG-CHUNKED-PREFILL`](engine-matrix.md) | [chunked-prefill.md](specs/chunked-prefill.md) accepted at pin `555967922`; existing code/test anchors reconciled, no runtime support claim advanced | `SPIKE` | CPU: port the three missing pinned behavioral groups (shared-budget partial requests, chunking-disabled ordering, concurrent 400/400/224 with prefix caching on/off). GPU every-axis recipe and closure are defined only after that semantic leaf passes. | | 0 | `ROAD-V1-A` | Restore exact performance closure against the faster applicable vLLM v0.25.0/SGLang floor before broader roadmap implementation | [`BACKEND-GATE-CUDA-VLLM`](backend-matrix.md), [`BACKEND-GATE-CUDA-SGLANG`](backend-matrix.md), [`BACKEND-GATE-CUDA-SGLANG-PREFIX`](backend-matrix.md), [`SERVE-GATE-ONLINE`](engine-matrix.md), [`KV-PREFIX-CACHE`](engine-matrix.md), [`KV-MAMBA-ALIGN`](engine-matrix.md), [`KV-DEVICE-RESIDENCY`](engine-matrix.md), [`SERVE-ASYNC-LLM`](engine-matrix.md), [`KERNEL-GEMM-BF16`](kernel-matrix.md), [`KERNEL-GEMM-NVFP4-W4A4`](kernel-matrix.md), [`KERNEL-ATTN-FA2`](kernel-matrix.md), [`KERNEL-GDN-PACKED-DECODE`](kernel-matrix.md), [`KERNEL-GDN-AOT-BF16`](kernel-matrix.md), [`SERVE-STREAM-USAGE`](engine-matrix.md), [`SERVE-E2E-NIGHTLY`](engine-matrix.md), [benchmark protocol](benchmark-protocol.md) | v0.25.0 target `702f481` is audited. **NEW BINDING `9ecd9d0`: 114/124** (gate NO — 10 remain; full production default set = async + Triton GDN cubin + bit-identical fast RMSNorm + bit-identical fast gated-RMSNorm; supersedes `a875397`'s 52/124, `246a23c`'s 49/124, `3f256ab`'s 55/124). Mem 4/4, c1 20/20, c2 20/20, c16 19/20, c4 & c32 18/20, c8 15/20. The bit-identical (0-ulp) fast decode-kernel stack (`348d12d`+`9ecd9d0`) closed +62 axes — confirming the decode deficit was norm/quant/act kernel glue. Landed: async (`a0013a2`, `ENG-ASYNC-SCHED` DONE), vendored Triton GDN cubin (`a321d7c`), packed-decode equivalence (`e47b4d6`), qkvz (`45f9e6d`), windowed-load memory PASS. SGLang remains open; the SGLang behavior-parity lane (`ENG-SGLANG-BEHAVIOR-FLAG` cache-aware LPM admission + `KV-SGLANG-RADIX-CACHE` radix alias) is IMPLEMENTED CPU-side 2026-07-27 (`CLAIM-SGLANG-IMPL`, rows `ACTIVE`) — the `--schedule-policy=lpm` admission the `BACKEND-GATE-CUDA-SGLANG-PREFIX` gate exercises now exists, output-neutral | `PARTIAL` | **EFFECTIVE PARITY-OR-BETTER reached (27B vs vLLM)** (two-grid totality 115/124: 110 pass-in-both + 5 coin-flip; the 9 residuals are the low-conc-median edge of a net-positive determinism tradeoff — we win the tails + high-conc + throughput). No closeable real deficit. NEXT: accept the 27B verdict → 35B performance closure → SGLang floor → open the T1/T2 portfolio (orders 1–14). **35B ENGINE LEVER LANDED 2026-07-19 (`ENG-MOE-SHARED-AUX`, `CLAIM-MOE-SHARED-AUX-1`):** the first slice of the multi-stream intra-step OVERLAP (the largest c1/c2 lever) — MoE shared-expert MLP on an aux CUDA stream concurrent with the routed experts, byte-identical, default-ON; in-situ 35B TPOT A/B WINS every concurrency (c1 −5.6% … c32 −1.5%, zero regression). Orchestrator re-grids the binding c1/c2/c4; remaining overlap slices + portable glue-fusion continue the 35B closure | | MM | `ROAD-V1-MM` | **TOP feature priority (user-directed 2026-07-25):** Multimodal (Audio/Video/Image) — COMPLETE Qwen3.6-27B/35B (already-shipped text-only mm architectures) image+video, first stood up on Qwen3-VL-4B; then Gemma-4 (staged); audio last | [`MODEL-MM-qwen3-5-qwen3-5-for-conditional-generation`](model-matrix.md), [`MODEL-MM-qwen3-5-qwen3-5-moe-for-conditional-generation`](model-matrix.md), [`MODEL-MM-gemma4-mm-gemma4-for-conditional-generation`](model-matrix.md), [`MODEL-MM-gemma4-unified-gemma4-unified-for-conditional-generation`](model-matrix.md) | [multimodal-track.md](specs/multimodal-track.md) — seam map (vLLM `file:line`) + per-target gateability + M0–M5 W-plan | `ACTIVE` | **M0+M1 LANDED 2026-07-25 (`CLAIM-MULTIMODAL-M1`).** M0 oracle reference captured (fixed image+prompt on Qwen3-VL-4B; `scripts/mm/m0_oracle_capture.py` + committed fixtures). M1 mm INPUT pipeline (image processor + placeholder expansion + `MultiModalHasher`) + encoder-cache engine seam + inert `mm_features` + `extra_keys` LMCache seam: **processor-parity gate PASS 23/23 BIT-identical** vs the oracle (RED-first proven), encoder-cache 32/32, text-inertness CPU-green + `check-device-leakage` OK (SACRED CUDA 27B/35B/Coder = the GPU inertness proof). **M2a LANDED 2026-07-25 (`CLAIM-MULTIMODAL-M2A`): Qwen3-VL vision TOWER proven faithful vs vLLM 0.25.0** — `Qwen3_VisionTransformer` C++ forward (patch-embed, host pos-embed interp, 24 ViT blocks w/ partial-rotary vision RoPE + non-causal attn + tanh-GELU MLP, patch merger, DeepStack → `[196,10240]`) + 2 additive vt GELU ops; 4 RED-first tower gates PASS 348/348 vs the dumped tower reference (patch-embed 2.1e-3, block0 6.8e-3, full tower 5.1e-2, bf16-depth envelope; RED = rope disabled → 6 fails), cutlass-ON+FA2 banner, clean `-Werror`, compute-sanitizer 0, text-inertness by construction. M2 DECOMPOSED: **M2a tower [DONE]** → M2b MRoPE+DeepStack text backbone → M2c merge+e2e image gate (the Qwen3-VL LLM needs MRoPE 3-D positions + DeepStack decoder injection, NOT the plain dense forward). GATING FACTS: oracle 0.25.0 SHIPS the mm files; Qwen3.6 mm CHECKPOINT-gated; Gemma-4 (+audio) SPIKE/BLOCKED; audio deferred M5. **M2b/M2c numeric contracts UNIT-GREEN 2026-07-25 (`CLAIM-MULTIMODAL-M2BC`):** `Qwen3VLGetRopeIndex` (MRoPE 3-D `get_rope_index` [3,T]), the 3-section MRoPE application (proven = the existing `vt::RopeFromCache` mrope path, faithful for Qwen3-VL's interleaved `section=[24,20,20]`), `Qwen3VLComputeDeepstack` scatter, `Qwen3VLMergeMultimodal` — 4 RED-first CPU gates PASS 85/85 vs vLLM 0.25.0 (get_rope_index BIT-exact, MRoPE rel-L2 1.5e-3, DeepStack+merge BIT-exact), additive-only (text SACRED byte-identical by construction). **M2c LANDED + M2 CLOSED 2026-07-25 (`CLAIM-MULTIMODAL-M2C`): STRICT image→text token-exact 32/32 vs vLLM 0.25.0 on Qwen3-VL-4B** — the VL weight loader (`language_model.*`+`visual.*`) + forked greedy decode (embed+`Qwen3VLMergeMultimodal` scatter + 3-section MRoPE via `vt::RopeFromCache` global cache + DeepStack inject at layers 0/1/2 + paged greedy) run the full pipeline (`src/vllm/model_executor/models/qwen3_vl.{h,cpp}`, gate `tests/vllm/multimodal/test_qwen3vl_e2e.cpp`); no near-tie needed (STRICT exact, first try); clean `-Werror`, additive (text SACRED byte-identical) + SACRED regressions re-run. **First multimodal capability in the tree (image, correctness-complete, speed pending).** **M3-W0 LANDED 2026-07-25 (`CLAIM-MULTIMODAL-M3`):** the GATING FACT resolved — vision-inclusive checkpoint **`Qwen/Qwen3.6-27B`** (51.7 GiB uniform bf16, 333 `visual.*`, NOT gated) FOUND + fits GB10 (after reclaiming mine-only `~/work` trees) + downloaded; **vLLM 0.25.0 CONSTRUCTS + runs the `Qwen3_5ForConditionalGeneration` mm path** (golden captured, `scripts/mm/m3_oracle_capture.py`); 27B vision config resolved (depth 27/out 5120/**EMPTY deepstack** ⇒ simpler than 4B), MRoPE `[11,11,10]`/rot 64/theta 1e7, backbone 48 GDN + 16 full-attn; **the bf16 GDN-hybrid LLM loader ALREADY handles it** (`LoadQwen3_5Dense` routes bf16 by `.weight_packed` absence) so M3-b needs only the `visual.*` loader + the forked forward (inputs_embeds + MRoPE + merge, gated ⇒ text byte-identical). **M3-b LANDED 2026-07-25 (`CLAIM-MULTIMODAL-M3B`): STRICT image→text token-exact 32/32 vs vLLM 0.25.0 on Qwen3.6-27B — our own gate model's image path now works end-to-end.** The forked GDN-hybrid VL forward (`Qwen3_5VLGenerateGreedy` in `src/vllm/model_executor/models/qwen3_5.cpp`: embed + scatter the 27B tower merger `[196,5120]` into image_token(248056) rows [no deepstack] + 3-section MRoPE `[11,11,10]` interleaved on the 16 full-attn layers via `BuildMropeCosSinHost`→`DenseForwardLayers` `mrope_cos_sin` param + GDN-hybrid backbone + paged greedy) + vision-only loader `LoadQwen3VLVisionWeights` (27B config) + M2a tower + `LoadQwen3_5Dense` bf16 LLM → full pipeline == golden `ead4b484…` (gate `tests/vllm/multimodal/test_qwen3_5_vl_e2e.cpp`, 54/54). **Text-inertness re-run cutlass-ON+FA2: 27B 235/235, 35B 315/315, Coder 138/138** (the mm path is gated on mm input ⇒ text byte-identical). Clean `-Werror` 0 warn; compute-sanitizer on the 27B VL forward. **First multimodal completion of a shipped gate model.** **M3c LANDED 2026-07-25 (`CLAIM-MULTIMODAL-M3C`): VIDEO understanding on Qwen3-VL-4B — preprocessing + full wiring LANDED + unit-gated; e2e token-exact 22/32, divergence RCA'd OUT of the new video path.** The genuinely-new piece is video preprocessing (frame sampling + temporal grid + timestamp-interleaved placeholder); the tower handles temporal patches + MRoPE the temporal axis. `ProcessVideo`/`BuildVideoRepl`/`Qwen3VLGetRopeIndexVideo`/`Qwen3VLGenerateGreedyVideo` (+ per-frame windowed tower attention). Video-processor UNIT gate 41/41 (pixel_values_videos BIT-exact 0/393216, RED-first 195838 mismatch on the image-duplicate mapping); video MRoPE positions BIT-exact vs vLLM (delta −48); per-frame windowed tower faithful (rel-L2 0.072, within the bf16 envelope); video e2e 22/32 vs greedy. **M3c-TOWER-FIDELITY RESOLVED 2026-07-25 (`CLAIM-MULTIMODAL-TOWER-FIDELITY`): the divergence is a GENUINE bf16 near-tie, MEASURED — video e2e now NEAR-TIE-ROBUST PASS.** The prior spike RCA mislocated the flip (claimed tok24) and never teacher-forced. Teacher-forcing vLLM 0.25.0 on OUR exact sequence (`scripts/mm/m3c_video_neartie_gap.py`): the sole divergence is ONE near-tie at tok22 (' colorful' 33866 vs vLLM ' static' 1099, gap **0.125 nats**, our token vLLM's 2nd of 4 tokens tied within 0.25 nats), and EVERY downstream token (tok23-31) IS vLLM's teacher-forced argmax at gap **0.0000** (the 22/32-vs-greedy is the deterministic one-token shift from that single tie). Tower-accumulation analysis: our tower ALREADY runs f32 everywhere (cuBLASLt `CUBLAS_COMPUTE_32F` GEMMs + f32 online-softmax attention + f32 LayerNorm) = matches vLLM's cuBLAS bf16-in/f32-accum + FlashAttention f32-softmax, so rel-L2 0.072 is the irreducible inter-op bf16 rounding envelope, NOT a fixable numeric choice — NO kernel change warranted. Adopted the ratified near-tie gate (`test_qwen3vl_video_e2e`: anchor `our_ids_i32.bin` + `neartie_gap_mnats_i32.bin`, PASS iff all gaps ≤ 0.5 nats; max 0.125 << 0.5), identical in form to olmo2/qwen3-dense/glm4. Image e2e 4B STRICT 32/32 = the deterministic strict-pass proof (unchanged). Text SACRED byte-identical BY CONSTRUCTION (only the video TEST + a new script changed, zero src/kernel/shared-op). **M3d LANDED 2026-07-25 (`CLAIM-MULTIMODAL-M3D`): VIDEO on Qwen3.6-27B — STRICT video→text token-exact 32/32 vs vLLM 0.25.0 — COMPLETES the Qwen video modalities on our own gate model (image+video both e2e; audio N/A for Qwen).** A REUSE increment: the video driver `Qwen3_5VLGenerateGreedyVideo` (`src/vllm/model_executor/models/qwen3_5.cpp`) refactors the M3-b image driver into a shared `VLGenerateCoreGdn` and reuses the M3c processor/per-frame-windowed-tower/`Qwen3VLGetRopeIndexVideo` verbatim; image+video wrappers differ only in the merge mask (video_token 248057) + get_rope_index (temporal MRoPE `[11,11,10]`). Oracle `scripts/mm/m3d_video_oracle_capture.py` on the M3c synthetic clip (raw sha `8a111599…`, grid `[4,8,8]`, 64 video tokens) K=5 DETERMINISTIC ⇒ STRICT golden; gate `test_qwen3_5_vl_video_e2e.cpp` **32/32** (27/27 assertions; teacher-forced near-tie gaps 0.0000 at every position). Inertness: 27B IMAGE e2e re-run STRICT 32/32 (the refactor is byte-identical on image); text SACRED 27B 235/235, 35B 315/315, Coder 138/138 by construction (shared text forward untouched, video path gated on mm input). Clean `-Werror` 0 warn, cutlass NVFP4+FP8+Marlin+FA2 banner; compute-sanitizer 0 on the 27B video forward. **Qwen3.6-27B is now image+video e2e (SPEED pending).** **Gemma-4 mm + AUDIO readiness assessed 2026-07-25 (`CLAIM-GEMMA4-MULTIMODAL`, [gemma4-multimodal.md](specs/gemma4-multimodal.md)):** Gemma-4 mm = **oracle-BLOCKED (decisive)** — its vision/audio towers load via Transformers `AutoModel.from_config` but the dgx oracle transformers 5.13.1 has no `gemma4` (measured; `gemma3n` present) ⇒ no constructible oracle, no gate; also ≥12B gated mm-wrapped + PLE/YOCO/Gemma-4-MoE backbone + USM-Conformer audio tower unbuilt (SigLIP vision tower reuses M2a); HW fits 12B. **AUDIO** is the genuinely-new modality (nothing built; Qwen3.6 has none) — reachable NOW on native oracle-runnable vehicles, staged A0–A3 on the smallest: `whisper-small` (pipeline+tower) → `Voxtral-Mini-3B` (e2e merge on the LANDED Mistral backbone); the Gemma-4 USM-Conformer tower delta proven on Granite-Speech-2b. Gemma-4 rows `SPIKE`/blocked. **AUDIO A0+A1 LANDED 2026-07-25 (`CLAIM-AUDIO-PIPELINE`, `ENG-MM-AUDIO-PIPELINE` `ACTIVE`, [audio-track.md](specs/audio-track.md)):** the C++ audio INPUT pipeline on `whisper-small` — canonical PCM16 WAV decode + log-mel `input_features` `[80,3000]` + placeholder expansion (`[0]*1500`) + mm-hash — **audio-processor parity gate PASS 77/77** vs the vLLM-0.25.0/transformers-5.13.1 oracle (log-mel rel-L2 **1.96e-7**, ids+mm-hash bit/byte-exact, RED-first mel/hop/normalize), INERT when no audio (image/video/text byte-identical; shared-TU gates 23/41/71/32/85 re-run). **AUDIO A2 LANDED 2026-07-25 (`CLAIM-AUDIO-ENCODER`, `ENG-MM-AUDIO-ENCODER` `ACTIVE`, [audio-track.md](specs/audio-track.md) §0b):** the Whisper-class AUDIO ENCODER TOWER proven faithful in ISOLATION on `whisper-small` — C++ `WhisperAudioEncoderForward` (`src/vllm/model_executor/models/whisper_audio.{h,cpp}`) mirrors transformers `WhisperEncoder` (2×Conv1d frontend as im2col+`vt::MatmulBT` [NO new CUDA kernel], fixed sinusoidal `embed_positions` golden, 12 pre-norm bidirectional blocks w/ k_proj-no-bias + `vt::Attention(causal=false)` + GELU-erf MLP, final `layer_norm`) → encoder hidden states `[1500,768]`; **encoder-tower fidelity gate PASS 203/203** vs the dumped bf16 reference (post_conv rel-L2 4.7e-3, block0 6.6e-3, encoder-output 3.0e-2; bf16-depth envelope ~0.28%/layer over 12 layers, matches M2a), GPU under `flock` on a cutlass-ON build (sibling 27B NOT co-resident), **RED-first** (wrong conv-stride 0.34 / missing sinusoid 0.86 / skipped final-LN 4.22 all FAIL; honest non-discriminators recorded: GELU-tanh≈erf in-envelope, single conv-weight aggregate-insensitive), additive ⇒ text/image/video/audio-pipeline byte-identical BY CONSTRUCTION. Delta from the M2a vision tower: NO patch-merger/DeepStack/RoPE (bidirectional + fixed additive sinusoid), conv frontend not patchify, GELU-erf everywhere. This is the encoder HALF (NOT audio→text). **AUDIO A3 LANDED 2026-07-25 (`CLAIM-AUDIO-E2E`, `ENG-MM-AUDIO-E2E` `ACTIVE`, [audio-track.md](specs/audio-track.md) §0c): the FIRST e2e AUDIO→TEXT understanding in the tree — audio→text on `Voxtral-Mini-3B-2507` (downloadable, NOT HF-gated; oracle-runnable, vLLM greedy K=5 DETERMINISTIC).** Full C++ pipeline `src/vllm/model_executor/models/voxtral.{h,cpp}` (A1 log-mel `[128,3000]` → the A2 encoder at Voxtral's Whisper-large-v3 config [1280/32L/head_dim 64/128 mel] → downsample-concat `[375,5120]` → AudioLanguageAdapter projector `[375,3072]` → `Qwen3VLMergeMultimodal` scatter at the 375 audio-token rows → forked greedy over the LANDED Mistral/Llama decoder, untied lm_head); loader applies vLLM's Meta→NeoX q/k rope PERMUTE for the mistral consolidated format (verified `permute(wq)==vLLM q_proj`; RED text-only 1/22→22/22). **e2e gate PASS 14/14** (`tests/vllm/multimodal/test_voxtral_e2e.cpp`, GPU under flock, cutlass-ON): STRICT prefix **33/48** vs vLLM greedy (log-mel rel-L2 7.7e-7), decoder proven token-exact (vLLM ref-audio→48/48), and — bit-exact infeasible (encoder uses different bf16 GEMM/attn kernels than vLLM's cuBLASLt+FLASH_ATTN; 8.7% = the A2 envelope over 32 layers) — the ratified near-tie-robust gate PASSES (teacher-forced worst gap **0.0 nats**, sole branch a 4-way bf16 tie at -2.069 nats). INERT: additive (`git diff --stat` 2 modified lines); Mistral 541/541 + A1 77/77 + A2 203/203 byte-identical; no new CUDA kernel. **The AUDIO leg is correctness-complete end-to-end (SPEED pending).** **MM SPEED MEASURED 2026-07-26 (`CLAIM-MULTIMODAL-SPEED`, [multimodal-speed.md](specs/multimodal-speed.md)):** correctness-complete → SPEED characterized at c1 vs vLLM 0.25.0 GRAPHED. **Qwen3.6-27B image: decode AT PARITY (225.0 vs 226.9 ms/tok, marginally faster) + LLM prefill at parity — the ENTIRE gap is the vision encoder tower (~2.1 s vs vLLM's ≤~250 ms encode, ~10×), which dominates time-to-first-token (2.44 s vs 0.32 s).** Verdict: encoder-tower-dominated, NOT host-bound at c1 (the 226 ms/tok is the ~54 GiB bf16 weight-streaming floor — both engines sit on it). Video: same story (decode at parity, tower is the gap). Audio (Voxtral): vLLM denominator captured (TTFT 43 ms, TPOT 41 ms/tok); our-side UNMEASURED (build-blocked, dgx disk 100% full) — the cheap 3B decode makes it the path where the eager-driver host overhead could bite. Ranked levers: (1) vision-tower kernel efficiency (nsys; suspect vision attn not on FA2 varlen), (2) route mm decode through the graphed paged runner (neutral c1-27B, the audio/c2+ lever), (3) batched mm serving (structural; single-seq drivers ⇒ no c2+/server today). **TOWER LEVER #1 EXECUTED + CLOSED 2026-07-26 (`CLAIM-MULTIMODAL-SPEED-TOWER`, [multimodal-speed.md](specs/multimodal-speed.md) §7):** nsys `cuda_gpu_kern_sum` attributed **98.9 % of the tower forward to the naive `vt::cuda::AttentionKernel`** (56 ms/block over 784 patches; NOT QKV/FA2-routing — the suspicion above REFUTED, and the `cudaFree`-93 % in `cuda_api_sum` was a sync-artifact red herring). Fixed by (a) a warp-scoped online-softmax op `AttentionDenseFast` (no `__syncthreads`, register accumulator; SEPARATE op ⇒ `kAttention`/text byte-identical) + (b) one-time resident-weight load ⇒ **per-image vision tower 2114 → 148 ms (14.3×), 0.59× vs vLLM's ~250 ms eager encode = FASTER.** Correctness RED-line HELD: 27B image e2e STRICT **32/32**, 27B video STRICT **32/32**, 4B DeepStack image STRICT **32/32**, `test_ops_attention` **37239/37239**, 27B text SACRED **235/235**; clean `-Werror`, compute-sanitizer memcheck **0**. Remaining DONE-bar work: batched/graphed mm serving (c2+) + audio our-side. No mm row advances to `DONE` (speed bar unmet on every axis). **DECODE LEVER #2 EXECUTED + CLOSED 2026-07-27 (`CLAIM-MULTIMODAL-SPEED-DECODE`, [multimodal-speed.md](specs/multimodal-speed.md) §8):** on-GPU greedy argmax (via `vt::GreedyArgmax`, dropping the full-vocab D2H + host scan) + removal of the decode embed D2H→H2D round-trip on both mm eager decode loops (`VLGenerateCoreGdn` 27B image+video; `VoxtralGenerateGreedy` audio). Bit-exact (goldens md5-identical; 27B image+video STRICT 32/32, 4B image 32/32, Voxtral 14/14 all HELD). SAME-BINARY A/B (rep0 dropped): audio decode TPOT 61.85 ms (61.73–61.94) vs 62.08 ms host = ~0.4% win; 27B image decode 223.0 ms (221.7–225.2) vs 224.0 ms host = NEUTRAL (~222 ms weight-streaming floor, at vLLM parity). HONEST: the win is small — even at 3B the ~62 ms eager forward dominates; the audio 1.52× gap vs vLLM's 40.8 ms graphed is eager per-step launch overhead (lever #3, graphed decode, for which on-GPU sampling is now a prerequisite in place). Audio our-side is now MEASURED (was build-blocked). mm rows stay `PARTIAL`. **DECODE LEVER #3 FIRST BRICK 2026-07-27 (`CLAIM-MULTIMODAL-SPEED-GRAPH`, [multimodal-speed.md](specs/multimodal-speed.md) §9):** the shared 27B image+video decode step (`VLGenerateCoreGdn`) now routes through the production `Qwen3_5DenseDecodeGraph` cold→warm→replay CAPTURED decode (was an eager per-step loop) — mm decode is now GRAPH-CAPTURABLE, closing the §3 un-graphed structural gap. Single-seq ⇒ S==B==1 bit-identical rebuild; decode-time 1-D device RoPE at p reproduces the degenerate MRoPE {p,p,p} → token-exact HELD (27B image STRICT 32/32, video STRICT 32/32, golden md5 unchanged, 30 graph replays confirmed). A/B graphed 232.5 vs eager 233.4 ms/tok = NEUTRAL at the 27B bandwidth floor (as §8 predicted — the ~1 ms/tok launch overhead is hidden). Structural gap closed; the launch-overhead win + c2+ + serving ingestion are the recorded W-plan (W1 Voxtral decode-graph = the audio 1.52× gap-closer since 3B decode is NOT bandwidth-floored; W2 batched multi-seq; W3 `image_url`/`audio_url` serving ingestion). mm rows stay `PARTIAL`. **DECODE LEVER #3 W1 LANDED 2026-07-27 (`CLAIM-MM-SPEED-GRAPH-W1`, [multimodal-speed.md](specs/multimodal-speed.md) §10): the Voxtral (Mistral/Llama) decode-graph class — the last mm text stack without one.** New `VoxtralDecodeGraph` (`voxtral.{h,cpp}`, sibling of `Qwen3MoeDecodeGraph`: pure full-attention over `dense_attn::AttnBlock`+`vt::PagedAttention`, no GDN); `VoxtralGenerateGreedy`'s pure-decode loop now runs `VoxtralDecodeGraph::Step` (captures the exact `ForwardLastLogits`; S==B==1 bit-identical rebuild), eager fallback `VT_MM_DECODE_EAGER`. RED line HELD (proven-to-run `VT_DECODE_GRAPH_STATS`: captured S=1 + 46 replays): **14/14** (near-tie seq 48/48, strict prefix 33/48), goldens md5 unchanged. A/B steady-state TPOT graphed **60.94 ms/tok** (60.79–61.07) vs eager **61.71** (61.57–61.88) = **−0.77 ms/tok (~1.25%, NON-OVERLAPPING)** — a real clean win, but it NARROWS the audio gap **1.52×→1.49×** vs vLLM's 40.8 ms, does NOT close it. HONEST REFINEMENT of the §9.5 hypothesis: the removable per-step launch overhead was only ~1.25% of TPOT, so the ~20 ms/tok residual is per-step COMPUTE/kernel efficiency (vLLM's torch.compile-fused + graphed decode), NOT launch overhead — closing the audio gap needs a decode-kernel nsys/port pass and/or W2 batching, not more graphing. Structural: Voxtral now graph-capturable (prereq for c2+). mm rows stay `PARTIAL`. **DECODE-KERNEL EFFICIENCY ATTRIBUTED + VALIDATED CEILING 2026-07-27 (`CLAIM-MM-SPEED-DECODE-KERN`, [multimodal-speed.md](specs/multimodal-speed.md) §11):** nsys (graph-node trace) of the graphed Voxtral decode shows the WHOLE ~20 ms/tok residual is ONE kernel — the naive scalar `PagedAttentionKernel` decode attention (1410 inst = 30 layers × 47 steps @ 723 µs/call = 21.7 ms/step, ~120× the KV floor); the GEMMs (cuBLAS `gemvx`, == vLLM's decode `F.linear`) + lm_head + norm/rope/silu glue are all near-BW-floor. The 1:1 vLLM lever (FA2 `flash_attn_varlen` split-KV decode, `flash_fwd_splitkv`) is ALREADY in-binary (DEFAULT-ON `fa2_decode_qwen3`), gated off ONLY because the driver's single KV block `block_size=444` isn't ÷16. `block_size÷16` routes decode through FA2 (18.5 µs, 39× faster): same-binary A/B **TPOT 59.4→38.2 ms/tok (−21.2, ~36%, NON-OVERLAPPING) = 0.94× vLLM 40.8 ms — CLOSES AND BEATS the gap.** BUT it changes the bf16 reduction order → flips the committed near-tie golden's pos-33 EXACT-tie branch (`repro` 48→18) → `repro==48` FAILS (RED line). The FA2 sequence is FULLY VALID (teacher-force vLLM 0.25.0: 0 divergences, worst gap 0.0000, PASS — a different-but-equal greedy branch, not a bug). A bf16 near-tie / golden-pinning ceiling; NO byte-exact faster decode-attention kernel exists. RECORDS-ONLY (14/14 held, golden unchanged); the validated ~36%/BEATS-vLLM win is one `block_size÷16` + a golden regen away (USER DECISION). **ADOPTED 2026-07-27 (USER-APPROVED, `CLAIM-MM-SPEED-DECODE-KERN-ADOPT`, multimodal-speed.md §12): FA2 decode SHIPS as the Voxtral default — audio DECODE BEATS vLLM (0.97×), the LAST mm decode-speed gap CLOSED.** One-line `block_size÷16` routes decode via FA2 (nsys: `flash_fwd_splitkv` 1410 @ 18.5 µs, zero `PagedAttentionKernel`); `test_voxtral_e2e` converted to the ratified near-tie DISTRIBUTIONAL gate (binding = teacher-force PASS, KERNEL-INDEPENDENT; strict prefix exact to the first bf16 tie — FA2 pos 18, `>=18`; determinism anchor to the FA2 seq); `voxtral_neartie.json` regenerated (md5 `937b9ad3…`), STRICT greedy golden UNCHANGED (`8ab87b7e…`); **gate PASS 16/16**; teacher-force vLLM 0.25.0 = **0 divergent, gap 0.0, PASS**; capture-safe (graph S=1 + 46 replays valid, compute-sanitizer **0 errors** on the graphed-FA2-decode path, 3 runs byte-identical) ⇒ ships as the DEFAULT graph path; **A/B (same-binary, 6 reps rep0 dropped): scalar 60.50 → FA2 39.50 ms/tok (−21.0, ~35%, NON-OVERLAPPING) = 0.97× vLLM 40.8 ms — BEATS.** Audio DECODE now correctness+speed DONE; MM row stays `ACTIVE` (umbrella PARTIAL: audio TTFT/32-layer Whisper encoder + c2+ batched serving). **ENCODER TTFT MEASURED + warp-attention brick 2026-07-27 (`CLAIM-MM-SPEED-AUDIO-ENC`, multimodal-speed.md §13):** the Whisper encoder ran the naive `kAttention` (O(t²) per-key block-`__syncthreads`) — routed the encoder self-attention (hd-64, non-causal) to the warp-scoped `vt::AttentionDenseFast` (§7 tower fix; `kAttention` untouched ⇒ text byte-identical): encoder forward **8870→1890 ms (4.7×, NON-OVERLAPPING)**, `test_voxtral_e2e` **16/16** with ZERO token flips (naive arm also 16/16 same tokens; goldens md5 UNCHANGED), nsys proof-of-run `AttentionWarpKernel` 32 inst/zero naive. **NOT at parity:** ~1.89 s vs vLLM's 43 ms TTFT (~44×) — the warp kernel is STILL 31.8 ms/layer (O(t²), memory-bound on redundant K/V reads, no shared-mem tile reuse) + per-call host weight marshalling + conv round-trip; closing needs (1) a flash-TILED non-causal hd-64 encoder attention (LARGE, the gap-closer) + (2) resident one-time encoder weights (MEDIUM, byte-exact). Audio TTFT/encoder stays speed-pending. **ENCODER FLASH-TILED KERNEL LANDED 2026-07-28 (`CLAIM-MM-SPEED-AUDIO-ENC-KERNEL`, multimodal-speed.md §14):** §13 lever #1 done — new `vt::AttentionDenseFlash` (`OpId::kAttentionDenseFlash`, `cuda_ops.cu`) shared-memory-TILES K/V across a block of `kFlashBr=16` query-warps (FA2 K/V tiling, structure-ported from vendored `flash_fwd_kernel.h:52`), per-warp online-softmax math copied verbatim from `AttentionWarpKernel` ⇒ BIT-IDENTICAL; encoder routed to it by default (`VT_WHISPER_ENC_WARP=1`/`EAGER=1` A/B); `kAttention`/`kAttentionDenseFast` untouched ⇒ text/vision byte-identical. **16/16** default-flash, flash/warp/eager token md5-IDENTICAL (`89923566…`), goldens md5 UNCHANGED, nsys proof `AttentionDenseFlashKernel` 32 inst/zero warp+naive, RED confirmed (corrupt→13/16→restore→16/16), compute-sanitizer 0, 3 runs identical. **A/B same-binary:** attention **35.11→19.29 ms/layer (1.82×, NON-OVERLAPPING)**, encoder forward **~1834→~1375 ms (1.33×)**. **NOT at parity:** ~1.37 s vs vLLM ~43 ms (~32×, was ~44×) — the scalar warp-per-query recurrence is now serial-latency-bound over 1500 keys (L2 already served the redundant reads ⇒ 1.8× not 16×); gap-closer = tensor-core MMA hd-64 non-causal FA2 (LARGE) + resident encoder weights (MEDIUM). **ENC lever #2 LANDED 2026-07-28 (`CLAIM-MM-SPEED-AUDIO-ENC-RESIDENT`, §15): device-resident one-time encoder weights** (mirror Qwen `d_dev` seam; 487 weight tensors converted+uploaded ONCE, reused across forwards) — BYTE-EXACT (16/16, goldens md5 unchanged, sanitizer 0), nsys HtoD 740 vs 1714 ops (−974, −2.5 GB), A/B encoder forward **~1377→~729 ms (−648 ms, 1.89×)** removing the confirmed ~0.75 s per-call host marshalling; trajectory 1834→1375→729 ms, ~17× vs vLLM (was ~32×), still NOT at parity (residual GPU-compute-bound). NEXT: the tensor-core MMA hd-64 flash (LARGE, the true gap-closer) + drop the conv host round-trip (needs a device im2col kernel); the USM Conformer tower delta (A2-follow, Granite-Speech-2b) for the Gemma-4 audio family; W2 batched multi-seq mm decode. **QWEN VISION-FORWARD SPEED 2026-07-28 (`CLAIM-MM-SPEED-QWEN-IMAGE`, multimodal-speed.md §16):** GPU campaign #2 — extended the §14 flash-tiled `vt::AttentionDenseFlash` to the Qwen3-VL/27B vision tower (hd-72) byte-exact. ATTRIBUTION-FIRST (nsys `cuda_gpu_kern_sum`): ~85% of the 148 ms tower forward is the dense attention (`AttentionWarpKernel` 4.66 ms/block×27). Routed warp→flash (per-warp math verbatim ⇒ BIT-IDENTICAL): STRICT 32/32 image (27B+4B) + video HELD, `test_ops_attention` 37239/37239, bench flash-vs-warp 0/1,003,520 mismatch, goldens md5 UNCHANGED, nsys default 4B e2e `AttentionDenseFlashKernel` 24 inst/zero warp, RED 30/46→46/46, compute-sanitizer 0. A/B warp **148.3→flash 142.3 ms = 1.04×** — the profile **REFUTED** a bigger lever: at t=784 (single window) the vision attention is serial-latency-bound not K/V-bandwidth-bound (audio §14 was 1.82× at t=1500), flash recovers only ~6 ms. **HONEST: the Qwen image/video mm-forward tower ALREADY BEATS vLLM — 142 ms vs vLLM 0.25.0 ~250 ms eager encode = 0.57×** (correctness-DONE + speed-BEATS); umbrella row stays `PARTIAL` for batched c2+/serving; residual (NOT needed for parity) = tensor-core MMA hd-72 non-causal attention. **SERVING TRACK OPENED 2026-07-28 (`CLAIM-MM-SERVING-W1`, [mm-serving.md](specs/mm-serving.md)): the FIRST CPU brick of wiring multimodal into the OpenAI server LANDED.** The chat request `content` now accepts the OpenAI multimodal content-part ARRAY (`[{type:text},{type:image_url,image_url:{url:"data:…;base64,…"}},{type:input_audio,input_audio:{data,format}}]`) in addition to the bare string; parse mirrors vLLM `chat_utils.py` MM_PARSER_MAP:1478/_parse_chat_message_content_mm_part:1524. New `entrypoints/openai/chat_mm.{h,cpp}`: `DecodeBase64` (RFC4648) + `DecodeDataUri` (RFC2397) + `RouteAudioWav`/`RouteImageRgb` route the decoded bytes through the EXISTING single-sequence processors (`qwen3vl_processor`/`audio_processor`) → `MultiModalInputs` (placeholder-expanded ids + mm_features), CPU-only, no model weights. Gate `test_chat_mm` 5/5 (65 asserts): bare-string INERTNESS (content_parts nullopt, prompt byte-identical), base64/data-URI vectors, `input_audio` (base64 whisper WAV) → features [80,3000] + 1500 placeholder tokens + byte-exact mm-hash, `image_url` (raw-RGB fixture data URI) → grid [1,28,28] + 196 merged tokens; inertness suites (`test_openai_protocol` 28/171, serving 40/527, chat-stream 2/210) byte-identical; clean `-Werror` lib+server 0-warn. Bricks (spec): `MM-SERVE-PARSE` DONE (this); `MM-SERVE-ENGINE` residual (attach mm_features to the engine request — no `add_request` mm overload yet; placeholder-string insertion into the chat template); `MM-SERVE-E2E` **MANDATORY closing gate** — a real image+prompt OpenAI request → token-correct output on Qwen3-VL-4B vs the mm oracle (needs DGX + checkpoint). Named residuals: container-format image decode (PNG/JPEG→RGB — no codec vendored, route takes raw RGB), http(s) media fetch, streaming/multi-image/video parts. **GEMMA-4 W0 RUN-VERIFIED 2026-07-28 (`CLAIM-GEMMA4-W0`):** the pinned oracle (vLLM 0.25.0 + transformers 5.13.1) LOADS+RUNS+GENERATES ungated `unsloth/gemma-4-E4B-it` (`Gemma4ForConditionalGeneration`) on GB10 with a STRICT K=5 greedy golden (`tests/parity/goldens/gemma4_e4b_text/`) — the "oracle lacks gemma4" block is RETIRED by measurement (runs on the CURRENT pin); the two `MODEL-MM-gemma4-*` rows stay `SPIKE`, now IMPLEMENTATION-blocked only (PLE/YOCO/Gemma-4-MoE backbone + USM-Conformer audio unbuilt; SigLIP vision reuses M2a); G1 backbone unblocked to start. **SERVING BRICK 2/3 LANDED 2026-07-28 (`CLAIM-MM-SERVING-W2`, [mm-serving.md](specs/mm-serving.md)): `MM-SERVE-ENGINE` DONE — the parsed `MultiModalInputs` is now CARRIED into the engine request.** Additive `LLMEngine`/`AsyncLLM` `add_request(MultiModalInputs)`+`generate(MultiModalInputs)` overloads via new `InputProcessor::process_inputs_mm` (mirror `input_processor.py:333-379`: the placeholder-EXPANDED prompt ids + `mm_features` ride onto `EngineCoreRequest`→`Request::FromEngineCoreRequest`; empty mm_features == the tokens path byte-for-byte). Chat-template placeholder-STRING helpers `ImagePlaceholderString`/`VideoPlaceholderString`/`AudioPlaceholderString(i)`+`CollectChatPlaceholders` mirror vLLM `get_placeholder_str` (qwen3_vl.py:1714 image/video vision markers, qwen2_audio.py:333 audio marker) + `_add_placeholder` (chat_utils.py:886); the single marker is what brick-1's `ExpandImagePlaceholders` expands to N=grid/feature-count. serving_chat gains an OPTIONAL `MultiModalChatFn` seam (`set_multimodal_chat_fn`, default UNSET ⇒ text path byte-identical; streaming mm rejected — residual) routing mm requests through the engine mm `generate`. Gate: `test_input_processor` +2 (`process_inputs_mm` carries mm_features + expanded prompt; empty==tokens) + `test_chat_mm` +2 (placeholder strings mirror vLLM; full chain parse→route→`process_inputs_mm`→`FromEngineCoreRequest` asserts the engine request carries the mm handles + the 196-slot expanded prompt); text-inertness suites (`test_input_processor` 10/10, `test_chat_mm` 7/7, `test_llm_engine`, `test_async_llm`, `test_openai_serving`, `test_openai_serving_chat_stream`) byte-identical; clean CPU `-Werror` library+server 0-warn. **`MM-SERVE-E2E` remains the MANDATORY closing gate** — the `MultiModalChatFn` seam BODY (model tokenizer to turn the markers→single placeholder token ids + the qwen3vl/whisper processors) + the mm FORWARD (encoder tower + DeepStack/MRoPE) consuming `Request.mm_features` on the GPU worker → a real image+prompt `/v1/chat/completions` request token-correct on Qwen3-VL-4B vs the mm oracle (needs DGX + checkpoint). **Gemma-4 G1b LANDED 2026-07-28 (`CLAIM-GEMMA4-G1B`): the `Gemma4ForConditionalGeneration` TEXT path is STRICT 32/32 TOKEN-EXACT vs vLLM 0.25.0 (`unsloth/gemma-4-E4B-it` loads through our engine + greedily emits the exact 32 golden ids; gate `tests/parity/test_gemma4_paged_engine.cpp`, dgx CUDA `flock`). The G1-named blocker is CLEARED: the runner now allocates a PER-LAYER KV head_dim (`KVCacheConfig::per_layer_attn_specs`) for the heterogeneous 256/512 heads — BYTE-NEUTRAL (empty ⇒ old path; full CPU runner/KV suite + OLMo-2 SACRED GPU 16/16 UNCHANGED). Three additive loader gaps fixed en route to the first-ever forward: nested `rope_parameters` (hf_config), Gemma `Replace(" "→"▁")` metaspace normalizer (tokenizer), and reading Gemma-4 scalars from `raw["text_config"]` (the real 256/512 head_dim source, a G1 latent bug). Residuals: YOCO cache dedup (G1c, memory-only), G2 IMAGE oracle + SigLIP/NaFlex port map LANDED 2026-07-28 (`CLAIM-GEMMA4-G2`, honest partial): the E4B IMAGE→text greedy golden is STRICT K=5 (`tests/parity/goldens/gemma4_e4b_image/`, 18 tokens → coherent image description, 256 soft tokens) + 4 staged vision refs (M2a unit-gate targets) + full tower port map (spec §G2) — ★ the tower is a custom NaFlex SigLIP2 WITH multidim vision-RoPE + q/k/v-norm + Gemma2 sandwich norms + learned-2D pos-embed + √hidden avg-pool pooler (the earlier "no RoPE, reuses M2a as-is" assumption REFUTED); image NOT yet engine-gated, the C++ NaFlex tower + Gemma-4 image processor + projector/merge are the named residual. **G2-impl LANDED 2026-07-28 (`CLAIM-GEMMA4-G2-IMPL`): the C++ NaFlex SigLIP2 vision TOWER is implemented (additive `gemma4_vision.{h,cpp}`) and PASSES all 4 per-stage gates vs the transformers-eager refs (patch-embed 2.15e-3 / encoder 3.14e-2 / pooled 1.36e-2 / projected 1.85e-2; 220/220; compute-sanitizer 0; text STRICT 32/32 inertness held; ★ found+implemented the FINITE QAT clamps the port-map missed; ZERO new vt op). Image→text e2e (C++ NaFlex image processor + engine merge-plumbing) is the named M2c-equivalent residual. **G3 LANDED 2026-07-28 (`CLAIM-GEMMA4-G3`): the C++ USM-Conformer AUDIO TOWER + audio projector are implemented (additive `gemma4_audio.{h,cpp}`) and PASS all 7 per-stage gates f32-exact vs the transformers-eager refs (host f32, 1256/1256: subsample 5.4e-7 / posemb 8.9e-8 / block0 4.2e-7 / block_mid 3.8e-7 / block_last 4.4e-6 / output_proj 5.9e-6 / projected 6.3e-6). Ported 1:1 from `modeling_gemma4.py` @ 5.13.1: 2×Conv2d subsample + rel-pos-enc + 12 Conformer layers (half-step FFN, chunked-local attn [chunk 12, past window 12, Transformer-XL rel-shift, softcap 50, per_dim_scale softplus], GLU + depthwise causal conv k5) + output_proj + embed_audio; FINITE QAT clamps; RED-first (wrong 13-key window → 2.8e-2, fixed 12-key → ~1e-6); ZERO new vt op (host f32). Gemma-4 TRI-MODAL TOWERS now all proven (text STRICT + vision + audio per-stage); audio/image feature-extractor + engine mm e2e is the named residual.** Per-axis SPEED (text correctness-DONE, speed-pending)** **ENGINE MM-FORWARD LANDED 2026-07-28 (`CLAIM-ENGINE-MM-FORWARD`, [mm-serving.md](specs/mm-serving.md)): the `MM-SERVE-E2E` architectural block is RESOLVED** — multimodal now runs through the engine's REGISTERED forward (`ModelRegistry::Forward`): additive default-nullopt `ModelForwardInput.mm` field (text byte-identical BY CONSTRUCTION) + `REGISTER_VLLM_MODEL(qwen3_vl, …)` + the registered forward folds the M2c decode via the SHARED `Qwen3VLForwardStepLastLogits`. GPU token-exact gate `test_qwen3vl_registry_e2e` (image→text THROUGH `ModelRegistry::Forward` == M2c golden **32/32 STRICT**, dgx.casa GB10); text inertness runner/scheduler/registry/chat_mm/serving all green. Residual: the in-runner scheduler-fed tower run (batched-loop mm) + the real server `/v1/chat/completions` GPU e2e.** **GEMMA-4 IMAGE mm e2e LANDED 2026-07-29 (`CLAIM-GEMMA4-MM-E2E`):** the Gemma-4 SigLIP2 vision tower is FOLDED into the ENGINE registered forward (`Gemma4ForConditionalGeneration` `supports_multimodal=true` + mm branch → `Gemma4Model::ForwardMm`; driver `Gemma4GenerateGreedyViaRegistry` in `gemma4_mm.cpp`, mirror of the Qwen3-VL fold). Gate `test_gemma4_registry_e2e` (dgx sm_121a, `flock`): **16/18 content tokens BIT-EXACT** vs the STRICT `gemma4_e4b_image` golden (full sentence), the single divergence a terminal-punctuation bf16 near-tie (margin ~0.10-0.12, invariant to vision-input precision ⇒ backbone bf16, not the fold); text SACRED 32/32 UNCHANGED. Residuals: STRICT-18/18, audio→text e2e (mel A1 + merge; the G3 audio tower is per-stage proven), speed.** | | MM-S | `ROAD-V1-MM-SERVE` | **Multimodal SERVING — wire image/audio/video into the OpenAI `/v1/chat/completions` server (user-directed roadmap item).** The single-sequence multimodal (MODEL-MM) pipeline is correctness-complete; this track makes it SERVABLE over the OpenAI API. | [engine-matrix `ENG-MM-INPUT-PIPELINE`](engine-matrix.md), [feature-matrix §11](feature-matrix.md) | [mm-serving.md](specs/mm-serving.md) — 3 bricks (PARSE/ENGINE/E2E) + vLLM `file:line` | `ACTIVE` | **W1+W2+W3 CPU LANDED (2026-07-28, `CLAIM-MM-SERVING-W1`/`W2`/`E2E`).** W1 content-part parse+route (`0a8dd58b`); W2 engine mm-request plumbing + `MultiModalChatFn` seam (`2581a7d4`); W3 the seam BODY `MakeQwen3VLImageChatFn` (messages → marker-inject → chat template → tokenize (single image_pad id) → RouteImageRgb EXPAND to 196 image tokens + mm_features) wired in `examples/server/main.cpp`, gated `test_chat_mm` 8/8 (RED: text path = 0 image tokens) + `test_openai_serving` (production seam invoked + routed); text path byte-identical; clean `-Werror` server build. **Residual `MM-SERVE-E2E` (GPU forward): ARCHITECTURALLY BLOCKED** — the engine model runner has no mm forward (`ModelForwardInput` has no vision field; `runner.cpp` ignores `Request.mm_features`; Qwen3-VL unregistered; M2c `Qwen3VLGenerateGreedy` is a standalone driver). Exact fold-into-engine recipe in the spec. | @@ -774,6 +775,14 @@ de-risked by the W1 config check). ## Decision rules carried forward +`ROAD-V1-A-CP` scheduler checkpoint (2026-08-01): +`ENG-CHUNKED-PREFILL` moved from `ANCHOR-BACKFILL` to `SPIKE` with the accepted +[basic chunked-prefill contract](specs/chunked-prefill.md). Existing runtime +support is unchanged. The next CPU leaf ports all three pinned groups: +shared-budget partial requests, disabled ordering, and concurrent-partial +400/400/224 cases with prefix caching on/off. The row cannot close until the +same-workload GPU every-axis gate runs. + - Every perf claim: same-box A/B vs the reference, token-exact gated, fresh denominators (benchmark-protocol.md). Vendoring needs a MEASURED win first (B4 criterion). Parallel execution and the `${GPU_LOCK}` mechanism come from diff --git a/.agents/specs/chunked-prefill.md b/.agents/specs/chunked-prefill.md new file mode 100644 index 00000000..ddc4dda3 --- /dev/null +++ b/.agents/specs/chunked-prefill.md @@ -0,0 +1,83 @@ +# Chunked prefill spike + +Row: `ENG-CHUNKED-PREFILL`. Claim: `CLAIM-ENG-CHUNKED-PREFILL-SPIKE`. +Upstream pin: vLLM `5559679229bc961848b121ccdeaa8fa5d79bec98` (`0.26.0.dev0`). + +## Scope + +This spike backfills the contract for basic token-budget chunked prefill that already exists in vllm.cpp. The row-sized supported slice is: split a prompt across scheduler steps when it exceeds the remaining token budget; admit multiple partial prefills into one step; cap each request with `long_prefill_token_threshold`; keep partial prefills in the running set; emit no sampled token until prefill completes; and refuse an over-budget waiting request when chunking is disabled. + +This spike does not claim newer adjacent modes as part of the basic row: multimodal encoder-input chunk boundaries, Mamba-aligned/fine-grained-prefix stops, DP prefill throttling, pooling-specific policy, or configurable multi-partial-prefill admission limits. Those need their own rows or an explicit split before implementation. No runtime source changes in this PR. + +## Upstream chain + +- `vllm/config/scheduler.py:58-91,126-136,261-310`: budgets, `enable_chunked_prefill`, `long_prefill_token_threshold`, partial-prefill limits, and validation/default derivation. +- `vllm/v1/core/sched/scheduler.py:427-561`: running-first remaining-token calculation, threshold cap, token-budget cap, and zero-work skip. +- `vllm/v1/core/sched/scheduler.py:640-930`: waiting admission, prefix-hit accounting, chunking-disabled stop, budget clipping, encoder-input and Mamba clipping, and slot allocation. +- `vllm/v1/core/sched/scheduler.py:1845-1900`: output folding and the `is_prefill_chunk`/discard contract that prevents sampling from incomplete prefills. + +No dependency kernel selects the chunk size. This is host scheduler policy; scheduled token counts shape normal model-runner batches. Dynamic execution tracing is therefore a follow-on performance gate, not a missing semantic dependency. + +## Our baseline + +- Configuration exists at `include/vllm/config/scheduler.h:91-158` and is validated at `src/vllm/config/scheduler.cpp:49-92`. +- The running loop caps remaining work by the threshold, token budget, and model length at `src/vllm/v1/core/sched/scheduler.cpp:280-404`. +- The waiting loop handles cached and uncached work, the chunking enable gate, budget clipping, allocation, and admission at `src/vllm/v1/core/sched/scheduler.cpp:431-534`. +- Invariants are checked at `src/vllm/v1/core/sched/scheduler.cpp:543-550`; partial-prefill state is refreshed at `src/vllm/v1/core/sched/scheduler.cpp:945-982`. +- Existing CPU coverage lives at `tests/vllm/v1/test_scheduler.cpp:205-227,315-336,713-735,1329-1369`. + +The basic slice is implemented and CPU-testable. The local suite does not directly pin `enable_chunked_prefill=false` ordering, the three-request `long_prefill_token_threshold=400` distribution, or that distribution with prefix caching toggled. The row remains `SPIKE`, not `DONE`, until those pinned cases are ported and the existing implementation is re-gated. + +## Port map + +| Upstream | Local | Disposition | +|---|---|---| +| `config/scheduler.py:58-91,126-136,261-310` | `include/vllm/config/scheduler.h`; `src/vllm/config/scheduler.cpp` | Basic fields and validation exist; multi-partial-prefill configuration is adjacent deferred scope. | +| `scheduler.py:427-561` running loop | `src/vllm/v1/core/sched/scheduler.cpp:280-404` | Basic token/threshold/model-length clipping exists. | +| `scheduler.py:640-930` waiting loop | `src/vllm/v1/core/sched/scheduler.cpp:431-534` | Basic cached-prefix accounting, disable gate, clipping, allocation, and admission exist. | +| `scheduler.py:1845-1900` output/discard | `src/vllm/v1/core/sched/scheduler.cpp:945-982`; runner discard tracked by `ENG-ASYNC-SCHED` | Basic state/output behavior exists; async runner ownership stays separate. | + +## Tests to port + +- `tests/v1/core/test_scheduler.py:271-333` `test_schedule_partial_requests`: multiple partial requests share one budget and incomplete rows produce no sampled token. +- `tests/v1/core/test_scheduler.py:589-661` `test_schedule_concurrent_partial_requests`, both prefix-cache modes: three 800-token prompts distribute as 400/400/224, then 400/400/224, then 1/1/352. +- `tests/v1/core/test_scheduler.py:988-1020` `test_schedule_order`, both `enable_chunked_prefill` values: enabled chunking fills the budget while disabled mode preserves waiting order and stops at an over-budget head. +- `tests/v1/core/test_scheduler.py:1433-1517` `test_no_spec_tokens_scheduled_for_prefill_chunks`: already ported at `tests/vllm/v1/test_scheduler.cpp:1329-1369`; retain as regression coverage. + +Adjacent cases stay deferred under their owning rows: multimodal input chunking (`:538-585`), DP throttling (`:335-537`), and Mamba/fine-grained prefix stops. They must not inflate this row's support claim. + +## Gates + +```sh +cmake -S . -B build-cpu -DVLLM_CPP_CUDA=OFF -DVLLM_CPP_SERVER=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Werror +cmake --build build-cpu --target test_scheduler test_scheduler_config -j2 +ctest --test-dir build-cpu --output-on-failure -R '^(test_scheduler|test_scheduler_config)$' +``` + +The ported cases must fail if the token-budget clip or threshold cap is removed, or the chunking-disabled break is bypassed. Prefix caching on and off must both pass. + +Because this policy changes batch composition, the closure gate on an authorized GPU host must compare an identical long-prompt concurrency sweep against pinned vLLM with chunking on/off, correctness first, then total/output throughput, request rate, TTFT, TPOT, ITL, and peak memory for 2-3 uncontended repetitions. The exact model, prompt/output lengths, concurrency grid, seed, engine/oracle commands, build, and evidence destination are recipe-definition `PENDING` until CP1 fixes and passes the semantic workload. This records-only spike is `NOT APPLICABLE` to benchmarking; the current executable next reproduction command is the CPU gate above. + +## Dependencies + +- `ENG-SCHED-CORE`: unified running/waiting scheduling and output folding. +- `KV-PREFIX-CACHE`: cached-token lookup before remaining-work calculation. +- `ENG-ASYNC-SCHED`: incomplete-prefill discard behavior in the async runner. +- `ENG-PARTIAL-PREFILL`: future configurable concurrent-partial limits, outside this row. +- `KV-MAMBA-ALIGN` and `KV-PREFIX-MATCH-UNIT`: hybrid/fine-grained stops, outside this row. + +The spike and implementation tests need only pinned source plus a CPU toolchain and no model data. The binding performance gate needs an authorized GPU host and the project exclusion protocol. + +## Work breakdown + +- `CP0` (this PR): accept this spike and reconcile records without changing runtime support claims. +- `CP1` (CPU-only): port the three missing upstream behavioral groups, prove RED mutations, and re-gate existing scheduler/config targets. Own only `tests/vllm/v1/test_scheduler.cpp` unless a defect is reproduced. +- `CP2` (CPU-only if needed): fix only a reproduced basic budget/threshold/disable defect, preserving adjacent row ownership. +- `CP3` (GPU-required): same-workload vLLM correctness and every-axis performance gate; only this leaf may close the speed-sensitive lifecycle. + +## Risks and decisions + +- Keep this row basic; combining multimodal, Mamba alignment, DP throttling, and configurable partial-prefill concurrency would hide independently gateable gaps. +- Local file headers cite older `e24d1b24`; CP1 ports pin-era `555967922` tests before changing implementation claims. +- Unit tests prove allocation semantics, not runtime latency or memory; CP3 remains mandatory for closure. +- Disabling chunking is ordering-sensitive; assert token counts and waiting/running queue state. diff --git a/.agents/state.md b/.agents/state.md index 173f48b6..93113445 100644 --- a/.agents/state.md +++ b/.agents/state.md @@ -34505,3 +34505,28 @@ The required Slack selection notification was attempted through the bundled secret-safe sender to the only conventional target available, `#general`, but Slack returned `channel_not_found`. No channel ID/name is configured and no credential was inspected or exposed. + +## 2026-08-01 - `ENG-CHUNKED-PREFILL` contract spike + +`CLAIM-ENG-CHUNKED-PREFILL-SPIKE`, isolated worktree +`/home/mudler/_git/vllm.cpp-wt-eng-chunked-prefill`, branch +`codex/eng-chunked-prefill-spike`, base `upstream/main` `1448e981`. CPU-only, +records/spec scope; no GPU, model, download, source, test, or benchmark change. + +Accepted `.agents/specs/chunked-prefill.md` at pin `555967922`. The audit +confirms the basic slice already exists: config validation, token-budget and +long-prefill clipping in both running/waiting loops, multi-step partial state, +no partial output, and speculative-token exclusion. It also makes the evidence +gap precise: port `test_schedule_partial_requests`, `test_schedule_order` with +chunking on/off, and `test_schedule_concurrent_partial_requests` with prefix caching on/off, including +the 400/400/224 distribution, before advancing the row. Multimodal boundaries, +Mamba alignment/fine-grained prefix stops, DP throttling, pooling policy, and +configurable partial-prefill limits remain separate rows/scopes. The row moves +`ANCHOR-BACKFILL` -> `SPIKE`; no support claim advances. + +The required selection Slack notification used the bundled secret-safe sender +and failed with `channel_not_found` for `#general`; no Slack channel was +configured and no credential was read. Next CPU command is the focused +`test_scheduler`/`test_scheduler_config` recipe in the spike. The exact GPU +workload/commands are recipe-definition PENDING until CP1 fixes the semantic +workload; binding speed closure remains GPU-required. diff --git a/docs/BENCHMARKS.md b/docs/BENCHMARKS.md index fc665a30..df7aa8dc 100644 --- a/docs/BENCHMARKS.md +++ b/docs/BENCHMARKS.md @@ -1,5 +1,21 @@ # Benchmarks +## Chunked-prefill contract spike (2026-08-01) - NOT APPLICABLE + +`ENG-CHUNKED-PREFILL` / `CLAIM-ENG-CHUNKED-PREFILL-SPIKE` is a records-only +checkpoint (`benchmark_binding=false`). It accepts the missing pinned-source +contract for the already-shipped basic token-budget chunking slice and changes +no source, test, build rule, runtime behavior, workload, or performance number. + +The follow-on performance gate remains `PENDING`, including recipe definition: +the exact model, prompt/output lengths, concurrency grid, seed, engine/oracle +commands, build, and evidence destination must be fixed after the three missing +CPU semantic groups pass. The current next reproduction command is the CPU CP1 +gate in [the accepted spike](../.agents/specs/chunked-prefill.md): configure +`build-cpu`, build `test_scheduler` and `test_scheduler_config`, then run the +focused CTest regex. Only then may a GPU checkpoint define and run the matched +chunking on/off vLLM sweep for all throughput, latency, and memory axes. + ## Laguna-S-2.1-NVFP4 decode — routed-MoE CastF32 fold (`VT_LAGUNA_TAIL_FUSED`), byte-exact, −39 nodes/step, wall-neutral (2026-08-03, `CLAIM-LAGUNA-TAIL-FUSED`) Continuation of the byte-exact node-count campaign (glue/preamble/addnorm/onecast) on the GB10 NVFP4 decode graph (`~/laguna-xs-nvfp4`, ids `2,785,9626,377,15360,395`, base env `VT_LAGUNA_RESIDENT_DECODE=1 VT_LAGUNA_MARLIN_MOE=1 VT_LAGUNA_DECODE_GRAPH=1`, origin/main `65f3cdc1`). A fresh `cuda_gpu_kern_sum --cuda-graph-trace=node` 20↔70 diff of the baseline ranked the remaining SMALL decode kernels; the biggest tail items are already folded (`RmsNormRow`+`AddAdd2RmsNorm` = the add_rms_norm forms, `FusedQkNormRope` = the preamble) or unfoldable (`SigmoidTopK`/router GEMV = cuBLAS-adjacent, `DecodeAttnGqaSplitG`/`DecodeAttnCombine` = attention compute, `MoeAlign`/`SiluAndMul`/`MoeCombine` = ported-Marlin pipeline). The one clean byte-exact node reduction left was the MoE-output `CastF32`. diff --git a/docs/STATUS.md b/docs/STATUS.md index b8bfbbca..c86e0e6c 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -42,6 +42,7 @@ token-for-token correctness against the pinned oracle. | Capability | State | Notes | |---|---|---| +| Basic token-budget chunked prefill (`ENG-CHUNKED-PREFILL`) | `SPIKE`; shipped baseline under evidence backfill | Accepted spike now grounds the existing budget/threshold clipping, multi-step partial-prefill state, and disabled-chunking gate at pin `555967922`. Three missing pin-era CPU groups cover shared-budget partial requests, disabled ordering, and the 400/400/224 concurrent distribution with prefix caching on/off. No new support claim; GPU recipe definition and every-axis closure remain pending after the CPU leaf. | | Qwen3.6-27B (NVFP4) text generation | Correctness-complete, at/above vLLM speed | Token-exact greedy on GB10; beats vLLM 0.25.0 total throughput at every concurrency (1.007-1.045x), effective parity 115/124 axes | | Qwen3.6-35B-A3B (NVFP4, GDN MoE) | Correctness-complete, decode at-parity, prefill speed-pending | Token-exact greedy; decode at or beyond vLLM, remaining gap is prefill TTFT | | Qwen3 / Qwen2 dense (BF16) | Correctness-complete, speed-pending | Near-tie-robust token-exact vs vLLM (Qwen3-0.6B, Qwen3-4B); c1 effective parity, c8 decode residual. **D1 (2026-07-31, `CLAIM-D1-BF16-MERGED-QKV`): the bf16 merged-QKV path (`Qwen3QkvMergeEnabled`/`VT_QWEN3_QKV_MERGE`) is now default-ON** — one `vt::MatmulBT` over the merged `[qdim+2kdim,H]` owner + a contiguous `vt::QkvSplit` (OLMo-2 exemplar), replacing three per-shard GEMMs. Bit-exact GEMM math (A/B unit `test_ops_qkv_merge` byte-identical, RED-first); the wider-N cuBLASLt K-reduction flips the 0.6B genuine bf16 near-tie so the SACRED 0.6B golden was regenerated (all tokens within the near-tie band, max 0.125 nats), while Qwen3-4B is byte-neutral (0 diffs, stays STRICT). Re-gated 0.6B 16/16 + 4B 16/16; consistency/launch-count fold (measured NEUTRAL on 4B decode), no new throughput owed |