Skip to content

feat(MODEL-MM-dots3-note): W4b-2 — the sliding arm on the decode path (#699) - #1969

Merged
localai-bot merged 9 commits into
mainfrom
row/MODEL-MM-dots3-note-W4b-2
Aug 26, 2026
Merged

feat(MODEL-MM-dots3-note): W4b-2 — the sliding arm on the decode path (#699)#1969
localai-bot merged 9 commits into
mainfrom
row/MODEL-MM-dots3-note-W4b-2

Conversation

@localai-bot

@localai-bot localai-bot commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

W4b-2 of the dots3-note row (#699). The 33 sliding_attention layers and the
PADDED physical KV row are on the decode path, reached from
ModelRegistry::Forward. W4b-1 landed the sliding maths as host code with no
production call site and named W4b-2 as the row that would wire it; this is that
wiring, plus the two windowed kernels it needed.

Upstream re-derived at vLLM origin/main = bc2d63e650.
git diff --stat d9fbe526c0 -- vllm/models/dots3_note/ is EMPTY against
bc2d63e650 and against origin/main alike, measured in a local vLLM checkout
rather than assumed, so every §2.3 anchor W4b-1 corrected holds unchanged at the
newer head.

The window is a kernel bound here and a gather upstream, and that is the same function

vt::MlaDecodeAttention and vt::MlaPrefillAttention each grow an optional
AttentionWindow — the (left, right) pair this tree already uses on
PagedAttentionArgs, and literally the pair upstream hands FlashAttention
(run_sliding_window(..., causal=True, window_size=(sliding_window - 1, 0)),
attention.py:300). Upstream's decode gathers [max(seq_len - GATHER_LEN, 0), …)
into a workspace with GATHER_LEN rounded up to 8 and then masks the scores
(:76-79, :151-152); the gather is a SUPERSET and the mask makes it exact,
because Triton needs a power-of-two tile. Walking the paged block table directly
over the same key range reaches the identical set with no gather and no mask.

std::nullopt is the ABSENT state and a NOT-TAKEN branch, not a wide window: the
CPU decode's loop START moves, the CUDA decode's kv_start moves in both split
stages, the FA-2 prefill reuses the paged launcher's own
is_causal = causal && !is_local normalization, and the CPU prefill's lower
bound moves. Both op gates prove that bit-for-bit rather than to a tolerance:
a window at least as wide as the sequence produces byte-identical output to no
window, which a mask applied afterwards could not.

The padded row needed zero vt changes

Tensor::Slice(2, 0, logical) shrinks shape[2] and keeps both leading strides,
every MLA cache op sources its strides from the tensor, and that IS upstream's
kv_cache[..., : self.head_size] (_logical_cache, attention.py:700-702). The
narrowing is one line in Dots3NoteModel::ForwardDevice. This is the correction
W4b-1 recorded, executed.

The evidence is the RAW cache bytes after a real forward, not an argument: lanes
[6, 10) of every slot a FULL layer wrote are still zero, with the CONTROL that
the same lanes on the sliding layers carry 28 non-zero values.

Two of W4a's three refusals are lifted, the third is narrowed, one is new

refusal now
any sliding_attention layer LIFTED
a PADDED physical latent row LIFTED
a KV cache row disagreeing with the config KEPT, now compared against the PHYSICAL row
seq_len > index_topk KEPT, NARROWED — asked only of a config that HAS a full layer, because a sliding layer sets self.indexer = None (model.py:432-434)
a windowed prefill with chunked CONTEXT NEW, in the seam — upstream never merges context chunks under a window, so there is nothing to mirror
a NEGATIVE MlaBlockDims::sliding_window NEW, and it shipped untested; the review repair gave it a case (below)
MoE / nextn unchanged (W5 / W10)

The RELEASED dots-studio/dots3-note-prev config still refuses, now at layer 1's
MoE rather than layer 2's sliding attention, so nothing a user can run changed.

The gate

test_dots3_note_attn 36 cases / 3028 assertions (30/2418 at W4b-1),
CPU-only, no GPU, no checkpoint, no speed claim. A MIXED config
({full, sliding, full}, dense MLPs, physical row 10 against the full arm's
logical 6) is loaded through the REAL registry and run through
ModelRegistry::Forward TWICE against one cache pool — a 6-token PREFILL then a
DECODE of the seventh, over a SHUFFLED block table — and compared against a
whole-model double reference that dispatches per layer kind into W3's
ref::Forward and W4b-1's sref::Forward.

Residue 0.0254 relative; bound 6e-2. Three ratios, kept SEPARATE because merging
them is the row's own finding F1: bound/residue 2.36x,
nearest-mechanism/bound 2.63x, nearest-mechanism/residue 6.22x. A port
with no window at all lands at 0.819 — 13.6x the bound.

The fixture was retuned twice, and a measurement forced both. The first draft
(four layers, thetas 41 vs 137) measured a residue of 0.119 with the nearest
mechanism at 0.106 — the nearest defect sat UNDER the quantisation floor. The fix
was the fixture, not the bound: thetas orders apart the way the released 5e4 vs
8e7 are, and three layers instead of four.

test_ops_mla_attn 15 cases / 246290 assertions (11 / 197113 at the base
SHA, measured by checking those two test files out at the base, rebuilding and
running, then restoring them byte-for-byte); test_ops_mla_prefill
7 cases / 329772 assertions (6 / 329772 before the review repair; 4 / 242156
at the base). That +1 case is +0 assertions on purpose, and the count is the
statement
: the case the repair added is a CUDA one, doctest scores a case that
returns before its first assertion as PASSED, and this box has no device. It is a
skip wearing a pass, it is written down as one, and it must not be read as new
coverage executed here. It WAS executed later, on a leased GPU — see the CUDA
section below.

Their oracle is the op itself on a DIFFERENT input — a windowed paged call
against an unwindowed call over the truncated key list — rather than a second
copy of the same arithmetic.

The mutation pass, through the harness this tree ships

27 rows through scripts/mutation-harness.py, all re-measured at the final
36/3028 baseline, plus six more for the review repair. Highlights, with the full
tables in spec §4.8:

  • Two reachability rows. Deleting the DECODE call site
    (impl.sliding_window = dims.sliding_window) and the PREFILL one
    (…, dims.sliding_window)) each take the gate RED, so the window comes from
    the config through the real loader and the shared seam.
  • FIVE of the twenty-seven failed to BUILD on their first attempt, each on
    -Werror=unused-variable. Nearly one row in five would have read as a passing
    test in a hand-driven pass; the compiler exit is printed beside every row and
    each was re-run behind ((void)x, …).
  • M16 found a real GATE GAP. Deleting the new windowed-prefill-with-context
    refusal left the gate green, because the case asserting it never made it out
    of the draft. It is in the gate now with two controls, and M16b reds.
  • M19/M20 map which gate sees what. The same leaked window is invisible to
    test_deepseek_v2_forward and RED on test_mla_attention_block. Together
    they say impl.sliding_window really is on the DeepSeek path and its 0 is
    load-bearing — which the byte-identity table needs and cannot supply alone,
    since identical output could also mean nothing ever read the field.

What a fresh review changed, and what it corrected in the record

Nine findings, all discharged. Six are code and three are record; the record half
needed the mutation numbers the code half makes measurable, which is why it is a
second commit.

The FA-2 MLA-prefill windowed path had no test on any device. The record
named both CUDA files together and then described ONE parity case, which reads as
covering both halves. It did not: the windowed CUDA case was the DECODE sibling
in test_ops_mla_attn, and test_ops_mla_prefill's only HasCuda() cases are
pre-existing and unwindowed. A later lease would have discharged the decode half
against a record that read as covering both. test_ops_mla_prefill now carries
CUDA MLA prefill: the sliding window matches the CPU reference, comparing the
windowed device call against the windowed CPU op, against the unwindowed device
call, and against the file's expanded single-query oracle. It deliberately does
NOT assert the CPU case's wide-window bit-identity: a finite window sets
is_causal = false and dispatches FA-2's LOCAL template, so on the GPU that
agreement is numerical rather than byte-exact. Both entries in ## Owed now name
the two halves separately, because a lease closes one at a time.

A divergence this brick creates and never recorded. Upstream's
MLAAttention.get_kv_cache_spec branches on the window and returns
SlidingWindowMLASpec(..., sliding_window=self.sliding_window)
(vllm/model_executor/layers/attention/mla_attention.py:1215-1219 @
bc2d63e650), and every sliding layer sets one
(vllm/models/dots3_note/nvidia/model.py:457). MakeDots3NoteKVCache emits one
uniform v1::MLAAttentionSpec for all 46. There is no correctness
consequence
— the window is applied on READ and the gate above proves it — but
33 of 46 layers then hold a full-length latent cache where upstream caps a
windowed layer near the window, 513 blocks against 524288 on the released
config. It is the single largest memory property of this architecture, and a
token gate structurally cannot see it, which is exactly why porting.md asks for
the memory format to be compared with the oracle explicitly. THREE pieces are
missing rather than one, so it is scoped to W4b-3 rather than fixed here. While this
branch sat in review, SlidingWindowMLASpec LANDED on main (KV-DSV4-MULTICACHE
W1, #1960, c1e6f3fb9), so the merge commit's own include/vllm/v1/kv_cache_interface.h
DEFINES the type this branch's copy still lists as omitted. The divergence is
unchanged — we still emit one uniform spec for all 46 layers — but W4b-3 now
inherits the spec type and owes only the per-layer wiring, which is less than was
owed when the paragraph above was written. Verified at merge time rather than
assumed: struct SlidingWindowMLASpec : SlidingWindowSpec at
include/vllm/v1/kv_cache_interface.h:396 on origin/main.

A byte-identity claim narrowed to what was actually measured. The record said
§4.6's six-arm fingerprint table "is reproducible from outside the session that
produced it". Two of six arms reproduce; four do not, and the first draft
generalised from the first two. The diagnosis is measured on three legs and is
not a behaviour change: exactly ONE commit touches the five shared MLA files
between the two bases and it is W4a itself; grep -r finds the fingerprints only
in the spec, so neither probe was ever committed; and q_lora_scale did not
exist
at §4.6's base (grep -c is 0 there and 2 at §4.8's), so §4.6's probe
could not have set the field its own arms 2-3 are said to cover. The byte COUNTS
agree on all six arms, so the two probes agreed on shapes and differed on values.
The transferable rule is the reason this is in the record rather than quietly
corrected: a fingerprint from an uncommitted, hand-written probe is not a
cross-session reproducible quantity.
Two probes sharing a prose label are two
instruments, and comparing their outputs measures the authors, not the code.
Committing the probe is what fixes it; neither scratch tree survives and a third
hand-written probe would be a third instrument, so it goes to ## Owed.

A mutation's stated mechanism was wrong, and the conclusion survives it. The
record explained M19's green by saying test_deepseek_v2_forward's CPU forward
drives the PREFILL half while impl.sliding_window reaches only the decode MQA —
which implies the prefill half WOULD be caught. Measured: leaking the window into
the prefill call instead is EXIT 0, 11 cases / 1052 assertions, zero failures,
SURVIVED. It misses a window leak on BOTH halves, because those CPU cases have no
value oracle for the attention output at all — each compares the model against
itself under another configuration, or against nothing.

A refusal that shipped untested now has a case.
MlaBlockDims::sliding_window < 0 is load-bearing, because the ops read the
window as > 0, so a negative value throws nowhere and silently degrades a
windowed layer to full attention. It has controls on both sides of the boundary
(0 is ABSENT and legal, 513 is legal) so it cannot pass on an implementation that
refused every window. test_mla_attention_block 2247715 -> 2247718
assertions, 12 cases unmoved.

One refusal is DECLINED rather than tested, on a stronger reason than the
review's.
The per-step ld.head_size() <= physical_row check is UNREACHABLE,
not merely untested: physical_latent_row() IS swa.latent_row(), so on a
sliding layer the comparison is an identity, and on a full layer
ParseDots3NoteParams has already refused the violating config at load. R3 is
the measurement that turns that from an argument into a gate — deleting the
CONFIG-level refusal reds test_dots3_note_scaffold, so the closure is gated
rather than assumed. The review's reading, that Tensor::Slice backstops it,
understates it: the backstop is not reached either. It is kept as the executable
spelling of upstream's assert physical_head_size >= self.head_size, the site
says so, and ## Owed carries it as an untested assertion.

A dead assignment and an uncalled accessor are deleted.
step.rope_cache = &rope_full had no reader in its TU and would have handed a
future one the full arm's rope on a sliding layer, or an empty Tensor on a pure
SWA config; a null fails at the first read instead.
MlaBlockDims::has_sliding_window() had no caller anywhere and no call site was
invented for it, because every consumer wants the value and
ForwardMlaAttentionBlock assigns it unconditionally precisely so a 0 cannot be
skipped. Two stale comments describing the pre-retune four-layer fixture go with
them.

The seam is byte-identical on all six arms, measured within this session

Six arms across the seam's branch space (q_lora present/absent, both rope
layouts, both dtypes), BASE in a separate git archive tree at 925a4a587 with
a byte-identical probe (md5sum equal), its own configure and its own build.
Six for six identical, base against head. That is the claim this table was
built to make, and it is the claim it supports; the cross-session comparison it
also attempted is the one narrowed above.

test_mla_attention_block 12 / 2247718 (12 / 2247715 before the review
repair added the negative-window case) and test_deepseek_v2_forward
11 / 1052; test_deepseek_v2_decode_graph_seam 3/230, test_ops_mla_cache
9/2947, test_dots3_note_scaffold 26 / 110819.

NOT run and named: the SACRED DeepSeek-V2-Lite e2e token gate needs a ~29.26 GiB
checkpoint on a CUDA host; this brick ran CPU-only on a box with neither.

## Nothing lands dead

Everything this PR adds is reached from ModelRegistry::Forward, and two
reachability mutations say so rather than the sentence: deleting the decode call
site (impl.sliding_window = dims.sliding_window) and the prefill one
(… , dims.sliding_window)) each take the gate RED.

