Skip to content

refactor(kda): stop 0.7 advertising unreleased KDA surface (mark prefill wrapper experimental, trim kda_kernels.__all__) - #5040

Open
kahyunnam wants to merge 3 commits into
flashinfer-ai:mainfrom
kahyunnam:kda/mark-prefill-wrapper-experimental
Open

refactor(kda): stop 0.7 advertising unreleased KDA surface (mark prefill wrapper experimental, trim kda_kernels.__all__)#5040
kahyunnam wants to merge 3 commits into
flashinfer-ai:mainfrom
kahyunnam:kda/mark-prefill-wrapper-experimental

Conversation

@kahyunnam

@kahyunnam kahyunnam commented Sep 8, 2026

Copy link
Copy Markdown
Member

📌 Description

The 0.7 holding action from #4936 (steps 3b-i and 3c): stop 0.7 from
advertising KDA surface that has never shipped and that the unification plan
expects to change. Three independent commits, no kernel logic, no behaviour
change on any released path.

Commit 1 — mark RecurrentKDAPrefillWrapper experimental. plan and run
get @flashinfer_experimental_api (warns once per process), the class
docstring gets a .. warning:: banner naming #4936, and
docs/api/kda_prefill.rst labels the wrapper experimental in prose. The class,
its constructor and its behaviour are untouched.

Commit 2 — keep the SM120a prefill facade out of kda_kernels.__all__.
kda_kernels.__all__ grew from 6 entries to 9 since v0.6.18, and all three
additions are the SM120a helpers (can_implement_kda_prefill_sm120,
clear_kda_prefill_sm120_caches, run_kda_prefill_sm120). They are dispatch
plumbing for flashinfer.kda_prefill, not surface a release should freeze.
__all__ is now byte-identical to v0.6.18's.

Commit 3 — move the wrapper's own tests to the experimental lane, per the
experimental policy. Details under "Test scope" below.

Why now

None of this is in v0.6.18 — that tag has no kda_kernels/sm120_prefill/ at
all, and its kda_kernels/__init__.py has no SM120a entries. Both changes are
free today and cost a deprecation cycle once 0.7 cuts.

Why commit 2 changes no call site

Removing a name from __all__ leaves the attribute in place, and every
consumer reaches these three by attribute or by the deeper module path:

Consumer How it reaches them Affected
kda_prefill.py:7042, :7135 kda_kernels.can_implement_… / .run_… attribute no
docs/api/kda_prefill.rst:343, :369 flashinfer.kda_kernels.sm120_prefill.clear_…() no
tests/kda/test_recurrent_kda_prefill_sm120.py from …kda_kernels.sm120_prefill import … no
benchmarks/routines/kda.py:336 sm120_prefill.run_kda_prefill_sm120(…) no

Nothing in the tree does from flashinfer.kda_kernels import *, nothing
asserts __all__'s contents, and no Sphinx automodule targets
flashinfer.kda_kernels. clear_kda_prefill_sm120_caches stays reachable at
the exact path the docs tell users to call, which is the deeper one.

🔍 Related Issues

🧪 Tests

  • pytest tests/experimental/test_kda_prefill_wrapper.py2 passed.
  • pytest tests/kda/test_recurrent_kda_prefill.py247 passed, 1 skipped
    (B200, CC 10.0) after the relocation.
  • pytest tests/kda/ -k 'prefill or export or api or trace'523 passed,
    90 skipped
    .
  • pytest tests/kda/test_recurrent_kda_prefill_sm120.py50 passed, 88
    skipped
    (skips are the CC 12.0 cells; this host is CC 10.0).
  • Confirmed pytest tests/ does not collect the relocated file, and that
    scripts/pr_checks/experimental_test_scope.py accepts the fence below.
  • Behavioural checks on B200: the wrapper still constructs and plans; plan
    and run carry is_experimental; the warning fires exactly once across two
    plan calls; all three SM120a names are absent from __all__ yet still
    present as attributes; _sm120_kda_prefill_is_eligible still resolves.
  • pre-commit run clean on all six touched files.

📋 Not included (deliberately)

Step 3c in #4936 also proposes giving SM120a an explicit backend= literal and
gating its automatic branch with experimental_auto_backends_allowed(). Both
are omitted here: they change "auto" prefill routing on CC 12.0, and per
#4936 the gating mostly converts working calls into raises — the same failure
shape #5037 is fixing for decode. That belongs in its own PR, benchmarked and
validated on a CC 12.0 device, which this change does not require.

🚀 Pull Request Checklist

  • I have read the Contributing Guidelines.
  • I have installed and run pre-commit.
  • Tests have been added or updated as needed.
  • All tests are passing (unittest, etc.).

🔬 Experimental Track

  • This PR is experimental: it adds or changes code under flashinfer/experimental/ and/or an @flashinfer_experimental_api. Tracking issue: [KDA] Unify the public recurrent_kda API, and settle the unreleased KDA surface before FI v0.7 #4936
    • The tracking issue names an owner, the reason for the experimental path, and a graduation plan with a target release.
    • Core changes are limited to a thin entry point (signature, shared validation, feature-gate check, backend selection, handoff).
    • Tests live in tests/experimental/ and were validated on the intended hardware; a runnable example is included.
    • Nothing is registered in flashinfer/aot.py, and no experimental backend is reachable from backend="auto" without FLASHINFER_ALLOW_EXPERIMENTAL_AUTO_BACKENDS=1. (Calling an @flashinfer_experimental_api or naming a backend explicitly is itself the opt-in and needs no environment variable.)
    • Test scope declared below. The experimental CI lane runs exactly these targets, so keep them as narrow as the change allows.
tests/experimental/test_kda_prefill_wrapper.py

