Add DeepSeek V4 Flash CPU inference with NVMe expert streaming - #165
Add DeepSeek V4 Flash CPU inference with NVMe expert streaming#165DrewZt wants to merge 17 commits into
Conversation
rajpratham1
left a comment
There was a problem hiding this comment.
This is a very impressive contribution and clearly represents a significant amount of engineering work. The implementation covers a complete DeepSeek V4 CPU inference pipeline including runtime, expert streaming, quantization, safetensors loading, CLI tooling, documentation, and an extensive unit test suite.
Because this PR introduces an entirely new inference stack across many core components, I'd prefer additional review before approval.
Some areas that would benefit from closer review include:
- Long-term API stability for the new DeepSeek V4 interfaces.
- Memory ownership and lifetime throughout the expert streaming/runtime pipeline.
- Performance characteristics of the NVMe streaming implementation under sustained inference.
- Cross-platform compatibility (Windows/Linux/macOS) for filesystem and I/O paths.
- Validation against larger real-world models beyond the included unit tests.
Overall the direction looks very promising, but given the size and architectural impact of this change, I think it should receive another maintainer review before merging.
|
Thanks for the thoughtful review. I agree that another maintainer review is appropriate given the size of the change. A few clarifications on the areas you mentioned: API stability: the new interfaces are currently scoped to the DeepSeek V4 engine and should be considered experimental. They are not intended to establish a stable generic model API at this stage. I’m happy to address targeted follow-up findings, add more validation, or split parts of the implementation into staged PRs if the maintainers feel that would make review and long-term maintenance easier. |
|
I pushed a follow-up series through The main changes are:
The latest changes pass: The remaining validation work is focused on sustained NVMe behavior and broader full-model comparison against the official Transformers implementation. Those limitations remain documented in the PR and do not represent unresolved API or resource-lifetime issues. I’m marking the PR ready for review and would appreciate another maintainer look, particularly at the revised API boundary and ownership model. |
|
First full-model validation on Linux/x86-64 — plus a build fix and an AVX2 kernel series, branch ready to pull: steve-m/colibri@v4-avx2-kernels (5 commits on top of this PR's Hardware: Ryzen 9 3900X (Zen 2, 12C/24T, AVX2 no AVX-512), 62 GiB RAM, NVMe ~6 GB/s, Manjaro, gcc 15. Model: Build fix you'll want regardless: two amalgam units ( Kernel series (all behind a
Measured, 48-token free-form decode, OMP_NUM_THREADS=12: 0.53 tok/s (PR defaults) → 0.62 (threads = physical cores; SMT only adds barrier traffic) → 0.78 (FP4 int8) → 0.99 (head) → 1.12 tok/s (FP8). Verify phase −27%, TTFT 20 → 16.7 s. Validation at every step: your oracle tool's Also on the branch, off by default: a dual-SSD mirror ( Happy to split any of this into separate PRs against your |
This is extremely helpful — thank you for doing the first independent full-model Linux/x86-64 validation and for documenting the performance progression in such detail. The Ryzen 3900X result directly addresses one of the main remaining validation gaps for this PR, and the 0.53 → 1.12 tok/s breakdown makes it much easier to see where the current bottlenecks are. I checked the branch history and it looks like Those later commits include the revised public/internal API separation, engine/session lifetime accounting, failure-path cleanup, isolated ownership-test objects, and V4 session tokenizer cleanup. The optimization work is still very valuable, but it should be rebased onto One clarification regarding the pthread build issue: I had already addressed the missing declaration problem in Your source-level includes may still be a cleaner and more localized solution, but the issue itself no longer needs a separate build-fix PR. When rebasing, please either drop the overlapping build-fix commit or call out why replacing the current compiler-level include with explicit includes in the two amalgam units would be preferable. For the remaining work, I suggest splitting it into two focused follow-ups:
I also noticed that the branch diff appears to include generated test binaries such as: Please drop those artifacts when preparing the follow-up PRs. After rebasing, please rerun the full-model correctness and performance validation because the runtime and ownership code has changed since The current benchmark result is already valuable as independent validation of the earlier implementation. Once the rebased kernel series is reviewed, I’d be happy to add the reproducible Linux/x86-64 measurements to the documentation with credit to you and the exact hardware and commands. Thanks again — this is a substantial and very useful contribution. Rebasing and splitting it should let us preserve the recent API and ownership work while giving the kernels and storage experiment the focused review they deserve. |
|
Follow-up for @JustVugg: head af86de1 closes the remaining validation findings. The safetensors index now requires payload bytes to equal dtype width times shape numel; V4 config integers, floats, and compress ratios now have finite/integer/range checks. I also removed the dense-cache borrowed config pointer in favor of the engine-owned canonical config and made the DSpark oracle require exact output lengths on both paths. Fresh validation passed make check (all C tests plus 71 Python tests), x86-64-v3/native builds, ASan+UBSan+LSan, and the 48-shard MEMORY_GB=32 oracle (19/19 teacher forcing, 8/8 greedy, 8/8 continuation self-check, exact DSpark on/off identity). This supersedes my earlier blocker summary; AVX2 and dual-SSD work remain out of scope. Could you please review when convenient? |
|
Pushed the rebased AVX2 kernel series to Two changes from the old
The three commits, all behind the
Validation on the rebased branch — Ryzen 9 3900X (Zen 2, AVX2 no AVX-512), 62 GiB, gcc 16.1.1,
Perf — AVX2 on vs the Kernel-only isolation, DSpark disabled (
For reference, DSpark on (same prompt): decode 0.62 → 0.85 tok/s (+36%), TTFT 43.6 → 30.3 s (−30%) — but that pass had asymmetric acceptance (on 3/10 vs off 1/10 speculative tokens), so the isolated The float-path baseline matches the known physical-cores number, so the kill-switch cleanly isolates the kernel gain. TTFT is stable across the DSpark condition (~31 s on / ~48 s off), as expected — the first token is prefill + first decode, before any speculation. (Absolute tok/s is workload-dependent — this was a heavy ~80 GB-streaming pass; a lighter/warmer pass on this box peaks around 1.12 tok/s. The on/off ratio is the stable claim.) |
This looks excellent — thank you for rebasing the series carefully and for preserving the API and ownership work underneath it. The updated scope is exactly what I was hoping for:
I also appreciate the distinction between the DSpark-enabled result and the The zero-copy resident-head path being exercised by the full-model oracle is also useful confirmation that the new path is covered rather than only compiled. Since the kernel branch is stacked on top of #165, I think the cleanest next step is to keep the branch as-is for now and open a dedicated follow-up PR after #165 is merged. At that point it can be rebased onto the resulting upstream Please preserve the current commit separation and validation details in that PR. In particular, the Thanks again — this is a strong follow-up series, and the careful validation and honest performance attribution make it much easier to review. |
|
Pushed follow-up stability fix
Validation:
|
|
I'm interested in this — DeepSeek V4 Flash on CPU with NVMe expert streaming is squarely what colibrì is for, and I'd like it in. The one condition is that I need to run it on my own machine first. Not as a gate to be difficult: it's the rule I've had to learn the hard way this week. So: as soon as I can get a checkpoint on this box, I'll test it and we'll work on it together. That's not a "no" parked forever — it's the next thing I want to do on this front. Two things that would make it land sooner, and I'd rather ask than have you guess:
I saw the stability fix you pushed ( Keeping this open. Let's keep going. |
Thanks — this gives me a clear integration path. I’ll make the tiny DeepSeek V4 fixture the immediate priority. The goal will be a deterministic, independently generated checkpoint and reference that The initial test contract will cover:
The generator will remain available so the fixture is reproducible rather than an opaque committed artifact, while CI itself will use the checked-in tiny checkpoint and reference. I’ll also continue removing local duplication where that does not change runtime or kernel boundaries. For the deeper shared-I/O work—particularly consolidating the streaming read path with the existing DIRECT/URING infrastructure—I would prefer to do that as a focused follow-up after this base engine and the already prepared AVX2 series land. That keeps the current correctness and performance baselines stable, avoids repeatedly invalidating the AVX2 branch, and lets the tiny token-exact oracle protect the later refactor across both scalar and optimized paths. I’ll keep AVX2 and the dual-SSD experiment out of this PR, and I’ll document the shortest full-checkpoint smoke-test path for your machine alongside the tiny fixture. |
|
Implemented the requested deterministic tiny DeepSeek V4 + DSpark oracle at head
Manual local validation (from the repository root): # Dedicated tiny target + DSpark token-exact oracle
make -C c deepseek-v4-tiny-check ARCH=x86-64-v3
# Or run the complete dependency-free check suite
make -C c checkTo exercise the normal runtime explicitly with drafting disabled: cd c
make deepseek-v4 ARCH=x86-64-v3
./deepseek_v4 deepseek_v4_tiny '<t005><t007><t009>' \
--raw-prompt --draft-model deepseek_v4_tiny/dspark --no-dsparkThe generator and regeneration package versions are documented in |
sorry what?! That's impressive for NVMe. |
The prompt 'What is the capital of France' have some uniqueness, the answer token got 100% dspark acceptance rate, that is the fastest speed boost. |
|
On your own Pc, Vincent, how does it compare to GLM in speed if you don't mind me asking (And what are the specs of yours , and what OS) 🤔From: DrewZt ***@***.***>Sent: Saturday, July 18, 2026 12:07:24 pmTo: JustVugg/colibri ***@***.***>Cc: Maikel Frias Mosquea ***@***.***>; Comment ***@***.***>Subject: Re: [JustVugg/colibri] Add DeepSeek V4 Flash CPU inference with NVMe expert streaming (PR #165)DrewZt left a comment (JustVugg/colibri#165)1.12 tok/s (FP8).sorry what?! That's impressive for NVMe.The prompt 'What is the capital of France' have some uniqueness, the answer token got 100% dspark acceptance rate, that is the fastest speed boost.
For another 0% dspark acceptance rate special case 'hello', decode speed will drop to 0.59tok/s, which is slower than no-dspark situation—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.
|
My pc is ai max 395+128gb ram+6gb/s ssd, tested glm with config think=0 and mtp=1, got around 0.7 tok/s |
|
Status check: |
Yes, I’m still actively working on this. Please keep the PR open. I reviewed the impact of the current I’m going to treat this as a minimal forward port onto current Work I will complete before merging #165
I had already done additional local work around redundant expert reads and the streamed I/O path, but I intentionally did not push it onto #165. At that point the branch had a stable correctness baseline and Steve’s AVX2 series was stacked on top of it; changing the I/O and cache boundaries again would have invalidated both his branch and the existing measurements. Work planned after #165 merges
So the immediate objective is to restore #165 on current |
|
The forward port is now pushed. PR #165 now points to The main Local The new PR workflows are currently waiting for maintainer approval. Could you approve them so the checks can run? |
|
CI is green — both workflows, all jobs. Sorry that took a day: GitHub holds workflow runs from contributors whose first PR here hasn't merged yet, and I hadn't spotted how many were queued behind that setting. Nothing to do with your code. So the state now: 20,780 lines, forward-ported onto current dev, and our own gates pass on it for the first time. That plus the fact that it touches neither I owe you a real read of the engine before merging, which is the part I can't rush. Two things that would help while I do that:
Thanks for staying with this through a refactor that would have killed most PRs. |
Thanks — and yes, the target engine is intended to be config-driven rather than tied to the Flash dimensions. Layer count, hidden size, attention ranks, expert count, MoE width, compression schedule, and tensor shapes are all derived from One important current limitation: please use the DeepSeek-V4-Flash-DSpark checkpoint for testing, not the plain Flash checkpoint. I found a checkpoint read issue yesterday, and the current branch only loads the DSpark-packaged layout correctly. Target-only execution can still be tested with --no-dspark; the limitation is the checkpoint package being loaded. I have not fixed the plain-checkpoint path yet. I have not tested a Pro checkpoint yet, so I would treat that as expected compatibility rather than confirmed support. The main things to verify are tensor names, compression ratios, tokenizer/prompt format, memory planning, and the Pro DSpark stage layout if a draft checkpoint is available. The most useful places to review first are:
One additional note: the implementation still contains a non-trivial number of reference, fallback, and experimental paths that emerged during development. Some are useful correctness baselines or low-memory fallbacks; others may now duplicate the preferred path. I avoided broad pruning during the forward port to keep the validated behavior stable. After Flash and Pro validation, I’d like to classify them explicitly: retain tested fallbacks, isolate research-only variants, and remove purely historical duplication. |
|
Pushed two follow-up commits, now at b09ab5: --no-dspark is now a true target-only mode and no longer requires or initializes a DSpark checkpoint. Initial V4-Pro target-only performance under the current test configuration: 16 GiB memory limit: 0.087 tok/s V4-Pro DSpark support has not been implemented; Pro currently requires --no-dspark. |
The V4 core and its quantization kernels are portable C; the only x86 dependencies were two unconditional immintrin.h includes (whose intrinsics were already gated behind __AVX512F__) and the platform gates themselves. Guard the includes with __AVX512F__, accept aarch64/arm64 in the Makefile.deepseek-v4 uname gate, and add an aarch64-linux branch to the parent COLI_V4_SUPPORTED triplet gate so the amalgam unit tests and the tiny oracle run in make check. Without AVX-512 the rows16 hot-expert packing stays disabled and the engine uses the portable reference paths, exactly as on pre-AVX-512 x86. Validated on NVIDIA DGX Spark GB10 (Cortex-X925/A725, gcc 13.3.0): make check green (79 Python tests, 19 C test binaries, tiny oracle 11/11 token-exact), plus tiny fixture regenerated on-device with transformers 5.14.1 (identical reference tokens) and re-passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add aarch64 NEON implementations of coli_fp4_matvec_rows16_v10 and coli_fp4_dual_matvec_rows16_v10 using the same 16-row interleaved layout as the AVX-512 kernels. The 16-entry E2M1 table is exactly 64 bytes, so a four-register TBL gathers whole decoded floats; UE8M0 block scales decode through the table once per 32-column block. Arithmetic is the same (activation * value) * scale multiply-multiply-add per column with no fused multiply-add, columns ascending, one row per vector lane — so rows are bit-identical to the scalar reference and to the AVX-512 kernel. A new COLI_FP4_ROWS16_KERNEL macro in native_quant_fp4_rows16.h names targets that have a rows16 kernel; the four engine gates that packed hot experts only under __AVX512F__ now key on it, enabling hot-pin packing on aarch64 under the same conditions as x86. x86 preprocessing is unchanged: with __AVX512F__ the macro is defined and the same branches are selected. Validation on GB10 (Cortex-X925/A725, gcc 13.3.0): standalone harness compares NEON kernels against the flat scalar reference over five shapes up to 7168x2048 (single and dual, both nibble paths) — all outputs bit-identical with -ffp-contract=off and with default -O3; make check green including the token-exact tiny oracle. Note the tiny fixture leaves pin_slots_per_layer=0 (4 experts, all resident) on every platform, so rows16 execution coverage comes from the harness, not the oracle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Tested this PR on aarch64 — first datapoint outside x86-64, I believe: NVIDIA DGX Spark GB10 (Grace, 10× Cortex-X925 + 10× Cortex-A725, 121 GB unified LPDDR5x), Ubuntu 24.04, gcc 13.3.0. The engine core is genuinely portable: with the platform gates bypassed, 41 of 43 amalgam TUs compile clean on aarch64 with zero warnings. The only x86 dependencies were the two unconditional I put up a small branch on top of this PR's current head (2 commits, 6 files, +197/−15): whale-agent-lab#1. It:
Validation on the GB10, on top of b09ab5d:
Kernel bench at the real V4-Flash expert shapes (hidden 4096 × moe_inter 2048, FP4), flat OMP scalar (
Pack cost is ~2.9 ms per 4 MiB matrix, once per pinned expert. These are kernel-level numbers only — no full-model tokens/s yet (checkpoint download pending on this box). Happy to split the build enablement from the NEON kernels if you'd rather keep this PR x86-only — whichever is easier. |
This is excellent work — thank you for the thorough aarch64 validation and the focused NEON implementation. The changes look reasonably contained, so I don’t think it makes sense to ask you to restructure them again unless the maintainers prefer a separate follow-up. I’ll keep the V4 runtime and kernel interfaces stable from this point so the branch does not need another rebase due to changes from my side. I’m happy to leave the integration decision to @JustVugg: these commits can remain part of #165 if the added review scope is acceptable, or be moved to a focused follow-up if keeping the base PR x86-only would make the merge easier. |
|
Thanks @DrewZt — and the interface freeze is much appreciated. Either route works for me: whale-agent-lab#1 is ready as-is, and if @JustVugg prefers a focused follow-up I'll open one against dev as soon as that's the call. Next datapoint from this box will be full-model tokens/s once the checkpoint lands. |
|
DeepSeek-V4-Flash-0731 works |
|
Ok today i merge it!Works with coli chat and coli web too? |
…wrong
The site said colibri runs GLM-5.2. It has run four families since v1.3.0, and
two of the model cards contradicted the project outright:
Inkling 975B MoE - Planned -> Live (docs/inkling.md ships; runs on 25 GB)
Kimi K2 1T MoE - Planned -> Kimi K3, 2.8T MoE, Live
Telling visitors that Inkling and Kimi are on the roadmap, while the README
front page says both run today, is the kind of contradiction someone finds in
thirty seconds.
Hero rewritten rather than merely widened. The old line worked because it put
two incompatible things next to each other -- an enormous model, your machine.
Replacing that with a range ('744B to 2.8T') informs and stops landing; the
contradiction was the message. It now reads:
These models do not fit in your machine. They run in it anyway.
Same rhetorical shape as the copy further down the page ('Weights are not state
to hold. They are data to stage.'), so the page speaks with one voice. The
subtitle now also explains WHY it is possible -- a MoE token touches a small
fraction of the weights -- which was missing entirely and is what turns an
unbelievable claim into an understandable one. The numbers move there, where
they serve the reader who wants detail instead of the one who is skimming.
DeepSeek and Qwen3 deliberately stay 'Planned': JustVugg#165 and JustVugg#712 are not merged,
and the site should not promise what the code does not do.
Text only. No CSS, structure or script changes -- the sole markup edits are the
two cards' buttons becoming real links now that both models are runnable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Not directly yet. This PR currently provides its own The experimental V4 engine/session API was designed with integration in mind, but it has not been wired into I’d treat the |
Enable the DeepSeek V4 engine on aarch64 Linux + NEON rows16 kernels
Hey @DrewZt, really appreciate you sticking with this PR through the refactor, the forward-port, and all the platform testing — it's been a genuinely impressive amount of follow-through. Quick follow-up on the 'DeepSeek-V4-Flash-0731 works' update: could you share the Hugging Face URL for the exact checkpoint you tested? And if you have benchmark numbers from that run (tok/s, TTFT, etc.), would you mind posting them along with your PC specs (CPU, RAM, NVMe speed, OS)? Would help a lot in comparing against the earlier Ryzen 3900X / GB10 numbers in this thread. Thanks again for all the work here! |
the Hugging Face URL is deepseek-ai/DeepSeek-V4-Flash-0731 Using the same configuration—108 GiB RAM limit, 32 generated tokens, and two runs per model—the results were: V4-Flash-0731: 0.868 tok/s average The 0731 checkpoint was about 5.7% faster in decode. Average TTFT was effectively identical: 26.00s vs 26.12s. Average full-process wall time was 65.67s vs 68.20s, about 3.7% shorter for 0731. Both runs used 186 target cache slots and a 99.58 GiB target cache. |
|
I said earlier "today I merge it". I am walking that back, and you deserve the reasoning rather than silence, because most of it is our fault rather than yours — the tree moved underneath you while this was open. Two things I got wrong about your PR, corrected firstI had this filed in my head as "duplicates I also described it as "seven What changed underneath you, and why it matters
And here is why that is directly relevant. We measured DeepSeek-V4-Flash's actual shard headers rather than trusting
The experts are declared So most of What we would like, and it is mostly deletionThe shape we have settled on across
And please wire the front end from the startThis is the part we would ask for even if nothing else changed. Users do not run engines directly — they run # c/coli:160 model_arch()
if "deepseek" in model_type: return "deepseek" # config.json says model_type: deepseek_v4
# c/coli:176 engine_for()
name = "inkling" if arch == "inkling" else "kimi_k3" # -> add "deepseek_v4"
DSpark
What we can do to help
No deadline from us, and nothing here is a complaint about the engineering. It is a request to land the same work in the shape the tree grew into while this PR was open. If some of it does not fit the way DeepSeek V4 actually works, say so — you have run this model and we have not. |
|
if you want help i'm here too make this merge faster! |
|
Correcting myself on DSpark — I asked you to hold it back, and the reasoning I gave was worse than the counter-argument. What I said was that 4,057 lines of speculative decoding would keep a working engine from landing for another week. That is true of the review cost, and it is the wrong thing to optimise for. DSpark is DeepSeek's, not an optimisation we invented. If it is part of how the model is meant to run, shipping without it hands people a half DeepSeek and asks them to judge it — and the first thing everyone will want to try is exactly the thing that is missing. Judging a model without the decoding path its authors designed for it is not a fair test of either. So: please keep it, but as the second of two consecutive PRs rather than folded into one.
Nothing gets thrown away, you do not rewrite anything, and neither of us reviews 13,000 lines in one sitting. If the first lands and the second is a day behind it, that is fine — people can run the model while the speculation is reviewed, instead of waiting for both. One thing I would still ask of the DSpark PR, and it is the same standard Take the time you need on both. Nothing here is urgent in a way that should push you into rushing a 9,000-line engine — and I would rather wait than have you strip something the model needs because a maintainer told you to. |
|
Understood — I’ll keep the existing DSpark implementation, but split the work into two consecutive PRs as suggested. For #165, I’ll focus on the target-only DeepSeek V4 engine, migrate it to the current shared I’ll preserve the current full implementation on a separate branch, then prepare the DSpark support as an immediately stacked follow-up on top of the target-engine PR. That follow-up will retain The target engine was developed and validated independently before DSpark was added, so this split should preserve the existing work without requiring the target runtime to be redesigned. |
|
For the target-engine cleanup, the main shared-infrastructure blocker is that upstream fmt=8 does not yet support the UE8M0 block scales used by DeepSeek V4. Could you add the UE8M0 scale variant to the shared quant.h implementation? The required weight format is: raw E4M3FN weight bytes in row-major [O, I] layout; It should coexist with the existing f32-scale fmt=8 path. Once that shared support is available, I’ll validate it against the current V4 implementation and the full DeepSeek-V4-Flash-0731 checkpoint, then remove the private FP8 weight path from #165. I’ll keep the activation QDQ and the CPU routed-expert kernels V4-specific for now, since they are separate from the missing shared weight-format support. |
Summary
This PR adds a separate, model-specific DeepSeek V4 Flash + DSpark CPU engine for x86-64 Linux and Windows/MSYS2. It streams routed FP4 experts directly from the original safetensors checkpoint on NVMe and allocates available memory between resident target tensors, DSpark stages, the output head, and per-layer expert caches.
The implementation includes:
make deepseek-v4target and standard-library-onlyc/v4launcher;The DeepSeek implementation remains a separate model-specific engine and does not modify the main
c/colibri.cinference or storage paths.; the default GLM build and unsupported-platform test path remain intact.Merge hardening
This branch was reconstructed as a fresh forward port onto current upstream
dev, rather than replaying the obsolete pre-#391 commit history. and integrates V4 targets with the upstream target-triplet detection,tools/run_tests.py, andtools/clean.pyflow.The safetensors index now:
dtype width ? shape numel, preventing undersized reads and oversized writes.Malformed fixtures cover bad header lengths, wrong JSON types, invalid offsets, invalid dimensions/rank, arithmetic overflow, dtype/shape/payload-size mismatches, and repeated open/close under LSan. The same JSON-tree ownership fix was applied to V4 config parsing after sanitizer validation exposed it.
V4 config integer fields and
compress_ratiosnow require finite, integral values in the Cintrange. Floating-point fields require finite values representable asfloat.The full-model oracle launcher resolves its local binary path correctly and requires exact output length and token identity for both DSpark-on and DSpark-off runs. The resident dense cache always uses the engine-owned canonical config and no longer retains a borrowed config pointer.
Validation
make -C c check- all C tests and 71 Python tests passmake -C c deepseek-v4 ARCH=x86-64-v3make -C c deepseek-v4 ARCH=nativetest_safetensors_index,test_deepseek_v4,test_v4_ownershipMEMORY_GB=32DeepseekV4ForCausalLMmake checkpassed; portable V4 infrastructure tests ran, whilethe x86-64-only V4 engine and tiny runtime oracle were explicitly gated off
The full-model fixture uses
source=coli-self: it validates deterministic target-token reproduction and DSpark losslessness, not independent Hugging Face parity.CUDA validation is not applicable because this PR does not add or modify a CUDA backend.
Scope
This PR intentionally does not include the proposed AVX2 kernel or dual-SSD mirror work; those should be reviewed separately.
Compatibility