What is NOT reached, declared: W4b-1's dots3_note_attn.{h,cpp} sliding
functions
ForwardSlidingAttention, GatherSwaKv, ApplySwaScoreMask,
BuildSlidingWindowMetadata, WritePaddedMlaCache, NarrowLogicalCacheRows
still have no production call site and did not gain one here, because the device
path reaches the same key set through the paged block table instead of
upstream's Triton gather-plus-mask. They are the gate's oracle, the status W3's
ForwardFullAttention has had since W4a. Owning row
MODEL-MM-dots3-note-dots3-note-for-causal-lm, issue #699, listed under
## Owed in the spec.

The CUDA half is compiled and EXECUTED, on sm_87

The two CUDA files this PR changes — src/vt/cuda/cuda_mla_attn.cu and
src/vt/cuda/cuda_flash_attn_fa2.cu — were written on a box with no GPU and no
nvcc, and for most of this row's life the record had to say "written, not
compiled, not run". An rc run lease on orin:gpu0 (Jetson AGX Orin, sm_87,
~36 minutes of device time) closed both halves of that. The SHA was PROVEN rather
than asserted: the job cloned in-container and refused to build unless
git rev-parse HEAD equalled 53424910dfa31fbd10bcb3296a12401eaed8ee54 with
git status --porcelain empty.