Notes on the checklist, since this is a retrofit rather than a new feature

The policy is written for a new, self-contained feature under
flashinfer/experimental/. This is the opposite case — a marker applied to
already-merged, unreleased surface that shares kernels and tests with a stable
API — so three items deserve explanation rather than a bare tick:

Test scope. The two tests covering the wrapper's own contract (the plan
metadata it builds, the buffers it forwards) moved to
tests/experimental/test_kda_prefill_wrapper.py. Three tests that drive the
wrapper but whose subject is the CuTe DSL prefill kernels stayed in
tests/kda/test_recurrent_kda_prefill.py:
test_cute_dsl_checkpoints_match_cake,
test_cute_dsl_padded_indexed_state_matches_cake and
test_cute_dsl_planned_zero_length_cuda_graph_capture_and_replay. They use the
wrapper because it is the only planned-path entry point, and relocating them
would take CuTe-vs-Cake numerics and graph-capture correctness out of
pytest tests/ (pytest.ini sets norecursedirs = … tests/experimental) while
dragging along that file's autouse legacy-stub fixture and ~200 lines of
reference implementation. Happy to move them too if you would rather the
experimental lane own every call site.

Runnable example. No new examples/ entry; the wrapper's usage is already
documented on docs/api/kda_prefill.rst, now labelled experimental.

aot.py. This PR adds nothing to aot.py. Strictly, though, the wrapper
is a thin host-side planner that forces backend="cute-dsl" and hands off to
recurrent_kda, so the kernels beneath it are the stable prefill path's
AOT-registered modules. They cannot be de-registered without de-registering
stable KDA prefill, so "experimental features are JIT-only" holds for the
wrapper's own code but not for the kernels it borrows. Flagging rather than
hiding it.

One visible side effect: the three stable-lane tests above now emit
ExperimentalWarning when they drive the wrapper. That is the marker working
as intended, and the suite passes with it.

Summary by CodeRabbit

  • Documentation

    • Marked RecurrentKDAPrefillWrapper as experimental, including its packed engine CUDA Graph capture usage.
    • Updated guidance for accessing SM120 prefill functionality.
  • API

    • Added experimental status indicators to the wrapper and its planning and execution methods.
    • Removed SM120 prefill utilities from package-level exports.
  • Tests

    • Added coverage for wrapper planning metadata, validation, buffer reuse, and execution behavior.
    • Centralized shared recurrent-KDA prefill test inputs for stable and experimental test suites.

The wrapper has not appeared in a release and its plan-and-run shape is
expected to change as the recurrent_kda surface is unified (flashinfer-ai#4936), so 0.7
should not advertise it as stable. plan and run carry
@flashinfer_experimental_api, which warns once per process, and the class
docstring and docs page say so.
The three *_kda_prefill_sm120 names are unreleased -- kda_kernels.__all__ grew
from 6 entries to 9 since v0.6.18 and these are the delta. They are dispatch
plumbing for flashinfer.kda_prefill, not surface a 0.7 cut should freeze. Every
consumer reaches them as attributes or through kda_kernels.sm120_prefill, so no
call site changes.
…lane

The experimental policy asks for an experimental API's tests under
tests/experimental/. The two tests covering the wrapper's own contract -- the
plan metadata it builds and the buffers it forwards -- move there; the shared
cpu_route_tensors factory moves to tests/test_helpers/ because the two lanes
cannot import each other.

Tests whose subject is the CuTe DSL prefill kernels stay in the stable lane
even though they drive the wrapper, since it is the only planned-path entry
point: moving them would take kernel numerics out of 'pytest tests/'.
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 9e3814cf-fe0a-49f7-986c-dcdb651e5271

📥 Commits

Reviewing files that changed from the base of the PR and between f32f740 and e639537.

📒 Files selected for processing (6)
  • docs/api/kda_prefill.rst
  • flashinfer/kda.py
  • flashinfer/kda_kernels/__init__.py
  • tests/experimental/test_kda_prefill_wrapper.py
  • tests/kda/test_recurrent_kda_prefill.py
  • tests/test_helpers/kda_prefill.py

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The pull request marks RecurrentKDAPrefillWrapper as experimental, removes SM120 prefill symbols from package-level exports, adds dedicated wrapper tests, and shares recurrent-KDA test input construction across stable and experimental tests.

Changes

KDA prefill API

Layer / File(s) Summary
Experimental wrapper contract
flashinfer/kda.py, docs/api/kda_prefill.rst
The wrapper, plan, and run now carry experimental API markers. The documentation identifies the wrapper as experimental.
Package export surface
flashinfer/kda_kernels/__init__.py
The package no longer exports the three SM120 prefill symbols. Its documentation points to the supported module paths.
Wrapper validation and shared test inputs
tests/experimental/test_kda_prefill_wrapper.py, tests/kda/test_recurrent_kda_prefill.py, tests/test_helpers/kda_prefill.py
New tests validate planning metadata, buffer reuse, input validation, workspace metadata, and kernel argument forwarding. Shared CPU test tensors replace the removed local helper.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to e6395

This change labels the unreleased KDA prefill wrapper as experimental, narrows package exports, and reorganizes its tests without changing kernel behavior. No current merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 5 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the KDA API exposure refactor, including marking the prefill wrapper experimental and removing SM120 helper names from all.
Description check ✅ Passed The description follows the required template, explains the changes and rationale, links related issues, reports tests and pre-commit results, completes the checklist, and declares the experimental te…
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 9.52% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 5 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@kahyunnam

Copy link
Copy Markdown
Member Author

/bot runt tests/kda

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

Unknown Command

Command /bot runt tests/kda is not recognized.

Use /bot help for available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

op: linear attention KDA, mamba, GDN, etc. review filtering.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants