Skip to content

integration(glm53-flash): complete NVFP4 and prefix-cache stack - #589

Merged
lukealonso merged 27 commits into
local-inference-lab:dev/jovian-judgementfrom
yatesdr:integration/glm53-flash-r16-cache-complete
Sep 4, 2026
Merged

integration(glm53-flash): complete NVFP4 and prefix-cache stack#589
lukealonso merged 27 commits into
local-inference-lab:dev/jovian-judgementfrom
yatesdr:integration/glm53-flash-r16-cache-complete

Conversation

@yatesdr

@yatesdr yatesdr commented Sep 2, 2026

Copy link
Copy Markdown

Purpose

Provide one conflict-resolved Jovian Judgement integration head for the
GLM-5.3-Flash cache-complete r16 build. This is the release-integration view of
the component work, not a replacement for its focused review units.

Included work

The overlapping #549/#575 test changes are resolved in this branch. During
composition, a dropped closing assertion delimiter in the replayed native
prefix test was also restored before publication.

Why this is not duplicate work

#549, #575, and #574 remain the focused review units. Their independently
mergeable heads overlap in test_b12x_sparse_mla_api.py, and the four native
prefix fixes are also required by the qualified image. This PR provides the
deterministic, buildable aggregate that an image-integration bot can consume
without inventing a conflict resolution or omitting an unpublished r15-only
equivalent.

Dependencies and preflight

Validation

  • All 21 changed Python files pass Ruff and Ruff format checks.
  • Python compilation and git diff --check pass.
  • vLLM auto-geometry suite: 8 passed, including DCP8 -> 512-token pages.
  • Exact r15 image smoke: vLLM/B12X/LMCache imports, cache ABIs, launcher matrix,
    CUDA cuMem interposer, and upstream allocator policy passed.
  • TP4 cold/APC/L1/restart-L2 content checks passed for DCP1, DCP2, and DCP4
    with both fp8_ds_mla and nvfp4_ds_mla.
  • DCP4 NVFP4 passed five repeated APC-reset/L1 restores.
  • TP8 is source-audited but not physically executed because an eight-GPU host
    was unavailable.

AI assistance

OpenAI Codex assisted with source audit, conflict resolution, regression
construction, and integration validation. The submitter reviewed the resulting
source and evidence.

yatesdr and others added 27 commits August 31, 2026 15:04
Register the model-specific nvfp4_ds_mla dtype, retain its uint8 storage, and allow only that packed dtype through the generic MLA NVFP4 guard. Select the 304-byte GLM_NEXT record in the B12X cache spec and pass the explicit no-RoPE, inline-per-token-scale recipe to decode and prefill.

Size hybrid attention/Mamba pages from the backend-published 337-byte token row so the smaller packed record receives a compatible manager block. Align the semantic record region to the embedded C4 index-page boundary, and derive the pooled-index tail from the bound runtime record width instead of hard-coding FP8 geometry.

Treat nvfp4_ds_mla as an opaque packed-byte MLA cache throughout forward and DCP workspace setup. This preserves its uint8 record instead of reinterpreting it as native FP8, while leaving ordinary FP8 and fp8_ds_mla behavior unchanged.

Non-GLM_NEXT sparse MLA configurations still reject the new dtype.

Depends on the matching B12X GLM_NEXT NVFP4 record implementation.

Co-authored-by: David Young <davidseanyoung@gmail.com>
Rebuild the MLA cache spec at the resolved manager block size before padding the Mamba page. This includes the backend-aligned pooled-index tail and prevents a 2 KiB underallocation at the 3328-token GLM5Next block size.

Signed-off-by: derek <derek.yates@live.com>
…glm53-flash-nvfp4-kv

# Conflicts:
#	tests/v1/attention/test_b12x_sparse_mla_api.py
Initialize the full-CKV and record-width fields expected by the merged target branch so the NVFP4 and finalized-geometry bind tests exercise their intended contracts.

Signed-off-by: derek <derek.yates@live.com>
Size the DCP full-CKV workspaces and raw-record gather from the selected GLM5Next cache format. This preserves the qualified 528-byte FP8 path while allowing the 304-byte NVFP4 layout through DCP4 full-context prefill.

Co-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: derek <derek.yates@live.com>
Select packed sparse MLA workspaces from the layer group cache spec so per-layer auto overrides do not inherit an unrelated global packed dtype. Add the focused resolved-spec regression and complete the new helper docstrings requested in review.

Co-authored-by: OpenAI Codex <codex@openai.com>

Signed-off-by: derek <derek.yates@live.com>
The generic DSA backend consumes a layer-compact token-major cache view, while GLM5Next requires a block-outermost view for its pooled index tail. Declare those contracts independently so layout resolution cannot select a shape that produces invalid attention output.