Compiled, on two toolchains. Both objects were deleted first, gencode was
read from compile_commands.json, and real per-arch SASS was confirmed with
cuobjdump --list-elf rather than a PTX leg.

TU CUDA 12.6 / sm_87 CUDA 13.0 + the full CI arch list
cuda_mla_attn.cu sm_87.cubin, 1.56 MB rc=0, 10 cubins — 80, 86, 87, 89, 90a, 100a, 103a, 110, 120a, 121a
cuda_flash_attn_fa2.cu sm_87.cubin, 514 KB rc=0, 6 cubins — 80, 86, 87, 89, 120a, 121a

The second column reproduces what CI's cuda-fat-build asks, on the toolchain it
uses. FA-2 being ON was MEASURED three ways rather than inferred from the default
CUDA feature fa2: ENABLED for [87], VLLM_CPP_FLASH_ATTN:BOOL=ON in
CMakeCache, and the generated manifest VLLM_CPP_CUDA_FA2_COMPILED_ARCHS "87"
which matters because cuda_flash_attn_fa2.cu enters the archive only when
VLLM_CPP_FLASH_ATTN (default ON), CUTLASS headers and a non-empty
VT_FA2_ARCHS all hold, and cuda-fat-build supplies the second with
-DVLLM_CPP_CUTLASS_FETCH=ON and the third through an arch list that intersects
the fa2 feature set at 80, 86, 87, 89, 120a and 121a.

