Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/issue-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -677,5 +677,6 @@ rather than merged. `scripts/check-agent-record.py` gates both.
| [#1791](https://github.com/mudler/vllm.cpp/issues/1791) | `SPEC-DSPARK` | **`scripts/dspark-paired-e2e.sh`'s `settle()` can never break early, so a wait for the GPU to drain always spends its full 360 s however fast the box actually drains.** The same idiom as [#1734](https://github.com/mudler/vllm.cpp/issues/1734), found by sweeping `scripts/` for it: `grep -c .` with an `\|\| echo 0` fallback makes `$n` the two-line string `0\n0`, so `[ "$n" -eq 0 ] && break` answers `integer expression expected` and returns 2 instead of deciding. The BUSY half of the guard works -- a positive count exits 0 and the fallback does not fire -- so only the FREE half is dead, and the failure is in the safe direction, which is why it was paid in silence. This is the FIFTH diagnosis of the idiom in this tree: `scripts/cpu-x86-llamacpp-floor.sh` already carries the removal and the reason in a comment, and a comment in one file is not reachable from another. FIXED IN FLOW with #1734: `\|\| true` keeps grep's own `0` and swallows only its status. The recurrence gate is `TheIdiomIsGoneFromEveryShellScript` in `tests/scripts/test_ltx25_ab_memwatch.py`, which sweeps every `scripts/*.sh` for a counting `grep`/`pgrep` paired with an `\|\| echo` fallback outside a comment; run against `27d8bfa70` it names all three live instances, this one included. It is a TRIPWIRE and says so: it reads text, and a `wc -l` with the same fallback walks past it | bug |
| [#1796](https://github.com/mudler/vllm.cpp/issues/1796) | `SPEC-DFLASH2` | **[#1456](https://github.com/mudler/vllm.cpp/issues/1456)'s conclusion is retracted AT THE ARTIFACT, off-GPU, and the DFlash2 speed ratio's denominator inherits the retraction: `0.8016987337853048` MAY BE FLATTERING US.** #1456 measured a real source build at `CUDA_ARCHS=12.0` emitting `sm_80` for `_vllm_fa2_C` and `sm_75` for `_vllm_fa3_C`, and concluded the GB10 oracle has no `FLASH_ATTN` denominator. **The arch measurement stands; the conclusion does not, and no lease was needed to show it.** Both staged oracle wheels were opened with `zipfile` and walked as fatbinaries on the CPU dev box: `0.1.dev1+g66e5414c6` (this row's oracle, `/mnt/nas_share/rc/oracle-dflash2/`) and `0.1.dev1+g555967922` (the parity pin, `/mnt/nas_share/rc/oracle-vllm/`) each carry 76 FA2 fatbinaries and 192 FA3 fatbinaries, and **every one holds a PTX image beside its SASS image** -- arch 80 for FA2, arch 75 for FA3. The first FA2 PTX payload is zstd and decompresses to `.version 9.0` / `.target sm_80` for `flash_fwd_hdim128_bf16_causal_sm80`. That is the `+PTX` half of `FA2_ARCHS "8.0+PTX"` and it is the mechanism by which the module CAN reach sm_121 -- the artifact establishes a necessary condition, forward-JITtable code being shipped, and that the JIT then ran is an inference from that plus a run selecting `FLASH_ATTN` and generating; `cudaErrorUnsupportedPtxVersion` is the OPPOSITE failure, PTX ISA newer than the driver, which `.version 9.0` under driver 580.173.02 is not. vLLM says it directly too: `FlashAttentionBackend.supports_compute_capability` returns `capability >= DeviceCapability(8, 0)` (`vllm/v1/attention/backends/flash_attn.py:251-252` in the staged wheel). **THE DOWNSTREAM IS THE THING TO CHASE.** #1456's body records that the DFlash2 speed gate's denominator "will be vLLM pinned to `TRITON_ATTN`, by developer decision on 2026-08-20", explicitly because of that conclusion. AGENTS.md requires vLLM's PRODUCTION configuration as the denominator, and on this box vLLM's own auto-selection picks `FLASH_ATTN`: the 0.8017 gate run's log carries BOTH paths in one process, the forced branch taking `TRITON_ATTN` for the 27B target (`cuda.py:426`) and the auto branch taking `FLASH_ATTN` out of four valid backends (`cuda.py:486`), in `/mnt/nas_share/rc/dflash2-1673/out-n1673b/m-gate.log`. **So if `TRITON_ATTN` is the slower backend -- which vLLM's own priority ordering IMPLIES rather than states, and which nothing here measures -- then 16.279 tok/s is too LOW and the ratio is too HIGH. An error in our own favour is the one nobody chases, so it is recorded with its sign.** The ratio is NOT withdrawn and no denominator is substituted, because a wave must not replace a denominator the developer declared. **The five FA layers of [#1685](https://github.com/mudler/vllm.cpp/issues/1685) fall out of the same read**: `vllm/v1/worker/gpu/spec_decode/dflash/utils.py:31-46` sets the draft's `backend=speculative_config.attention_backend` UNCONDITIONALLY, so a harness that sets only the engine backend leaves the draft at `None` and the draft re-runs auto-selection; the siblings `dspark/utils.py:24-28` and `gemma4/speculator.py:66-89` both carry the target's backend through, and dspark's comment names this hazard by name. NOT reconciled in flow, and the reason is precise: what remains is ONE lease running vLLM against itself on this workload with `attention_backend=FLASH_ATTN` against `TRITON_ATTN`, each read back off the built engine, and **no GPU lease is authorised for this session**, so it is PENDING. Recommended collapse, recommended and not taken: #1456, [#1679](https://github.com/mudler/vllm.cpp/issues/1679) and #1685 observe ONE mechanism on two wheels, and #1685 is the one attached to a live number and should survive. Owed under `## Owed` O33 of [the DFlash2 spec](specs/dflash2-spec-decode.md), with caveat 5 beside the ratio in the same file | verification |
| [#1794](https://github.com/mudler/vllm.cpp/issues/1794) | `LTX25-DIT-ATTN-ARM-PARSE` | **#1551 renamed the values of `VLLM_LTX2_DIT_FLASH_ATTN` and the two #1549-era LTX-2.5 A/B harnesses kept exporting the old ones, so three committed arms name a rung they do not select -- and one of the three says nothing.** At [#1549](https://github.com/mudler/vllm.cpp/issues/1549) the knob was BINARY: `=0` selected `vt::Attention` and every other value, unset included, selected `vt::AttentionDenseFlash`. [#1551](https://github.com/mudler/vllm.cpp/issues/1551) made it THREE-WAY, moved the unset default up a rung to `vt::AttentionDenseFa2` and gave the flash rung the exact spelling `flash`; it touched neither harness. Read at `27d8bfa70`: `scripts/ltx25-dit-attn-flash-pixel-ab.sh` exports `=1` for both its `flash` and its `flash-ctl` arms, and `scripts/ltx25-dit-attn-flash-ab.sh` leaves the variable UNSET for its `flash` arm -- all three of which selected `AttentionDenseFlash` before #1551 and select `AttentionDenseFa2` after it. `scripts/ltx25-dit-attn-fa2-hd128-ab.sh` is CORRECT and is the contrast that makes the other two legible: written after the rename, it exports `flash` / `""` / `0` and carries `assert_arm_op`. THE ASYMMETRY IS THE ISSUE: the pixel harness's `arm_report` counts `op=18` and `op=21` in the arm's own log and exits 46 on `ROUTING_BAD`, so its two `=1` arms abort -- after the render, an hour of a four-hour lease spent to learn a literal went stale -- while `ltx25-dit-attn-flash-ab.sh` has NO such assertion at all: its phase `[F]` PRINTS the op-provider selections and asserts nothing, so its `flash` arm renders FA-2, is reduced under the label `flash`, and the ratio it publishes is FA-2 against naive while the file's own header says flash against naive. THE RECORDED NUMBERS ARE NOT INVALIDATED: `.agents/specs/ltx25-dit-attn-flash.md` section 10 records `knob=1` announcing `op=21` and `ROUTING_OK=flash`, so the binary that ran it is one where `=1` still selected flash; what is wrong is the file as it stands against the binary `main` builds today. WHY A GATE AND NOT A REVIEWER: both harnesses were TRUE when written and both became false in a commit that touched neither file, because nothing connected the literal in a shell script to the literal in the C++ dispatch. FIXED IN FLOW with the red-first case that would have caught it -- `tests/scripts/test_ltx2_dit_attn_knob_arms.py` reads the accepted set out of `ltx2_device.cpp`'s own `std::strcmp(arm, "...")` calls rather than restating it, reads each harness's arm invocations, and asserts BOTH that every value is one the dispatch parses AND that every arm selects the rung its LABEL claims; the second half is the one that matters, because `unset` is a perfectly valid value and was still the wrong arm for a whole row. Registered on the preflight and CI record lanes, and it asserts both registrations itself. Found while fixing [#1751](https://github.com/mudler/vllm.cpp/issues/1751), which is the same defect one level down. Spec [`ltx25-dit-attn-arm-parse.md`](specs/ltx25-dit-attn-arm-parse.md) | bug |
| [#1824](https://github.com/mudler/vllm.cpp/issues/1824) | `SPEC-DFLASH2` | **A configured speculator forces synchronous scheduling; upstream keeps async ON for the Eagle-type family (dflash included).** `model_loader.cpp` resolves `async_scheduling_enabled_` to false whenever `resolved_spec_config_` is present, a deferral recorded at SPEC-MTP I5d ([mtp-spec-decode.md](specs/mtp-spec-decode.md) §2.8's not-ported list). Upstream's polarity at the pin (`vllm/config/vllm.py:1064-1112`) disables async only for a method OUTSIDE `EagleModelTypes ∪ NgramGPUTypes ∪ {"dspark"}` — and `"dflash"` (which DFlash2 rides) and every MTP type are Eagle-type. At c1 spec decode (~360 steps / 2048 tokens) every host-side scheduling cost is serialized into each step, the largest named host-side divergence in the [#1574](https://github.com/mudler/vllm.cpp/issues/1574) gap. W7 under `SPEC-DFLASH2` ports the draft-in-output flow (AsyncScheduler `-1` placeholders, worker-side fill, `update_draft_token_ids_in_output`, the `async_tokens_to_discard` rollback guard) and flips the enable to upstream's method predicate; the GPU TPOT A/B stays owed to the operator. Spec [`spec-decode-async-scheduling.md`](specs/spec-decode-async-scheduling.md) | feature |
| [#1754](https://github.com/mudler/vllm.cpp/issues/1754) | `GATE-CI-SITE-HUGO-LANE` | **`agent-record` is RED on `main` and on every pull request cut from it: `test_rendered_benchmark_index_links_resolve_to_emitted_pages` shells out to `hugo` and no job in `ci.yml` installs it, so `subprocess.run` raises `FileNotFoundError` before any assertion runs and `unittest` reports an ERROR.** Introduced by [#1714](https://github.com/mudler/vllm.cpp/pull/1714) at `1db7e59cf`; the scheduled baseline at `deb53c6a3` was green on this job and `08c81a892` and every scheduled run after it is red. FIXED IN FLOW by installing the renderer on the lane -- the same `peaceiris/actions-hugo@v3` action, the same `extended: true`, and the same `0.146.3` pin the `gh-pages` job publishes on -- plus `hugo version` as the step's first line and `tests/scripts/test_ci_site_lane.py` holding the two pins equal and the setup step present and ordered before the render. A SKIP GUARD WAS REJECTED AS THE FIX and is deliberately not in this change: it retires the red by arranging for the assertion to run nowhere, which [PR #1726](https://github.com/mudler/vllm.cpp/pull/1726) demonstrates -- its `agent-record` is SUCCESS having rendered no site. The guard is still wanted for a developer box without Hugo and is separately owned by [#1722](https://github.com/mudler/vllm.cpp/issues/1722) / #1726, which edits a disjoint file, so the two compose. [#1764](https://github.com/mudler/vllm.cpp/issues/1764) names this red as one of its three and is not closed by this change | bug |
| [#1828](https://github.com/mudler/vllm.cpp/issues/1828) | `GATE-CI-SITE-HUGO-LANE` | **`tests/scripts/test_check_site.py` asserts a literal `10` rendered benchmark detail links, which is a stored count of `docs/benchmarks/*.md` inside another file, and #1754's lane fix is what ARMS it**: until Hugo was installed the case never reached that line in CI. Measured on `d60692c89` with Hugo 0.146.3+extended: 10 slugs, 10 table hrefs, no duplicated target and no unlinked slug, so the relationship is a bijection and the literal is derivable at read time -- with its own non-vacuity floor, since `sorted(x) == sorted(y)` is satisfied by two empty sets. NOT FIXED IN FLOW: deriving it changes what the case asserts rather than how it spells a number, which `AGENTS.md` routes through the normal row, spec and fresh-review path, and the file already has an open pull request against the same case. Listed under `## Owed` in [gate-ci-site-hugo-lane.md](specs/gate-ci-site-hugo-lane.md) | bug |
11 changes: 11 additions & 0 deletions .agents/specs/dflash2-spec-decode.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,17 @@ reviewer who mutates the guarantee rather than reading it.
- **W5 — the GGUF drafter arm**, with its lower bound. LANDED 2026-08-20.
- **W6 — the gates.** G2 and G3 on a leased GPU against the PR-head oracle,
then `## Outcome`.
- **W7 — async scheduling for the Eagle-type speculative family
([#1824](https://github.com/mudler/vllm.cpp/issues/1824)). LANDED
2026-08-23.** The engine forced synchronous scheduling under ANY speculator
(a SPEC-MTP I5d deferral); upstream keeps async ON for Eagle-type methods,
dflash included, and at c1 that difference serializes every host-side
scheduling cost into each of ~360 steps — the largest named host-side
divergence in the #1574 gap. W7 ports the draft-in-output flow and flips the
enable to upstream's method predicate. Own spec:
[spec-decode-async-scheduling.md](spec-decode-async-scheduling.md); the c1
TPOT A/B (async-ON vs `VT_ASYNC_SCHED=0`, same binary, #1574 workload) is
owed there as A1, operator-run under an `rc` lease.

**The gate head is reconciled to ONE head here and it is `66e5414c`, which is
NOT what G2's rule selects.** W6 wrote that vllm#52816 was "still OPEN on
Expand Down
10 changes: 10 additions & 0 deletions .agents/specs/mtp-spec-decode.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,16 @@ lookup, the async draft-in-output path
(`update_draft_token_ids_in_output`, `scheduler.py:1959`), and the
structured-output grammar validation of proposed drafts.

**2026-08-23 update:** the async draft-in-output path — and with it
`num_spec_tokens_to_schedule` / `num_invalid_spec_tokens` and the
AsyncScheduler's `-1` placeholder assignment — LANDED as `SPEC-DFLASH2` W7
([spec-decode-async-scheduling.md](spec-decode-async-scheduling.md),
[#1824](https://github.com/mudler/vllm.cpp/issues/1824)); the "configured
speculator forces sync scheduling" line this section justified is retired
for the Eagle-type family. The sync scheduler's first-decode-step padding
(`pad_spec_decode`), the dynamic-SD lookup, and the grammar `validate_tokens`
arm stay deferred.

## 3. GDN linear-state rollback — the mechanism (B5's hard problem, answered)

Linear-attention state is not a paged KV you can truncate. Upstream solves
Expand Down
Loading
Loading