Assisted-by: OpenAI Codex
Signed-off-by: derek <derek.yates@live.com>
Give the shared GLM-5.2/5.3 DSA architecture an explicit B12X backend contract for its 368-byte NVFP4-latent plus FP8-RoPE cache record. Keep GLM5Next on its independent 304-byte no-RoPE ABI and reject unrelated 576-wide sparse MLA models.

Use the B12X 1.3 public cache writer and explicit GLM_NSA run recipe without environment-controlled layout selection.

Assisted-by: OpenAI Codex
Signed-off-by: derek <derek.yates@live.com>
Signed-off-by: derek <derek.yates@live.com>
Assisted-by: OpenAI Codex
…pare/jj-glm-nvfp4

Signed-off-by: derek <derek.yates@live.com>

# Conflicts:
#	tests/v1/attention/test_b12x_sparse_mla_api.py
#	vllm/v1/attention/backends/mla/b12x_mla_sparse.py
Assisted-by: OpenAI Codex
Signed-off-by: derek <derek.yates@live.com>
Pass the resolved cache recipe into B12X caps, bind the concrete KV cache against it, select the FP8 or NVFP4 writer at construction, and stop resending recipe policy on every decode or prefill call.

Assisted-by: OpenAI Codex

Signed-off-by: derek <derek.yates@live.com>
…3-nvfp4-auto-geometry-review

# Conflicts:
#	tests/v1/attention/test_b12x_sparse_mla_api.py
…uncate the load boundary

update_state_after_alloc scans the allocated block list for the first block that
is not null and has no hash, and treats that index as the start of the freshly
allocated region. That index drives keys_to_load (via start_chunk_idx),
dst_block_ids, group_sizes and block_indices, so getting it wrong loads the
wrong keys into the wrong destination blocks.