Executed — and the assertion counts are the proof. Same binaries in both
columns; the control is CUDA_VISIBLE_DEVICES="", so the delta is the device and
not the build.

run cases assertions
windowed decode alone, no device 1 0
windowed decode alone, on device 1 49,158
windowed prefill alone, no device 1 0
windowed prefill alone, on device 1 467,010

1 case / 0 assertions / SUCCESS! is exactly the shape these two cases have worn
until today, and the right-hand column is the first execution either has ever
had
. Whole-binary figures on device: test_ops_mla_attn 246,290 -> 2,401,528
and test_ops_mla_prefill 329,772 -> 2,931,678. Every filter matched exactly one
case, so no zero-match false green; all exit codes 0 and no timeout.

Numerically correct. Windowed decode MaxAbsDiff(gpu, cpu) is 2.38e-07,
2.68e-07 and 2.68e-07 across the three split arms, against a < 1e-3 bar.
Windowed prefill, with 475 (query, key) pairs dropped across 57 queries: gpu_win
vs cpu_win 0.00294137, gpu_none vs cpu_none 0.00294137 and gpu_win vs
expanded 0.00294137, all against < 3e-2 — and the decisive one, gpu_win
vs gpu_none = 1.06055
against a > 1e-2 bar. The window demonstrably BITES
on the device, so the FA-2 launcher is not dropping window_size on the floor.
That is the exact defect the is_local normalization exists to prevent, now
measured rather than argued.

The wrinkle, stated rather than tidied away. Three of those four prefill
numbers are byte-identical at 0.00294137. The likely reason is that the global
max-error element sits on an UNWINDOWED row, where gpu_win/gpu_none and
cpu_win/cpu_none/expanded each coincide and all three become the same
subtraction — but that element was not instrumented, so this is inference and not
a measurement. It is not degeneracy: if the CPU arms agreed wholesale the second
assertion would read about 1.06, not 0.0029.

Two limits. Execution is proven on sm_87 only; the ten-arch result is
COMPILE-ONLY, because CUDA 13 cannot run against that box's NVRM 540.4.0 driver
(cudaGetDeviceCount rc=35). And this is KERNEL-level parity on two ops. It is
not the e2e model gate, which is unrelated and still owed.

The two red CI lanes are pre-existing and unrelated, with the evidence to re-derive that

Neither red is attributable to this change, and both are named here rather than
left for a reader to assume.

The merge that built clean and threw

Integrating origin/main a second time merged clean, COMPILED clean, and took
test_dots3_note_attn from 36/3028 green to five cases throwing
resident weight: EMPTY tensor has no host bytes to alias. The incoming change
is #1952's review finding #1953: ResidentWeight now refuses an empty weight,
because an empty one aliases a null host pointer no downstream op can detect.
The refusal is right and this branch was on the wrong side of it — it made BOTH
rope caches resident up front while the materializer deliberately leaves the
unused one empty (each is 64 MiB at 524288 positions). One guard per cache fixes
it, and the comment now says the guard is the CONTRACT rather than an
optimization.

The two branches touched different files, so nothing about this was visible to
the merge: it is "merge-tree CLEAN is not merge-tree BUILDS" one step further
along, where it builds too. Re-running the focused gate set AFTER the merge and
BEFORE the push is the only thing that caught it. Spec §4.8 records it.

What is owed, and the split I am proposing

The row is NOT finished, and the sm_87 result above does not narrow this list.

W4b-3, and the line is real: the DSA lightning indexer's SELECTION shares
nothing with the sliding window. The sliding layers have no indexer at all; the
indexer is on the FULL layers, and lifting seq_len > index_topk needs indexer
weights on device, a logits kernel, a top-k and a SPARSE MLA attention kernel on
both backends. Bundling it here would have doubled a PR that already carries two
new kernel bounds and a seam extension. W4b-3 carries it, together with the
windowed-prefill-with-context refusal and the SlidingWindowMLASpec divergence
above.

.agents/specs/dots3-note.md is STALE against this body at the merge commit,
in three places, and W4b-3 owns every one.
The spec is the row's authoritative
record, so a merge that leaves it disagreeing with its own commit message is a
debt and is written down as one. It is not fixed on this branch because a push
now would cancel a cuda-fat-build this change has already had destroyed twice,
and the fresh reviewer sanctioned folding record-only corrections into W4b-3:

  • §4.8 reads test_mla_attention_block 12 / 2247715 and calls it "unmoved
    from the numbers §4.6 recorded". The measured value at this SHA is
    12 / 2247718 — the implementer, a fresh reviewer and the operator each
    measured it independently and agree. 2247718 appears nowhere in the spec.
    This body says 2247718 and the spec contradicts it.
  • §4.8's #### The #1969 REVIEW-REPAIR rows section says "Five more rows" and
    its table lists six: R1, R1-control, R2, R3, R4 and R4b. This body says
    six.
  • The most misleading of the three. §4.8 and ## Owed still say the CUDA
    lease "cannot currently be taken" and name thor:gpu0 as the host that
    discharges it. Both statements are now false. The compile and the execution
    above were discharged on orin:gpu0, and thor could never have discharged
    the PREFILL half at any point, because VT_CUDA_FEATURE_TABLE's fa2 row is
    8.0,8.6,8.7,8.9,12.0a,12.1a — sm_87 carries FA-2 and thor's sm_110 does not.
    Left alone, the record claims blocked work that has in fact been done, on a
    host that could not have done it.

