Skip to content

Feat: add DeepSeek V4 Flash prefill context parallelism - #889

Open
sjduan wants to merge 4 commits into
hw-native-sys:mainfrom
sjduan:dsv4-prefill-cp-baseline
Open

Feat: add DeepSeek V4 Flash prefill context parallelism#889
sjduan wants to merge 4 commits into
hw-native-sys:mainfrom
sjduan:dsv4-prefill-cp-baseline

Conversation

@sjduan

@sjduan sjduan commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Add correctness-first context-parallel prefill support for DeepSeek V4 Flash.

  • Add Zigzag context ownership and CP2/CP4/CP8 KV-tail exchange.
  • Add standalone CP attention paths for SWA, ratio-128 HCA, and ratio-4 CSA.
  • Add shared CP exchange seams for projected tails, compact compressed/state records, and sparse-source staging.
  • Keep baseline QKV/RoPE, compressor, indexer, sparse-attention, and HC math as the source of truth.
  • Consolidate HCA/CSA communication helpers in prefill_exchange_cp.py.
  • Rename attention entry files to the mode-first convention.

Design

  • Cross-rank work is wave-major only at communication boundaries; rank-local math relies on tensor dependencies.
  • Each rank owns two Zigzag segments and keeps temporary projection/staging tensors inside the rank child.
  • Persistent cache/state roots use receiver-local physical lowering and a single writer.
  • Sparse-attention math remains a fixed 128-row child instead of receiving the rank-local orchestration shape.
  • HCA exchanges ratio-128 compressed rows and final compressor state after local completion.
  • CSA uses a coarse correctness boundary across the main ratio-4 compressor and inner indexer compressor before publishing compact cache/state records.

Shared baseline seams

  • prefill_compressor_ratio4.py: completion-aware CP composition without changing the standalone path.
  • prefill_indexer_compressor.py: completion-aware inner-compressor composition.
  • prefill_indexer.py: CP score/top-k composition for receiver-local index history.
  • prefill_sparse_attn.py: fixed-row sparse math and source-staging constants used by CP.
  • prefill_csa.py: shared completion/indexer seams while preserving baseline behavior.

Latest stabilization

  • Preserve statically inferable child tensor metadata with explicit fixed-shape pl.slice boundaries.
  • Keep HCA/CSA state and compressed-cache roots as InOut, and capture compressor SSA returns before assembling them into the parent tensors.
  • Keep the Zigzag host launch on direct rank slices while running standalone epoch communication inside the incore child, avoiding sliced nested-JIT arguments and TileType communication sources.
  • Use explicit GM load/store for exchanged window rows.
  • Align CSA index-cache comparison with the standalone indexer's INT8 quantization contract.
  • Fix the BF16/INT8 indexer local-name collision exposed by newer PyPTO type checking.
  • Restore repository-standard copyright headers and remove unused imports.

Validation

Final CP2/CP4 runtime and golden matrix

Path CP Task Build Result
Zigzag 2 task_20260803_051602_231811720024 _jit_prefill_cp_zigzag_kv_tail_exchange_test_20260803_051605 PASS
Zigzag 4 task_20260803_051636_234358831874 _jit_prefill_cp_zigzag_kv_tail_exchange_test_20260803_051639 PASS
SWA 2 task_20260803_051716_23785312097 _jit_prefill_cp_swa_test_20260803_051720 PASS
SWA 4 task_20260803_051822_258260720944 _jit_prefill_cp_swa_test_20260803_051827 PASS
HCA 2 task_20260803_052256_307288431301 _jit_prefill_cp_hca_test_20260803_052301 PASS
HCA 4 task_20260803_052414_33836153137 _jit_prefill_cp_hca_test_20260803_052421 PASS
CSA 2 task_20260803_053158_121001810760 _jit_prefill_cp_csa_test_20260803_053204 PASS
CSA 4 task_20260803_053344_158081518768 _jit_prefill_cp_csa_test_20260803_053350 PASS

All expected output comparisons passed, including x_out, kv_cache, and path-specific persistent cache/state outputs. No 507018 or HCCL stall was observed.

CP8 bring-up coverage

Path Coverage Result
SWA representative zero-history case PASS
HCA state block-table permutation PASS
CSA ratio-4 cross-segment boundary PASS

Shared standalone paths

Entry Compared outputs Result
ratio-4 compressor compressed KV and compressor state PASS
indexer compressor index KV/scale and inner state PASS
indexer score, top-k, index KV/scale PASS
sparse attention attention output PASS
baseline SWA/HCA/CSA attention x_out and kv_cache PASS

Local checks

  • Python compilation for all files touched by the stabilization commit: PASS.
  • Repository copyright-header, English-only, and public-doc checks: PASS.
  • git diff --check: PASS.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

DeepSeek V4 Flash attention paths

Layer / File(s) Summary
Module renames and integration wiring
docs/..., models/deepseek/v4-flash/decode_*, models/deepseek/v4-flash/prefill_*
Documentation, imports, and fixture references now use the renamed SWA, HCA, and CSA modules.
Decode attention implementations
models/deepseek/v4-flash/decode_swa.py, decode_hca.py, decode_sparse_attn_csa.py
Adds SWA and HCA decode pipelines and a CSA sparse-attention implementation with golden references, fixtures, and CLI validation.
Prefill scheduling and sparse-attention core
models/deepseek/v4-flash/prefill_compressor_ratio4.py, prefill_indexer.py, prefill_indexer_compressor.py, prefill_sparse_attn.py, prefill_csa.py
Adds completion-aware compressor scheduling, CP indexer scoring, and staged sparse-attention processing.
Context-parallel exchange foundations
models/deepseek/v4-flash/prefill_exchange_cp.py, prefill_zigzag_cp.py
Adds distributed tail exchange, compact cache/state transport, sparse staging, ownership mapping, and synchronization.
Context-parallel prefill implementations
models/deepseek/v4-flash/prefill_*_cp.py
Adds CP SWA, HCA, and CSA prefill kernels with metadata construction, host wrappers, golden paths, fixtures, and CLI validation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

Suggested labels: enhancement

Poem

A rabbit hops through caches bright,
Compressing tails by moonlit light.
SWA, HCA, and CSA align,
While sparse rows march in a parallel line.
New paths compile, compare, and run—
The burrow celebrates work done!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: adding DeepSeek V4 Flash prefill context parallelism.
Description check ✅ Passed The description directly explains the context-parallel prefill features, design, renames, and validation results.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
models/deepseek/v4-flash/prefill_indexer_compressor.py (1)

347-393: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add an explicit dependency from prefill_idx_c4_scale_scatter to cache_write_tid.

scale_scratch is written inside the prefill_idx_c4_cache_write SPMD task at line 368. The prefill_idx_c4_scale_scatter block at line 382 reads scale_scratch but declares no deps. The producer task id cache_write_tid is already in scope and is only used later at line 425 for the completion signal.

If the scheduler does not derive this read-after-write edge automatically, the scatter can publish stale or uninitialized dequantization scales into idx_kv_scale. That corrupts the C8 indexer cache while the INT8 rows stay correct, which makes the defect hard to trace.

🔒️ Proposed fix to order the scale scatter after the cache write
-    with pl.at(level=pl.Level.CORE_GROUP, name_hint="prefill_idx_c4_scale_scatter") as scale_scatter_tid:
+    with pl.at(
+        level=pl.Level.CORE_GROUP,
+        name_hint="prefill_idx_c4_scale_scatter",
+        deps=[cache_write_tid],
+    ) as scale_scatter_tid:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_indexer_compressor.py` around lines 347 -
393, Add an explicit dependency on cache_write_tid to the
prefill_idx_c4_scale_scatter task declaration so it waits for the producer that
writes scale_scratch. Preserve the existing scale scatter logic and dependency
behavior for all other tasks.
🧹 Nitpick comments (14)
models/deepseek/v4-flash/prefill_csa.py (1)

251-259: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark the unused indexer outputs as intentional.

Ruff RUF059 reports idx_kv_cache_out and idx_kv_scale_out as unused. If prefill_indexer updates idx_kv_cache and idx_kv_scale in place, use underscore-prefixed bindings.

Suggested binding change
-    idx_kv_cache_out, idx_kv_scale_out, idx_score_unused, cmp_topk_indices = prefill_indexer(
+    _idx_kv_cache_out, _idx_kv_scale_out, idx_score_unused, cmp_topk_indices = prefill_indexer(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_csa.py` around lines 251 - 259, Update the
assignment receiving outputs from prefill_indexer so the intentionally unused
idx_kv_cache_out and idx_kv_scale_out bindings use underscore-prefixed names,
while preserving the remaining outputs and call behavior.

Source: Linters/SAST tools

models/deepseek/v4-flash/prefill_swa_cp.py (2)

502-510: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The loop variable tail_start shadows the module-level tail_start function.

Line 502 binds tail_start to a scalar inside prefill_cp_swa. Line 142 defines tail_start(seg_start, seg_len) at module scope. The function is not called later in this kernel, so the shadowing is currently harmless.

Rename the local to tail_start0, matching tail_offset0 in prefill_hca_cp.py line 646. That prevents a confusing failure if this kernel later needs the helper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_swa_cp.py` around lines 502 - 510, Rename
the local scalar `tail_start` in `prefill_cp_swa` to `tail_start0`, and update
its use when computing `tail_offset`; preserve the existing tail-copy behavior
while avoiding shadowing the module-level `tail_start` helper.

642-644: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align build_tensor_specs with the sibling CP modules and add the cp_size guard.

This builder returns (specs, ctx) at line 704 and the __main__ block installs golden_prefill_cp_swa._ctx externally at line 854. prefill_csa_cp.py line 1007 and prefill_hca_cp.py line 1546 instead set _ctx inside the builder and return only the spec list. A shared harness that calls build_tensor_specs uniformly across these modules will break on this one.

This builder also omits the cp_size guard. prefill_hca_cp.py lines 1309-1312 and prefill_csa_cp.py lines 639-642 raise when the runtime cp_size differs from the import-time CP_SIZE. Here, build_metadata(args.cp) would build metadata for one CP size while the compiled kernel shapes use another.

Set _ctx inside build_tensor_specs, return only specs, and raise when cp_size != CP_SIZE.

♻️ Proposed change
 def build_tensor_specs(cp_size: int = CP_SIZE):
+    if cp_size != CP_SIZE:
+        raise ValueError(
+            f"runtime cp_size={cp_size} does not match static CP_SIZE={CP_SIZE}"
+        )
     meta, ctx = build_metadata(cp_size)
     specs.append(TensorSpec("x_out", list(x.shape), torch.float32, is_output=True))
-    return specs, ctx
+    golden_prefill_cp_swa._ctx = ctx
+    return specs
-    specs, ctx = build_tensor_specs(args.cp)
-    golden_prefill_cp_swa._ctx = ctx
     result = run_jit(
         fn=prefill_cp_swa_test,
-        specs=specs,
+        specs=build_tensor_specs(args.cp),
         golden_fn=golden_prefill_cp_swa,

Also applies to: 836-854

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_swa_cp.py` around lines 642 - 644, Update
build_tensor_specs to reject any cp_size that differs from the import-time
CP_SIZE before building metadata, set golden_prefill_cp_swa._ctx within the
builder, and return only specs. Adjust the __main__ block to use the builder’s
new return contract without externally installing _ctx.
models/deepseek/v4-flash/prefill_hca_cp.py (2)

647-662: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Collapse the no-op branch in cp_hca_tail_assemble.

Both arms of the if tail_offset < TAIL_ROWS branch compute the same source expression. The branch has no effect.

The layout is already correct: tiles of one part are contiguous, so part * MAX_SEGMENT_TILES * TAIL_ROWS + tail_offset addresses tile 0 for tail_offset < TAIL_ROWS and tile 1 above it. The branch reads as an unfinished edit and invites a wrong "fix" later.

The equivalent code in prefill_swa_cp.py lines 506-509 has the same redundancy in a different form (TAIL_ROWS + tail_offset - TAIL_ROWS). Simplify both.

♻️ Proposed simplification
             for row in pl.range(TAIL_ROWS):
                 tail_offset = tail_offset0 + row
                 if tail_offset < total:
-                    if tail_offset < TAIL_ROWS:
-                        source = (
-                            part * MAX_SEGMENT_TILES * TAIL_ROWS
-                            + tail_offset
-                        )
-                    else:
-                        source = (
-                            part * MAX_SEGMENT_TILES * TAIL_ROWS
-                            + tail_offset
-                        )
+                    # Tiles of one part are contiguous, so the offset indexes directly.
+                    source = part * MAX_SEGMENT_TILES * TAIL_ROWS + tail_offset
                     destination = part * TAIL_ROWS + row
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_hca_cp.py` around lines 647 - 662, In
cp_hca_tail_assemble, remove the redundant if/else around source and assign it
directly using part * MAX_SEGMENT_TILES * TAIL_ROWS + tail_offset. Apply the
same simplification to the corresponding tail assembly logic in
prefill_swa_cp.py, preserving the existing contiguous tile layout and indexing
behavior.

1313-1314: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Two metadata builders produce overlapping fixture data.

build_hca_metadata at line 322 and _build_raw_attention_metadata at line 169 both recompute prefix, span, lengths, starts, owners, and query_positions from the same inputs. device_values at lines 1501-1523 then mixes the two sources: query_positions comes from raw_metadata, while segment_starts_t, cmp_indices, and segment_tail_positions come from metadata.

The two query_positions tensors also differ in their inactive fill: _build_raw_attention_metadata uses 0 at line 177 and build_hca_metadata uses -1 at line 335. The kernel only reads active rows, so today this is benign, but the split makes the fixture contract hard to audit.

Derive the shared segment geometry once and pass it to both builders.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_hca_cp.py` around lines 1313 - 1314, Derive
the shared segment geometry once before the metadata construction in the fixture
setup, then pass that geometry into both build_hca_metadata and
_build_raw_attention_metadata instead of recomputing prefix, span, lengths,
starts, owners, and query_positions independently. Update both builder
signatures and their callers, and ensure device_values uses fields from this
single consistent geometry source.
models/deepseek/v4-flash/prefill_zigzag_cp.py (1)

33-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Export _parse_static_int instead of copying it into prefill_swa_cp.py.

prefill_swa_cp.py lines 75-82 define an identical _parse_static_int and then derive its own CP_SIZE from CP_DEFAULT, which it already imports from this module. Two independent argv scans can disagree if the parsing rule ever changes.

Import this helper in prefill_swa_cp.py, or import CP_SIZE directly since both modules derive the same value from the same flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_zigzag_cp.py` around lines 33 - 43, Export
and reuse the existing _parse_static_int helper from prefill_zigzag_cp.py in
prefill_swa_cp.py, removing the duplicate implementation and deriving CP_SIZE
through the shared parser (or importing CP_SIZE directly). Ensure both modules
use one consistent --cp argument parsing rule.
models/deepseek/v4-flash/prefill_csa_cp.py (1)

271-289: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

_build_metadata_tensors computes a large unused result, and it hides the only capacity check.

build_tensor_specs at line 643 unpacks metadata, ctx and then reads only four entries: compress_state_block_table, inner_compress_state_block_table, cmp_block_table, and idx_block_table. All four come from _build_block_tables. Ruff also reports that ctx is never used.

Two consequences:

  1. Lines 292-483 build boundary_positions, seed_*, main_slot_mapping, idx_slot_mapping, final_*_state_mapping, dense_cmp_prefix, and dense_idx_prefix that no spec consumes. Lines 896-955 then recompute the equivalent leaf slot mappings with the same _lower_row rule. The two derivations can drift apart, and only the second one reaches the kernel.
  2. validate_cp_indexer_capacity at line 289 runs only as a side effect of this otherwise-unused function. If someone removes the dead branch, the capacity guard disappears silently.

Reduce _build_metadata_tensors to the tables and context that build_tensor_specs actually consumes, and call validate_cp_indexer_capacity from build_tensor_specs directly.

Also applies to: 643-643

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_csa_cp.py` around lines 271 - 289, Reduce
_build_metadata_tensors to return only the metadata tables and context entries
consumed by build_tensor_specs, removing the unused boundary, seed,
slot-mapping, state-mapping, and dense-prefix calculations. Move
validate_cp_indexer_capacity out of _build_metadata_tensors and invoke it
directly from build_tensor_specs, preserving the existing capacity validation
behavior independently of metadata construction.

Source: Linters/SAST tools

models/deepseek/v4-flash/prefill_exchange_cp.py (1)

478-623: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

_prefill_cp_sparse_stage still duplicates _cp_swa_stage_sources.

This helper and _cp_swa_stage_sources in prefill_swa_cp.py lines 294-379 implement the same persistent/predecessor/current overlay lowering. The gather loop, the overlay index derivation, and the bias build are line-for-line equivalent. This helper adds the compressed-index branch at lines 564-577 and the valid-mask build at lines 603-621; the SWA copy omits both.

The PR objective states that exchange logic is consolidated into prefill_exchange_cp.py, so the SWA copy is an outlier. The SWA path can call _prefill_cp_sparse_stage with IDX_TOPK-wide cmp_indices filled with -1, which makes the compressed branch inert and produces the same valid mask.

This is deferable, but it prevents the two overlay lowerings from diverging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_exchange_cp.py` around lines 478 - 623,
Refactor the SWA path to reuse _prefill_cp_sparse_stage instead of maintaining
the duplicate _cp_swa_stage_sources implementation in prefill_swa_cp.py. Supply
IDX_TOPK-wide cmp_indices initialized to -1 and the required compressed-stage
buffers so the compressed branch remains inert, while preserving the existing
SWA outputs and overlay behavior.
models/deepseek/v4-flash/prefill_indexer.py (1)

379-482: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Consider extracting the shared query-preparation pipeline.

Lines 379-482 of _prefill_indexer_cp_score_topk repeat the body of prefill_indexer lines 148-253 almost verbatim: the qr_proj INT8 GEMM and dequantization, the interleaved RoPE table materialization, the swap-index build, the per-token RoPE rotation, the Hadamard multiply, and the per-row INT8 quantization. Only the name_hint strings differ.

Extract one @pl.jit.inline helper that returns qr_hadamard_i8 and qr_hadamard_scale_dq, and give it a name_prefix argument for the task hints. That keeps the two scoring paths from drifting when the quantization math changes.

This is deferable if you prefer to land the CP path first, but track it: the same block already exists in three copies across the CP modules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_indexer.py` around lines 379 - 482, Extract
the duplicated query-preparation pipeline from `_prefill_indexer_cp_score_topk`
and `prefill_indexer` into one `@pl.jit.inline` helper that returns
`qr_hadamard_i8` and `qr_hadamard_scale_dq`. Move the shared
projection/dequantization, RoPE preparation and rotation, Hadamard
multiplication, and per-row INT8 quantization into the helper, using a
`name_prefix` parameter to generate task-specific `name_hint` values, then
replace each duplicated block with the helper call.
models/deepseek/v4-flash/decode_sparse_attn_csa.py (4)

52-57: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the duplicate MAX_SEQ_LEN assignment.

Line 39 already sets MAX_SEQ_LEN = M.max_position_embeddings. Line 54 repeats the same assignment inside the CSA masking block, where the preceding comment describes compressed-slot masking. The duplicate suggests a different value is intended here.

♻️ Proposed cleanup
 # CSA compressed-slot masking (folded in from the CSA orchestrator): raw indexer
 # topk -> per-token bound floor((pos + 1) / COMPRESS_RATIO).
-MAX_SEQ_LEN = M.max_position_embeddings
 INDEXER_SCORE_LEN = MAX_SEQ_LEN // 4
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 52 - 57,
Remove the duplicate MAX_SEQ_LEN assignment from the CSA compressed-slot masking
block, while retaining the existing assignment near line 39. Keep
INDEXER_SCORE_LEN and the remaining CSA constants using the shared MAX_SEQ_LEN
value.

690-710: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename the loop variable to avoid shadowing the masked tensor.

raw is bound at Line 670 to the masked indexer tensor. Both loops here rebind raw to a plain int. The tensor is not read after Line 673, so the result is correct, but the reuse makes the masking block harder to follow.

♻️ Proposed rename
-        for raw in window_swa_indices[t].tolist():
-            slot = int(raw)
+        for win_slot_raw in window_swa_indices[t].tolist():
+            slot = int(win_slot_raw)
@@
-        for raw in cmp_sparse_indices[t].tolist():
-            if raw < 0:
+        for cmp_slot_raw in cmp_sparse_indices[t].tolist():
+            if cmp_slot_raw < 0:
                 kv_rows.append(torch.zeros(HEAD_DIM, dtype=ori_kv.dtype))
                 valid.append(False)
                 continue
-            cmp_slot = int(raw)
+            cmp_slot = int(cmp_slot_raw)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 690 - 710,
Rename the loop variable raw in both index-iteration loops to distinct
descriptive names, updating each corresponding reference while preserving the
existing index handling and masking behavior.

542-545: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Hoist the T_PAD zero-fill out of the token loop.

This block sits inside for qt in pl.pipeline(0, T, QUANT_TOKEN_TILE, ...). It writes the same constant zeros to the same padding rows on every token tile, so it repeats T // QUANT_TOKEN_TILE times. The result is correct, but the work is redundant. The padding rows do not depend on qt.

♻️ Proposed refactor
                     o_r_i8_pad = pl.assemble(o_r_i8_pad, oq_i8, [qt, col_g])
-                    if T_PAD > T:
-                        zero_half = pl.full([T_PAD - T, O_LORA], dtype=pl.FP16, value=0.0)
-                        zero_i8 = pl.cast(zero_half, target_type=pl.INT8, mode="trunc")
-                        o_r_i8_pad = pl.assemble(o_r_i8_pad, zero_i8, [T, col_g])
+                if T_PAD > T:
+                    zero_half = pl.full([T_PAD - T, O_LORA], dtype=pl.FP16, value=0.0)
+                    zero_i8 = pl.cast(zero_half, target_type=pl.INT8, mode="trunc")
+                    o_r_i8_pad = pl.assemble(o_r_i8_pad, zero_i8, [T, col_g])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 542 - 545,
Move the T_PAD padding initialization out of the for qt token-loop and perform
it once before the loop, preserving the existing zero_half, zero_i8, and
o_r_i8_pad assembly behavior for T_PAD > T. Keep token-dependent processing
inside the loop and ensure the padding rows remain unchanged for every tile.

316-337: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Consider bulk-run detection for the window gather.

This loop issues one pl.gather_row per sparse-K row, 128 rows per work item. The sibling kernels avoid that for the window prefix. decode_sparse_attn_swa.sparse_attn_swa and decode_sparse_attn_hca.sparse_attn_hca probe the first and last slot of a GATHER_RUN sub-tile, and copy the whole run as one bulk transfer when the endpoints are GATHER_RUN - 1 apart. Window slots are contiguous in the common case, so the same probe applies here.

This changes scheduling only, not results. Treat it as deferrable if the current profile is acceptable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 316 - 337,
Optimize the window-prefix path in the loop around qk_kv by detecting contiguous
GATHER_RUN sub-tiles, probing the first and last window slots as in
decode_sparse_attn_swa.sparse_attn_swa and
decode_sparse_attn_hca.sparse_attn_hca, and using one bulk gather when their
separation is GATHER_RUN - 1. Preserve the existing per-row gather and fallback
behavior for non-contiguous or invalid slots, without changing results for the
comparison-sparse path.
models/deepseek/v4-flash/decode_swa.py (1)

417-427: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Cache the SWA metadata to avoid recomputing the nested Python loop.

init_swa_indices and init_swa_lens each call init_swa_metadata, which runs swa_indices_and_lens. That helper loops over T * WIN elements with per-element .item() calls. It also rebuilds init_start_pos and init_block_table on every call. The values are deterministic, so the results stay consistent, but the fixture pays the cost twice.