The scan started at index 0, inside the region the scheduler had already
reported as locally computed. Blocks there are computed by definition, so
scanning them can only do harm -- and for a recurrent group it does. A Mamba /
GDN group has no per-token KV at all: it carries a fixed-size state, which is
why get_sliding_window_size_in_chunks() returns 1 for MambaSpec ("Mamba depends
on a single state"). Most positions in its block table point at the shared null
sentinel, and the one real block holding the state is legitimately not
full-and-cached. The scan took that as the start of the fresh region, collapsed
the boundary below the computed mark, and the following assert fired.

Start the scan at the locally computed boundary instead. For a full-attention
group this is a no-op: every token has KV, every block below the boundary is
full-and-cached, so the old scan skipped them anyway. The existing assert now
holds by construction (nlcgb >= cdiv(nlct, tpb) implies nlct <= nlcgb * tpb) and
is kept as a guard for other causes.

Reproduced on a 4-node GB200 deployment (Qwen3.5-family hybrid GDN+GQA, 4 KV
cache groups, 3 recurrent, MTP): under sustained partial-hit load the leader
crashed after 47,142 requests, exit=1 with this assert while the other three
ranks exited 137 on gang teardown. Partial hits immediately preceding: 12768,
6384, 8512, 6384, 4256 offloaded tokens.

Reachable only when num_external_tokens > 0 AND num_locally_computed_tokens > 0,
i.e. a partial hit. Tests that flood to full eviction before re-sending produce
num_computed_tokens == 0, where the assert reads 0 <= X and cannot fire; the
same deployment ran clean and idle for 3h47m immediately before the load.

Independent of the drafter-annotation defect in vllm-project#52735/vllm-project#52771: the crash above
was observed with vllm-project#52771 applied, no group marked as a drafter, and the
volatile-tail pop therefore never running.

Signed-off-by: Yifan Jiang <yifanjiang1997@gmail.com>
… under spec decode

Two deterministic defects on the spec-decode + hybrid-mamba + KV-connector
path:

1. Offloading connector marked every KV group as eagle under DFlash/DSpark.
   `SchedulerOffloadConfig` fell back to `use_eagle()` when no group carried
   `is_eagle_group`, flagging all groups (including the target's mamba
   group) as volatile and excluding the trailing chunk of every decode step
   from offloading, so the store/lookup windows drift. Use the precise
   `use_eagle_preserves_target_kv_cache()` capability bit
   (eagle/eagle3/mtp only) for the fallback.

2. `SlidingWindowManager.find_longest_cache_hit()` assert-crashed the engine
   when the coordinator alignment was finer than the sliding-window group's
   block size (`alignment_tokens % block_size != 0`, e.g. `prefix_match_unit`
   finer than the draft model's SWA block). Fall back to block-aligned hits
   for that group instead of asserting.

3. Regression test for the SWA group fallback.

Tests:
- pytest tests/v1/core/test_mamba_align_chunk_split.py -q
- pytest tests/v1/core/test_scheduler.py -q -k mamba_align

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: ouzq <ouzq@seu.edu.cn>
…che block

SpeculativeConfig.use_eagle() is a stand-in for "spec decode that reads
target hidden states" and returns True for dflash/dspark too. The scheduler
used it in _mamba_block_aligned_split() to back last_cache_position off by
one mamba block, but only eagle-family drafters (eagle/eagle3/mtp) pollute
the target's last matching full-attention block with the lookahead KV write;
DFlash/DSpark draft via block diffusion from their own KV cache and never
write target blocks.

The spurious back-off made every prompt shorter than two mamba blocks skip
the final block-aligned chunk, so the mamba recurrent state never
materialized on a block boundary and the next turn's prefix-cache lookup
converged to 0 -> the whole context was recomputed on every reply.

Add SpeculativeConfig.use_eagle_preserves_target_kv_cache() (eagle/eagle3/
mtp) and drive the scheduler's last-block drop and the KV cache manager's
eagle handling with it. use_eagle() keeps its existing semantics (encoder
shift, lookahead budget, num_prefill_lookahead); only the prefix-cache
last-block drop is scoped precisely.

Tests:
- pytest tests/v1/core/test_mamba_align_chunk_split.py -q
- pytest tests/v1/core/test_scheduler.py -q -k mamba_align

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: ouzq <ouzq@seu.edu.cn>
…LE spec decode

Fixes vllm-project#52735. Three defects in the offloading connector scheduler combined
to make the CPU offload tier store KV but never serve it when speculative
decoding is enabled:

1. When an eagle-family speculative method is active but no KV-cache group
   is annotated as a drafter group — the normal situation for shared-group
   MTP models like Qwen3.5/3.8, whose drafter is a regular full-attention
   decoder layer merged into a target group — a fallback marked EVERY group
   as a drafter group. Drafter KV served stale can only lower speculative
   acceptance (the target verifies every draft), so fail toward serving:
   mark nothing and log once.

2. The volatile-trailing-chunk pop in _lookup_complete_chunks widened its
   query only for sliding-window groups. For full-attention drafter groups
   the pop shrank the confirmed boundary below what was queried, which can
   drop it under a coarser sibling group's chunk granularity (e.g. a
   mamba-align group) and zero the whole request's hit. Widen the query for
   every drafter group so the pop lands on the extra queried chunk.

3. The store-side trailing-chunk exclusion for drafter groups persisted
   after the request finished, permanently losing the final chunk of every
   drafter group per request. Once finished, no spec-token rejection can
   rewrite the tail, so the exclusion is lifted at finish. The lookup-side
   pop still prevents the (possibly volatile) final stored chunk from ever
   being served directly.

Unit repro: with a full-attention + mamba-align hybrid and a manager that
only hits stored keys, a re-sent prompt served 0 tokens from the offload
tier with MTP on vs 16 with MTP off; all three regression tests fail on
main and pass with this change. Full offloading connector suite passes.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Kam Basra <kameldipbasra@gmail.com>
@yatesdr
yatesdr requested a review from mgoin as a code owner September 2, 2026 14:17
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 655a4536-6a45-4bab-a445-657b74505176

📥 Commits

Reviewing files that changed from the base of the PR and between 9c4dd05 and 1c2b1bc.

📒 Files selected for processing (21)
  • tests/models/test_glm5next_pooled_indexer.py
  • tests/v1/attention/test_b12x_sparse_mla_api.py
  • tests/v1/core/test_kv_cache_utils.py
  • tests/v1/core/test_kv_connector_block_state.py
  • tests/v1/core/test_mamba_align_chunk_split.py
  • tests/v1/core/test_scheduler.py
  • tests/v1/kv_connector/unit/offloading_connector/test_scheduler.py
  • tests/v1/kv_connector/unit/offloading_connector/utils.py
  • vllm/config/cache.py
  • vllm/config/speculative.py
  • vllm/config/vllm.py
  • vllm/distributed/kv_transfer/kv_connector/v1/offloading/scheduler.py
  • vllm/model_executor/layers/attention/mla_attention.py
  • vllm/models/deepseek_v32/attention.py
  • vllm/models/glm5next/nvidia/pooled_indexer.py
  • vllm/platforms/interface.py
  • vllm/utils/torch_utils.py
  • vllm/v1/attention/backends/mla/b12x_mla_sparse.py
  • vllm/v1/core/sched/output.py
  • vllm/v1/core/sched/scheduler.py
  • vllm/v1/core/single_type_kv_cache_manager.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@logprobz

logprobz commented Sep 2, 2026

Copy link
Copy Markdown

Scoped review of the cache-semantics part of 1c2b1bc (DFlash no longer treated as EAGLE by the prefix cache); the NVFP4 stack is not covered here. Merged with #596/#560 onto 9c4dd05 cleanly and run in the r15 image. #556 conflicts with this head in three NVFP4/B12X sparse-MLA files (tests/v1/attention/test_b12x_sparse_mla_api.py, vllm/models/glm5next/nvidia/pooled_indexer.py, vllm/v1/attention/backends/mla/b12x_mla_sparse.py) because its branch predates 9c4dd05's B12X contracts; the validation tree takes this head's side there, and the cache-semantics files merge without conflict.

The DFlash no-drop changes what the LP15 profile reuses; please back it with a live equivalence run

use_eagle_preserves_target_kv_cache() (vllm/config/speculative.py:1880) is false for DFlash, so drop_last_prefix_cache_block (vllm/v1/core/sched/scheduler.py:345-347) is false, KVCacheManager is built with use_eagle=False (:364) and _mamba_block_aligned_split (:500-507) stops backing off one block. Effect on the LP15 shape (hybrid MLA + Mamba align + SWA draft group; the resolved scheduler block size is the recorded 2304, from production's pinned --block-size 256): a turn extending a 122871-token cached history now hits 122112 tokens on every group. With the drop on, the same shape hits 119808 when prefix_cache_retention_interval=2304 and 0 at LP15's pinned retention of 0, so on LP15 as configured today the change is 0 to 122112 per turn; that is the right outcome if the claim holds. One caveat: no record pins the production hash block size, and under those flags resolve_kv_cache_block_sizes derives it as the gcd of the group sizes (256), so the probe (which assumes hash equals scheduler size, 2304) is a coarse-hash model of LP15; the live run below settles the real numbers.

Two things the code alone does not settle:

  1. The base docstring gives a different reason for the drop than this PR does. vllm/v1/core/single_type_kv_cache_manager.py:561-562 says the last block is recomputed "to get the required hidden states for eagle drafting head"; the new comment in _mamba_block_aligned_split says eagle-family drafters "pollute the target's last matching full-attention block with their lookahead KV write". DFlash builds its context K/V from target hidden states (vllm/v1/spec_decode/dflash.py, precompute_and_store_context_kv on _dflash_hidden_states) and writes both its context and its query K/V through the draft group's own slot mapping (both mappings are computed from the draft group's block table, dflash.py:167-172), so the pollution argument holds for the target group; the hidden-states argument would apply to DFlash too if the drafter ever needs target states for tokens the target did not recompute. If the docstring is stale, please update it in this PR so the two rationales agree.

  2. All LP15 evidence so far was gathered with the drop on (fix(hybrid): preserve cache reuse and decode under prefill pressure #583 and base). Before this lands on dev/jovian-judgement, a live check that greedy outputs with a warm prefix (second turn hitting 122112) match cold-prefix outputs on the LP15 profile would close it; it also settles the hash-granularity caveat above. That can run on the LP15 station once an image with this head exists.

One test break to fix before merge

tests/v1/core/test_prefix_caching.py:1089 still sets use_eagle=False on the SimpleNamespace scheduler mock, but scheduler.py:506 now reads drop_last_prefix_cache_block, so test_hybrid_cache_mamba_align_shared_prefix_detection dies with AttributeError on this head and passes on base. Renaming the field in the mock fixes it. The merged validation tree shows the same failure, so it is not a merge artifact.


This review was written by Claude Fable 5.1 (Anthropic) and posted by me.

@voipmonitor

Copy link
Copy Markdown

Integration qualification and merge status

Status: the exact PR head is qualified as an ancestor of the R20 composed
source; direct merge requires conflict resolution
.

voipmonitor/vllm:jovian-judgement-community-20260903-r20 exercised this
PR's packed GLM_NEXT cache, split cache geometry, exact recurrent boundaries,
native offload, prefix reuse, and LMCache integration on four stock-clock RTX
PRO 6000 Blackwell Workstation Edition GPUs.

Qualification covered:

  • FP8 and NVFP4 target cache formats;
  • TP4/DCP1 and TP4/DCP4;
  • cold compute, vLLM automatic prefix reuse, LMCache DRAM restore, and
    filesystem restore after restarting both vLLM and the LMCache sidecar;
  • byte-for-byte restored-page comparison on every TP rank;
  • no-speculation, MTP3, and DFlash2 C1, C8, and 32K-prefill cells;
  • a 54,639-token cold DCP4 request at GPU_MEMORY_UTILIZATION=0.93.

GitHub reports that this PR conflicts with dev/jovian-judgement. The exact
head remains a qualified source component, but a conflict-resolved tree is a
different artifact. Re-run the focused cache tests, cold/APC/L1/restart-L2
matrix, and serving regression cells after resolving that conflict. Preserve
the imported authors during the port.

The performance values and immutable image identity are recorded in #590.

@lukealonso
lukealonso merged commit 91e4884 into local-inference-lab:dev/jovian-judgement Sep 4, 2026
2 of 3 checks passed
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.

6 participants