Two comment-level corrections also go to W4b-3, named here so the miss is in
the history rather than only in a review thread.
They are not fixed on this
branch for the same reason, and neither is worth a gate run of its own:

  • src/vllm/model_executor/models/dots3_note_device.cpp's upstream anchors for
    the deepseek_v2.py diff are off by three. The lines are 460 and 498
    at bc2d63e650, not 457 and 495 — 457 is qk_nope_head_dim: int, and 495 is
    a bare ). The substance of that correction is right; only the two numbers
    are wrong.
  • The new CUDA prefill case's comment says the CPU fixture is "unchanged". It is
    not literally one experiment: the CUDA case uses h = kHeadsLite (16) where
    the CPU case uses h = 4. Lengths, window and seeds do match.

Still open, and blocked on things this row cannot buy. The end-to-end parity
gate against vLLM — token-exact or the ratified near-tie form, chosen by
measurement — plus every throughput, latency and memory axis, and the quantized
arms. No host this project owns runs the dots3_note oracle at any published
precision, and the row is beyond the parity pin. ## Owed in the spec carries
each of these with its owner and #699.

Row stays SPIKE. Under §6.4 option B the CPU gate remains a consistency gate
against an independent reference, not a correctness gate against an oracle: no
vLLM instance for dots3_note runs on any host this project owns.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]

mudler added 9 commits August 26, 2026 08:03
…#699)