♻️ Proposed refactor
-    def init_swa_metadata():
-        return swa_indices_and_lens(
-            position_ids_from_starts(init_start_pos(), seq=S),
-            init_block_table(),
-            block_size=BLOCK_SIZE,
-            window=WIN,
-        )
+    swa_metadata_cache = {}
+
+    def init_swa_metadata():
+        if "value" not in swa_metadata_cache:
+            swa_metadata_cache["value"] = swa_indices_and_lens(
+                position_ids_from_starts(init_start_pos(), seq=S),
+                init_block_table(),
+                block_size=BLOCK_SIZE,
+                window=WIN,
+            )
+        return swa_metadata_cache["value"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_swa.py` around lines 417 - 427, Cache the
result of init_swa_metadata so swa_indices_and_lens, init_start_pos, and
init_block_table execute only once. Update init_swa_indices and init_swa_lens to
reuse the cached metadata while preserving their respective contiguous outputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/models/deepseek.md`:
- Line 95: Update the entry-point table in the DeepSeek documentation to replace
the old *_attention_csa.py, *_attention_hca.py, and *_attention_swa.py
references with the renamed mode-first modules, including the applicable _cp
variants, while retaining prefill_csa.py where already correct.

In `@models/deepseek/v4-flash/decode_hca.py`:
- Around line 225-241: Update the top-k token iteration around topk_all so the
final partial HCA_TOPK_TOKEN_TILE is included rather than relying on a grid that
truncates the tail. Remove the ineffective topk_t < T guard or replace the loop
bounds with a ceil-divided token-block count, and ensure every token index below
T initializes its HCA_CMP_TOPK entries to valid compressed slots or -1
consistently with sparse_attn_hca expectations.
- Around line 13-14: Update the companion-file references in the module
docstring to use the renamed mode-first files decode_swa.py and decode_csa.py,
replacing the obsolete attention_swa.py and attention_csa_draft.py names.
- Around line 195-202: Add a module-level divisibility assertion for
HCA_WB_TOKEN_TILE, matching the guard style used in decode_sparse_attn_csa.py,
to ensure the configured T value is an exact multiple of HCA_WB_TOKEN_TILE
before the writeback loop runs. Preserve the existing writeback logic in the
hca_cache_writeback loop.
- Around line 273-276: Update attention_hca_test’s compressor-cache handling:
declare compress_state and cmp_kv as pl.InOut, and mark both corresponding
TensorSpecs with is_output=True and output comparison. Ensure
compressor_ratio128 and golden_compressor updates to these buffers are
validated.
- Around line 84-90: Replace HCA_CMP_TOPK usage with HCA_TOPK_LIMIT for the HCA
top-k bound, and add an assertion that HCA_TOPK_LIMIT is at least
get_standalone_cmp_valid(128). Do not reuse HCA_SPARSE_CMP_TOPK for this HCA
limit.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py`:
- Line 743: Update the zip call in the loop over block_mi, block_li, and
block_oi to pass strict=True, explicitly validating that all three iterables
have equal lengths while preserving the existing iteration behavior.
- Around line 256-264: Add an assertion alongside the existing tiling-invariant
checks in the module initialization/configuration validation to require WIN ==
ATTN_K_TILE. Keep the block-validity mapping in the loops using its current
offsets, and ensure invalid configurations fail before qk_pv executes.

In `@models/deepseek/v4-flash/decode_swa.py`:
- Around line 14-15: Update the module docstring’s companion file references to
use decode_csa.py and decode_hca.py instead of the renamed
attention_csa_draft.py and attention_hca_draft.py entries, preserving the
existing ratio annotations.

In `@models/deepseek/v4-flash/prefill_csa_cp.py`:
- Line 1973: Update the sparse_bias initialization in the prefill sparse
attention path to import FP32_NEG_INF from config and use it instead of the
literal -3.0e38, keeping the existing tensor shape, dtype, and initialization
behavior unchanged.

In `@models/deepseek/v4-flash/prefill_csa.py`:
- Around line 231-237: The sparse-attention launch following
`_prefill_compressor_ratio4_with_completion` must depend on the compressor write
completion before reading `cmp_kv`. Update the
`_prefill_sparse_attn_with_block_mask` call or its launch dependency arguments
to include `compressor_completion[0]`, preserving the same CP ordering behavior
used in `prefill_csa_cp.py`.

In `@models/deepseek/v4-flash/prefill_hca_cp.py`:
- Around line 784-807: Update the HCA compression flow around
prefill_compressor_ratio128 and cp_hca_pack_compact to collect the compressor
completion IDs for each launched leaf/state write, then pass or commission those
completions through the compact payload dependency path before
cp_hca_pack_compact reads leaf_cmp_flat and scratch_state_flat. Preserve the
existing buffer slicing and packing behavior while ensuring compact packing
waits on all compressor roots, matching the CSA ratio-4 caller’s dependency
handling.

In `@models/deepseek/v4-flash/prefill_swa_cp.py`:
- Around line 306-310: Populate valid_block_mask in prefill_cp_swa using the
same mask-construction logic as _prefill_cp_sparse_stage before invoking
_prefill_sparse_attn_math. Ensure every staged attention block row is enabled
according to the SWA CP staging inputs, rather than leaving nonzero rows masked
by the zero-initialized valid_mask.

---

Outside diff comments:
In `@models/deepseek/v4-flash/prefill_indexer_compressor.py`:
- Around line 347-393: Add an explicit dependency on cache_write_tid to the
prefill_idx_c4_scale_scatter task declaration so it waits for the producer that
writes scale_scratch. Preserve the existing scale scatter logic and dependency
behavior for all other tasks.

---

Nitpick comments:
In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py`:
- Around line 52-57: Remove the duplicate MAX_SEQ_LEN assignment from the CSA
compressed-slot masking block, while retaining the existing assignment near line
39. Keep INDEXER_SCORE_LEN and the remaining CSA constants using the shared
MAX_SEQ_LEN value.
- Around line 690-710: Rename the loop variable raw in both index-iteration
loops to distinct descriptive names, updating each corresponding reference while
preserving the existing index handling and masking behavior.
- Around line 542-545: Move the T_PAD padding initialization out of the for qt
token-loop and perform it once before the loop, preserving the existing
zero_half, zero_i8, and o_r_i8_pad assembly behavior for T_PAD > T. Keep
token-dependent processing inside the loop and ensure the padding rows remain
unchanged for every tile.
- Around line 316-337: Optimize the window-prefix path in the loop around qk_kv
by detecting contiguous GATHER_RUN sub-tiles, probing the first and last window
slots as in decode_sparse_attn_swa.sparse_attn_swa and
decode_sparse_attn_hca.sparse_attn_hca, and using one bulk gather when their
separation is GATHER_RUN - 1. Preserve the existing per-row gather and fallback
behavior for non-contiguous or invalid slots, without changing results for the
comparison-sparse path.

In `@models/deepseek/v4-flash/decode_swa.py`:
- Around line 417-427: Cache the result of init_swa_metadata so
swa_indices_and_lens, init_start_pos, and init_block_table execute only once.
Update init_swa_indices and init_swa_lens to reuse the cached metadata while
preserving their respective contiguous outputs.

In `@models/deepseek/v4-flash/prefill_csa_cp.py`:
- Around line 271-289: Reduce _build_metadata_tensors to return only the
metadata tables and context entries consumed by build_tensor_specs, removing the
unused boundary, seed, slot-mapping, state-mapping, and dense-prefix
calculations. Move validate_cp_indexer_capacity out of _build_metadata_tensors
and invoke it directly from build_tensor_specs, preserving the existing capacity
validation behavior independently of metadata construction.

In `@models/deepseek/v4-flash/prefill_csa.py`:
- Around line 251-259: Update the assignment receiving outputs from
prefill_indexer so the intentionally unused idx_kv_cache_out and
idx_kv_scale_out bindings use underscore-prefixed names, while preserving the
remaining outputs and call behavior.

In `@models/deepseek/v4-flash/prefill_exchange_cp.py`:
- Around line 478-623: Refactor the SWA path to reuse _prefill_cp_sparse_stage
instead of maintaining the duplicate _cp_swa_stage_sources implementation in
prefill_swa_cp.py. Supply IDX_TOPK-wide cmp_indices initialized to -1 and the
required compressed-stage buffers so the compressed branch remains inert, while
preserving the existing SWA outputs and overlay behavior.

In `@models/deepseek/v4-flash/prefill_hca_cp.py`:
- Around line 647-662: In cp_hca_tail_assemble, remove the redundant if/else
around source and assign it directly using part * MAX_SEGMENT_TILES * TAIL_ROWS
+ tail_offset. Apply the same simplification to the corresponding tail assembly
logic in prefill_swa_cp.py, preserving the existing contiguous tile layout and
indexing behavior.
- Around line 1313-1314: Derive the shared segment geometry once before the
metadata construction in the fixture setup, then pass that geometry into both
build_hca_metadata and _build_raw_attention_metadata instead of recomputing
prefix, span, lengths, starts, owners, and query_positions independently. Update
both builder signatures and their callers, and ensure device_values uses fields
from this single consistent geometry source.

In `@models/deepseek/v4-flash/prefill_indexer.py`:
- Around line 379-482: Extract the duplicated query-preparation pipeline from
`_prefill_indexer_cp_score_topk` and `prefill_indexer` into one `@pl.jit.inline`
helper that returns `qr_hadamard_i8` and `qr_hadamard_scale_dq`. Move the shared
projection/dequantization, RoPE preparation and rotation, Hadamard
multiplication, and per-row INT8 quantization into the helper, using a
`name_prefix` parameter to generate task-specific `name_hint` values, then
replace each duplicated block with the helper call.

In `@models/deepseek/v4-flash/prefill_swa_cp.py`:
- Around line 502-510: Rename the local scalar `tail_start` in `prefill_cp_swa`
to `tail_start0`, and update its use when computing `tail_offset`; preserve the
existing tail-copy behavior while avoiding shadowing the module-level
`tail_start` helper.
- Around line 642-644: Update build_tensor_specs to reject any cp_size that
differs from the import-time CP_SIZE before building metadata, set
golden_prefill_cp_swa._ctx within the builder, and return only specs. Adjust the
__main__ block to use the builder’s new return contract without externally
installing _ctx.

In `@models/deepseek/v4-flash/prefill_zigzag_cp.py`:
- Around line 33-43: Export and reuse the existing _parse_static_int helper from
prefill_zigzag_cp.py in prefill_swa_cp.py, removing the duplicate implementation
and deriving CP_SIZE through the shared parser (or importing CP_SIZE directly).
Ensure both modules use one consistent --cp argument parsing rule.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f6cfc98-1646-4186-8e55-061d272ea038

📥 Commits

Reviewing files that changed from the base of the PR and between c0751b7 and b3cae16.

📒 Files selected for processing (27)
  • docs/debug-and-tune/debugging.md
  • docs/debug-and-tune/performance-tuning.md
  • docs/models/deepseek.md
  • docs/run-and-validate/compile-runtime-workflow.md
  • models/deepseek/v4-flash/decode_csa.py
  • models/deepseek/v4-flash/decode_fwd.py
  • models/deepseek/v4-flash/decode_hca.py
  • models/deepseek/v4-flash/decode_indexer.py
  • models/deepseek/v4-flash/decode_layer.py
  • models/deepseek/v4-flash/decode_mtp.py
  • models/deepseek/v4-flash/decode_sparse_attn_csa.py
  • models/deepseek/v4-flash/decode_swa.py
  • models/deepseek/v4-flash/prefill_compressor_ratio4.py
  • models/deepseek/v4-flash/prefill_csa.py
  • models/deepseek/v4-flash/prefill_csa_cp.py
  • models/deepseek/v4-flash/prefill_exchange_cp.py
  • models/deepseek/v4-flash/prefill_fwd.py
  • models/deepseek/v4-flash/prefill_hca.py
  • models/deepseek/v4-flash/prefill_hca_cp.py
  • models/deepseek/v4-flash/prefill_indexer.py
  • models/deepseek/v4-flash/prefill_indexer_compressor.py
  • models/deepseek/v4-flash/prefill_layer.py
  • models/deepseek/v4-flash/prefill_mtp.py
  • models/deepseek/v4-flash/prefill_sparse_attn.py
  • models/deepseek/v4-flash/prefill_swa.py
  • models/deepseek/v4-flash/prefill_swa_cp.py
  • models/deepseek/v4-flash/prefill_zigzag_cp.py

Comment thread docs/models/deepseek.md

```bash
python models/deepseek/v4-flash/prefill_attention_csa.py -p a2a3sim
python models/deepseek/v4-flash/prefill_csa.py -p a2a3sim

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the entry-point table with the renamed attention modules.

This command now uses prefill_csa.py, but the same document still lists *_attention_csa.py, *_attention_hca.py, and *_attention_swa.py. Update the table to use the mode-first module names and include _cp variants where applicable.

As per coding guidelines, keep public documentation and examples aligned when behavior changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/models/deepseek.md` at line 95, Update the entry-point table in the
DeepSeek documentation to replace the old *_attention_csa.py,
*_attention_hca.py, and *_attention_swa.py references with the renamed
mode-first modules, including the applicable _cp variants, while retaining
prefill_csa.py where already correct.

Source: Coding guidelines

Comment on lines +231 to +237
compressor_completion = pl.array.create(1, pl.TASK_ID)
_prefill_compressor_ratio4_with_completion(
x_normed, compress_state, compress_state_block_table,
cmp_wkv, cmp_wgate, cmp_ape, cmp_norm_w,
freqs_cos, freqs_sin, cmp_kv,
position_ids, num_tokens, cmp_slot_mapping, state_slot_mapping,
cmp_wkv, cmp_wgate, cmp_ape,
cmp_norm_w, freqs_cos, freqs_sin,
cmp_kv, position_ids, num_tokens,
cmp_slot_mapping, state_slot_mapping, compressor_completion,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 10 \
  '_prefill_compressor_ratio4_with_completion|compressor_completion|_prefill_sparse_attn_with_block_mask' \
  models/deepseek/v4-flash/prefill_csa.py \
  models/deepseek/v4-flash/prefill_compressor_ratio4.py

rg -n -C 8 \
  'main_completion|inner_completion|deps=.*completion' \
  models/deepseek/v4-flash/prefill_csa_cp.py

Repository: hw-native-sys/pypto-lib

Length of output: 15138


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== prefill_csa.py relevant sections =="
sed -n '200,335p' models/deepseek/v4-flash/prefill_csa.py

echo
echo "== prefill_compressor_ratio4.py signature/body tail =="
sed -n '55,220p' models/deepseek/v4-flash/prefill_compressor_ratio4.py
sed -n '380,416p' models/deepseek/v4-flash/prefill_compressor_ratio4.py

echo
echo "== prefill_sparse_attn files =="
fd -a 'prefill_sparse_attn.py$' .
for f in $(fd 'prefill_sparse_attn.py$' .); do
  echo "--- $f outline/load/sparse_attn ---"
  rg -n "def _prefill_sparse_attn_with_block_mask|prefill_csa.py|at[level=|deps=" "$f" -C 4 || true
done

echo
echo "== task dependency / pl.at usage in deepseek v4-flash =="
rg -n "pl\.at\(|deps=.*completion|completion\[0\]|main_completion|inner_completion" models/deepseek/v4-flash -C 3

echo
echo "== pypto imports and TASK_ID creation semantics in repo =="
rg -n "TASK_ID|create\\(1, pl\\.TASK_ID\\)|array\\.create|pl\\.array" --iglob '*.md' --iglob '*.py' | head -n 200

Repository: hw-native-sys/pypto-lib

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== prefill_sparse_attn.py signature/body outline =="
awk '/def _prefill_sparse_attn_with_block_mask/,/^def / {print NR": "$0}' models/deepseek/v4-flash/prefill_sparse_attn.py | head -n 220

echo
echo "== exact sparse attn call in prefill_csa.py =="
sed -n '300,332p' models/deepseek/v4-flash/prefill_csa.py

echo
echo "== cmp_kv producers in prefill_compressor_ratio4.py =="
rg -n "cmp_kv|cmp_kv_flat|cmp.*write|write_dst|pl\.write|cmp_cache" models/deepseek/v4-flash/prefill_compressor_ratio4.py -C 4

echo
echo "== sparse_attn reads/writes related to cmp_kv in prefill_sparse_attn.py =="
rg -n "cmp_kv|sparse_kv|write|pl\.read|pl\.assemble|tile\.get_block_idx|spmd" models/deepseek/v4-flash/prefill_sparse_attn.py -C 5 | head -n 260

echo
echo "== deterministic task dependency check: does sparse launch include compressor completion deps? =="
python3 - <<'PY'
from pathlib import Path
import re

csa = Path("models/deepseek/v4-flash/prefill_csa.py").read_text()
attn = Path("models/deepseek/v4-flash/prefill_sparse_attn.py").read_text()

def text_between(start, end):
    i = csa.find(start)
    j = csa.find(end, i + 1)
    return csa[i:j] if i >= 0 and j > 0 else ""

call_block = text_between("compressor_completion = pl.array.create", "attn_out = pl.create_tensor").split("_prefill_sparse_attn_with_block_mask")[0] + "attn_out = pl.create_tensor"
print("has compressor_completion creation:", "compressor_completion = pl.array.create(1, pl.TASK_ID)" in csa)
print("has compressor_completion passed to compressor:", "_prefill_compressor_ratio4_with_completion(" in call_block and "compressor_completion," in call_block)
print("has compressor_completion read/consumed by sparse block or later:", bool(re.search(r'compressor_completion\s*\[\s*0\s*\]', csa)))

call = re.search(r'_prefill_sparse_attn_with_block_mask\s*\((.*?)\n\s*\)', csa, re.S)
call_text = call.group(1) if call else ""
print("sparse call lines:", csa[call.start():call.end()+1] if call else "NOT FOUND")
print("sparse call contains 'deps':", "deps" in call_text)
print("sparse call contains any completion id:", bool(re.search(r'\.completion|completion|_tid\s*\)', call_text)))

print("sparse file contains deps in at/with context:", bool(re.search(r'\bdeps\s*=', attn)))
PY

Repository: hw-native-sys/pypto-lib

Length of output: 27950


🌐 Web query:

PyPTO pl.at deps pl.system.task_dummy Tensor dependency completion documentation

💡 Result:

In the PyPTO (Parallel Tensor/Tile Operation) framework, task dependencies are primarily managed automatically by the runtime (specifically the TensorMap system) based on tensor read/write patterns [1]. However, developers can manually influence task scheduling and dependency edges when automatic inference is insufficient or non-deterministic [2][3]. Regarding the specific components mentioned: 1. pl.at: This is a scope-based construct used within PyPTO to define execution contexts (e.g., specifying pl.Level.CORE_GROUP) and hint at task boundaries or kernel optimization strategies [4][5][6]. 2. pl.system.task_dummy: This refers to a placeholder "dummy" task that was historically used in PyPTO orchestration to force a bridge or synchronization point between two operations (e.g., bridging an attention layer to an output projection) when the automatic dependency graph could not detect the necessary ordering [3]. Current best practices in PyPTO development involve replacing these dummy tasks with explicit dependency management [3]. 3. Tensor Dependency Completion and Manual Overrides: When the automatic dependency tracker fails to establish a required edge (such as in Write-After-Read/WAR scenarios where the runtime fails to infer a serialization dependency on a shared buffer), developers use explicit dependency injection [2]. The framework exposes pl.submit(kernel, *args, deps=[...]) for this purpose [2]. By passing a list of deps (containing producer TaskIDs), the developer explicitly mandates that a task cannot start until its listed predecessors have completed [2][3]. This approach is preferred over using dummy tasks or "no-op" hacks (like forced self-copies) because it provides precise, overhead-free control over the dependency graph [2][3]. In summary, while PyPTO aims for automated dependency tracking through tensor dataflow analysis, developers should utilize explicit deps arguments in pl.submit to handle complex scheduling requirements or to resolve non-deterministic race conditions that the runtime cannot automatically detect [2][1].

Citations:


Wait for the compressor completion before starting sparse attention.

_prefill_compressor_ratio4_with_completion writes cmp_kv back through cmp_kv_flat and exposes the write completion in compressor_completion, but _prefill_sparse_attn_with_block_mask reads cmp_kv without that dependency. Add compressor_completion[0] to the sparse-attention launch/dependency so the CP ordering in models/deepseek/v4-flash/prefill_csa_cp.py also applies here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_csa.py` around lines 231 - 237, The
sparse-attention launch following `_prefill_compressor_ratio4_with_completion`
must depend on the compressor write completion before reading `cmp_kv`. Update
the `_prefill_sparse_attn_with_block_mask` call or its launch dependency
arguments to include `compressor_completion[0]`, preserving the same CP ordering
behavior used in `prefill_csa_cp.py`.

Comment on lines +784 to +807
for part in pl.range(LOCAL_PARTS):
state_base = part * HCA_STATE_PHYSICAL_BLOCKS
state_end = state_base + HCA_STATE_PHYSICAL_BLOCKS
state_part = scratch_state[state_base:state_end, 0:HCA_STATE_BLOCK_SIZE, 0:COMPRESS_STATE_DIM]
for leaf in pl.range(MAX_COMPRESS_LEAVES):
leaf_index = part * MAX_COMPRESS_LEAVES + leaf
token0 = leaf_index * TAIL_ROWS
cmp_block0 = leaf_index * LEAF_CMP_BLOCKS
x_leaf = effective_x[token0 : token0 + TAIL_ROWS, 0:D]
position_leaf = leaf_positions[token0 : token0 + TAIL_ROWS]
cmp_slots_leaf = leaf_cmp_slots[token0 : token0 + TAIL_ROWS]
state_slots_leaf = leaf_state_slots[token0 : token0 + TAIL_ROWS]
cmp_leaf = leaf_cmp[cmp_block0 : cmp_block0 + LEAF_CMP_BLOCKS, 0:BLOCK_SIZE, 0:1, 0:HEAD_DIM]
active = pl.read(leaf_num_tokens, [part, leaf])
prefill_compressor_ratio128(
x_leaf, state_part, compress_state_block_table,
cmp_wkv, cmp_wgate, cmp_ape, cmp_norm_w,
freqs_cos, freqs_sin,
cmp_leaf, position_leaf, active,
cmp_slots_leaf, state_slots_leaf,
)
leaf_cmp[cmp_block0 : cmp_block0 + LEAF_CMP_BLOCKS, 0:BLOCK_SIZE, 0:1, 0:HEAD_DIM] = cmp_leaf
state_end = state_base + HCA_STATE_PHYSICAL_BLOCKS
scratch_state[state_base:state_end, 0:HCA_STATE_BLOCK_SIZE, 0:COMPRESS_STATE_DIM] = state_part

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare prefill_compressor_ratio128 and the ratio-4 completion-aware variant.
set -euo pipefail

fd -t f 'prefill_compressor_ratio128.py' models --exec ast-grep outline {} --items all \;
fd -t f 'prefill_compressor_ratio128.py' models --exec rg -n 'def prefill_compressor_ratio128|completion|task_dummy|return ' {} \;
rg -nP -C3 'prefill_compressor_ratio128\(' --type=py -g 'models/**'

Repository: hw-native-sys/pypto-lib

Length of output: 5807


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file sizes =="
wc -l models/deepseek/v4-flash/prefill_hca_cp.py models/deepseek/v4-flash/prefill_csa_cp.py models/deepseek/v4-flash/prefill_compressor_ratio128.py 2>/dev/null || true

echo "== hca cp outline around relevant symbols =="
ast-grep outline models/deepseek/v4-flash/prefill_hca_cp.py --view expanded | sed -n '1,220p'

echo "== hca cp lines 740-920 =="
sed -n '740,920p' models/deepseek/v4-flash/prefill_hca_cp.py | nl -ba -v740

echo "== hca pack references =="
rg -n -C4 'cp_hca_pack_compact|leaf_cmp_flat|scratch_state_flat|task_dummy|completion|return .*cmp_kv|return .*compress_state|prefill_compressor_ratio128' models/deepseek/v4-flash/prefill_hca_cp.py

echo "== ratio128 definition lines 72-284 =="
sed -n '72,284p' models/deepseek/v4-flash/prefill_compressor_ratio128.py | nl -ba -v72

Repository: hw-native-sys/pypto-lib

Length of output: 2678


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== csa cp lines around completion usage =="
sed -n '1050,1115p' models/deepseek/v4-flash/prefill_csa_cp.py | nl -ba -v1050

echo "== csa cp compressor call context if any =="
rg -n -C5 'prefill_compressor_ratio128|leaf_cmp_flat|scratch_state_flat|cp_hca_pack_compact|task_dummy|completion' models/deepseek/v4-flash/prefill_csa_cp.py || true

Repository: hw-native-sys/pypto-lib

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== hca cp lines 740-920 =="
python3 - <<'PY'
from pathlib import Path
p=Path('models/deepseek/v4-flash/prefill_hca_cp.py')
text=p.read_text().splitlines()
for i in range(739, min(919, len(text))):
    print(f"{i+1}: {text[i]}")
PY

echo "== hca cp pack and compressor hits =="
rg -n -C4 'cp_hca_pack_compact|leaf_cmp_flat|scratch_state_flat|task_dummy|completion|prefill_compressor_ratio128' models/deepseek/v4-flash/prefill_hca_cp.py

echo "== csa cp lines 1050-1125 =="
python3 - <<'PY'
from pathlib import Path
p=Path('models/deepseek/v4-flash/prefill_csa_cp.py')
text=p.read_text().splitlines()
for i in range(1049, min(1124, len(text))):
    print(f"{i+1}: {text[i]}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 20631


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== ratio128 definition lines 72-284 =="
python3 - <<'PY'
from pathlib import Path
p=Path('models/deepseek/v4-flash/prefill_compressor_ratio128.py')
text=p.read_text().splitlines()
for i in range(71, min(283, len(text))):
    print(f"{i+1}: {text[i]}")
PY

echo "== ratio4 completion-aware definitions =="
rg -n -C4 'def _prefill_compressor_ratio4_with_completion|prefill_compressor_ratio4_with_completion|completion|task_dummy|return .*main_cache_written|return .*main_state_written' models/deepseek/v4-flash models/deepseek/v4-pro --type=py || true

echo "== return/completion references in ratio128 files =="
rg -n -C2 'return cmp_kv, compress_state|task_dummy|completion|array\.create|with pl\.at\(.*deps|return.*written' models/deepseek/v4-flash/prefill_compressor_ratio128.py models/deepseek/v4-pro/prefill_compressor_ratio128.py || true

echo "== all ratio128 call sites =="
rg -n -C3 'prefill_compressor_ratio128\(' models --type=py || true

Repository: hw-native-sys/pypto-lib

Length of output: 50379


Gate compact packing behind the compressor completions.

prefill_compressor_ratio128 writes the caller-owned cmp_kv and compress_state buffers through cmp_leaf and state_part, but it does not return a completion ID. cp_hca_pack_compact then reads leaf_cmp_flat and scratch_state_flat without a dependency on those writes, unlike the CSA ratio-4 caller. Add a completion-array dependency for the HCA compressor and capture/commission the compressor root returns through the compact payload path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_hca_cp.py` around lines 784 - 807, Update
the HCA compression flow around prefill_compressor_ratio128 and
cp_hca_pack_compact to collect the compressor completion IDs for each launched
leaf/state write, then pass or commission those completions through the compact
payload dependency path before cp_hca_pack_compact reads leaf_cmp_flat and
scratch_state_flat. Preserve the existing buffer slicing and packing behavior
while ensuring compact packing waits on all compressor roots, matching the CSA
ratio-4 caller’s dependency handling.

Comment on lines +306 to +310
sparse_kv: pl.Tensor[[LOCAL_SPARSE_ROWS, HEAD_DIM], pl.BF16],
sparse_bias: pl.Tensor[[NUM_LOCAL_TILES * TAIL_ROWS, PREFILL_SPARSE_PAD], pl.FP32],
valid_block_mask: pl.Tensor[[NUM_LOCAL_TILES * TAIL_ROWS, VALID_BLOCK_MASK_COLS], pl.INT32],
overlay_active_lengths: pl.Tensor[[NUM_LOCAL_TILES, OVERLAY_SOURCES], pl.INT32],
):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Resolve WIN, PREFILL_ATTN_TILE, PREFILL_ATTN_BLOCKS, and VALID_BLOCK_MASK_COLS.
set -euo pipefail

fd -t f 'prefill_sparse_attn.py' models/deepseek --exec rg -n 'PREFILL_ATTN_TILE\s*=|PREFILL_ATTN_BLOCKS\s*=|PREFILL_SPARSE_PAD\s*=|SPARSE_BIAS_COLS\s*=|VALID_BLOCK_MASK_COLS\s*=|^WIN\s*=' {} \;
fd -t f 'config.py' models/deepseek --exec rg -n 'sliding_window' {} \;

# Confirm no other site writes valid_mask in the SWA CP path.
fd -t f 'prefill_swa_cp.py' models/deepseek --exec rg -n 'valid_mask|valid_block_mask' {} \;

Repository: hw-native-sys/pypto-lib

Length of output: 1381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
fd -t f 'prefill_swa_cp.py|prefill_sparse_attn.py|prefill_exchange_cp.py|config.py' models/deepseek

echo "== prefill_swa_cp.py outline =="
ast-grep outline models/deepseek/prefill_swa_cp.py --view expanded || true
wc -l models/deepseek/prefill_swa_cp.py

echo "== relevant prefill_swa_cp.py sections =="
sed -n '270,580p' models/deepseek/prefill_swa_cp.py | cat -n

echo "== relevant prefill_sparse_attn.py sections =="
sed -n '35,140p' models/deepseek/prefill_sparse_attn.py | cat -n
sed -n '180,320p' models/deepseek/prefill_sparse_attn.py | cat -n
sed -n '320,460p' models/deepseek/prefill_sparse_attn.py | cat -n

echo "== prefill_exchange_cp.py around mask build =="
sed -n '560,645p' models/deepseek/prefill_exchange_cp.py | cat -n

echo "== sliding window config occurrences =="
sed -n '1,35p' models/deepseek/config.py | cat -n

Repository: hw-native-sys/pypto-lib

Length of output: 618


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="models/deepseek/v4-flash/prefill_swa_cp.py"
OTHER="models/deepseek/v4-flash/prefill_sparse_attn.py"
EX="models/deepseek/v4-flash/prefill_exchange_cp.py"
CONFIG="models/deepseek/v4-flash/config.py"

echo "== file sizes =="
wc -l "$FILE" "$OTHER" "$EX" "$CONFIG"

echo "== relevant prefill_swa_cp.py sections =="
sed -n '250,590p' "$FILE" | cat -n

echo "== relevant prefill_sparse_attn.py sections =="
sed -n '1,180p' "$OTHER" | cat -n
sed -n '180,460p' "$OTHER" | cat -n

echo "== prefill_exchange_cp.py around mask build =="
sed -n '560,635p' "$EX" | cat -n

echo "== config window and helper sections =="
sed -n '1,180p' "$CONFIG" | cat -n

echo "== deterministic config derivation for a2a3/a2a3sim/a5/a5sim =="
python3 - <<'PY'
from pathlib import Path
import re, ast

config_path = Path("models/deepseek/v4-flash/config.py")
text = config_path.read_text()
config = {}
exec(text, config)
for name in ["a2a3", "a2a3sim", "a5", "a5sim"]:
    m = config.get(name)
    print(name, m.sliding_window if m else "*", "PREFILL_ATTN_TILE", config.get("PREFILL_ATTN_TILE"), "PREFILL_SPARSE_TOPK", config.get("PREFILL_SPARSE_TOPK"))
    sw = m.sliding_window if m else None
    attn_tile = config.get("PREFILL_ATTN_TILE")
    topk = config.get("PREFILL_SPARSE_TOPK")
    if sw is None or attn_tile is None or topk is None:
        print(name, "undetermined")
        continue
    blocks = (topk + attn_tile - 1) // attn_tile
    print(name, "sw_blocks", blocks if sw > attn_tile else 1,
          "topk_tiles", (topk + attn_tile - 1) // attn_tile)
PY

Repository: hw-native-sys/pypto-lib

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

CONFIG="models/deepseek/v4-flash/config.py"

echo "== model configs with keys =="
python3 - <<'PY' 2>&1
from pathlib import Path
import ast

path = Path("models/deepseek/v4-flash/config.py")
tree = ast.parse(path.read_text())
classes = {n: [] for n in ("Flash", "FlashV2")}
for node in tree.body:
    if isinstance(node, ast.ClassDef) and node.name in classes:
        for item in node.body:
            if isinstance(item, ast.Assign):
                for target in item.targets:
                    if isinstance(target, ast.Name):
                        classes[node.name].append(target.id)
for name, keys in classes.items():
    print(name, " ".join(key for key in keys if key.lower().startswith(("sliding_", "index_", "flash"))))

# Print relevant class bodies compactly.
for name in ("Flash", "FlashV2"):
    print(f"\n== {name} relevant attributes ==")
    for node in tree.body:
        if isinstance(node, ast.ClassDef) and node.name == name:
            for item in node.body:
                if isinstance(item, ast.Assign):
                    ids = " ".join(t.id if isinstance(t, ast.Name) else ast.unparse(t) for t in item.targets)
                    val = ast.unparse(item.value)
                    if any(k in ids for k in ("sliding_window", "index_topk", "o_groups", "head_dim", "name")):
                        print(f"{ids} = {val}")
PY

echo "== deterministic window/topk configuration =="
python3 - <<'PY'
from pathlib import Path
import ast

src = Path("models/deepseek/v4-flash/config.py").read_text().splitlines()
env = {}
lines = []
for i, line in enumerate(src, start=1):
    if "VALID_BLOCK_MASK_COLS" in line or "PREFILL_ATTN_BLOCKS" in line or "PREFILL_SPARSE_PAD" in line:
        print(f"{i}: {line}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 321


🏁 Script executed:

#!/bin/bash
set -euo pipefail

CONFIG="models/deepseek/v4-flash/config.py"
SOURCER="models/deepseek/v4-flash/prefill_swa_cp.py"
MATH="models/deepseek/v4-flash/prefill_sparse_attn.py"

echo "== top-level names =="
grep -nE '^[A-Z][A-Za-z0-9_]* = ' "$CONFIG" "$SOURCER" "$MATH" | rg 'Flash|sliding_window|sliding|index|top|local|local' || true

echo "== all valid_block_mask writes in deepseek/v4-flash Python files =="
rg -n 'valid_block_mask|valid_mask|prefill_cp_build_valid_mask|prefill_cp_sparse_stage' models/deepseek/v4-flash -g '*.py' || true

echo "== Flash config text =="
cat "$CONFIG" | sed -n '1,230p'

echo "== relevant _cp_swa_stage_sources references around write candidates =="
python3 - <<'PY'
from pathlib import Path
p = Path("models/deepseek/v4-flash/prefill_swa_cp.py")
text = p.read_text().splitlines()
needles = [
    "pl.write(mask",
    "valid_block_mask",
    "sparse_kv",
]
for start, end in [(40, 130), (435, 530)]:
    print(f"\n---- {p}:{start}-{end} ----")
    for i in range(start, min(end, len(text))+1):
        if any(n in text[i-1] for n in needles):
            print(f"{i:4}: {text[i-1]}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 14185


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== sparse topk and blocks in v4-flash config via Python eval =="
python3 - <<'PY'
from pathlib import Path
import ast

src = Path("models/deepseek/v4-flash/config.py").read_text()
top_level = "\n".join(line for line in src.splitlines() if not line.strip().startswith("#"))
ns = {}
exec(compile(top_level, "config.py", "exec"), ns)

flash = ns["FLASH"]
topk_window_entries = flash.sliding_window + flash.index_topk
topk_window_entries = min(topk_window_entries, len(flash.compress_ratios))
attn_tile = 128
topk = slide_add_idx_topk = flash.sliding_window + flash.index_topk
sparse_topk = min(slide_add_idx_topk, min(flash.sliding_window, flash.max_position_embeddings) + min(1, min(flash.index_topk, flash.sliding_window + flash.sliding_window // 2)))
blocks = (sparse_topk + attn_tile - 1) // attn_tile
print("sliding_window", flash.sliding_window)
print("index_topk", flash.index_topk)
print("topk_window_entries", topk_window_entries)
print("sparse_topk", sparse_topk)
print("blocks", blocks)
print("PREFILL_SPARSE_PAD", blocks * attn_tile)
PY

Repository: hw-native-sys/pypto-lib

Length of output: 330


Populate valid_block_mask in the SWA CP stage.

_cp_swa_stage_sources stages more than one attention block for the default config, but prefill_cp_swa creates valid_mask with init_value=0 and passes it only to _prefill_sparse_attn_math. In that backend, block 0 is force-enabled, but the remaining sparse block rows stay masked. Add the same mask build used by _prefill_cp_sparse_stage before calling the math backend.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_swa_cp.py` around lines 306 - 310, Populate
valid_block_mask in prefill_cp_swa using the same mask-construction logic as
_prefill_cp_sparse_stage before invoking _prefill_sparse_attn_math. Ensure every
staged attention block row is enabled according to the SWA CP staging inputs,
rather than leaving nonzero rows masked by the zero-initialized valid_mask.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
models/deepseek/v4-flash/prefill_indexer_compressor.py (1)

347-393: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add an explicit dependency from prefill_idx_c4_scale_scatter to cache_write_tid.

scale_scratch is written inside the prefill_idx_c4_cache_write SPMD task at line 368. The prefill_idx_c4_scale_scatter block at line 382 reads scale_scratch but declares no deps. The producer task id cache_write_tid is already in scope and is only used later at line 425 for the completion signal.

If the scheduler does not derive this read-after-write edge automatically, the scatter can publish stale or uninitialized dequantization scales into idx_kv_scale. That corrupts the C8 indexer cache while the INT8 rows stay correct, which makes the defect hard to trace.

🔒️ Proposed fix to order the scale scatter after the cache write
-    with pl.at(level=pl.Level.CORE_GROUP, name_hint="prefill_idx_c4_scale_scatter") as scale_scatter_tid:
+    with pl.at(
+        level=pl.Level.CORE_GROUP,
+        name_hint="prefill_idx_c4_scale_scatter",
+        deps=[cache_write_tid],
+    ) as scale_scatter_tid:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_indexer_compressor.py` around lines 347 -
393, Add an explicit dependency on cache_write_tid to the
prefill_idx_c4_scale_scatter task declaration so it waits for the producer that
writes scale_scratch. Preserve the existing scale scatter logic and dependency
behavior for all other tasks.
🧹 Nitpick comments (14)
models/deepseek/v4-flash/prefill_csa.py (1)

251-259: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark the unused indexer outputs as intentional.

Ruff RUF059 reports idx_kv_cache_out and idx_kv_scale_out as unused. If prefill_indexer updates idx_kv_cache and idx_kv_scale in place, use underscore-prefixed bindings.

Suggested binding change
-    idx_kv_cache_out, idx_kv_scale_out, idx_score_unused, cmp_topk_indices = prefill_indexer(
+    _idx_kv_cache_out, _idx_kv_scale_out, idx_score_unused, cmp_topk_indices = prefill_indexer(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_csa.py` around lines 251 - 259, Update the
assignment receiving outputs from prefill_indexer so the intentionally unused
idx_kv_cache_out and idx_kv_scale_out bindings use underscore-prefixed names,
while preserving the remaining outputs and call behavior.

Source: Linters/SAST tools

models/deepseek/v4-flash/prefill_swa_cp.py (2)

502-510: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The loop variable tail_start shadows the module-level tail_start function.

Line 502 binds tail_start to a scalar inside prefill_cp_swa. Line 142 defines tail_start(seg_start, seg_len) at module scope. The function is not called later in this kernel, so the shadowing is currently harmless.

Rename the local to tail_start0, matching tail_offset0 in prefill_hca_cp.py line 646. That prevents a confusing failure if this kernel later needs the helper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_swa_cp.py` around lines 502 - 510, Rename
the local scalar `tail_start` in `prefill_cp_swa` to `tail_start0`, and update
its use when computing `tail_offset`; preserve the existing tail-copy behavior
while avoiding shadowing the module-level `tail_start` helper.

642-644: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align build_tensor_specs with the sibling CP modules and add the cp_size guard.

This builder returns (specs, ctx) at line 704 and the __main__ block installs golden_prefill_cp_swa._ctx externally at line 854. prefill_csa_cp.py line 1007 and prefill_hca_cp.py line 1546 instead set _ctx inside the builder and return only the spec list. A shared harness that calls build_tensor_specs uniformly across these modules will break on this one.

This builder also omits the cp_size guard. prefill_hca_cp.py lines 1309-1312 and prefill_csa_cp.py lines 639-642 raise when the runtime cp_size differs from the import-time CP_SIZE. Here, build_metadata(args.cp) would build metadata for one CP size while the compiled kernel shapes use another.

Set _ctx inside build_tensor_specs, return only specs, and raise when cp_size != CP_SIZE.

♻️ Proposed change
 def build_tensor_specs(cp_size: int = CP_SIZE):
+    if cp_size != CP_SIZE:
+        raise ValueError(
+            f"runtime cp_size={cp_size} does not match static CP_SIZE={CP_SIZE}"
+        )
     meta, ctx = build_metadata(cp_size)
     specs.append(TensorSpec("x_out", list(x.shape), torch.float32, is_output=True))
-    return specs, ctx
+    golden_prefill_cp_swa._ctx = ctx
+    return specs
-    specs, ctx = build_tensor_specs(args.cp)
-    golden_prefill_cp_swa._ctx = ctx
     result = run_jit(
         fn=prefill_cp_swa_test,
-        specs=specs,
+        specs=build_tensor_specs(args.cp),
         golden_fn=golden_prefill_cp_swa,

Also applies to: 836-854

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_swa_cp.py` around lines 642 - 644, Update
build_tensor_specs to reject any cp_size that differs from the import-time
CP_SIZE before building metadata, set golden_prefill_cp_swa._ctx within the
builder, and return only specs. Adjust the __main__ block to use the builder’s
new return contract without externally installing _ctx.
models/deepseek/v4-flash/prefill_hca_cp.py (2)

647-662: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Collapse the no-op branch in cp_hca_tail_assemble.

Both arms of the if tail_offset < TAIL_ROWS branch compute the same source expression. The branch has no effect.

The layout is already correct: tiles of one part are contiguous, so part * MAX_SEGMENT_TILES * TAIL_ROWS + tail_offset addresses tile 0 for tail_offset < TAIL_ROWS and tile 1 above it. The branch reads as an unfinished edit and invites a wrong "fix" later.

The equivalent code in prefill_swa_cp.py lines 506-509 has the same redundancy in a different form (TAIL_ROWS + tail_offset - TAIL_ROWS). Simplify both.

♻️ Proposed simplification
             for row in pl.range(TAIL_ROWS):
                 tail_offset = tail_offset0 + row
                 if tail_offset < total:
-                    if tail_offset < TAIL_ROWS:
-                        source = (
-                            part * MAX_SEGMENT_TILES * TAIL_ROWS
-                            + tail_offset
-                        )
-                    else:
-                        source = (
-                            part * MAX_SEGMENT_TILES * TAIL_ROWS
-                            + tail_offset
-                        )
+                    # Tiles of one part are contiguous, so the offset indexes directly.
+                    source = part * MAX_SEGMENT_TILES * TAIL_ROWS + tail_offset
                     destination = part * TAIL_ROWS + row
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_hca_cp.py` around lines 647 - 662, In
cp_hca_tail_assemble, remove the redundant if/else around source and assign it
directly using part * MAX_SEGMENT_TILES * TAIL_ROWS + tail_offset. Apply the
same simplification to the corresponding tail assembly logic in
prefill_swa_cp.py, preserving the existing contiguous tile layout and indexing
behavior.

1313-1314: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Two metadata builders produce overlapping fixture data.

build_hca_metadata at line 322 and _build_raw_attention_metadata at line 169 both recompute prefix, span, lengths, starts, owners, and query_positions from the same inputs. device_values at lines 1501-1523 then mixes the two sources: query_positions comes from raw_metadata, while segment_starts_t, cmp_indices, and segment_tail_positions come from metadata.

The two query_positions tensors also differ in their inactive fill: _build_raw_attention_metadata uses 0 at line 177 and build_hca_metadata uses -1 at line 335. The kernel only reads active rows, so today this is benign, but the split makes the fixture contract hard to audit.

Derive the shared segment geometry once and pass it to both builders.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_hca_cp.py` around lines 1313 - 1314, Derive
the shared segment geometry once before the metadata construction in the fixture
setup, then pass that geometry into both build_hca_metadata and
_build_raw_attention_metadata instead of recomputing prefix, span, lengths,
starts, owners, and query_positions independently. Update both builder
signatures and their callers, and ensure device_values uses fields from this
single consistent geometry source.
models/deepseek/v4-flash/prefill_zigzag_cp.py (1)

33-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Export _parse_static_int instead of copying it into prefill_swa_cp.py.

prefill_swa_cp.py lines 75-82 define an identical _parse_static_int and then derive its own CP_SIZE from CP_DEFAULT, which it already imports from this module. Two independent argv scans can disagree if the parsing rule ever changes.

Import this helper in prefill_swa_cp.py, or import CP_SIZE directly since both modules derive the same value from the same flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_zigzag_cp.py` around lines 33 - 43, Export
and reuse the existing _parse_static_int helper from prefill_zigzag_cp.py in
prefill_swa_cp.py, removing the duplicate implementation and deriving CP_SIZE
through the shared parser (or importing CP_SIZE directly). Ensure both modules
use one consistent --cp argument parsing rule.
models/deepseek/v4-flash/prefill_csa_cp.py (1)

271-289: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

_build_metadata_tensors computes a large unused result, and it hides the only capacity check.

build_tensor_specs at line 643 unpacks metadata, ctx and then reads only four entries: compress_state_block_table, inner_compress_state_block_table, cmp_block_table, and idx_block_table. All four come from _build_block_tables. Ruff also reports that ctx is never used.

Two consequences:

  1. Lines 292-483 build boundary_positions, seed_*, main_slot_mapping, idx_slot_mapping, final_*_state_mapping, dense_cmp_prefix, and dense_idx_prefix that no spec consumes. Lines 896-955 then recompute the equivalent leaf slot mappings with the same _lower_row rule. The two derivations can drift apart, and only the second one reaches the kernel.
  2. validate_cp_indexer_capacity at line 289 runs only as a side effect of this otherwise-unused function. If someone removes the dead branch, the capacity guard disappears silently.

Reduce _build_metadata_tensors to the tables and context that build_tensor_specs actually consumes, and call validate_cp_indexer_capacity from build_tensor_specs directly.

Also applies to: 643-643

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_csa_cp.py` around lines 271 - 289, Reduce
_build_metadata_tensors to return only the metadata tables and context entries
consumed by build_tensor_specs, removing the unused boundary, seed,
slot-mapping, state-mapping, and dense-prefix calculations. Move
validate_cp_indexer_capacity out of _build_metadata_tensors and invoke it
directly from build_tensor_specs, preserving the existing capacity validation
behavior independently of metadata construction.

Source: Linters/SAST tools

models/deepseek/v4-flash/prefill_exchange_cp.py (1)

478-623: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

_prefill_cp_sparse_stage still duplicates _cp_swa_stage_sources.

This helper and _cp_swa_stage_sources in prefill_swa_cp.py lines 294-379 implement the same persistent/predecessor/current overlay lowering. The gather loop, the overlay index derivation, and the bias build are line-for-line equivalent. This helper adds the compressed-index branch at lines 564-577 and the valid-mask build at lines 603-621; the SWA copy omits both.

The PR objective states that exchange logic is consolidated into prefill_exchange_cp.py, so the SWA copy is an outlier. The SWA path can call _prefill_cp_sparse_stage with IDX_TOPK-wide cmp_indices filled with -1, which makes the compressed branch inert and produces the same valid mask.

This is deferable, but it prevents the two overlay lowerings from diverging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_exchange_cp.py` around lines 478 - 623,
Refactor the SWA path to reuse _prefill_cp_sparse_stage instead of maintaining
the duplicate _cp_swa_stage_sources implementation in prefill_swa_cp.py. Supply
IDX_TOPK-wide cmp_indices initialized to -1 and the required compressed-stage
buffers so the compressed branch remains inert, while preserving the existing
SWA outputs and overlay behavior.
models/deepseek/v4-flash/prefill_indexer.py (1)

379-482: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Consider extracting the shared query-preparation pipeline.

Lines 379-482 of _prefill_indexer_cp_score_topk repeat the body of prefill_indexer lines 148-253 almost verbatim: the qr_proj INT8 GEMM and dequantization, the interleaved RoPE table materialization, the swap-index build, the per-token RoPE rotation, the Hadamard multiply, and the per-row INT8 quantization. Only the name_hint strings differ.

Extract one @pl.jit.inline helper that returns qr_hadamard_i8 and qr_hadamard_scale_dq, and give it a name_prefix argument for the task hints. That keeps the two scoring paths from drifting when the quantization math changes.

This is deferable if you prefer to land the CP path first, but track it: the same block already exists in three copies across the CP modules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_indexer.py` around lines 379 - 482, Extract
the duplicated query-preparation pipeline from `_prefill_indexer_cp_score_topk`
and `prefill_indexer` into one `@pl.jit.inline` helper that returns
`qr_hadamard_i8` and `qr_hadamard_scale_dq`. Move the shared
projection/dequantization, RoPE preparation and rotation, Hadamard
multiplication, and per-row INT8 quantization into the helper, using a
`name_prefix` parameter to generate task-specific `name_hint` values, then
replace each duplicated block with the helper call.
models/deepseek/v4-flash/decode_sparse_attn_csa.py (4)

52-57: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the duplicate MAX_SEQ_LEN assignment.

Line 39 already sets MAX_SEQ_LEN = M.max_position_embeddings. Line 54 repeats the same assignment inside the CSA masking block, where the preceding comment describes compressed-slot masking. The duplicate suggests a different value is intended here.

♻️ Proposed cleanup
 # CSA compressed-slot masking (folded in from the CSA orchestrator): raw indexer
 # topk -> per-token bound floor((pos + 1) / COMPRESS_RATIO).
-MAX_SEQ_LEN = M.max_position_embeddings
 INDEXER_SCORE_LEN = MAX_SEQ_LEN // 4
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 52 - 57,
Remove the duplicate MAX_SEQ_LEN assignment from the CSA compressed-slot masking
block, while retaining the existing assignment near line 39. Keep
INDEXER_SCORE_LEN and the remaining CSA constants using the shared MAX_SEQ_LEN
value.

690-710: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename the loop variable to avoid shadowing the masked tensor.

raw is bound at Line 670 to the masked indexer tensor. Both loops here rebind raw to a plain int. The tensor is not read after Line 673, so the result is correct, but the reuse makes the masking block harder to follow.

♻️ Proposed rename
-        for raw in window_swa_indices[t].tolist():
-            slot = int(raw)
+        for win_slot_raw in window_swa_indices[t].tolist():
+            slot = int(win_slot_raw)
@@
-        for raw in cmp_sparse_indices[t].tolist():
-            if raw < 0:
+        for cmp_slot_raw in cmp_sparse_indices[t].tolist():
+            if cmp_slot_raw < 0:
                 kv_rows.append(torch.zeros(HEAD_DIM, dtype=ori_kv.dtype))
                 valid.append(False)
                 continue
-            cmp_slot = int(raw)
+            cmp_slot = int(cmp_slot_raw)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 690 - 710,
Rename the loop variable raw in both index-iteration loops to distinct
descriptive names, updating each corresponding reference while preserving the
existing index handling and masking behavior.

542-545: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Hoist the T_PAD zero-fill out of the token loop.

This block sits inside for qt in pl.pipeline(0, T, QUANT_TOKEN_TILE, ...). It writes the same constant zeros to the same padding rows on every token tile, so it repeats T // QUANT_TOKEN_TILE times. The result is correct, but the work is redundant. The padding rows do not depend on qt.

♻️ Proposed refactor
                     o_r_i8_pad = pl.assemble(o_r_i8_pad, oq_i8, [qt, col_g])
-                    if T_PAD > T:
-                        zero_half = pl.full([T_PAD - T, O_LORA], dtype=pl.FP16, value=0.0)
-                        zero_i8 = pl.cast(zero_half, target_type=pl.INT8, mode="trunc")
-                        o_r_i8_pad = pl.assemble(o_r_i8_pad, zero_i8, [T, col_g])
+                if T_PAD > T:
+                    zero_half = pl.full([T_PAD - T, O_LORA], dtype=pl.FP16, value=0.0)
+                    zero_i8 = pl.cast(zero_half, target_type=pl.INT8, mode="trunc")
+                    o_r_i8_pad = pl.assemble(o_r_i8_pad, zero_i8, [T, col_g])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 542 - 545,
Move the T_PAD padding initialization out of the for qt token-loop and perform
it once before the loop, preserving the existing zero_half, zero_i8, and
o_r_i8_pad assembly behavior for T_PAD > T. Keep token-dependent processing
inside the loop and ensure the padding rows remain unchanged for every tile.

316-337: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Consider bulk-run detection for the window gather.

This loop issues one pl.gather_row per sparse-K row, 128 rows per work item. The sibling kernels avoid that for the window prefix. decode_sparse_attn_swa.sparse_attn_swa and decode_sparse_attn_hca.sparse_attn_hca probe the first and last slot of a GATHER_RUN sub-tile, and copy the whole run as one bulk transfer when the endpoints are GATHER_RUN - 1 apart. Window slots are contiguous in the common case, so the same probe applies here.

This changes scheduling only, not results. Treat it as deferrable if the current profile is acceptable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 316 - 337,
Optimize the window-prefix path in the loop around qk_kv by detecting contiguous
GATHER_RUN sub-tiles, probing the first and last window slots as in
decode_sparse_attn_swa.sparse_attn_swa and
decode_sparse_attn_hca.sparse_attn_hca, and using one bulk gather when their
separation is GATHER_RUN - 1. Preserve the existing per-row gather and fallback
behavior for non-contiguous or invalid slots, without changing results for the
comparison-sparse path.
models/deepseek/v4-flash/decode_swa.py (1)

417-427: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Cache the SWA metadata to avoid recomputing the nested Python loop.

init_swa_indices and init_swa_lens each call init_swa_metadata, which runs swa_indices_and_lens. That helper loops over T * WIN elements with per-element .item() calls. It also rebuilds init_start_pos and init_block_table on every call. The values are deterministic, so the results stay consistent, but the fixture pays the cost twice.

♻️ Proposed refactor
-    def init_swa_metadata():
-        return swa_indices_and_lens(
-            position_ids_from_starts(init_start_pos(), seq=S),
-            init_block_table(),
-            block_size=BLOCK_SIZE,
-            window=WIN,
-        )
+    swa_metadata_cache = {}
+
+    def init_swa_metadata():
+        if "value" not in swa_metadata_cache:
+            swa_metadata_cache["value"] = swa_indices_and_lens(
+                position_ids_from_starts(init_start_pos(), seq=S),
+                init_block_table(),
+                block_size=BLOCK_SIZE,
+                window=WIN,
+            )
+        return swa_metadata_cache["value"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_swa.py` around lines 417 - 427, Cache the
result of init_swa_metadata so swa_indices_and_lens, init_start_pos, and
init_block_table execute only once. Update init_swa_indices and init_swa_lens to
reuse the cached metadata while preserving their respective contiguous outputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/models/deepseek.md`:
- Line 95: Update the entry-point table in the DeepSeek documentation to replace
the old *_attention_csa.py, *_attention_hca.py, and *_attention_swa.py
references with the renamed mode-first modules, including the applicable _cp
variants, while retaining prefill_csa.py where already correct.

In `@models/deepseek/v4-flash/decode_hca.py`:
- Around line 225-241: Update the top-k token iteration around topk_all so the
final partial HCA_TOPK_TOKEN_TILE is included rather than relying on a grid that
truncates the tail. Remove the ineffective topk_t < T guard or replace the loop
bounds with a ceil-divided token-block count, and ensure every token index below
T initializes its HCA_CMP_TOPK entries to valid compressed slots or -1
consistently with sparse_attn_hca expectations.
- Around line 13-14: Update the companion-file references in the module
docstring to use the renamed mode-first files decode_swa.py and decode_csa.py,
replacing the obsolete attention_swa.py and attention_csa_draft.py names.
- Around line 195-202: Add a module-level divisibility assertion for
HCA_WB_TOKEN_TILE, matching the guard style used in decode_sparse_attn_csa.py,
to ensure the configured T value is an exact multiple of HCA_WB_TOKEN_TILE
before the writeback loop runs. Preserve the existing writeback logic in the
hca_cache_writeback loop.
- Around line 273-276: Update attention_hca_test’s compressor-cache handling:
declare compress_state and cmp_kv as pl.InOut, and mark both corresponding
TensorSpecs with is_output=True and output comparison. Ensure
compressor_ratio128 and golden_compressor updates to these buffers are
validated.
- Around line 84-90: Replace HCA_CMP_TOPK usage with HCA_TOPK_LIMIT for the HCA
top-k bound, and add an assertion that HCA_TOPK_LIMIT is at least
get_standalone_cmp_valid(128). Do not reuse HCA_SPARSE_CMP_TOPK for this HCA
limit.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py`:
- Line 743: Update the zip call in the loop over block_mi, block_li, and
block_oi to pass strict=True, explicitly validating that all three iterables
have equal lengths while preserving the existing iteration behavior.
- Around line 256-264: Add an assertion alongside the existing tiling-invariant
checks in the module initialization/configuration validation to require WIN ==
ATTN_K_TILE. Keep the block-validity mapping in the loops using its current
offsets, and ensure invalid configurations fail before qk_pv executes.

In `@models/deepseek/v4-flash/decode_swa.py`:
- Around line 14-15: Update the module docstring’s companion file references to
use decode_csa.py and decode_hca.py instead of the renamed
attention_csa_draft.py and attention_hca_draft.py entries, preserving the
existing ratio annotations.

In `@models/deepseek/v4-flash/prefill_csa_cp.py`:
- Line 1973: Update the sparse_bias initialization in the prefill sparse
attention path to import FP32_NEG_INF from config and use it instead of the
literal -3.0e38, keeping the existing tensor shape, dtype, and initialization
behavior unchanged.

In `@models/deepseek/v4-flash/prefill_csa.py`:
- Around line 231-237: The sparse-attention launch following
`_prefill_compressor_ratio4_with_completion` must depend on the compressor write
completion before reading `cmp_kv`. Update the
`_prefill_sparse_attn_with_block_mask` call or its launch dependency arguments
to include `compressor_completion[0]`, preserving the same CP ordering behavior
used in `prefill_csa_cp.py`.

In `@models/deepseek/v4-flash/prefill_hca_cp.py`:
- Around line 784-807: Update the HCA compression flow around
prefill_compressor_ratio128 and cp_hca_pack_compact to collect the compressor
completion IDs for each launched leaf/state write, then pass or commission those
completions through the compact payload dependency path before
cp_hca_pack_compact reads leaf_cmp_flat and scratch_state_flat. Preserve the
existing buffer slicing and packing behavior while ensuring compact packing
waits on all compressor roots, matching the CSA ratio-4 caller’s dependency
handling.

In `@models/deepseek/v4-flash/prefill_swa_cp.py`:
- Around line 306-310: Populate valid_block_mask in prefill_cp_swa using the
same mask-construction logic as _prefill_cp_sparse_stage before invoking
_prefill_sparse_attn_math. Ensure every staged attention block row is enabled
according to the SWA CP staging inputs, rather than leaving nonzero rows masked
by the zero-initialized valid_mask.

---

Outside diff comments:
In `@models/deepseek/v4-flash/prefill_indexer_compressor.py`:
- Around line 347-393: Add an explicit dependency on cache_write_tid to the
prefill_idx_c4_scale_scatter task declaration so it waits for the producer that
writes scale_scratch. Preserve the existing scale scatter logic and dependency
behavior for all other tasks.

---

Nitpick comments:
In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py`:
- Around line 52-57: Remove the duplicate MAX_SEQ_LEN assignment from the CSA
compressed-slot masking block, while retaining the existing assignment near line
39. Keep INDEXER_SCORE_LEN and the remaining CSA constants using the shared
MAX_SEQ_LEN value.
- Around line 690-710: Rename the loop variable raw in both index-iteration
loops to distinct descriptive names, updating each corresponding reference while
preserving the existing index handling and masking behavior.
- Around line 542-545: Move the T_PAD padding initialization out of the for qt
token-loop and perform it once before the loop, preserving the existing
zero_half, zero_i8, and o_r_i8_pad assembly behavior for T_PAD > T. Keep
token-dependent processing inside the loop and ensure the padding rows remain
unchanged for every tile.
- Around line 316-337: Optimize the window-prefix path in the loop around qk_kv
by detecting contiguous GATHER_RUN sub-tiles, probing the first and last window
slots as in decode_sparse_attn_swa.sparse_attn_swa and
decode_sparse_attn_hca.sparse_attn_hca, and using one bulk gather when their
separation is GATHER_RUN - 1. Preserve the existing per-row gather and fallback
behavior for non-contiguous or invalid slots, without changing results for the
comparison-sparse path.

In `@models/deepseek/v4-flash/decode_swa.py`:
- Around line 417-427: Cache the result of init_swa_metadata so
swa_indices_and_lens, init_start_pos, and init_block_table execute only once.
Update init_swa_indices and init_swa_lens to reuse the cached metadata while
preserving their respective contiguous outputs.

In `@models/deepseek/v4-flash/prefill_csa_cp.py`:
- Around line 271-289: Reduce _build_metadata_tensors to return only the
metadata tables and context entries consumed by build_tensor_specs, removing the
unused boundary, seed, slot-mapping, state-mapping, and dense-prefix
calculations. Move validate_cp_indexer_capacity out of _build_metadata_tensors
and invoke it directly from build_tensor_specs, preserving the existing capacity
validation behavior independently of metadata construction.

In `@models/deepseek/v4-flash/prefill_csa.py`:
- Around line 251-259: Update the assignment receiving outputs from
prefill_indexer so the intentionally unused idx_kv_cache_out and
idx_kv_scale_out bindings use underscore-prefixed names, while preserving the
remaining outputs and call behavior.

In `@models/deepseek/v4-flash/prefill_exchange_cp.py`:
- Around line 478-623: Refactor the SWA path to reuse _prefill_cp_sparse_stage
instead of maintaining the duplicate _cp_swa_stage_sources implementation in
prefill_swa_cp.py. Supply IDX_TOPK-wide cmp_indices initialized to -1 and the
required compressed-stage buffers so the compressed branch remains inert, while
preserving the existing SWA outputs and overlay behavior.

In `@models/deepseek/v4-flash/prefill_hca_cp.py`:
- Around line 647-662: In cp_hca_tail_assemble, remove the redundant if/else
around source and assign it directly using part * MAX_SEGMENT_TILES * TAIL_ROWS
+ tail_offset. Apply the same simplification to the corresponding tail assembly
logic in prefill_swa_cp.py, preserving the existing contiguous tile layout and
indexing behavior.
- Around line 1313-1314: Derive the shared segment geometry once before the
metadata construction in the fixture setup, then pass that geometry into both
build_hca_metadata and _build_raw_attention_metadata instead of recomputing
prefix, span, lengths, starts, owners, and query_positions independently. Update
both builder signatures and their callers, and ensure device_values uses fields
from this single consistent geometry source.

In `@models/deepseek/v4-flash/prefill_indexer.py`:
- Around line 379-482: Extract the duplicated query-preparation pipeline from
`_prefill_indexer_cp_score_topk` and `prefill_indexer` into one `@pl.jit.inline`
helper that returns `qr_hadamard_i8` and `qr_hadamard_scale_dq`. Move the shared
projection/dequantization, RoPE preparation and rotation, Hadamard
multiplication, and per-row INT8 quantization into the helper, using a
`name_prefix` parameter to generate task-specific `name_hint` values, then
replace each duplicated block with the helper call.

In `@models/deepseek/v4-flash/prefill_swa_cp.py`:
- Around line 502-510: Rename the local scalar `tail_start` in `prefill_cp_swa`
to `tail_start0`, and update its use when computing `tail_offset`; preserve the
existing tail-copy behavior while avoiding shadowing the module-level
`tail_start` helper.
- Around line 642-644: Update build_tensor_specs to reject any cp_size that
differs from the import-time CP_SIZE before building metadata, set
golden_prefill_cp_swa._ctx within the builder, and return only specs. Adjust the
__main__ block to use the builder’s new return contract without externally
installing _ctx.

In `@models/deepseek/v4-flash/prefill_zigzag_cp.py`:
- Around line 33-43: Export and reuse the existing _parse_static_int helper from
prefill_zigzag_cp.py in prefill_swa_cp.py, removing the duplicate implementation
and deriving CP_SIZE through the shared parser (or importing CP_SIZE directly).
Ensure both modules use one consistent --cp argument parsing rule.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f6cfc98-1646-4186-8e55-061d272ea038

📥 Commits

Reviewing files that changed from the base of the PR and between c0751b7 and b3cae16.

📒 Files selected for processing (27)
  • docs/debug-and-tune/debugging.md
  • docs/debug-and-tune/performance-tuning.md
  • docs/models/deepseek.md
  • docs/run-and-validate/compile-runtime-workflow.md
  • models/deepseek/v4-flash/decode_csa.py
  • models/deepseek/v4-flash/decode_fwd.py
  • models/deepseek/v4-flash/decode_hca.py
  • models/deepseek/v4-flash/decode_indexer.py
  • models/deepseek/v4-flash/decode_layer.py
  • models/deepseek/v4-flash/decode_mtp.py
  • models/deepseek/v4-flash/decode_sparse_attn_csa.py
  • models/deepseek/v4-flash/decode_swa.py
  • models/deepseek/v4-flash/prefill_compressor_ratio4.py
  • models/deepseek/v4-flash/prefill_csa.py
  • models/deepseek/v4-flash/prefill_csa_cp.py
  • models/deepseek/v4-flash/prefill_exchange_cp.py
  • models/deepseek/v4-flash/prefill_fwd.py
  • models/deepseek/v4-flash/prefill_hca.py
  • models/deepseek/v4-flash/prefill_hca_cp.py
  • models/deepseek/v4-flash/prefill_indexer.py
  • models/deepseek/v4-flash/prefill_indexer_compressor.py
  • models/deepseek/v4-flash/prefill_layer.py
  • models/deepseek/v4-flash/prefill_mtp.py
  • models/deepseek/v4-flash/prefill_sparse_attn.py
  • models/deepseek/v4-flash/prefill_swa.py
  • models/deepseek/v4-flash/prefill_swa_cp.py
  • models/deepseek/v4-flash/prefill_zigzag_cp.py
🛑 Comments failed to post (9)
models/deepseek/v4-flash/decode_hca.py (5)

13-14: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the companion file names after the rename.

The docstring points to attention_swa.py and attention_csa_draft.py. This PR renames the attention entry files to mode-first names, so these paths no longer exist. Use decode_swa.py and decode_csa.py.

📝 Proposed doc fix
-Companion files: attention_swa.py (ratio=0)
-                 attention_csa_draft.py (ratio=4)."""
+Companion files: decode_swa.py (ratio=0)
+                 decode_csa.py (ratio=4)."""

As per coding guidelines "Keep public documentation and examples aligned when behavior changes".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Companion files: decode_swa.py (ratio=0)
                 decode_csa.py (ratio=4)."""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_hca.py` around lines 13 - 14, Update the
companion-file references in the module docstring to use the renamed mode-first
files decode_swa.py and decode_csa.py, replacing the obsolete attention_swa.py
and attention_csa_draft.py names.

Source: Coding guidelines


84-90: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare the HCA compressed topk bound with the sparse module's CMP_TOPK.
set -euo pipefail

fd -t f 'decode_sparse_attn_hca.py' | while IFS= read -r file; do
  echo "== $file"
  rg -n -C 3 '^CMP_TOPK|^IDX_TOPK|^TOPK\b|^WIN\b|^PADDED_TOPK' "$file"
done

fd -t f 'config.py' --full-path 'v4-flash' | while IFS= read -r file; do
  rg -n 'index_topk|max_position_embeddings|sliding_window' "$file"
done

Repository: hw-native-sys/pypto-lib

Length of output: 2951


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate v4-flash files =="
fd -t f 'decode_hca.py|decode_sparse_attn_hca.py|config.py|.*\.json$' models/deepseek/v4-flash -x sh -c 'echo "-- $1"; wc -l "$1"' sh {}

echo "== relevant decode_hca.py sections =="
sed -n '1,120p' models/deepseek/v4-flash/decode_hca.py
sed -n '220,255p' models/deepseek/v4-flash/decode_hca.py

echo "== search COMPRESS_RATIO definitions/usages =="
rg -n -C 2 'COMPRESS_RATIO|DEFAULT_COMPRESS_RATIO|index_topk|max_position_embeddings|sliding_window|MAX_SEQ_LEN|CMP_TOPK|HCA_TOPK_LIMIT|HCA_CMP_TOPK|topk_all' models/deepseek/v4-flash

echo "== compute constants from source text (no repo code run) =="
python3 - <<'PY'
import pathlib, re
fp = pathlib.Path("models/deepseek/v4-flash/decode_sparse_attn_hca.py")
text = fp.read_text()
m = dict(re.findall(r'^(?:PADDED_)?TOPK\s*=\s*(.+)$|^(?:DEFAULT_)?COMPRESS_RATIO\s*=\s*(.+)$|^M\.(.+)$', text, re.M))
# extract expressions and evaluate only if safe numeric-like
def safe(expr):
    try:
        return eval(expr, {"__builtins__":{}}, {
            "MAX_SEQ_LEN": 16384,
            "sliding_window": 512,
            "ATTN_K_TILE": next(int(s) for s in re.findall(r'\bATTN_K_TILE\b', text)),
            "BLOCK_SIZE": 16,
            "GATHER_SEGS": 2,
        })
    except Exception as e:
        return f"<eval_failed: {e!r}>"
attrs = ["MAX_SEQ_LEN", "sliding_window", "DEFAULT_COMPRESS_RATIO", "ATTN_K_TILE", "BLOCK_SIZE", "GATHER_SEGS"]
for a in attrs:
    print(f"M.{a} = {safe(a)}")
for name in ["PADDED_TOPK", "TOPK", "CMP_TOPK", "SPARSE_BLOCKS"]:
    print(f"{name} = {m.get(name)} -> {safe(m.get(name))}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 50380


🏁 Script executed:

#!/bin/bash
#!/bin/bash
set -euo pipefail

echo "== targeted constants at v4-flash decode files =="
for f in models/deepseek/v4-flash/decode_hca.py models/deepseek/v4-flash/decode_sparse_attn_hca.py; do
  echo "-- $f"
  rg -n -C 3 '^(COMPRESS_RATIO|DEFAULT_COMPRESS_ratio|HCA_TOPK_LIMIT|HCA_CMP_TOPK|AT...|ATTN_K|BLOCK_SIZE|PADDED_TOPK|TOPK)$|^(CMP_)?(TOPK|CAPACITY|BLOCKS|TOPK_LIMIT).*=|from .* import' "$f"
done

echo "== exact targeted definitions only =="
python3 - <<'PY'
import pathlib, re
files = [
  pathlib.Path("models/deepseek/v4-flash/decode_hca.py"),
  pathlib.Path("models/deepseek/v4-flash/decode_sparse_attn_hca.py"),
]
for p in files:
    print(f"-- {p}")
    text = p.read_text()
    for pat in [
        r'(?m)^COMPRESS_RATIO\s*=\s*(.+)$',
        r'(?m)^DEFAULT_COMPRESS_RATIO\s*=\s*(.+)$',
        r'(?m)^HCA_TOPK_LIMIT\s*=\s*(.+)$',
        r'(?m)^HCA_CMP_TOPK\s*=\s*(.+)$',
        r'(?m)^CMP_TOPK\s*=\s*(.+)$',
        r'(?m)^MAYBE_BLOCK_SIZE\s*=\s*(.+)$',
        r'(?m)^AT..._K_TILE\s*=\s*(.+)$',
        r'(?m)^TOPK\s*=\s*(.+)$',
        r'(?m)^PADDED_TOPK\s*=\s*(.+)$',
    ]:
        m = re.search(pat, text)
        if m:
            print(f"{pat.split('s',1)[0].strip()[1:-1]} = {m.group(1)}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 4585


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== decode_hca.py relevant constants =="
sed -n '60,95p' models/deepseek/v4-flash/decode_hca.py

echo "== decode_sparse_attn_hca.py constants and sparse-attn loop =="
rg -n -C 4 '^(AT..._K_TILE|BLOCK_SIZE|MAYBE_|ATTN_|DEFAULT_|CMP_CAPACITY|CMP_TOPK|TOPK|PADDED_TOPK)$|^def sparse_attn_hca|^CMP_TOPK' models/deepseek/v4-flash/decode_sparse_attn_hca.py

echo "== all topk_usages and loop boundaries in sparse model =="
rg -n -C 3 'topk_all|range\(|valid_comp|CMP_TOPK|TOPK|window_start|position|score_pos|kv_pos' models/deepseek/v4-flash/decode_sparse_attn_hca.py

echo "== numeric probe from source constants =="
python3 - <<'PY'
import pathlib, re
from collections import OrderedDict

files = [
 ("models/deepseek/v4-flash/decode_hca.py", ["COMPRESS_RATIO", "DEFAULT_COMPRESS_RATIO", "HCA_TOPK_LIMIT", "HCA_CMP_TOPK", "PADDED_TOPK"]),
 ("models/deepseek/v4-flash/decode_sparse_attn_hca.py", ["WIN", "PADDED_TOPK", "ATTN_K_TILE", "BLOCK_SIZE", "MAYBE_BLOCK_SIZE", "COMPACTION...", "DEFAULT_COMPRESS_RATIO", "CMP_CAPACITY", "CMP_TOPK", "MAX_SEQ_LEN", "TOPK", "TOPK_FULL", "SPARSE_BLOCKS", "GATHER", "GATHER_SEGS"]),
]
for path, wanted in files:
    print(f"-- {path} wanted")
    text = pathlib.Path(path).read_text()
    for pat in wanted:
        m = re.search(fr'(?m)^{re.escape(pat)}\s*=\s*(.+)$', text)
        if m:
            print(f"{pat}={m.group(1)}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 19052


Replace HCA_CMP_TOPK with HCA_TOPK_LIMIT.

HCA_TOPK_LIMIT is MAX_SEQ_LEN // 128 (128), but HCA_CMP_TOPK follows get_standalone_cmp_valid() and can be smaller for non-128 ratios. Use HCA_TOPK_LIMIT for the HCA top-k bound and assert HCA_TOPK_LIMIT >= get_standalone_cmp_valid(128) instead of reusing the generic sparse CMP_TOPK.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_hca.py` around lines 84 - 90, Replace
HCA_CMP_TOPK usage with HCA_TOPK_LIMIT for the HCA top-k bound, and add an
assertion that HCA_TOPK_LIMIT is at least get_standalone_cmp_valid(128). Do not
reuse HCA_SPARSE_CMP_TOPK for this HCA limit.

195-202: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add a divisibility assertion for HCA_WB_TOKEN_TILE.

The grid is T // HCA_WB_TOKEN_TILE. If T is not a multiple of HCA_WB_TOKEN_TILE, the last T % HCA_WB_TOKEN_TILE tokens are never written into kv_cache. The kernel produces no error; the cache silently keeps stale rows and attention reads wrong KV. T = DECODE_BATCH * DECODE_SEQ comes from config, so a config change can break this without warning. decode_sparse_attn_csa.py guards the same class of assumption with module-level asserts (Lines 141-154).

🛡️ Proposed guard
 HCA_TOPK_TOKEN_TILE = 8   # tokens per cache-window topk SPMD block
 HCA_WB_TOKEN_TILE = 8  # tokens per cache-writeback SPMD block
+
+assert T % HCA_WB_TOKEN_TILE == 0, "cache writeback grid must cover every token"
+assert T % HCA_TOPK_TOKEN_TILE == 0, "cache topk grid must cover every token"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_hca.py` around lines 195 - 202, Add a
module-level divisibility assertion for HCA_WB_TOKEN_TILE, matching the guard
style used in decode_sparse_attn_csa.py, to ensure the configured T value is an
exact multiple of HCA_WB_TOKEN_TILE before the writeback loop runs. Preserve the
existing writeback logic in the hca_cache_writeback loop.

225-241: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

The topk_t < T guard is unreachable, and the tail tokens are unreachable too.

topk_t0 is at most (T // HCA_TOPK_TOKEN_TILE - 1) * HCA_TOPK_TOKEN_TILE, and topk_dt < HCA_TOPK_TOKEN_TILE, so topk_t is always below T. The condition at Line 229 never fails. The real gap is the opposite: when T is not a multiple of HCA_TOPK_TOKEN_TILE, the tail tokens keep the uninitialized topk_all contents, which sparse_attn_hca then reads as compressed slots. This shares the root cause with the writeback grid at Lines 195-202.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_hca.py` around lines 225 - 241, Update the
top-k token iteration around topk_all so the final partial HCA_TOPK_TOKEN_TILE
is included rather than relying on a grid that truncates the tail. Remove the
ineffective topk_t < T guard or replace the loop bounds with a ceil-divided
token-block count, and ensure every token index below T initializes its
HCA_CMP_TOPK entries to valid compressed slots or -1 consistently with
sparse_attn_hca expectations.

273-276: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare InOut/is_output marking for compressor-written caches across v4-flash modules.
set -euo pipefail

rg -n -C 2 'cmp_kv|compress_state' --glob 'models/deepseek/v4-flash/*.py' | rg -n 'InOut|is_output' -C 2

Repository: hw-native-sys/pypto-lib

Length of output: 161


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidates =="
git ls-files 'models/deepseek/v4-flash/*.py' | sed -n '1,200p'

echo "== target file line count =="
wc -l models/deepseek/v4-flash/decode_hca.py

echo "== decode_hca relevant sections =="
sed -n '240,310p' models/deepseek/v4-flash/decode_hca.py
sed -n '630,660p' models/deepseek/v4-flash/decode_hca.py

Repository: hw-native-sys/pypto-lib

Length of output: 8292


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== decode_compressor_ratio128 outline =="
ast-grep outline models/deepseek/v4-flash/decode_compressor_ratio128.py --view compact || true

echo "== decode_compressor_ratio128 relevant writes =="
rg -n -C 3 'compress_state|cmp_kv|compressor_ratio128|def golden|is_input|InOut|In|Out' models/deepseek/v4-flash/decode_compressor_ratio128.py

echo "== prefill compressor tensor specs =="
rg -n -C 2 'compress_state|cmp_kv|TensorSpec' models/deepseek/v4-flash/prefill_compressor_ratio128.py

echo "== compare svmlib/prefill/sparse HCA signatures and specs =="
for f in \
  models/deepseek/v4-flash/prefill_hca.py \
  models/deepseek/v4-flash/decode_swa.py \
  models/deepseek/v4-flash/decode_sparse_attn_hca.py \
  models/deepseek/v4-flash/decode_metadata.py
do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    rg -n -C 2 'cmp_kv|compress_state|pl\.InOut|TensorSpec\("compress_state"|TensorSpec\("cmp_kv"|is_output=True' "$f" || true
  fi
done

Repository: hw-native-sys/pypto-lib

Length of output: 31902


Mark compress_state and cmp_kv as outputs in attention_hca_test.

compressor_ratio128 writes compress_state rows and the pooled cmp_kv_cache; golden_compressor does the same. In this harness, pass them as pl.InOut, and add is_output=True plus comparison for both compress_state and cmp_kv in the TensorSpecs so the compressor cache updates are exercised.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_hca.py` around lines 273 - 276, Update
attention_hca_test’s compressor-cache handling: declare compress_state and
cmp_kv as pl.InOut, and mark both corresponding TensorSpecs with is_output=True
and output comparison. Ensure compressor_ratio128 and golden_compressor updates
to these buffers are validated.
models/deepseek/v4-flash/decode_sparse_attn_csa.py (2)

256-264: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The block-validity mapping assumes WIN == ATTN_K_TILE; add an assertion.

Sparse block sb covers sparse-K columns [sb*ATTN_K_TILE, (sb+1)*ATTN_K_TILE). The code maps block sb >= 1 to compressed-mask columns [(sb-1)*ATTN_K_TILE, sb*ATTN_K_TILE), and it treats block 0 as pure window. Both mappings hold only when WIN equals ATTN_K_TILE exactly.

If WIN > ATTN_K_TILE, block 1 still contains window columns but its validity comes from the compressed mask. If WIN < ATTN_K_TILE, block 0 already contains compressed columns and block 1 reads the wrong compressed offset. In both cases qk_pv can take the empty branch at Line 370 for a block that holds valid KV, write mi = -3.0e38 and li = 0, and drop that attention mass with no error.

The module already asserts the other tiling invariants at Lines 141-154. Add this one.

🛡️ Proposed guard
 assert WIN <= TOPK <= TOPK_FULL, f"TOPK ({TOPK}) must be in [WIN={WIN}, TOPK_FULL={TOPK_FULL}]"
+# Block 0 is treated as pure window and block sb>=1 maps to compressed-mask
+# columns [(sb-1)*ATTN_K_TILE, sb*ATTN_K_TILE); both hold only at this equality.
+assert WIN == ATTN_K_TILE, f"valid_block_mask assumes WIN ({WIN}) == ATTN_K_TILE ({ATTN_K_TILE})"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` around lines 256 - 264,
Add an assertion alongside the existing tiling-invariant checks in the module
initialization/configuration validation to require WIN == ATTN_K_TILE. Keep the
block-validity mapping in the loops using its current offsets, and ensure
invalid configurations fail before qk_pv executes.

743-743: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add strict=True to zip().

Ruff reports B905 on this call. The three lists always have the same length, so the behavior does not change today, but strict=True makes that invariant explicit and catches a future mismatch.

🔧 Proposed fix
-        for mi_cur, li_cur, oi_cur in zip(block_mi[1:], block_li[1:], block_oi[1:]):
+        for mi_cur, li_cur, oi_cur in zip(block_mi[1:], block_li[1:], block_oi[1:], strict=True):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        for mi_cur, li_cur, oi_cur in zip(block_mi[1:], block_li[1:], block_oi[1:], strict=True):
🧰 Tools
🪛 Ruff (0.16.0)

[warning] 743-743: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_sparse_attn_csa.py` at line 743, Update the
zip call in the loop over block_mi, block_li, and block_oi to pass strict=True,
explicitly validating that all three iterables have equal lengths while
preserving the existing iteration behavior.

Source: Linters/SAST tools

models/deepseek/v4-flash/decode_swa.py (1)

14-15: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the companion file names after the rename.

This PR renames the attention entry files to mode-first names. The docstring still points to attention_csa_draft.py and attention_hca_draft.py, which no longer exist. Use decode_csa.py and decode_hca.py.

📝 Proposed doc fix
-Companion files: attention_csa_draft.py (ratio=4)
-                 attention_hca_draft.py (ratio=128)."""
+Companion files: decode_csa.py (ratio=4)
+                 decode_hca.py (ratio=128)."""

As per coding guidelines "Keep public documentation and examples aligned when behavior changes".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Companion files: decode_csa.py (ratio=4)
                 decode_hca.py (ratio=128)."""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/decode_swa.py` around lines 14 - 15, Update the
module docstring’s companion file references to use decode_csa.py and
decode_hca.py instead of the renamed attention_csa_draft.py and
attention_hca_draft.py entries, preserving the existing ratio annotations.

Source: Coding guidelines

models/deepseek/v4-flash/prefill_csa_cp.py (1)

1973-1973: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the shared FP32_NEG_INF sentinel for sparse_bias.

This line initializes sparse_bias to the literal -3.0e38. prefill_hca_cp.py line 924 and prefill_swa_cp.py line 452 initialize the same buffer with FP32_NEG_INF from config. _prefill_cp_sparse_stage also writes FP32_NEG_INF into the padding columns at prefill_exchange_cp.py lines 597-601.

If the two values differ, masked and padded columns in this path carry different sentinels than the other CP paths, which changes the pl.row_max and pl.exp behavior in _prefill_sparse_attn_math. Import FP32_NEG_INF from config and use it here.

♻️ Proposed fix
 from config import (
     BLOCK_SIZE,
     CSA_INNER_STATE_PHYSICAL_BLOCKS,
     CSA_STATE_PHYSICAL_BLOCKS,
     FLASH as M,
+    FP32_NEG_INF,
     IDX_CACHE_MAX_BLOCKS,
-    sparse_bias = pl.create_tensor([LOCAL_ROWS, PREFILL_SPARSE_PAD], dtype=pl.FP32, init_value=-3.0e38)
+    sparse_bias = pl.create_tensor([LOCAL_ROWS, PREFILL_SPARSE_PAD], dtype=pl.FP32, init_value=FP32_NEG_INF)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    sparse_bias = pl.create_tensor([LOCAL_ROWS, PREFILL_SPARSE_PAD], dtype=pl.FP32, init_value=FP32_NEG_INF)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/deepseek/v4-flash/prefill_csa_cp.py` at line 1973, Update the
sparse_bias initialization in the prefill sparse attention path to import
FP32_NEG_INF from config and use it instead of the literal -3.0e38, keeping the
existing tensor shape, dtype, and initialization behavior unchanged.

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.

1 participant