From aed1424aadeac577638966d5d78e36f7c7491dfe Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sun, 16 Aug 2026 22:51:39 +0000 Subject: [PATCH 1/3] spec(GATE-ISSUE-INDEX-TABLE-SHAPE): the issue index is a table nothing measured (#1033) `check_table_shapes` in `scripts/check-agent-record.py` already counts unescaped pipes per table row with exactly the regex a malformed row needs. Its call site hands it the roadmap, coordination, every matrix and every live spec, and does not hand it `.agents/issue-index.md`. No other checker counts that file's cells, so the one record surface every change must write is the only markdown table in the record set with no shape gate. This spec commits before the implementation, because arming a gate on a new path is a semantic checker change: it needs a red-before, a green-after, and an argument for the append-only exception the row repair requires. It records the measurement that will be red (line 279 reads 9 pipes where the header reads 5), the three test cases, and the stop conditions that keep the repair to escaping and out of the row's meaning. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code] --- .agents/specs/gate-issue-index-table-shape.md | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 .agents/specs/gate-issue-index-table-shape.md diff --git a/.agents/specs/gate-issue-index-table-shape.md b/.agents/specs/gate-issue-index-table-shape.md new file mode 100644 index 000000000..c8aa840a1 --- /dev/null +++ b/.agents/specs/gate-issue-index-table-shape.md @@ -0,0 +1,184 @@ +# Spec — the issue index is a table nothing measured + +Issue: [#1033](https://github.com/mudler/vllm.cpp/issues/1033) +Row: `GATE-ISSUE-INDEX-TABLE-SHAPE` (unplaced record/gate defect; the index is a +record surface, not a matrix row) +State: `ACTIVE` + +## Scope + +`check_table_shapes` (`scripts/check-agent-record.py:1292`) counts the +unescaped pipes on every table line of every path it is handed and reports any +line whose count differs from the first line of that table: + +```python +pipes = len(re.findall(r"(? Date: Sun, 16 Aug 2026 22:57:40 +0000 Subject: [PATCH 2/3] fix(GATE-ISSUE-INDEX-TABLE-SHAPE): count the index's cells, and repair the row that proves nothing did (#1033) `check_table_shapes` already carried the right measurement -- unescaped pipes per table line, `re.findall(r"(?1 a clamped step can hand every request the same shorter prefix, produce a perfectly uniform batch at a query length no graph is admitted for, and run the verify eager. At k=1 the same truncation is all-or-nothing and the batch merely stops being uniform, so this is reachable in a NEW shape once depth is configurable. The cost is measured, not hypothetical: capturing the T=1+k verify moved the 35B cells 0.870x to 0.986x in `c5615cfe0`. **(b)** The graph slot ring is keyed on `S` ALONE (`qwen3_5.cpp:9276`, dense sibling `:9698`, with `S = B` on a spec step at `:9253`), and the predicate that reaches it is `uniform_decode = input.pure_decode \|\| (spec_graph && ...)`, so BOTH branches share one map and two uniform query lengths already collide on one key: at k=1, 8 requests pure-decode and 4 requests spec both give `S = 8`; at k=3, 2 requests spec gives `S = 8` too. `SizeSlot` invalidates on `fa_cols` and `aux_taps` (`:9280-9330`) and on nothing keyed to spec-versus-pure. This is PRE-EXISTING since SPEC-DSPARK W8 ([#442](https://github.com/mudler/vllm.cpp/issues/442)) made a uniform spec batch capturable at all, and MTP depth does NOT widen it, because `num_spec()` is one value per engine. A first revision of [`mtp-k-gt-1.md`](specs/mtp-k-gt-1.md) section 4.2a claimed the key does not collide at all; a fresh review disproved it and the claim is withdrawn there. (a) and (b) are one repair because a predicate widened to the step's ACTUAL query length is only unambiguous once the ring distinguishes those query lengths. Also owed: a measured before-and-after on the capture-set size and persistent logits memory, and a counter or log for the eager fallback so it can never again be invisible. NOT fixed in flow: widening the capture set is a persistent-memory decision that has to be measured on a GPU, which was held by another session for the whole flow, and which no CPU gate can observe at all. Found while porting MTP k>1 ([#81](https://github.com/mudler/vllm.cpp/issues/81) M1); listed under `## Owed` in [`mtp-k-gt-1.md`](specs/mtp-k-gt-1.md) | bug | | [#1027](https://github.com/mudler/vllm.cpp/issues/1027) | `SPEC-MTP-K-GT-1` | DUPLICATE of [#1022](https://github.com/mudler/vllm.cpp/issues/1022), and FIXED on `origin/main` by [#1025](https://github.com/mudler/vllm.cpp/pull/1025) before this row landed. Filed while merging `origin/main` into `SPEC-MTP-K-GT-1` ([#81](https://github.com/mudler/vllm.cpp/issues/81)): `.agents/issue-index.md` listed [#995](https://github.com/mudler/vllm.cpp/issues/995) TWICE on `origin/main` @ `45b022cdc`, because `332aed738` (#996) and `45b022cdc` (#997) each appended a row for the same issue without seeing the other and the path carries `merge=union`, so `check-agent-record` and `test_agent_record` were RED there and on every branch merging it. The filing claimed the file "cannot be made green by any edit to it" because `check-agent-record` refuses the duplicate while `check-issue-index-append-only` refuses the deletion that resolves it. **That premise was WRONG**, and the reason is worth keeping: `check-issue-index-append-only.py:47-56` diffs `merge-base(origin/main, HEAD)..HEAD`, not the file's own history, so the two checkers conflict only while the duplicate sits in the MERGE BASE. #1025 merged the two rows by key ON MAIN, which moved the merge base, and a branch that then takes main's version and appends removes nothing at all. Both checkers are green on one tree with neither weakened. The union driver still produces the WRONG result automatically here: `git merge-tree` against `origin/main` re-added the deleted row and yielded TWO `#995` rows again, which is why the keyed-record rule (take the complete target-branch version, re-apply the scoped edit) applies rather than the driver's output. Owed only a duplicate-close on GitHub, which this flow had no authority for; listed under `## Owed` in [`mtp-k-gt-1.md`](specs/mtp-k-gt-1.md) | bug | | [#857](https://github.com/mudler/vllm.cpp/issues/857) | `ORACLE-LLAMACPP-REPIN-STOCK` | The recorded llama.cpp pin `237ad9b96` names an object no remote carries: `git branch -r --contains 237ad9b96` is empty and it lives only on local branch `localai-paged` in the developer's checkout. `git describe --tags` returns `b9827-65-g237ad9b96`, so it is 65 of OUR OWN performance commits past upstream tag `b9827`, and the recorded `pin_label = b9892` came from `git rev-list --count`, which returns 9892. That label is not merely derived, it COLLIDES: stock reached tag `b9892` exactly 65 commits after the same base `b9827`, so upstream `b9892` also counts 9892 and resolves to `ee445f93d`, `git merge-base 237ad9b96 b9892` is `b9827`, and neither is an ancestor of the other. A reader checking out `b9892` to reproduce a number silently gets stock. That already happened here: `rpi5-a76-llamacpp-20260806.md` substituted stock `b9892` after finding the pin unobtainable while `cpu-x86-llamacpp-20260811.md` built the fork under the same label. The working tree at the pin also carried 27 uncommitted entries at +2279/-762, so the binaries came from a tree in no repository. `ORACLE-LLAMACPP-REPIN-STOCK` moves the record to stock `b10451` (`10bf611e5`) and drops `gateable` to `no` naming THIS issue, which still owes the build-and-run on dgx.casa that would make it `yes`. Spec [`oracle-llamacpp-repin-stock.md`](specs/oracle-llamacpp-repin-stock.md) | bug | -| [#1003](https://github.com/mudler/vllm.cpp/issues/1003) | `ORACLE-LLAMACPP-REPIN-STOCK` | Every recorded llama.cpp floor number was measured against the local-only fork `237ad9b96` and is owed a re-take against stock `b10451`. The contamination is NOT confined to CUDA, which is what makes it a CPU-oracle defect rather than a filing error: six of the 65 fork commits touch `ggml/src/ggml-cpu/`, and `git diff --numstat b9827 237ad9b96 -- ggml/src/ggml-cpu/` returns `ops.cpp` at +318/-13 and `ggml-cpu.c` at +2/-1, so 320 inserted lines across the two files and +305 net in `ops.cpp` alone, in `ssm_conv_f32`, `gated_delta_net_*`, `flash_attn_ext_f16*` and `scale`, and `570aadd7a` states in its own body that the fused GDN op and the discriminated SSM_CONV decode op are emitted DEFAULT-ON and implemented for the CUDA family "and the CPU reference ONLY". `git grep ssm_conv_update origin/master` and `git grep gated_delta_net_inplace origin/master` both return nothing, and the CPU floor arm built that fork with `GGML_CUDA=OFF` on a `qwen35` model whose CPU graph reaches exactly those ops. THIRTEEN measurements are enumerated with a re-take verdict each in the spec, and the enumeration is the output of a recorded three-stage sweep rather than a hand list, because successive fresh reviews each found a verdict a hand list had missed: the GB10 20-core floor (prefill 1.18x PASS, decode 0.97x, RSS 1.01x), the 2026-07-22 remeasure, the G4/G7 refresh, GDN-orientation, elementwise-GEMM, the threadpool context, Vulkan `BENCH-VK-LLAMA`, the x86 RSS 1.0022x, the Pi 5 arm, the Muse Glimmer and #391 arm, `KERNEL-GEMM-CPU-TILED`, and keep-f16's L7 "RSS gap CLOSED to 1.01x llama.cpp". **The sweep's OWN path set was the fourth miss.** It read `git ls-files docs .agents benchmarks`, so `README.md` at the repository root sat outside the instrument built to stop hand enumeration, and the front page carried the CPU comparison table, the "1.18x llama.cpp's prefill" headline and the "matches llama.cpp" 4.36 vs 4.35 Vulkan claim unmarked, that last one being the most fragile verdict in the whole set. The fix is not to add one path, which is the same hand list one level up: stage 0 is now `git ls-files` with NO path arguments, so a file added anywhere is in scope the day it is committed. 651 files become 4514, candidates 961 become 1008 over 117 files rather than 93, and stage-2 favourable 719 becomes 752, so scanning everything costs 47 lines of adjudication and no exclusion list. A FIFTH hole surfaced with it: `CMP` carried no token for the word this project uses in its own headline, so `README.md:310` "decode **matches llama.cpp Vulkan**" was invisible to both path sets. Adding `match(es|ed)` takes candidates to 1095 over 141 files and favourable to 842. **A SIXTH hole was different in kind: a token that was PRESENT and DEAD.** `CMP` read `[0-9]+(?:\.[0-9]+)? *[x×]\b`, and since U+00D7 is not a `\w` character the `\b` after it can only be satisfied by a FOLLOWING word character, so the `×` alternative fired on `3.9×decode` and on nothing else this tree writes: `1.18× llama.cpp`, `| 1.023× |` and `2× over llama.cpp` all MISSED. The stage-2 filter spells the same idea without the trailing `\b` and was live the whole time, so the two expressions disagreed and only the narrower one gated. Repairing it to `(?:x\b|×)` moves stage 1 from 1118 to 1225 candidates over 141 to 144 files at `85a9a7ae7`, a larger correction than the `match` token. The five earlier holes were all things ABSENT from a list, which a careful reader can find; a dead branch cannot be found by reading, because the instrument prints the same clean output whether the branch is unreachable or the tree is clean. The sweep therefore now SELF-TESTS against known-positive and known-negative strings before it scans, and that assertion is armed rather than decorative: run against the defective expression it replaces, it fails on exactly those three shapes. The twelfth measurement is the one that matters most, because it is the only place the contamination reaches shipped behaviour rather than a document: keep-f16's llama.cpp denominators (pp128 173.2, peak RSS 2.798 GiB) are quoted in `src/vllm/model_executor/model_loader/gguf_keep_quant.cpp:173-228` as the justification for `VT_GGUF_KEEP_F16` shipping DEFAULT ON, and restated beside a `CHECK` in `tests/vllm/test_gguf_keep_quant.cpp:478-494`. **That default is owed a DECISION, not only a re-wording, and an earlier pass of this row recorded the opposite.** It said the default stands because its acceptance is a same-binary ours-versus-ours A/B (3.885 to 2.832 GiB, tokens byte-identical) that no denominator move touches. That reads one row of a three-row table. The binding L7 A/B (`gguf-keep-quant-loader.md:587-590`) has three axes and TWO regress: prefill about 10% worse (224 to 204 t/s, TTFT 571 to 625 ms) and decode about 1.4% worse (TPOT 40.4 to 40.95 ms), bought for 1.05 GiB of peak RSS. The recorded reason the PREFILL loss is acceptable is stated at `:595` in the contaminated denominator's own terms: 204 t/s is "about 9% under the keep-f16-off default's 224 t/s but comfortably above the competitor floor", and that floor IS the fork's pp128 173.2. Since `b10451` is 624 commits past `b9827` and carries its own `fused_gdn`, the direction is NOT established, so if a re-taken stock pp128 lands above 204 t/s the "comfortably above" clause fails and this default's only recorded justification for its prefill regression is gone. The RSS leg would still stand alone and may well suffice, but it would then be a live call rather than a settled one. Re-taking row 12 therefore owes a keep-f16 verdict to `QUANT-GGUF-KEEPQ-LOADER`, and the repin row deliberately does NOT change the default, having measured nothing. The product comment additionally quoted "205 t/s = 1.16x AHEAD of pp128 176.6", and NO recorded run produces either operand: `git grep 176.6` returns only an unrelated MoE microbenchmark mean in MICROSECONDS, while the binding record says 204 against 173.2 = 1.18x. That pair is left unreconciled rather than guessed, because picking one would assert an attribution nobody measured, and #1003 owes one re-measured pair to replace both. FIVE llama.cpp revisions are in play, not two and not the four an earlier pass recorded. They are the fork `237ad9b96`, stock `b9892` on the Pi 5 arm, stock `704485942` at `b10362-5` on Muse Glimmer and #391 (which appeared nowhere in `docs/` or the spec before the sweep), stock `030ebb5` at `b10358` carrying one explicitly NON-BINDING datapoint, and **a Poolside FORK on branch `laguna` with NO commit SHA recorded anywhere in this tree** (`github.com/poolsideai/llama.cpp@laguna`, named at `laguna-s21-w4-2026-07-31.md:65`). That fifth one is measurement THIRTEEN, the Laguna-S-2.1 `27.8 tok/s` on the identical UD-Q4_K_XL GGUF, and the `15x` warm / `18x` cold gap plus the `18x` to `4.7x` and `18x` to `3.6x` W8/W9 claims all derive from it. It was hidden behind the dead `×` branch for five drafts. A branch name is a moving reference, not a revision, so unlike the other four it was never reproducible and cannot simply be re-run: re-taking it means CHOOSING a revision first (stock `b10451` if it now carries `laguna`, or a named Poolside commit) and recording it as a sixth entry. No verdict there is favourable to us, so the count of seven favourable verdicts is unchanged, but it is the target the whole Laguna speed campaign ranks its levers against. Direction: against `b9827` the fork can only be at or above stock, so our recorded deficits are upper bounds and our wins are lower bounds. Against `b10451` the direction is NOT established, because 624 stock commits landed after `b9827` and upstream now carries its own `fused_gdn`. That window is 624 rather than the 122 an earlier draft recorded: the developer's llama.cpp clone is SHALLOW, grafted at `687e77892`, so every distance and ancestry answer crossing the graft is truncated and looks correct. That graft also invalidated this row's own headline evidence. "The pin is on no remote" rested on `git branch -r --contains 237ad9b96` returning empty, and a control disproves the instrument rather than merely doubting it: `git branch -r --contains b9827`, for an upstream release tag that is beyond argument an ancestor of `origin/master`, lists 70 remote branches today and omits `origin/master` (that total reads a clone outside our control and was 68 when first written; the OMISSION is the load-bearing half and reproduces exactly). The finding survives on evidence a graft cannot corrupt: `gh api repos/ggml-org/llama.cpp/commits/237ad9b96` and the same call against `mudler/llama.cpp` both return HTTP 422 "No commit found for SHA", with `gh api repos/ggml-org/llama.cpp/commits/10bf611e5` resolving on the identical call shape as the positive control, and `gh api repos/ggml-org/llama.cpp/git/ref/tags/b10451` binding the new label to the new commit ON the remote, which is the check the old `pin_label = b9892` would have failed. SEVEN recorded verdicts can flip unfavourably, five of them on the public page and one of them holding up a shipped default, and the GB10 prefill 1.18x is NOT the most exposed: ordered by fragility they are the Vulkan `BENCH-VK-LLAMA` decode 4.36 vs 4.35 `MET` (a 0.23% margin inside its own 0.69% 7-leg spread, whose source calls it "a narrow pass, not a comfortable one"), the Muse Glimmer in128 prefill 1.023x (a 2.3% margin inside our own arm's 4.5% leg spread over n=4), the GB10 peak RSS 1.01x PARITY and decode 0.97x tie (ties by declaration, so any denominator movement makes them gaps), keep-f16's "RSS gap CLOSED to 1.01x" with "prefill 1.18x AHEAD" (the same 2.798 GiB denominator, and the one verdict a user's bytes depend on), `KERNEL-GEMM-CPU-TILED` "at parity with ggml's stock kernel, ahead on 4 of 6 shapes" (overlapping bands, one shape already behind), the GB10 prefill 1.18x PASS, then the Pi 5 peak RSS 2.841 vs 3.747 GiB at 0.758x, whose denominator was already stock `b9892` so its only exposure is `b9892` to `b10451` drift. Re-take all seven, not prefill alone. Also owes the re-anchoring of the source citations. The spec records the three commands that count them rather than a bare number, because the number moved inside this pull request already. At `bf621287a` they return 112 files mentioning the SHA, 69 attributing a path or a tree to it in the `@ ` form, and 52 carrying a `path.ext:LINE` anchor within three lines. The first is now 113 because `README.md` finally names the fork its front-page numbers were measured against. No reviewer can fetch that object. Listed under `## Owed` in [`oracle-llamacpp-repin-stock.md`](specs/oracle-llamacpp-repin-stock.md) | perf | +| [#1003](https://github.com/mudler/vllm.cpp/issues/1003) | `ORACLE-LLAMACPP-REPIN-STOCK` | Every recorded llama.cpp floor number was measured against the local-only fork `237ad9b96` and is owed a re-take against stock `b10451`. The contamination is NOT confined to CUDA, which is what makes it a CPU-oracle defect rather than a filing error: six of the 65 fork commits touch `ggml/src/ggml-cpu/`, and `git diff --numstat b9827 237ad9b96 -- ggml/src/ggml-cpu/` returns `ops.cpp` at +318/-13 and `ggml-cpu.c` at +2/-1, so 320 inserted lines across the two files and +305 net in `ops.cpp` alone, in `ssm_conv_f32`, `gated_delta_net_*`, `flash_attn_ext_f16*` and `scale`, and `570aadd7a` states in its own body that the fused GDN op and the discriminated SSM_CONV decode op are emitted DEFAULT-ON and implemented for the CUDA family "and the CPU reference ONLY". `git grep ssm_conv_update origin/master` and `git grep gated_delta_net_inplace origin/master` both return nothing, and the CPU floor arm built that fork with `GGML_CUDA=OFF` on a `qwen35` model whose CPU graph reaches exactly those ops. THIRTEEN measurements are enumerated with a re-take verdict each in the spec, and the enumeration is the output of a recorded three-stage sweep rather than a hand list, because successive fresh reviews each found a verdict a hand list had missed: the GB10 20-core floor (prefill 1.18x PASS, decode 0.97x, RSS 1.01x), the 2026-07-22 remeasure, the G4/G7 refresh, GDN-orientation, elementwise-GEMM, the threadpool context, Vulkan `BENCH-VK-LLAMA`, the x86 RSS 1.0022x, the Pi 5 arm, the Muse Glimmer and #391 arm, `KERNEL-GEMM-CPU-TILED`, and keep-f16's L7 "RSS gap CLOSED to 1.01x llama.cpp". **The sweep's OWN path set was the fourth miss.** It read `git ls-files docs .agents benchmarks`, so `README.md` at the repository root sat outside the instrument built to stop hand enumeration, and the front page carried the CPU comparison table, the "1.18x llama.cpp's prefill" headline and the "matches llama.cpp" 4.36 vs 4.35 Vulkan claim unmarked, that last one being the most fragile verdict in the whole set. The fix is not to add one path, which is the same hand list one level up: stage 0 is now `git ls-files` with NO path arguments, so a file added anywhere is in scope the day it is committed. 651 files become 4514, candidates 961 become 1008 over 117 files rather than 93, and stage-2 favourable 719 becomes 752, so scanning everything costs 47 lines of adjudication and no exclusion list. A FIFTH hole surfaced with it: `CMP` carried no token for the word this project uses in its own headline, so `README.md:310` "decode **matches llama.cpp Vulkan**" was invisible to both path sets. Adding `match(es\|ed)` takes candidates to 1095 over 141 files and favourable to 842. **A SIXTH hole was different in kind: a token that was PRESENT and DEAD.** `CMP` read `[0-9]+(?:\.[0-9]+)? *[x×]\b`, and since U+00D7 is not a `\w` character the `\b` after it can only be satisfied by a FOLLOWING word character, so the `×` alternative fired on `3.9×decode` and on nothing else this tree writes: `1.18× llama.cpp`, `\| 1.023× \|` and `2× over llama.cpp` all MISSED. The stage-2 filter spells the same idea without the trailing `\b` and was live the whole time, so the two expressions disagreed and only the narrower one gated. Repairing it to `(?:x\b\|×)` moves stage 1 from 1118 to 1225 candidates over 141 to 144 files at `85a9a7ae7`, a larger correction than the `match` token. The five earlier holes were all things ABSENT from a list, which a careful reader can find; a dead branch cannot be found by reading, because the instrument prints the same clean output whether the branch is unreachable or the tree is clean. The sweep therefore now SELF-TESTS against known-positive and known-negative strings before it scans, and that assertion is armed rather than decorative: run against the defective expression it replaces, it fails on exactly those three shapes. The twelfth measurement is the one that matters most, because it is the only place the contamination reaches shipped behaviour rather than a document: keep-f16's llama.cpp denominators (pp128 173.2, peak RSS 2.798 GiB) are quoted in `src/vllm/model_executor/model_loader/gguf_keep_quant.cpp:173-228` as the justification for `VT_GGUF_KEEP_F16` shipping DEFAULT ON, and restated beside a `CHECK` in `tests/vllm/test_gguf_keep_quant.cpp:478-494`. **That default is owed a DECISION, not only a re-wording, and an earlier pass of this row recorded the opposite.** It said the default stands because its acceptance is a same-binary ours-versus-ours A/B (3.885 to 2.832 GiB, tokens byte-identical) that no denominator move touches. That reads one row of a three-row table. The binding L7 A/B (`gguf-keep-quant-loader.md:587-590`) has three axes and TWO regress: prefill about 10% worse (224 to 204 t/s, TTFT 571 to 625 ms) and decode about 1.4% worse (TPOT 40.4 to 40.95 ms), bought for 1.05 GiB of peak RSS. The recorded reason the PREFILL loss is acceptable is stated at `:595` in the contaminated denominator's own terms: 204 t/s is "about 9% under the keep-f16-off default's 224 t/s but comfortably above the competitor floor", and that floor IS the fork's pp128 173.2. Since `b10451` is 624 commits past `b9827` and carries its own `fused_gdn`, the direction is NOT established, so if a re-taken stock pp128 lands above 204 t/s the "comfortably above" clause fails and this default's only recorded justification for its prefill regression is gone. The RSS leg would still stand alone and may well suffice, but it would then be a live call rather than a settled one. Re-taking row 12 therefore owes a keep-f16 verdict to `QUANT-GGUF-KEEPQ-LOADER`, and the repin row deliberately does NOT change the default, having measured nothing. The product comment additionally quoted "205 t/s = 1.16x AHEAD of pp128 176.6", and NO recorded run produces either operand: `git grep 176.6` returns only an unrelated MoE microbenchmark mean in MICROSECONDS, while the binding record says 204 against 173.2 = 1.18x. That pair is left unreconciled rather than guessed, because picking one would assert an attribution nobody measured, and #1003 owes one re-measured pair to replace both. FIVE llama.cpp revisions are in play, not two and not the four an earlier pass recorded. They are the fork `237ad9b96`, stock `b9892` on the Pi 5 arm, stock `704485942` at `b10362-5` on Muse Glimmer and #391 (which appeared nowhere in `docs/` or the spec before the sweep), stock `030ebb5` at `b10358` carrying one explicitly NON-BINDING datapoint, and **a Poolside FORK on branch `laguna` with NO commit SHA recorded anywhere in this tree** (`github.com/poolsideai/llama.cpp@laguna`, named at `laguna-s21-w4-2026-07-31.md:65`). That fifth one is measurement THIRTEEN, the Laguna-S-2.1 `27.8 tok/s` on the identical UD-Q4_K_XL GGUF, and the `15x` warm / `18x` cold gap plus the `18x` to `4.7x` and `18x` to `3.6x` W8/W9 claims all derive from it. It was hidden behind the dead `×` branch for five drafts. A branch name is a moving reference, not a revision, so unlike the other four it was never reproducible and cannot simply be re-run: re-taking it means CHOOSING a revision first (stock `b10451` if it now carries `laguna`, or a named Poolside commit) and recording it as a sixth entry. No verdict there is favourable to us, so the count of seven favourable verdicts is unchanged, but it is the target the whole Laguna speed campaign ranks its levers against. Direction: against `b9827` the fork can only be at or above stock, so our recorded deficits are upper bounds and our wins are lower bounds. Against `b10451` the direction is NOT established, because 624 stock commits landed after `b9827` and upstream now carries its own `fused_gdn`. That window is 624 rather than the 122 an earlier draft recorded: the developer's llama.cpp clone is SHALLOW, grafted at `687e77892`, so every distance and ancestry answer crossing the graft is truncated and looks correct. That graft also invalidated this row's own headline evidence. "The pin is on no remote" rested on `git branch -r --contains 237ad9b96` returning empty, and a control disproves the instrument rather than merely doubting it: `git branch -r --contains b9827`, for an upstream release tag that is beyond argument an ancestor of `origin/master`, lists 70 remote branches today and omits `origin/master` (that total reads a clone outside our control and was 68 when first written; the OMISSION is the load-bearing half and reproduces exactly). The finding survives on evidence a graft cannot corrupt: `gh api repos/ggml-org/llama.cpp/commits/237ad9b96` and the same call against `mudler/llama.cpp` both return HTTP 422 "No commit found for SHA", with `gh api repos/ggml-org/llama.cpp/commits/10bf611e5` resolving on the identical call shape as the positive control, and `gh api repos/ggml-org/llama.cpp/git/ref/tags/b10451` binding the new label to the new commit ON the remote, which is the check the old `pin_label = b9892` would have failed. SEVEN recorded verdicts can flip unfavourably, five of them on the public page and one of them holding up a shipped default, and the GB10 prefill 1.18x is NOT the most exposed: ordered by fragility they are the Vulkan `BENCH-VK-LLAMA` decode 4.36 vs 4.35 `MET` (a 0.23% margin inside its own 0.69% 7-leg spread, whose source calls it "a narrow pass, not a comfortable one"), the Muse Glimmer in128 prefill 1.023x (a 2.3% margin inside our own arm's 4.5% leg spread over n=4), the GB10 peak RSS 1.01x PARITY and decode 0.97x tie (ties by declaration, so any denominator movement makes them gaps), keep-f16's "RSS gap CLOSED to 1.01x" with "prefill 1.18x AHEAD" (the same 2.798 GiB denominator, and the one verdict a user's bytes depend on), `KERNEL-GEMM-CPU-TILED` "at parity with ggml's stock kernel, ahead on 4 of 6 shapes" (overlapping bands, one shape already behind), the GB10 prefill 1.18x PASS, then the Pi 5 peak RSS 2.841 vs 3.747 GiB at 0.758x, whose denominator was already stock `b9892` so its only exposure is `b9892` to `b10451` drift. Re-take all seven, not prefill alone. Also owes the re-anchoring of the source citations. The spec records the three commands that count them rather than a bare number, because the number moved inside this pull request already. At `bf621287a` they return 112 files mentioning the SHA, 69 attributing a path or a tree to it in the `@ ` form, and 52 carrying a `path.ext:LINE` anchor within three lines. The first is now 113 because `README.md` finally names the fork its front-page numbers were measured against. No reviewer can fetch that object. Listed under `## Owed` in [`oracle-llamacpp-repin-stock.md`](specs/oracle-llamacpp-repin-stock.md) | perf | | [#1006](https://github.com/mudler/vllm.cpp/issues/1006) | `LTX25-DECODE-SPEED` | LTX-2.5 render speed has never been attributed on any axis: `docs/BENCHMARKS.md` carries one LTX line, under `## Open gaps`. The shipped video VAE decode is the **CPU reference arm** and production executes it — `src/vllm/multimodal/ltx2_video.cpp:3258 @ 332aed738` calls `Ltx2VideoDecodeStreaming`, reaching `Ltx2ConvVideoDecode` via `ltx2_video_vae_tiled.cpp:113,369 @ 332aed738` — while the file itself says `src/vllm/model_executor/models/ltx2_video_vae.cpp:46-49 @ 332aed738` "no memory or throughput number should be taken from it". One 448x256/25f decode is ~7.25 TFLOP over 42 convs (COMPUTED from the LTX-2.5 conv VAE config in the checkpoint header) against a measured wall of 2681.02 s — ~2.7 GFLOP/s. **That wall is ONE sample on a CONTENDED box** and carries its conditions: its own source records a full 405-target build and a 416-test `ctest -j 6` running in the same window ([`ltx25-tiled-decode.md`](specs/ltx25-tiled-decode.md):377-380) at `uptime` load average 30.2 (`:454`), with no idle-host same-binary repeat. It is also pre-[#1008](https://github.com/mudler/vllm.cpp/issues/1008): the f64 accumulation it measured landed out at `d1b0ea3a8`, and the f32 arm has never been timed. Owning row for the ranked levers in [`ltx25-decode-speed.md`](specs/ltx25-decode-speed.md) | feature | | [#1007](https://github.com/mudler/vllm.cpp/issues/1007) | — | The LTX-2.5 video VAE decode has **no device arm at all**: `vt::OpId::kLtx2` (`include/vllm/model_executor/models/ltx2_kernels.h @ 332aed738`, `src/vt/cuda/cuda_ltx2.cu @ 332aed738`) is the DiT device-forward glue — seven ops, no convolution — and nothing the decode reaches. Not an unwired path; the arm does not exist. Every oracle runs this decode GPU-resident and decides placement at build time: Lightricks `packages/ltx-pipelines/src/ltx_pipelines/utils/blocks.py:1139` + `packages/ltx-core/src/ltx_core/loader/single_gpu_model_builder.py:273 @ fd4ded7f2`, SGLang `python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/ltx_2/decoding_av.py:71 @ f63458b5b`, vLLM-Omni `vllm_omni/diffusion/models/interface.py:92 @ a4ea67a21` ("VAE(s) (always on GPU)"), diffusers `src/diffusers/models/autoencoders/ltx2_diffusion_decoder.py:208-209 @ c6da9936e` ("No CPU path", which is scoped to ONE of that file's two processors, `LTX2VideoVaeNeighborhoodNattenProcessor` at `:203`, in the DIFFUSION decoder this port refuses by name; the sibling `LTX2VideoVaeNeighborhoodAttnProcessor` at `:153` is "Portable ... Runs anywhere the flex attention path runs", so this citation narrows to NATTEN and the other three carry the claim) — cited at the revision [`oracles/diffusers.md`](oracles/diffusers.md) PINS, not at the SHA the local checkout sits on. Lever 1, ranked first on magnitude and last on cost. Listed under `## Owed` in [`ltx25-decode-speed.md`](specs/ltx25-decode-speed.md) | feature | | [#1008](https://github.com/mudler/vllm.cpp/issues/1008) | `LTX25-DECODE-DTYPE` | **FIXED, and this row records it as fixed rather than as owed.** The LTX-2.5 conv video VAE decode accumulated in **f64** at 8 sites (`src/vllm/model_executor/models/ltx2_video_vae.cpp:165,201,303,312,546,570,579,916 @ 332aed738`, with `static_cast` on **29 lines / 30 occurrences** — `:287` carries two, so the line count and the occurrence count are different numbers and both are stated) and stored **f32 NCDHW** (`Volume::At`, `:73-75 @ 332aed738`). No oracle accumulates in f64 anywhere on this path — Lightricks `model/video_vae/conv_video_decoder.py:282-284` and `model/common/normalization.py:32-40 @ fd4ded7f2`, diffusers `src/diffusers/models/autoencoders/autoencoder_kl_ltx2.py:50-59 @ c6da9936e`, SGLang `python/sglang/multimodal_gen/configs/pipeline_configs/ltx_2.py:189 @ f63458b5b` (bf16, deliberately overriding an fp32 base default) — and upstream's default-on fast path is `channels_last_3d` for weights AND activations (`memory_efficient_decode.py:617-627,655-656 @ fd4ded7f2`). No EXISTING gate could see it: the golden generator casts every upstream parameter to f32 (`scripts/gen-ltx2-vae-goldens.py:223`), so the oracle itself ran f32 (`ltx2_video_vae.cpp:41-44 @ 332aed738`). **Closed by `LTX25-DECODE-DTYPE` ([spec](specs/ltx25-decode-dtype.md)), merged as `d1b0ea3a8` via [PR #1036](https://github.com/mudler/vllm.cpp/pull/1036)**, which took the DTYPE half only: at that commit `double acc` is **0** and `static_cast` is **6 lines / 7 occurrences**, all annotated scalar-constant exceptions. It shipped its own instrument — a separable-reduction width case entering through the production `Ltx2VideoDecodeStreaming` (`tests/vllm/models/test_ltx2_vae.cpp`) — and it had to change its DESIGN to keep the numerics: naive serial f32 pushed `test_ltx2_tiling`'s non-causal untiled control to 5.00679e-06 against a 5e-06 tolerance, repaired by per-input-channel BLOCKED summation, which is what torch's f32 convolution does, with no tolerance widened. **Still owed there, not here:** NDHWC / `channels_last_3d` (that spec §5 — a shared helper `minimax_h3.h:756` hard-codes NCDHW across three models), bf16 storage, and a width gate for nine narrowed sites including `Linear3d`, which was widened back to `double` with 40/40 cases still passing. The speed magnitude of the change is **UNMEASURED**: `dgx.casa` was unreachable for that row's whole duration. Filed by [`ltx25-decode-speed.md`](specs/ltx25-decode-speed.md) as lever 2 and deliberately NOT listed under its `## Owed`, because a closed issue owed by a row that did not close it misattributes the work | feature | @@ -303,3 +303,4 @@ rather than merged. `scripts/check-agent-record.py` gates both. | [#1052](https://github.com/mudler/vllm.cpp/issues/1052) | — | `tests/vllm/v1/test_engine_core_proc.cpp:481` ("EngineCoreProc: immediate shutdown aborts in-flight requests") searches for the abort frame over a FIXED budget of 1000 dequeues while a `max_tokens=100000` request keeps the busy loop producing token deltas, so nothing bounds how many frames precede the abort and the budget is a bet on scheduling. MEASURED at `37e680cab`, same binary throughout, CPU-only Release on 20 cores: **2 failures in 3 `ctest -j4` runs** of the full 492-test suite (`CHECK( abort_seen ) is NOT correct!`), **0 in 25 solo runs** on an idle box at load 3.34, **0 in 25 solo runs against 20 spinning processes**, and 0 in two `ctest -R '^test_engine_core_proc$'` runs (`Passed 0.03 sec`). So CPU pressure alone does not reproduce it; it needs the `-j4` harness. The third `-j4` run failed `test_cpu_threadpool` INSTEAD, which is on the same load-dependent list, so the IDENTITY of the failing test rotates between runs of an unchanged binary and both pass alone with exit 0. NO ISSUE NAMED THIS TEST: PR [#1032](https://github.com/mudler/vllm.cpp/pull/1032)'s body attributed its flake to [#294](https://github.com/mudler/vllm.cpp/issues/294), which is a different defect in a different test (`test_async_llm` reusing an aborted request id), and a misattributed flake is worse than an untracked one because the next reader checks the citation, finds an open issue about something else, and stops looking. The assertion guards a real guarantee (an in-flight request gets a `kAbort` finish on immediate shutdown); the 1000-frame budget is the part that is a guess. Found repairing the fresh review of [#1039](https://github.com/mudler/vllm.cpp/issues/1039), on a branch that touches no file under `tests/vllm/v1/` or `src/vllm/v1/`. Listed under `## Owed` in [`ltx25-t2a-one-stage.md`](specs/ltx25-t2a-one-stage.md) | bug | | [#960](https://github.com/mudler/vllm.cpp/issues/960) | `MODEL-TEXT-nemotron-h-nemotron-hfor-causal-lm` | `vt::QuantFp8Static`'s ONLY CUDA registration lived at `src/vt/cuda/cuda_matmul_fp8_cutlass.cu:376` (@ `0e1bee42f`), and `CMakeLists.txt:1668` compiles that translation unit only when `VT_CUTLASS_FP8_ARCHS` is non-empty — yet the kernel body has ZERO cutlass tokens (`:353-370`): it is `out[i] = e4m3(x[i] * (1/input_scale))`, a grid-stride elementwise convert. So on every CUDA arch outside the cutlass-fp8 cell — sm_110/Thor is the measured one, and `cutlass-fp8: DISABLED for [110]` is that arch's DOCUMENTED NORMAL PROFILE, not a misconfiguration — `OpId::kQuantFp8Static` was not registered for `DeviceType::kCUDA` at all. Nothing refused first: the GEMM partner `kMatmulFp8CublasLt` IS registered unconditionally (`src/vt/cuda/cuda_matmul.cu:920`), so `MatmulFp8CutlassD`'s guard passed, and the missing quant then resolved through `src/vt/op_provider.cpp:501` to the portable CPU reference tier — eligible because `CudaBackend::UnifiedMemory()` is true — which dereferenced DEVICE pointers on the host and SIGSEGV'd one call later under a banner reading "correct but slow". Fixed by relocating the registration to a new unconditionally-compiled TU `src/vt/cuda/cuda_quant_fp8.cu`, which restores upstream's own partition (vLLM builds `static_scaled_fp8_quant` from the unconditional `VLLM_EXT_SRC` list and gates only its cutlass `scaled_mm` sources). This removes one live INSTANCE of [#844](https://github.com/mudler/vllm.cpp/issues/844) and does not address its class, which stays open. Unblocks the FP8 W8A8 arm on every non-cutlass CUDA arch — the base [#810](https://github.com/mudler/vllm.cpp/issues/810)/[#517](https://github.com/mudler/vllm.cpp/issues/517) A2-Q1 needs, where 46 FP8 mamba projections are 36.6% of decode bytes. Spec [`vt-fp8-quant-arch-gate.md`](specs/vt-fp8-quant-arch-gate.md) | bug | | [#989](https://github.com/mudler/vllm.cpp/issues/989) | `VT-FP8-QUANT-ARCH-GATE` | `scripts/check-pr-size.py`'s `classify_path` has no entry for `.agents/reachability.md` (added by `POLICY-NOTHING-LANDS-DEAD`, [#888](https://github.com/mudler/vllm.cpp/issues/888) @ `8f49ac3be`), and it FAILS CLOSED, so `pr-size` — a REQUIRED check — refuses every pull request that touches that guide, and `tests/scripts/test_check_pr_size.py` has been red on `main` ever since. Red SILENTLY: that suite is wired into no CI job and is not in `agent-preflight.sh`'s `SUITES`, so the only thing that ever loads it is `check-pr-size`'s own executable-evidence contract, which fires only when a PR edits a checker — the red is reachable exclusively by the next person who must touch that file, and presents to them as their own breakage (the [#584](https://github.com/mudler/vllm.cpp/issues/584)/[#965](https://github.com/mudler/vllm.cpp/issues/965) shape). Third instance of the class after [#856](https://github.com/mudler/vllm.cpp/issues/856) (`issue-index.md` + the style guides) and [#668](https://github.com/mudler/vllm.cpp/issues/668) (`.agents/oracles/*`), both fixed in flow by the row that tripped over them. FIXED IN FLOW while landing [#960](https://github.com/mudler/vllm.cpp/issues/960), which could not register its new checker's creation mutation without touching `check-pr-size.py` at all. NOT fixed: wiring that suite into CI, which is its own change and would red `main` until this landed | bug | +| [#1033](https://github.com/mudler/vllm.cpp/issues/1033) | `GATE-ISSUE-INDEX-TABLE-SHAPE` | `check_table_shapes` (`scripts/check-agent-record.py:1292`) never ran on `.agents/issue-index.md`, so a malformed row there was invisible to every gate. The function already counted unescaped pipes per table line with exactly the right regex; its call site (`:1527-1530`) passed `roadmap_v1.md`, `coordination.md`, `*MATRIX_PATHS` and `*spec_paths`, and simply did not pass this path. Nothing else in the tree counts this file's cells, which made the index the ONLY markdown table in the record set with no shape gate. It is also the one record surface every change must write, with rows long enough to hide a stray pipe in a code span. Arming it reds exactly one row on `origin/main` at `100026481`: a pipe histogram over the index's 289 table lines reads `{5: 288, 9: 1}`, and the outlier is line 279, the [#1003](https://github.com/mudler/vllm.cpp/issues/1003) `ORACLE-LLAMACPP-REPIN-STOCK` row that arrived with `283c7e492` ([#1051](https://github.com/mudler/vllm.cpp/pull/1051)), carrying four unescaped pipes inside code spans at columns 2705, 3106, 3115 and 3338. FIXED IN FLOW: the path is added, the four pipes are escaped, and three cases in `tests/scripts/test_agent_record.py` hold it — one capturing the paths `main()` really hands the gate, one running it on the shipped file, one mutating a copy so the instrument is proven to fire. Repairing the row EDITS an append-only file, so `check-issue-index-append-only.py` is red on the branch and the exception is argued in the commit body, as `ff264cb82` ([#1025](https://github.com/mudler/vllm.cpp/pull/1025)) argued the same one: appending a corrected copy would leave the broken row in place and add a duplicate key, so the file only becomes well-formed by editing it where it sits. TWO PREMISES OF THE REPORT MEASURED FALSE and are recorded in the spec rather than quietly dropped: the checker does NOT stop at the first finding (one `errors` list, three findings in one run, exit 1 once), and the four pipes are NOT in a `git diff` piped into `grep` — that span does not exist in the row. Spec [`gate-issue-index-table-shape.md`](specs/gate-issue-index-table-shape.md) | bug | diff --git a/.agents/specs/gate-issue-index-table-shape.md b/.agents/specs/gate-issue-index-table-shape.md index c8aa840a1..7ab75350f 100644 --- a/.agents/specs/gate-issue-index-table-shape.md +++ b/.agents/specs/gate-issue-index-table-shape.md @@ -35,6 +35,16 @@ correct; only its argument list was short. Changing it would widen a gate to make a red go green, which is the one move [`AGENTS.md`](../../CLAUDE.md) § *Changing the rules or a checker* forbids. +Also out of scope, and for a different reason: **making the checker report all +findings instead of stopping at the first**. #1033 attributes the two-day +concealment partly to that shape. It measured false. `main()` threads one +`errors` list through every check and prints all of it after the last one; the +`if not errors:` guard above the block covers only the missing-canonical-record +case, where continuing would raise on a file that is not there. Measured in +`## Evidence` rather than read off the source, because reading is how the wrong +premise got into the issue. There is nothing here to contain, so nothing is +changed. + ## Upstream anchors None. This is a repository checker, not a ported behavior. vLLM has no @@ -80,6 +90,13 @@ and 3338 — one in a regex alternation over the word `match`, two delimiting a quoted table cell, and one in a character-class alternation. The repair escapes each of the four and changes nothing else. +They are **not** the spans the dispatch named, which placed all four inside a +single `git diff … | grep …` code span. This row carries `git diff` spans and +`git grep` spans, and none of them is piped into anything. Same row, same count, +different spans. The four were located by re-running the checker's own regex +over the line rather than by searching for the quoted text, which is the only +reason the discrepancy is visible at all. + GFM replaces an escaped pipe with a literal pipe inside a table cell before inline parsing, so each code span then renders exactly as its author wrote it. Today they do not: the cell splits at each of the four instead. @@ -160,6 +177,27 @@ Captured verbatim with exit codes in the pull request body. No gate command whose status is needed is piped: `cmd | head` reports `head`'s status, which is how this tree has produced false green verdicts before. +### The checker does not stop at the first finding + +Measured, not read. A scratch index carrying three defects at once — a duplicate +key, a row that lost its trailing pipe, and the unrepaired `#1003` row — reports +all three in one run of `python3 scripts/check-agent-record.py`: + +``` +ERROR: .agents/issue-index.md: issue #168 listed twice. Under `merge=union` a duplicate is what two branches appending the same issue look like +ERROR: .agents/issue-index.md:279: table has 9 pipes; expected 5 +ERROR: .agents/issue-index.md:307: table has 3 pipes; expected 5 +RC=1 +``` + +The two synthetic rows were appended to a working copy and reverted with +`git checkout --` immediately after, and `check_issue_index` reported the +duplicate on the row it was given rather than the number of the real issue. + +So the concealment #1033 describes was real and its cause was not ordering: it +was solely that `check_table_shapes` never saw this path. One reporting run, +three findings, exit 1 once. + Accounted-for failures: - `issue-index append-only` in preflight — argued above. diff --git a/scripts/check-agent-record.py b/scripts/check-agent-record.py index 8062b775a..026d10591 100644 --- a/scripts/check-agent-record.py +++ b/scripts/check-agent-record.py @@ -1524,8 +1524,21 @@ def main() -> int: check_row_contracts(rows, by_id, errors) check_model_invariants(errors) spec_paths = [path for row in rows if row.state in READY_STATES for path in local_spec_paths(row)] + # ISSUE_INDEX is here for the same reason every other record table is: + # nothing else counts its cells. It was the ONE record surface every + # change must write and the only markdown table in the set with no shape + # gate, so a row that lost its trailing pipe, or carried an unescaped one + # inside a code span, mis-rendered on GitHub while every gate stayed + # green (#1033). The constant is reused rather than respelled so this + # gate and check_issue_index cannot drift onto different files. check_table_shapes( - [AGENTS / "roadmap_v1.md", AGENTS / "coordination.md", *MATRIX_PATHS, *spec_paths], + [ + AGENTS / "roadmap_v1.md", + AGENTS / "coordination.md", + ISSUE_INDEX, + *MATRIX_PATHS, + *spec_paths, + ], errors, ) check_spec_location(errors) diff --git a/tests/scripts/test_agent_record.py b/tests/scripts/test_agent_record.py index b0bccdd98..11385d176 100644 --- a/tests/scripts/test_agent_record.py +++ b/tests/scripts/test_agent_record.py @@ -4,6 +4,7 @@ from __future__ import annotations import importlib.util +import io import re import sys import tempfile @@ -1336,5 +1337,91 @@ def test_owed_issues_reads_specs_with_a_glob(self) -> None: self.assertIsInstance(agent_record.owed_issues(), set) +class IssueIndexTableShape(unittest.TestCase): + """The index is a TABLE, and until #1033 nothing counted its cells. + + `check_issue_index` reads the index by regex, row by row, and answers about + KEYS: is the number well-formed, does it link to itself, is it listed twice, + does it name an owner. None of that is the table's SHAPE. A row that lost + its trailing pipe still matches `ISSUE_ROW`, and a row carrying an unescaped + pipe inside a code span matches it too -- both mis-render on GitHub while + every gate in the tree stays green. + + `check_table_shapes` is the function that measures shape, it already carried + the right regex, and its call site simply did not name this path. + """ + + def paths_main_hands_the_shape_gate(self) -> list: + """The paths the REAL call site passes, captured from the real call. + + Read from the call rather than from the source text on purpose. A test + that greps `check-agent-record.py` for the string `issue-index` passes + on a line that is commented out, on a second call site that is never + reached, and on a constant that is defined and never used. + """ + + captured: list = [] + + def capture(paths, errors) -> None: + captured.extend(paths) + + with mock.patch.object(agent_record, "check_table_shapes", capture): + with mock.patch.object(sys, "stdout", io.StringIO()): + with mock.patch.object(sys, "stderr", io.StringIO()): + agent_record.main() + return captured + + def test_check_table_shapes_covers_the_issue_index(self) -> None: + paths = self.paths_main_hands_the_shape_gate() + # A run that handed the gate NOTHING would satisfy any assertNotIn and + # would satisfy an assertIn only by accident, so the count is asserted + # first. It is the same "how many things did you examine" question the + # index itself went two days without an answer to. + self.assertGreater( + len(paths), 1, "main() handed check_table_shapes no paths at all" + ) + # assertTrue rather than assertIn: the path list runs to ~180 entries + # and assertIn prints all of them, which buries the sentence that says + # what is wrong under the evidence that it is. + self.assertTrue( + agent_record.ISSUE_INDEX in paths, + f"{agent_record.ISSUE_INDEX.name} is not among the {len(paths)} " + "paths main() hands check_table_shapes, so nothing counts the " + "cells of the one record surface every change must write (#1033)", + ) + + def test_the_shipped_issue_index_is_a_well_formed_table(self) -> None: + # The case that would have fired in the offending PR's own preflight. + errors: list[str] = [] + agent_record.check_table_shapes([agent_record.ISSUE_INDEX], errors) + self.assertEqual(errors, []) + + def test_a_malformed_index_row_is_caught(self) -> None: + """The mutation. Without it the two cases above prove only that a list + contains a path and that a file happens to be clean today. + + The copy lives under ROOT because `check_table_shapes` reports through + `relative_to(ROOT)`; a path outside the tree would raise instead of + reporting, and an exception in the harness is not the gate firing. + """ + + text = agent_record.ISSUE_INDEX.read_text(encoding="utf-8") + rows = text.rstrip("\n").split("\n") + self.assertTrue(rows[-1].endswith("|"), "the last index row is not a row") + rows[-1] = rows[-1][:-1] + + with tempfile.TemporaryDirectory(dir=ROOT) as tmp: + mutated = Path(tmp) / "issue-index.md" + mutated.write_text("\n".join(rows) + "\n", encoding="utf-8") + # The mutation APPLIED: one byte shorter, one pipe fewer. + self.assertEqual( + len(mutated.read_text(encoding="utf-8")), len(text) - 1 + ) + errors: list[str] = [] + agent_record.check_table_shapes([mutated], errors) + + require(errors, rf"issue-index\.md:{len(rows)}: table has 4 pipes; expected 5") + + if __name__ == "__main__": unittest.main() From db15388754435ddccc9e09d0853970e32704e699 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Mon, 17 Aug 2026 01:44:21 +0000 Subject: [PATCH 3/3] fix(records): escape two regex pipes in the #1083 row, which this gate now sees `main` gained a THIRD malformed row while this branch was gating. Row `#1083` (`MODEL-MUSIC3`, arrived with #1089) carries two unescaped `|` inside regex code spans -- `($|[^*])` at column 213 and `(^|[^*])` at column 1385 -- so it splits into 8 parts where a well-formed 4-column row splits into 6. This PR is the gate that catches it, so it cannot land while the row is broken: `check-agent-record.py` reports `.agents/issue-index.md:308: table has 7 pipes; expected 5`. Repairing it here is the same in-scope repair `#1003` needed. This is exactly the recurrence the issue predicted. An unescaped `|` inside a code span is the NATURAL way to write a regex alternation or a shell pipeline in a Title cell -- it is not carelessness, it is the obvious way to write the thing, which is why the gate has to exist rather than the habit being fixed. Three separate rows have now needed it: `#995` (twice), `#1003`, `#1083`. Verified mechanically, not by eye: exactly two pipes escaped, the row is 2 bytes longer, and unescape-normalising the result reproduces the original byte-for-byte, so only the escaping changed. The pipe-part histogram over every row now reads {6: 292}, and `check-agent-record.py` exits 0. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code] --- .agents/issue-index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/issue-index.md b/.agents/issue-index.md index 684fe0aee..86eaa9dfe 100644 --- a/.agents/issue-index.md +++ b/.agents/issue-index.md @@ -305,6 +305,6 @@ rather than merged. `scripts/check-agent-record.py` gates both. | [#960](https://github.com/mudler/vllm.cpp/issues/960) | `MODEL-TEXT-nemotron-h-nemotron-hfor-causal-lm` | `vt::QuantFp8Static`'s ONLY CUDA registration lived at `src/vt/cuda/cuda_matmul_fp8_cutlass.cu:376` (@ `0e1bee42f`), and `CMakeLists.txt:1668` compiles that translation unit only when `VT_CUTLASS_FP8_ARCHS` is non-empty — yet the kernel body has ZERO cutlass tokens (`:353-370`): it is `out[i] = e4m3(x[i] * (1/input_scale))`, a grid-stride elementwise convert. So on every CUDA arch outside the cutlass-fp8 cell — sm_110/Thor is the measured one, and `cutlass-fp8: DISABLED for [110]` is that arch's DOCUMENTED NORMAL PROFILE, not a misconfiguration — `OpId::kQuantFp8Static` was not registered for `DeviceType::kCUDA` at all. Nothing refused first: the GEMM partner `kMatmulFp8CublasLt` IS registered unconditionally (`src/vt/cuda/cuda_matmul.cu:920`), so `MatmulFp8CutlassD`'s guard passed, and the missing quant then resolved through `src/vt/op_provider.cpp:501` to the portable CPU reference tier — eligible because `CudaBackend::UnifiedMemory()` is true — which dereferenced DEVICE pointers on the host and SIGSEGV'd one call later under a banner reading "correct but slow". Fixed by relocating the registration to a new unconditionally-compiled TU `src/vt/cuda/cuda_quant_fp8.cu`, which restores upstream's own partition (vLLM builds `static_scaled_fp8_quant` from the unconditional `VLLM_EXT_SRC` list and gates only its cutlass `scaled_mm` sources). This removes one live INSTANCE of [#844](https://github.com/mudler/vllm.cpp/issues/844) and does not address its class, which stays open. Unblocks the FP8 W8A8 arm on every non-cutlass CUDA arch — the base [#810](https://github.com/mudler/vllm.cpp/issues/810)/[#517](https://github.com/mudler/vllm.cpp/issues/517) A2-Q1 needs, where 46 FP8 mamba projections are 36.6% of decode bytes. Spec [`vt-fp8-quant-arch-gate.md`](specs/vt-fp8-quant-arch-gate.md) | bug | | [#989](https://github.com/mudler/vllm.cpp/issues/989) | `VT-FP8-QUANT-ARCH-GATE` | `scripts/check-pr-size.py`'s `classify_path` has no entry for `.agents/reachability.md` (added by `POLICY-NOTHING-LANDS-DEAD`, [#888](https://github.com/mudler/vllm.cpp/issues/888) @ `8f49ac3be`), and it FAILS CLOSED, so `pr-size` — a REQUIRED check — refuses every pull request that touches that guide, and `tests/scripts/test_check_pr_size.py` has been red on `main` ever since. Red SILENTLY: that suite is wired into no CI job and is not in `agent-preflight.sh`'s `SUITES`, so the only thing that ever loads it is `check-pr-size`'s own executable-evidence contract, which fires only when a PR edits a checker — the red is reachable exclusively by the next person who must touch that file, and presents to them as their own breakage (the [#584](https://github.com/mudler/vllm.cpp/issues/584)/[#965](https://github.com/mudler/vllm.cpp/issues/965) shape). Third instance of the class after [#856](https://github.com/mudler/vllm.cpp/issues/856) (`issue-index.md` + the style guides) and [#668](https://github.com/mudler/vllm.cpp/issues/668) (`.agents/oracles/*`), both fixed in flow by the row that tripped over them. FIXED IN FLOW while landing [#960](https://github.com/mudler/vllm.cpp/issues/960), which could not register its new checker's creation mutation without touching `check-pr-size.py` at all. NOT fixed: wiring that suite into CI, which is its own change and would red `main` until this landed | bug | | [#1066](https://github.com/mudler/vllm.cpp/issues/1066) | `ENG-EXPERT-STREAM` | `Qwen35ExpertStream` (`src/vllm/model_executor/models/qwen3_5.cpp`) is a **process-lifetime singleton** and keyed its slot cache on `(TowerId(base), expert)`, where `base` is the expert tower's host buffer **ADDRESS**. Its own comment stated the premise and drew the wrong conclusion: "A tower's identity is its base pointer, which is stable for the model's life". The premise is true; the conclusion does not follow, because the CACHE is not scoped to one model's life. Free a model, load another, and the allocator hands the new towers addresses the old ones held, so the new model's expert resolves to an entry filled from a DIFFERENT checkpoint — returned as a HIT, which by contract moves no bytes, so no counter moves and nothing downstream has anything to observe. MEASURED on two synthetic 4-layer/4-expert MoE models in one process, instrumenting `KqExpertSlice` to `memcmp` each returned slot against the tower slice it claims to be: **24 towers occupied 21 distinct addresses, and 20 of 222 slices returned another tower's bytes**; end to end the two arms disagreed on all 160 logits while each arm was internally deterministic (0 differing values on a repeat), which rules out nondeterminism. Invisible to every existing test of this row by construction, because all of them build the cache, store and streamer by hand and none runs two models through the production seam. Reachable by any process that loads a model, releases it, and loads another. Fixed by `OwnedTensor::TowerUid()`, a lazily assigned process-unique counter stamped on the tensor and re-stamped when `bytes` moves (so a copy cannot inherit an identity along with a different buffer); a counter cannot collide because it never goes backwards. Found and fixed while repairing the F1-F11 wiring review for [#912](https://github.com/mudler/vllm.cpp/issues/912). Spec [`expert-streaming.md`](specs/expert-streaming.md) | bug | -| [#1083](https://github.com/mudler/vllm.cpp/issues/1083) | `MODEL-MUSIC-minimax-music3-mini-max-music3-for-conditional-generation` | `CleanCaption`'s italic unwrap emulated upstream's `(?!\*)` with a CAPTURED `($|[^*])` (`src/vllm/model_executor/models/minimax_music3_ar.cpp:85,114` @ `a332fb98d`), and a captured group is not a zero-width assertion: consuming the trailing neighbour advanced `regex_replace` past it, so an emphasis span opening within ONE character of the previous close was never examined and the surviving asterisks re-paired ACROSS the intended spans. `*a* *b* *c*` -> `a *b c*` where `_clean_caption` (`encoders.py:72` @ diffusers `c6da9936`) gives `a b c`, and `Warm *lo-fi* *jazzy* keys with a *soft* *brushed* snare` -> `Warm lo-fi *jazzy keys with a soft brushed* snare` — a re-association, not a leftover marker, so the caption handed to the tokenizer is a string upstream would never emit. `encoders.py`'s own header states that whitespace-level prompt changes change the generated audio, so this is a checkpoint-contract break. Invisible to the gate because `markdown_and_tags`, the only golden with italics, carries ONE span per line and the defect needs adjacency. FIXED by porting the trailing side LITERALLY as `(?!\*)` — std::regex's ECMAScript grammar has negative lookahead though not lookbehind, so only the leading `(? `a *b c*` where `_clean_caption` (`encoders.py:72` @ diffusers `c6da9936`) gives `a b c`, and `Warm *lo-fi* *jazzy* keys with a *soft* *brushed* snare` -> `Warm lo-fi *jazzy keys with a soft brushed* snare` — a re-association, not a leftover marker, so the caption handed to the tokenizer is a string upstream would never emit. `encoders.py`'s own header states that whitespace-level prompt changes change the generated audio, so this is a checkpoint-contract break. Invisible to the gate because `markdown_and_tags`, the only golden with italics, carries ONE span per line and the defect needs adjacency. FIXED by porting the trailing side LITERALLY as `(?!\*)` — std::regex's ECMAScript grammar has negative lookahead though not lookbehind, so only the leading `(?