W4b-2 of the dots3-note row (#699). The 33 `sliding_attention` layers and the
PADDED physical KV row are on the decode path, reached from
`ModelRegistry::Forward`. W4b-1 landed the sliding maths as host code with no
production call site and named W4b-2 as the row that would wire it; this is that
wiring, plus the two vt kernels it needed.

WHAT THE WINDOW IS, AND WHERE IT LIVES. `vt::MlaDecodeAttention` and
`vt::MlaPrefillAttention` each grow an optional `AttentionWindow` — the
`(left, right)` pair this tree already uses on `PagedAttentionArgs`, and
literally the pair upstream hands FlashAttention
(`run_sliding_window(..., causal=True, window_size=(sliding_window - 1, 0))`,
`vllm/models/dots3_note/nvidia/attention.py:300` @ `bc2d63e650`). `std::nullopt`
is the ABSENT state and it is a NOT-TAKEN branch, not a wide window: on the CPU
decode the window is the loop's START BOUND, on the CUDA decode it moves
`kv_start` in both split stages, and on the FA-2 prefill it reuses the paged
launcher's own `is_causal = causal && !is_local` normalization. Upstream's
`_gather_swa_kv_kernel` + `_apply_swa_score_mask_kernel` pair (`:49`, `:119`) is
a Triton WORKSPACE strategy over a rounded-up gather; walking the paged block
table directly over the same key range reaches the identical set with no gather
and no mask, and the op tests prove that by comparing the windowed call against
an UNWINDOWED call over the truncated key list rather than against a second copy
of the same arithmetic.

THE PADDED ROW NEEDED NO `vt` CHANGE AT ALL, which is the correction W4b-1
already recorded and this brick executed. `Tensor::Slice(2, 0, logical)` shrinks
`shape[2]` and keeps both leading strides, every MLA cache op reads those strides
from the tensor, and that IS upstream's `kv_cache[..., : self.head_size]`
(`Dots3NotePaddedSparseImpl._logical_cache`, `attention.py:700-702`). The
narrowing is one line in `Dots3NoteModel::ForwardDevice`. The gate reads the RAW
cache bytes after a real forward: lanes [6, 10) of every slot a FULL layer wrote
are still zero, while the same lanes on the sliding layers carry 28 non-zero
values — the control that says the assertion is about the narrowing and not
about a fixture that produces zeros anyway.

TWO OF W4A'S THREE REFUSALS ARE LIFTED, AND THE THIRD IS NARROWED. The
`sliding_attention` refusal and the PADDED-row refusal are gone from
`Dots3NoteDeviceRefusal`. The per-step cache-row check STAYS — an engine
allocates the cache separately from the config it was built from — and now
compares against the PHYSICAL row, which is what the allocator is told. The
`seq_len > index_topk` refusal STAYS and is now asked only of a config that HAS a
full-attention layer, because `Dots3NoteSlidingAttention` sets
`self.indexer = None` / `is_sparse = False` (`model.py:432-434`), so a pure-SWA
config has no DSA anywhere. Two cases pin both halves.

ONE NEW REFUSAL, NAMED RATHER THAN APPROXIMATED: a windowed prefill that also
carries chunked CONTEXT. Upstream caps a sliding layer's gather at
`min(seq_len, query_len + W - 1)` and runs one varlen call per request group
(`attention.py:206`, `:594-654`); it never merges context chunks under a window,
so there is no windowed form of `forward_mha`'s LSE merge to mirror. The seam
throws instead of merging an unwindowed context into a windowed suffix.

THE GATE. `test_dots3_note_attn` 35 cases / 3025 assertions (30 / 2418 at
W4b-1), CPU-only, no GPU, no checkpoint, no speed claim. A MIXED config —
`{full, sliding, full}`, dense MLPs, physical row 10 against the full arm's
logical 6 — is loaded through the REAL registry and run through
`ModelRegistry::Forward` TWICE against one cache pool: a 6-token PREFILL, then a
DECODE of the seventh, over a SHUFFLED block table. Both are compared against a
whole-model double reference that dispatches per layer kind into W3's
`ref::Forward` and W4b-1's `sref::Forward` — a materialized MHA with no cache, no
paging and the window as a direct positional predicate. Residue 0.0254 relative,
bound 6e-2, and the three ratios are kept SEPARATE because merging them is spec
§4.6's finding F1: bound/residue 2.36x, nearest-mechanism/bound 2.63x,
nearest-mechanism/residue 6.22x. A port with NO window lands at 0.819, i.e. 13.6x
the bound.

`vt` op gates: `test_ops_mla_attn` 15 cases (11 before), `test_ops_mla_prefill`
6 (4 before). A window at least as wide as the sequence is BIT-IDENTICAL to no
window on both ops, which is what says the absent state is a branch and not a
mask.

NO REGRESSION ON THE SEAM'S OTHER CALLERS: `test_mla_attention_block` 12 / 2247715
and `test_deepseek_v2_forward` 11 / 1052, both unmoved from the numbers §4.6
recorded, plus `test_deepseek_v2_decode_graph_seam` 3 / 230 and
`test_ops_mla_cache` 9 / 2947.

CUDA IS WRITTEN AND NOT GATED HERE. This box has no GPU. The CUDA decode's
windowed split partition and the FA-2 prefill's local-mask normalization compile
in the fat build but have not been RUN; the CUDA-vs-CPU window parity case is
present and skips without a device. That is owed and named rather than implied.

Row stays SPIKE. Under §6.4 option B this remains a consistency gate against an
independent reference, not a correctness gate against an oracle — no vLLM
instance for `dots3_note` runs on any host this project owns.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…te-W4b-2

Routine integration of origin/main into the W4b-2 branch before pushing. The
four incoming commits are issue-index appends only; the merge is a union of that
append-only file and touches nothing this branch changed.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…gate missed

The spec section for W4b-2: the re-derived upstream anchors at `bc2d63e650`, why
the window is a kernel bound here and a gather upstream, the padded row's
one-line narrowing, the refusal table, the fixture's two forced retunings, the
op gates' oracle-is-the-op-on-a-different-input design, and the six-arm seam
byte-identity measurement.

ONE FINDING FROM WRITING IT DOWN. The seam probe's first BASE run used doctest's
`-ts=` — the test-SUITE filter — instead of `--test-case=`. It matched zero
cases, printed `test cases: 0 | 0 passed | 0 failed | 13 skipped` and
`Status: SUCCESS!`, and exited 0. Read without checking the case count, that is a
clean pass with no fingerprints: the third of the four failure modes
`scripts/mutation-harness.py`'s own docstring enumerates, met in the one place
that was hand-driven rather than run through the harness. §4.8 records it.

AND ONE GATE GAP THE MUTATION PASS FOUND. `M16-windowed-prefill-with-context-
accepted` deleted the new seam refusal and the gate stayed GREEN, because the
case that asserts it never made it out of the draft. It is here now, with two
controls that keep it from passing vacuously: with no window the same call
proceeds into `vt::MlaPrefillAttention` and fails there with a DIFFERENT
exception type, and with a window but no chunk list it does not fire either. A
refusal whose test does not exist is indistinguishable from a refusal that works.

`test_dots3_note_attn` 36 cases / 3028 assertions.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…d FEATURES

The evidence W4b-2's §4.8 was still owing, plus the two projections its
lifecycle touches.

THE MUTATION TABLE, 27 rows through `scripts/mutation-harness.py` rather than a
scratch driver — which is what §4.7 says W4b-1 should have used. Every count was
RE-MEASURED at the final 36/3028 baseline instead of being carried over from the
first pass at 35/3025, because a table mixing two baselines is an instrument
reporting on a state it was not given.

FIVE of the twenty-seven failed to BUILD on their first attempt, every one on
`-Werror=unused-variable`, and each is printed with its compiler exit rather
than tidied away. Nearly one row in five would have read as a passing test in a
hand-driven pass; W4b-1 hit the same trap once in twenty-six and the harness
caught it five times here without anyone looking.

THREE GREEN ROWS, and they say three different things. M5 is a green the driver
earned: forcing the CPU prefill's PASS-1 loop to start at 0 is a numeric no-op,
because softmax is invariant to the constant subtracted before `exp` and passes
2 and 3 still sum the windowed range — M5b moves the bound's DEFINITION, reaches
all three passes and reds. M16 found a real gate gap, already fixed in the
previous commit. M19 and M20 apply the same leaked window to the DeepSeek path
and disagree: `test_deepseek_v2_forward` is blind to it because its synthetic
forward drives the prefill half, while `test_mla_attention_block` reds on 3
cases / 4 assertions. Together they say `impl.sliding_window` really is on the
DeepSeek path and its 0 is load-bearing — which the byte-identity table needs
and cannot supply alone, since identical output could also mean nothing ever
read the field.

The two vt op-gate baselines are MEASURED, not counted off `TEST_CASE` lines:
both files were checked out at the base SHA `925a4a587`, rebuilt, run, then
restored and verified byte-for-byte. `test_ops_mla_attn` 11 / 197113 → 15 /
246290; `test_ops_mla_prefill` 4 / 242156 → 6 / 329772.

§7 marks W4b-2 DONE and opens W4b-3 for the three debts it named: the DSA
lightning indexer's SELECTION, the windowed prefill with chunked CONTEXT, and
the `rc` lease on `thor:gpu0` that gates the CUDA half. The split line is that
the indexer shares nothing with the sliding window — the sliding layers carry no
indexer at all.

`docs/FEATURES.md` stops saying the dots3-note forward refuses. It has not since
W4a, and it now runs both geometries; what still refuses on the RELEASED
checkpoint is its first MoE layer.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…te-W4b-2

Second integration of origin/main before pushing. The two incoming commits are
ENG-POOL-BEST-FIT (#1930) and SPEC-DFLASH2's shared embedding copy (#1952);
neither touches the MLA seam, the two `vt` MLA ops or anything dots3-note owns,
and the merge is clean. The focused gate set was re-run after it.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
… refusal

Integrating `origin/main` merged clean, COMPILED clean, and took
`test_dots3_note_attn` from 36/3028 green to five cases throwing:

    vt: resident weight: EMPTY tensor has no host bytes to alias
        (host-alias arm, dtype f32, rank 0)   dense_attn_block.h:206

The incoming change is #1952's review finding #1953: `ResidentWeight` now refuses
an empty weight, because an empty one aliases a null host pointer that no
downstream op can detect — every op validates rank, shape, dtype and device, and
the shape comes from the caller rather than from the bytes. The refusal is right.

W4b-2 was on the wrong side of it. It made BOTH rope caches resident up front,
while `MaterializeDots3NoteDevice` deliberately leaves the unused one empty: each
is 64 MiB at the released 524288 positions, so a config with no sliding layer
should not build the sliding table and a config with no full layer should not
build the full one. A layer only ever reads its own kind's cache, so the guard
costs nothing and the comment now says it is the CONTRACT rather than an
optimization.

Nothing about this was visible to the merge itself: the two branches touched
different files, `git merge` reported clean and `cmake --build` exited 0. It is
the "merge-tree CLEAN is not merge-tree BUILDS" trap one step further along,
where it builds too and only the gate can see it. Re-running the focused gate set
after the merge and before the push is what caught it; §4.8 records that.

`test_dots3_note_attn` back to 36 cases / 3028 assertions.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…ot on scheduling

W4b-2's record said the CUDA half was owed against an `rc` lease on `thor:gpu0`.
That reads as work nobody has got round to. It is not: the lease cannot be taken
at all. Measured here with `rc devices` rather than taken from a report:

    dgx:gpu0   unhealthy (no contact 1h27m50s)
    orin:gpu0  unknown   (no contact 1m17s)
    thor:gpu0  unhealthy (no contact 1h16m32s)

Both CUDA hosts this row could use are QUARANTINED, and the third device is
`unknown` rather than healthy — it is an `orin` (sm_87) and not this row's host
in any case. Clearing a quarantined device needs an admin token, which is a
human's decision and not an agent's. So the blocker is hardware recovery, and
§4.8, `## Owed` and the two §7 bullets now say that with the measurement attached
instead of naming a lease as if it were schedulable.

A SECOND STATEMENT THE RECORD WAS RUNNING TOGETHER. "Written and not run" let
"written" imply "builds". The two CUDA files have not been COMPILED here either
— this box has no `nvcc` — and CI's `cuda-fat-build` is the only compile
verification this change can give them. Until that lane reports on this branch
the CUDA half is neither compiled nor executed, and the section says so in those
words.

Record-only: no source, test or gate file is touched, so the numbers in §4.8
stand as measured at `fa96f9557`.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…ow gets a case, and three dead or stale lines go (#699)

Six of the nine findings a fresh review raised on #1969 are discharged here;
the three record-only ones ride in the following commit, which needs the
mutation numbers this one makes measurable.

F1. `tests/vt/test_ops_mla_prefill.cpp` gains a `HasCuda()`-skipping windowed
CUDA-vs-CPU parity case. Before it, the FA-2 MLA-prefill launcher's `is_local`
normalization — one of the two CUDA files W4b-2 changed — had no gate on any
device: the file's only `HasCuda()` cases are pre-existing and unwindowed, and
the PR's one windowed CUDA case is the DECODE sibling in `test_ops_mla_attn`.
A later GPU lease would have discharged the decode half while the record read
as covering both. The case SKIPS on this box, which has no CUDA device, so it
raises `test_ops_mla_prefill` from 6 cases to 7 and its assertion count not at
all (329772, unmoved). It is written and unexecuted, and it is recorded that
way rather than counted as coverage. It deliberately does NOT assert the CPU
case's wide-window bit-identity: a finite window sets `is_causal = false` and
dispatches FA-2's LOCAL template, so on the GPU that agreement is numerical.

F5a. `MlaBlockDims::sliding_window < 0` shipped without a test and its review
mutation SURVIVED. The refusal is load-bearing — the ops read the window as
`> 0`, so a negative value throws nowhere and silently degrades a windowed
layer to full attention — so it now has a case, with controls on both sides of
the boundary (0 is ABSENT and legal, 513 is legal) so it cannot pass on an
implementation that refused every window. `test_mla_attention_block`
2247715 -> 2247718 assertions, 12 cases unmoved.

F6. `step.rope_cache = &rope_full` in `dots3_note_device.cpp` is deleted. No
code in that TU reads the field; the three models that do read it
(`deepseek_v2`, `minicpm3`, `kimi_linear_device`) each have ONE per-model rope
table, and dots3-note has two whose selection is a property of the layer. The
assignment would have handed a future reader the full arm's rope on a sliding
layer, or an empty `Tensor` on a pure-SWA config. A null fails at the first
read instead, and the comment now says so.

F7. `MlaBlockDims::has_sliding_window()` had no caller in `src`, `include` or
`tests` and is dropped under `## Nothing lands dead`, with a note on why no
call site was invented for it: every consumer wants the value, and
`ForwardMlaAttentionBlock` assigns it unconditionally precisely so a 0 cannot
be skipped.

F8. Two comments in `test_dots3_note_attn.cpp` described the pre-retune
four-layer fixture (`{full, sliding, full, sliding}`) that the committed
`Spec::kinds` and the case's own `REQUIRE(num_hidden_layers == 3)` contradict.

F9. `dots3_note_device.cpp` anchored upstream at `06ecec7a84` while the spec
and this PR re-derive at `bc2d63e650`. Re-derived and MEASURED, not assumed:
`git diff 06ecec7a84 bc2d63e650 -- vllm/models/dots3_note/` is empty, and the
only `deepseek_v2.py` delta is two equal-length lines inside
`DeepseekV2Attention` (`:457`, `:495`), a class dots3-note does not subclass,
so every anchor holds unmoved. The old comment claimed that second diff was
EMPTY; it is not, and naming the two lines is what makes the claim checkable.

F5b is NOT fixed here and the code says why at the site. The per-step
`ld.head_size() <= physical_row` check is UNREACHABLE, not merely untested:
`physical_latent_row()` IS `swa.latent_row()`, so it is an identity on a
sliding layer, and `ParseDots3NoteParams` already refuses the full-layer case
at load. That is a stronger statement than the review's "backstopped by
`Tensor::Slice`", and it is why the mutation survived. The following commit
lists it under `## Owed`.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…w measured otherwise, and one divergence it never said (#699)

The record half of #1969's fresh review. Every claim below is re-measured at
this head rather than transcribed, and the mutation rows carry their compiler
exit.

F1. §4.8's CUDA paragraph and its `## Owed` bullet named the two CUDA files
together and then described ONE parity case. That reads as covering both
halves. It did not: the prefill half had no windowed case on any device until
the preceding commit added one. Both entries now name the halves separately,
because a lease closes one at a time. They also carry the number that says
neither has executed — `test_ops_mla_prefill` reads 7 cases / 329772
assertions, one more case than before and not one more assertion, which is
what a skipped case looks like in a count.

F3. §4.8 claimed §4.6's six-arm fingerprint table "is reproducible from outside
the session that produced it". Two of six arms reproduce; four do not. Verified
here before writing it down, and the diagnosis holds on all three legs:
`git log d7d1ee9..925a4a5` over the five MLA files returns exactly one
commit, `446ac1806`, which is W4a itself — and widening the sweep to all of
`src/vt` adds only `Conv3d` and `Exl3Gemm`, which the MLA block does not reach;
`grep -r` finds the fingerprints only in this spec, so the probe was never
committed; and `q_lora_scale` does not exist at §4.6's base at all
(`grep -c` is 0 there and 2 at §4.8's), so §4.6's probe could not have set the
field its own table says arms 2-3 exist to cover. The byte counts agree on all
six arms, so the two probes agreed on shapes and differed on values. It is a
probe difference, not a behaviour change, and the section now says so with the
general rule: a fingerprint from an uncommitted, hand-written probe is not a
cross-session reproducible quantity. Committing the probe is what fixes it,
neither scratch tree survives, and a third hand-written probe would be a third
instrument — so it goes to `## Owed` rather than being faked here.

F4. §4.8 explained M19's green by saying `test_deepseek_v2_forward`'s CPU
forward drives the prefill half while `impl.sliding_window` reaches only the
decode MQA — which implies the prefill half WOULD be caught. Measured: leaking
the window into the prefill call instead is compiler exit 0, EXIT 0, 11 cases /
1052 assertions, zero failures, SURVIVED; the same mutation on
`test_mla_attention_block` is compiler exit 0, EXIT 1, 4 cases / 2 assertions
failing. The real reason is that those CPU cases have no value oracle for the
attention output at all — `:443`, `:464`, `:482`, `:511` and `:537` each compare
the model against itself under another configuration, or against nothing. The
M19 conclusion survives; its map was drawn wrong.

F2. A divergence W4b-2 created and never recorded. Upstream returns
`SlidingWindowMLASpec` for a windowed layer
(`mla_attention.py:1215-1219` @ `bc2d63e650`) and passes
`sliding_window=config.sliding_window_size` per sliding layer
(`model.py:457`); `MakeDots3NoteKVCache` emits one uniform `MLAAttentionSpec`
for all 46. No correctness consequence — the window is applied on read and the
W4b-2 gate proves it — but 33 of 46 layers then hold a full-length latent cache
where upstream caps a windowed layer near the window, 513 against 524288. That
is the class a token gate structurally cannot see, which is why `porting.md`
asks for the memory format explicitly. §4.8 gains a subsection, `## Owed` gains
an entry scoped to W4b-3, and `MakeDots3NoteKVCache`'s own comment — which
still said the group split was "W4's, and NOT represented here" after W4b-2
made those layers run — now names the owning brick and the reason for each of
the three things it defers.

F5b. Recorded rather than fixed, with the site saying why. The per-step
`ld.head_size() <= physical_row` check is UNREACHABLE, not merely untested, and
that is stronger than the review's reading. R3 is the measurement: deleting the
CONFIG-level refusal that closes the full-layer case reds
`test_dots3_note_scaffold` at compiler exit 0, 1 case / 1 assertion, so the
closure is gated rather than assumed.

The `#1969 REVIEW-REPAIR rows` table records all six mutations run for this
repair, each with its compiler exit, including the two GREEN ones and the
before/after pair that shows R1 going from SURVIVED on the row gate to
DETECTED once the new case exists.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
localai-bot pushed a commit that referenced this pull request Aug 26, 2026
…lkan red found while gating W2 (#1979)

Not this branch's defect and not this branch's fix. `windows-msvc-vulkan` stops
on `test_openai_api_server.exe exited with status -1073740791` on this pull
request and on #1975, #1969 and #1967, whose diffs share no file under
src/vllm/entrypoints/. The job is PR-only and never runs on main, so there is no
green reference commit to bisect against, which is why four authors could each
meet this red without any of them being able to attribute it.

It rides here rather than in its own record-only pull request because the
alternative to filing it now is not filing it: AGENTS.md requires a bug found
during other work to get an issue that names an owner, and this one is owned by
ENG-RELEASE-WINDOWS rather than by the row that found it.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-fable-5 [Claude Code]
@localai-bot
localai-bot merged commit 21fe11c into main Aug 26, 2026
26 of 29 checks passed
@localai-bot
localai-bot deleted the row/MODEL-MM-dots3-note-W4b-2 branch August 26, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants