diff --git a/blog/2026-06-29-mxfp8-nvfp4-rl.md b/blog/2026-06-29-mxfp8-nvfp4-rl.md
new file mode 100644
index 000000000..f0ae0dc36
--- /dev/null
+++ b/blog/2026-06-29-mxfp8-nvfp4-rl.md
@@ -0,0 +1,402 @@
+---
+title: "Towards Blackwell-Native 8-bit and 4-bit RL: End-to-End MXFP8 and NVFP4 RL in Miles"
+author: "humans&, Miles Team"
+date: "June 29, 2026"
+previewImg: "/images/blog/mxfp8-nvfp4-rl/NVFP4-dq.drawio.png"
+---
+
+> TL;DR: We implemented two Blackwell-native RL recipes in Miles: end-to-end MXFP8 and per-token NVFP4 for MoE experts. Both are supported by fine-grained precision control across checkpoint conversion, Megatron training, SGLang rollout, and live weight updates. MXFP8 covers rollout, forward propagation, weight-gradient GEMMs, and data-gradient GEMMs. NVFP4 uses online per-token activation scaling for its MoE expert path, and both formats support high-precision or dequantized backward modes. In a Qwen3-30B-A3B recipe ablation on 8x B200, BF16 and all five low-precision configurations have closely overlapping raw reward curves, while MXFP8 and NVFP4 reduce rollout time.
+
+## Introduction
+
+In low-precision RL, rollout, training, checkpoint conversion, and live weight updates must agree on one precision contract, or the sampler and trainer policies will diverge. Miles and the SGLang RL ecosystem have already incorporated low-precision recipes: the LMSYS [FP8 RL post](https://www.lmsys.org/blog/2025-11-25-fp8-rl) showed that using FP8 across training and sampling reduces mismatch relative to BF16 training with FP8 rollout; the [INT4 QAT post](https://www.lmsys.org/blog/2026-01-26-int4-qat) showed that fake quantization during training and W4A16 rollout can make INT4 practical. We extend that work to Blackwell-native formats by implementing MXFP8 and NVFP4 recipes in Miles and contributing the supporting components across SGLang, TransformerEngine, FlashInfer, Megatron, and cuDNN frontend. The public roadmap is tracked in [miles#615](https://github.com/radixark/miles/issues/615).
+
+The main contributions are:
+
+1. End-to-end MXFP8 RL, where rollout, forward propagation, weight-gradient GEMMs, and data-gradient GEMMs all use MXFP8.
+2. Per-token NVFP4 RL for MoE expert weights, using online per-token activation scaling.
+3. Fine-grained precision control, so selected tensors such as final layers can remain BF16 consistently.
+4. A bit-exact quantizer contract between TransformerEngine and FlashInfer, so weight updates do not introduce avoidable train-inference mismatch.
+
+## Why Blackwell-Native Recipes?
+
+Previous low-precision approaches were not designed around MXFP8 or NVFP4. The existing Miles path follows a [DeepSeek-V3](https://arxiv.org/html/2412.19437v2)-style block-scaled FP8 recipe: weights use 128x128 block scaling, activations use 1x128 tile scaling, and scales are computed online for each tile or block. This is a strong Hopper-era recipe, but on Blackwell its FP32 scales are still applied in software around the Tensor Core path rather than through native microscaling hardware.
+
+INT4 QAT solves a different problem. Training uses fake quantization to adapt the model to INT4 weights, while rollout uses W4A16. Although memory efficient, the compute path still effectively uses BF16 activations with dequantized INT4 weights. The table below normalizes NVIDIA's [HGX platform](https://www.nvidia.com/en-us/data-center/hgx/) dense Tensor Core specs to per-GPU throughput: B200 and B300 from 8-GPU HGX systems, Rubin from the HGX Rubin NVL8 table.
+
+| GPU | BF16 dense Tensor Core | FP8 dense Tensor Core | FP4 dense Tensor Core |
+| --- | ---: | ---: | ---: |
+| B200 | 2.25 PFLOPS | 4.5 PFLOPS | 9 PFLOPS |
+| B300 | 2.25 PFLOPS | 4.5 PFLOPS | 13.5 PFLOPS |
+| Rubin GPU (NVL8) | 4 PFLOPS | 17.5 PFLOPS | 35 PFLOPS |
+
+For RL systems, the precision contract spans:
+
+- SGLang rollout.
+- Megatron and TransformerEngine training.
+- Hugging Face checkpoint conversion.
+- Megatron-to-Hugging Face live weight export.
+- Fine-grained high-precision exceptions.
+
+## Format Background
+
+### MXFP8
+
+MXFP8 is a microscaling FP8 format. TransformerEngine's [MXFP8 documentation](https://docs.nvidia.com/deeplearning/transformer-engine/user-guide/features/low_precision_training/mxfp8/mxfp8.html) describes it as a Blackwell-native blockwise scaling recipe: every 32 consecutive E4M3 values share one local E8M0 scale, and the block is one-dimensional.
+
+Because E8M0 scales represent powers of two, the decoded scale is usually rounded up so the maximum value in the block is not clipped.
+
+### NVFP4
+
+NVFP4 is Blackwell's native FP4 format. As described in NVIDIA's [NVFP4 introduction](https://developer.nvidia.com/blog/introducing-nvfp4-for-efficient-and-accurate-low-precision-inference/), it stores FP4 E2M1 values with one FP8 E4M3 scale per 16-value block. Because E4M3 has finer resolution than UE8M0, its scale is typically rounded to the nearest representable value. A standard NVFP4 recipe also adds one FP32 scale for the larger tensor scope, creating a two-level hierarchy:
+
+- A coarse FP32 scale that maps the tensor or token into the NVFP4 representable range.
+- A fine E4M3 scale that adapts each 1x16 block.
+
+
+
+
+
+The FP32 scale can be chosen over different tensor scopes. That choice is a recipe decision rather than a property of the format itself, and it becomes especially important for RL.
+
+## Recipe 1: End-to-End MXFP8 RL
+
+The MXFP8 recipe is the most direct Blackwell-native extension of the earlier end-to-end FP8 work. Rollout, forward propagation, weight-gradient GEMMs, and data-gradient GEMMs all use MXFP8, while selected tensors remain BF16 through the precision-control rules described below.
+
+
+
+
+
+### Training
+
+TransformerEngine and Megatron implement MXFP8 as a performance-optimized, first-class Blackwell training path, including the GB200 DeepSeek-V3 optimizations described in [deepseek-v3-gb200-optimization.md](https://github.com/NVIDIA/Megatron-LM/blob/eb0783b6d35607ef1953eaca60b37b886b1a25d0/docs/discussions/deepseek-v3-gb200-optimization/deepseek-v3-gb200-optimization.md). In our Miles integration, we use this path as the training-side foundation for end-to-end MXFP8 RL.
+
+One difference from the [DeepSeek-V3 FP8 recipe](https://arxiv.org/html/2412.19437v2) is how backward activations are represented. DeepSeek-V3 stores forward activations in 1x128 FP8 tiles and converts them to the backward orientation before the backward GEMM. That approach stores less FP8 data, but it introduces dequantization plus requantization before the backward GEMM. TransformerEngine's MXFP8 docs note that rowwise 1x32 blocks and columnwise 32x1 blocks are numerically different and must be quantized independently from full-precision data. TransformerEngine therefore materializes both row-wise and column-wise quantized copies during quantization. This uses more memory, but it avoids an extra requantization step and reduces additional quantization error in the backward path.
+
+This is a typical systems trade-off for RL. We use the TransformerEngine path to preserve one end-to-end MXFP8 contract without adding another source of mismatch.
+
+### Rollout
+
+On the rollout side, SGLang uses Blackwell MXFP8 kernels from FlashInfer and Triton. We implemented and upstreamed the rollout path across FlashInfer and SGLang ([flashinfer#2581](https://github.com/flashinfer-ai/flashinfer/pull/2581), [sglang#17449](https://github.com/sgl-project/sglang/pull/17449), [sglang#19537](https://github.com/sgl-project/sglang/pull/19537), [sglang#21576](https://github.com/sgl-project/sglang/pull/21576), and [sglang#28459](https://github.com/sgl-project/sglang/pull/28459)).
+
+Almost all major GEMMs can be quantized to MXFP8, including attention projections and MoE experts. The main exceptions are explicitly controlled high-precision layers, such as the BF16 MLA projections described below.
+
+## Recipe 2: Per-Token NVFP4 RL
+
+NVFP4 is more aggressive than MXFP8, so we apply it selectively. We quantize MoE experts because they dominate model size and rollout memory traffic, while the rest of the model remains BF16 unless explicitly configured otherwise.
+
+For example, [DeepSeek-V3](https://arxiv.org/html/2412.19437v2) has about 671B total parameters. Its MoE experts account for:
+
+```text
+(61 - 3) * (256 + 1) * 3 * 7168 * 2048 / 1e9 = 656.5B parameters
+```
+
+That is about 97.8% of the model. Targeting MoE experts therefore captures most of the memory benefit without forcing every layer into the most aggressive precision format.
+
+### Why not directly use the NVFP4 pretraining recipe?
+
+The original [NVFP4 pretraining recipe](https://arxiv.org/html/2509.25149v2) is designed for large-scale pretraining, where the goal is preserving a coarse optimization direction over many tokens while still using FP4 GEMMs. It combines FP4 linear-layer GEMMs with several stabilizers: selected layers remain in higher precision, weight scaling is consistent across forward and backward, and the training path uses stochastic rounding (SR) and Random Hadamard Transforms (RHT). In the paper, SR is applied to gradients to reduce quantization bias and produce unbiased quantized gradients, while RHT disperses large-magnitude block-level outliers, especially for weight-gradient GEMM inputs.
+
+
+
+
+
+That is a good starting point, but RL has a different failure surface:
+
+| Setting | Numerical situation | Bottom line |
+| --- | --- | --- |
+| Pre-training | Gradient signals are stable, weight updates are substantial, model weights are adaptive, and activations and gradients are precision-sensitive with high dynamic range. | Preserve the coarse optimization direction and convergence. |
+| RL | Gradients are noisy, rewards are high-variance, and useful updates are small and delicate. | Keep quantization noise below the true update signal; otherwise it can overwrite fragile capabilities and lead to performance collapse. |
+
+The NVFP4 RL recipe does not incorporate every part of the pretraining recipe. We target MoE expert weight quantization, per-token activation scaling, consistent precision control, and BF16 backward GEMMs with selectable original or dequantized operands.
+
+### Per-token activation scaling
+
+The two-level NVFP4 hierarchy is powerful, but the scope of the FP32 activation scale must be chosen carefully. As discussed in the [Cursor Composer 2 technical report](https://arxiv.org/html/2603.24477v2), per-tensor NVFP4 scaling can make training batch-variant, and inter-token scale sharing can leak future-token information into past-token representations. If a token shares its scale with other tokens, its quantized representation depends on the batch composition. This is especially problematic for RL, where rollout scheduling and sequence lengths vary.
+
+Our recipe therefore computes one FP32 activation scale per token online. This localizes activation outliers to one token, removes the static activation calibration artifact, and lets SGLang rollout and Megatron training use the same activation-scale scope.
+
+On the rollout side, the per-token FP32 scale computation is fused into FlashInfer's activation quantization kernel path: the same call that emits packed FP4 activations and E4M3 block scales also returns the per-token FP32 scales. As a result, per-token activation scaling does not require a separate calibration-scale pass.
+
+Train-inference consistency also requires matching parallelism. If the FP32 scale is computed per token within an expert-tensor-parallel partition, SGLang and Megatron should use the same ETP size. Otherwise, each side may see a different partition of the tensor and compute a different scale.
+
+SwiGLU MoE layers add another key contract. SGLang and Megatron commonly fuse the gate and up projections into one GEMM, so both tensors must share the same FP32 scale during conversion and live weight update even when the Hugging Face checkpoint stores them separately. Miles enforces this by quantizing gate/up pairs together in the NVFP4 export path.
+
+We implemented and upstreamed the per-token NVFP4 recipe across the entire stack:
+
+- TransformerEngine training recipe: [TransformerEngine#2931](https://github.com/NVIDIA/TransformerEngine/pull/2931)
+- cuDNN frontend training kernels: [cudnn-frontend#251](https://github.com/NVIDIA/cudnn-frontend/pull/251)
+- FlashInfer rollout kernels: [flashinfer#3027](https://github.com/flashinfer-ai/flashinfer/pull/3027)
+- SGLang integrations and weight-update fixes: [sglang#22918](https://github.com/sgl-project/sglang/pull/22918), [sglang#22204](https://github.com/sgl-project/sglang/pull/22204)
+
+### High-precision and dequantized backward
+
+In the high-precision-backward NVFP4 variant, the forward pass and rollout use NVFP4 for MoE experts, while the backward GEMMs use the original BF16 operands.
+
+
+
+
+
+Dequantized backward is a second selectable mode. The backward GEMMs still run in BF16, but consume BF16 dequantizations of the exact low-precision operands produced in forward instead of the original BF16 values.
+
+
+
+
+
+Both modes avoid low-precision backward GEMMs, so these configurations do not use RHT or stochastic rounding from the original NVFP4 pretraining recipe. They trade backward throughput for higher-precision computation, but RL is often rollout-bound, and long-context attention and communication further reduce the end-to-end impact.
+
+The same backward-mode selection also applies to MXFP8:
+
+
+
+
+
+
+
+
+
+We implemented and upstreamed `NVTE_BACKWARD_OVERRIDE` as a reusable TransformerEngine interface for selecting high-precision or dequantized backward operands ([TransformerEngine#2644](https://github.com/NVIDIA/TransformerEngine/pull/2644)), then exposed both modes through the Miles recipe configuration. The companion [humans&](https://humansand.ai/blog/nvfp4-rl) post covers the algorithmic motivation and additional backward-mode ablations.
+
+#### Backward cost and memory
+
+Dequantized backward adds a training-side dequantization step. We worked with NVIDIA to reduce its overhead in [TransformerEngine#2865](https://github.com/NVIDIA/TransformerEngine/pull/2865).
+
+High-precision and dequantized backward can also reduce peak memory relative to TransformerEngine's default low-precision backward paths. Neither mode needs to generate and retain the second column-wise quantized copy used by the low-precision backward GEMMs described in the MXFP8 training section above.
+
+We measured the memory data below while validating our TransformerEngine backward-mode implementation in [TransformerEngine#2644](https://github.com/NVIDIA/TransformerEngine/pull/2644#issuecomment-4026583299). The `alloc` columns report allocated memory, the `resrv` columns report reserved memory, and all values are in MB.
+
+MXFP8 linear memory, `dtype=torch.bfloat16`, `input_shape=(2048, 2048)`, `out_features=8192`:
+
+| mode | fwd_alloc | bwd_alloc | e2e_alloc | fwd_resrv | bwd_resrv | e2e_resrv | delta_fwd | delta_bwd | delta_e2e |
+| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
+| default | 73.75 | 73.02 | 94.14 | 474.00 | 474.00 | 474.00 | +0.00 (+0.00%) | +0.00 (+0.00%) | +0.00 (+0.00%) |
+| high precision | 53.12 | 40.02 | 53.12 | 474.00 | 474.00 | 474.00 | -20.62 (-27.97%) | -33.00 (-45.20%) | -41.02 (-43.57%) |
+| dequantized | 53.25 | 80.02 | 84.64 | 474.00 | 474.00 | 474.00 | -20.50 (-27.80%) | +7.00 (+9.59%) | -9.50 (-10.09%) |
+
+NVFP4 linear memory, `dtype=torch.bfloat16`, `input_shape=(2048, 2048)`, `out_features=8192`:
+
+| mode | fwd_alloc | bwd_alloc | e2e_alloc | fwd_resrv | bwd_resrv | e2e_resrv | delta_fwd | delta_bwd | delta_e2e |
+| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
+| default | 55.75 | 146.02 | 150.27 | 478.00 | 478.00 | 478.00 | +0.00 (+0.00%) | +0.00 (+0.00%) | +0.00 (+0.00%) |
+| high precision | 44.50 | 40.02 | 44.50 | 478.00 | 478.00 | 478.00 | -11.25 (-20.18%) | -106.00 (-72.60%) | -105.77 (-70.39%) |
+| dequantized | 44.50 | 80.02 | 75.27 | 478.00 | 478.00 | 478.00 | -11.25 (-20.18%) | -66.00 (-45.20%) | -75.00 (-49.91%) |
+
+## Bit-Exact Quantizer Contract
+
+In RL, quantization mismatch can accumulate across weight updates. If the training and rollout sides quantize a tensor differently, the policies used for sampling and learning are no longer the same low-precision model. We therefore need an explicit contract between both sides of the RL stack.
+
+We align the FlashInfer and TransformerEngine quantizers to the same MXFP8 and NVFP4 bit-level contract. Our FlashInfer unit tests check exact byte-level agreement against a TransformerEngine-style reference across random data, quantization-boundary data, all-zero tensors, and maximum-value tensors, corresponding to `init_data = ["random", "boundary", "zeros", "maxes"]`. We implemented and upstreamed this quantizer alignment in [flashinfer#3387](https://github.com/flashinfer-ai/flashinfer/pull/3387).
+
+There is one practical distinction between serving and RL. For serving-only workloads, FlashInfer may use fast math in parts of the FP4 quantization path for performance. This is a reasonable serving default, but RL weight updates benefit from exact agreement with the training-side quantizer. For this recipe, we set:
+
+```bash
+FLASHINFER_DISABLE_FP4_QUANT_FAST_MATH=1
+```
+
+Every backend that touches rollout weights should either implement this quantization contract exactly or make approximate behavior opt-in.
+
+## Fine-Grained Precision Control
+
+In practice, a single global precision switch is insufficient for low-precision RL. Some tensors should remain in BF16, but selecting them is only part of the problem: the same decision must be enforced across Hugging Face checkpoint conversion, Megatron training, SGLang rollout, and live weight export.
+
+We implemented this tensor-level precision control in Miles through count-based and name-based BF16 exceptions across checkpoint conversion, training, rollout, and live export ([miles#614](https://github.com/radixark/miles/pull/614), [miles#1054](https://github.com/radixark/miles/pull/1054), and [miles#1261](https://github.com/radixark/miles/pull/1261)). We also implemented SGLang support for the resulting mixed-precision checkpoints ([sglang#18742](https://github.com/sgl-project/sglang/pull/18742) and [sglang#20214](https://github.com/sgl-project/sglang/pull/20214)). Concretely, conversion uses `--num-layers-at-start-in-bf16` and `--num-layers-at-end-in-bf16`; Megatron training combines those counts with `--first-last-layers-bf16`; and SGLang serves the resulting mixed-precision checkpoints.
+
+### Layer Precision Choices
+
+As recommended in the [NVIDIA NVFP4 pretraining paper](https://arxiv.org/html/2509.25149v2), we keep a small fraction of final layers in higher precision. In our experiments, keeping the last 15% of layers in BF16 meaningfully reduces train-inference mismatch and stabilizes gradients.
+
+
+
+
+
+Turning on BF16 for early layers does not lead to meaningful train-inference mismatch reduction in our experiments:
+
+
+
+
+
+Keeping shared experts in high precision also reduces train-inference mismatch with little performance or memory overhead. Routed experts are selected sparsely, and their outputs pass through a high-precision weighted reduction. Shared experts are always active, so their precision errors affect every token passing through the block.
+
+
+
+
+
+#### Case Study: MXFP8 MLA
+
+For MLA models, `kv_b_proj` is an important MXFP8 case. Absorbed and non-absorbed MLA modes can use different contraction axes, while MXFP8 uses one-dimensional microscaling blocks. Changing the contraction axis can therefore change which elements share a scale. The same concern applies to other one-dimensional formats, including NVFP4. The original [DeepSeek-V3](https://arxiv.org/html/2412.19437v2) FP8 recipe does not have this exact weight-side issue because it uses 128x128 weight-scale blocks rather than one-dimensional blocks. We keep these projection tensors in BF16 to avoid hidden requantization and preserve train-inference consistency.
+
+```yaml
+configs:
+ bf16:
+ transformer_engine_config_type: "TEQuantizationParams"
+ training_recipe: {}
+matchers:
+ mla_kv_up_proj_bf16:
+ type: "glob"
+ enabled: true
+ pattern: "*.self_attention.linear_kv_up_proj"
+ config: "bf16"
+ absorbed_k_up_proj_bf16:
+ type: "glob"
+ enabled: true
+ pattern: "*.self_attention.linear_k_up_proj"
+ config: "bf16"
+ absorbed_v_up_proj_bf16:
+ type: "glob"
+ enabled: true
+ pattern: "*.self_attention.linear_v_up_proj"
+ config: "bf16"
+```
+
+The matching name-based conversion-time and rollout-time arguments are:
+
+```bash
+--extra-high-precision-layers-hf .kv_b_proj.
+--extra-high-precision-layers-megatron .linear_kv_up_proj .linear_k_up_proj .linear_v_up_proj
+```
+
+For [DeepSeek-V3](https://arxiv.org/html/2412.19437v2)-style MLA, this BF16 exception is small. A `kv_b_proj` tensor of shape `32768 x 512`, stored in BF16 across 61 layers, occupies about 1.90625 GB.
+
+## Results: Qwen3-30B-A3B Recipe Ablation on 8x B200
+
+For consistent comparison, all experiments use synchronous Qwen3-30B-A3B RL with the default Miles setup on 8x B200. The fixed workload uses GRPO-style training on `dapo-math-17k`, with 8 rollout samples per prompt and a maximum response length of 8192 tokens. This is only a recipe ablation setup, not a fully tuned training or serving benchmark. The KL path is enabled for diagnostics, but its coefficient is 0.0, so KL is not an optimization penalty in this ablation.
+
+The hardware split is 4 GPUs for rollout and 4 GPUs for training.
+
+For all low-precision recipes:
+
+- MoE rollout-routing replay is enabled.
+- The last 15% of layers are kept in BF16.
+- Low-precision weights use 0 weight decay for stability.
+- SGLang rollout uses BF16 KV cache and the FlashInfer TRTLLM routed MoE backend for the low-precision MoE path.
+
+We compare six configurations:
+
+1. BF16 training + BF16 rollout.
+2. End-to-end MXFP8 training + MXFP8 rollout.
+3. MXFP8 rollout and forward with high-precision backward.
+4. MXFP8 rollout and forward with dequantized backward.
+5. Per-token NVFP4 MoE rollout and forward with high-precision backward.
+6. Per-token NVFP4 MoE rollout and forward with dequantized backward.
+
+### Train-inference mismatch
+
+As expected, both low-precision formats show higher train-inference mismatch than BF16, while the two backward choices behave similarly within each format. The values remain in a reasonable range for this ablation.
+
+
+
+
+
+
+NVFP4 begins with a higher reference KL than BF16 or MXFP8. Miles computes this diagnostic against a Megatron BF16 reference model, so the metric includes the difference between each low-precision policy and the BF16 reference in addition to policy evolution during RL. It should not be read as a standalone optimization penalty.
+
+### Reward
+
+Despite the higher diagnostic mismatch, all five low-precision reward curves closely track the BF16 reward curve.
+
+
+
+
+
+This is the key result of the recipe ablation: in this Qwen3-30B-A3B B200 setup, Blackwell-native low precision preserves the observed learning curve while improving rollout efficiency.
+
+### Performance
+
+MXFP8 and NVFP4 both reduce rollout time compared with BF16:
+
+
+
+
+
+For NVFP4 rollout, FlashInfer computes the online per-token FP32 scale directly inside the activation quantization kernel path rather than as a separate preprocessing step. The reported rollout performance therefore includes the cost of online scale computation.
+
+On the training side, the MXFP8 variants are faster than BF16, while the NVFP4 backward-override variants are slower in the implementation measured here:
+
+
+
+
+
+The training-side gap comes from the implementation used in this ablation, not an inherent FP4 Tensor Core limit. Our TransformerEngine path applies per-token FP32 scaling as a separate PyTorch operation ([TransformerEngine#2931](https://github.com/NVIDIA/TransformerEngine/pull/2931)) instead of a native per-token NVFP4 GEMM path with scaling fused into the kernel epilogue. We have implemented and upstreamed the fused cuDNN frontend kernels ([cudnn-frontend#251](https://github.com/NVIDIA/cudnn-frontend/pull/251)); TransformerEngine integration remains pending. Dequantized backward adds the dequantization step described above. Because this RL workload is rollout-heavy, the rollout speedup remains meaningful even before the training path is fully accelerated.
+
+Beyond this ablation, [humans&](https://humansand.ai/) uses the same recipe family and components in production for large-scale, long-context, multi-agent asynchronous RL research.
+
+## Future Work
+
+### Dropping the extra BF16 weight copy
+
+Although rollout and training execute the same low-precision recipe, Megatron still saves an additional BF16 weight copy. This increases memory consumption and limits the practical memory benefit of the low-precision path.
+
+Megatron has `--fp8-param-gather` and `--fp4-param-gather`, but the Blackwell-native path is still maturing. The Megatron-Bridge tracking issue [Megatron-Bridge#3801](https://github.com/NVIDIA-NeMo/Megatron-Bridge/issues/3801) reflects ongoing work needed for robust low-precision parameter gather. NVFP4 `--fp4-param-gather` does not yet support the 1D 1x16 weight layout used by this recipe.
+
+### Occasional gradient spikes
+
+The high-precision-backward NVFP4 variant can still show occasional gradient spikes:
+
+
+
+
+
+Dequantized backward reduces the largest spikes in this ablation but does not eliminate them. More advanced techniques, including 4/6 and chain-rule-consistent backward choices, are discussed in the companion [humans&](https://humansand.ai/blog/nvfp4-rl) post.
+
+### Refactoring the weight-update interface
+
+Low-latency FlashInfer backends often require padding, swizzling, shuffling, and backend-specific weight layouts. Those transformations are natural for serving, but they complicate live RL weight update and RDMA because the training side usually owns a different canonical tensor layout.
+
+Work in Miles and SGLang aims to preserve high-performance serving layouts while making each weight transformation explicit, verifiable, and less dependent on backend-private details.
+
+## Try the NVFP4 Recipe in Miles
+
+The following environment settings reproduce the per-token NVFP4 high-precision-backward setup:
+
+```bash
+NVTE_NVFP4_ROW_SCALED_ACTIVATION=1
+NVTE_BACKWARD_OVERRIDE=high_precision
+NVTE_NVFP4_DISABLE_2D_QUANTIZATION=1
+NVTE_NVFP4_DISABLE_RHT=1
+NVTE_NVFP4_DISABLE_STOCHASTIC_ROUNDING=1
+TRTLLM_DISABLE_FP4_QUANT_FAST_MATH=1
+FLASHINFER_DISABLE_FP4_QUANT_FAST_MATH=1
+SGLANG_FLASHINFER_NVFP4_PER_TOKEN_ACTIVATION=1
+```
+
+Set `NVTE_BACKWARD_OVERRIDE=dequantized` to select the dequantized-backward variant without changing the rest of the recipe.
+
+For Miles launch scripts, the recipe pairs these environment variables with `--fp4-format e2m1`, `--fp4-recipe nvfp4`, the same BF16 first/last-layer controls used during checkpoint conversion, and the following TransformerEngine precision config:
+
+```yaml
+configs:
+ nvfp4:
+ transformer_engine_config_type: "TEQuantizationParams"
+ training_recipe:
+ fp4_quantization_recipe: "nvfp4"
+ bf16:
+ transformer_engine_config_type: "TEQuantizationParams"
+ training_recipe: {}
+matchers:
+ routed_experts_fc1_nvfp4:
+ type: "glob"
+ enabled: true
+ pattern: "*.mlp.experts.linear_fc1"
+ config: "nvfp4"
+ routed_experts_fc2_nvfp4:
+ type: "glob"
+ enabled: true
+ pattern: "*.mlp.experts.linear_fc2"
+ config: "nvfp4"
+ default_bf16:
+ type: "glob"
+ enabled: true
+ pattern: "*"
+ config: "bf16"
+```
+
+## Acknowledgements
+
+The recipe design and the majority of the implementation described in this post were done by Ziang Li at [humans&](https://humansand.ai/).
+
+We thank the following collaborators for engineering support, integration help, and review:
+
+- RadixArk and the Miles Team (Yueming Yuan, Baizhou Zhang).
+- NVIDIA DevTech Compute Team (Siyuan Fu, Yigong Qin, Zhongbo Zhu), NVIDIA TransformerEngine Team, and FlashInfer Team.
+
+We also thank the Cursor team for the per-token NVFP4 activation-scaling idea.
diff --git a/public/images/blog/mxfp8-nvfp4-rl/MXFP8-E2E.drawio.png b/public/images/blog/mxfp8-nvfp4-rl/MXFP8-E2E.drawio.png
new file mode 100644
index 000000000..5eabcc86a
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/MXFP8-E2E.drawio.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/MXFP8-dq.drawio.png b/public/images/blog/mxfp8-nvfp4-rl/MXFP8-dq.drawio.png
new file mode 100644
index 000000000..90697c9f0
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/MXFP8-dq.drawio.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/MXFP8-hp.drawio.png b/public/images/blog/mxfp8-nvfp4-rl/MXFP8-hp.drawio.png
new file mode 100644
index 000000000..ee1cbab41
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/MXFP8-hp.drawio.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/NVFP4-dq.drawio.png b/public/images/blog/mxfp8-nvfp4-rl/NVFP4-dq.drawio.png
new file mode 100644
index 000000000..dc2257a9d
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/NVFP4-dq.drawio.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/NVFP4-hp.drawio.png b/public/images/blog/mxfp8-nvfp4-rl/NVFP4-hp.drawio.png
new file mode 100644
index 000000000..b84514902
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/NVFP4-hp.drawio.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/NVFP4-pretrain.png b/public/images/blog/mxfp8-nvfp4-rl/NVFP4-pretrain.png
new file mode 100644
index 000000000..16b22769b
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/NVFP4-pretrain.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/hp-kl.png b/public/images/blog/mxfp8-nvfp4-rl/hp-kl.png
new file mode 100644
index 000000000..b5d0afd09
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/hp-kl.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/hp-logprob.png b/public/images/blog/mxfp8-nvfp4-rl/hp-logprob.png
new file mode 100644
index 000000000..963ce7b81
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/hp-logprob.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/hp-raw-reward.png b/public/images/blog/mxfp8-nvfp4-rl/hp-raw-reward.png
new file mode 100644
index 000000000..fd2bebd4d
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/hp-raw-reward.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/hp-rollout-time.png b/public/images/blog/mxfp8-nvfp4-rl/hp-rollout-time.png
new file mode 100644
index 000000000..cc1618c81
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/hp-rollout-time.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/hp-train-time.png b/public/images/blog/mxfp8-nvfp4-rl/hp-train-time.png
new file mode 100644
index 000000000..a6d94fdaa
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/hp-train-time.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/mxfp8-f1l6-vs-l6.png b/public/images/blog/mxfp8-nvfp4-rl/mxfp8-f1l6-vs-l6.png
new file mode 100644
index 000000000..e361c7748
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/mxfp8-f1l6-vs-l6.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/mxfp8-last-2-4-8.png b/public/images/blog/mxfp8-nvfp4-rl/mxfp8-last-2-4-8.png
new file mode 100644
index 000000000..a3e144c1f
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/mxfp8-last-2-4-8.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/mxfp8-se.png b/public/images/blog/mxfp8-nvfp4-rl/mxfp8-se.png
new file mode 100644
index 000000000..606458f66
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/mxfp8-se.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/nvfp4-hp-spike.png b/public/images/blog/mxfp8-nvfp4-rl/nvfp4-hp-spike.png
new file mode 100644
index 000000000..6278f957e
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/nvfp4-hp-spike.png differ
diff --git a/public/images/blog/mxfp8-nvfp4-rl/nvfp4-two-level-scaling.png b/public/images/blog/mxfp8-nvfp4-rl/nvfp4-two-level-scaling.png
new file mode 100644
index 000000000..b7d330a42
Binary files /dev/null and b/public/images/blog/mxfp8-nvfp4-rl/nvfp4-two-level-scaling.png differ