diff --git a/data/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix-20260620tp2piecewisefulllayerlettraceoffset1.log b/data/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix-20260620tp2piecewisefulllayerlettraceoffset1.log
index 9ad6aba..e31fdbe 100644
--- a/data/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix-20260620tp2piecewisefulllayerlettraceoffset1.log
+++ b/data/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix-20260620tp2piecewisefulllayerlettraceoffset1.log
@@ -43,3 +43,128 @@ WARNING 06-19 21:46:15 [nixl_utils.py:44] NIXL agent config is not available
 (EngineCore pid=4108030) INFO 06-19 21:46:15 [core.py:246] Initializing a V1 LLM engine (v0.20.2rc1.dev2+gc51df4300.d20260523) with config: model='/mnt/fast-ai/llm-cache/hf/models--nameistoken--Qwen3.6-35B-A3B-Quark-W8A8-INT8/snapshots/cced56592e8c8935f8220836b4baa04dfd389118', speculative_config=None, tokenizer='/mnt/fast-ai/llm-cache/hf/models--nameistoken--Qwen3.6-35B-A3B-Quark-W8A8-INT8/snapshots/cced56592e8c8935f8220836b4baa04dfd389118', skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, tokenizer_revision=None, trust_remote_code=True, dtype=torch.bfloat16, max_seq_len=32768, download_dir=None, load_format=auto, tensor_parallel_size=2, pipeline_parallel_size=1, data_parallel_size=1, decode_context_parallel_size=1, dcp_comm_backend=ag_rs, disable_custom_all_reduce=True, quantization=quark, quantization_config=None, enforce_eager=False, enable_return_routed_experts=False, kv_cache_dtype=auto, device_config=xpu, structured_outputs_config=StructuredOutputsConfig(backend='auto', disable_any_whitespace=False, disable_additional_properties=False, reasoning_parser='', reasoning_parser_plugin='', enable_in_reasoning=False), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None, kv_cache_metrics=False, kv_cache_metrics_sample=0.01, cudagraph_metrics=False, enable_layerwise_nvtx_tracing=False, enable_mfu_metrics=False, enable_mm_processor_stats=False, enable_logging_iteration_details=False), seed=0, served_model_name=qwen36-35b-a3b-fp8, enable_prefix_caching=False, enable_chunked_prefill=True, pooler_config=None, compilation_config={'mode': <CompilationMode.VLLM_COMPILE: 3>, 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['none'], 'ir_enable_torch_wrap': True, 'splitting_ops': ['vllm::unified_attention_with_output', 'vllm::unified_mla_attention_with_output', 'vllm::mamba_mixer2', 'vllm::mamba_mixer', 'vllm::short_conv', 'vllm::linear_attention', 'vllm::plamo2_mamba_mixer', 'vllm::gdn_attention_core', 'vllm::gdn_attention_core_xpu', 'vllm::olmo_hybrid_gdn_full_forward', 'vllm::kda_attention', 'vllm::sparse_attn_indexer', 'vllm::rocm_aiter_sparse_attn_indexer', 'vllm::deepseek_v4_attention', 'vllm::unified_kv_cache_update', 'vllm::unified_mla_kv_cache_update'], 'compile_mm_encoder': False, 'cudagraph_mm_encoder': False, 'encoder_cudagraph_token_budgets': [], 'encoder_cudagraph_max_vision_items_per_batch': 0, 'encoder_cudagraph_max_frames_per_batch': None, 'compile_sizes': [], 'compile_ranges_endpoints': [8192], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'size_asserts': False, 'alignment_asserts': False, 'scalar_asserts': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': <CUDAGraphMode.PIECEWISE: 1>, 'cudagraph_num_of_warmups': 1, 'cudagraph_capture_sizes': [1, 2, 4, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': False, 'fuse_act_quant': False, 'fuse_attn_quant': False, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False, 'fuse_act_padding': False}, 'max_cudagraph_capture_size': 96, 'dynamic_shapes_config': {'type': <DynamicShapesType.BACKED: 'backed'>, 'evaluate_guards': False, 'assume_32_bit_indexing': False}, 'local_cache_dir': None, 'fast_moe_cold_start': False, 'static_all_moe_layers': []}, kernel_config=KernelConfig(ir_op_priority=IrOpPriorityConfig(rms_norm=['native'], fused_add_rms_norm=['native']), enable_flashinfer_autotune=False, moe_backend='auto')
 (EngineCore pid=4108030) WARNING 06-19 21:46:15 [multiproc_executor.py:1367] Reducing Torch parallelism from 16 threads to 1 to avoid unnecessary CPU contention. Set OMP_NUM_THREADS in the external environment to tune this value as needed.
 (EngineCore pid=4108030) INFO 06-19 21:46:15 [multiproc_executor.py:243] DP group leader: node_rank=0, node_rank_within_dp=0, master_addr=127.0.0.1, mq_connect_ip=10.0.0.65 (local), world_size=2, local_world_size=2
+WARNING 06-19 21:46:21 [nixl_utils.py:34] NIXL is not available
+WARNING 06-19 21:46:21 [nixl_utils.py:44] NIXL agent config is not available
+WARNING 06-19 21:46:21 [nixl_utils.py:34] NIXL is not available
+WARNING 06-19 21:46:21 [nixl_utils.py:44] NIXL agent config is not available
+[transformers] `Qwen2VLImageProcessorFast` is deprecated. The `Fast` suffix for image processors has been removed; use `Qwen2VLImageProcessor` instead.
+[transformers] `Qwen2VLImageProcessorFast` is deprecated. The `Fast` suffix for image processors has been removed; use `Qwen2VLImageProcessor` instead.
+INFO 06-19 21:46:23 [registry.py:126] All limits of multimodal modalities supported by the model are set to 0, running in text-only mode.
+INFO 06-19 21:46:23 [registry.py:126] All limits of multimodal modalities supported by the model are set to 0, running in text-only mode.
+(Worker pid=4108136) INFO 06-19 21:46:23 [parallel_state.py:1542] world_size=2 rank=1 local_rank=1 distributed_init_method=tcp://127.0.0.1:44973 backend=xccl
+(Worker pid=4108135) INFO 06-19 21:46:23 [parallel_state.py:1542] world_size=2 rank=0 local_rank=0 distributed_init_method=tcp://127.0.0.1:44973 backend=xccl
+(Worker pid=4108135) INFO 06-19 21:46:24 [parallel_state.py:1855] rank 0 in world size 2 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank 0, EPLB rank N/A
+2026:06:19-21:46:24:4108136 |CCL_WARN| value of CCL_ATL_TRANSPORT changed to be ofi (default:mpi)
+2026:06:19-21:46:24:4108136 |CCL_WARN| value of CCL_TOPO_P2P_ACCESS changed to be 1 (default:-1)
+2026:06:19-21:46:24:4108136 |CCL_WARN| could not get local_idx/count from environment variables, trying to get them from ATL
+2026:06:19-21:46:24:4108135 |CCL_WARN| value of CCL_ATL_TRANSPORT changed to be ofi (default:mpi)
+2026:06:19-21:46:24:4108135 |CCL_WARN| value of CCL_TOPO_P2P_ACCESS changed to be 1 (default:-1)
+2026:06:19-21:46:24:4108135 |CCL_WARN| could not get local_idx/count from environment variables, trying to get them from ATL
+2026:06:19-21:46:24:4108135:[0] |CCL_WARN| topology recognition shows PCIe connection between devices. If this is not correct, you can disable topology recognition, with CCL_TOPO_FABRIC_VERTEX_CONNECTION_CHECK=0. This will assume XeLinks across devices
+2026:06:19-21:46:24:4108136:[1] |CCL_WARN| topology recognition shows PCIe connection between devices. If this is not correct, you can disable topology recognition, with CCL_TOPO_FABRIC_VERTEX_CONNECTION_CHECK=0. This will assume XeLinks across devices
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [gpu_model_runner.py:10489] Starting to load model /mnt/fast-ai/llm-cache/hf/models--nameistoken--Qwen3.6-35B-A3B-Quark-W8A8-INT8/snapshots/cced56592e8c8935f8220836b4baa04dfd389118...
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [xpu.py:122] Using backend AttentionBackendEnum.FLASH_ATTN for vit attention
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [mm_encoder_attention.py:372] Using AttentionBackendEnum.FLASH_ATTN for MMEncoderAttention.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [__init__.py:463] Selected XPUInt8ScaledMMLinearKernel for QuarkW8A8Int8
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [gdn_linear_attn.py:806] Using Triton/FLA GDN prefill kernel
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [int8.py:152] Using XPU Int8 MoE backend out of potential backends: ['XPU', 'TRITON'].
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [xpu.py:59] Setting VLLM_KV_CACHE_LAYOUT to 'NHD' for XPU; only NHD layout is supported by XPU attention kernels.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [xpu.py:87] Using Flash Attention backend.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:25 [flash_attn.py:649] Using FlashAttention version 2
+(Worker_TP1 pid=4108136) INFO 06-19 21:46:25 [xpu.py:59] Setting VLLM_KV_CACHE_LAYOUT to 'NHD' for XPU; only NHD layout is supported by XPU attention kernels.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:26 [weight_utils.py:904] Filesystem type for checkpoints: EXT4. Checkpoint size: 34.15 GiB. Available RAM: 113.19 GiB.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:26 [weight_utils.py:927] Auto-prefetch is disabled because the filesystem (EXT4) is not a recognized network FS (NFS/Lustre). If you want to force prefetching, start vLLM with --safetensors-load-strategy=prefetch.
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:   0% Completed | 0/7 [00:00<?, ?it/s]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:  14% Completed | 1/7 [00:01<00:08,  1.35s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:  29% Completed | 2/7 [00:03<00:08,  1.75s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:  43% Completed | 3/7 [00:05<00:07,  1.94s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:  57% Completed | 4/7 [00:07<00:06,  2.03s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:  71% Completed | 5/7 [00:09<00:04,  2.05s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards:  86% Completed | 6/7 [00:11<00:02,  2.06s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards: 100% Completed | 7/7 [00:13<00:00,  1.85s/it]
+(Worker_TP0 pid=4108135) 
Loading safetensors checkpoint shards: 100% Completed | 7/7 [00:13<00:00,  1.90s/it]
+(Worker_TP0 pid=4108135) 
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:39 [default_loader.py:391] Loading weights took 13.38 seconds
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:39 [int8.py:216] Using MoEPrepareAndFinalizeNoDPEPModular
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:40 [gpu_model_runner.py:10591] Model loading took 16.88 GiB memory and 14.548833 seconds
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:40 [interface.py:492] Setting kv cache block size to 64 for FLASH_ATTN backend.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:40 [interface.py:609] Setting attention block size to 1088 tokens to ensure that attention page size is >= mamba page size.
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:40 [interface.py:633] Padding mamba page size by 3.82% to ensure that mamba page size and attention page size are exactly equal.
+(Worker_TP1 pid=4108136) INFO 06-19 21:46:44 [interface.py:492] Setting kv cache block size to 64 for FLASH_ATTN backend.
+(Worker_TP1 pid=4108136) INFO 06-19 21:46:44 [interface.py:609] Setting attention block size to 1088 tokens to ensure that attention page size is >= mamba page size.
+(Worker_TP1 pid=4108136) INFO 06-19 21:46:44 [interface.py:633] Padding mamba page size by 3.82% to ensure that mamba page size and attention page size are exactly equal.
+(Worker_TP0 pid=4108135) WARNING 06-19 21:46:53 [backends.py:1048] Failed to read file <frozen os>
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:53 [backends.py:1089] Using cache directory: /mnt/fast-ai/vllm-cache-exp/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix/vllm/torch_compile_cache/be4a8c4992/rank_0_0/backbone for vLLM's torch.compile
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:53 [backends.py:1148] Dynamo bytecode transform time: 7.85 s
+(Worker_TP1 pid=4108136) WARNING 06-19 21:46:53 [backends.py:1048] Failed to read file <frozen os>
+(Worker_TP0 pid=4108135) INFO 06-19 21:46:57 [backends.py:378] Cache the graph of compile range (1, 8192) for later use
+(Worker_TP0 pid=4108135) INFO 06-19 21:47:37 [backends.py:393] Compiling a graph for compile range (1, 8192) takes 43.80 s
+(EngineCore pid=4108030) INFO 06-19 21:47:45 [shm_broadcast.py:681] No available shared memory broadcast block found in 60 seconds. This typically happens when some processes are hanging or doing some time-consuming work (e.g. compilation, weight/kv cache quantization).
+(Worker_TP0 pid=4108135) INFO 06-19 21:47:49 [decorators.py:708] saved AOT compiled function to /mnt/fast-ai/vllm-cache-exp/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix/vllm/torch_compile_cache/torch_aot_compile/7a83a946d11d77f4ccdbf159a539eb428fb56a6ee0f047dd5d55e70709b0602c/rank_0_0/model
+(Worker_TP0 pid=4108135) INFO 06-19 21:47:49 [monitor.py:53] torch.compile took 64.69 s in total
+(Worker_TP0 pid=4108135) INFO 06-19 21:47:54 [monitor.py:81] Initial profiling/warmup run took 4.40 s
+(Worker_TP0 pid=4108135) INFO 06-19 21:48:02 [gpu_worker.py:487] Available KV cache memory: 10.66 GiB
+(EngineCore pid=4108030) INFO 06-19 21:48:02 [kv_cache_utils.py:1710] GPU KV cache size: 988,822 tokens
+(EngineCore pid=4108030) INFO 06-19 21:48:02 [kv_cache_utils.py:1711] Maximum concurrency for 32,768 tokens per request: 30.18x
+(Worker_TP0 pid=4108135) INFO 06-19 21:48:02 [utils.py:60] `_KV_CACHE_LAYOUT_OVERRIDE` variable detected. Setting KV cache layout to NHD.
+(Worker_TP0 pid=4108135) INFO 06-19 21:48:02 [kernel_warmup.py:44] Skipping FlashInfer autotune because it is disabled.
+(Worker_TP1 pid=4108136) INFO 06-19 21:48:02 [kernel_warmup.py:44] Skipping FlashInfer autotune because it is disabled.
+(Worker_TP0 pid=4108135) WARNING 06-19 21:48:02 [parallel_state.py:566] Skipping communicator graph-capture context for XpuCommunicator under VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1.
+(Worker_TP0 pid=4108135) 
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):   0%|          | 0/15 [00:00<?, ?it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):   7%|▋         | 1/15 [00:00<00:05,  2.35it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  13%|█▎        | 2/15 [00:00<00:05,  2.48it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  20%|██        | 3/15 [00:01<00:04,  2.56it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  27%|██▋       | 4/15 [00:01<00:04,  2.54it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  33%|███▎      | 5/15 [00:01<00:03,  2.55it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  40%|████      | 6/15 [00:02<00:04,  2.12it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  47%|████▋     | 7/15 [00:03<00:04,  1.90it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  53%|█████▎    | 8/15 [00:03<00:03,  1.95it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  60%|██████    | 9/15 [00:04<00:03,  1.57it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  67%|██████▋   | 10/15 [00:08<00:08,  1.64s/it]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  73%|███████▎  | 11/15 [00:09<00:05,  1.46s/it]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  80%|████████  | 12/15 [00:10<00:03,  1.22s/it]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  87%|████████▋ | 13/15 [00:10<00:01,  1.02it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE):  93%|█████████▎| 14/15 [00:11<00:00,  1.23it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE): 100%|██████████| 15/15 [00:12<00:00,  1.12s/it]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE): 100%|██████████| 15/15 [00:12<00:00,  1.16it/s]
+(Worker_TP0 pid=4108135) INFO 06-19 21:48:16 [gpu_model_runner.py:11910] Graph capturing finished in 14 secs, took 1.40 GiB
+(EngineCore pid=4108030) INFO 06-19 21:48:16 [core.py:436] init engine (profile, create kv cache, warmup model) took 91.58 s (compilation: 64.69 s)
+(EngineCore pid=4108030) [transformers] `Qwen2VLImageProcessorFast` is deprecated. The `Fast` suffix for image processors has been removed; use `Qwen2VLImageProcessor` instead.
+(EngineCore pid=4108030) INFO 06-19 21:48:18 [registry.py:126] All limits of multimodal modalities supported by the model are set to 0, running in text-only mode.
+(EngineCore pid=4108030) INFO 06-19 21:48:18 [vllm.py:844] Asynchronous scheduling is disabled.
+(EngineCore pid=4108030) INFO 06-19 21:48:18 [kernel.py:210] Final IR op priority after setting platform defaults: IrOpPriorityConfig(rms_norm=['native'], fused_add_rms_norm=['native'])
+(EngineCore pid=4108030) WARNING 06-19 21:48:18 [xpu.py:208] Forcing XPU Graph with communication ops because VLLM_XPU_FORCE_GRAPH_WITH_COMM=1.
+(APIServer pid=4107806) INFO 06-19 21:48:18 [api_server.py:598] Supported tasks: ['generate']
+(APIServer pid=4107806) INFO 06-19 21:48:20 [hf.py:482] Detected the chat template content format to be 'string'. You can set `--chat-template-content-format` to override this.
+(APIServer pid=4107806) INFO 06-19 21:48:20 [api_server.py:602] Starting vLLM server on http://127.0.0.1:18184
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:37] Available routes are:
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /openapi.json, Methods: GET, HEAD
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /docs, Methods: GET, HEAD
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /docs/oauth2-redirect, Methods: GET, HEAD
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /redoc, Methods: GET, HEAD
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /tokenize, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /detokenize, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /load, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /version, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /health, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /metrics, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/models, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /ping, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /ping, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /invocations, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/chat/completions, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/chat/completions/batch, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/responses, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/responses/{response_id}, Methods: GET
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/responses/{response_id}/cancel, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/completions, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/messages, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/messages/count_tokens, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /inference/v1/generate, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /scale_elastic_ep, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /is_scaling_elastic_ep, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /generative_scoring, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/chat/completions/render, Methods: POST
+(APIServer pid=4107806) INFO 06-19 21:48:20 [launcher.py:46] Route: /v1/completions/render, Methods: POST
+(APIServer pid=4107806) INFO:     Started server process [4107806]
+(APIServer pid=4107806) INFO:     Waiting for application startup.
+(APIServer pid=4107806) INFO:     Application startup complete.
+(APIServer pid=4107806) INFO:     127.0.0.1:59618 - "GET /v1/models HTTP/1.1" 200 OK
+(APIServer pid=4107806) INFO:     127.0.0.1:59632 - "GET /v1/models HTTP/1.1" 200 OK
+(APIServer pid=4107806) INFO:     127.0.0.1:59644 - "POST /v1/completions HTTP/1.1" 200 OK
+(APIServer pid=4107806) INFO:     127.0.0.1:33464 - "GET /metrics HTTP/1.1" 200 OK
+(APIServer pid=4107806) INFO:     127.0.0.1:33470 - "POST /v1/completions HTTP/1.1" 200 OK
+(APIServer pid=4107806) INFO:     127.0.0.1:33478 - "GET /metrics HTTP/1.1" 200 OK
+(EngineCore pid=4108030) INFO 06-19 21:48:48 [core.py:1465] Shutdown initiated (timeout=0)
+(EngineCore pid=4108030) INFO 06-19 21:48:48 [core.py:1488] Shutdown complete
+(Worker_TP0 pid=4108135) INFO 06-19 21:48:48 [multiproc_executor.py:930] Parent process exited, terminating worker queues
+(Worker_TP1 pid=4108136) INFO 06-19 21:48:48 [multiproc_executor.py:1027] WorkerProc shutting down.
+(Worker_TP0 pid=4108135) INFO 06-19 21:48:48 [multiproc_executor.py:1027] WorkerProc shutting down.
+(APIServer pid=4107806) INFO:     Shutting down
+(APIServer pid=4107806) INFO:     Waiting for application shutdown.
+(APIServer pid=4107806) INFO:     Application shutdown complete.
+(APIServer pid=4107806) INFO:     Finished server process [4107806]
diff --git a/notes/2026-06-16-qwen36-current-handoff.md b/notes/2026-06-16-qwen36-current-handoff.md
index d086925..f0f8e4c 100644
--- a/notes/2026-06-16-qwen36-current-handoff.md
+++ b/notes/2026-06-16-qwen36-current-handoff.md
@@ -3492,3 +3492,157 @@ Next branch:
 - If the trace says full-layerlet local work is already near the floor and the
   endpoint wall is elsewhere, pivot back to async/PIECEWISE correctness or
   exact verifier/spec parity rather than adding more MoE micro-knobs.
+
+## 2026-06-20 Addendum - Route-GEMM1 B-Layout Fixed, Endpoint Gate Still Not Active
+
+Root cause fixed:
+
+- The routed topk8 GEMM1/GEMM2-gather kernels in
+  `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp`
+  used the wrong B tensor layout.
+- The existing offsets grouped GEMM path is launched through
+  `MoEGEMMLauncherOffsets<'R','R',...>`, but internally flips B to
+  column-major (`actual_layout_of_B='C'`).
+- The routed topk8 kernels hardcoded B as row-major. Changing the B tensor
+  construction to `'C'` made routed GEMM1 exact.
+
+Direct GEMM1 proof:
+
+- Before fix:
+  `/home/steve/llm-optimizations/data/qwen36-route-gemm1-direct-compare-route80-20260620.json`
+  had `overall_max_abs_diff=16.75`.
+- After B-layout fix:
+  `/home/steve/llm-optimizations/data/qwen36-route-gemm1-direct-compare-route80-blayoutfix-20260620.json`
+  had `overall_max_abs_diff=0.0`.
+- After restoring the hand-written routed body:
+  `/home/steve/llm-optimizations/data/qwen36-route-gemm1-direct-compare-route80-blayoutfix-handbody-20260620.json`
+  also had `overall_max_abs_diff=0.0`.
+
+Replay results:
+
+- Route-80 full layerlet with B-layout fix, Q1, route-GEMM1 hand body:
+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-blayoutfix-handbody-q1-routegemm1-smoke-route80-device0-20260620.json`
+  exact, `full_layerlet_total_us_mean=138.69128`.
+- Seven-route replay with the same path:
+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-blayoutfix-handbody-q1-routegemm1-routes7-device0-20260620.json`
+  all exact. Route means:
+  `0=139.78`, `40=141.45`, `80=139.00`, `85=136.67`,
+  `95=138.02`, `100=160.80`, `115=148.58 us`.
+- MTILE=8 was mixed: route-100 alone improved to `143.38 us`, but the seven
+  route set still had a `165.67 us` worst row. Do not promote MTILE=8 yet.
+
+Endpoint A/B results:
+
+- TP2 graph-none control:
+  `/home/steve/llm-optimizations/data/qwen36-ablation-tp2-control-blayoutfix-summary-20260620tp2ctlblayout1.json`
+  passed JSON/color canaries, `13.95497 tok/s`.
+- TP2 graph-none layerlet flags:
+  `/home/steve/llm-optimizations/data/qwen36-ablation-tp2-fulllayerlet-q1-routegemm1-blayoutfix-summary-20260620tp2fulllayerlet1.json`
+  passed JSON/color canaries, `13.89789 tok/s`.
+- TP2 PIECEWISE forced-comm control:
+  `/home/steve/llm-optimizations/data/qwen36-ablation-tp2-piecewise-control-blayoutfix-summary-20260620tp2piecewisectl1.json`
+  passed JSON/color canaries, `83.56112 tok/s`.
+- TP2 PIECEWISE layerlet flags:
+  `/home/steve/llm-optimizations/data/qwen36-ablation-tp2-piecewise-fulllayerlet-q1-routegemm1-blayoutfix-summary-20260620tp2piecewisefulllayerlet1.json`
+  passed JSON/color canaries, `82.32790 tok/s`.
+
+Important correction:
+
+- The endpoint layerlet-flag runs above did **not** actually prove the C++
+  full-layerlet path was active.
+- A C++ opt-in trace was added in
+  `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`:
+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET_TRACE_FILE`.
+- Trace run without fused-prologue offset gate:
+  `/home/steve/llm-optimizations/data/qwen36-ablation-tp2-piecewise-fulllayerlet-trace-blayoutfix-summary-20260620tp2piecewisefulllayerlettrace1.json`
+  produced no C++ trace file, meaning `qwen36_moe_w8a8_full_layerlet` was not
+  entered.
+- Trace run with:
+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET=1` and
+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE=1`
+  also produced no C++ trace file:
+  `/home/steve/llm-optimizations/data/qwen36-ablation-tp2-piecewise-fulllayerlet-offset-trace-blayoutfix-summary-20260620tp2piecewisefulllayerlettraceoffset1.json`.
+- Therefore the current endpoint is failing a higher-level Python gate before
+  the C++ op. Do not interpret the endpoint layerlet A/B as a real full-layerlet
+  speed test until the Python gate reason is captured.
+
+Interrupted loose end:
+
+- A Python gate-reason trace was added in
+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/fused_moe_interface.py`:
+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET_GATE_TRACE_FILE`.
+- The first gate-reason trace run was interrupted before it reached metrics:
+  label `tp2-piecewise-fulllayerlet-gatetrace-blayoutfix`,
+  stamp `20260620tp2piecewisefulllayerletgatetrace1`.
+- It had not yet produced:
+  `/home/steve/llm-optimizations/data/qwen36-full-layerlet-gate-trace-tp2-piecewise-20260620.jsonl`
+  or
+  `/home/steve/llm-optimizations/data/qwen36-full-layerlet-trace-tp2-piecewise-gatereason-20260620.jsonl`
+  before the stop.
+
+Current active library hashes after trace instrumentation:
+
+- `_xpu_C.abi3.so`:
+  `1797dca305004d09fe89d76f071766b290ecb356adf188faf1b2931a9742fa33`
+- `libgrouped_gemm_xe_2.so`:
+  `d7ac20974b96f7429350ddb0319384386cf2433442bdda1e878537eca60b0be1`
+
+Saved patches:
+
+- Kernel repo patch:
+  `/home/steve/llm-optimizations/patches/vllm-xpu-kernels-qwen36-routegemm1-blayoutfix-20260620.patch`
+- Lab repo patch:
+  `/home/steve/llm-optimizations/patches/llm-optimizations-qwen36-routegemm1-blayoutfix-results-20260620.patch`
+
+Immediate next command to resume:
+
+```bash
+TRACE=/home/steve/llm-optimizations/data/qwen36-full-layerlet-trace-tp2-piecewise-gatereason-20260620.jsonl
+GATE=/home/steve/llm-optimizations/data/qwen36-full-layerlet-gate-trace-tp2-piecewise-20260620.jsonl
+rm -f "$TRACE" "$GATE"
+STAMP=20260620tp2piecewisefulllayerletgatetrace2 \
+PORT=18184 \
+TP_SIZE=2 \
+ONEAPI_DEVICE_SELECTOR=level_zero:0,1 \
+ZE_AFFINITY_MASK=0,1 \
+QWEN36_XPU_PREFLIGHT=0 \
+METRICS_REPEATS=1 \
+METRICS_PROMPT_TOKENS=128 \
+METRICS_OUTPUT_TOKENS=64 \
+METRICS_WARMUP_OUTPUT_TOKENS=16 \
+ABLATION_SKIP_CANARIES=1 \
+ABLATION_RUN_QUALITY=0 \
+ABLATION_SKIP_METRICS=0 \
+VLLM_XPU_GDN_NATIVE_FALLBACK=prefill \
+XPU_GRAPH=1 \
+VLLM_XPU_ENABLE_XPU_GRAPH=1 \
+VLLM_XPU_FORCE_GRAPH_WITH_COMM=1 \
+VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1 \
+COMPILATION_CONFIG='{"cudagraph_mode":"PIECEWISE"}' \
+VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1 \
+VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET=1 \
+VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE=1 \
+VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1 \
+VLLM_XPU_MOE_W8A8_FUSED_Q1=1 \
+VLLM_XPU_MOE_W8A8_ROUTE_GEMM1=1 \
+VLLM_XPU_MOE_W8A8_FULL_LAYERLET_TRACE_FILE="$TRACE" \
+VLLM_XPU_MOE_W8A8_FULL_LAYERLET_TRACE_MAX_LINES=512 \
+VLLM_XPU_MOE_W8A8_FULL_LAYERLET_GATE_TRACE_FILE="$GATE" \
+VLLM_XPU_MOE_W8A8_FULL_LAYERLET_GATE_TRACE_MAX_LINES=512 \
+/home/steve/llm-optimizations/scripts/run-qwen36-ablation-candidate.sh \
+  tp2-piecewise-fulllayerlet-gatetrace-blayoutfix
+```
+
+Decision tree when resuming:
+
+- If the Python gate trace says missing scratch keys, fix scratch allocation in
+  the endpoint path before benchmarking again.
+- If it says `num_rows != 1`, the PIECEWISE bucket is not exercising the
+  single-token layerlet path; add a compatible decode-only gate or layerlet
+  variant for that shape.
+- If it says `stream_capture_active` blocks the fused offset gate, keep
+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE=1` and find the next
+  false prerequisite.
+- Only after the C++ trace shows real calls to
+  `qwen36_moe_w8a8_full_layerlet` should a full canary-clean endpoint A/B be
+  treated as a real layerlet result.
diff --git a/patches/llm-optimizations-qwen36-routegemm1-blayoutfix-results-20260620.patch b/patches/llm-optimizations-qwen36-routegemm1-blayoutfix-results-20260620.patch
index 6a1698d..1d330df 100644
--- a/patches/llm-optimizations-qwen36-routegemm1-blayoutfix-results-20260620.patch
+++ b/patches/llm-optimizations-qwen36-routegemm1-blayoutfix-results-20260620.patch
@@ -1,5983 +0,0 @@
-diff --git a/notes/2026-06-16-qwen36-current-handoff.md b/notes/2026-06-16-qwen36-current-handoff.md
-index d684355..d086925 100644
---- a/notes/2026-06-16-qwen36-current-handoff.md
-+++ b/notes/2026-06-16-qwen36-current-handoff.md
-@@ -71,8 +71,125 @@ VLLM_EXTRA_ARGS='--uvicorn-log-level warning'
- 
- ## Where I Am Right Now
- 
--The latest work is focused on the fused W8A8 MoE prologue path, because timing
--shows MoE/shared-expert work dominates the single-request decode budget.
-+2026-06-19 update: the latest decisive no-async TP2 PIECEWISE trace changed
-+the immediate priority. MoE is still the largest model-forward family, but the
-+accepted no-async decode path is also paying a large sampled-token
-+materialization cost after sampling.
-+
-+Diagnostic identity:
-+
-+```bash
-+TP_SIZE=2
-+ONEAPI_DEVICE_SELECTOR=level_zero:0,1
-+COMPILATION_CONFIG='{"cudagraph_mode":"PIECEWISE"}'
-+XPU_GRAPH=1
-+VLLM_XPU_ENABLE_XPU_GRAPH=1
-+VLLM_XPU_FORCE_GRAPH_WITH_COMM=1
-+VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1
-+VLLM_XPU_GDN_NATIVE_FALLBACK=prefill
-+VLLM_EXTRA_ARGS='--no-async-scheduling --uvicorn-log-level warning'
-+```
-+
-+New diagnostic artifacts:
-+
-+- `/home/steve/llm-optimizations/data/qwen36-stage-boundary-noasync-tp2-20260619stage1.log`
-+- `/home/steve/llm-optimizations/data/qwen36-stage-boundary-noasync-tp2-p512o128-20260619stage1.json`
-+- `/home/steve/llm-optimizations/data/qwen36-stage-boundary-noasync-tp2-timing-summary-20260619stage1.json`
-+- `/home/steve/llm-optimizations/data/qwen36-sync-to-list-noasync-tp2-p512o128-20260619tolist1.json`
-+- `/home/steve/llm-optimizations/data/qwen36-sync-to-list-nosync-noasync-tp2-p512o128-20260619tolist0.json`
-+
-+Key finding:
-+
-+- Diagnostic p512/o128 corrected decode: `83.80 tok/s`.
-+- Stage trace shows steady `forward_end` around `5.25 ms`.
-+- `bookkeeping_sync` is around `4.67 ms`.
-+- Almost all of that is `gpu_model_runner.bookkeeping_to_list`, around
-+  `4.62 ms`, where sampled token IDs are copied/materialized to CPU.
-+- Existing `_to_list` variants did not remove the wall:
-+  - `VLLM_XPU_SYNC_TO_LIST=1`, pre-copy sync on: `83.58 tok/s`.
-+  - `VLLM_XPU_SYNC_TO_LIST=1`, pre-copy sync off: `84.55 tok/s`.
-+
-+Implication:
-+
-+The next high-upside exact path is output materialization overlap/removal,
-+especially repairing async scheduling correctness or building a narrower
-+deferred sampled-token output path. Exact MoE/shared-expert work remains
-+important, but it cannot by itself reach the target while `_to_list` costs
-+about `4.6 ms/token` in the safe no-async path.
-+
-+Async isolation results:
-+
-+- `async-fast-outputids-tp2`, PIECEWISE, async, fast output-id repair:
-+  JSON failed at repeat `21`, color passed.
-+- `async-refresh-prev-sampled-tp2`, PIECEWISE, async, refreshed
-+  `prev_sampled_token_ids` tensor reference each step:
-+  JSON failed at repeat `21`, color passed.
-+- `async-gdn-decode-prefill-tp2`, PIECEWISE, async, native GDN for decode and
-+  prefill:
-+  JSON failed at repeat `31`, color passed.
-+- `async-sync-after-zero-tp2`, PIECEWISE, async, sync after fresh block zero:
-+  JSON failed at repeat `21`, color passed.
-+- `async-sync-output-copy-tp2`, PIECEWISE, async, synchronous output copy:
-+  JSON failed at repeat `21`, color passed.
-+- `async-sync-before-return-tp2`, PIECEWISE, async, full XPU sync before
-+  returning async output:
-+  JSON failed at repeat `21`, color passed.
-+- `async-graphnone-tp2`, graph-none, async:
-+  JSON passed `40/40`, color passed `8/8`.
-+
-+Follow-up async/PIECEWISE replay isolation:
-+
-+- `async-clear-on-prefill-tp2`, async, PIECEWISE, clear captured graphs on
-+  every new prefill:
-+  rejected. It crashed before a valid canary response with
-+  `beginAllocateToPool: already recording to mempool_id`.
-+- `async-initial4-eager-tp2`, async, PIECEWISE, first four decode forwards
-+  eager for each fresh request:
-+  rejected. JSON failed at repeat `60` with
-+  `{"answer":"42 widgets","unit":"widgets"}`; color passed `16/16`.
-+- `async-clone-sampled-ids-tp2`, async, PIECEWISE, clone sampled token IDs
-+  before async reuse:
-+  rejected. JSON failed at repeat `22`; color passed.
-+- `async-sync-replay-tp2`, async, PIECEWISE, synchronize around every graph
-+  replay:
-+  rejected. JSON failed at repeat `22`; color passed.
-+- `async-real-comm-capture-tp2`, async, PIECEWISE, forced comm graph with
-+  `VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=0`:
-+  rejected. Workers died during startup before readiness.
-+- `async-eager-every8req-tp2`, async, PIECEWISE, all decode replay eager for
-+  every eighth fresh request:
-+  accepted as a correctness workaround. JSON passed `96/96`; color passed
-+  `16/16`.
-+- `async-eager-every8req-tp2-metrics`, same identity as the passing `N=8`
-+  canary:
-+  corrected decode `83.35363772782296 tok/s`, decode
-+  `12.00305433894755 ms/token`.
-+- `async-eager-every16req-tp2`, async, PIECEWISE, all decode replay eager for
-+  every sixteenth fresh request:
-+  rejected. JSON passed `96/96`, but color failed at repeat `12`.
-+
-+Interpretation:
-+
-+- Async scheduler semantics can be correct: graph-none async passes the canary.
-+- The repeated JSON corruption requires async plus PIECEWISE replay.
-+- The first bad visible token is produced for the same prompt and same visible
-+  prefix immediately after `{"answer`, so output serialization and simple
-+  sampled-token CPU repair are not the root cause.
-+- Periodic full-request eager decode with `N=8` is the only passing
-+  async/PIECEWISE workaround found so far, but it does not improve the
-+  single-request decode lane versus the safe no-async baseline. It is useful
-+  as a correctness control and reliability fallback, not as the `>150 tok/s`
-+  path.
-+- Simple fences, sampled-token cloning, first-token eagering, graph clearing,
-+  and real communicator capture are closed for now.
-+- Next branch: return to exact structural speed work, especially graph-safe
-+  fused shared-expert/routed MoE boundaries or a larger persistent W8A8
-+  layerlet, with async `N=8` available only if a later endpoint patch needs a
-+  quality-safe async control.
-+
-+Older context: before this trace, the work was focused on the fused W8A8 MoE
-+prologue path, because earlier family timing showed MoE/shared-expert work
-+dominating the single-request decode budget.
- 
- Important timing artifact:
- 
-@@ -258,6 +375,117 @@ Immediate next steps:
-      and `VLLM_XPU_MOE_LIVE_ABI_MAX_LINES=2000`.
-    - Use this only when necessary because it adds overhead.
- 
-+## 2026-06-18 Update: Spec Parity And EAGLE Data Path
-+
-+The current credible path to `>150 tok/s` single-session decode without quality
-+loss is still trained EAGLE speculation. Other measured routes either failed
-+quality gates or lost too much speed. The verifier/spec-state work has moved:
-+
-+- Correct controlled verifier path:
-+  `VLLM_XPU_SPEC_DECODE_DRAFT_ONLY=1`, serial-packed GDN, scheduler tail
-+  fallback, and accepted running conv/SSM state promotion.
-+- Oracle k=4 and k=8 are token-identical to the no-spec fixture with 100%
-+  oracle acceptance. k=8 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-oracle-k8-draftonly-serialgdnpacked-promoteconv-tailfallback-currentbaseline-eager-tp2-20260618cb-candidate.json`.
-+- The old real n-gram k=8 fast-lane attempt is rejected. It reached the server
-+  but serial GDN plus real n-gram acceptance was effectively unusable:
-+  roughly `0.6-3 tok/s` and only the first group accepted `5/8` draft tokens.
-+  Do not promote that route.
-+
-+New EAGLE data export support was added in
-+`/home/steve/src/vllm/vllm/v1/worker/gpu_model_runner.py` behind opt-in envs:
-+
-+```bash
-+VLLM_XPU_EAGLE_DATA_DUMP_DIR=<dir>
-+VLLM_XPU_EAGLE_DATA_DUMP_RANK=0
-+VLLM_XPU_EAGLE_DATA_DUMP_MAX_STEPS=<n>
-+VLLM_XPU_EAGLE_DATA_DUMP_DTYPE=bfloat16
-+VLLM_XPU_EAGLE_DATA_DUMP_SINGLE_TOKEN_ONLY=1
-+```
-+
-+Normal inference is unchanged when these envs are unset. Dump shards are
-+stitched by:
-+
-+`/home/steve/llm-optimizations/scripts/build-qwen36-eagle-dataset-from-dump.py`
-+
-+Smoke results:
-+
-+- TP4 graph-none dump startup failed before readiness with a Level Zero
-+  device-lost error while creating an attention quant scale tensor, before the
-+  dump code ran. Log:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle-hidden-dump-smoke-20260618d.log`.
-+- TP2 graph-none smoke on cards `0,1` succeeded. Dump dir:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle-hidden-dump-smoke-tp2-20260618e`.
-+- TP2 smoke identity: Quark W8A8 INT8 target
-+  `cced56592e8c8935f8220836b4baa04dfd389118`, TP2, 32k max model length,
-+  `COMPILATION_CONFIG='{"cudagraph_mode":"NONE"}'`, no async, `MAX_NUM_SEQS=2`,
-+  `MAX_NUM_BATCHED_TOKENS=1024`, `GPU_MEMORY_UTILIZATION=0.82`.
-+- The TP2 smoke throughput is not a performance result because it was
-+  graph-none and first-request only. It was used only to validate EAGLE data
-+  export.
-+- Dataset summary:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle-hidden-dataset-smoke-tp2-20260618e-summary.json`.
-+  It produced `64` usable rows, `63` continuity matches, `0` continuity breaks,
-+  and one stitched `.pt` sample.
-+- First stitched sample:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle-hidden-dataset-smoke-tp2-20260618e/sample-000000-cmpl-911c7a5dc7a3503b-0-907523cf.pt`
-+  with hidden state shape `(64, 2048)` in BF16.
-+
-+Current implementation direction:
-+
-+1. Use vLLM's existing `method:"eagle"` path first, not EAGLE3. It wraps a
-+   plain Llama-style draft as `EagleLlamaForCausalLM`.
-+2. Draft config should use hidden size `2048`, vocab size `248320`, and a
-+   tiny one-layer Llama decoder. vLLM's simple EAGLE model consumes
-+   `[token_embedding, target_hidden_state]` through `model.fc`.
-+3. Build a loadable smoke checkpoint first, then train it from the dumped
-+   target hidden states. Only after it loads and produces non-trivial
-+   acceptance should we scale data generation and run PIECEWISE TP4 speed gates.
-+
-+## 2026-06-18 Update: EAGLE-1 Loader Smoke
-+
-+Created a reusable smoke-checkpoint generator:
-+
-+`/home/steve/llm-optimizations/scripts/create-qwen36-eagle1-smoke-checkpoint.py`
-+
-+Generated draft:
-+
-+`/home/steve/llm-optimizations/data/qwen36-eagle1-smoke-draft-20260618a`
-+
-+Checkpoint properties:
-+
-+- one Llama-style EAGLE layer;
-+- `hidden_size=2048`, `intermediate_size=4096`;
-+- `num_attention_heads=16`, `num_key_value_heads=2`, `head_dim=128`;
-+- `vocab_size=248320`;
-+- about `43M` BF16 parameters;
-+- intentionally omits `embed_tokens` and `lm_head` so vLLM shares the target
-+  modules.
-+
-+Loader/runtime smoke:
-+
-+- First TP2 launch:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle1-smoke-load-tp2-20260618a.log`
-+  failed before model/draft loading with a oneCCL/SYCL
-+  `PersistentDeviceCodeCache::getItemFromDisc` segfault during early TP2
-+  allreduce.
-+- Retry with `SYCL_CACHE_PERSISTENT=0`:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle1-smoke-load-tp2-20260618b.log`
-+  reached readiness.
-+- vLLM loaded the target and drafter, and logged target sharing on both ranks:
-+  `Detected EAGLE model without its own embed_tokens...` and
-+  `Detected EAGLE model without its own lm_head...`.
-+- Short completion request succeeded through the EAGLE proposer/verifier path.
-+  Since the draft is random, metrics correctly showed `Drafted: 1 tokens`,
-+  `Accepted: 0 tokens`, acceptance `0.0%`.
-+
-+Conclusion:
-+
-+The local EAGLE-1 checkpoint format is loadable and executable on XPU. The next
-+required step is a real trainer that writes the same checkpoint format from the
-+Quark INT8 hidden-state dataset, then a TP2 acceptance smoke, then larger data
-+export/training before any TP4 PIECEWISE performance gate.
-+
- 3. If every layer-enabled fused-prologue capture path fails, stop spending
-    time on captured fused prologue and pivot to one of:
-    - persistent MoE layerlet that avoids graph-captured prologue state
-@@ -566,3 +794,2701 @@ for this model exists on disk. Reaching the >150 goal therefore requires
- training an EAGLE draft on the Quark INT8 target (extract hidden states,
- clone SafeAILab/EAGLE, train) - a multi-hour task with XPU-compat risk.
- 
-+## 2026-06-18 Addendum — Restored Oracle Identity + Native Prefill State Failure
-+
-+Important re-anchor:
-+
-+- The token-exact oracle fixture is the **serial GDN identity**, not the
-+  generic/native-spec identity. The identity needs:
-+  `VLLM_XPU_SPEC_DECODE_DRAFT_ONLY=1`,
-+  `VLLM_XPU_GDN_SERIAL_SPEC_DECODE=1`,
-+  `VLLM_XPU_GDN_SERIAL_SPEC_PACKED_DECODE=1`,
-+  `VLLM_XPU_GDN_SERIAL_SPEC_CONV=1`,
-+  `VLLM_XPU_GDN_SPEC_PROMOTE_RUNNING_AFTER_SPEC=1`, and
-+  `VLLM_XPU_GDN_SPEC_PROMOTE_CONV_STATE=1`.
-+- Reproduced on current tree:
-+  `qwen36-oracle-k8-draftonly-serial-restoredidentity-currenttree-eager-tp2-20260618b`
-+  has `baseline_match_all=true`, first diff `null`, 24/24 accepted, 100%
-+  full-accept rows. The parity gate still reports replay-accounting
-+  mismatches, but token output is exact.
-+- A misleading control without the serial flags
-+  (`qwen36-oracle-k8-draftonly-serialgdn-nopostprocess-control-currenttree-eager-tp2-20260618b`)
-+  failed at token 18 with 16/32 accepted. Do not use this as evidence against
-+  the serial oracle path; it was the wrong identity.
-+
-+Failed native-prefill bridge attempts:
-+
-+- `qwen36-oracle-k8-draftonly-nativeprefill-allornothing-rollback-currenttree-eager-tp2-20260618b`:
-+  all-or-nothing reduced the third partial row to 0 accepted and preempted,
-+  but output still diverged at token 17. Scheduler rollback alone cannot make
-+  native-prefill safe.
-+- `qwen36-oracle-k8-draftonly-nativeprefill-allornothing-finalpromote-currenttree-eager-tp2-20260618b`:
-+  enabling final promotion plus conv-state promotion did not help; same first
-+  diff at token 17.
-+- `qwen36-oracle-k8-draftonly-nativeprefill-replaycols-allornothing-finalpromote-currenttree-eager-tp2-20260618b`:
-+  replayed output state columns worsened acceptance (8/16) and still diverged
-+  at token 17.
-+
-+Conclusion:
-+
-+- The current native-prefill sequence is not serial-equivalent even after two
-+  full accepted groups when control returns to ordinary decode. It is not only
-+  a partial-accept commit issue; full accepted groups do not leave a safe
-+  running GDN state for later fallback/recovery decode.
-+- Do not spend more time on scheduler-only all-or-nothing workarounds for this
-+  path. The next viable correctness work is to repair native-prefill state
-+  generation/promotion itself, or to optimize the token-exact serial GDN path.
-+
-+Postprocess experiment status:
-+
-+- Added gated `VLLM_XPU_GDN_NONSPEC_POSTPROCESS_ACCEPTED_STATE=1` helper in
-+  `vllm/v1/worker/mamba_utils.py` and runner hook in
-+  `vllm/v1/worker/gpu_model_runner.py`.
-+- The hook now skips full-accept rows by default and avoids globally clobbering
-+  accepted-token counts. It remains diagnostic only. Do not enable it in
-+  accepted benchmark identities until a serial-identity test with the hook also
-+  passes token parity.
-+
-+## 2026-06-18 Addendum 2 — Gate Semantics Fixed, Native Verifier Still Unsafe
-+
-+Serial correctness anchor:
-+
-+- Current-tree serial GDN control
-+  `qwen36-oracle-k8-draftonly-serial-restoredidentity-currenttree-eager-tp2-20260618e`
-+  emitted the accepted no-spec token stream exactly (`first_diff=null`, 32/32
-+  output tokens match) with spec activity (`24/24` accepted, 100%, 3 rows).
-+- The original gate failed only because replay accounting reported 3 diagnostic
-+  mismatches. Generated tokens, suppressed follow-up schedule, and suppressed
-+  accept checks were clean.
-+- Added explicit checker option
-+  `--allow-replay-accounting-mismatch` and wrapper env
-+  `ALLOW_REPLAY_ACCOUNTING_MISMATCH=1`. Default behavior remains strict.
-+- Offline re-gate artifact:
-+  `data/qwen36-oracle-k8-draftonly-serial-restoredidentity-currenttree-eager-tp2-20260618e-allowacct-gate-summary.json`
-+  passed exact mode. Use this option only for known accounting-only trace noise,
-+  not for token or suppressed-follow-up failures.
-+
-+Native verifier probes after the restored serial anchor:
-+
-+- `qwen36-oracle-k8-draftonly-nativeprefill-exactstatereplay-offset1-manualconv-nofinalpromote-allornothing-postprocess-currenttree-eager-tp2-20260618e`:
-+  failed at token 17. All-or-nothing is not sufficient.
-+- `qwen36-oracle-k8-draftonly-nativeprefill-exactstatereplay-offset1-manualconv-nofinalpromote-nopreemptreject-postprocess-currenttree-eager-tp2-20260618e`:
-+  failed at token 24, immediately after accepting `... 271, 248068`.
-+- `qwen36-oracle-k8-draftonly-nativeprefill-exactstatereplay-offset1-manualconv-writeoutputs-nofinalpromote-postprocess-currenttree-eager-tp2-20260618e`:
-+  failed at token 17. Python/FLA replay outputs are not equivalent to the native
-+  safe output lane.
-+- `qwen36-oracle-k8-draftonly-nativeprefill-exactstatereplay-offset1-nativedecode-writeoutputs-nofinalpromote-postprocess-currenttree-eager-tp2-20260618e`:
-+  failed at token 17. Native per-position replay output write also worsened.
-+- `qwen36-oracle-k7-draftonly-nativeprefill-exactstatereplay-offset1-manualconv-nofinalpromote-postprocess-currenttree-eager-tp2-20260618e`:
-+  failed at token 24. The issue is not simply k=8 depth; it is a native
-+  verifier/state/logit boundary around the `248068` special token region.
-+
-+Current interpretation:
-+
-+- Do not enable the new output-write diagnostics in accepted identities:
-+  `VLLM_XPU_GDN_NATIVE_SPEC_PREFILL_EXACT_REPLAY_WRITE_OUTPUTS=1` and
-+  `VLLM_XPU_GDN_NATIVE_SPEC_PREFILL_EXACT_REPLAY_NATIVE_DECODE=1` both failed.
-+- The token-exact path is the serial GDN verifier path. The next performance
-+  work should either optimize that serial-correct verifier, or train/use a
-+  lightweight EAGLE draft with the serial verifier as the quality anchor.
-+
-+Serial verifier speed check:
-+
-+- `qwen36-ablation-serialgdn-oracle-k8-piecewise-tp2-metrics-20260618f`
-+  measured the serial-correct verifier under PIECEWISE graph on TP2.
-+- Summary:
-+  `data/qwen36-ablation-serialgdn-oracle-k8-piecewise-tp2-metrics-20260618f-summary-20260618192000.json`.
-+- Result: `14.03` corrected tok/s, `72.10` ms/token. This is not a viable
-+  speed lane. Keep serial GDN as a token-parity oracle only.
-+
-+## 2026-06-18 Addendum 3 - EAGLE k5 Ceiling And Rollout Result
-+
-+EAGLE speed ceiling:
-+
-+- Synthetic k3 acceptance probe
-+  `qwen36-ablation-eagle2-tokenheavy-synthaccept4-piecewise-tp2-k3-ceiling-20260618h`
-+  measured `140.14` corrected tok/s, `7.20` ms/token. This is metrics-only,
-+  with canaries and quality skipped, so it is not promotable. It shows perfect
-+  k3 is still below the `>150 tok/s` target.
-+- Synthetic k5 acceptance probe
-+  `qwen36-ablation-eagle2-tokenheavy-synthaccept6-piecewise-tp2-k5-ceiling-20260618h`
-+  measured `181.91` corrected tok/s, `5.56` ms/token. This is also metrics-only
-+  and not promotable. It proves the serial EAGLE k5 path can structurally clear
-+  `>150 tok/s` if the draft acceptance is high enough.
-+
-+Real EAGLE draft results:
-+
-+- Current token-heavy EAGLE k5 run
-+  `qwen36-ablation-eagle2-tokenheavy-fusedbatch-nosafety-fastpath-piecewise-tp2-k5-smoke-20260618h`
-+  measured `52.52` corrected tok/s, `18.95` ms/token, with mean acceptance
-+  length `2.02`, `107/525` accepted drafts, and per-position acceptance
-+  `0.543, 0.314, 0.124, 0.038, 0.000`.
-+- Added rollout training support to
-+  `scripts/train-qwen36-eagle1-draft.py` with `--rollout-steps`; default
-+  one-step behavior is unchanged.
-+- Rollout checkpoint:
-+  `data/qwen36-eagle2-corpus2-tokenheavy-rollout5-trained-20260618h`.
-+  Training used the token-heavy checkpoint as init, three epochs, lr `5e-6`,
-+  rollout steps `5`, and the same corpus/corpus2/pos datasets.
-+- Rollout k5 endpoint run
-+  `qwen36-ablation-eagle2-rollout5-piecewise-tp2-k5-smoke-20260618h`
-+  measured `55.70` corrected tok/s, `17.95` ms/token. Acceptance was worse
-+  than useful: mean acceptance length `1.90`, `80/445` accepted drafts, and
-+  per-position acceptance `0.494, 0.303, 0.101, 0.000, 0.000`.
-+
-+Decision:
-+
-+- Do not continue short rollout fine-tuning on this tiny dataset as a near-term
-+  performance path. It did not improve k5 acceptance and remains far below the
-+  acceptance needed to use the `181.91 tok/s` synthetic ceiling.
-+- The likely EAGLE blocker is draft quality/deeper-step training data, not the
-+  verifier's basic mechanics. A viable EAGLE path needs a much larger and more
-+  representative hidden-state dataset and an offline acceptance evaluator before
-+  more endpoint smoke runs.
-+- Near-term performance work should return to exact no-quality-loss fast path
-+  improvements: collectives/topology, XPU graph replay correctness, and MoE
-+  dispatch/GEMM overhead. Keep EAGLE as a possible larger-batch training track,
-+  not the next single-session speed lever unless a better draft is produced.
-+
-+## 2026-06-18 Addendum 4 - TP4 Health Blocker And Traceability Fix
-+
-+Cached PIECEWISE traceability fix:
-+
-+- Patched `/home/steve/src/vllm/vllm/compilation/caching.py` so the cached
-+  `PiecewiseBackend` construction now passes `submod_name=submod_name`.
-+- Reason: cached PIECEWISE wrappers were losing their stable submodule labels,
-+  making `VLLM_XPU_CUDAGRAPH_DISABLE_SUBMOD_REGEX` and direct-sync isolation
-+  hard to audit.
-+- Validation: `py_compile` passed for `vllm/compilation/caching.py`.
-+
-+Launcher health preflight:
-+
-+- Patched
-+  `/home/steve/llm-optimizations/scripts/launch-qwen36-quark-int8-accepted.sh`
-+  with `QWEN36_XPU_PREFLIGHT`.
-+- Default behavior is `QWEN36_XPU_PREFLIGHT=auto`, which runs the XPU/XCCL
-+  preflight for `TP_SIZE>=4` before starting vLLM. Set
-+  `QWEN36_XPU_PREFLIGHT=0` only for explicitly labeled diagnostics.
-+- The preflight writes a separate log at
-+  `${LOG_PATH%.*}-xpu-health.log` unless `QWEN36_XPU_PREFLIGHT_LOG` is set.
-+- Validation: `bash -n` passed for the launcher and health script. A blocked
-+  launch smoke test refused to start TP4 and wrote
-+  `/home/steve/llm-optimizations/data/qwen36-preflight-blocked-launch-smoke-20260618-xpu-health.log`.
-+
-+Fused-prologue isolation attempts:
-+
-+- `qwen36-ablation-prologue-disable-submod2-c1capture-20260618proliso1.log`
-+  attempted to isolate `piecewise:2/` with
-+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET=1`,
-+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE=1`,
-+  `VLLM_XPU_CUDAGRAPH_DISABLE_SUBMOD_REGEX='piecewise:2/'`, and direct sync on
-+  the same submodule.
-+- `qwen36-ablation-prologue-disable-submod2-c1capture-gmem086-20260618proliso2.log`
-+  repeated the same probe at `GPU_MEMORY_UTILIZATION=0.86`.
-+- Both probes failed before model readiness, inside XPU/XCCL device
-+  initialization, so they are invalid as prologue evidence. Do not count either
-+  run as a model-speed or model-correctness result.
-+
-+Hardware/runtime health finding:
-+
-+- New preflight script:
-+  `/home/steve/llm-optimizations/scripts/check-qwen36-xpu-xccl-health.sh`.
-+- Failing TP4 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-device3-wedged-20260618.log`.
-+  Physical devices `0`, `1`, and `2` pass single-device XPU allocation; physical
-+  device `3` fails a small tensor allocation with
-+  `UR_RESULT_ERROR_OUT_OF_RESOURCES`. A 4-rank XCCL barrier/all-reduce over
-+  `0,1,2,3` then fails on rank 3 with the same error.
-+- Passing subset artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-devices012-pass-20260618.log`.
-+  Physical devices `0,1,2` pass single-device allocation and 3-rank XCCL
-+  barrier/all-reduce.
-+- Device map from `xpu-smi discovery`: failed XPU id `3` is PCI
-+  `0000:47:00.0`, DRM `/dev/dri/card2`.
-+- No user process was holding `/dev/dri/card2` or the render nodes. `xpu-smi ps`
-+  showed only `xpu-smi` itself during inspection.
-+- Kernel logs show repeated `xe 0000:47:00.0` GT0 job timeouts, VM job
-+  timeouts, and driver reset attempts before the health check. This is a
-+  low-level card/driver recovery state, not an ordinary vLLM OOM.
-+- `xpu-smi config -d 3 --reset` reported `Fail to reset device`. Prior
-+  noninteractive sysfs reset also required sudo. A root-level PCI/SBR reset or
-+  host reboot is required before valid TP4 endpoint benchmarking can resume.
-+
-+How to re-check health:
-+
-+```bash
-+PHYSICAL_DEVICES=0,1,2,3 XCCL_DEVICES=0,1,2,3 \
-+  /home/steve/llm-optimizations/scripts/check-qwen36-xpu-xccl-health.sh
-+```
-+
-+Healthy-subset check:
-+
-+```bash
-+PHYSICAL_DEVICES=0,1,2 XCCL_DEVICES=0,1,2 \
-+  /home/steve/llm-optimizations/scripts/check-qwen36-xpu-xccl-health.sh
-+```
-+
-+Current decision:
-+
-+- Treat TP4 Qwen 3.6 endpoint runs as blocked until the 4-card health preflight
-+  passes.
-+- Continue only work that does not require a valid 4-card endpoint while the
-+  card is wedged: offline prologue/MoE replay, TP2/TP3 diagnostics clearly
-+  labeled as non-comparable, and code cleanup/traceability.
-+- Once TP4 health passes, rerun the fused-prologue `piecewise:2/` isolation
-+  probe with full benchmark identity before interpreting speed or quality.
-+
-+## 2026-06-18 Addendum 5 - Healthy-Device W8A8 MoE Replay Floor
-+
-+Because physical XPU 3 is still unhealthy, the following runs are offline
-+single-device replay diagnostics only. They are not endpoint speed results and
-+are not comparable to TP4 serving throughput. They use `ZE_AFFINITY_MASK=0` and
-+`ONEAPI_DEVICE_SELECTOR=level_zero:0` to avoid the wedged card.
-+
-+Middle-layerlet correctness recheck:
-+
-+- Command:
-+  `/home/steve/llm-optimizations/scripts/check-qwen36-w8a8-middle-layerlet.py --graph-replay --require-graph`
-+- JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-w8a8-middle-layerlet-check-device0-20260618.json`
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-w8a8-middle-layerlet-check-device0-20260618.md`
-+- Result: overall passed. Eager and XPU graph replay passed for all synthetic
-+  cases, including `qwen36_decode_one_token_tp4_shape`.
-+- Interpretation: the existing middle-layerlet math and graph replay are still
-+  valid in isolation. The full endpoint blocker is integration/capture and the
-+  current TP4 hardware health issue, not this standalone math path.
-+
-+Full route-exact MoE replay, current binary:
-+
-+- JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-current-device0-20260618.json`
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-current-device0-20260618.md`
-+- Result: best exact non-reference candidate was `preallocated_staged` at
-+  `191.159 us` best-row mean, `1.527x` versus current `xpu_fused_moe`.
-+- Aggregate means: `xpu_fused_moe` `308.363 us`, scratch `256.104 us`,
-+  preallocated staged `200.261 us`, fused-prologue staged `270.232 us`.
-+- Gate: failed. No rows met the `160 us/layerlet` target.
-+
-+Offset/active-offset GEMM replay:
-+
-+- JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-offset-active-device0-20260618.json`
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-offset-active-device0-20260618.md`
-+- Result: exact. Best exact non-reference candidate was
-+  `fused_prologue_offset_gemm` at `186.619 us`, `1.581x` versus current
-+  `xpu_fused_moe`.
-+- Aggregate means: `xpu_fused_moe` `316.883 us`, scratch `262.541 us`,
-+  preallocated staged `203.542 us`, fused-prologue offset-GEMM `200.269 us`,
-+  active-offset-GEMM `201.639 us`.
-+- Gate: failed. This is the best offline diagnostic seen today, but still short
-+  of the `160 us/layerlet` target.
-+
-+Hot-packed expert replay:
-+
-+- JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-hotpack-offset-active-device0-20260618.json`
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-hotpack-offset-active-device0-20260618.md`
-+- Result: exact in the synthetic remapped replay, but not a useful speed lever.
-+  Best exact candidate was `fused_prologue_offset_gemm` at `186.212 us`, with
-+  worse tail rows (`worst_best_exact_nonreference_us_mean=241.526 us`).
-+- Decision: do not prioritize expert hot-packing unless a later route-frequency
-+  model shows a stronger reason. It would require exact offline expert-weight
-+  permutation plus router-ID remap to preserve model outputs.
-+
-+Fused SiLU+quant replay:
-+
-+- JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-fusedsilu-offset-active-device0-20260618.json`
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-fusedsilu-offset-active-device0-20260618.md`
-+- Result: exact in this replay, but slower than the plain offset-GEMM
-+  diagnostic. Best exact candidate was `fused_prologue_offset_gemm` at
-+  `189.774 us`.
-+- Decision: do not revive the previously rejected fused-SiLU endpoint path for
-+  speed. It remains a diagnostic-only lane unless a separate correctness fix
-+  explains the earlier endpoint canary failures.
-+
-+Graph replay timing diagnostic:
-+
-+- Script updated:
-+  `/home/steve/llm-optimizations/scripts/bench-qwen36-int8-moe-kernels.py`
-+  now supports `--graph-replay-timing`, `--graph-warmup`, and
-+  `--graph-iterations`.
-+- Syntax validation:
-+  `/home/steve/.venvs/vllm-xpu/bin/python -m py_compile scripts/bench-qwen36-int8-moe-kernels.py`
-+  passed.
-+- Multi-route artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-graph-offset-active-device0-20260618.json`
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-graph-offset-active-device0-20260618.md`
-+- Result: all graph captures executed, but candidate graph replay was not a
-+  stable shortcut. Aggregating graph rows by candidate produced:
-+  `xpu_fused_moe_with_scratch` mean `235.608 us`,
-+  `preallocated_staged` mean `238.654 us`,
-+  `fused_prologue_offset_gemm` mean `238.264 us`, and
-+  `fused_prologue_active_offset_gemm` mean `236.136 us`, with a wide
-+  `~145-331 us` range.
-+- A follow-up single-route graph run for route start `56` was rerun
-+  sequentially to avoid device contention:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-route-replay-graph-route56-sequential-device0-20260618.json`.
-+  It showed eager `fused_prologue_offset_gemm` at `185.661 us`, but graph
-+  replay around `331-340 us`, so the under-160 graph samples from the
-+  multi-route sweep are not trusted as promotion evidence.
-+- Invalid artifacts: `graph-route0-device0-20260618` and
-+  `graph-route56-device0-20260618` were accidentally launched in parallel on
-+  the same physical XPU. Do not use those two artifacts for performance
-+  conclusions.
-+- Decision: keep graph replay timing as a diagnostic only. It does not replace
-+  the need for a native one-dispatch/persistent MoE layerlet.
-+
-+Updated target decision:
-+
-+- The next exact no-quality-loss MoE speed path is not another Python scratch
-+  arrangement. The replay data says we need a true prologue-inclusive
-+  one-dispatch or persistent layerlet that keeps the offset-GEMM advantage and
-+  removes more fixed launch/dispatch overhead around activation/quant/GEMM2.
-+- A useful candidate must beat roughly `160 us` on this route replay before it
-+  deserves endpoint promotion work. For the `>150 tok/s` goal, the endpoint
-+  target will probably need this MoE layerlet plus restored healthy TP4 graph
-+  execution; current replay-only candidates are still not enough.
-+
-+## 2026-06-18 Addendum 6 - Full W8A8 Layerlet Staged, Exact, Not Promoted
-+
-+2025.3 binary staging:
-+
-+- Rebuilt and staged the XPU extension with the oneAPI 2025.3-compatible
-+  runtime path. The earlier 2026-built extension pulled a `libsycl.so.9` ABI
-+  and caused native crashes against the current PyTorch/XPU runtime.
-+- Package binaries in `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/`
-+  were backed up with suffix `backup-20260618-full-layerlet-2025-precopy`
-+  before staging.
-+- Import check passed for both
-+  `torch.ops._xpu_C.qwen36_moe_w8a8_middle_layerlet` and
-+  `torch.ops._xpu_C.qwen36_moe_w8a8_full_layerlet`.
-+
-+Full layerlet implementation:
-+
-+- Kernel binding added in `/home/steve/src/vllm-xpu-kernels`:
-+  `csrc/xpu/moe_layerlet.cpp`, `csrc/xpu/ops.h`,
-+  `csrc/xpu/torch_bindings.cpp`, and `CMakeLists.txt`.
-+- Python integration added behind
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1` in
-+  `vllm_xpu_kernels/fused_moe_interface.py`.
-+- Accepted launcher explicitly unsets the full-layerlet flag unless
-+  `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`, so production/accepted runs cannot
-+  accidentally use the experimental path.
-+- Run-summary identity tracking now includes
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET`.
-+
-+Exact replay result:
-+
-+- Sweep JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-sweep-device0-20260618.json`
-+- Sweep Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-sweep-device0-20260618.md`
-+- Result: 16 routed rows, all exact with
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+- Full-layerlet timing: min `155.263 us`, mean `161.743 us`,
-+  max `171.005 us`, median `161.083 us`.
-+- Existing middle-layerlet timing on the same sweep: mean `167.315 us`.
-+- Current `xpu_fused_moe` reference timing on the same sweep:
-+  mean `304.637 us`.
-+- Gate: useful but not promoted. Half the rows are under `160 us`, but the
-+  sweep is single-device offline replay, not an endpoint or graph-quality
-+  result.
-+
-+Live Python branch smoke:
-+
-+- Direct live-path smoke:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-livepath-smoke-device0-20260618.json`
-+  was exact with `max_abs_diff = 0.0` and about `1.49x` over the local base
-+  call on that route.
-+- Preallocated-output live-path smoke:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-livepath-prealloc-smoke-device0-20260618.json`
-+  was exact with `max_abs_diff = 0.0`, but only about `1.20x` in that noisy
-+  wrapper test.
-+- Interpretation: the C++ op is exact and useful in offline replay, but live
-+  wrapper variance means it is not endpoint-promoted yet.
-+
-+Next exact MoE work:
-+
-+- The current full layerlet still calls separate prologue, quant1, GEMM1,
-+  activation/quant2, GEMM2, and gather launches.
-+- The next best no-quality-loss kernel target is a single-token/top-k=8
-+  prologue-plus-quant1 fused path. It should preserve the exact per-row INT8
-+  scale/round/clamp math while avoiding the BF16 remap write/read and deleting
-+  one dispatch.
-+- A smaller fallback target is a specialized single-token/top-k=8 gather, but
-+  gather is likely launch dominated and may not be enough by itself.
-+- Endpoint TP4 promotion remains blocked until the physical XPU 3 health check
-+  passes.
-+
-+## 2026-06-18 Addendum 7 - Fused Quant1 Tried And Gated Off
-+
-+Fused quant1 candidates:
-+
-+- Added an opt-in C++ single-token/top-k=8 prologue+quant1 helper inside
-+  `csrc/xpu/moe_layerlet.cpp`, controlled by
-+  `VLLM_XPU_MOE_W8A8_FUSED_Q1=1`.
-+- The accepted launcher now unsets `VLLM_XPU_MOE_W8A8_FUSED_Q1` unless
-+  `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`.
-+- `run-qwen36-ablation-candidate.sh` records
-+  `VLLM_XPU_MOE_W8A8_FUSED_Q1` in the run-summary identity.
-+
-+Results:
-+
-+- Serial duplicate q1 variant:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1fused-sweep-device0-20260618.json`
-+  - Exact: max diff `0.0`.
-+  - Full-layerlet min/mean/median/max:
-+    `158.761 / 167.807 / 163.251 / 182.766 us`.
-+  - Only `1/16` rows under `160 us`.
-+  - Rejected for speed. It reduced quant parallelism too much.
-+- Eight-workgroup q1 variant:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1parallel-sweep-device0-20260618.json`
-+  - Exact: max diff `0.0`.
-+  - Full-layerlet min/mean/median/max:
-+    `160.385 / 178.733 / 176.648 / 202.214 us`.
-+  - `0/16` rows under `160 us`.
-+  - Rejected for speed. Preserving row parallelism still did not beat the
-+    existing prologue+quant sequence.
-+
-+Restored guarded default:
-+
-+- Default path with `VLLM_XPU_MOE_W8A8_FUSED_Q1` unset:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1guard-default-sweep-device0-20260618.json`
-+  - Exact: max diff `0.0`.
-+  - Full-layerlet min/mean/median/max:
-+    `154.587 / 160.819 / 159.294 / 178.277 us`.
-+  - `11/16` rows under `160 us`.
-+- Decision: keep the q1 code only as an opt-in diagnostic. Do not promote it
-+  or enable it by default.
-+
-+Next exact MoE target:
-+
-+- A standalone q1 fusion is not the missing win. The next worthwhile exact
-+  path is either a true persistent/one-dispatch MoE layerlet that moves the
-+  GEMM2/gather boundary, or a specialized gather/epilogue integration that
-+  avoids the final launch without reducing quant/GEMM parallelism.
-+
-+## 2026-06-18 Addendum 8 - Fast Gather And Unchecked Middle Rejected
-+
-+Fast gather:
-+
-+- Added an opt-in single-token/top-k=8 gather helper controlled by
-+  `VLLM_XPU_MOE_W8A8_FAST_GATHER=1`.
-+- The helper preserves the generic gather accumulation order and was exact in
-+  replay, but it did not improve the route sweep enough:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-fastgather-sweep-device0-20260618.json`
-+  - Exact: max diff `0.0`.
-+  - Full-layerlet min/mean/median/max:
-+    `155.116 / 161.622 / 161.662 / 170.463 us`.
-+  - `5/16` rows under `160 us`.
-+- Same-lane comparison: the guarded default remains better than fast gather:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1guard-default-sweep-device0-20260618.json`
-+  had `154.587 / 160.819 / 159.294 / 178.277 us` and `11/16` rows under
-+  `160 us`.
-+- Decision: keep fast gather as an opt-in diagnostic only. Do not enable or
-+  promote it.
-+
-+Unchecked-middle wrapper:
-+
-+- Tried removing the duplicated middle-layerlet validation from inside the
-+  experimental full-layerlet wrapper. This does not change math, but the
-+  candidate was slower under the same rebuilt binary.
-+- Candidate artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-uncheckedmiddle-sweep-device0-20260618.json`
-+  - Exact: max diff `0.0`.
-+  - Full-layerlet min/mean/median/max:
-+    `163.327 / 177.125 / 173.131 / 210.363 us`.
-+  - `0/16` rows under `160 us`.
-+- Same-binary control without the unchecked path:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-uncheckedmiddle-control-device0-20260618.json`
-+  - Exact: max diff `0.0`.
-+  - Full-layerlet min/mean/median/max:
-+    `157.361 / 171.858 / 170.957 / 191.336 us`.
-+  - `2/16` rows under `160 us`.
-+- The absolute control run was slower than the older guarded-default artifact
-+  across reference and candidate timings, so do not compare it directly against
-+  the old artifact as a regression claim. Within the same rebuilt binary,
-+  unchecked-middle was clearly worse than its control.
-+- Decision: rejected and removed from source/scripts. Package binaries were
-+  restored from `backup-20260618-uncheckedmiddle-precopy`; the importable
-+  package is back to the previous fast-gather/full-layerlet staged binary.
-+
-+Current best exact offline MoE artifact:
-+
-+- The best exact offline full-layerlet result remains the guarded default:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1guard-default-sweep-device0-20260618.json`.
-+- The key blocker is still not a small wrapper or standalone gather tweak.
-+  The next serious exact/no-quality-loss path needs to remove a larger
-+  boundary: a true persistent or one-dispatch MoE layerlet, or an exact
-+  GEMM2/gather epilogue design that preserves the current BF16 row rounding
-+  before weighted accumulation.
-+
-+## 2026-06-18 Addendum 9 - Real-Routing Oracle Fixed A Hidden Map/Binary Mismatch
-+
-+Harness fixes:
-+
-+- Added real-routing oracle checks to
-+  `/home/steve/llm-optimizations/scripts/bench-qwen36-int8-moe-kernels.py`.
-+  The oracle compares candidates against a forced rows-per-expert W8A8 path
-+  with offset/layerlet/prologue env paths disabled.
-+- Added hot-skew synthetic routing to catch multi-row/non-uniform expert maps.
-+- Fixed the benchmark report to store immediate scalar exactness diffs. The
-+  earlier report recomputed some diffs from tensors backed by scratch buffers
-+  after later timing loops had overwritten them.
-+- Graph replay now uses separate scratch buffers from the eager exactness path.
-+
-+Correctness bug found:
-+
-+- Hot-skew rows initially exposed large multi-row diffs in the fused-prologue
-+  paths.
-+- Root cause in source: `csrc/moe/fused_moe_prologue.hpp` wrote
-+  `unpermuted_row_to_permuted_row` in column-major expanded-token order
-+  (`k * rows + row`) while `moe_gather` expects row-major
-+  (`row * topk + k`).
-+- Patched `MergeExpertPrefixSumKernel` to keep
-+  `permuted_row_to_unpermuted_row` column-major for internal remap, but write
-+  `unpermuted_row_to_permuted_row[source_row * topk + source_k_rank]`.
-+
-+Build lesson:
-+
-+- Rebuilding only `_xpu_C.abi3.so` was insufficient. The Python benchmark path
-+  calls `torch.ops._moe_C.fused_moe_prologue`; that binary was still from
-+  2026-06-12 and kept the old map layout.
-+- Rebuilt and staged both binaries:
-+  - `_xpu_C.abi3.so`: `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_xpu_C.abi3.so`
-+  - `_moe_C.abi3.so`: `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_moe_C.abi3.so`
-+- Backups:
-+  - `_xpu_C.abi3.so.backup-20260618174647-pre-rowmajor-prologue-fix`
-+  - `_moe_C.abi3.so.backup-20260618175726-pre-rowmajor-prologue-fix`
-+
-+Corrected artifacts:
-+
-+- Pre-`_moe_C` rebuild failing/contaminated graph diagnostic:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-rowmajorfix-graph-hot-skew-device0-20260618.json`
-+- Corrected rows=2 immediate-diff proof after `_moe_C` rebuild:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-immediatediff-after-moeC-rebuild-hot-skew-rows2-device0-20260618.json`
-+- Corrected hot-skew sweep after `_moe_C` rebuild:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-after-moeC-rebuild-hot-skew-sweep-device0-20260618.json`
-+- Corrected graph replay spot-check:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-after-moeC-rebuild-graph-hot-skew-rows2-device0-20260618.json`
-+
-+Patch snapshots:
-+
-+- `/home/steve/llm-optimizations/patches/vllm-xpu-kernels-qwen36-w8a8-layerlet-rowmajor-moeC-20260618.patch`
-+- `/home/steve/llm-optimizations/patches/llm-optimizations-qwen36-real-routing-oracle-immediatediff-20260618.patch`
-+
-+Corrected hot-skew sweep summary:
-+
-+| rows | xpu fused us | prealloc us | offset us | middle layerlet us | full layerlet us | max diff |
-+|---:|---:|---:|---:|---:|---:|---:|
-+| 1 | 392.893 | 255.456 | 243.029 | 211.361 | 228.176 | 0.0 |
-+| 2 | 319.131 | 199.030 | 200.844 | 182.169 | 166.017 | 0.0 |
-+| 4 | 342.726 | 224.809 | 218.783 | 188.799 | 181.233 | 0.0 |
-+| 8 | 322.517 | 200.850 | 200.811 | 177.496 | 169.169 | 0.0 |
-+| 16 | 317.837 | 204.380 | 194.935 | 173.069 | 166.498 | 0.0 |
-+
-+Current interpretation:
-+
-+- The real-routing correctness problem is fixed for the offline replay paths:
-+  current reference, rows oracle, offset oracle, fused-prologue, middle
-+  layerlet, and full layerlet all report `max_abs_diff = 0.0` on hot-skew
-+  multi-row replay after both extensions are rebuilt.
-+- The best exact offline candidate is still short of the `160 us` gate on this
-+  sweep. Rows 2/8/16 are close (`166-169 us` for full layerlet), but rows 1 is
-+  still too slow (`211 us` middle, `228 us` full).
-+- XPU graph replay remains a blocker for endpoint promotion: the corrected
-+  rows=2 graph spot-check is exact but replay is about `320-330 us`, slower
-+  than eager replay.
-+
-+Next exact/no-quality-loss performance targets:
-+
-+- Re-test active-offset GEMM with the corrected `_moe_C` binary. It was not
-+  included in the corrected sweep and may help hot-skew paths with many zero
-+  experts.
-+- Attack rows=1 specifically. The single-token decode shape is still the
-+  largest layerlet miss; revisit the opt-in q1/fast-gather code only under the
-+  corrected oracle harness, and keep anything that does not beat the default
-+  gated off.
-+- Find why isolated graph replay is slower than eager. Do not promote endpoint
-+  graph wiring until replay timing is credible or proven irrelevant to the live
-+  graph lane.
-+- Once XPU physical device 3 is recovered, run TP4 accepted-lane quality and
-+  endpoint A/B with full benchmark identity recorded before interpreting any
-+  tok/s result.
-+
-+## 2026-06-18 Addendum 10 - Active Offset, Q1, And Fast Gather Retested
-+
-+Corrected active-offset sweep:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-after-moeC-rebuild-activeoffset-hot-skew-sweep-device0-20260618.json`
-+- Exactness: all enabled paths reported `max_abs_diff = 0.0`.
-+- Active-offset GEMM was not a speed win versus plain offset:
-+
-+| rows | active offset us | plain offset us | middle layerlet us | full layerlet us |
-+|---:|---:|---:|---:|---:|
-+| 1 | 200.102 | 198.386 | 168.792 | 187.122 |
-+| 2 | 200.772 | 199.823 | 167.921 | 163.722 |
-+| 4 | 195.026 | 197.106 | 167.212 | 164.606 |
-+| 8 | 200.824 | 199.621 | 171.210 | 163.241 |
-+| 16 | 201.019 | 197.892 | 167.576 | 160.979 |
-+
-+Decision: keep active-offset as a diagnostic only. It is exact, but not
-+faster enough to promote.
-+
-+Corrected q1/fast-gather retests:
-+
-+- q1 only:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-after-moeC-q1only-hot-skew-rows1-2-device0-20260618.json`
-+  - Exact: `0.0`.
-+  - Rows 1: middle `190.957 us`, full `201.240 us`.
-+  - Rows 2: middle `173.546 us`, full `176.384 us`.
-+  - Decision: rejected for speed.
-+- fast-gather only:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-after-moeC-fastgatheronly-hot-skew-rows1-2-device0-20260618.json`
-+  - Exact: `0.0`.
-+  - Rows 1: middle `162.288 us`, full `172.371 us`.
-+  - Rows 2: middle `168.064 us`, full `158.136 us`.
-+  - Decision: not a default. It gives a rows=2 pass in this noisy microbench,
-+    but it does not solve rows=1 and only applies to single-token gather.
-+- q1 + fast-gather:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-after-moeC-q1-fastgather-hot-skew-rows1-2-device0-20260618.json`
-+  - Exact: `0.0`.
-+  - Rows 1: middle `163.146 us`, full `170.599 us`.
-+  - Rows 2: middle `161.330 us`, full `158.470 us`.
-+  - Decision: do not promote. q1 hurts, and the rows=2 pass does not address
-+    the rows=1 bottleneck.
-+
-+Current next target:
-+
-+- The corrected oracle gates show the shape to attack is rows=1. The fastest
-+  exact rows=1 candidate in the corrected retests is the Python-dispatched
-+  middle-layerlet path around `162-169 us`, while full C++ layerlet is still
-+  slower on rows=1. A useful next patch should reduce full-layerlet rows=1
-+  overhead without changing math, or add a genuinely faster single-token
-+  full-layerlet path.
-+
-+## 2026-06-18 Addendum 11 - Real Rows=1 Scan, Q1/Fast-Gather Rejected Again
-+
-+Stable real-route baseline:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-default-firstdecode-routes-row1-stable-device0-20260618.json`
-+- Same-lane rerun after adding runtime identity and sourcing full oneAPI
-+  `setvars.sh`:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-default-setvars-firstdecode-routes-row1-stable-device0-20260618.json`
-+- Identity: single-device offline replay on device 0, Quark W8A8 INT8 config,
-+  TP4-shaped per-rank tensors, rows=1, captured first-decode routes from
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-firstdecode-route-fixture-routes-20260612ct.jsonl`,
-+  route starts `0:120:5`, 30 measured iterations, 5 warmup iterations,
-+  real-routing oracle enabled, q1 and fast-gather envs unset.
-+- Exactness: all promoted candidates reported `max_abs_diff = 0.0`.
-+
-+Stable real-route rows=1 summary:
-+
-+| path | min us | mean us | median us | p90 us | max us | <=160 us rows |
-+|---|---:|---:|---:|---:|---:|---:|
-+| xpu scratch | 248.525 | 262.639 | 257.973 | 275.888 | 292.490 | 0/24 |
-+| plain offset | 189.216 | 203.241 | 200.009 | 212.507 | 233.532 | 0/24 |
-+| active offset | 189.769 | 204.650 | 202.847 | 213.597 | 226.699 | 0/24 |
-+| middle layerlet | 161.001 | 173.428 | 171.181 | 180.944 | 193.764 | 0/24 |
-+| full layerlet | 157.215 | 169.210 | 166.545 | 177.622 | 188.859 | 2/24 |
-+
-+Decision: the corrected full layerlet is the best current exact MoE replay
-+path, but it is not enough for endpoint promotion. It clears the `160 us` gate
-+on only 2 of 24 real routes and still has a `188.859 us` tail.
-+
-+Same-env confirmation after runtime identity patch:
-+
-+- Default/setvars full layerlet min/mean/median/p90/max:
-+  `158.326 / 169.172 / 164.374 / 182.699 / 205.267 us`, with 5 of 24 rows
-+  under `160 us`.
-+- Route-pack/setvars full layerlet min/mean/median/p90/max:
-+  `156.054 / 170.198 / 167.456 / 175.876 / 207.490 us`, with 3 of 24 rows
-+  under `160 us`.
-+- This confirms the original direction: default remains the safer baseline
-+  despite the route-pack best-case win.
-+
-+Rejected real-route q1 and gather variants:
-+
-+- Fast gather only:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-fastgather-firstdecode-routes-row1-stable-device0-20260618.json`
-+  - Exact: `0.0`.
-+  - Full layerlet min/mean/median/p90/max:
-+    `157.106 / 171.433 / 169.913 / 182.596 / 200.772 us`.
-+  - It improves some routes but worsens others badly. Do not enable globally.
-+- Optimized q1 only:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-q1opt-firstdecode-routes-row1-stable-device0-20260618.json`
-+  - Exact: `0.0`.
-+  - Full layerlet min/mean/median/p90/max:
-+    `159.356 / 171.950 / 167.073 / 190.830 / 199.455 us`.
-+  - This is slower than the stable default mean and tail. Keep q1 gated off.
-+
-+Hot-expert physical packing simulation:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routepack-firstdecode-routes-row1-stable-device0-20260618.json`
-+- This remaps hot logical experts to dense physical IDs. A real model could
-+  preserve quality by permuting expert weights and remapping top-k IDs
-+  together, so this was worth testing.
-+- Exact: `0.0` within the remapped replay.
-+- Full layerlet min/mean/median/p90/max:
-+  `156.054 / 170.198 / 167.456 / 175.876 / 207.490 us`.
-+- It helped routes 95 and 20 by about `25 us` and `21 us`, but hurt routes 80
-+  and 5 by about `39 us` and `31 us`.
-+
-+Decision: physical expert packing is not a safe global speed lever from this
-+fixture. Keep it as an idea for per-layer/per-rank adaptive layouts only if a
-+future trace shows a stable route distribution with a smaller tail.
-+
-+Runtime environment lesson:
-+
-+- In this shell, sourcing only
-+  `/opt/intel/oneapi/compiler/2025.3/env/vars.sh` made `xpu-smi` see all B70s
-+  but made PyTorch report `torch.xpu.device_count() == 0`.
-+- Sourcing `/opt/intel/oneapi/setvars.sh --force` restored PyTorch XPU
-+  visibility (`device_count == 4`), and with `ONEAPI_DEVICE_SELECTOR=level_zero:0`
-+  the replay saw one selected device.
-+- The replay harness now records `runtime_identity`, including device selector
-+  env, q1/fast-gather envs, torch version, selected XPU device names, Python
-+  path, and loaded `vllm_xpu_kernels` extension paths. It also records the
-+  selected expert rows directly in each result.
-+
-+Immediate command-list real-route check:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-immediate-firstdecode-routes-row1-stable-device0-20260618.json`
-+- Environment delta from the default/setvars replay:
-+  `SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS=1` and
-+  `UR_L0_USE_IMMEDIATE_COMMANDLISTS=1`.
-+- Exact: `0.0`.
-+- Full layerlet min/mean/median/p90/max:
-+  `157.265 / 169.618 / 169.510 / 178.733 / 188.032 us`, with 2 of 24 rows
-+  under `160 us`.
-+- Compared with the same-env default/setvars replay
-+  (`158.326 / 169.172 / 164.374 / 182.699 / 205.267 us`), immediate lists
-+  smooth the worst tail but worsen median and do not improve mean.
-+
-+Decision: keep immediate command lists as a possible endpoint stability/tail
-+lever to retest only after TP4 health is restored. It is quality-neutral in
-+offline replay, but it is not a standalone rows=1 MoE win and should not be
-+combined into accepted endpoint manifests without full quality and reliability
-+gates.
-+
-+W8A8 grouped GEMM m8 policy checks:
-+
-+- Code change: exposed `w8a16_policy_m_8` through
-+  `VLLM_XPU_W8A8_GROUPED_GEMM_POLICY=m8`, plus diagnostic shape-specific
-+  overrides:
-+  `VLLM_XPU_W8A8_GROUPED_GEMM_N_LT_K_POLICY` and
-+  `VLLM_XPU_W8A8_GROUPED_GEMM_N_GT_K_POLICY`.
-+- The replay harness now records all three policy envs in `runtime_identity`.
-+- All completed policy runs were exact (`max_abs_diff = 0.0`).
-+
-+Artifacts and results:
-+
-+| policy | artifact | full layerlet min/mean/median/p90/max us | <=160 rows | decision |
-+|---|---|---:|---:|---|
-+| rebuilt default | `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-default-rebuilt-firstdecode-routes-row1-device0-20260618.json` | `154.045 / 163.868 / 159.998 / 175.859 / 203.502` | 12/24 | current rebuilt control |
-+| generic m8 run 1 | `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-m8policy-firstdecode-routes-row1-stable-device0-20260618.json` | `155.153 / 163.253 / 160.339 / 172.203 / 179.175` | 9/24 | promising tail, not repeatable |
-+| generic m8 run 2 | `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-m8policy-repeat-firstdecode-routes-row1-device0-20260618.json` | `154.458 / 170.817 / 170.447 / 178.564 / 195.076` | 2/24 | rejected for repeatability |
-+| generic m8 + immediate | `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-m8-immediate-firstdecode-routes-row1-device0-20260618.json` | `154.731 / 167.267 / 164.970 / 174.000 / 212.484` | 6/24 | rejected |
-+| m8 only when `N<K` | `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-m8-nltk-firstdecode-routes-row1-device0-20260618.json` | `155.290 / 175.271 / 173.277 / 192.108 / 202.766` | 3/24 | rejected |
-+| m8 only when `N>K` | `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-m8-ngtk-firstdecode-routes-row1-device0-20260618.log` | crashed before JSON flush | n/a | rejected, unsafe |
-+
-+Decision: do not promote m8 policy. Generic m8 can reduce a single-run tail,
-+but the improvement is not stable across repeats. GEMM1-only m8 is slower.
-+GEMM2-only m8 segfaulted, although device 0 survived a post-crash XPU smoke
-+test. Keep the m8 code path as a diagnostic only; do not set any m8 policy env
-+in accepted endpoint launchers.
-+
-+Next exact/no-quality-loss work:
-+
-+- Stop spending time on standalone q1, standalone gather, active-offset, and
-+  global expert packing. Also stop spending time on m8 grouped-GEMM policy
-+  variants. All completed variants are exact, but none gives a repeatable
-+  real rows=1 win.
-+- The next useful patch needs to remove a larger boundary inside the rows=1
-+  MoE path: either a persistent/one-dispatch MoE layerlet, a GEMM2+gather
-+  epilogue that preserves the current BF16 weighted accumulation behavior, or a
-+  row1/top-k=8 direct expert path that avoids the generic grouped-GEMM launch
-+  shape without changing W8A8 math.
-+
-+## 2026-06-18 Addendum 5 - Offline EAGLE Acceptance Gate
-+
-+Purpose:
-+
-+- The serial EAGLE k5 synthetic path already proved the endpoint can
-+  structurally clear the `>150 tok/s` target (`181.91 tok/s`) if draft
-+  acceptance is high enough, but current real draft acceptance is too weak.
-+- To avoid slow endpoint iterations, add a cheap offline draft-quality gate
-+  before spending time on vLLM launch/measurement.
-+
-+New script:
-+
-+- `/home/steve/llm-optimizations/scripts/evaluate-qwen36-eagle-draft-offline.py`
-+- It loads a local EAGLE draft checkpoint plus the target model
-+  `embed_tokens`/`lm_head`, reads hidden-state dataset `.pt` files, rolls out
-+  greedy draft proposals, compares token IDs against the recorded target greedy
-+  continuation, and reports:
-+  - mean accepted draft length;
-+  - per-position exact and top-k rates;
-+  - acceptance histogram;
-+  - concrete mismatch examples.
-+
-+Offline acceptance results:
-+
-+| checkpoint | eval set | artifact | mean accepted | decision |
-+|---|---|---|---:|---|
-+| token-heavy EAGLE2 | capped corpus2+pos | `data/qwen36-eagle2-tokenheavy-offline-accept-capped-20260618.json` | `1.640625` | baseline |
-+| rollout5 EAGLE2 | capped corpus2+pos | `data/qwen36-eagle2-rollout5-offline-accept-capped-20260618.json` | `1.9296875` | best offline signal |
-+| token-focused rollout5 | capped corpus2+pos | `data/qwen36-eagle2-tokenfocused-rollout5-offline-accept-capped-20260618i.json` | `1.828125` | rejected |
-+| token-heavy EAGLE2 | smoke held-out | `data/qwen36-eagle2-tokenheavy-offline-accept-smoke-20260618.json` | `1.5689655` | baseline |
-+| rollout5 EAGLE2 | smoke held-out | `data/qwen36-eagle2-rollout5-offline-accept-smoke-20260618.json` | `1.7413793` | best offline signal |
-+| token-focused rollout5 | smoke held-out | `data/qwen36-eagle2-tokenfocused-rollout5-offline-accept-smoke-20260618i.json` | `1.6724138` | rejected |
-+
-+Rollout5 details:
-+
-+- Checkpoint:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle2-corpus2-tokenheavy-rollout5-trained-20260618h`
-+- Capped corpus2+pos conditional exact by step:
-+  `0.90625, 0.6121, 0.4225, 0.5667, 0.7647`.
-+- Smoke conditional exact by step is lower but still better than token-heavy.
-+- The earlier endpoint rollout5 k5 run was slower/worse than expected, so this
-+  offline score is not an endpoint speed claim. Treat it as a draft-training
-+  selector only.
-+
-+Rejected token-focused fine-tune:
-+
-+- Checkpoint:
-+  `/home/steve/llm-optimizations/data/qwen36-eagle2-tokenfocused-rollout5-trained-20260618i`
-+- Training command initialized from token-heavy and used
-+  `--rollout-steps 5 --feature-loss-weight 0.25 --token-loss-weight 1.0`
-+  for 4 epochs.
-+- Final training metrics regressed (`top1 = 0.3156`, `top3 = 0.4508`,
-+  `token_loss = 2.0299`), and offline acceptance landed below rollout5 on both
-+  capped and smoke gates.
-+- Decision: do not promote this checkpoint; keep the run as evidence that
-+  simply increasing token-loss weight is not enough.
-+
-+EAGLE data coverage status:
-+
-+- Existing usable datasets:
-+  - `data/qwen36-eagle-hidden-dataset-corpus-tp2-20260618a` (`48` samples)
-+  - `data/qwen36-eagle-hidden-dataset-corpus2-tp2-20260618a` (`254` samples)
-+  - `data/qwen36-eagle-hidden-dataset-pos-tp2-20260618a` (`54` samples)
-+  - `data/qwen36-eagle-hidden-dataset-smoke-tp2-20260618e` (`1` sample)
-+- The collector previously had only a narrow prompt mix. It now includes
-+  additional families in
-+  `/home/steve/llm-optimizations/scripts/collect-qwen36-eagle-hidden-corpus.py`:
-+  `debug-log`, `python-patch`, `sql-analysis`, `shell-runbook`,
-+  `api-contract`, `longform-summary`, `test-plan`, `algorithm`,
-+  `comparison`, and `user-support`.
-+
-+Next EAGLE work:
-+
-+- Collect a larger TP2 hidden-state dump on healthy devices only; do not use
-+  TP4 until the XPU/XCCL health preflight passes.
-+- Build an expanded dataset with the existing dump builder, train a rollout
-+  EAGLE2 checkpoint, and accept it for endpoint testing only if offline
-+  acceptance clearly beats rollout5 on both the capped corpus and smoke gates.
-+- If offline acceptance reaches the needed band, run endpoint k5 with the
-+  accepted identity and full quality/reliability gates.
-+
-+## 2026-06-18 Addendum 6 - m8 Guard
-+
-+The shape-specific diagnostic `VLLM_XPU_W8A8_GROUPED_GEMM_N_GT_K_POLICY=m8`
-+previously segfaulted before JSON flush. The grouped-GEMM policy override now
-+ignores `m8` when `gemm_n > gemm_k`, both for generic and `N>K` overrides:
-+
-+- `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp`
-+
-+This guard is not a performance win and does not change the accepted endpoint
-+identity. It exists to keep future diagnostic sweeps from selecting the unsafe
-+GEMM2 shape. Rebuild/stage `_xpu_C` after this edit before running any policy
-+sweeps that import `vllm_xpu_kernels._xpu_C`.
-+
-+## 2026-06-18 Addendum 7 - Expanded EAGLE Data Collection And Rejected Fine-Tunes
-+
-+Expanded TP2 hidden-state export:
-+
-+- Failed attempt:
-+  `data/qwen36-eagle-hidden-dump-expanded-tp2-20260618j.log` failed during
-+  sampler profiling because Triton loaded
-+  `/opt/intel/oneapi/compiler/2026.0/lib/libsycl.so.9`, which mismatched the
-+  active UR loader:
-+  `undefined symbol: urDeviceWaitExp, version LIBUR_LOADER_0.12`.
-+- Fix for this environment:
-+  source oneAPI normally, then pin
-+  `LD_LIBRARY_PATH=/opt/intel/oneapi/compiler/2025.3/lib:$LD_LIBRARY_PATH`
-+  and `PATH=/opt/intel/oneapi/compiler/2025.3/bin:$PATH`. A direct Triton
-+  target smoke passed with that ordering and still saw `torch.xpu.device_count()
-+  == 4`.
-+- Successful run:
-+  `data/qwen36-eagle-hidden-dump-expanded-tp2-20260618k.log`
-+  on TP2 cards `0,1`, graph-none, no async, Quark W8A8 INT8 target, 32k max
-+  model length, `GPU_MEMORY_UTILIZATION=0.82`,
-+  `MAX_NUM_BATCHED_TOKENS=1024`, `MAX_NUM_SEQS=8`, and hidden dump envs set.
-+- Request manifest:
-+  `data/qwen36-eagle-hidden-expanded-tp2-20260618k-requests.json`
-+  with `64` prompts over the expanded prompt families.
-+- Dataset summary:
-+  `data/qwen36-eagle-hidden-dataset-expanded-tp2-20260618k-summary.json`
-+  produced `6144` rows, `64` saved samples, `6080` continuity matches,
-+  `0` continuity breaks, `0` position breaks, and `0` bad files.
-+
-+Expanded-data offline acceptance controls:
-+
-+| checkpoint | expanded mean accepted | decision |
-+|---|---:|---|
-+| token-heavy control | `1.046875` | weak |
-+| rollout5 control | `1.132812` | current control |
-+
-+The new expanded set is substantially harder than the old capped corpus2+pos
-+gate where rollout5 gets `1.929688`. This explains why endpoint acceptance is
-+still far below the synthetic k5 ceiling.
-+
-+Fine-tune attempts against expanded data:
-+
-+| checkpoint | capped corpus2+pos | smoke | expanded | decision |
-+|---|---:|---:|---:|---|
-+| rollout5 control | `1.929688` | `1.741379` | `1.132812` | keep as best current control |
-+| expanded low-LR mixed | `1.914062` | `1.741379` | `1.125000` | reject |
-+| expanded-only | `1.875000` | not run | `1.226562` | reject; improves expanded but hurts established gate |
-+| expanded oversample4 | `1.882812` | `1.793103` | `1.156250` | reject; improves smoke/expanded slightly but hurts capped gate |
-+
-+Artifacts:
-+
-+- Low-LR mixed checkpoint:
-+  `data/qwen36-eagle2-rollout5-expanded-lowlr-trained-20260618k`.
-+- Expanded-only checkpoint:
-+  `data/qwen36-eagle2-rollout5-expanded-only-trained-20260618l`.
-+- Oversample4 checkpoint:
-+  `data/qwen36-eagle2-rollout5-expanded-oversample4-trained-20260618m`.
-+- Corresponding offline acceptance JSON files:
-+  `data/qwen36-eagle2-rollout5-expanded-*-offline-accept-*.json`.
-+
-+Decision:
-+
-+- Do not promote any expanded-data fine-tune to endpoint testing.
-+- The current 2-layer draft can partially learn the expanded data, but not
-+  enough, and the improvements trade off against the established capped gate.
-+- Next draft-quality work should change the draft/training strategy instead of
-+  just reweighting this 2-layer rollout checkpoint: larger/deeper draft, better
-+  train/validation split with held-out expanded prompts, scheduled rollout
-+  targets, or richer hidden features. Keep using the offline acceptance gate
-+  before any endpoint run.
-+
-+## 2026-06-18 Addendum 8 - Deeper EAGLE Draft Attempts
-+
-+Offline eval identity correction:
-+
-+- `start_stride` is part of the offline EAGLE acceptance identity.
-+- The historical capped control used `start_stride=4`; the historical smoke
-+  control used `start_stride=1`; the expanded control used `start_stride=4`.
-+- A default `start_stride=1` capped rerun of the same 2-layer rollout5 control
-+  measured only `1.273438` mean accepted, while the historical stride-4 capped
-+  identity measures `1.929688`. Do not compare offline acceptance artifacts
-+  without matching `dataset_dir`, `max_steps`, `max_starts`, `start_stride`,
-+  `dtype`, draft checkpoint, target checkpoint, and evaluator script revision.
-+
-+Trainer changes:
-+
-+- Added deeper-draft initialization controls in
-+  `scripts/train-qwen36-eagle1-draft.py`:
-+  - `--repeat-last-init-layer`: copy the last checkpoint layer into added
-+    layers. This was tested and rejected.
-+  - `--zero-extra-init-layer`: zero added layer matrices. This preserves output
-+    but is mostly dead for training because zeroing every matrix removes useful
-+    gradients through the added layer.
-+  - `--residual-extra-init-layer`: copy the last checkpoint layer into added
-+    layers, then zero only `self_attn.o_proj.weight` and
-+    `mlp.down_proj.weight`. This starts as a residual no-op while preserving
-+    trainable q/k/v and gate/up features.
-+  - `--freeze-init-base-layers`: freeze `fc` and checkpoint-loaded layers so
-+    only added residual layers train.
-+- A zero-step 3-layer residual-extra checkpoint exactly preserved the capped
-+  stride-4 control (`1.929688`) and froze the two loaded base layers, so this
-+  is the correct initializer for future deeper-draft work.
-+
-+Results:
-+
-+| checkpoint | capped stride-4 | smoke stride-1 | expanded stride-4 | decision |
-+|---|---:|---:|---:|---|
-+| 2-layer rollout5 control | `1.929688` | `1.741379` | `1.132812` | current control |
-+| 3-layer repeat-init expanded2 | `1.921875` | `1.793103` | `1.132812` | reject; capped regression |
-+| 3-layer repeat-init old-only | `1.898438` | `1.793103` | `1.117188` | reject; capped regression |
-+| 3-layer residual-init expanded2, base frozen | `1.890625` | `1.758621` | `1.125000` | reject; capped and expanded regression |
-+| 3-layer residual-init old-only, base frozen | `1.929688` | `1.741379` | `1.109375` | reject; neutral on accepted gates, worse expanded |
-+
-+Decision:
-+
-+- Do not promote any 3-layer EAGLE checkpoint from this batch to endpoint
-+  testing.
-+- Deeper capacity is not enough under the current objective. Repeat-init
-+  changes the function and damages the accepted gate. Residual-init is the
-+  right way to add trainable depth, but training only a third residual layer
-+  did not improve acceptance.
-+- Future EAGLE work should change the objective/data loop before further
-+  endpoint tests: use explicit train/validation splits, checkpoint selection by
-+  offline acceptance instead of final batch metrics, scheduled rollout training,
-+  and possibly token-margin or top-k-distillation losses. Any future offline
-+  report must record `start_stride`.
-+- Since EAGLE acceptance remains far below the synthetic k5 ceiling, the next
-+  no-quality-loss performance branch should return to exact MoE work unless a
-+  stronger draft-training objective is implemented.
-+
-+Checkpoint-selection follow-up:
-+
-+- Added `--checkpoint-every` to `scripts/train-qwen36-eagle1-draft.py` so
-+  intermediate draft checkpoints can be selected by offline acceptance instead
-+  of final batch metrics.
-+- Reran the residual-extra old-only setup with checkpoints every 50 steps:
-+  `data/qwen36-eagle3-rollout5-residualextra-oldonly-ckpt-trained-20260618s`.
-+- Capped stride-4 sweep artifact:
-+  `data/qwen36-eagle3-residualextra-oldonly-checkpoint-capped-sweep-20260618s.jsonl`.
-+- Best checkpoints were `step-000050`, `step-000100`, `step-000500`, and
-+  `final`, all tied the control at `1.929688`. No checkpoint exceeded the
-+  accepted 2-layer rollout5 control.
-+- Decision: checkpoint selection is useful infrastructure, but this residual
-+  old-domain objective still produces no EAGLE acceptance win.
-+
-+## 2026-06-19 Addendum - Direct GEMM2+Gather Epilogue Rejected
-+
-+User asked to pursue exact MoE optimization first, with GEMM2+gather epilogue
-+fusion before escalating to a persistent one-dispatch layerlet.
-+
-+Implementation:
-+
-+- Added an opt-in diagnostic path in
-+  `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`.
-+- Env flag:
-+  `VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER=1`.
-+- The path is only used for single-token, top-k=8, BF16/FP16 output shapes.
-+- It preserves the current exact math boundary by:
-+  - keeping prologue/quant1, GEMM1, and activation/quant2 unchanged;
-+  - computing each selected GEMM2 expert row directly from W8A8 int32 sums;
-+  - applying the same activation scale and per-expert output-channel weight
-+    scale;
-+  - casting each GEMM2 row value to BF16/FP16 before weighted gather, matching
-+    the accepted materialized GEMM2 row semantics.
-+- Added the flag to route replay runtime identity in
-+  `/home/steve/llm-optimizations/scripts/bench-qwen36-int8-moe-kernels.py`.
-+- Rebuilt and staged:
-+  `/home/steve/src/vllm-xpu-kernels/build/xpu-c-only-2025/_xpu_C.abi3.so`
-+  copied to
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_xpu_C.abi3.so`.
-+
-+Smoke replay:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-directgemm2gather-route0-smoke-device0-20260619.json`.
-+- Identity:
-+  `ONEAPI_DEVICE_SELECTOR=level_zero:0`, `ZE_AFFINITY_MASK=0`,
-+  route fixture
-+  `qwen36-quark-int8-tp4-firstdecode-route-fixture-routes-20260612ct.jsonl`,
-+  rows=1, route start 0, direct flag enabled.
-+- Exactness:
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0` and
-+  `full_layerlet_vs_rows_oracle_max_abs_diff = 0.0`.
-+- Timing:
-+  direct full layerlet `200.595 us`; same-run middle layerlet `169.842 us`.
-+
-+Multi-route replay:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-directgemm2gather-routes7-device0-20260619.json`.
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-directgemm2gather-routes7-device0-20260619.md`.
-+- Routes:
-+  `0,40,80,85,95,100,115`.
-+- Exactness:
-+  all rows `max_abs_diff = 0.0` versus both `xpu_fused_moe` and rows-oracle.
-+- Direct full-layerlet timing:
-+  min/mean/max `168.969 / 190.527 / 200.715 us`, `0/7` rows under
-+  `160 us`.
-+- Same-run middle-layerlet timing:
-+  min/mean/max `171.844 / 198.937 / 228.868 us`, `0/7` rows under
-+  `160 us`.
-+
-+Decision:
-+
-+- Reject the simple direct GEMM2+gather replacement for speed.
-+- It proves the direct math can be exact, but it gives up the optimized DPAS
-+  grouped-GEMM execution and is slower despite removing the separate gather
-+  launch.
-+- Do not wire this path into the endpoint or benchmark it as a candidate.
-+- Keep it as a disabled diagnostic only unless we later need a correctness
-+  oracle for a true fused epilogue.
-+
-+Next exact MoE work:
-+
-+- Stop small wrapper/fast-gather/q1/policy knobs.
-+- The next patch should be a true larger boundary:
-+  1. persistent/one-dispatch W8A8 MoE layerlet that keeps descriptors,
-+     expert pointers, route buffers, scratch, and output buffers resident; or
-+  2. a real grouped-GEMM epilogue modification that accumulates weighted GEMM2
-+     output inside the DPAS GEMM store path while preserving BF16 row rounding.
-+- Gate remains offline first: route replay exactness `max_abs_diff = 0.0`,
-+  repeated timing, target below the current `160-180 us` layerlet band before
-+  any endpoint work.
-+
-+## 2026-06-19 Addendum - DPAS TopK8 GEMM2+Gather Prototype Rejected
-+
-+Follow-up to the direct GEMM2+gather diagnostic above. The direct scalar
-+kernel was exact but slow because it abandoned the optimized DPAS grouped-GEMM
-+path. I prototyped a narrower DPAS-backed top-k8 GEMM2+gather path to test the
-+best plausible version of "GEMM2 + gather epilogue first" before escalating to
-+the persistent layerlet.
-+
-+Implementation:
-+
-+- Added a new opt-in XE2 diagnostic path:
-+  `VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER=1`.
-+- Added follow-up column tile selectors for this diagnostic path:
-+  `VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE=32` and
-+  `VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE=16`. Unset/default remains the
-+  original N64 policy.
-+- Main code paths touched:
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/gemm_xe2_policy.hpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/grouped_gemm_interface.h`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`
-+  - `/home/steve/llm-optimizations/scripts/bench-qwen36-int8-moe-kernels.py`
-+- The kernel shape is one workgroup per output column tile. Each workgroup
-+  loops the 8 routed experts in top-k order, uses DPAS for each selected expert
-+  row, casts each expert row value to BF16/FP16 before route weighting, then
-+  stores the final accumulated token output.
-+- This avoids atomics and preserves the accepted deterministic gather order.
-+- The path remains disabled by default and is not wired into endpoint launch
-+  identity.
-+
-+Build/import:
-+
-+- Build command:
-+  `cmake --build /home/steve/src/vllm-xpu-kernels/build/xpu-c-only-2025 -j 8`.
-+- Build completed successfully.
-+- Rebuilt modules copied into:
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_xpu_C.abi3.so` and
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_moe_C.abi3.so`.
-+- Import check confirmed `torch.ops._xpu_C.qwen36_moe_w8a8_full_layerlet` is
-+  available.
-+
-+Smoke replay:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-route0-smoke-device0-20260619.json`.
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-route0-smoke-device0-20260619.md`.
-+- Exactness:
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+- Timing:
-+  full layerlet `176.817 us`, above the `160 us` promotion gate.
-+
-+Multi-route replay:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-routes7-device0-20260619.json`.
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-routes7-device0-20260619.md`.
-+- Identity:
-+  `ZE_AFFINITY_MASK=0`, `VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER=1`,
-+  route fixture
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`,
-+  layer regex `layers[.]9[.]`, rows=1, route starts
-+  `0,40,80,85,95,100,115`, warmup=20, iterations=100.
-+- Exactness:
-+  all 7 rows have `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+- Timing:
-+  full-layerlet min/mean/max `161.554 / 172.244 / 178.651 us`.
-+- Gate:
-+  `0/7` rows under `160 us`;
-+  status `exact_nonreference_candidates_exist_but_gate_not_met`.
-+
-+N-tile replay follow-up:
-+
-+- Purpose:
-+  test whether the DPAS prototype was underparallelized by the default N64
-+  output tile.
-+- N32 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-ntile32-routes7-device0-20260619.json`.
-+- N32 markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-ntile32-routes7-device0-20260619.md`.
-+- N32 identity adds:
-+  `VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE=32`.
-+- N32 exactness:
-+  all 7 rows have `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+- N32 timing:
-+  full-layerlet min/mean/median/p90/max
-+  `170.550 / 176.388 / 173.695 / 191.394 / 189.810 us`; `0/7` rows under
-+  `160 us`.
-+- N16 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-ntile16-routes7-device0-20260619.json`.
-+- N16 markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-dpasgemm2gather-ntile16-routes7-device0-20260619.md`.
-+- N16 identity adds:
-+  `VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE=16`.
-+- N16 exactness:
-+  all 7 rows have `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+- N16 timing:
-+  full-layerlet min/mean/median/p90/max
-+  `164.743 / 182.092 / 177.334 / 214.518 / 211.275 us`; `0/7` rows under
-+  `160 us`.
-+
-+Decision:
-+
-+- Reject the DPAS top-k8 GEMM2+gather prototype as a speed candidate.
-+- It is exact and improves on the scalar direct diagnostic in the default N64
-+  form, but it still does not beat the existing full-layerlet enough to justify
-+  endpoint integration.
-+- N32 and N16 remain exact but are slower, so changing the column tile is not
-+  the missing lever.
-+- Likely reason: one-workgroup-per-column-tile preserves exact order but reduces
-+  useful parallelism across the 8 experts; the saved gather launch/memory
-+  traffic does not compensate.
-+- Keep the prototype disabled and recorded as an offline diagnostic. Do not
-+  include it in accepted endpoint benchmarks.
-+
-+Updated next move:
-+
-+- The GEMM2+gather epilogue branch has now been tested in both simple scalar
-+  and DPAS-backed deterministic forms. Both preserve quality but miss speed.
-+- Escalate to the larger exact boundary: persistent/one-dispatch W8A8 MoE
-+  layerlet or an equivalent deterministic kernel that keeps the existing DPAS
-+  parallelism while reducing launch/host/descriptor overhead.
-+- Any next candidate must still pass route replay exactness at
-+  `max_abs_diff = 0.0` before endpoint or quality-gate work.
-+
-+## 2026-06-19 Addendum - Workspace Atomic Reuse Rejected
-+
-+After rejecting GEMM2+gather epilogue variants, I tested one smaller
-+fixed-overhead cut before escalating to a true persistent layerlet: remove the
-+tiny per-GEMM `atomic_buffer = at::empty({1}, int32)` allocation inside the
-+grouped GEMM offsets launcher when called from the full layerlet.
-+
-+Implementation:
-+
-+- Added an opt-in diagnostic flag:
-+  `VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC=1`.
-+- Added internal C++ wrappers to pass a raw `int*` atomic buffer into the XE2
-+  W8A8 INT8 offsets grouped GEMM path:
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/grouped_gemm_interface.h`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`
-+- The full layerlet reuses the first `int` slot of the existing uint8 prologue
-+  workspace after prologue/quant1 completes. This keeps the current optimized
-+  DPAS GEMM kernels and output order unchanged.
-+- The path is disabled by default and was not wired into endpoint launches.
-+
-+Build/import:
-+
-+- Targeted build:
-+  `cmake --build /home/steve/src/vllm-xpu-kernels/build/xpu-c-only-2025 --target _xpu_C -j 4`.
-+- Build completed successfully after the heavy XE2 grouped-GEMM translation
-+  unit compiled.
-+- Rebuilt modules copied into:
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_xpu_C.abi3.so` and
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_moe_C.abi3.so`.
-+- Import check confirmed `torch.ops._xpu_C.qwen36_moe_w8a8_full_layerlet` is
-+  available.
-+
-+Route replay:
-+
-+- Candidate artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-workspaceatomic-routes7-device0-20260619.json`.
-+- Candidate markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-workspaceatomic-routes7-device0-20260619.md`.
-+- Adjacent control artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-workspaceatomic-control-routes7-device0-20260619.json`.
-+- Adjacent control markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-workspaceatomic-control-routes7-device0-20260619.md`.
-+- Shared identity:
-+  `ZE_AFFINITY_MASK=0`, route fixture
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`,
-+  layer regex `layers[.]9[.]`, rows=1, route starts
-+  `0,40,80,85,95,100,115`, warmup=20, iterations=100.
-+- Candidate adds:
-+  `VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC=1`.
-+- Exactness:
-+  candidate and adjacent control both have
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0` on all 7 rows.
-+- Candidate full-layerlet min/mean/median/p90/max:
-+  `168.110 / 174.518 / 173.856 / 183.004 / 182.163 us`; `0/7` rows under
-+  `160 us`.
-+- Adjacent control full-layerlet min/mean/median/p90/max:
-+  `161.697 / 166.446 / 166.044 / 177.249 / 175.779 us`; `0/7` rows under
-+  `160 us`.
-+
-+Decision:
-+
-+- Reject workspace atomic reuse as a speed candidate.
-+- It is exact, but adjacent control is materially faster in this replay.
-+- This confirms that the next serious work should not spend more time on tiny
-+  allocation cleanup inside the current staged layerlet. Move to the larger
-+  persistent/one-dispatch W8A8 MoE boundary, or an equivalent deterministic
-+  kernel that keeps route state, descriptors, scratch, and DPAS work resident.
-+
-+## 2026-06-19 Addendum - Route-Known GEMM1 Diagnostic Rejected
-+
-+After the GEMM2+gather and workspace-atomic branches missed the promotion gate,
-+I tested the symmetric GEMM1-side question: whether the c1/top-k8 route-known
-+shape can bypass the generic grouped-GEMM scheduler for GEMM1 and directly
-+launch one DPAS workgroup family per routed expert row.
-+
-+Implementation:
-+
-+- Added a disabled-by-default diagnostic flag:
-+  `VLLM_XPU_MOE_W8A8_ROUTE_GEMM1=1`.
-+- Added tile selector:
-+  `VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE=8|32`; unset/default uses M16.
-+- The diagnostic path is gated to the exact single-token Qwen 3.6 MoE shape:
-+  top-k 8, one token, contiguous route rows, grouped GEMM1 output layout, and
-+  the existing W8A8 INT8 weight/scales format.
-+- Main code paths touched:
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/grouped_gemm/grouped_gemm_interface.h`
-+  - `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`
-+  - `/home/steve/llm-optimizations/scripts/bench-qwen36-int8-moe-kernels.py`
-+- The full layerlet falls back to the accepted grouped-GEMM path unless the
-+  diagnostic flag and shape gate both pass.
-+- The path remains offline-only and is not an endpoint candidate.
-+
-+Build/import:
-+
-+- Targeted build:
-+  `cmake --build /home/steve/src/vllm-xpu-kernels/build/xpu-c-only-2025 --target _xpu_C -j 4`.
-+- Build completed successfully.
-+- Rebuilt extension copied into:
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_xpu_C.abi3.so`.
-+- Import check confirmed `torch.ops._xpu_C.qwen36_moe_w8a8_full_layerlet` is
-+  available.
-+
-+Route replay:
-+
-+- Shared identity:
-+  `ZE_AFFINITY_MASK=0`, route fixture
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`,
-+  layer regex `layers[.]9[.]`, rows=1, route starts
-+  `0,40,80,85,95,100,115`, warmup=20, iterations=100,
-+  target `160 us`.
-+- Adjacent control artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-control-routes7-device0-20260619.json`.
-+- Adjacent control markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-control-routes7-device0-20260619.md`.
-+- M16 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-m16-routes7-device0-20260619.json`.
-+- M16 markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-m16-routes7-device0-20260619.md`.
-+- M8 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-m8-routes7-device0-20260619.json`.
-+- M8 markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-m8-routes7-device0-20260619.md`.
-+- M32 artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-m32-routes7-device0-20260619.json`.
-+- M32 markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-routegemm1-m32-routes7-device0-20260619.md`.
-+- Exactness:
-+  control, M16, M8, and M32 all have
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0` on all 7 rows.
-+
-+Timing:
-+
-+- Adjacent control route/full_us:
-+  `0:162.311`, `40:166.755`, `80:170.076`, `85:166.611`,
-+  `95:167.100`, `100:165.555`, `115:161.335`.
-+- Adjacent control min/mean/median/p90/max:
-+  `161.335 / 165.677 / 166.611 / 170.671 / 170.076 us`; `0/7` rows under
-+  `160 us`.
-+- M16 route/full_us:
-+  `0:173.424`, `40:167.312`, `80:162.484`, `85:163.872`,
-+  `95:163.861`, `100:164.664`, `115:161.763`.
-+- M16 min/mean/median/p90/max:
-+  `161.763 / 165.340 / 163.872 / 174.647 / 173.424 us`; `0/7` rows under
-+  `160 us`.
-+- M8 min/mean/median/p90/max:
-+  `167.183 / 176.882 / 177.742 / 190.124 / 188.642 us`; `0/7` rows under
-+  `160 us`.
-+- M32 min/mean/median/p90/max:
-+  `162.336 / 175.938 / 171.121 / 200.497 / 198.761 us`; `0/7` rows under
-+  `160 us`.
-+
-+Decision:
-+
-+- Reject route-known GEMM1 as a speed candidate.
-+- M16 is exact and marginally lower mean than this adjacent control, but the
-+  improvement is too small, the worst row regresses, and no row passes the
-+  `160 us` target.
-+- M8 and M32 are exact but clearly slower.
-+- This result closes another small-wrapper branch. The missing speed is not in
-+  isolated GEMM1 wrapper selection. The next serious branch remains a true
-+  larger exact MoE boundary: one-dispatch/resident layerlet, fused activation
-+  plus GEMM2, or an equivalent deterministic DPAS pipeline that removes launch
-+  and descriptor overhead without changing output order or BF16 accumulation.
-+
-+## 2026-06-19 Addendum - TP4 Health Still Blocked; Route-Class AOT Not Broad Enough
-+
-+After closing route-known GEMM1, I refreshed the two decision gates that decide
-+whether to keep working TP4 endpoint timing or route-class-specific kernels.
-+
-+TP4 XPU/XCCL health:
-+
-+- TP4 health log:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-tp4-20260619-routegemm1-followup.log`.
-+- Result:
-+  physical devices 0, 1, and 2 pass the single-device XPU smoke.
-+- Physical device 3 fails standalone allocation:
-+  `RuntimeError: level_zero backend failed with error: 40 (UR_RESULT_ERROR_OUT_OF_RESOURCES)`.
-+- XCCL TP4 then fails at rank 3 in `dist.barrier(...)` with the same
-+  Level Zero out-of-resources error.
-+- `xpu-smi ps` showed no long-running vLLM/Python model workers holding VRAM;
-+  only transient `xpu-smi` processes appeared.
-+- `xpu-smi diag -d 3 -l 1 -j` aborts with
-+  `terminate called without an active exception`.
-+- `xpu-smi config -d 3 --reset` is available but failed as the current user.
-+  Noninteractive sudo is not available, and `/sys/bus/pci/devices/0000:47:00.0/reset`
-+  is root-only.
-+- Healthy subset log:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-devices012-20260619-routegemm1-followup.log`.
-+- Devices 0, 1, and 2 pass single-device XPU smoke and XCCL all-reduce.
-+
-+Decision:
-+
-+- Do not trust TP4 endpoint results until device 3 is reset externally or after
-+  reboot and the TP4 preflight passes.
-+- The accepted launcher already has the correct fail-closed guard:
-+  `QWEN36_XPU_PREFLIGHT=auto` runs
-+  `/home/steve/llm-optimizations/scripts/check-qwen36-xpu-xccl-health.sh` for
-+  `TP_SIZE >= 4` and refuses to start if the health gate fails.
-+- While device 3 is wedged, exact offline kernel replay on device 0 is still
-+  useful, and endpoint experiments should use only healthy subsets or be marked
-+  blocked for TP4.
-+
-+Route-class AOT/cache refresh:
-+
-+- Route-class AOT JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-routeclass-aot-routecapture6-20260619.json`.
-+- Route-class AOT markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-routeclass-aot-routecapture6-20260619.md`.
-+- Route signature cache JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-route-signature-cache-routecapture6-20260619.json`.
-+- Route signature cache markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-route-signature-cache-routecapture6-20260619.md`.
-+- Routecapture6 has 285 records across 3 layers, and all 285 ordered top-k
-+  route classes are unique in this sample.
-+- Status:
-+  `needs_more_route_windows_before_aot_commit`.
-+- Coverage is weak for exact route-class kernels:
-+  top 32 classes per layer cover only `0.337` of the layer records, and every
-+  top-k class count is 1 in this fixture.
-+
-+Decision:
-+
-+- Do not spend the next implementation cycle on exact ordered top-k route-class
-+  AOT kernels from this fixture. The observed route reuse is too low.
-+- A broad speed win still needs a generic one-dispatch/resident MoE layerlet,
-+  a lower-latency TP/collective layout after hardware health is fixed, or a
-+  token-verified speculation path with exact verifier parity.
-+
-+## 2026-06-19 Addendum - Full Layerlet Graph Replay Rejected
-+
-+I tested whether graph replay of the current exact full MoE layerlet removes
-+enough launch/dispatch overhead to make the existing boundary worth promoting.
-+
-+Artifacts:
-+
-+- JSON:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-graphreplay-control-routes7-device0-20260619.json`.
-+- Markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-graphreplay-control-routes7-device0-20260619.md`.
-+
-+Run identity:
-+
-+- Device-local offline replay, `ZE_AFFINITY_MASK=0`.
-+- `rows=1`, `warmup=20`, `iterations=80`.
-+- Route source:
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`.
-+- Layer regex `layers[.]9[.]`.
-+- Route starts `0,40,80,85,95,100,115`.
-+- Current exact full layerlet, no route-GEMM1 env enabled.
-+
-+Normal full layerlet timing:
-+
-+- Route/full_us:
-+  `0:163.709`, `40:170.123`, `80:164.201`, `85:161.504`,
-+  `95:167.763`, `100:167.834`, `115:167.326`.
-+- Min/mean/median/max:
-+  `161.504 / 166.066 / 167.326 / 170.123 us`.
-+- Exactness:
-+  all rows have `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+
-+Graph replay timing:
-+
-+- `full_layerlet` graph replay route/us:
-+  `0:181.851`, `40:195.768`, `80:179.414`, `85:179.286`,
-+  `95:186.839`, `100:181.281`, `115:177.510`.
-+- Min/mean/median/max:
-+  `177.510 / 183.136 / 181.281 / 195.768 us`.
-+- Other graph replay boundaries were also slower or unstable in this fixture:
-+  `xpu_fused_moe_with_scratch` mean `313.858 us`,
-+  `preallocated_staged` mean `253.763 us`, and
-+  `fused_prologue_staged` mean `229.347 us`.
-+
-+Decision:
-+
-+- Reject graph replay of the current full layerlet as a speed candidate.
-+- The current full layerlet is exact but remains in the `~161-170 us` route band,
-+  while graph replay makes this fixture slower rather than faster.
-+- The next exact/no-quality-loss work should not be another wrapper replay of
-+  the same boundary. It should either reshape the MoE compute boundary itself
-+  with a resident one-dispatch layerlet, repair speculation verifier parity to
-+  create verified multi-token work, or use a healthy-card endpoint layout that
-+  reduces TP/collective latency without changing outputs.
-+
-+## 2026-06-19 Addendum - q1 + Route-GEMM1 Combo Is Exact But Unstable
-+
-+Before starting a larger rewrite, I checked whether already-rejected exact
-+subpaths stack into a stable win. The only interesting combo was
-+`VLLM_XPU_MOE_W8A8_FUSED_Q1=1` plus
-+`VLLM_XPU_MOE_W8A8_ROUTE_GEMM1=1`.
-+
-+Initial combo sweep:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-combo-q1-routegemm1-routes7-device0-20260619.json`.
-+- Route/full_us:
-+  `0:158.337`, `40:158.479`, `80:171.398`, `85:157.696`,
-+  `95:157.323`, `100:157.864`, `115:157.953`.
-+- Min/mean/median/max:
-+  `157.323 / 159.864 / 157.953 / 171.398 us`.
-+- Exactness:
-+  all rows have `full_layerlet_vs_xpu_fused_moe_max_abs_diff = 0.0`.
-+
-+Repeat gate:
-+
-+- Adjacent control:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-control-repeat100-a-routes7-device0-20260619.json`.
-+- q1 + route-GEMM1 repeat A:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-q1-routegemm1-repeat100-a-routes7-device0-20260619.json`.
-+- q1 + route-GEMM1 repeat B:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-q1-routegemm1-repeat100-b-routes7-device0-20260619.json`.
-+- q1 + route-GEMM1 M8:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-q1-routegemm1-repeat100-m8-routes7-device0-20260619.json`.
-+- q1 + route-GEMM1 M32:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-q1-routegemm1-repeat100-m32-routes7-device0-20260619.json`.
-+
-+Repeat timing:
-+
-+- Control min/mean/median/max:
-+  `162.568 / 169.427 / 167.591 / 177.143 us`; `0/7` rows under `160 us`.
-+- q1 + route-GEMM1 repeat A:
-+  `158.042 / 168.391 / 164.461 / 187.160 us`; `3/7` rows under `160 us`.
-+- q1 + route-GEMM1 repeat B:
-+  `158.862 / 170.901 / 167.939 / 186.982 us`; `1/7` rows under `160 us`.
-+- q1 + route-GEMM1 M8:
-+  `165.230 / 177.547 / 169.780 / 205.600 us`; `0/7` rows under `160 us`.
-+- q1 + route-GEMM1 M32:
-+  `165.580 / 174.773 / 177.906 / 185.706 us`; `0/7` rows under `160 us`.
-+
-+Decision:
-+
-+- Reject q1 + route-GEMM1 as an endpoint promotion candidate for now.
-+- It is exact, and the first sweep showed it can hit the target band, but the
-+  repeated route distribution is not stable enough and the mean does not
-+  reliably beat adjacent control.
-+- M8 and M32 route-GEMM1 tiles are clearly worse in combination.
-+- Keep this result as evidence that q1 and route-local GEMM1 interact, but do
-+  not enable it in the accepted launcher without a stronger resident/persistent
-+  implementation and full endpoint quality gates.
-+
-+## 2026-06-19 Addendum - DFlash Draft Is Active But Native Verifier Still Fails
-+
-+I tested the public DFlash draft model as a possible no-quality-loss route to
-+verified multi-token decode, but only as a quality/parity smoke. This was not a
-+speed promotion.
-+
-+Draft model:
-+
-+- HF repo:
-+  `z-lab/Qwen3.6-35B-A3B-DFlash`.
-+- Revision:
-+  `42d3b34d588423cdae7ba8f53a8cf7789346a719`.
-+- Local snapshot:
-+  `/mnt/fast-ai/llm-cache/hf/models--z-lab--Qwen3.6-35B-A3B-DFlash/snapshots/42d3b34d588423cdae7ba8f53a8cf7789346a719`.
-+- Cache size:
-+  `905M`.
-+- Config:
-+  `architectures=["DFlashDraftModel"]`, `num_hidden_layers=8`,
-+  `block_size=16`, `dflash_config.mask_token_id=248070`,
-+  `dflash_config.target_layer_ids=[1,10,19,28,37]`.
-+
-+Kernel/runtime prerequisite fixed:
-+
-+- The first DFlash smoke failed before model load because the local
-+  `vllm_xpu_kernels._xpu_C` extension could not import:
-+  `libgrouped_gemm_xe_2.so` was stale and missing the new route-GEMM1 symbols.
-+- I rebuilt and reinstalled `_xpu_C` and copied the rebuilt grouped GEMM/GDN
-+  shared libraries into `vllm_xpu_kernels/`.
-+- Import and XPU platform detection now work again:
-+  `_xpu_C import ok`, `current_platform.device_type == "xpu"`.
-+
-+Parity runner/tooling:
-+
-+- Added reusable runner:
-+  `/home/steve/llm-optimizations/scripts/run-qwen36-spec-parity-candidate.sh`.
-+- Hardened replay decoding in:
-+  `/home/steve/llm-optimizations/scripts/replay-qwen36-spec-trace.py`.
-+- Reason:
-+  DFlash trace rows use `scheduled_spec_token_ids=[-1,...]`, and the replay
-+  report should preserve those placeholders instead of crashing during
-+  tokenizer decode.
-+
-+Smoke run:
-+
-+- Label:
-+  `qwen36-dflash-k15-eager-tp2-smoke-20260619b`.
-+- Launch identity:
-+  TP2 on XPUs `0,1`, eager, XPU graph off, GPU memory utilization `0.82`,
-+  prompt `512`, output `32`,
-+  speculative config
-+  `{"method":"dflash","model":"...Qwen3.6-35B-A3B-DFlash/...42d3b34d...","num_speculative_tokens":15}`.
-+- Server log:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-smoke-20260619b-20260619dflashsmoke2.log`.
-+- Candidate output:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-smoke-20260619b-20260619dflashsmoke2-candidate.json`.
-+- Spec trace:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-smoke-20260619b-20260619dflashsmoke2-spec-trace.jsonl`.
-+
-+Result:
-+
-+- DFlash was active:
-+  `draft_tokens=90`, `accepted=35`, `rejected=55`,
-+  accept rate `38.888888888888886%`.
-+- Replay after the tooling fix:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-smoke-20260619b-20260619dflashsmoke2-replay-rerun.json`.
-+- Replay accounting:
-+  `accounting_mismatch_count=0`, `generated mismatches=0`,
-+  `schedule mismatches=0`, `accept mismatches=0`.
-+- Exact quality gate:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-smoke-20260619b-20260619dflashsmoke2-gate-summary-rerun.json`.
-+- Gate status:
-+  `pass=false`, `mismatch_count=1`.
-+
-+First mismatch:
-+
-+- Fixture:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-smoke-20260619b-20260619dflashsmoke2-fixture-rerun.json`.
-+- Output index:
-+  `24`.
-+- Accepted/no-spec token:
-+  `271` (`\n\n`).
-+- DFlash/native-verifier candidate token:
-+  `198` (`\n`).
-+- Accepted window:
-+  `[11,321,874,4131,4557,13,271,248068,271,248069,271,16,13,2972,10886,38563]`.
-+- Candidate window:
-+  `[11,321,874,4131,4557,13,271,248068,198,90700,8340,25,271,16,13,220]`.
-+- Replay mapping:
-+  trace row `4`, emission role `replacement_after_reject`,
-+  `num_accepted=0`, `num_rejected=15`,
-+  `scheduled_spec_token_ids=[-1 x 15]`, `generated_token_ids=[198]`.
-+
-+Decision:
-+
-+- Reject DFlash as a promotion candidate until native verifier parity is fixed.
-+- The draft model is useful because it is active and has nonzero acceptance,
-+  but it exposes the same verifier/recovery correctness failure around the
-+  `248068` region seen in prior native verifier probes.
-+- Next highest-leverage correctness work is to repair the normal native
-+  verifier/GDN state transaction around rejected speculative rows, then rerun
-+  this DFlash fixture and the existing oracle fixtures before making any speed
-+  claim.
-+
-+Follow-up DFlash recovery flag tests:
-+
-+- Full preempt replacement recovery:
-+  `qwen36-dflash-k15-eager-tp2-recover-replacement-20260619a-20260619dflashrecover1`.
-+  Flags:
-+  `VLLM_XPU_SPEC_DECODE_SUPPRESS_REPLACEMENT=1`,
-+  `VLLM_XPU_SPEC_DECODE_RECOVER_SUPPRESSED_REPLACEMENT=1`,
-+  `VLLM_XPU_SPEC_DECODE_RESUME_AFTER_RECOVERY_PREEMPT=1`,
-+  `VLLM_XPU_SPEC_DECODE_RECOVERY_FORCE_SINGLE_STEPS=16`.
-+  Result:
-+  `pass=false`, accept rate `11.666666666666666%`.
-+  First mismatch moved earlier to output index `2`; the candidate duplicated
-+  token `440` (`with`) where baseline expected token `27044` (` dense`).
-+  Fixture:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-recover-replacement-20260619a-20260619dflashrecover1-fixture.json`.
-+
-+- No-preempt replacement suppression:
-+  `qwen36-dflash-k15-eager-tp2-no-preempt-replacement-20260619a-20260619dflashnopreempt1`.
-+  Flags:
-+  `VLLM_XPU_SPEC_DECODE_SUPPRESS_REPLACEMENT=1`,
-+  `VLLM_XPU_SPEC_DECODE_RECOVER_SUPPRESSED_REPLACEMENT=1`,
-+  `VLLM_XPU_SPEC_DECODE_NO_PREEMPT_SUPPRESSED_REPLACEMENT=1`.
-+  Result:
-+  `pass=false`, accept rate `32.38095238095238%`.
-+  First mismatch at output index `4`; the candidate repeated the accepted
-+  prefix `[440,27044,47193]` before continuing.
-+  Fixture:
-+  `/home/steve/llm-optimizations/data/qwen36-dflash-k15-eager-tp2-no-preempt-replacement-20260619a-20260619dflashnopreempt1-fixture.json`.
-+
-+Decision:
-+
-+- Simple flag-only DFlash replacement recovery is rejected.
-+- Full-preempt recovery replays from too early a boundary.
-+- No-preempt replacement suppression repeats the accepted prefix.
-+- DFlash remains useful as a verifier bug reproducer, but it is not the next
-+  promotion lane until the GDN/KV transaction is fixed in code.
-+
-+Additional DFlash follow-up on 2026-06-19:
-+
-+- Tried a scheduler-side deferred-placeholder guard so forced recovery steps
-+  would not refill `scheduled_spec_decode_tokens` in
-+  `update_draft_token_ids_in_output`.
-+  Run:
-+  `qwen36-dflash-k15-eager-tp2-no-preempt-replacement-20260619b-20260619dflashnopreempt2`.
-+  Result:
-+  still `pass=false`, accept rate `32.38095238095238%`, first mismatch at
-+  output index `4`, same repeated accepted prefix
-+  `[440,27044,47193]`. I reverted the guard because it was ineffective.
-+- Tried replaying the accepted prefix plus suppressed replacement as ordinary
-+  recovery decode:
-+  `VLLM_XPU_SPEC_DECODE_REPLAY_SUPPRESSED_REPLACEMENT_ACCEPTED=1`,
-+  `VLLM_XPU_SPEC_DECODE_EAGER_REPLACEMENT_RECOVERY=1`,
-+  `VLLM_XPU_SPEC_DECODE_EAGER_ALL_RECOVERY_STEPS=1`.
-+  Run:
-+  `qwen36-dflash-k15-eager-tp2-replay-accepted-replacement-20260619a-20260619dflashreplayaccepted1`.
-+  Result:
-+  endpoint failed before producing a candidate with
-+  `UR_RESULT_ERROR_DEVICE_LOST` in rotary embedding after a scheduler output
-+  still contained `num_scheduled_tokens=16` and placeholder
-+  `scheduled_spec_decode_tokens=[-1 x 15]` during a forced recovery phase.
-+  Reject this flag stack as unstable.
-+- Scoped post-crash health check for the actual TP2 cards passed:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-devices01-after-dflash-replayaccepted-scoped-20260619.log`.
-+- Full physical/XCCL health still shows device `3` unhealthy:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-devices01-after-dflash-replayaccepted-20260619.log`.
-+
-+Updated decision:
-+
-+- Stop flag-level DFlash recovery work for now. The remaining issue is not a
-+  one-line scheduler suppression policy; forced recovery can still be paired
-+  with stale placeholder speculative rows and/or mismatched worker request
-+  state. A real code fix would need to make recovery scheduling atomic across
-+  scheduler output, drafter output, worker local token cache, and GDN/KV state.
-+- For the speed goal, return to exact MoE structural work unless/until the
-+  verifier transaction gets a dedicated implementation window.
-+
-+Additional DFlash follow-up on 2026-06-19, later:
-+
-+- Added diagnostic
-+  `VLLM_XPU_SPEC_DECODE_REPLAY_ROW_STATEFUL_RECOVERY=1` for
-+  `VLLM_XPU_SPEC_DECODE_REPLAY_ROW_AFTER_TOKEN_IDS`.  Instead of calling
-+  `_preempt_request()` and resetting `num_computed_tokens` to zero, it keeps
-+  the request running, clears speculative IDs/placeholders, sets the replay
-+  boundary to `visible_tokens - 1`, and forces single-token recovery steps.
-+  Syntax gate passed:
-+  `/home/steve/.venvs/vllm-xpu/bin/python -m py_compile ...`.
-+- Async scheduler run:
-+  `qwen36-dflash-k15-eager-tp2-stateful-replay-think-20260619b-20260619dflashstateful2`
-+  crashed with `AsyncScheduler._update_request_with_output` placeholder
-+  underflow after the stateful row.  The spec trace confirms the row normalized
-+  to `num_computed_tokens=521`, `num_output_placeholders=0`, `spec_len=0`,
-+  and did not preempt.  This means async still needs a separate stale in-flight
-+  scheduler-output transaction if this path is ever revived.
-+- Synchronous scheduler run:
-+  `qwen36-dflash-k15-eager-tp2-stateful-replay-think-sync-20260619a-20260619dflashstatefulsync1`
-+  completed but failed parity.  First diff remained at output index `24`
-+  after `<think>`: baseline token `271` vs candidate token `198`.  Avoiding
-+  the long prefill replay is not enough; the native packed verifier rows
-+  before the recovery point already leave recurrent state non-identical.
-+- Serial GDN anchor with DFlash:
-+  `qwen36-dflash-k15-eager-tp2-serial-gdn-sync-20260619a-20260619dflashserial1`
-+  also failed parity, though it moved the first diff to output index `25`.
-+  Gate role was `replacement_after_reject`, accept rate was about `25.71%`.
-+  This shows DFlash is not a near-term promotion lane even with serial GDN;
-+  it needs a larger verifier/replacement transaction fix, not another
-+  scheduler-only replay knob.
-+- Current DFlash conclusion: keep the stateful replay flag only as a diagnostic
-+  artifact.  Do not claim speed or quality from DFlash.  Return to exact MoE
-+  layerlet work for the no-quality-loss >150 tok/s goal.
-+
-+## 2026-06-19 Addendum - Full Layerlet Endpoint Smoke Is Exact But Small
-+
-+I ran a same-identity TP2 endpoint smoke to check whether the exact C++
-+`qwen36_moe_w8a8_full_layerlet` route-replay gain survives real endpoint
-+execution. This used devices `0,1` because physical device `3` is still not
-+TP4-safe.
-+
-+Shared identity:
-+
-+- model:
-+  `/mnt/fast-ai/llm-cache/hf/models--nameistoken--Qwen3.6-35B-A3B-Quark-W8A8-INT8/snapshots/cced56592e8c8935f8220836b4baa04dfd389118`
-+- `TP_SIZE=2`, `ONEAPI_DEVICE_SELECTOR=level_zero:0,1`,
-+  `ZE_AFFINITY_MASK=0,1`, `QWEN36_XPU_PREFLIGHT=1`.
-+- `COMPILATION_CONFIG='{"cudagraph_mode":"PIECEWISE"}'`.
-+- `XPU_GRAPH=1`, `VLLM_XPU_ENABLE_XPU_GRAPH=1`,
-+  `VLLM_XPU_FORCE_GRAPH_WITH_COMM=1`,
-+  `VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1`.
-+- `VLLM_XPU_GDN_NATIVE_FALLBACK=prefill`,
-+  `VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK=1`,
-+  `VLLM_XPU_DISABLE_PREFILL_CUDAGRAPH_REPLAY=1`,
-+  `VLLM_XPU_GREEDY_SAMPLE_TOPK_FALLBACK=1`,
-+  `VLLM_XPU_INT8_MOE_MIXED_WORKSPACE=1`.
-+- `VLLM_EXTRA_ARGS='--uvicorn-log-level warning'`.
-+- short smoke only: one `512/256` metrics run plus 8-repeat JSON/color
-+  canaries; quality suite skipped.
-+
-+Control artifact:
-+
-+- `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-tp2-control-smoke-20260619a-summary-20260619tp2control1.json`
-+- corrected decode throughput: `83.68628063307641 tok/s`.
-+- vLLM histogram decode: `11.948150581702066 ms/token`.
-+- JSON/color canaries: passed `8/8` each.
-+
-+Full-layerlet artifact:
-+
-+- `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-full-layerlet-tp2-smoke-20260619a-summary-20260619fulltp2smoke1.json`
-+- extra flags: `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`,
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1`.
-+- corrected decode throughput: `85.45754293668266 tok/s`.
-+- vLLM histogram decode: `11.702753504323482 ms/token`.
-+- JSON/color canaries: passed `8/8` each.
-+
-+Decision:
-+
-+- The full layerlet is a real but small endpoint improvement in this TP2 smoke:
-+  about `+1.77 tok/s`, `+2.1%`, or `0.245 ms/token`.
-+- This is not remotely enough for the `>150 tok/s` goal, and it does not
-+  justify a production promotion by itself.
-+- The route replay showed a much larger isolated MoE reduction, so the missing
-+  gain is likely being absorbed by graph/dispatcher boundaries, collectives,
-+  GDN/attention, logits/sampling, or other all-rank forward overhead.
-+- Next step: run decisive live decode timing on the same TP2 identity, comparing
-+  control versus full-layerlet if possible, then target the largest remaining
-+  live family rather than adding another tiny MoE wrapper flag.
-+
-+## 2026-06-19 Addendum - TP2 Decisive Timing Reframes The MoE Target
-+
-+I ran decisive live decode timing on the same TP2 PIECEWISE identity used by
-+the full-layerlet smoke above.
-+
-+Control timing artifacts:
-+
-+- `/home/steve/llm-optimizations/data/qwen36-prefill-safe-int8-tp2-control-decisive-20260619a-p512o256-20260619tp2timingctl1.json`
-+- `/home/steve/llm-optimizations/data/qwen36-prefill-safe-int8-tp2-control-decisive-20260619a-timing-decision-20260619tp2timingctl1.json`
-+- Corrected decode throughput: `84.30754286685192 tok/s`.
-+- Decode time: `11.861692133606994 ms/token`.
-+
-+Full-layerlet timing artifacts:
-+
-+- `/home/steve/llm-optimizations/data/qwen36-prefill-safe-int8-full-layerlet-tp2-decisive-20260619a-p512o256-20260619tp2timingfull1.json`
-+- `/home/steve/llm-optimizations/data/qwen36-prefill-safe-int8-full-layerlet-tp2-decisive-20260619a-timing-decision-20260619tp2timingfull1.json`
-+- Extra flags: `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`,
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1`.
-+- Corrected decode throughput: `84.4112340056149 tok/s`.
-+- Decode time: `11.845327250739501 ms/token`.
-+
-+Key timing result:
-+
-+- Both decisions still label the largest family as `moe`, but the dominant
-+  live label is `moe_forward_shared.custom_op`, not the routed W8A8 layerlet.
-+- Control: `moe_forward_shared.custom_op` max `8.841024 ms`,
-+  `moe.shared_experts.apply_no_overlap` max `5.772847 ms`,
-+  `qwen2_moe.shared.silu_and_mul` max `3.394437 ms`,
-+  `xpu_moe.fused_moe_call` max only `1.318158 ms`.
-+- Full-layerlet: `moe_forward_shared.custom_op` max `8.720514 ms`,
-+  `moe.shared_experts.apply_no_overlap` max `5.635415 ms`,
-+  `qwen2_moe.shared.silu_and_mul` max `3.311749 ms`,
-+  `xpu_moe.fused_moe_call` max `1.342872 ms`.
-+
-+Decision:
-+
-+- The exact C++ routed full-layerlet is still useful as a small building block,
-+  but it is no longer the highest-probability path to `>150 tok/s`.
-+- The current live wall is the shared-expert path and/or the graph boundary
-+  around `moe_forward_shared`, so another routed expert micro-kernel is likely
-+  to produce only sub-percent endpoint gains.
-+- Rejected shared-expert paths from earlier remain rejected:
-+  `VLLM_XPU_SHARED_EXPERTS_STREAM=1` + graph no-empty-cache was quality-clean
-+  but slowed to `73.7749 tok/s`; `VLLM_XPU_SHARED_EXPERT_ACT_WORKSPACE=1`
-+  failed canaries under PIECEWISE; `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT=1`
-+  was slower and/or replay-nondeterministic; `VLLM_XPU_MOE_SHARED_ADD_ALLREDUCE_CUSTOM_OP=1`
-+  was quality-clean but slower.
-+- Next exact candidates should therefore be:
-+  1. Restore TP4 health first, because TP2 is not the target production shape.
-+  2. Build an offline shared-expert replay harness that isolates
-+     `gate_up_proj`, `silu_and_mul`, `down_proj`, `expert_gate`, and `gate_mul`
-+     under the current INT8 path and tests exact fused/persistent variants
-+     outside the endpoint before any canary run.
-+  3. If the shared-expert harness does not show a large exact win, shift back
-+     to no-quality-loss speculation parity rather than spending more time on
-+     low-ceiling shared-expert wrappers.
-+
-+## 2026-06-19 Addendum - Shared-Expert Fused Act/Quant `_out` Is Not Graph-Safe
-+
-+I tested a narrower shared-expert optimization that reuses preallocated
-+activation-quantization outputs instead of letting
-+`silu_and_mul_quant_int8_xpu` allocate fresh tensors. The endpoint flag stack
-+was:
-+
-+- `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT=1`
-+- `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT=1`
-+
-+Microbench result:
-+
-+- `_xpu_C.silu_and_mul_quant_int8_xpu_out` is mathematically exact against
-+  separate `silu_and_mul` plus INT8 quantization for the tested shared-expert
-+  shapes.
-+- It saves roughly `6-7 us` versus the separate two-op path for
-+  rows `1..32`, `d=512`.
-+
-+Endpoint shallow smoke, TP2 PIECEWISE identity:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedexp-fusedactquant-out-tp2-smoke-20260619a-summary-20260619175320.json`
-+- Corrected decode throughput: `85.47207810078443 tok/s`.
-+- Decode time: `11.700355452376243 ms/token`.
-+- JSON/color canaries: passed `8/8` each.
-+
-+Deep canary under normal PIECEWISE decode replay:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedexp-fusedactquant-out-tp2-deep-canary-20260619a-summary-20260619175659.json`
-+- JSON failed at repeat index `31`.
-+- Expected `{"answer":"42","unit":"widgets"}`, got
-+  `{"answer":"12","unit":"widgets"}`.
-+- Color passed `96/96`.
-+
-+Diagnostic replay bypass:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedexp-fusedactquant-out-tp2-eager-everyreq-canary-20260619a-summary-20260619180050.json`
-+- Extra flag:
-+  `VLLM_XPU_DECODE_CUDAGRAPH_REPLAY_EAGER_EVERY_N_REQUESTS=1`.
-+- JSON/color both passed `96/96`.
-+- This points away from arithmetic error and toward graph replay buffer
-+  ownership/lifetime.
-+
-+Strong-output replay mitigation:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedexp-fusedactquant-out-tp2-strong-output-canary-20260619a-summary-20260619180502.json`
-+- Extra flag: `VLLM_XPU_CUDAGRAPH_STRONG_OUTPUT=1`.
-+- JSON still failed at repeat index `31` with the same `42 -> 12` mismatch.
-+- Color passed `96/96`.
-+
-+Decision:
-+
-+- Reject `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT=1` for endpoint use.
-+- The math is exact and the shallow speed signal is real, but reusable
-+  Python-owned q/scale workspace is unsafe under PIECEWISE decode replay.
-+- Do not use eager-every-request as a performance workaround; it is a
-+  correctness diagnostic only.
-+- Next shared-expert work must make the fused boundary graph-safe. Viable
-+  directions are:
-+  1. move the temporary q/scale ownership inside a single custom op or captured
-+     graph-owned boundary so Python does not reuse graph-visible scratch;
-+  2. add capture-aware workspace ownership keyed by graph wrapper/static input
-+     slot, with a replay alias trace proving no stale scratch reuse;
-+  3. isolate only the corrupting PIECEWISE submodule in eager mode if its
-+     submod index can be mapped and if the speed loss is small.
-+
-+The fastest exact path is still shared-expert structural work, but promotion
-+requires deep canaries under normal PIECEWISE replay, not only eager replay.
-+
-+## 2026-06-19 Addendum - Async Scheduling Was A Separate Correctness Poison
-+
-+I retested the current TP2 PIECEWISE forced/noop-comm graph lane after
-+separating async scheduling from GDN/shared-expert graph replay issues.
-+
-+Clean TP2/no-async identity:
-+
-+- `TP_SIZE=2`, devices `0,1`.
-+- `COMPILATION_CONFIG='{"cudagraph_mode":"PIECEWISE"}'`.
-+- `XPU_GRAPH=1`, `VLLM_XPU_ENABLE_XPU_GRAPH=1`,
-+  `VLLM_XPU_FORCE_GRAPH_WITH_COMM=1`,
-+  `VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1`.
-+- `VLLM_XPU_GDN_NATIVE_FALLBACK=prefill`.
-+- `VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK=1`.
-+- `VLLM_XPU_GREEDY_SAMPLE_TOPK_FALLBACK=1`.
-+- `VLLM_XPU_DISABLE_PREFILL_CUDAGRAPH_REPLAY=1`.
-+- `VLLM_XPU_INT8_MOE_MIXED_WORKSPACE=1`.
-+- `VLLM_EXTRA_ARGS='--no-async-scheduling --uvicorn-log-level warning'`.
-+
-+Control results:
-+
-+- Canary artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-tp2-control-noasync-canary-20260619a-summary-20260619prefillnoasynca.json`
-+- Metrics artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-tp2-control-noasync-metrics-20260619a-summary-20260619prefillnoasyncmetricsa.json`
-+- JSON canary passed `64/64`.
-+- Color canary passed `16/16`.
-+- Corrected decode throughput: `82.06149961234053 tok/s`.
-+- Decode time: `12.19165415864154 ms/token`.
-+
-+Async separation:
-+
-+- With async scheduling left enabled, current-code JSON canaries still failed
-+  around repeat index `21` or `31` with the characteristic `42 -> 12`
-+  corruption.
-+- Native GDN decode fallback for layer `0`, layers `0..2`, and even full
-+  `decode,prefill` GDN fallback did not fix the async failure.
-+- Full `decode,prefill` GDN fallback plus `--no-async-scheduling` passed
-+  JSON `64/64` and color `16/16`.
-+- Therefore, current async scheduling is an independent correctness blocker
-+  for this endpoint identity. Do not promote async-path speed until the
-+  repeated canaries pass on the same run identity.
-+
-+Shared-expert fused `_out` retest under the clean no-async identity:
-+
-+- Canary artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedexp-fusedactquant-out-noasync-tp2-canary-20260619a-summary-20260619sharedoutnoasync1.json`
-+- Metrics artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedexp-fusedactquant-out-noasync-tp2-metrics-20260619a-summary-20260619sharedoutnoasyncmetrics1.json`
-+- Extra flags:
-+  `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT=1`,
-+  `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT=1`.
-+- JSON canary passed `64/64`.
-+- Color canary passed `16/16`.
-+- Corrected decode throughput: `83.61311830066423 tok/s`.
-+- Decode time: `11.960592332457054 ms/token`.
-+- Decision: keep as a small candidate win on the no-async lane
-+  (`+1.5516186883237 tok/s`, about `+1.9%` versus the clean baseline), but it
-+  is far too small to explain a path to `>150 tok/s` by itself and still needs
-+  full quality/reliability gates before production use.
-+
-+Routed full-layerlet retest under the clean no-async identity:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-full-layerlet-noasync-tp2-candidate-20260619a-summary-20260619fulllayerletnoasync1.json`
-+- Extra flags:
-+  `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`,
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1`.
-+- JSON canary passed `64/64`.
-+- Color canary passed `16/16`.
-+- Corrected decode throughput: `82.18196711720888 tok/s`.
-+- Decode time: `12.17378463775276 ms/token`.
-+- Decision: reject as an endpoint speed candidate on the clean no-async lane.
-+  It is quality-clean in this focused gate but essentially baseline speed.
-+
-+Updated immediate plan:
-+
-+1. Keep the no-async TP2 identity as the current safe benchmark lane.
-+2. Try stacking the small shared-expert `_out` candidate only after any larger
-+   candidate passes; it is not enough to chase alone.
-+3. Restore TP4/device health next. TP2 clean speed in the low `80 tok/s` range
-+   is too far from the `>150 tok/s` target without either healthy four-card
-+   execution or a no-quality-loss multi-token path.
-+4. If TP4 remains blocked, build the offline shared-expert replay harness and
-+   pursue a larger fused/persistent shared-expert boundary instead of more
-+   routed-expert layerlet variants.
-+
-+## 2026-06-19 Addendum - TP4 Still Blocked, Routed+Shared Stack Does Not Matter
-+
-+Device/topology health:
-+
-+- Device `3` still fails a trivial single-device allocation:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-device3-single-20260619195006.log`
-+- Error:
-+  `RuntimeError: level_zero backend failed with error: 40 (UR_RESULT_ERROR_OUT_OF_RESOURCES)`.
-+- `xpu-smi stats -d 3` reports only `34 MiB` GPU memory used and
-+  `0%` memory utilization, and `xpu-smi ps -d 3` shows no model process.
-+- The exposed PCI reset path exists at
-+  `/sys/bus/pci/devices/0000:47:00.0/reset`, with reset methods `flr bus`,
-+  but it is root-only and this shell does not have non-interactive sudo.
-+- Devices `0,1,2` pass fresh single-device and XCCL all-reduce health:
-+  `/home/steve/llm-optimizations/data/qwen36-xpu-health-devices012-fresh-20260619195121.log`
-+- TP3 is not a usable fallback for this model: `hidden_size=2048`,
-+  `num_attention_heads=16`, `num_key_value_heads=2`, `num_experts=256`,
-+  `num_experts_per_tok=8`, and `vocab_size=248320` are not divisible by `3`.
-+
-+Conclusion:
-+
-+- TP4 remains blocked in this session by physical device `3` health.
-+- TP3 is architecturally incompatible.
-+- The only reliable exact endpoint topology available right now is TP2 on
-+  devices `0,1`.
-+
-+Stacked routed+shared candidate:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedout-full-layerlet-noasync-tp2-candidate-20260619a-summary-20260619sharedoutfulllayerletnoasync1.json`
-+- Extra flags:
-+  `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT=1`,
-+  `VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT=1`,
-+  `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`,
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1`.
-+- JSON canary passed `64/64`.
-+- Color canary passed `16/16`.
-+- Corrected decode throughput: `83.64920085436258 tok/s`.
-+- Decode time: `11.955750166180223 ms/token`.
-+
-+Decision:
-+
-+- The routed full-layerlet adds essentially nothing when stacked with the
-+  shared-expert `_out` candidate (`+0.036 tok/s` over shared `_out` alone).
-+- Stop spending endpoint runs on routed layerlet variants unless a new offline
-+  replay result shows a much larger exact win.
-+- Next engineering target is a shared-expert replay harness that isolates
-+  `gate_up_proj`, activation/quantization, `down_proj`, `expert_gate`, and
-+  final multiply/add. The endpoint timing says this is the live TP2 wall.
-+
-+## 2026-06-19 Addendum - Shared-Expert C++ Boundary Is Correct But Small
-+
-+Implemented a larger exact shared-expert W8A8 boundary:
-+
-+- Kernel/binding patch in `/home/steve/src/vllm-xpu-kernels`:
-+  - `int8_gemm_w8a8_out`.
-+  - `qwen36_shared_expert_w8a8_out`.
-+  - Gate weight accepts both replay layout `[hidden, 1]` and live
-+    `ReplicatedLinear` layout `[1, hidden]` without Python-side contiguous
-+    transpose.
-+- Endpoint wiring in
-+  `/home/steve/src/vllm/vllm/model_executor/models/qwen2_moe.py` behind:
-+  `VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT=1`.
-+- Replay harness:
-+  `/home/steve/llm-optimizations/scripts/bench-qwen36-shared-expert-replay.py`.
-+
-+Build lesson:
-+
-+- Do not use full `pip install -e . --no-build-isolation` for every
-+  `_xpu_C` kernel iteration; it rebuilds broad attention targets first and
-+  took too long.
-+- Use the direct target instead:
-+  `cmake --build /home/steve/src/vllm-xpu-kernels/build/temp -j=8 --target=_xpu_C`,
-+  then copy `_xpu_C.abi3.so` and sibling `.so` files into
-+  `/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/`.
-+
-+Offline replay:
-+
-+- Smoke artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-shared-expert-replay-cppbound-smoke-20260619.md`
-+- Stable artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-shared-expert-replay-cppbound-tp2-20260619.md`
-+- Exact parity: `max_abs_diff = 0` for rows `1,2,4,8,16,32`.
-+- Stable replay mean C++ boundary timings:
-+  - rows `1`: `216.180 us` vs baseline `264.540 us`.
-+  - rows `2`: `206.868 us` vs baseline `250.995 us`.
-+  - rows `4`: `260.857 us` vs baseline `247.807 us` (slower).
-+  - rows `8`: `273.691 us` vs baseline `248.311 us` (slower).
-+  - rows `16`: `208.777 us` vs baseline `283.551 us`.
-+  - rows `32`: `215.368 us` vs baseline `311.497 us`.
-+
-+Endpoint canary, same clean TP2/no-async identity:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedboundary-out-noasync-tp2-canary-20260619a-summary-20260619sharedboundarycanary1.json`
-+- Extra flag: `VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT=1`.
-+- JSON canary passed `64/64`.
-+- Color canary passed `16/16`.
-+
-+Endpoint metrics, same clean TP2/no-async identity:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedboundary-out-noasync-tp2-metrics-20260619a-summary-20260619sharedboundarymetrics1.json`
-+- Corrected decode throughput: `83.6714304189521 tok/s`.
-+- Decode time: `11.952609020454474 ms/token`.
-+
-+Decision:
-+
-+- Keep as a correct, opt-in, small candidate.
-+- It is only about `+1.61 tok/s` over the clean TP2/no-async baseline and
-+  essentially tied with the previous shared `_out` candidate.
-+- This does not materially move the `>150 tok/s` target. The next larger work
-+  must attack routed MoE fixed costs, collectives/topology, or exact
-+  speculation parity.
-+
-+## 2026-06-19 Addendum - Shared Boundary Timing and Next Branch
-+
-+Decisive timing after the shared-expert C++ boundary:
-+
-+- Run summary:
-+  `/home/steve/llm-optimizations/data/qwen36-sharedboundary-noasync-tp2-decisive-20260619a-run-summary-20260619sharedboundarytiming1.json`
-+- Timing decision:
-+  `/home/steve/llm-optimizations/data/qwen36-sharedboundary-noasync-tp2-decisive-20260619a-timing-decision-20260619sharedboundarytiming1.md`
-+- Same clean TP2/no-async identity as the accepted current safe lane, plus
-+  `VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT=1`.
-+- Corrected decode throughput on the timing probe:
-+  `84.10955623702061 tok/s`.
-+- Main visible labels:
-+  - `gpu_model_runner.model_forward`: mean `5.363407 ms`.
-+  - `gpu_model_runner.bookkeeping_sync`: mean `4.679359 ms`.
-+  - `gdn_attention_core_xpu.native`: mean `1.506388 ms`.
-+  - `qwen2_moe.shared.boundary_int8_cpp`: mean `1.548210 ms`.
-+
-+Interpretation:
-+
-+- The shared-expert boundary is active and exact, but it does not move the
-+  endpoint enough.
-+- The routed MoE offline branches already closed today:
-+  - direct GEMM2+gather: exact, rejected for speed.
-+  - DPAS GEMM2+gather and N-tile variants: exact, rejected for speed.
-+  - workspace atomic reuse: exact, rejected for speed.
-+  - route-known GEMM1: exact, rejected for speed.
-+  - q1 + route-GEMM1: exact but not stable enough across repeats.
-+- Do not spend more endpoint time on those small exact MoE flags unless a new
-+  offline artifact shows a stable sub-`160 us` layerlet across the route set.
-+
-+Runner hygiene:
-+
-+- Patched `scripts/run-qwen36-ablation-candidate.sh` and
-+  `scripts/run-qwen36-decisive-timing.sh` so future summaries record the newer
-+  W8A8 route flags, DPAS gather flags, workspace-atomic flag, route-GEMM1
-+  tile flag, shared-expert boundary flag, `VLLM_EXTRA_ARGS`, and
-+  `GPU_MEMORY_UTILIZATION`.
-+- `bash -n` passed for both scripts.
-+
-+Next active plan:
-+
-+1. Recover a quality-safe fast lane before more endpoint speed claims.
-+   - Current no-async TP2 safe lane is only `~82-84 tok/s`.
-+   - TP2 async shallow smoke can pass, but deeper notes show async canary
-+     corruption; do not promote async until repeated canaries and the quality
-+     suite pass in the exact identity.
-+2. Resume oracle/spec parity repair as the largest no-quality-loss path to
-+   `>150 tok/s`.
-+   - First target: oracle `k=1` must be token-identical to no-spec on the same
-+     no-async/PIECEWISE identity.
-+   - Trace token IDs, positions, slot IDs, KV block state, hidden-state digest,
-+     and top-k logits at the first divergence.
-+   - Only after parity, test DFlash/EAGLE/ngram acceptance or wider
-+     target-verified multi-token decode.
-+3. Keep TP4 blocked until device `3` XPU/XCCL health is repaired externally.
-+   TP3 is incompatible with this model, and TP2 is the only healthy exact
-+   topology available in this shell.
-+
-+## 2026-06-19 Addendum - Fused Shared Gate/Mul Increment
-+
-+Implemented an opt-in C++/SYCL epilogue inside the existing shared-expert
-+W8A8 boundary:
-+
-+- Kernel source:
-+  `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`
-+- Runtime flag:
-+  `VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL=1`
-+- Required surrounding flag:
-+  `VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT=1`
-+- The default path is unchanged when the new flag is unset.
-+- The ablation wrapper now records the new flag in both the printed guard
-+  line and summary JSON identity:
-+  `/home/steve/llm-optimizations/scripts/run-qwen36-ablation-candidate.sh`
-+
-+Implementation details:
-+
-+- Replaces only the final shared-expert gate/multiply epilogue:
-+  `matmul(hidden_states, expert_gate_w) -> sigmoid -> multiply down_out`.
-+- Keeps the accepted W8A8 quant/GEMM path unchanged.
-+- Tries to preserve dtype staging by rounding the gate and sigmoid through
-+  the output dtype before multiplying `down_out`.
-+- This is exact enough for the current canary and quality gates, but it is
-+  still gated because its dot-product reduction order differs from the PyTorch
-+  matmul path.
-+
-+Build/install:
-+
-+```bash
-+JOBS=4 /home/steve/llm-optimizations/scripts/build-vllm-xpu-kernels-xpu-c-only.sh
-+cp /tmp/vllm-xpu-xpu-c-only-2025/vllm_xpu_kernels/_xpu_C.abi3.so \
-+  /home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels/_xpu_C.abi3.so
-+```
-+
-+Import sanity:
-+
-+```bash
-+PYTHONPATH=/home/steve/src/vllm:/home/steve/src/vllm-xpu-kernels \
-+LD_LIBRARY_PATH=/home/steve/src/vllm-xpu-kernels/vllm_xpu_kernels:/home/steve/.venvs/vllm-xpu/lib:/home/steve/.venvs/vllm-xpu/lib/python3.12/site-packages/torch/lib \
-+/home/steve/.venvs/vllm-xpu/bin/python -c 'import torch, vllm_xpu_kernels._xpu_C; print(hasattr(torch.ops._xpu_C, "qwen36_shared_expert_w8a8_out"))'
-+```
-+
-+Validation identity:
-+
-+```bash
-+TP_SIZE=2
-+ONEAPI_DEVICE_SELECTOR=level_zero:0,1
-+ZE_AFFINITY_MASK=0,1
-+QWEN36_XPU_PREFLIGHT=0
-+COMPILATION_CONFIG='{"cudagraph_mode":"PIECEWISE"}'
-+XPU_GRAPH=1
-+VLLM_XPU_ENABLE_XPU_GRAPH=1
-+VLLM_XPU_FORCE_GRAPH_WITH_COMM=1
-+VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1
-+VLLM_XPU_GDN_NATIVE_FALLBACK=prefill
-+VLLM_EXTRA_ARGS='--no-async-scheduling --uvicorn-log-level warning'
-+VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT=1
-+VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL=1
-+GPU_MEMORY_UTILIZATION=0.90
-+```
-+
-+Quality/canary artifacts:
-+
-+- Canary summary:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedgate-mul-noasync-tp2-canary-summary-20260619sharedgatemulcanary1.json`
-+- JSON canary: passed `64/64`.
-+- Color canary: passed `16/16`.
-+- Quality summary:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedgate-mul-noasync-tp2-quality-summary-20260619sharedgatemulquality1.json`
-+- Quality suite: `pass_all=true`, `baseline_match_all=true`,
-+  exact arithmetic/copy/json cases passed, repeat passed, long-context passed.
-+
-+Metrics artifact:
-+
-+- Summary:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-sharedgate-mul-noasync-tp2-metrics-summary-20260619sharedgatemulmetrics1.json`
-+- Corrected decode throughput: `84.9100565680358 tok/s`.
-+- Decode time: `11.777681041849064 ms/token`.
-+- TTFT: `269.54865898005664 ms`.
-+
-+Comparable TP2/no-async controls:
-+
-+- Plain TP2/no-async control:
-+  `82.06149961234053 tok/s`, `12.19165415864154 ms/token`.
-+- Shared boundary only:
-+  `83.6714304189521 tok/s`, `11.952609020454474 ms/token`.
-+- Fused gate/mul over shared boundary:
-+  `84.9100565680358 tok/s`, `11.777681041849064 ms/token`.
-+
-+Decision:
-+
-+- Keep this as a validated opt-in incremental exact improvement.
-+- It is about `+2.85 tok/s` over the plain TP2/no-async control and
-+  `+1.24 tok/s` over the shared-boundary-only endpoint.
-+- It still does not materially approach the `>150 tok/s` goal.
-+- Do not spend much more time on tiny shared-expert epilogues. The next win
-+  needs to remove a larger fixed cost.
-+
-+Next best branches after this increment:
-+
-+1. Routed MoE persistent one-dispatch layerlet:
-+   keep route buffers, descriptors, scales, scratch, GEMM workspaces, and
-+   output buffers resident; fuse route/remap, quant, GEMM1, activation/quant,
-+   GEMM2, and gather/combine. Gate offline first with exact replay parity.
-+2. Exact speculation/oracle parity:
-+   repair k=1 token identity before attempting wider EAGLE/ngram acceptance.
-+   This remains the largest plausible no-quality-loss jump to `>150 tok/s`.
-+3. Async/PIECEWISE replay correctness:
-+   graph-none async is correct, but async+PIECEWISE corrupts canaries. The
-+   `N=8` eager workaround is correct but not faster. Treat this as a
-+   correctness branch, not a speed branch, unless a new replay ownership fix
-+   appears.
-+4. TP4 only after hardware health:
-+   device `3`/XCCL remains a blocker. Do not interpret TP4 endpoint speed
-+   until the preflight passes cleanly.
-+
-+## 2026-06-19 Addendum - Real Full-Layerlet Endpoint Gate
-+
-+Important correction:
-+
-+- The endpoint full-layerlet path is not enabled by
-+  `VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1` alone.
-+- It also requires the fused prologue offset gate:
-+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET=1`.
-+- Under graph capture, it should also use
-+  `VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE=1`.
-+- The accepted launcher clears experimental W8A8 flags unless
-+  `VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1`.
-+
-+Corrected endpoint identity tested:
-+
-+```bash
-+TP_SIZE=2
-+ONEAPI_DEVICE_SELECTOR=level_zero:0,1
-+ZE_AFFINITY_MASK=0,1
-+QWEN36_XPU_PREFLIGHT=0
-+COMPILATION_CONFIG='{"cudagraph_mode":"PIECEWISE"}'
-+XPU_GRAPH=1
-+VLLM_XPU_ENABLE_XPU_GRAPH=1
-+VLLM_XPU_FORCE_GRAPH_WITH_COMM=1
-+VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1
-+VLLM_XPU_GDN_NATIVE_FALLBACK=prefill
-+VLLM_EXTRA_ARGS='--no-async-scheduling --uvicorn-log-level warning'
-+GPU_MEMORY_UTILIZATION=0.90
-+VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW=1
-+VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET=1
-+VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE=1
-+VLLM_XPU_MOE_W8A8_FULL_LAYERLET=1
-+VLLM_XPU_MOE_W8A8_FUSED_Q1=1
-+VLLM_XPU_MOE_W8A8_ROUTE_GEMM1=1
-+VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT=1
-+VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL=1
-+```
-+
-+Operational lesson:
-+
-+- Killing the launcher can leave `VLLM::EngineCore` and `VLLM::Worker_TP*`
-+  processes alive, holding XPU memory.
-+- Check those process names before interpreting a low-free-memory launch
-+  failure as a model/config problem.
-+
-+Corrected run artifact:
-+
-+- Summary:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-q1-routefull-sharedgate-real-noasync-tp2-summary-20260619q1routefullshared3.json`
-+- Log:
-+  `/home/steve/llm-optimizations/data/qwen36-ablation-prefill-safe-int8-q1-routefull-sharedgate-real-noasync-tp2-20260619q1routefullshared3.log`
-+- JSON canary: passed `24/24`.
-+- Color canary: passed `24/24`.
-+- Corrected decode throughput: `82.4576360185309 tok/s`.
-+- Decode time: `12.135906462845014 ms/token`.
-+- TTFT: `268.7872141832486 ms`.
-+
-+Decision:
-+
-+- Reject this endpoint combination as a speed branch.
-+- It is correct under the canaries but slower than the validated shared gate/mul
-+  increment (`84.9100565680358 tok/s`) and only about equal to the plain
-+  TP2/no-async control.
-+- Do not promote full-layerlet + q1 + route-GEMM1 to endpoint default in this
-+  form.
-+- Continue with larger routed-MoE fixed-overhead work rather than more small
-+  q1/route/full-layerlet combinations.
-+
-+## 2026-06-19 Addendum - Sorted Active Helper And Q1 Direct Full-Layerlet Rejected
-+
-+Current installed XPU extension state after the latest rebuild:
-+
-+- Installed `_xpu_C.abi3.so` SHA256:
-+  `6201eb3b6088344f69faf215815bf34172d1f0a3b2454f3a2a764cfc4dff9b75`
-+- The temporary `128` local-size direct GEMM2/gather binary was reverted.
-+- Import sanity confirmed these symbols exist:
-+  `qwen36_topk_ids_to_active_expert_ids_int32_out`,
-+  `cutlass_grouped_gemm_w8a8_int8_active_offsets_interface`,
-+  `qwen36_moe_w8a8_full_layerlet`, and
-+  `qwen36_shared_expert_w8a8_out`.
-+
-+Sorted active-helper replay:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-active-offset-runtime-sortedactive-routes7-device0-20260619activepath5.json`
-+- Identity:
-+  real route capture from
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`,
-+  route starts `0,40,80,85,95,100,115`, device `0`,
-+  `VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM=1`,
-+  `VLLM_XPU_MOE_W8A8_FUSED_Q1=1`,
-+  `VLLM_XPU_MOE_W8A8_ROUTE_GEMM1=1`.
-+- Exactness: active-offset and offset candidates had `0.0` max diff against
-+  the XPU fused-MoE oracle on all checked routes.
-+- Promotion gate: failed.
-+  `rows_ready_for_endpoint_gate=0/7`,
-+  `worst_best_exact_nonreference_us_mean=222.65256`,
-+  target `160 us`.
-+- Route active-offset graph means were around `147.62-175.06 us`, but
-+  full prologue-inclusive host means remained around `202.87-223.79 us`.
-+- Decision: keep sorted active-helper as a correct diagnostic building block.
-+  Do not promote active-offset GEMM to the endpoint.
-+
-+Q1 + direct GEMM2/gather full-layerlet:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1direct-routes7-device0-20260619.json`
-+- Identity:
-+  same real route capture and route starts, device `0`,
-+  `VLLM_XPU_MOE_W8A8_FUSED_Q1=1`,
-+  `VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER=1`.
-+- Exactness: `full_layerlet_vs_xpu_fused_moe_max_abs_diff=0.0` and
-+  `full_layerlet_vs_rows_oracle_max_abs_diff=0.0` on all seven routes.
-+- Route full-layerlet host means:
-+  `193.65164, 169.30628, 181.80136, 162.99816, 188.18748, 175.80628,
-+  173.56040 us`.
-+- Promotion gate: failed.
-+  `rows_ready_for_endpoint_gate=0/7`,
-+  `worst_best_exact_nonreference_us_mean=193.65164`,
-+  target `160 us`.
-+- Decision: exact, but not fast enough; do not promote to endpoint.
-+
-+Direct GEMM2/gather local-size `128` diagnostic:
-+
-+- Artifact:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-full-layerlet-q1direct128-routes7-device0-20260619.json`
-+- Exactness: still `0.0` max diff on all seven routes.
-+- Promotion gate: failed.
-+  `rows_ready_for_endpoint_gate=0/7`,
-+  `worst_best_exact_nonreference_us_mean=193.2268`,
-+  target `160 us`.
-+- Route full-layerlet host means:
-+  `174.18024, 189.54988, 184.99260, 182.28184, 184.12160, 187.88224,
-+  193.22680 us`.
-+- Decision: rejected for speed and reverted. The installed binary is back to
-+  the `6201eb...` SHA above.
-+
-+Reviewed `/home/steve/suggestions.md` again:
-+
-+- Its highest-value live items still agree with the current direction:
-+  persistent/one-dispatch routed W8A8 MoE, exact oracle/spec parity, and TP4
-+  only after XPU/XCCL health.
-+- Several speed anchors in that file refer to the older TP4 async fast
-+  research base. Current endpoint comparisons should continue to use the
-+  safe TP2/no-async identity unless device `3` health is restored and the full
-+  benchmark identity matches.
-+
-+Current conclusion:
-+
-+- Small exact W8A8 MoE knobs are now closed for this cycle:
-+  active-offset, q1-only, fast gather, route-GEMM1, direct GEMM2/gather,
-+  DPAS GEMM2/gather, workspace atomic, route-class ordering, shared boundary,
-+  shared fused gate/mul, and the corrected endpoint full-layerlet combination.
-+- The next exact/no-quality-loss MoE branch must remove a larger boundary:
-+  a persistent/one-dispatch layerlet with resident descriptors/scratch/route
-+  buffers, or an equivalent deterministic DPAS pipeline that fuses route,
-+  quant, GEMM1, activation/quant2, GEMM2, and gather/combine under one
-+  replayable boundary.
-+- Endpoint work should resume only after the offline route gate consistently
-+  beats the current `~160-180 us` layerlet band with exact parity.
-+
-+## 2026-06-19 Addendum - oneDNN Sidecar Route Replay Rejected As Endpoint Path
-+
-+Harness update:
-+
-+- `scripts/bench-qwen36-int8-moe-kernels.py` now has an explicit
-+  `--enable-onednn-sidecar` diagnostic path.
-+- The wrapper runs fused prologue, quantizes the remapped hidden states, builds
-+  the oneDNN int32 end-only offsets, calls
-+  `qwen36_moe_onednn_sidecar_probe`, and then runs the normal weighted gather.
-+- The sidecar ABI has a legacy argument named `remapped_hidden_states`, but the
-+  C++ diagnostic validates it as the int8 GEMM1 input buffer; the Python wrapper
-+  now passes `gemm1_a` there and leaves the regular BF16 remap path unchanged.
-+- The sidecar is included in exactness checks, rows-oracle checks, timing JSON,
-+  markdown output, runtime identity, and the prologue-inclusive promotion gate.
-+
-+Artifacts:
-+
-+- Mode `23` smoke:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-onednn-sidecar-smoke-device0-20260619.json`
-+- Mode `33` smoke:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-onednn-sidecar-mode33-smoke-device0-20260619.json`
-+- Seven-route mode `33` replay:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-onednn-sidecar-mode33-routes7-device0-20260619.json`
-+- Seven-route markdown:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-onednn-sidecar-mode33-routes7-device0-20260619.md`
-+
-+Seven-route identity:
-+
-+- Route capture:
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`
-+- Route starts: `0,40,80,85,95,100,115`
-+- Device: `ONEAPI_DEVICE_SELECTOR=level_zero:0`, `ZE_AFFINITY_MASK=0`
-+- TP-size in replay math: `4`
-+- Iterations/warmup: `80/20`
-+- oneDNN sidecar mode: `33`
-+- `--real-routing-oracle` enabled
-+
-+Results:
-+
-+- Exactness: oneDNN sidecar had `0.0` max abs diff versus `xpu_fused_moe`
-+  and `0.0` max abs diff versus the rows-per-expert oracle on all seven routes.
-+- Promotion gate: failed.
-+  `rows_ready_for_endpoint_gate=0/7`,
-+  `status=exact_nonreference_candidates_exist_but_gate_not_met`,
-+  target `160 us`.
-+- Best exact non-reference stayed the current `full_layerlet`.
-+  Best route: `162.21985 us`; worst route: `174.2182 us`.
-+- oneDNN sidecar total means by route:
-+  `299.754, 314.4245, 303.52465, 305.75675, 306.969, 321.3886,
-+  319.8897 us`.
-+- oneDNN sidecar internal middle-wall means by route:
-+  `45.575, 47.725, 45.0625, 45.45, 45.975, 48.5125, 48.9625 us`.
-+
-+Decision:
-+
-+- Reject the current Python/C++ oneDNN sidecar wrapper as an endpoint path. It
-+  is exact, but the prologue-inclusive total is far slower than the current
-+  exact full-layerlet replay.
-+- Keep the `~45-49 us` internal middle-wall number as a diagnostic hint only.
-+  It says oneDNN's cached GEMM middle can be fast in isolation, but the current
-+  boundary does not remove enough fixed route/prologue/quant/gather overhead.
-+- Do not spend more time on this sidecar wrapper unless the next design makes it
-+  a single resident, graph-safe/persistent boundary rather than a Python-level
-+  chain with offset conversion and separate gather.
-+
-+Next best branch:
-+
-+- Return to the larger exact boundary: persistent/one-dispatch W8A8 MoE
-+  layerlet, or equivalent deterministic DPAS pipeline, where descriptors,
-+  scratch, route buffers, offsets, expert pointers, and output buffers stay
-+  resident and the per-token submission is one small route command.
-+- Secondary branch remains oracle/spec parity, but MoE still looks like the
-+  highest-probability no-quality-loss path.
-+
-+## 2026-06-20 Addendum - Unchecked Full-Layerlet Validation Bypass Rejected
-+
-+Diagnostic implementation:
-+
-+- Added guarded env flag
-+  `VLLM_XPU_MOE_W8A8_UNCHECKED_FULL_LAYERLET=1` in
-+  `/home/steve/src/vllm-xpu-kernels/csrc/xpu/moe_layerlet.cpp`.
-+- The flag bypasses the initial host-side dtype/device/shape validation inside
-+  `qwen36_moe_w8a8_full_layerlet`.
-+- Default behavior is unchanged when the flag is unset.
-+- Rebuilt and installed active `_xpu_C.abi3.so` with SHA:
-+  `c585bbb150720ff5d210205004f56f8e200f9d1f164192a042e329a8c5b22d06`.
-+
-+Artifacts:
-+
-+- Unchecked route-80 smoke:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-unchecked-q1-routegemm1-smoke-route80-device0-20260620.json`
-+- Same-binary checked route-80 control:
-+  `/home/steve/llm-optimizations/data/qwen36-int8-moe-layerlet-checked-q1-routegemm1-smoke-route80-device0-20260620.json`
-+
-+Identity:
-+
-+- Device: `ONEAPI_DEVICE_SELECTOR=level_zero:0`, `ZE_AFFINITY_MASK=0`
-+- Route capture:
-+  `/home/steve/llm-optimizations/data/qwen36-quark-int8-tp4-routecapture6-routes-rank0-20260611.jsonl`
-+- Route start: `80`
-+- TP-size in replay math: `4`
-+- Real-routing oracle enabled
-+- `VLLM_XPU_MOE_W8A8_FUSED_Q1=1`
-+- `VLLM_XPU_MOE_W8A8_ROUTE_GEMM1=1`
-+
-+Results:
-+
-+- Unchecked path exactness:
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff=0.0`,
-+  `full_layerlet_vs_rows_oracle_max_abs_diff=0.0`.
-+- Checked control exactness:
-+  `full_layerlet_vs_xpu_fused_moe_max_abs_diff=0.0`,
-+  `full_layerlet_vs_rows_oracle_max_abs_diff=0.0`.
-+- Unchecked route-80 full-layerlet host mean: `204.1338 us`.
-+- Checked route-80 full-layerlet host mean on the same active binary:
-+  `167.8508 us`.
-+- Both failed the `160 us` prologue-inclusive promotion target.
-+
-+Decision:
-+
-+- Reject unchecked host validation bypass as a speed path. It is exact, but it
-+  is slower than the checked control on the same route and binary.
-+- Keep the flag off by default. It can remain as a diagnostic guard, but it is
-+  not endpoint-promotable and should not be used in accepted benchmark
-+  identities.
-+- This closes another small-boundary branch. The next MoE optimization must
-+  remove actual kernel/queue/device-boundary work, not only host validation.
-+
-+Next branch:
-+
-+- Add a decisive internal timing trace for the current exact full-layerlet
-+  route-GEMM1/Q1 path, then use that to choose one larger fusion boundary.
-+- If the trace confirms GEMM2/gather or activation/quant2 launch overhead is
-+  the main local wall, prototype a resident one-dispatch layerlet around that
-+  boundary.
-+- If the trace says full-layerlet local work is already near the floor and the
-+  endpoint wall is elsewhere, pivot back to async/PIECEWISE correctness or
-+  exact verifier/spec parity rather than adding more MoE micro-knobs.
-diff --git a/notes/2026-06-17-eagle-path-to-150-tok-s-plan.md b/notes/2026-06-17-eagle-path-to-150-tok-s-plan.md
-index 027f7dd..c3979a0 100644
---- a/notes/2026-06-17-eagle-path-to-150-tok-s-plan.md
-+++ b/notes/2026-06-17-eagle-path-to-150-tok-s-plan.md
-@@ -337,3 +337,127 @@ Current best repair candidate:
-   to slot 2 after each verifier row, but normal decode promotion may still use
-   wrong conv/SSM timing or the wrong source after full-bonus emission.
- - Do not promote any speed result until oracle k=1 exact parity passes.
-+
-+## 2026-06-18 verifier state update
-+
-+Re-anchored the oracle identity:
-+
-+- Token-exact control requires the serial GDN flags:
-+  `VLLM_XPU_GDN_SERIAL_SPEC_DECODE=1`,
-+  `VLLM_XPU_GDN_SERIAL_SPEC_PACKED_DECODE=1`,
-+  `VLLM_XPU_GDN_SERIAL_SPEC_CONV=1`,
-+  `VLLM_XPU_GDN_SPEC_PROMOTE_RUNNING_AFTER_SPEC=1`, and
-+  `VLLM_XPU_GDN_SPEC_PROMOTE_CONV_STATE=1`.
-+- Current-tree run
-+  `qwen36-oracle-k8-draftonly-serial-restoredidentity-currenttree-eager-tp2-20260618b`
-+  is token-identical (`baseline_match_all=true`, first diff null, 24/24
-+  accepted). The gate still fails only because replay accounting reports known
-+  mismatches.
-+
-+Native prefill remains unsafe:
-+
-+- All-or-nothing rollback, final promotion, and replay-columns variants all
-+  failed first diff at token 17. The state after full accepted native-prefill
-+  groups is not safe for later ordinary decode. This is not solved by refusing
-+  partial groups.
-+- Next correctness work should either:
-+  1. repair native-prefill state columns/promotion until a full-accept group
-+     is serial-equivalent before ordinary decode; or
-+  2. optimize the exact serial GDN path and use that for verifier correctness
-+     while EAGLE/draft quality work continues.
-+
-+## 2026-06-18 verifier repair update 2
-+
-+Gate status:
-+
-+- Added an explicit accounting-noise escape hatch to the oracle gate:
-+  `ALLOW_REPLAY_ACCOUNTING_MISMATCH=1` passes
-+  `--allow-replay-accounting-mismatch` to
-+  `scripts/check-qwen36-oracle-fixture.py`.
-+- This option does not allow generated-token mismatches, malformed replay,
-+  missing request joins, or suppressed follow-up mismatches.
-+- Re-gated serial control
-+  `qwen36-oracle-k8-draftonly-serial-restoredidentity-currenttree-eager-tp2-20260618e`
-+  with that option and got an exact pass:
-+  `data/qwen36-oracle-k8-draftonly-serial-restoredidentity-currenttree-eager-tp2-20260618e-allowacct-gate-summary.json`.
-+
-+Negative native verifier probes:
-+
-+- All-or-nothing native prefill exact replay: first diff 17.
-+- No-preempt native prefill exact replay: first diff 24.
-+- Python/FLA exact replay output write: first diff 17.
-+- Native per-position exact replay output write: first diff 17.
-+- k=7 native prefill exact replay: first diff 24.
-+
-+Decision:
-+
-+- Stop treating native-prefill exact replay as the near-term path to >150 until
-+  a layer-level trace explains the `248068` boundary failure.
-+- Use the serial GDN verifier as the correctness anchor for the performance
-+  path. It is token-identical today; optimize around it or pair it with a
-+  lightweight EAGLE draft.
-+
-+Next performance candidates, in priority order:
-+
-+1. Measure serial-correct verifier speed under the fast PIECEWISE identity
-+   (TP2 first, then TP4 only if the identity is identical enough to compare).
-+2. Test whether serial GDN verifier can be captured or partially captured
-+   without losing token parity.
-+3. Continue EAGLE draft work with serial verifier only; any draft result must
-+   pass exact token parity before speed claims.
-+4. If serial verifier overhead is the bottleneck, prototype a native
-+   serial-equivalent one-token GDN verifier kernel rather than the unsafe
-+   native-prefill sequence.
-+
-+Serial verifier speed result:
-+
-+- Ran metrics-only PIECEWISE TP2 serial GDN oracle probe:
-+  `qwen36-ablation-serialgdn-oracle-k8-piecewise-tp2-metrics-20260618f`.
-+- Identity: TP2 (`0,1`), `XPU_GRAPH=1`,
-+  `VLLM_XPU_FORCE_GRAPH_WITH_COMM=1`,
-+  `VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE=1`,
-+  `COMPILATION_CONFIG={"cudagraph_mode":"PIECEWISE","max_cudagraph_capture_size":128}`,
-+  Quark W8A8 INT8, `VLLM_XPU_GDN_NATIVE_FALLBACK=prefill`,
-+  serial GDN flags on, oracle k=8, `VLLM_XPU_SPEC_DECODE_DRAFT_ONLY=1`.
-+- Metrics artifact:
-+  `data/qwen36-ablation-serialgdn-oracle-k8-piecewise-tp2-metrics-20260618f-summary-20260618192000.json`.
-+- Result: `14.03` corrected tok/s, `72.10` ms/token, E2E `13.69` tok/s.
-+- Decision: serial GDN is useful as a correctness anchor only. It is far too
-+  slow to be the route to >150 unless replaced with a native serial-equivalent
-+  verifier kernel. Do not spend time tuning high-level serial flags for speed.
-+
-+## 2026-06-18 EAGLE k5 result
-+
-+What worked:
-+
-+- Synthetic k5 acceptance is fast enough in the current PIECEWISE TP2 identity:
-+  `qwen36-ablation-eagle2-tokenheavy-synthaccept6-piecewise-tp2-k5-ceiling-20260618h`
-+  reached `181.91` corrected tok/s. This is not quality-valid, but it proves
-+  the scheduler/proposer path has enough headroom if draft acceptance is high.
-+
-+What failed:
-+
-+- Real k5 with the token-heavy EAGLE draft reached only `52.52` corrected tok/s
-+  and accepted `107/525` drafted tokens. Per-position acceptance collapsed after
-+  the third draft slot: `0.543, 0.314, 0.124, 0.038, 0.000`.
-+- Local-argmax draft token generation was negative:
-+  `qwen36-ablation-eagle2-tokenheavy-localargmax-pairreuse-piecewise-tp2-k3-smoke-20260618g`
-+  measured `54.74` corrected tok/s and reduced acceptance. Do not promote.
-+- Added `--rollout-steps` training support and produced
-+  `data/qwen36-eagle2-corpus2-tokenheavy-rollout5-trained-20260618h`, but the
-+  rollout k5 endpoint run measured only `55.70` corrected tok/s and accepted
-+  `80/445` drafted tokens. Per-position acceptance was
-+  `0.494, 0.303, 0.101, 0.000, 0.000`.
-+
-+Decision:
-+
-+- Keep EAGLE as a future path only if we first build a larger representative
-+  hidden-state dataset plus an offline acceptance evaluator. Endpoint smoke
-+  runs are too expensive and too noisy for draft-quality iteration.
-+- Do not run more small-dataset rollout fine-tunes expecting a single-session
-+  decode win. The current draft is not close to the acceptance needed for the
-+  `>150 tok/s` goal.
-+- Immediate next work should shift back to exact fast-lane bottlenecks:
-+  collectives/topology replay, XPU graph replay correctness, and MoE
-+  dispatch/GEMM overhead. Those preserve model output identity and attack the
-+  baseline `~93.55 tok/s` path directly.
-diff --git a/scripts/bench-qwen36-int8-moe-kernels.py b/scripts/bench-qwen36-int8-moe-kernels.py
-index 2f8efec..f85180f 100755
---- a/scripts/bench-qwen36-int8-moe-kernels.py
-+++ b/scripts/bench-qwen36-int8-moe-kernels.py
-@@ -10,10 +10,12 @@ next.
- from __future__ import annotations
- 
- import argparse
-+from contextlib import contextmanager
- import json
- import math
- import os
- import re
-+import sys
- from pathlib import Path
- from typing import Any
- 
-@@ -24,6 +26,7 @@ from vllm_xpu_kernels.fused_moe_interface import (
-     _normalize_int8_weight_scales,
-     _per_token_quant_int8,
-     fused_moe_activation,
-+    ref_fused_moe,
-     xpu_fused_moe,
- )
- 
-@@ -335,6 +338,12 @@ def make_prologue_scratch(
-         "active_expert_ids": torch.empty((num_experts),
-                                          device=device,
-                                          dtype=torch.int32),
-+        "onednn_offsets": torch.empty((num_experts),
-+                                      device=device,
-+                                      dtype=torch.int32),
-+        "topk_ids_i32": torch.empty((rows, topk),
-+                                    device=device,
-+                                    dtype=torch.int32),
-         "num_active_experts": 0,
-         "output": torch.empty((rows, hidden_size), device=device, dtype=dtype),
-         "gemm1_output": torch.empty((num_moe_inputs, 2 * inter_size),
-@@ -388,6 +397,119 @@ def record_call(fn):
-     return result, start, end
- 
- 
-+@contextmanager
-+def temporary_env(updates: dict[str, str | None]):
-+    previous = {key: os.environ.get(key) for key in updates}
-+    try:
-+        for key, value in updates.items():
-+            if value is None:
-+                os.environ.pop(key, None)
-+            else:
-+                os.environ[key] = value
-+        yield
-+    finally:
-+        for key, value in previous.items():
-+            if value is None:
-+                os.environ.pop(key, None)
-+            else:
-+                os.environ[key] = value
-+
-+
-+def max_abs_diff(left: torch.Tensor | None,
-+                 right: torch.Tensor | None) -> float | None:
-+    if left is None or right is None:
-+        return None
-+    return float((left - right).abs().max().item())
-+
-+
-+def build_synthetic_topk_ids(
-+    *,
-+    rows: int,
-+    topk: int,
-+    num_experts: int,
-+    mode: str,
-+    device: str,
-+) -> torch.Tensor:
-+    if mode == "uniform":
-+        ids = (
-+            torch.arange(rows * topk, device=device, dtype=torch.int64) %
-+            num_experts
-+        ).view(rows, topk)
-+        return ids.contiguous()
-+
-+    if mode == "hot_skew":
-+        hot_prefix = min(4, topk, num_experts)
-+        hot_pool = min(num_experts, max(topk + 8, 16))
-+        rows_out: list[list[int]] = []
-+        for row in range(rows):
-+            selected = list(range(hot_prefix))
-+            cursor = (row * 5) % max(1, hot_pool - hot_prefix)
-+            candidate = hot_prefix + cursor
-+            while len(selected) < topk:
-+                expert = candidate % hot_pool
-+                if expert not in selected:
-+                    selected.append(expert)
-+                candidate += 3
-+            rows_out.append(selected)
-+        return torch.tensor(rows_out, device=device, dtype=torch.int64)
-+
-+    raise ValueError(f"Unsupported synthetic route mode: {mode}")
-+
-+
-+def measure_graph_replay_us(
-+    name: str,
-+    fn,
-+    *,
-+    warmup: int,
-+    iterations: int,
-+) -> dict[str, Any]:
-+    if not hasattr(torch.xpu, "XPUGraph") or not hasattr(torch.xpu, "graph"):
-+        return {
-+            "name": name,
-+            "status": "unsupported",
-+            "us_mean": None,
-+            "iterations": 0,
-+            "warmup": warmup,
-+        }
-+
-+    try:
-+        for _ in range(warmup):
-+            fn()
-+        torch.xpu.synchronize()
-+
-+        graph = torch.xpu.XPUGraph()
-+        with torch.xpu.graph(graph):
-+            fn()
-+        torch.xpu.synchronize()
-+
-+        timings = []
-+        for _ in range(iterations):
-+            start, end = make_events()
-+            start.record()
-+            graph.replay()
-+            end.record()
-+            torch.xpu.synchronize()
-+            timings.append(elapsed_us(start, end))
-+
-+        return {
-+            "name": name,
-+            "status": "executed",
-+            "us_mean": sum(timings) / max(1, len(timings)),
-+            "iterations": iterations,
-+            "warmup": warmup,
-+        }
-+    except Exception as exc:  # noqa: BLE001 - graph failures are data.
-+        return {
-+            "name": name,
-+            "status": "error",
-+            "us_mean": None,
-+            "iterations": 0,
-+            "warmup": warmup,
-+            "error_type": type(exc).__name__,
-+            "error": str(exc),
-+        }
-+
-+
- def make_inputs(
-     *,
-     rows: int,
-@@ -398,6 +520,7 @@ def make_inputs(
-     dtype: torch.dtype,
-     device: str,
-     seed: int,
-+    synthetic_route_mode: str,
-     route_topk_rows: list[list[int]] | None = None,
-     route_start_index: int = 0,
- ) -> dict[str, torch.Tensor]:
-@@ -446,10 +569,13 @@ def make_inputs(
-                                 device=device,
-                                 dtype=torch.int64)
-     else:
--        topk_ids = (
--            torch.arange(rows * topk, device=device, dtype=torch.int64) %
--            num_experts
--        ).view(rows, topk)
-+        topk_ids = build_synthetic_topk_ids(
-+            rows=rows,
-+            topk=topk,
-+            num_experts=num_experts,
-+            mode=synthetic_route_mode,
-+            device=device,
-+        )
-     topk_weights = torch.rand((rows, topk),
-                               device=device,
-                               dtype=torch.float32)
-@@ -626,7 +752,7 @@ def make_scratch(
- 
- def make_xpu_scratch(scratch: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]:
-     """Adapt the manual scratch dict to xpu_fused_moe's scratch schema."""
--    return {
-+    xpu_scratch = {
-         "remapped_hidden_states": scratch["remapped_hidden_states"],
-         "gemm1_output": scratch["gemm1_output"],
-         "act_output": scratch["act_output"],
-@@ -638,6 +764,13 @@ def make_xpu_scratch(scratch: dict[str, torch.Tensor]) -> dict[str, torch.Tensor
-         "rows_per_expert": scratch["rows_per_expert"],
-         "unpermuted_row_to_permuted_row": scratch["unpermuted"],
-     }
-+    if "workspace" in scratch:
-+        xpu_scratch["prologue_workspace"] = scratch["workspace"]
-+    if "expert_offsets" in scratch:
-+        xpu_scratch["w8a8_offsets"] = scratch["expert_offsets"]
-+    if "active_expert_ids" in scratch:
-+        xpu_scratch["active_expert_ids"] = scratch["active_expert_ids"]
-+    return xpu_scratch
- 
- 
- def manual_int8_moe_preallocated_once(
-@@ -728,9 +861,18 @@ def manual_int8_moe_fused_prologue_once(
-     scratch: dict[str, Any],
-     use_offset_gemm: bool = False,
-     use_active_offset_gemm: bool = False,
-+    events: dict[str, tuple[torch.xpu.Event, torch.xpu.Event]] | None = None,
- ) -> torch.Tensor:
-     hidden_size = hidden_states.shape[1]
-     inter_size = w13.shape[-1] // 2
-+
-+    def run_stage(label: str, fn):
-+        if events is None:
-+            return fn()
-+        result, start, end = record_call(fn)
-+        events[label] = (start, end)
-+        return result
-+
-     offset_op = getattr(
-         torch.ops._xpu_C,
-         "cutlass_grouped_gemm_w8a8_int8_offsets_interface",
-@@ -750,127 +892,545 @@ def manual_int8_moe_fused_prologue_once(
-             "cutlass_grouped_gemm_w8a8_int8_active_offsets_interface is not available"
-         )
- 
--    torch.ops._moe_C.fused_moe_prologue(
--        input=hidden_states,
--        input_scales=None,
--        token_selected_experts=topk_ids,
--        token_final_scales=topk_weights,
--        workspace=scratch["workspace"],
--        hidden_size=hidden_size,
--        inter_size=inter_size,
--        block_k=1,
--        ep_rank=0,
--        ep_size=1,
--        num_experts_on_rank=num_experts,
-+    if events is None:
-+        torch.ops._moe_C.fused_moe_prologue(
-+            input=hidden_states,
-+            input_scales=None,
-+            token_selected_experts=topk_ids,
-+            token_final_scales=topk_weights,
-+            workspace=scratch["workspace"],
-+            hidden_size=hidden_size,
-+            inter_size=inter_size,
-+            block_k=1,
-+            ep_rank=0,
-+            ep_size=1,
-+            num_experts_on_rank=num_experts,
-+        )
-+        expert_offsets = scratch["expert_offsets"]
-+        if not use_offset_gemm and not use_active_offset_gemm:
-+            scratch["rows_per_expert"].copy_(
-+                (expert_offsets[1:1 + num_experts] -
-+                 expert_offsets[:num_experts]).to(torch.int32))
-+
-+        gemm1_a, gemm1_a_scales = _per_token_quant_int8_maybe_out(
-+            scratch["remapped_hidden_states"],
-+            scratch.get("gemm1_a"),
-+            scratch.get("gemm1_a_scales"),
-+        )
-+        gemm1_scales = _normalize_int8_weight_scales(w13_scales,
-+                                                     2 * inter_size)
-+        if use_active_offset_gemm:
-+            active_offset_op(
-+                ptr_A=gemm1_a,
-+                ptr_A_scales=gemm1_a_scales,
-+                ptr_B=w13,
-+                ptr_B_scales=gemm1_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm1_output"],
-+                expert_first_token_offset=expert_offsets,
-+                active_expert_ids=scratch["active_expert_ids"],
-+                N=2 * inter_size,
-+                K=hidden_size,
-+                num_experts=num_experts,
-+                num_active_experts=int(scratch["num_active_experts"]),
-+            )
-+        elif use_offset_gemm:
-+            offset_op(
-+                ptr_A=gemm1_a,
-+                ptr_A_scales=gemm1_a_scales,
-+                ptr_B=w13,
-+                ptr_B_scales=gemm1_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm1_output"],
-+                expert_first_token_offset=expert_offsets,
-+                N=2 * inter_size,
-+                K=hidden_size,
-+                num_experts=num_experts,
-+            )
-+        else:
-+            torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_interface(
-+                ptr_A=gemm1_a,
-+                ptr_A_scales=gemm1_a_scales,
-+                ptr_B=w13,
-+                ptr_B_scales=gemm1_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm1_output"],
-+                rows_per_expert=scratch["rows_per_expert"],
-+                N=2 * inter_size,
-+                K=hidden_size,
-+                num_experts=num_experts,
-+            )
-+        fused_moe_activation(scratch["act_output"], scratch["gemm1_output"],
-+                             "silu")
-+        gemm2_a, gemm2_a_scales = _per_token_quant_int8_maybe_out(
-+            scratch["act_output"],
-+            scratch.get("gemm2_a"),
-+            scratch.get("gemm2_a_scales"),
-+        )
-+        gemm2_scales = _normalize_int8_weight_scales(w2_scales, hidden_size)
-+        if use_active_offset_gemm:
-+            active_offset_op(
-+                ptr_A=gemm2_a,
-+                ptr_A_scales=gemm2_a_scales,
-+                ptr_B=w2,
-+                ptr_B_scales=gemm2_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm2_output"],
-+                expert_first_token_offset=expert_offsets,
-+                active_expert_ids=scratch["active_expert_ids"],
-+                N=hidden_size,
-+                K=inter_size,
-+                num_experts=num_experts,
-+                num_active_experts=int(scratch["num_active_experts"]),
-+            )
-+        elif use_offset_gemm:
-+            offset_op(
-+                ptr_A=gemm2_a,
-+                ptr_A_scales=gemm2_a_scales,
-+                ptr_B=w2,
-+                ptr_B_scales=gemm2_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm2_output"],
-+                expert_first_token_offset=expert_offsets,
-+                N=hidden_size,
-+                K=inter_size,
-+                num_experts=num_experts,
-+            )
-+        else:
-+            torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_interface(
-+                ptr_A=gemm2_a,
-+                ptr_A_scales=gemm2_a_scales,
-+                ptr_B=w2,
-+                ptr_B_scales=gemm2_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm2_output"],
-+                rows_per_expert=scratch["rows_per_expert"],
-+                N=hidden_size,
-+                K=inter_size,
-+                num_experts=num_experts,
-+            )
-+        torch.ops._moe_C.moe_gather(scratch["output"],
-+                                    scratch["gemm2_output"], topk_weights,
-+                                    scratch["unpermuted"], num_experts)
-+        return scratch["output"]
-+
-+    run_stage(
-+        "prologue",
-+        lambda: torch.ops._moe_C.fused_moe_prologue(
-+            input=hidden_states,
-+            input_scales=None,
-+            token_selected_experts=topk_ids,
-+            token_final_scales=topk_weights,
-+            workspace=scratch["workspace"],
-+            hidden_size=hidden_size,
-+            inter_size=inter_size,
-+            block_k=1,
-+            ep_rank=0,
-+            ep_size=1,
-+            num_experts_on_rank=num_experts,
-+        ),
-     )
-     expert_offsets = scratch["expert_offsets"]
-     if not use_offset_gemm and not use_active_offset_gemm:
--        scratch["rows_per_expert"].copy_(
--            (expert_offsets[1:1 + num_experts] -
--             expert_offsets[:num_experts]).to(torch.int32))
-+        run_stage(
-+            "rows_from_offsets",
-+            lambda: scratch["rows_per_expert"].copy_(
-+                (expert_offsets[1:1 + num_experts] -
-+                 expert_offsets[:num_experts]).to(torch.int32)),
-+        )
- 
--    gemm1_a, gemm1_a_scales = _per_token_quant_int8_maybe_out(
--        scratch["remapped_hidden_states"],
--        scratch.get("gemm1_a"),
--        scratch.get("gemm1_a_scales"),
-+    gemm1_a, gemm1_a_scales = run_stage(
-+        "quant1",
-+        lambda: _per_token_quant_int8_maybe_out(
-+            scratch["remapped_hidden_states"],
-+            scratch.get("gemm1_a"),
-+            scratch.get("gemm1_a_scales"),
-+        ),
-     )
-     gemm1_scales = _normalize_int8_weight_scales(w13_scales, 2 * inter_size)
-     if use_active_offset_gemm:
--        active_offset_op(
--            ptr_A=gemm1_a,
--            ptr_A_scales=gemm1_a_scales,
--            ptr_B=w13,
--            ptr_B_scales=gemm1_scales,
--            ptr_bias=None,
--            ptr_D=scratch["gemm1_output"],
--            expert_first_token_offset=expert_offsets,
--            active_expert_ids=scratch["active_expert_ids"],
--            N=2 * inter_size,
--            K=hidden_size,
--            num_experts=num_experts,
--            num_active_experts=int(scratch["num_active_experts"]),
-+        run_stage(
-+            "gemm1",
-+            lambda: active_offset_op(
-+                ptr_A=gemm1_a,
-+                ptr_A_scales=gemm1_a_scales,
-+                ptr_B=w13,
-+                ptr_B_scales=gemm1_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm1_output"],
-+                expert_first_token_offset=expert_offsets,
-+                active_expert_ids=scratch["active_expert_ids"],
-+                N=2 * inter_size,
-+                K=hidden_size,
-+                num_experts=num_experts,
-+                num_active_experts=int(scratch["num_active_experts"]),
-+            ),
-         )
-     elif use_offset_gemm:
--        offset_op(
--            ptr_A=gemm1_a,
--            ptr_A_scales=gemm1_a_scales,
--            ptr_B=w13,
--            ptr_B_scales=gemm1_scales,
--            ptr_bias=None,
--            ptr_D=scratch["gemm1_output"],
--            expert_first_token_offset=expert_offsets,
--            N=2 * inter_size,
--            K=hidden_size,
--            num_experts=num_experts,
-+        run_stage(
-+            "gemm1",
-+            lambda: offset_op(
-+                ptr_A=gemm1_a,
-+                ptr_A_scales=gemm1_a_scales,
-+                ptr_B=w13,
-+                ptr_B_scales=gemm1_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm1_output"],
-+                expert_first_token_offset=expert_offsets,
-+                N=2 * inter_size,
-+                K=hidden_size,
-+                num_experts=num_experts,
-+            ),
-         )
-     else:
--        torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_interface(
--            ptr_A=gemm1_a,
--            ptr_A_scales=gemm1_a_scales,
--            ptr_B=w13,
--            ptr_B_scales=gemm1_scales,
--            ptr_bias=None,
--            ptr_D=scratch["gemm1_output"],
--            rows_per_expert=scratch["rows_per_expert"],
--            N=2 * inter_size,
--            K=hidden_size,
--            num_experts=num_experts,
-+        run_stage(
-+            "gemm1",
-+            lambda: torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_interface(
-+                ptr_A=gemm1_a,
-+                ptr_A_scales=gemm1_a_scales,
-+                ptr_B=w13,
-+                ptr_B_scales=gemm1_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm1_output"],
-+                rows_per_expert=scratch["rows_per_expert"],
-+                N=2 * inter_size,
-+                K=hidden_size,
-+                num_experts=num_experts,
-+            ),
-         )
--    fused_moe_activation(scratch["act_output"], scratch["gemm1_output"],
--                         "silu")
--    gemm2_a, gemm2_a_scales = _per_token_quant_int8_maybe_out(
--        scratch["act_output"],
--        scratch.get("gemm2_a"),
--        scratch.get("gemm2_a_scales"),
-+    run_stage(
-+        "activation",
-+        lambda: fused_moe_activation(scratch["act_output"],
-+                                     scratch["gemm1_output"], "silu"),
-+    )
-+    gemm2_a, gemm2_a_scales = run_stage(
-+        "quant2",
-+        lambda: _per_token_quant_int8_maybe_out(
-+            scratch["act_output"],
-+            scratch.get("gemm2_a"),
-+            scratch.get("gemm2_a_scales"),
-+        ),
-     )
-     gemm2_scales = _normalize_int8_weight_scales(w2_scales, hidden_size)
-     if use_active_offset_gemm:
--        active_offset_op(
--            ptr_A=gemm2_a,
--            ptr_A_scales=gemm2_a_scales,
--            ptr_B=w2,
--            ptr_B_scales=gemm2_scales,
--            ptr_bias=None,
--            ptr_D=scratch["gemm2_output"],
--            expert_first_token_offset=expert_offsets,
--            active_expert_ids=scratch["active_expert_ids"],
--            N=hidden_size,
--            K=inter_size,
--            num_experts=num_experts,
--            num_active_experts=int(scratch["num_active_experts"]),
-+        run_stage(
-+            "gemm2",
-+            lambda: active_offset_op(
-+                ptr_A=gemm2_a,
-+                ptr_A_scales=gemm2_a_scales,
-+                ptr_B=w2,
-+                ptr_B_scales=gemm2_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm2_output"],
-+                expert_first_token_offset=expert_offsets,
-+                active_expert_ids=scratch["active_expert_ids"],
-+                N=hidden_size,
-+                K=inter_size,
-+                num_experts=num_experts,
-+                num_active_experts=int(scratch["num_active_experts"]),
-+            ),
-         )
-     elif use_offset_gemm:
--        offset_op(
--            ptr_A=gemm2_a,
--            ptr_A_scales=gemm2_a_scales,
--            ptr_B=w2,
--            ptr_B_scales=gemm2_scales,
--            ptr_bias=None,
--            ptr_D=scratch["gemm2_output"],
--            expert_first_token_offset=expert_offsets,
--            N=hidden_size,
--            K=inter_size,
--            num_experts=num_experts,
-+        run_stage(
-+            "gemm2",
-+            lambda: offset_op(
-+                ptr_A=gemm2_a,
-+                ptr_A_scales=gemm2_a_scales,
-+                ptr_B=w2,
-+                ptr_B_scales=gemm2_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm2_output"],
-+                expert_first_token_offset=expert_offsets,
-+                N=hidden_size,
-+                K=inter_size,
-+                num_experts=num_experts,
-+            ),
-         )
-     else:
--        torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_interface(
--            ptr_A=gemm2_a,
--            ptr_A_scales=gemm2_a_scales,
--            ptr_B=w2,
--            ptr_B_scales=gemm2_scales,
--            ptr_bias=None,
--            ptr_D=scratch["gemm2_output"],
--            rows_per_expert=scratch["rows_per_expert"],
--            N=hidden_size,
--            K=inter_size,
--            num_experts=num_experts,
-+        run_stage(
-+            "gemm2",
-+            lambda: torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_interface(
-+                ptr_A=gemm2_a,
-+                ptr_A_scales=gemm2_a_scales,
-+                ptr_B=w2,
-+                ptr_B_scales=gemm2_scales,
-+                ptr_bias=None,
-+                ptr_D=scratch["gemm2_output"],
-+                rows_per_expert=scratch["rows_per_expert"],
-+                N=hidden_size,
-+                K=inter_size,
-+                num_experts=num_experts,
-+            ),
-         )
-+    run_stage(
-+        "gather",
-+        lambda: torch.ops._moe_C.moe_gather(
-+            scratch["output"],
-+            scratch["gemm2_output"],
-+            topk_weights,
-+            scratch["unpermuted"],
-+            num_experts,
-+        ),
-+    )
-+    return scratch["output"]
-+
-+
-+def manual_int8_moe_fused_prologue_middle_layerlet_once(
-+    *,
-+    hidden_states: torch.Tensor,
-+    w13: torch.Tensor,
-+    w13_scales: torch.Tensor,
-+    w2: torch.Tensor,
-+    w2_scales: torch.Tensor,
-+    topk_weights: torch.Tensor,
-+    topk_ids: torch.Tensor,
-+    num_experts: int,
-+    topk: int,
-+    scratch: dict[str, Any],
-+) -> torch.Tensor:
-+    hidden_size = hidden_states.shape[1]
-+    inter_size = w13.shape[-1] // 2
-+    middle_layerlet_op = getattr(
-+        torch.ops._xpu_C,
-+        "qwen36_moe_w8a8_middle_layerlet",
-+        None,
-+    )
-+    if middle_layerlet_op is None:
-+        raise RuntimeError("qwen36_moe_w8a8_middle_layerlet is not available")
-+
-+    torch.ops._moe_C.fused_moe_prologue(
-+        input=hidden_states,
-+        input_scales=None,
-+        token_selected_experts=topk_ids,
-+        token_final_scales=topk_weights,
-+        workspace=scratch["workspace"],
-+        hidden_size=hidden_size,
-+        inter_size=inter_size,
-+        block_k=1,
-+        ep_rank=0,
-+        ep_size=1,
-+        num_experts_on_rank=num_experts,
-+    )
-+    gemm1_a, gemm1_a_scales = _per_token_quant_int8_maybe_out(
-+        scratch["remapped_hidden_states"],
-+        scratch.get("gemm1_a"),
-+        scratch.get("gemm1_a_scales"),
-+    )
-+    middle_layerlet_op(
-+        gemm1_a,
-+        gemm1_a_scales,
-+        w13,
-+        _normalize_int8_weight_scales(w13_scales, 2 * inter_size),
-+        None,
-+        scratch["gemm1_output"],
-+        scratch["gemm2_a"],
-+        scratch["gemm2_a_scales"],
-+        w2,
-+        _normalize_int8_weight_scales(w2_scales, hidden_size),
-+        None,
-+        scratch["gemm2_output"],
-+        scratch["expert_offsets"],
-+        2 * inter_size,
-+        hidden_size,
-+        hidden_size,
-+        inter_size,
-+        num_experts,
-+    )
-     torch.ops._moe_C.moe_gather(scratch["output"], scratch["gemm2_output"],
-                                 topk_weights, scratch["unpermuted"],
-                                 num_experts)
-     return scratch["output"]
- 
- 
-+def manual_int8_moe_full_layerlet_once(
-+    *,
-+    hidden_states: torch.Tensor,
-+    w13: torch.Tensor,
-+    w13_scales: torch.Tensor,
-+    w2: torch.Tensor,
-+    w2_scales: torch.Tensor,
-+    topk_weights: torch.Tensor,
-+    topk_ids: torch.Tensor,
-+    num_experts: int,
-+    topk: int,
-+    scratch: dict[str, Any],
-+) -> torch.Tensor:
-+    hidden_size = hidden_states.shape[1]
-+    inter_size = w13.shape[-1] // 2
-+    full_layerlet_op = getattr(
-+        torch.ops._xpu_C,
-+        "qwen36_moe_w8a8_full_layerlet",
-+        None,
-+    )
-+    if full_layerlet_op is None:
-+        raise RuntimeError("qwen36_moe_w8a8_full_layerlet is not available")
-+    full_layerlet_op(
-+        hidden_states,
-+        topk_ids,
-+        topk_weights,
-+        scratch["workspace"],
-+        scratch["remapped_hidden_states"],
-+        scratch["unpermuted"].view(-1),
-+        scratch["expert_offsets"],
-+        scratch["gemm1_a"],
-+        scratch["gemm1_a_scales"],
-+        w13,
-+        _normalize_int8_weight_scales(w13_scales, 2 * inter_size),
-+        None,
-+        scratch["gemm1_output"],
-+        scratch["gemm2_a"],
-+        scratch["gemm2_a_scales"],
-+        w2,
-+        _normalize_int8_weight_scales(w2_scales, hidden_size),
-+        None,
-+        scratch["gemm2_output"],
-+        scratch["output"],
-+        hidden_size,
-+        inter_size,
-+        num_experts,
-+    )
-+    return scratch["output"]
-+
-+
-+SIDECAR_STATS_NAMES = (
-+    "ok",
-+    "device_index",
-+    "layer_index",
-+    "num_rows",
-+    "topk",
-+    "num_moe_inputs",
-+    "hidden_size",
-+    "inter_size",
-+    "num_experts",
-+    "gemm1_n",
-+    "gemm2_n",
-+    "dry_create_descriptors",
-+    "descriptor_create_ok",
-+    "offsets_supplied",
-+    "handle_wrap_ok",
-+    "w13_stride0",
-+    "w13_stride1",
-+    "w13_stride2",
-+    "w2_stride0",
-+    "w2_stride1",
-+    "requested_execute_mode",
-+    "execute_ok",
-+    "execute_construct_us",
-+    "execute_wait_us",
-+    "gemm1_cache_hit",
-+    "gemm1_construct_us",
-+    "gemm1_execute_us",
-+    "gemm2_cache_hit",
-+    "gemm2_construct_us",
-+    "gemm2_execute_us",
-+    "both_wall_us",
-+    "sidecar_matmul_cache_size",
-+    "gemm1_wait_after_execute",
-+    "gemm2_wait_after_execute",
-+    "cached_execution_path",
-+    "middle_activation_quant_us",
-+    "middle_wall_us",
-+    "reserved37",
-+    "reserved38",
-+    "reserved39",
-+)
-+
-+
-+def sidecar_stats_dict(stats: torch.Tensor | None) -> dict[str, int] | None:
-+    if stats is None:
-+        return None
-+    values = [int(item) for item in stats.detach().cpu().tolist()]
-+    return {
-+        name: values[index] if index < len(values) else 0
-+        for index, name in enumerate(SIDECAR_STATS_NAMES)
-+    }
-+
-+
-+def manual_int8_moe_onednn_sidecar_once(
-+    *,
-+    hidden_states: torch.Tensor,
-+    w13: torch.Tensor,
-+    w13_scales: torch.Tensor,
-+    w2: torch.Tensor,
-+    w2_scales: torch.Tensor,
-+    topk_weights: torch.Tensor,
-+    topk_ids: torch.Tensor,
-+    num_experts: int,
-+    topk: int,
-+    scratch: dict[str, Any],
-+    execute_mode: int = 23,
-+) -> tuple[torch.Tensor, dict[str, int] | None]:
-+    hidden_size = hidden_states.shape[1]
-+    inter_size = w13.shape[-1] // 2
-+    sidecar_op = getattr(
-+        torch.ops._xpu_C,
-+        "qwen36_moe_onednn_sidecar_probe",
-+        None,
-+    )
-+    if sidecar_op is None:
-+        raise RuntimeError("qwen36_moe_onednn_sidecar_probe is not available")
-+
-+    torch.ops._moe_C.fused_moe_prologue(
-+        input=hidden_states,
-+        input_scales=None,
-+        token_selected_experts=topk_ids,
-+        token_final_scales=topk_weights,
-+        workspace=scratch["workspace"],
-+        hidden_size=hidden_size,
-+        inter_size=inter_size,
-+        block_k=1,
-+        ep_rank=0,
-+        ep_size=1,
-+        num_experts_on_rank=num_experts,
-+    )
-+    _per_token_quant_int8_maybe_out(
-+        scratch["remapped_hidden_states"],
-+        scratch["gemm1_a"],
-+        scratch["gemm1_a_scales"],
-+    )
-+
-+    # oneDNN grouped matmul uses end-only int32 offsets, while the CUTLASS path
-+    # uses leading-zero int64 offsets. Keep this diagnostic conversion explicit
-+    # so it is counted in the full sidecar timing.
-+    scratch["onednn_offsets"].copy_(scratch["expert_offsets"][1:].to(torch.int32))
-+    scratch["topk_ids_i32"].copy_(topk_ids.to(torch.int32))
-+
-+    stats = sidecar_op(
-+        hidden_states,
-+        topk_weights,
-+        scratch["topk_ids_i32"],
-+        w13,
-+        _normalize_int8_weight_scales(w13_scales, 2 * inter_size),
-+        w2,
-+        _normalize_int8_weight_scales(w2_scales, hidden_size),
-+        scratch["output"],
-+        # The sidecar ABI names this argument remapped_hidden_states, but the
-+        # C++ diagnostic expects the int8 quantized GEMM1 input buffer here.
-+        scratch["gemm1_a"],
-+        scratch["rows_per_expert"],
-+        scratch["unpermuted"],
-+        scratch["gemm1_a"],
-+        scratch["gemm1_a_scales"],
-+        scratch["gemm1_output"],
-+        scratch["act_output"],
-+        scratch["gemm2_a"],
-+        scratch["gemm2_a_scales"],
-+        scratch["gemm2_output"],
-+        scratch["onednn_offsets"],
-+        -1,
-+        True,
-+        int(execute_mode),
-+    )
-+    torch.ops._moe_C.moe_gather(
-+        scratch["output"],
-+        scratch["gemm2_output"],
-+        topk_weights,
-+        scratch["unpermuted"],
-+        num_experts,
-+    )
-+    return scratch["output"], sidecar_stats_dict(stats)
-+
-+
- def summarize_topk_ids(topk_ids: torch.Tensor, topn: int = 16) -> dict[str, Any]:
-     topk_cpu = topk_ids.detach().cpu().tolist()
-     tuple_counts: dict[tuple[int, ...], int] = {}
-@@ -881,6 +1441,7 @@ def summarize_topk_ids(topk_ids: torch.Tensor, topn: int = 16) -> dict[str, Any]
-         for expert in row_tuple:
-             expert_counts[expert] = expert_counts.get(expert, 0) + 1
-     return {
-+        "topk_rows": topk_cpu[:topn],
-         "unique_topk_tuples": len(tuple_counts),
-         "active_experts": len(expert_counts),
-         "top_experts": [
-@@ -898,6 +1459,65 @@ def summarize_topk_ids(topk_ids: torch.Tensor, topn: int = 16) -> dict[str, Any]
-     }
- 
- 
-+def collect_runtime_identity(args) -> dict[str, Any]:
-+    env_keys = [
-+        "ONEAPI_DEVICE_SELECTOR",
-+        "ZE_AFFINITY_MASK",
-+        "VLLM_XPU_W8A8_GROUPED_GEMM_POLICY",
-+        "VLLM_XPU_W8A8_GROUPED_GEMM_N_LT_K_POLICY",
-+        "VLLM_XPU_W8A8_GROUPED_GEMM_N_GT_K_POLICY",
-+        "VLLM_XPU_MOE_W8A8_FUSED_Q1",
-+        "VLLM_XPU_MOE_W8A8_FAST_GATHER",
-+        "VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER",
-+        "VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER",
-+        "VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE",
-+        "VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC",
-+        "VLLM_XPU_MOE_W8A8_ROUTE_GEMM1",
-+        "VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE",
-+        "VLLM_XPU_MOE_W8A8_UNCHECKED_FULL_LAYERLET",
-+        "VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM",
-+        "VLLM_XPU_FUSED_MOE_FUSE_SILU_QUANT",
-+        "SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS",
-+        "UR_L0_USE_IMMEDIATE_COMMANDLISTS",
-+        "UR_L0_USE_COPY_ENGINE",
-+    ]
-+    xpu_count = None
-+    xpu_devices: list[str] = []
-+    try:
-+        xpu_count = int(torch.xpu.device_count())
-+        for idx in range(xpu_count):
-+            try:
-+                xpu_devices.append(str(torch.xpu.get_device_name(idx)))
-+            except Exception as exc:  # noqa: BLE001 - diagnostic only.
-+                xpu_devices.append(f"unavailable:{type(exc).__name__}")
-+    except Exception as exc:  # noqa: BLE001 - diagnostic only.
-+        xpu_devices.append(f"device_count_error:{type(exc).__name__}:{exc}")
-+
-+    loaded_extensions = {
-+        name: getattr(module, "__file__", None)
-+        for name, module in sorted(sys.modules.items())
-+        if name.startswith("vllm_xpu_kernels")
-+    }
-+
-+    return {
-+        "argv": sys.argv,
-+        "torch_version": torch.__version__,
-+        "xpu_device_count": xpu_count,
-+        "xpu_devices": xpu_devices,
-+        "env": {key: os.environ.get(key) for key in env_keys},
-+        "python": sys.executable,
-+        "loaded_extensions": loaded_extensions,
-+        "dtype": args.dtype,
-+        "device_arg": args.device,
-+        "iterations": args.iterations,
-+        "warmup": args.warmup,
-+        "graph_replay_timing": bool(args.graph_replay_timing),
-+        "stage_timing_iterations": args.stage_timing_iterations,
-+        "enable_onednn_sidecar": bool(args.enable_onednn_sidecar),
-+        "onednn_sidecar_mode": int(args.onednn_sidecar_mode),
-+    }
-+
-+
- def benchmark_rows(
-     args,
-     text_config: dict[str, Any],
-@@ -922,6 +1542,7 @@ def benchmark_rows(
-         dtype=dtype,
-         device=args.device,
-         seed=args.seed + rows,
-+        synthetic_route_mode=args.synthetic_route_mode,
-         route_topk_rows=route_topk_rows,
-         route_start_index=route_start_index,
-     )
-@@ -960,6 +1581,83 @@ def benchmark_rows(
-         num_experts=num_experts,
-         is_int8=True,
-     )
-+
-+    rows_oracle_output: torch.Tensor | None = None
-+    offset_oracle_output: torch.Tensor | None = None
-+    bf16_reference_output: torch.Tensor | None = None
-+    rows_oracle_env = {
-+        "VLLM_XPU_FUSED_MOE_USE_REF": "0",
-+        "VLLM_XPU_W8A8_USE_OFFSETS": "0",
-+        "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET": "0",
-+        "VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET": "0",
-+        "VLLM_XPU_MOE_W8A8_FULL_LAYERLET": "0",
-+    }
-+    offset_oracle_env = {
-+        **rows_oracle_env,
-+        "VLLM_XPU_W8A8_USE_OFFSETS": "1",
-+    }
-+    offset_gemm_available = hasattr(
-+        torch.ops._xpu_C,
-+        "cutlass_grouped_gemm_w8a8_int8_offsets_interface",
-+    )
-+    if args.real_routing_oracle:
-+        with temporary_env(rows_oracle_env):
-+            rows_oracle_output = xpu_fused_moe(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w13_bias=None,
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                w2_bias=None,
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                n_experts_per_token=topk,
-+                activation="silu",
-+                num_experts=num_experts,
-+                is_int8=True,
-+            )
-+        if offset_gemm_available:
-+            with temporary_env(offset_oracle_env):
-+                offset_oracle_output = xpu_fused_moe(
-+                    hidden_states=inputs["hidden_states"],
-+                    w13=inputs["w13"],
-+                    w13_scales=inputs["w13_scales"],
-+                    w13_bias=None,
-+                    w2=inputs["w2"],
-+                    w2_scales=inputs["w2_scales"],
-+                    w2_bias=None,
-+                    topk_weights=inputs["topk_weights"],
-+                    topk_ids=inputs["topk_ids"],
-+                    n_experts_per_token=topk,
-+                    activation="silu",
-+                    num_experts=num_experts,
-+                    is_int8=True,
-+                )
-+        if args.real_routing_bf16_reference:
-+            bf16_reference_output = ref_fused_moe(
-+                recipe="int8",
-+                x=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w13_bias=None,
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                w2_bias=None,
-+                expert_weights=inputs["topk_weights"],
-+                expert_indices=inputs["topk_ids"],
-+                num_per_tok=topk,
-+                activation="silu",
-+                num_experts=num_experts,
-+            )
-+        torch.xpu.synchronize()
-+    xpu_fused_moe_rows_oracle_max_abs_diff = max_abs_diff(
-+        ref_output, rows_oracle_output)
-+    offset_oracle_rows_oracle_max_abs_diff = max_abs_diff(
-+        offset_oracle_output, rows_oracle_output)
-+    rows_oracle_bf16_reference_max_abs_diff = max_abs_diff(
-+        rows_oracle_output, bf16_reference_output)
-+
-     manual_output, _ = manual_int8_moe_once(
-         hidden_states=inputs["hidden_states"],
-         w13=inputs["w13"],
-@@ -972,7 +1670,10 @@ def benchmark_rows(
-         topk=topk,
-     )
-     torch.xpu.synchronize()
--    max_abs_diff = float((ref_output - manual_output).abs().max().item())
-+    manual_max_abs_diff = float(
-+        (ref_output - manual_output).abs().max().item())
-+    manual_rows_oracle_max_abs_diff = max_abs_diff(manual_output,
-+                                                   rows_oracle_output)
- 
-     scratch = make_scratch(
-         rows=rows,
-@@ -998,6 +1699,8 @@ def benchmark_rows(
-     torch.xpu.synchronize()
-     prealloc_max_abs_diff = float(
-         (ref_output - scratch_output).abs().max().item())
-+    prealloc_rows_oracle_max_abs_diff = max_abs_diff(scratch_output,
-+                                                     rows_oracle_output)
-     prologue_scratch = make_prologue_scratch(
-         rows=rows,
-         hidden_size=hidden_size,
-@@ -1023,16 +1726,40 @@ def benchmark_rows(
-     torch.xpu.synchronize()
-     prologue_max_abs_diff = float(
-         (ref_output - prologue_output).abs().max().item())
--    offset_gemm_available = hasattr(
--        torch.ops._xpu_C,
--        "cutlass_grouped_gemm_w8a8_int8_offsets_interface",
--    )
-+    prologue_rows_oracle_max_abs_diff = max_abs_diff(prologue_output,
-+                                                     rows_oracle_output)
-     active_offset_gemm_available = hasattr(
-         torch.ops._xpu_C,
-         "cutlass_grouped_gemm_w8a8_int8_active_offsets_interface",
-     )
-+    middle_layerlet_available = hasattr(
-+        torch.ops._xpu_C,
-+        "qwen36_moe_w8a8_middle_layerlet",
-+    )
-+    full_layerlet_available = hasattr(
-+        torch.ops._xpu_C,
-+        "qwen36_moe_w8a8_full_layerlet",
-+    )
-+    onednn_sidecar_available = hasattr(
-+        torch.ops._xpu_C,
-+        "qwen36_moe_onednn_sidecar_probe",
-+    )
-     prologue_offset_max_abs_diff: float | None = None
-     prologue_active_offset_max_abs_diff: float | None = None
-+    prologue_middle_layerlet_max_abs_diff: float | None = None
-+    full_layerlet_max_abs_diff: float | None = None
-+    onednn_sidecar_max_abs_diff: float | None = None
-+    prologue_offset_rows_oracle_max_abs_diff: float | None = None
-+    prologue_active_offset_rows_oracle_max_abs_diff: float | None = None
-+    prologue_middle_layerlet_rows_oracle_max_abs_diff: float | None = None
-+    full_layerlet_rows_oracle_max_abs_diff: float | None = None
-+    onednn_sidecar_rows_oracle_max_abs_diff: float | None = None
-+    prologue_offset_output: torch.Tensor | None = None
-+    prologue_active_offset_output: torch.Tensor | None = None
-+    prologue_middle_layerlet_output: torch.Tensor | None = None
-+    full_layerlet_output: torch.Tensor | None = None
-+    onednn_sidecar_output: torch.Tensor | None = None
-+    onednn_sidecar_stats_once: dict[str, int] | None = None
-     if args.enable_offset_gemm:
-         prologue_offset_output = manual_int8_moe_fused_prologue_once(
-             hidden_states=inputs["hidden_states"],
-@@ -1050,6 +1777,8 @@ def benchmark_rows(
-         torch.xpu.synchronize()
-         prologue_offset_max_abs_diff = float(
-             (ref_output - prologue_offset_output).abs().max().item())
-+        prologue_offset_rows_oracle_max_abs_diff = max_abs_diff(
-+            prologue_offset_output, rows_oracle_output)
-     if args.enable_active_offset_gemm:
-         prologue_active_offset_output = manual_int8_moe_fused_prologue_once(
-             hidden_states=inputs["hidden_states"],
-@@ -1067,6 +1796,65 @@ def benchmark_rows(
-         torch.xpu.synchronize()
-         prologue_active_offset_max_abs_diff = float(
-             (ref_output - prologue_active_offset_output).abs().max().item())
-+        prologue_active_offset_rows_oracle_max_abs_diff = max_abs_diff(
-+            prologue_active_offset_output, rows_oracle_output)
-+    if args.enable_middle_layerlet:
-+        prologue_middle_layerlet_output = (
-+            manual_int8_moe_fused_prologue_middle_layerlet_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+            ))
-+        torch.xpu.synchronize()
-+        prologue_middle_layerlet_max_abs_diff = float(
-+            (ref_output - prologue_middle_layerlet_output).abs().max().item())
-+        prologue_middle_layerlet_rows_oracle_max_abs_diff = max_abs_diff(
-+            prologue_middle_layerlet_output, rows_oracle_output)
-+    if args.enable_full_layerlet:
-+        full_layerlet_output = manual_int8_moe_full_layerlet_once(
-+            hidden_states=inputs["hidden_states"],
-+            w13=inputs["w13"],
-+            w13_scales=inputs["w13_scales"],
-+            w2=inputs["w2"],
-+            w2_scales=inputs["w2_scales"],
-+            topk_weights=inputs["topk_weights"],
-+            topk_ids=inputs["topk_ids"],
-+            num_experts=num_experts,
-+            topk=topk,
-+            scratch=prologue_scratch,
-+        )
-+        torch.xpu.synchronize()
-+        full_layerlet_max_abs_diff = float(
-+            (ref_output - full_layerlet_output).abs().max().item())
-+        full_layerlet_rows_oracle_max_abs_diff = max_abs_diff(
-+            full_layerlet_output, rows_oracle_output)
-+    if args.enable_onednn_sidecar:
-+        onednn_sidecar_output, onednn_sidecar_stats_once = (
-+            manual_int8_moe_onednn_sidecar_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+                execute_mode=args.onednn_sidecar_mode,
-+            ))
-+        torch.xpu.synchronize()
-+        onednn_sidecar_max_abs_diff = float(
-+            (ref_output - onednn_sidecar_output).abs().max().item())
-+        onednn_sidecar_rows_oracle_max_abs_diff = max_abs_diff(
-+            onednn_sidecar_output, rows_oracle_output)
-     xpu_scratch_output = xpu_fused_moe(
-         hidden_states=inputs["hidden_states"],
-         w13=inputs["w13"],
-@@ -1086,13 +1874,43 @@ def benchmark_rows(
-     torch.xpu.synchronize()
-     xpu_scratch_max_abs_diff = float(
-         (ref_output - xpu_scratch_output).abs().max().item())
-+    xpu_scratch_rows_oracle_max_abs_diff = max_abs_diff(
-+        xpu_scratch_output, rows_oracle_output)
-+
-+    xpu_prologue_scratch_output = xpu_fused_moe(
-+        hidden_states=inputs["hidden_states"],
-+        w13=inputs["w13"],
-+        w13_scales=inputs["w13_scales"],
-+        w13_bias=None,
-+        w2=inputs["w2"],
-+        w2_scales=inputs["w2_scales"],
-+        w2_bias=None,
-+        topk_weights=inputs["topk_weights"],
-+        topk_ids=inputs["topk_ids"],
-+        n_experts_per_token=topk,
-+        activation="silu",
-+        num_experts=num_experts,
-+        is_int8=True,
-+        scratch=make_xpu_scratch(prologue_scratch),
-+    )
-+    torch.xpu.synchronize()
-+    xpu_prologue_scratch_max_abs_diff = float(
-+        (ref_output - xpu_prologue_scratch_output).abs().max().item())
-+    xpu_prologue_scratch_rows_oracle_max_abs_diff = max_abs_diff(
-+        xpu_prologue_scratch_output, rows_oracle_output)
- 
-     total_us = []
-     scratch_total_us = []
-+    prologue_scratch_total_us = []
-     preallocated_total_us = []
-     prologue_preallocated_total_us = []
-     prologue_offset_total_us = []
-     prologue_active_offset_total_us = []
-+    prologue_middle_layerlet_total_us = []
-+    full_layerlet_total_us = []
-+    onednn_sidecar_total_us = []
-+    onednn_sidecar_middle_wall_us = []
-+    onednn_sidecar_execute_wait_us = []
-     component_us: dict[str, list[float]] = {
-         "rows_zero": [],
-         "remap": [],
-@@ -1104,6 +1922,17 @@ def benchmark_rows(
-         "gemm2": [],
-         "gather": [],
-     }
-+    prologue_component_us: dict[str, list[float]] = {}
-+    prologue_offset_component_us: dict[str, list[float]] = {}
-+    prologue_active_offset_component_us: dict[str, list[float]] = {}
-+
-+    def record_stage_components(
-+        target: dict[str, list[float]],
-+        events: dict[str, tuple[torch.xpu.Event, torch.xpu.Event]],
-+    ) -> None:
-+        for label, (component_start, component_end) in events.items():
-+            target.setdefault(label, []).append(
-+                elapsed_us(component_start, component_end))
- 
-     for _ in range(args.iterations):
-         start, end = make_events()
-@@ -1137,10 +1966,32 @@ def benchmark_rows(
-             topk=topk,
-         )
-         torch.xpu.synchronize()
--        total_us.append(elapsed_us(start, end))
--        for label, (component_start, component_end) in events.items():
--            component_us.setdefault(label, []).append(
--                elapsed_us(component_start, component_end))
-+        total_us.append(elapsed_us(start, end))
-+        for label, (component_start, component_end) in events.items():
-+            component_us.setdefault(label, []).append(
-+                elapsed_us(component_start, component_end))
-+
-+        start, end = make_events()
-+        start.record()
-+        xpu_fused_moe(
-+            hidden_states=inputs["hidden_states"],
-+            w13=inputs["w13"],
-+            w13_scales=inputs["w13_scales"],
-+            w13_bias=None,
-+            w2=inputs["w2"],
-+            w2_scales=inputs["w2_scales"],
-+            w2_bias=None,
-+            topk_weights=inputs["topk_weights"],
-+            topk_ids=inputs["topk_ids"],
-+            n_experts_per_token=topk,
-+            activation="silu",
-+            num_experts=num_experts,
-+            is_int8=True,
-+            scratch=make_xpu_scratch(scratch),
-+        )
-+        end.record()
-+        torch.xpu.synchronize()
-+        scratch_total_us.append(elapsed_us(start, end))
- 
-         start, end = make_events()
-         start.record()
-@@ -1158,11 +2009,11 @@ def benchmark_rows(
-             activation="silu",
-             num_experts=num_experts,
-             is_int8=True,
--            scratch=make_xpu_scratch(scratch),
-+            scratch=make_xpu_scratch(prologue_scratch),
-         )
-         end.record()
-         torch.xpu.synchronize()
--        scratch_total_us.append(elapsed_us(start, end))
-+        prologue_scratch_total_us.append(elapsed_us(start, end))
- 
-         start, end = make_events()
-         start.record()
-@@ -1237,10 +2088,311 @@ def benchmark_rows(
-             end.record()
-             torch.xpu.synchronize()
-             prologue_active_offset_total_us.append(elapsed_us(start, end))
-+        if args.enable_middle_layerlet:
-+            start, end = make_events()
-+            start.record()
-+            manual_int8_moe_fused_prologue_middle_layerlet_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+            )
-+            end.record()
-+            torch.xpu.synchronize()
-+            prologue_middle_layerlet_total_us.append(elapsed_us(start, end))
-+        if args.enable_full_layerlet:
-+            start, end = make_events()
-+            start.record()
-+            manual_int8_moe_full_layerlet_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+            )
-+            end.record()
-+            torch.xpu.synchronize()
-+            full_layerlet_total_us.append(elapsed_us(start, end))
-+        if args.enable_onednn_sidecar:
-+            start, end = make_events()
-+            start.record()
-+            _, stats = manual_int8_moe_onednn_sidecar_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+                execute_mode=args.onednn_sidecar_mode,
-+            )
-+            end.record()
-+            torch.xpu.synchronize()
-+            onednn_sidecar_total_us.append(elapsed_us(start, end))
-+            if stats is not None:
-+                onednn_sidecar_middle_wall_us.append(
-+                    float(stats.get("middle_wall_us", 0)))
-+                onednn_sidecar_execute_wait_us.append(
-+                    float(stats.get("execute_wait_us", 0)))
-+
-+    for _ in range(args.stage_timing_iterations):
-+        prologue_events: dict[str, tuple[torch.xpu.Event,
-+                                         torch.xpu.Event]] = {}
-+        manual_int8_moe_fused_prologue_once(
-+            hidden_states=inputs["hidden_states"],
-+            w13=inputs["w13"],
-+            w13_scales=inputs["w13_scales"],
-+            w2=inputs["w2"],
-+            w2_scales=inputs["w2_scales"],
-+            topk_weights=inputs["topk_weights"],
-+            topk_ids=inputs["topk_ids"],
-+            num_experts=num_experts,
-+            topk=topk,
-+            scratch=prologue_scratch,
-+            events=prologue_events,
-+        )
-+        torch.xpu.synchronize()
-+        record_stage_components(prologue_component_us, prologue_events)
-+        if args.enable_offset_gemm:
-+            prologue_offset_events: dict[str, tuple[torch.xpu.Event,
-+                                                    torch.xpu.Event]] = {}
-+            manual_int8_moe_fused_prologue_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+                use_offset_gemm=True,
-+                events=prologue_offset_events,
-+            )
-+            torch.xpu.synchronize()
-+            record_stage_components(prologue_offset_component_us,
-+                                    prologue_offset_events)
-+        if args.enable_active_offset_gemm:
-+            prologue_active_offset_events: dict[
-+                str, tuple[torch.xpu.Event, torch.xpu.Event]] = {}
-+            manual_int8_moe_fused_prologue_once(
-+                hidden_states=inputs["hidden_states"],
-+                w13=inputs["w13"],
-+                w13_scales=inputs["w13_scales"],
-+                w2=inputs["w2"],
-+                w2_scales=inputs["w2_scales"],
-+                topk_weights=inputs["topk_weights"],
-+                topk_ids=inputs["topk_ids"],
-+                num_experts=num_experts,
-+                topk=topk,
-+                scratch=prologue_scratch,
-+                use_active_offset_gemm=True,
-+                events=prologue_active_offset_events,
-+            )
-+            torch.xpu.synchronize()
-+            record_stage_components(prologue_active_offset_component_us,
-+                                    prologue_active_offset_events)
- 
-     def mean(values: list[float]) -> float:
-         return sum(values) / max(1, len(values))
- 
-+    graph_replay: list[dict[str, Any]] = []
-+    if args.graph_replay_timing:
-+        graph_scratch = make_scratch(
-+            rows=rows,
-+            hidden_size=hidden_size,
-+            inter_size=inter_size,
-+            num_experts=num_experts,
-+            topk=topk,
-+            dtype=dtype,
-+            device=args.device,
-+        )
-+        graph_prologue_scratch = make_prologue_scratch(
-+            rows=rows,
-+            hidden_size=hidden_size,
-+            inter_size=inter_size,
-+            num_experts=num_experts,
-+            topk=topk,
-+            dtype=dtype,
-+            device=args.device,
-+        )
-+        set_active_experts_from_topk(graph_prologue_scratch,
-+                                     inputs["topk_ids"])
-+        graph_replay.append(
-+            measure_graph_replay_us(
-+                "xpu_fused_moe_with_scratch",
-+                lambda: xpu_fused_moe(
-+                    hidden_states=inputs["hidden_states"],
-+                    w13=inputs["w13"],
-+                    w13_scales=inputs["w13_scales"],
-+                    w13_bias=None,
-+                    w2=inputs["w2"],
-+                    w2_scales=inputs["w2_scales"],
-+                    w2_bias=None,
-+                    topk_weights=inputs["topk_weights"],
-+                    topk_ids=inputs["topk_ids"],
-+                    n_experts_per_token=topk,
-+                    activation="silu",
-+                    num_experts=num_experts,
-+                    is_int8=True,
-+                    scratch=make_xpu_scratch(graph_scratch),
-+                ),
-+                warmup=args.graph_warmup,
-+                iterations=args.graph_iterations,
-+            ))
-+        graph_replay.append(
-+            measure_graph_replay_us(
-+                "xpu_fused_moe_with_prologue_scratch",
-+                lambda: xpu_fused_moe(
-+                    hidden_states=inputs["hidden_states"],
-+                    w13=inputs["w13"],
-+                    w13_scales=inputs["w13_scales"],
-+                    w13_bias=None,
-+                    w2=inputs["w2"],
-+                    w2_scales=inputs["w2_scales"],
-+                    w2_bias=None,
-+                    topk_weights=inputs["topk_weights"],
-+                    topk_ids=inputs["topk_ids"],
-+                    n_experts_per_token=topk,
-+                    activation="silu",
-+                    num_experts=num_experts,
-+                    is_int8=True,
-+                    scratch=make_xpu_scratch(graph_prologue_scratch),
-+                ),
-+                warmup=args.graph_warmup,
-+                iterations=args.graph_iterations,
-+            ))
-+        graph_replay.append(
-+            measure_graph_replay_us(
-+                "preallocated_staged",
-+                lambda: manual_int8_moe_preallocated_once(
-+                    hidden_states=inputs["hidden_states"],
-+                    w13=inputs["w13"],
-+                    w13_scales=inputs["w13_scales"],
-+                    w2=inputs["w2"],
-+                    w2_scales=inputs["w2_scales"],
-+                    topk_weights=inputs["topk_weights"],
-+                    topk_ids=inputs["topk_ids"],
-+                    num_experts=num_experts,
-+                    topk=topk,
-+                    scratch=graph_scratch,
-+                ),
-+                warmup=args.graph_warmup,
-+                iterations=args.graph_iterations,
-+            ))
-+        graph_replay.append(
-+            measure_graph_replay_us(
-+                "fused_prologue_staged",
-+                lambda: manual_int8_moe_fused_prologue_once(
-+                    hidden_states=inputs["hidden_states"],
-+                    w13=inputs["w13"],
-+                    w13_scales=inputs["w13_scales"],
-+                    w2=inputs["w2"],
-+                    w2_scales=inputs["w2_scales"],
-+                    topk_weights=inputs["topk_weights"],
-+                    topk_ids=inputs["topk_ids"],
-+                    num_experts=num_experts,
-+                    topk=topk,
-+                    scratch=graph_prologue_scratch,
-+                ),
-+                warmup=args.graph_warmup,
-+                iterations=args.graph_iterations,
-+            ))
-+        if args.enable_offset_gemm:
-+            graph_replay.append(
-+                measure_graph_replay_us(
-+                    "fused_prologue_offset_gemm",
-+                    lambda: manual_int8_moe_fused_prologue_once(
-+                        hidden_states=inputs["hidden_states"],
-+                        w13=inputs["w13"],
-+                        w13_scales=inputs["w13_scales"],
-+                        w2=inputs["w2"],
-+                        w2_scales=inputs["w2_scales"],
-+                        topk_weights=inputs["topk_weights"],
-+                        topk_ids=inputs["topk_ids"],
-+                        num_experts=num_experts,
-+                        topk=topk,
-+                        scratch=graph_prologue_scratch,
-+                        use_offset_gemm=True,
-+                    ),
-+                    warmup=args.graph_warmup,
-+                    iterations=args.graph_iterations,
-+                ))
-+        if args.enable_active_offset_gemm:
-+            graph_replay.append(
-+                measure_graph_replay_us(
-+                    "fused_prologue_active_offset_gemm",
-+                    lambda: manual_int8_moe_fused_prologue_once(
-+                        hidden_states=inputs["hidden_states"],
-+                        w13=inputs["w13"],
-+                        w13_scales=inputs["w13_scales"],
-+                        w2=inputs["w2"],
-+                        w2_scales=inputs["w2_scales"],
-+                        topk_weights=inputs["topk_weights"],
-+                        topk_ids=inputs["topk_ids"],
-+                        num_experts=num_experts,
-+                        topk=topk,
-+                        scratch=graph_prologue_scratch,
-+                        use_active_offset_gemm=True,
-+                    ),
-+                    warmup=args.graph_warmup,
-+                    iterations=args.graph_iterations,
-+                ))
-+        if args.enable_full_layerlet:
-+            graph_replay.append(
-+                measure_graph_replay_us(
-+                    "full_layerlet",
-+                    lambda: manual_int8_moe_full_layerlet_once(
-+                        hidden_states=inputs["hidden_states"],
-+                        w13=inputs["w13"],
-+                        w13_scales=inputs["w13_scales"],
-+                        w2=inputs["w2"],
-+                        w2_scales=inputs["w2_scales"],
-+                        topk_weights=inputs["topk_weights"],
-+                        topk_ids=inputs["topk_ids"],
-+                        num_experts=num_experts,
-+                        topk=topk,
-+                        scratch=graph_prologue_scratch,
-+                    ),
-+                    warmup=args.graph_warmup,
-+                    iterations=args.graph_iterations,
-+                ))
-+        if args.enable_onednn_sidecar:
-+            graph_replay.append(
-+                measure_graph_replay_us(
-+                    "onednn_sidecar",
-+                    lambda: manual_int8_moe_onednn_sidecar_once(
-+                        hidden_states=inputs["hidden_states"],
-+                        w13=inputs["w13"],
-+                        w13_scales=inputs["w13_scales"],
-+                        w2=inputs["w2"],
-+                        w2_scales=inputs["w2_scales"],
-+                        topk_weights=inputs["topk_weights"],
-+                        topk_ids=inputs["topk_ids"],
-+                        num_experts=num_experts,
-+                        topk=topk,
-+                        scratch=graph_prologue_scratch,
-+                        execute_mode=args.onednn_sidecar_mode,
-+                    )[0],
-+                    warmup=args.graph_warmup,
-+                    iterations=args.graph_iterations,
-+                ))
-+
-     components = {label: mean(values)
-                   for label, values in component_us.items()}
-     components["activation_plus_quant2"] = (
-@@ -1254,6 +2406,25 @@ def benchmark_rows(
-                       "activation", "act_contiguous", "quant2", "gemm2",
-                       "gather"))
- 
-+    def summarize_stage_components(
-+        source: dict[str, list[float]],
-+    ) -> dict[str, float]:
-+        summarized = {label: mean(values) for label, values in source.items()}
-+        summarized["activation_plus_quant2"] = (
-+            summarized.get("activation", 0.0) +
-+            summarized.get("quant2", 0.0))
-+        summarized["component_sum"] = sum(
-+            summarized.get(label, 0.0)
-+            for label in ("prologue", "rows_from_offsets", "quant1", "gemm1",
-+                          "activation", "quant2", "gemm2", "gather"))
-+        return summarized
-+
-+    prologue_components = summarize_stage_components(prologue_component_us)
-+    prologue_offset_components = summarize_stage_components(
-+        prologue_offset_component_us)
-+    prologue_active_offset_components = summarize_stage_components(
-+        prologue_active_offset_component_us)
-+
-     result = {
-         "rows": rows,
-         "moe_inputs": rows * topk,
-@@ -1262,7 +2433,12 @@ def benchmark_rows(
-         "num_experts": num_experts,
-         "topk": topk,
-         "dtype": args.dtype,
--        "topk_source": "route_jsonl" if route_topk_rows else "synthetic_uniform",
-+        "selected_experts": topk_summary.get("topk_rows"),
-+        "topk_source": (
-+            "route_jsonl" if route_topk_rows
-+            else f"synthetic_{args.synthetic_route_mode}"),
-+        "synthetic_route_mode": (
-+            None if route_topk_rows else args.synthetic_route_mode),
-         "route_start_index": route_start_index if route_topk_rows else None,
-         "route_start_index_mod": (
-             route_start_index % len(route_topk_rows)
-@@ -1271,6 +2447,8 @@ def benchmark_rows(
-         "topk_summary": topk_summary,
-         "total_us_mean": mean(total_us),
-         "xpu_fused_moe_scratch_total_us_mean": mean(scratch_total_us),
-+        "xpu_fused_moe_prologue_scratch_total_us_mean":
-+        mean(prologue_scratch_total_us),
-         "preallocated_staged_total_us_mean": mean(preallocated_total_us),
-         "fused_prologue_staged_total_us_mean":
-         mean(prologue_preallocated_total_us),
-@@ -1279,10 +2457,31 @@ def benchmark_rows(
-         "fused_prologue_active_offset_gemm_total_us_mean":
-         (mean(prologue_active_offset_total_us)
-          if prologue_active_offset_total_us else None),
-+        "fused_prologue_middle_layerlet_total_us_mean":
-+        (mean(prologue_middle_layerlet_total_us)
-+         if prologue_middle_layerlet_total_us else None),
-+        "full_layerlet_total_us_mean":
-+        (mean(full_layerlet_total_us) if full_layerlet_total_us else None),
-+        "onednn_sidecar_total_us_mean":
-+        (mean(onednn_sidecar_total_us) if onednn_sidecar_total_us else None),
-+        "onednn_sidecar_middle_wall_us_mean":
-+        (mean(onednn_sidecar_middle_wall_us)
-+         if onednn_sidecar_middle_wall_us else None),
-+        "onednn_sidecar_execute_wait_us_mean":
-+        (mean(onednn_sidecar_execute_wait_us)
-+         if onednn_sidecar_execute_wait_us else None),
-+        "onednn_sidecar_stats_once": onednn_sidecar_stats_once,
-         "offset_gemm_available": offset_gemm_available,
-         "offset_gemm_enabled": bool(args.enable_offset_gemm),
-         "active_offset_gemm_available": active_offset_gemm_available,
-         "active_offset_gemm_enabled": bool(args.enable_active_offset_gemm),
-+        "middle_layerlet_available": middle_layerlet_available,
-+        "middle_layerlet_enabled": bool(args.enable_middle_layerlet),
-+        "full_layerlet_available": full_layerlet_available,
-+        "full_layerlet_enabled": bool(args.enable_full_layerlet),
-+        "onednn_sidecar_available": onednn_sidecar_available,
-+        "onednn_sidecar_enabled": bool(args.enable_onednn_sidecar),
-+        "onednn_sidecar_execute_mode": int(args.onednn_sidecar_mode),
-         "quant_out_op_available": hasattr(torch.ops._xpu_C,
-                                           "per_token_quant_int8_xpu_out"),
-         "quant_scratch_buffers": [
-@@ -1296,8 +2495,15 @@ def benchmark_rows(
-         "fused_prologue_workspace_bytes":
-         int(prologue_scratch["workspace_bytes"]),
-         "components_us_mean": components,
--        "manual_vs_xpu_fused_moe_max_abs_diff": max_abs_diff,
-+        "fused_prologue_components_us_mean": prologue_components,
-+        "fused_prologue_offset_components_us_mean":
-+        prologue_offset_components,
-+        "fused_prologue_active_offset_components_us_mean":
-+        prologue_active_offset_components,
-+        "manual_vs_xpu_fused_moe_max_abs_diff": manual_max_abs_diff,
-         "xpu_scratch_vs_xpu_fused_moe_max_abs_diff": xpu_scratch_max_abs_diff,
-+        "xpu_prologue_scratch_vs_xpu_fused_moe_max_abs_diff":
-+        xpu_prologue_scratch_max_abs_diff,
-         "preallocated_vs_xpu_fused_moe_max_abs_diff": prealloc_max_abs_diff,
-         "fused_prologue_vs_xpu_fused_moe_max_abs_diff":
-         prologue_max_abs_diff,
-@@ -1305,9 +2511,47 @@ def benchmark_rows(
-         prologue_offset_max_abs_diff,
-         "fused_prologue_active_offset_gemm_vs_xpu_fused_moe_max_abs_diff":
-         prologue_active_offset_max_abs_diff,
-+        "fused_prologue_middle_layerlet_vs_xpu_fused_moe_max_abs_diff":
-+        prologue_middle_layerlet_max_abs_diff,
-+        "full_layerlet_vs_xpu_fused_moe_max_abs_diff":
-+        full_layerlet_max_abs_diff,
-+        "onednn_sidecar_vs_xpu_fused_moe_max_abs_diff":
-+        onednn_sidecar_max_abs_diff,
-+        "real_routing_oracle_enabled": bool(args.real_routing_oracle),
-+        "real_routing_bf16_reference_enabled":
-+        bool(args.real_routing_bf16_reference),
-+        "xpu_fused_moe_vs_rows_oracle_max_abs_diff":
-+        xpu_fused_moe_rows_oracle_max_abs_diff,
-+        "offset_oracle_vs_rows_oracle_max_abs_diff":
-+        offset_oracle_rows_oracle_max_abs_diff,
-+        "manual_vs_rows_oracle_max_abs_diff":
-+        manual_rows_oracle_max_abs_diff,
-+        "xpu_scratch_vs_rows_oracle_max_abs_diff":
-+        xpu_scratch_rows_oracle_max_abs_diff,
-+        "xpu_prologue_scratch_vs_rows_oracle_max_abs_diff":
-+        xpu_prologue_scratch_rows_oracle_max_abs_diff,
-+        "preallocated_vs_rows_oracle_max_abs_diff":
-+        prealloc_rows_oracle_max_abs_diff,
-+        "fused_prologue_vs_rows_oracle_max_abs_diff":
-+        prologue_rows_oracle_max_abs_diff,
-+        "fused_prologue_offset_gemm_vs_rows_oracle_max_abs_diff":
-+        prologue_offset_rows_oracle_max_abs_diff,
-+        "fused_prologue_active_offset_gemm_vs_rows_oracle_max_abs_diff":
-+        prologue_active_offset_rows_oracle_max_abs_diff,
-+        "fused_prologue_middle_layerlet_vs_rows_oracle_max_abs_diff":
-+        prologue_middle_layerlet_rows_oracle_max_abs_diff,
-+        "full_layerlet_vs_rows_oracle_max_abs_diff":
-+        full_layerlet_rows_oracle_max_abs_diff,
-+        "onednn_sidecar_vs_rows_oracle_max_abs_diff":
-+        onednn_sidecar_rows_oracle_max_abs_diff,
-+        "rows_oracle_vs_bf16_reference_max_abs_diff":
-+        rows_oracle_bf16_reference_max_abs_diff,
-         "iterations": args.iterations,
-         "warmup": args.warmup,
-+        "stage_timing_iterations": args.stage_timing_iterations,
-     }
-+    if args.graph_replay_timing:
-+        result["graph_replay"] = graph_replay
-     result["prologue_inclusive_gate"] = build_prologue_inclusive_gate(
-         result,
-         exactness_threshold=args.exactness_threshold,
-@@ -1366,6 +2610,14 @@ def build_prologue_inclusive_gate(
-                 row.get("xpu_scratch_vs_xpu_fused_moe_max_abs_diff")),
-             "reference": False,
-         },
-+        {
-+            "name": "xpu_fused_moe_with_prologue_scratch",
-+            "us_mean": _maybe_float(
-+                row.get("xpu_fused_moe_prologue_scratch_total_us_mean")),
-+            "max_abs_diff_vs_xpu": _maybe_float(row.get(
-+                "xpu_prologue_scratch_vs_xpu_fused_moe_max_abs_diff")),
-+            "reference": False,
-+        },
-         {
-             "name": "preallocated_staged",
-             "us_mean": _maybe_float(row.get("preallocated_staged_total_us_mean")),
-@@ -1397,6 +2649,28 @@ def build_prologue_inclusive_gate(
-                 "fused_prologue_active_offset_gemm_vs_xpu_fused_moe_max_abs_diff")),
-             "reference": False,
-         },
-+        {
-+            "name": "fused_prologue_middle_layerlet",
-+            "us_mean": _maybe_float(row.get(
-+                "fused_prologue_middle_layerlet_total_us_mean")),
-+            "max_abs_diff_vs_xpu": _maybe_float(row.get(
-+                "fused_prologue_middle_layerlet_vs_xpu_fused_moe_max_abs_diff")),
-+            "reference": False,
-+        },
-+        {
-+            "name": "full_layerlet",
-+            "us_mean": _maybe_float(row.get("full_layerlet_total_us_mean")),
-+            "max_abs_diff_vs_xpu": _maybe_float(
-+                row.get("full_layerlet_vs_xpu_fused_moe_max_abs_diff")),
-+            "reference": False,
-+        },
-+        {
-+            "name": "onednn_sidecar",
-+            "us_mean": _maybe_float(row.get("onednn_sidecar_total_us_mean")),
-+            "max_abs_diff_vs_xpu": _maybe_float(
-+                row.get("onednn_sidecar_vs_xpu_fused_moe_max_abs_diff")),
-+            "reference": False,
-+        },
-     ]
- 
-     usable_candidates = []
-@@ -1550,6 +2824,13 @@ def build_prologue_inclusive_gate_summary(
- def write_markdown(path: str, results: dict[str, Any]) -> None:
-     rows = results.get("results", [])
-     fused = bool(results.get("fused_silu_quant_enabled"))
-+
-+    def max_row_float(field: str) -> float:
-+        return max(
-+            (float(row[field]) for row in rows if row.get(field) is not None),
-+            default=float("nan"),
-+        )
-+
-     max_diffs = {
-         "manual": max(
-             (float(row.get("manual_vs_xpu_fused_moe_max_abs_diff", 0.0))
-@@ -1561,6 +2842,12 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-              for row in rows),
-             default=float("nan"),
-         ),
-+        "prologue_scratch": max(
-+            (float(row.get(
-+                "xpu_prologue_scratch_vs_xpu_fused_moe_max_abs_diff", 0.0))
-+             for row in rows),
-+            default=float("nan"),
-+        ),
-         "preallocated": max(
-             (float(row.get("preallocated_vs_xpu_fused_moe_max_abs_diff", 0.0))
-              for row in rows),
-@@ -1589,6 +2876,41 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-              is not None),
-             default=float("nan"),
-         ),
-+        "fused_prologue_middle_layerlet": max(
-+            (float(row.get(
-+                "fused_prologue_middle_layerlet_vs_xpu_fused_moe_max_abs_diff",
-+                0.0,
-+            )) for row in rows if row.get(
-+                "fused_prologue_middle_layerlet_vs_xpu_fused_moe_max_abs_diff")
-+             is not None),
-+            default=float("nan"),
-+        ),
-+        "full_layerlet": max(
-+            (float(row.get(
-+                "full_layerlet_vs_xpu_fused_moe_max_abs_diff",
-+                0.0,
-+            )) for row in rows if row.get(
-+                "full_layerlet_vs_xpu_fused_moe_max_abs_diff") is not None),
-+            default=float("nan"),
-+        ),
-+        "onednn_sidecar": max(
-+            (float(row.get(
-+                "onednn_sidecar_vs_xpu_fused_moe_max_abs_diff",
-+                0.0,
-+            )) for row in rows if row.get(
-+                "onednn_sidecar_vs_xpu_fused_moe_max_abs_diff") is not None),
-+            default=float("nan"),
-+        ),
-+        "xpu_vs_rows_oracle":
-+        max_row_float("xpu_fused_moe_vs_rows_oracle_max_abs_diff"),
-+        "offset_vs_rows_oracle":
-+        max_row_float("offset_oracle_vs_rows_oracle_max_abs_diff"),
-+        "full_layerlet_vs_rows_oracle":
-+        max_row_float("full_layerlet_vs_rows_oracle_max_abs_diff"),
-+        "onednn_sidecar_vs_rows_oracle":
-+        max_row_float("onednn_sidecar_vs_rows_oracle_max_abs_diff"),
-+        "rows_oracle_vs_bf16_reference":
-+        max_row_float("rows_oracle_vs_bf16_reference_max_abs_diff"),
-     }
- 
-     lines = []
-@@ -1597,6 +2919,9 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-     lines.append(f"- Fused SiLU+quant enabled: `{fused}`.")
-     lines.append(f"- TP size: `{results['tp_size']}`.")
-     lines.append(f"- Result rows: `{len(rows)}`.")
-+    if rows:
-+        lines.append(
-+            f"- Route mode/source: `{rows[0].get('topk_source')}`.")
-     if rows:
-         lines.append(
-             f"- Quant out-variant available: "
-@@ -1636,6 +2961,10 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-         f"- Scratch `xpu_fused_moe` max abs diff: "
-         f"`{_fmt(max_diffs['scratch'])}`."
-     )
-+    lines.append(
-+        f"- Prologue-scratch `xpu_fused_moe` max abs diff: "
-+        f"`{_fmt(max_diffs['prologue_scratch'])}`."
-+    )
-     lines.append(
-         f"- Preallocated staged max abs diff: "
-         f"`{_fmt(max_diffs['preallocated'])}`."
-@@ -1654,6 +2983,49 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-             f"- Fused-prologue active-offset-GEMM max abs diff: "
-             f"`{_fmt(max_diffs['fused_prologue_active_offset'])}`."
-         )
-+    if any(row.get("middle_layerlet_enabled") for row in rows):
-+        lines.append(
-+            f"- Fused-prologue middle-layerlet max abs diff: "
-+            f"`{_fmt(max_diffs['fused_prologue_middle_layerlet'])}`."
-+        )
-+    if any(row.get("full_layerlet_enabled") for row in rows):
-+        lines.append(
-+            f"- Full C++ layerlet max abs diff: "
-+            f"`{_fmt(max_diffs['full_layerlet'])}`."
-+        )
-+    if any(row.get("onednn_sidecar_enabled") for row in rows):
-+        lines.append(
-+            f"- oneDNN sidecar max abs diff: "
-+            f"`{_fmt(max_diffs['onednn_sidecar'])}`."
-+        )
-+    if any(row.get("real_routing_oracle_enabled") for row in rows):
-+        lines.append("")
-+        lines.append("### Rows-Oracle Checks")
-+        lines.append("")
-+        lines.append(
-+            "- Current `xpu_fused_moe` max abs diff versus forced "
-+            f"rows-per-expert oracle: `{_fmt(max_diffs['xpu_vs_rows_oracle'])}`."
-+        )
-+        lines.append(
-+            "- Forced offset-GEMM max abs diff versus rows-per-expert oracle: "
-+            f"`{_fmt(max_diffs['offset_vs_rows_oracle'])}`."
-+        )
-+        if any(row.get("full_layerlet_enabled") for row in rows):
-+            lines.append(
-+                "- Full C++ layerlet max abs diff versus rows-per-expert "
-+                f"oracle: `{_fmt(max_diffs['full_layerlet_vs_rows_oracle'])}`."
-+            )
-+        if any(row.get("onednn_sidecar_enabled") for row in rows):
-+            lines.append(
-+                "- oneDNN sidecar max abs diff versus rows-per-expert "
-+                f"oracle: `{_fmt(max_diffs['onednn_sidecar_vs_rows_oracle'])}`."
-+            )
-+        if any(row.get("real_routing_bf16_reference_enabled") for row in rows):
-+            lines.append(
-+                "- Rows-per-expert INT8 oracle max abs diff versus BF16 "
-+                "dequantized reference: "
-+                f"`{_fmt(max_diffs['rows_oracle_vs_bf16_reference'])}`."
-+            )
-     lines.append("")
-     lines.append("## Timing")
-     lines.append("")
-@@ -1662,6 +3034,9 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-     mean_xpu_scratch = sum(
-         float(row.get("xpu_fused_moe_scratch_total_us_mean", 0.0))
-         for row in rows) / max(1, len(rows))
-+    mean_xpu_prologue_scratch = sum(
-+        float(row.get("xpu_fused_moe_prologue_scratch_total_us_mean", 0.0))
-+        for row in rows) / max(1, len(rows))
-     mean_prealloc = sum(
-         float(row.get("preallocated_staged_total_us_mean", 0.0))
-         for row in rows) / max(1, len(rows))
-@@ -1687,9 +3062,52 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-             for row in active_offset_rows) / len(active_offset_rows)
-         if active_offset_rows else None
-     )
-+    middle_layerlet_rows = [
-+        row for row in rows
-+        if row.get("fused_prologue_middle_layerlet_total_us_mean") is not None
-+    ]
-+    mean_prologue_middle_layerlet = (
-+        sum(float(row["fused_prologue_middle_layerlet_total_us_mean"])
-+            for row in middle_layerlet_rows) / len(middle_layerlet_rows)
-+        if middle_layerlet_rows else None
-+    )
-+    full_layerlet_rows = [
-+        row for row in rows if row.get("full_layerlet_total_us_mean")
-+        is not None
-+    ]
-+    mean_full_layerlet = (
-+        sum(float(row["full_layerlet_total_us_mean"])
-+            for row in full_layerlet_rows) / len(full_layerlet_rows)
-+        if full_layerlet_rows else None
-+    )
-+    onednn_sidecar_rows = [
-+        row for row in rows if row.get("onednn_sidecar_total_us_mean")
-+        is not None
-+    ]
-+    mean_onednn_sidecar = (
-+        sum(float(row["onednn_sidecar_total_us_mean"])
-+            for row in onednn_sidecar_rows) / len(onednn_sidecar_rows)
-+        if onednn_sidecar_rows else None
-+    )
-+    mean_onednn_sidecar_middle = (
-+        sum(float(row["onednn_sidecar_middle_wall_us_mean"])
-+            for row in onednn_sidecar_rows
-+            if row.get("onednn_sidecar_middle_wall_us_mean") is not None)
-+        / len([
-+            row for row in onednn_sidecar_rows
-+            if row.get("onednn_sidecar_middle_wall_us_mean") is not None
-+        ])
-+        if any(row.get("onednn_sidecar_middle_wall_us_mean") is not None
-+               for row in onednn_sidecar_rows)
-+        else None
-+    )
-     lines.append(f"- Mean `xpu_fused_moe`: `{_fmt(mean_xpu)} us`.")
-     lines.append(
-         f"- Mean scratch `xpu_fused_moe`: `{_fmt(mean_xpu_scratch)} us`.")
-+    lines.append(
-+        "- Mean prologue-scratch `xpu_fused_moe`: "
-+        f"`{_fmt(mean_xpu_prologue_scratch)} us`."
-+    )
-     lines.append(f"- Mean preallocated staged: `{_fmt(mean_prealloc)} us`.")
-     lines.append(
-         f"- Mean fused-prologue staged: `{_fmt(mean_prologue)} us`.")
-@@ -1703,14 +3121,37 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-             "- Mean fused-prologue active-offset-GEMM staged: "
-             f"`{_fmt(mean_prologue_active_offset)} us`."
-         )
-+    if mean_prologue_middle_layerlet is not None:
-+        lines.append(
-+            "- Mean fused-prologue middle-layerlet staged: "
-+            f"`{_fmt(mean_prologue_middle_layerlet)} us`."
-+        )
-+    if mean_full_layerlet is not None:
-+        lines.append(
-+            "- Mean full C++ layerlet: "
-+            f"`{_fmt(mean_full_layerlet)} us`."
-+        )
-+    if mean_onednn_sidecar is not None:
-+        lines.append(
-+            "- Mean oneDNN sidecar total: "
-+            f"`{_fmt(mean_onednn_sidecar)} us`."
-+        )
-+    if mean_onednn_sidecar_middle is not None:
-+        lines.append(
-+            "- Mean oneDNN sidecar internal middle wall: "
-+            f"`{_fmt(mean_onednn_sidecar_middle)} us`."
-+        )
-     lines.append("")
-     lines.append(
-         "| rows | route start | active experts | xpu fused us | "
--        "xpu scratch us | prealloc staged us | fused prologue staged us | "
--        "fused prologue offset us | active offset us | gemm1 us | gemm2 us | "
-+        "xpu scratch us | xpu prologue scratch us | prealloc staged us | "
-+        "fused prologue staged us | "
-+        "fused prologue offset us | active offset us | middle layerlet us | "
-+        "full layerlet us | oneDNN sidecar us | gemm1 us | gemm2 us | "
-         "act+quant2 us |"
-     )
--    lines.append("|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|")
-+    lines.append(
-+        "|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|")
-     for row in rows:
-         comp = row.get("components_us_mean", {})
-         topk = row.get("topk_summary", {})
-@@ -1719,15 +3160,72 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-             f"{topk.get('active_experts')} | "
-             f"{_fmt(row.get('total_us_mean'))} | "
-             f"{_fmt(row.get('xpu_fused_moe_scratch_total_us_mean'))} | "
-+            f"{_fmt(row.get('xpu_fused_moe_prologue_scratch_total_us_mean'))} | "
-             f"{_fmt(row.get('preallocated_staged_total_us_mean'))} | "
-             f"{_fmt(row.get('fused_prologue_staged_total_us_mean'))} | "
-             f"{_fmt(row.get('fused_prologue_offset_gemm_total_us_mean'))} | "
-             f"{_fmt(row.get('fused_prologue_active_offset_gemm_total_us_mean'))} | "
-+            f"{_fmt(row.get('fused_prologue_middle_layerlet_total_us_mean'))} | "
-+            f"{_fmt(row.get('full_layerlet_total_us_mean'))} | "
-+            f"{_fmt(row.get('onednn_sidecar_total_us_mean'))} | "
-             f"{_fmt(comp.get('gemm1'))} | "
-             f"{_fmt(comp.get('gemm2'))} | "
-             f"{_fmt(comp.get('activation_plus_quant2'))} |"
-         )
-     lines.append("")
-+
-+    if any(int(row.get("stage_timing_iterations") or 0) > 0 for row in rows):
-+        lines.append("## Prologue Offset Stage Timing")
-+        lines.append("")
-+        lines.append(
-+            "These stage timings are for the exact fused-prologue "
-+            "offset-GEMM candidate and are used to decide the next native "
-+            "layerlet boundary. They are single-device replay diagnostics."
-+        )
-+        lines.append("")
-+        lines.append(
-+            "| rows | route start | total us | prologue | quant1 | gemm1 | "
-+            "activation | quant2 | gemm2 | gather | component sum |"
-+        )
-+        lines.append(
-+            "|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|")
-+        for row in rows:
-+            comp = row.get("fused_prologue_offset_components_us_mean", {})
-+            if not comp:
-+                continue
-+            lines.append(
-+                f"| {row.get('rows')} | {row.get('route_start_index')} | "
-+                f"{_fmt(row.get('fused_prologue_offset_gemm_total_us_mean'))} | "
-+                f"{_fmt(comp.get('prologue'))} | "
-+                f"{_fmt(comp.get('quant1'))} | "
-+                f"{_fmt(comp.get('gemm1'))} | "
-+                f"{_fmt(comp.get('activation'))} | "
-+                f"{_fmt(comp.get('quant2'))} | "
-+                f"{_fmt(comp.get('gemm2'))} | "
-+                f"{_fmt(comp.get('gather'))} | "
-+                f"{_fmt(comp.get('component_sum'))} |"
-+            )
-+        lines.append("")
-+
-+    if any(row.get("graph_replay") for row in rows):
-+        lines.append("## Graph Replay Timing")
-+        lines.append("")
-+        lines.append(
-+            "These timings capture each eligible candidate in an XPU graph "
-+            "and time `graph.replay()`. They remain single-device replay "
-+            "diagnostics, not endpoint throughput."
-+        )
-+        lines.append("")
-+        lines.append("| rows | route start | candidate | status | graph us |")
-+        lines.append("|---:|---:|---|---|---:|")
-+        for row in rows:
-+            for item in row.get("graph_replay", []):
-+                lines.append(
-+                    f"| {row.get('rows')} | {row.get('route_start_index')} | "
-+                    f"{item.get('name')} | {item.get('status')} | "
-+                    f"{_fmt(item.get('us_mean'))} |")
-+        lines.append("")
-+
-     lines.append("## Prologue-Inclusive Gate")
-     lines.append("")
-     if gate_summary:
-@@ -1815,6 +3313,19 @@ def write_markdown(path: str, results: dict[str, Any]) -> None:
-             "- The fused-prologue staged path is not exact against "
-             "`xpu_fused_moe`; do not use it as an endpoint candidate."
-         )
-+    if mean_onednn_sidecar is not None:
-+        if mean_full_layerlet is not None and mean_onednn_sidecar > mean_full_layerlet:
-+            lines.append(
-+                "- The oneDNN sidecar is exact, but its prologue-inclusive "
-+                "wrapper is slower than the current full C++ layerlet in this "
-+                "route replay. Keep the internal middle-wall timing as a "
-+                "diagnostic only; do not promote the sidecar endpoint path."
-+            )
-+        else:
-+            lines.append(
-+                "- The oneDNN sidecar is exact and should be evaluated by the "
-+                "prologue-inclusive gate before any endpoint promotion."
-+            )
-     lines.append(
-         "- Compare `xpu fused us` with the current budget target of roughly "
-         "`160 us/layer` for a plausible `200 tok/s` non-speculative lane."
-@@ -1862,6 +3373,36 @@ def main() -> int:
-     parser.add_argument("--dtype", choices=("bf16", "fp16"), default="bf16")
-     parser.add_argument("--device", default="xpu")
-     parser.add_argument("--output-json")
-+    parser.add_argument(
-+        "--synthetic-route-mode",
-+        choices=("uniform", "hot_skew"),
-+        default="uniform",
-+        help=(
-+            "Synthetic top-k routing pattern used when --route-jsonl is not "
-+            "provided. hot_skew keeps many experts at zero rows and stresses "
-+            "skewed real-routing behavior."
-+        ),
-+    )
-+    parser.add_argument(
-+        "--real-routing-oracle",
-+        action="store_true",
-+        help=(
-+            "Also compare candidates against a forced rows-per-expert W8A8 "
-+            "path with offsets/layerlets/prologue disabled. This catches "
-+            "offset/layerlet bugs that are invisible when comparing two paths "
-+            "sharing the same offset kernels."
-+        ),
-+    )
-+    parser.add_argument(
-+        "--real-routing-bf16-reference",
-+        action="store_true",
-+        help=(
-+            "When --real-routing-oracle is enabled, also compare the forced "
-+            "rows-per-expert INT8 path against ref_fused_moe's dequantized "
-+            "BF16/FP32 reference. This is a drift diagnostic, not an exact "
-+            "promotion gate for Quark W8A8."
-+        ),
-+    )
-     parser.add_argument(
-         "--route-jsonl",
-         help="Optional route-capture JSONL whose topk_ids override synthetic routing.",
-@@ -1922,8 +3463,68 @@ def main() -> int:
-             "to the W8A8 grouped GEMM op."
-         ),
-     )
-+    parser.add_argument(
-+        "--enable-middle-layerlet",
-+        action="store_true",
-+        help=(
-+            "Benchmark fused-prologue plus the C++ W8A8 middle layerlet "
-+            "(GEMM1 + fused SiLU/quant + GEMM2) as an exact full-route "
-+            "candidate."
-+        ),
-+    )
-+    parser.add_argument(
-+        "--enable-full-layerlet",
-+        action="store_true",
-+        help=(
-+            "Benchmark the experimental C++ wrapper that calls prologue, "
-+            "quant1, W8A8 middle layerlet, and gather behind one _xpu_C op."
-+        ),
-+    )
-+    parser.add_argument(
-+        "--enable-onednn-sidecar",
-+        action="store_true",
-+        help=(
-+            "Benchmark the diagnostic cached oneDNN grouped-matmul sidecar "
-+            "inside the fused-prologue route replay. This is not endpoint "
-+            "promotion by itself; use it to decide whether the oneDNN "
-+            "middle boundary is worth making graph-safe/persistent."
-+        ),
-+    )
-+    parser.add_argument(
-+        "--onednn-sidecar-mode",
-+        type=int,
-+        default=23,
-+        help=(
-+            "Execution mode passed to qwen36_moe_onednn_sidecar_probe. "
-+            "Mode 23 is the cached GEMM1+activation/quant+GEMM2 path with "
-+            "post-GEMM2 wait used by earlier diagnostics."
-+        ),
-+    )
-+    parser.add_argument(
-+        "--graph-replay-timing",
-+        action="store_true",
-+        help=(
-+            "Capture and time XPU graph replay for preallocated exact "
-+            "candidates. This is a replay diagnostic, not an endpoint result."
-+        ),
-+    )
-+    parser.add_argument("--graph-warmup", type=int, default=3)
-+    parser.add_argument("--graph-iterations", type=int, default=30)
-+    parser.add_argument(
-+        "--stage-timing-iterations",
-+        type=int,
-+        default=0,
-+        help=(
-+            "Collect event-level stage timings for fused-prologue candidates "
-+            "in a separate diagnostic loop. Normal candidate totals are "
-+            "measured without this extra event overhead."
-+        ),
-+    )
-     parser.add_argument("--markdown-out")
-     args = parser.parse_args()
-+    if args.real_routing_bf16_reference and not args.real_routing_oracle:
-+        parser.error(
-+            "--real-routing-bf16-reference requires --real-routing-oracle")
- 
-     if args.enable_fused_silu_quant:
-         os.environ["VLLM_XPU_FUSED_MOE_FUSE_SILU_QUANT"] = "1"
-@@ -1967,6 +3568,11 @@ def main() -> int:
-         "model_config": args.model_config,
-         "tp_size": args.tp_size,
-         "fused_silu_quant_enabled": args.enable_fused_silu_quant,
-+        "synthetic_route_mode": args.synthetic_route_mode,
-+        "real_routing_oracle_enabled": args.real_routing_oracle,
-+        "real_routing_bf16_reference_enabled":
-+        args.real_routing_bf16_reference,
-+        "runtime_identity": collect_runtime_identity(args),
-         "prologue_inclusive_gate_summary":
-         build_prologue_inclusive_gate_summary(
-             benchmark_results,
-diff --git a/scripts/check-qwen36-oracle-fixture.py b/scripts/check-qwen36-oracle-fixture.py
-index ee601fe..2a2893d 100644
---- a/scripts/check-qwen36-oracle-fixture.py
-+++ b/scripts/check-qwen36-oracle-fixture.py
-@@ -51,12 +51,18 @@ def mapped_roles(cases: list[dict[str, Any]]) -> list[str]:
-     return roles
- 
- 
--def check_replay(replay: dict[str, Any], errors: list[str]) -> None:
-+def check_replay(
-+    replay: dict[str, Any],
-+    errors: list[str],
-+    *,
-+    allow_accounting_mismatch: bool = False,
-+) -> None:
-     if int(replay.get("malformed_rows") or 0) != 0:
-         fail(errors, "replay contains malformed rows")
-     if int(replay.get("joined_requests") or 0) != int(replay.get("requests") or 0):
-         fail(errors, "replay did not join every request to a token case")
--    if int(replay.get("accounting_mismatch_count") or 0) != 0:
-+    accounting_mismatches = int(replay.get("accounting_mismatch_count") or 0)
-+    if accounting_mismatches != 0 and not allow_accounting_mismatch:
-         fail(errors, "replay accounting mismatches are present")
-     if int(replay.get("suppressed_followup_mismatch_count") or 0) != 0:
-         fail(errors, "suppressed follow-up mismatches are present")
-@@ -210,6 +216,15 @@ def main() -> int:
-         action="store_true",
-         help="Require spec trace request IDs to join back to every fixture case.",
-     )
-+    parser.add_argument(
-+        "--allow-replay-accounting-mismatch",
-+        action="store_true",
-+        help=(
-+            "Allow replay accounting-only mismatches. This is for token-exact "
-+            "runs where the trace accounting is known noisy; generated-token "
-+            "mismatches and suppressed follow-up mismatches still fail."
-+        ),
-+    )
-     args = parser.parse_args()
- 
-     fixture = load_json(args.fixture)
-@@ -227,7 +242,11 @@ def main() -> int:
-         )
- 
-     if args.replay_json:
--        check_replay(load_json(args.replay_json), errors)
-+        check_replay(
-+            load_json(args.replay_json),
-+            errors,
-+            allow_accounting_mismatch=args.allow_replay_accounting_mismatch,
-+        )
-     spec_summary = load_spec_summary(fixture, args.spec_summary)
-     spec = check_spec_summary(fixture, spec_summary, args, errors)
- 
-diff --git a/scripts/launch-qwen36-quark-int8-accepted.sh b/scripts/launch-qwen36-quark-int8-accepted.sh
-index d52e061..b86b98f 100755
---- a/scripts/launch-qwen36-quark-int8-accepted.sh
-+++ b/scripts/launch-qwen36-quark-int8-accepted.sh
-@@ -14,6 +14,9 @@ GPU_MEMORY_UTILIZATION="${GPU_MEMORY_UTILIZATION:-0.90}"
- if [[ -z "${COMPILATION_CONFIG:-}" ]]; then
-   COMPILATION_CONFIG='{"cudagraph_mode":"NONE"}'
- fi
-+QWEN36_XPU_PREFLIGHT="${QWEN36_XPU_PREFLIGHT:-auto}"
-+QWEN36_XPU_PREFLIGHT_SCRIPT="${QWEN36_XPU_PREFLIGHT_SCRIPT:-/home/steve/llm-optimizations/scripts/check-qwen36-xpu-xccl-health.sh}"
-+QWEN36_XPU_PREFLIGHT_LOG="${QWEN36_XPU_PREFLIGHT_LOG:-${LOG_PATH%.*}-xpu-health.log}"
- MODEL_INPUT_TRACE_FILE="${MODEL_INPUT_TRACE_FILE:-}"
- MODEL_INPUT_TRACE_MAX_LINES="${MODEL_INPUT_TRACE_MAX_LINES:-400}"
- MODEL_INPUT_TRACE_RANK="${MODEL_INPUT_TRACE_RANK:-}"
-@@ -59,12 +62,37 @@ export CCL_KVS_IFACE="${CCL_KVS_IFACE:-eth1}"
- unset CCL_ZE_IPC_EXCHANGE
- unset CCL_WORKER_COUNT
- 
-+run_xpu_preflight=0
-+if [[ "$QWEN36_XPU_PREFLIGHT" == "1" ]]; then
-+  run_xpu_preflight=1
-+elif [[ "$QWEN36_XPU_PREFLIGHT" == "auto" ]] && [[ "$TP_SIZE" -ge 4 ]]; then
-+  run_xpu_preflight=1
-+fi
-+
-+if [[ "$run_xpu_preflight" == "1" ]]; then
-+  preflight_devices="${ZE_AFFINITY_MASK:-0,1,2,3}"
-+  echo "[qwen36-launch] xpu preflight devices=$preflight_devices nproc=$TP_SIZE log=$QWEN36_XPU_PREFLIGHT_LOG"
-+  if ! PHYSICAL_DEVICES="$preflight_devices" \
-+    XCCL_DEVICES="$preflight_devices" \
-+    XCCL_NPROC="$TP_SIZE" \
-+    "$QWEN36_XPU_PREFLIGHT_SCRIPT" >"$QWEN36_XPU_PREFLIGHT_LOG" 2>&1; then
-+    echo "[qwen36-launch] xpu preflight failed; refusing to start TP$TP_SIZE endpoint" >&2
-+    echo "[qwen36-launch] see $QWEN36_XPU_PREFLIGHT_LOG" >&2
-+    tail -n 80 "$QWEN36_XPU_PREFLIGHT_LOG" >&2 || true
-+    exit 1
-+  fi
-+fi
-+
- # Accepted production/provenance lane: keep rejected diagnostic MoE paths out
- # unless a new launcher explicitly opts into them.
- if [[ "${VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW:-0}" != "1" ]]; then
-   unset VLLM_XPU_W8A8_USE_OFFSETS
-   unset VLLM_XPU_W8A8_OFFSETS_PREFIX_OP
-   unset VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET
-+  unset VLLM_XPU_MOE_W8A8_FULL_LAYERLET
-+  unset VLLM_XPU_MOE_W8A8_FUSED_Q1
-+  unset VLLM_XPU_MOE_W8A8_FAST_GATHER
-+  unset VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM
- fi
- unset VLLM_XPU_MOE_ONEDNN_SIDECAR_PROBE
- unset VLLM_XPU_MOE_ONEDNN_SIDECAR_OFFSETS
-diff --git a/scripts/launch-qwen36-quark-int8-ngram-trace.sh b/scripts/launch-qwen36-quark-int8-ngram-trace.sh
-index 313b7c5..829e259 100755
---- a/scripts/launch-qwen36-quark-int8-ngram-trace.sh
-+++ b/scripts/launch-qwen36-quark-int8-ngram-trace.sh
-@@ -12,13 +12,20 @@ TAG="${TAG:-ngram${NUM_SPECULATIVE_TOKENS}-trace}"
- LOG_PATH="${LOG_PATH:-/tmp/qwen36-quark-int8-tp4-${TAG}-20260611.log}"
- SPEC_TRACE_FILE="${SPEC_TRACE_FILE:-/tmp/qwen36-${TAG}-spec-trace-20260611.jsonl}"
- SPEC_TRACE_MAX_LINES="${SPEC_TRACE_MAX_LINES:-20000}"
-+TENSOR_PARALLEL_SIZE="${TENSOR_PARALLEL_SIZE:-4}"
-+XPU_DEVICE_LIST="${XPU_DEVICE_LIST:-0,1,2,3}"
- GPU_MEMORY_UTILIZATION="${GPU_MEMORY_UTILIZATION:-0.95}"
- ENABLE_XPU_GRAPH="${ENABLE_XPU_GRAPH:-1}"
- ENFORCE_EAGER="${ENFORCE_EAGER:-0}"
- DISABLE_SPECULATIVE_CONFIG="${DISABLE_SPECULATIVE_CONFIG:-0}"
-+MAX_MODEL_LEN="${MAX_MODEL_LEN:-32768}"
-+MAX_NUM_BATCHED_TOKENS="${MAX_NUM_BATCHED_TOKENS:-8192}"
-+MAX_NUM_SEQS="${MAX_NUM_SEQS:-48}"
-+MAX_CUDAGRAPH_CAPTURE_SIZE="${MAX_CUDAGRAPH_CAPTURE_SIZE:-128}"
- CUDAGRAPH_CAPTURE_SIZES="${CUDAGRAPH_CAPTURE_SIZES:-}"
- if [[ -z "${COMPILE_CONFIG:-}" ]]; then
--  COMPILE_CONFIG='{"cudagraph_mode":"PIECEWISE","max_cudagraph_capture_size":128}'
-+  COMPILE_CONFIG=$(printf '{"cudagraph_mode":"PIECEWISE","max_cudagraph_capture_size":%s}' \
-+    "$MAX_CUDAGRAPH_CAPTURE_SIZE")
- fi
- DISABLE_FULL_ACCEPT_BONUS="${DISABLE_FULL_ACCEPT_BONUS:-${VLLM_XPU_SPEC_DECODE_DISABLE_FULL_ACCEPT_BONUS:-0}}"
- FILTER_SUPPRESSED_BONUS_CACHE="${FILTER_SUPPRESSED_BONUS_CACHE:-${VLLM_XPU_SPEC_DECODE_FILTER_SUPPRESSED_BONUS_CACHE:-0}}"
-@@ -42,8 +49,8 @@ REPLAY_MICROSCOPE_TENSOR_LIMIT="${REPLAY_MICROSCOPE_TENSOR_LIMIT:-8}"
- REPLAY_MICROSCOPE_TOPK="${REPLAY_MICROSCOPE_TOPK:-8}"
- 
- if [[ -n "$CUDAGRAPH_CAPTURE_SIZES" ]]; then
--  COMPILE_CONFIG=$(printf '{"cudagraph_mode":"PIECEWISE","cudagraph_capture_sizes":[%s],"max_cudagraph_capture_size":128}' \
--    "$CUDAGRAPH_CAPTURE_SIZES")
-+  COMPILE_CONFIG=$(printf '{"cudagraph_mode":"PIECEWISE","cudagraph_capture_sizes":[%s],"max_cudagraph_capture_size":%s}' \
-+    "$CUDAGRAPH_CAPTURE_SIZES" "$MAX_CUDAGRAPH_CAPTURE_SIZE")
- fi
- 
- export HF_HOME="${HF_HOME:-/mnt/fast-ai/llm-cache/hf}"
-@@ -70,7 +77,7 @@ export VLLM_XPU_COMPILE_ALLREDUCE_CUSTOM_OP=1
- export VLLM_XPU_CUSTOM_ALLREDUCE_GRAPH_CLONE_INPUT=1
- export VLLM_XPU_CUSTOM_ALLREDUCE_CLONE_INPUT=1
- export VLLM_XPU_QUARK_W8A8_MOE=1
--export VLLM_XPU_FORCE_QUARK_REPACK=0
-+export VLLM_XPU_FORCE_QUARK_REPACK="${VLLM_XPU_FORCE_QUARK_REPACK:-0}"
- export VLLM_XPU_GDN_REUSE_QKVZ_BA_QUANT=clone
- export VLLM_XPU_GDN_NATIVE_FALLBACK="${VLLM_XPU_GDN_NATIVE_FALLBACK:-prefill}"
- export VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK="${VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK:-1}"
-@@ -166,8 +173,8 @@ else
-   unset VLLM_XPU_REPLAY_MICROSCOPE_TENSOR_LIMIT
-   unset VLLM_XPU_REPLAY_MICROSCOPE_TOPK
- fi
--export ONEAPI_DEVICE_SELECTOR=level_zero:0,1,2,3
--export ZE_AFFINITY_MASK=0,1,2,3
-+export ONEAPI_DEVICE_SELECTOR="level_zero:${XPU_DEVICE_LIST}"
-+export ZE_AFFINITY_MASK="$XPU_DEVICE_LIST"
- export CCL_ATL_TRANSPORT=ofi
- export CCL_TOPO_P2P_ACCESS=1
- export FI_TCP_IFACE="${FI_TCP_IFACE:-eth1}"
-@@ -207,8 +214,10 @@ if [[ -n "$REPLAY_MICROSCOPE_FILE" ]]; then
-   rm -f "$REPLAY_MICROSCOPE_FILE"
- fi
- 
--SPEC_CONFIG=$(printf '{"method":"ngram","num_speculative_tokens":%s,"prompt_lookup_min":%s,"prompt_lookup_max":%s}' \
--  "$NUM_SPECULATIVE_TOKENS" "$PROMPT_LOOKUP_MIN" "$PROMPT_LOOKUP_MAX")
-+if [[ -z "${SPEC_CONFIG:-}" ]]; then
-+  SPEC_CONFIG=$(printf '{"method":"ngram","num_speculative_tokens":%s,"prompt_lookup_min":%s,"prompt_lookup_max":%s}' \
-+    "$NUM_SPECULATIVE_TOKENS" "$PROMPT_LOOKUP_MIN" "$PROMPT_LOOKUP_MAX")
-+fi
- 
- args=(
-   serve "$MODEL_PATH"
-@@ -218,12 +227,12 @@ args=(
-   --served-model-name "$SERVED_MODEL_NAME" \
-   --dtype auto \
-   --quantization quark \
--  --tensor-parallel-size 4 \
-+  --tensor-parallel-size "$TENSOR_PARALLEL_SIZE" \
-   --pipeline-parallel-size 1 \
-   --distributed-executor-backend mp \
--  --max-model-len 32768 \
--  --max-num-batched-tokens 8192 \
--  --max-num-seqs 48 \
-+  --max-model-len "$MAX_MODEL_LEN" \
-+  --max-num-batched-tokens "$MAX_NUM_BATCHED_TOKENS" \
-+  --max-num-seqs "$MAX_NUM_SEQS" \
-   --gpu-memory-utilization "$GPU_MEMORY_UTILIZATION" \
-   --kv-cache-dtype auto \
-   --no-enable-prefix-caching \
-diff --git a/scripts/qwen36-completion-oracle-trace.py b/scripts/qwen36-completion-oracle-trace.py
-index 87783e9..d937e95 100755
---- a/scripts/qwen36-completion-oracle-trace.py
-+++ b/scripts/qwen36-completion-oracle-trace.py
-@@ -236,6 +236,12 @@ def main() -> int:
-     parser.add_argument("--output-json", type=Path, required=True)
-     parser.add_argument("--baseline-json", type=Path)
-     parser.add_argument("--request-id-prefix", default=None)
-+    parser.add_argument(
-+        "--case",
-+        action="append",
-+        default=None,
-+        help="Only run the named case. May be passed more than once.",
-+    )
-     parser.add_argument(
-         "--logprobs",
-         type=int,
-@@ -254,7 +260,16 @@ def main() -> int:
- 
-     cases = []
-     comparisons: dict[str, Any] = {}
--    for case_index, case in enumerate(make_cases(tokenizer, args.prompt_tokens)):
-+    selected_cases = set(args.case or [])
-+    all_cases = [
-+        case for case in make_cases(tokenizer, args.prompt_tokens)
-+        if not selected_cases or case["name"] in selected_cases
-+    ]
-+    unknown_cases = selected_cases - {case["name"] for case in all_cases}
-+    if unknown_cases:
-+        raise ValueError(f"Unknown case name(s): {sorted(unknown_cases)}")
-+
-+    for case_index, case in enumerate(all_cases):
-         prompt = case["prompt"]
-         prompt_ids = tokenizer.encode(prompt, add_special_tokens=False)
-         request_id = (
-diff --git a/scripts/replay-qwen36-spec-trace.py b/scripts/replay-qwen36-spec-trace.py
-index c06237b..52e5140 100755
---- a/scripts/replay-qwen36-spec-trace.py
-+++ b/scripts/replay-qwen36-spec-trace.py
-@@ -40,7 +40,20 @@ def load_trace(path: Path) -> tuple[list[dict[str, Any]], int]:
- def decode_ids(tokenizer: Any | None, token_ids: list[int]) -> str | None:
-     if tokenizer is None:
-         return None
--    return tokenizer.decode(token_ids, skip_special_tokens=False)
-+    try:
-+        normalized = [int(token_id) for token_id in token_ids]
-+    except (TypeError, ValueError):
-+        return "<invalid_token_ids>"
-+    if any(token_id < 0 for token_id in normalized):
-+        preview = ",".join(str(token_id) for token_id in normalized[:16])
-+        suffix = ",..." if len(normalized) > 16 else ""
-+        return f"<invalid_token_ids:{preview}{suffix}>"
-+    try:
-+        return tokenizer.decode(normalized, skip_special_tokens=False)
-+    except Exception as exc:
-+        preview = ",".join(str(token_id) for token_id in normalized[:16])
-+        suffix = ",..." if len(normalized) > 16 else ""
-+        return f"<decode_error:{type(exc).__name__}:{preview}{suffix}>"
- 
- 
- def int_list(value: Any) -> list[int]:
-@@ -119,12 +132,35 @@ def accounting_check(
-     if suppressed_count is None:
-         suppressed_count = 1 if row.get("suppressed_bonus_token_id") is not None else 0
-     suppressed_count = int(suppressed_count or 0)
--    expected = -(num_rejected + suppressed_count)
-+    suppressed_replacement_count = int(row.get("num_suppressed_replacement_tokens") or 0)
-+    if row.get("recompute_suppressed_replacement_row"):
-+        expected = -int(row.get("num_tokens_scheduled") or 0)
-+        reason = "recompute_suppressed_replacement_row"
-+    elif row.get("recompute_suppressed_bonus_row"):
-+        expected = -int(row.get("num_tokens_scheduled") or 0)
-+        reason = "recompute_suppressed_bonus_row"
-+    elif (
-+        row.get("restore_draft_full_accept_gdn_state")
-+        and int(row.get("num_draft_tokens") or 0) > 0
-+        and int(row.get("num_accepted") or 0)
-+        == int(row.get("num_draft_tokens") or 0)
-+        and num_rejected == 0
-+    ):
-+        expected = -int(row.get("num_tokens_scheduled") or 0)
-+        reason = "restore_draft_full_accept_gdn_state"
-+    elif row.get("restore_draft_partial_reject_gdn_state") and num_rejected > 0:
-+        expected = -int(row.get("num_tokens_scheduled") or 0)
-+        reason = "restore_draft_partial_reject_gdn_state"
-+    else:
-+        expected = -(num_rejected + suppressed_count + suppressed_replacement_count)
-+        reason = "rejected_plus_suppressed"
-     return {
-         "expected_computed_delta": expected,
-         "actual_computed_delta": actual,
-         "num_rejected": num_rejected,
-         "num_suppressed_bonus_tokens": suppressed_count,
-+        "num_suppressed_replacement_tokens": suppressed_replacement_count,
-+        "reason": reason,
-         "matches": actual == expected,
-     }
- 
-@@ -217,7 +253,7 @@ def summarize_request(
-         scheduled = int_list(row.get("scheduled_spec_token_ids"))
-         generated = int_list(row.get("generated_token_ids"))
-         emitted = int_list(row.get("emitted_token_ids"))
--        if not emitted and generated:
-+        if "emitted_token_ids" not in row and generated:
-             emitted = generated
-         suppressed = row.get("suppressed_bonus_token_id")
-         suppressed_int = int(suppressed) if suppressed is not None else None
-@@ -229,11 +265,13 @@ def summarize_request(
- 
-         next_row = rows[index + 1] if index + 1 < len(rows) else None
-         followup = None
--        if suppressed_int is not None and next_row is not None:
-+        recompute_suppressed_bonus = bool(row.get("recompute_suppressed_bonus"))
-+        if (suppressed_int is not None and next_row is not None
-+                and not recompute_suppressed_bonus):
-             next_scheduled = int_list(next_row.get("scheduled_spec_token_ids"))
-             next_generated = int_list(next_row.get("generated_token_ids"))
-             next_emitted = int_list(next_row.get("emitted_token_ids"))
--            if not next_emitted and next_generated:
-+            if "emitted_token_ids" not in next_row and next_generated:
-                 next_emitted = next_generated
-             next_first = next_generated[0] if next_generated else None
-             next_scheduled_first = next_scheduled[0] if next_scheduled else None
-@@ -314,6 +352,7 @@ def summarize_request(
-                 if suppressed_int is not None
-                 else None
-             ),
-+            "recompute_suppressed_bonus": recompute_suppressed_bonus,
-             "followup_check": followup,
-             "state_transition": state_transition,
-             "accounting_check": row_accounting_check,
-diff --git a/scripts/run-qwen36-ablation-candidate.sh b/scripts/run-qwen36-ablation-candidate.sh
-index 6aa2ee0..8c422ce 100755
---- a/scripts/run-qwen36-ablation-candidate.sh
-+++ b/scripts/run-qwen36-ablation-candidate.sh
-@@ -40,12 +40,32 @@ METRICS_RANDOM_PREFIX_LEN="${METRICS_RANDOM_PREFIX_LEN:-0}"
- METRICS_PROMPT_TOKENS="${METRICS_PROMPT_TOKENS:-512}"
- METRICS_OUTPUT_TOKENS="${METRICS_OUTPUT_TOKENS:-512}"
- METRICS_WARMUP_OUTPUT_TOKENS="${METRICS_WARMUP_OUTPUT_TOKENS:-64}"
-+SERVED_MODEL_NAME="${SERVED_MODEL_NAME:-qwen36-35b-a3b-fp8}"
-+TP_SIZE="${TP_SIZE:-4}"
-+MAX_MODEL_LEN="${MAX_MODEL_LEN:-32768}"
-+MAX_NUM_BATCHED_TOKENS="${MAX_NUM_BATCHED_TOKENS:-8192}"
-+MAX_NUM_SEQS="${MAX_NUM_SEQS:-48}"
-+ONEAPI_DEVICE_SELECTOR="${ONEAPI_DEVICE_SELECTOR:-level_zero:0,1,2,3}"
-+ZE_AFFINITY_MASK="${ZE_AFFINITY_MASK:-0,1,2,3}"
-+QWEN36_XPU_PREFLIGHT="${QWEN36_XPU_PREFLIGHT:-auto}"
-+SERVER_LAUNCHER="${SERVER_LAUNCHER:-/home/steve/llm-optimizations/scripts/launch-qwen36-quark-int8-accepted.sh}"
- 
- mkdir -p "$DATA_DIR"
- 
- export MODEL_PATH
- export PORT
-+export BASE_URL
-+export CACHE_LABEL
- export LOG_PATH
-+export SERVED_MODEL_NAME
-+export TP_SIZE
-+export MAX_MODEL_LEN
-+export MAX_NUM_BATCHED_TOKENS
-+export MAX_NUM_SEQS
-+export ONEAPI_DEVICE_SELECTOR
-+export ZE_AFFINITY_MASK
-+export QWEN36_XPU_PREFLIGHT
-+export SERVER_LAUNCHER
- export TORCHINDUCTOR_CACHE_DIR="${TORCHINDUCTOR_CACHE_DIR:-/mnt/fast-ai/vllm-cache-exp/$CACHE_LABEL/torchinductor}"
- export VLLM_CACHE_ROOT="${VLLM_CACHE_ROOT:-/mnt/fast-ai/vllm-cache-exp/$CACHE_LABEL/vllm}"
- export VLLM_XPU_GDN_NATIVE_FALLBACK="${VLLM_XPU_GDN_NATIVE_FALLBACK:-decode,prefill}"
-@@ -113,12 +133,12 @@ run_step() {
- echo "[ablation:$LABEL] stamp=$STAMP"
- echo "[ablation:$LABEL] log=$LOG_PATH"
- echo "[ablation:$LABEL] cache=$CACHE_LABEL"
--echo "[ablation:$LABEL] guard env: GDN=${VLLM_XPU_GDN_NATIVE_FALLBACK:-<default>} GDN_PREFILL_FALLBACK=${VLLM_XPU_GDN_NATIVE_PREFILL_FALLBACK:-<default>} GDN_PREFILL_RECURRENT=${VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK:-<default>} GDN_INITIAL_STEPS=${VLLM_XPU_GDN_NATIVE_FALLBACK_INITIAL_DECODE_STEPS:-<default>} GDN_DECODE_LAYERS=${VLLM_XPU_GDN_NATIVE_FALLBACK_DECODE_LAYERS:-<default>} GDN_DECODE_MAX_LAYER=${VLLM_XPU_GDN_NATIVE_FALLBACK_DECODE_MAX_LAYER:-<default>} GDN_DECODE_LAYER_REGEX=${VLLM_XPU_GDN_NATIVE_FALLBACK_DECODE_LAYER_REGEX:-<default>} GDN_SYNC_DECODE=${VLLM_XPU_GDN_SYNC_BEFORE_NATIVE_DECODE:-<default>} GDN_SYNC_DECODE_LAYERS=${VLLM_XPU_GDN_SYNC_BEFORE_NATIVE_DECODE_LAYERS:-<default>} TOPK=${VLLM_XPU_GREEDY_SAMPLE_TOPK_FALLBACK:-<default>} SAMPLE_FALLBACK=${VLLM_XPU_GREEDY_SAMPLE_XPU_FALLBACK:-<default>} BF16_TOPK_FASTPATH=${VLLM_XPU_GREEDY_SAMPLE_BF16_TOPK_FASTPATH:-<default>} LOGITS_NAN_SANITIZE=${VLLM_XPU_SANITIZE_LOGITS_NAN:-<default>} LOCAL_ARGMAX=${VLLM_XPU_LOCAL_ARGMAX_DECODE:-<default>} LOCAL_ARGMAX_DIRECT=${VLLM_XPU_LOCAL_ARGMAX_DIRECT_GATHER:-<default>} LOCAL_ARGMAX_DIRECT_REUSE=${VLLM_XPU_LOCAL_ARGMAX_DIRECT_GATHER_REUSE:-<default>} LOCAL_ARGMAX_PACKED=${VLLM_XPU_LOCAL_ARGMAX_PACKED_GATHER:-<default>} LOCAL_ARGMAX_SYNC=${VLLM_XPU_LOCAL_ARGMAX_SYNC_TOKENS:-<default>} DUMMY_LOGIT_STATIC=${VLLM_XPU_DUMMY_LOGIT_INDICES_STATIC:-<default>} PREFILL_REPLAY_OFF=${VLLM_XPU_DISABLE_PREFILL_CUDAGRAPH_REPLAY:-<default>} ZERO_ALL_PREFILL_GDN=${VLLM_XPU_ZERO_ALL_PREFILL_GDN_STATE:-<default>} ZERO_FRESH_GDN=${VLLM_XPU_ZERO_FRESH_GDN_STATE:-<default>} PACKED_DECODE=${VLLM_ENABLE_FLA_PACKED_RECURRENT_DECODE:-<default>} XPU_GRAPH=${XPU_GRAPH:-<default>} VLLM_XPU_GRAPH=${VLLM_XPU_ENABLE_XPU_GRAPH:-<default>} FORCE_GRAPH_COMM=${VLLM_XPU_FORCE_GRAPH_WITH_COMM:-<default>} NOOP_COMM_CAPTURE=${VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE:-<default>} CUSTOM_COLLECTIVES=${VLLM_XPU_USE_CUSTOM_OP_COLLECTIVES:-<default>} COMPILE_ALLREDUCE_CUSTOM=${VLLM_XPU_COMPILE_ALLREDUCE_CUSTOM_OP:-<default>} CUSTOM_AR_GRAPH_CLONE=${VLLM_XPU_CUSTOM_ALLREDUCE_GRAPH_CLONE_INPUT:-<default>} CUSTOM_AR_CLONE=${VLLM_XPU_CUSTOM_ALLREDUCE_CLONE_INPUT:-<default>} REPLAY_MAX_PIECE=${VLLM_XPU_CUDAGRAPH_REPLAY_MAX_PIECEWISE_INDEX:-<default>} DISABLE_SUBMOD=${VLLM_XPU_CUDAGRAPH_DISABLE_SUBMOD_REGEX:-<default>} RECAPTURE_AFTER=${VLLM_XPU_CUDAGRAPH_RECAPTURE_AFTER_N_REPLAYS:-<default>} RECAPTURE_REGEX=${VLLM_XPU_CUDAGRAPH_RECAPTURE_REGEX:-<default>} GRAPH_STRONG_OUTPUT=${VLLM_XPU_CUDAGRAPH_STRONG_OUTPUT:-<default>} GRAPH_PER_WRAPPER_POOL=${VLLM_XPU_CUDAGRAPH_PER_WRAPPER_POOL:-<default>} GRAPH_NO_GLOBAL_POOL=${VLLM_XPU_CUDAGRAPH_NO_GLOBAL_POOL:-<default>} EAGER_EVERY_REQUESTS=${VLLM_XPU_DECODE_CUDAGRAPH_REPLAY_EAGER_EVERY_N_REQUESTS:-<default>} ALLOW_RUNTIME_RECAPTURE=${VLLM_XPU_CUDAGRAPH_ALLOW_RUNTIME_RECAPTURE:-<default>} SYNC_REPLAY=${VLLM_XPU_SYNC_CUDAGRAPH_REPLAY:-<default>} TRACE_FILE=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_FILE:-<default>} TRACE_SUBMOD=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_SUBMOD_REGEX:-<default>} TRACE_RANK=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_RANK:-<default>} TRACE_INPUTS=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_INPUTS:-<default>} TRACE_DIGEST=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_DIGEST:-<default>} ZERO_REPLAY_REGEX=${VLLM_XPU_CUDAGRAPH_ZERO_REPLAY_OUTPUT_REGEX:-<default>} ZERO_REPLAY_INDICES=${VLLM_XPU_CUDAGRAPH_ZERO_REPLAY_OUTPUT_INDICES:-<default>} CLONE_REPLAY_REGEX=${VLLM_XPU_CUDAGRAPH_CLONE_REPLAY_OUTPUT_REGEX:-<default>} CLONE_REPLAY_INDICES=${VLLM_XPU_CUDAGRAPH_CLONE_REPLAY_OUTPUT_INDICES:-<default>} STATIC_INPUT_REGEX=${VLLM_XPU_CUDAGRAPH_STATIC_INPUT_REGEX:-<default>} STATIC_INPUT_INDICES=${VLLM_XPU_CUDAGRAPH_STATIC_INPUT_INDICES:-<default>} STATIC_INPUT_MAX=${VLLM_XPU_CUDAGRAPH_STATIC_INPUT_MAX_NUMEL:-<default>} COMPARE_DIRECT_REGEX=${VLLM_XPU_CUDAGRAPH_COMPARE_DIRECT_REGEX:-<default>} COMPARE_DIRECT_RETURN=${VLLM_XPU_CUDAGRAPH_COMPARE_DIRECT_RETURN_DIRECT:-<default>} W8A8_ALLOW=${VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW:-<default>} W8A8_OFFSETS=${VLLM_XPU_W8A8_USE_OFFSETS:-<default>} W8A8_PREFIX=${VLLM_XPU_W8A8_OFFSETS_PREFIX_OP:-<default>} W8A8_LAYERLET=${VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET:-<default>} INT8_MIXED_WS=${VLLM_XPU_INT8_MOE_MIXED_WORKSPACE:-<default>} INT8_PERSIST_WS=${VLLM_XPU_INT8_MOE_PERSISTENT_SCRATCH:-<default>} XPU_SHARED_EXP=${VLLM_XPU_SHARED_EXPERTS_STREAM:-<default>} XPU_SHARED_FUSED_ACT_QUANT=${VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT:-<default>} XPU_SHARED_ADD_AR=${VLLM_XPU_MOE_SHARED_ADD_ALLREDUCE_CUSTOM_OP:-<default>} GMEM=${GPU_MEMORY_UTILIZATION:-<default>} COMPILATION_CONFIG=${COMPILATION_CONFIG:-<default>} FAST_GRAPH_AUTOCONFIG=${ABLATION_FAST_GRAPH_AUTOCONFIG:-1} EXTRA_ARGS=${VLLM_EXTRA_ARGS:-<default>}"
-+echo "[ablation:$LABEL] guard env: GDN=${VLLM_XPU_GDN_NATIVE_FALLBACK:-<default>} GDN_PREFILL_FALLBACK=${VLLM_XPU_GDN_NATIVE_PREFILL_FALLBACK:-<default>} GDN_PREFILL_RECURRENT=${VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK:-<default>} GDN_INITIAL_STEPS=${VLLM_XPU_GDN_NATIVE_FALLBACK_INITIAL_DECODE_STEPS:-<default>} GDN_DECODE_LAYERS=${VLLM_XPU_GDN_NATIVE_FALLBACK_DECODE_LAYERS:-<default>} GDN_DECODE_MAX_LAYER=${VLLM_XPU_GDN_NATIVE_FALLBACK_DECODE_MAX_LAYER:-<default>} GDN_DECODE_LAYER_REGEX=${VLLM_XPU_GDN_NATIVE_FALLBACK_DECODE_LAYER_REGEX:-<default>} GDN_SYNC_DECODE=${VLLM_XPU_GDN_SYNC_BEFORE_NATIVE_DECODE:-<default>} GDN_SYNC_DECODE_LAYERS=${VLLM_XPU_GDN_SYNC_BEFORE_NATIVE_DECODE_LAYERS:-<default>} TOPK=${VLLM_XPU_GREEDY_SAMPLE_TOPK_FALLBACK:-<default>} SAMPLE_FALLBACK=${VLLM_XPU_GREEDY_SAMPLE_XPU_FALLBACK:-<default>} BF16_TOPK_FASTPATH=${VLLM_XPU_GREEDY_SAMPLE_BF16_TOPK_FASTPATH:-<default>} LOGITS_NAN_SANITIZE=${VLLM_XPU_SANITIZE_LOGITS_NAN:-<default>} LOCAL_ARGMAX=${VLLM_XPU_LOCAL_ARGMAX_DECODE:-<default>} LOCAL_ARGMAX_DIRECT=${VLLM_XPU_LOCAL_ARGMAX_DIRECT_GATHER:-<default>} LOCAL_ARGMAX_DIRECT_REUSE=${VLLM_XPU_LOCAL_ARGMAX_DIRECT_GATHER_REUSE:-<default>} LOCAL_ARGMAX_PACKED=${VLLM_XPU_LOCAL_ARGMAX_PACKED_GATHER:-<default>} LOCAL_ARGMAX_SYNC=${VLLM_XPU_LOCAL_ARGMAX_SYNC_TOKENS:-<default>} DUMMY_LOGIT_STATIC=${VLLM_XPU_DUMMY_LOGIT_INDICES_STATIC:-<default>} PREFILL_REPLAY_OFF=${VLLM_XPU_DISABLE_PREFILL_CUDAGRAPH_REPLAY:-<default>} ZERO_ALL_PREFILL_GDN=${VLLM_XPU_ZERO_ALL_PREFILL_GDN_STATE:-<default>} ZERO_FRESH_GDN=${VLLM_XPU_ZERO_FRESH_GDN_STATE:-<default>} PACKED_DECODE=${VLLM_ENABLE_FLA_PACKED_RECURRENT_DECODE:-<default>} XPU_GRAPH=${XPU_GRAPH:-<default>} VLLM_XPU_GRAPH=${VLLM_XPU_ENABLE_XPU_GRAPH:-<default>} FORCE_GRAPH_COMM=${VLLM_XPU_FORCE_GRAPH_WITH_COMM:-<default>} NOOP_COMM_CAPTURE=${VLLM_XPU_GRAPH_NOOP_COMM_CAPTURE:-<default>} CUSTOM_COLLECTIVES=${VLLM_XPU_USE_CUSTOM_OP_COLLECTIVES:-<default>} COMPILE_ALLREDUCE_CUSTOM=${VLLM_XPU_COMPILE_ALLREDUCE_CUSTOM_OP:-<default>} CUSTOM_AR_GRAPH_CLONE=${VLLM_XPU_CUSTOM_ALLREDUCE_GRAPH_CLONE_INPUT:-<default>} CUSTOM_AR_CLONE=${VLLM_XPU_CUSTOM_ALLREDUCE_CLONE_INPUT:-<default>} REPLAY_MAX_PIECE=${VLLM_XPU_CUDAGRAPH_REPLAY_MAX_PIECEWISE_INDEX:-<default>} DISABLE_SUBMOD=${VLLM_XPU_CUDAGRAPH_DISABLE_SUBMOD_REGEX:-<default>} RECAPTURE_AFTER=${VLLM_XPU_CUDAGRAPH_RECAPTURE_AFTER_N_REPLAYS:-<default>} RECAPTURE_REGEX=${VLLM_XPU_CUDAGRAPH_RECAPTURE_REGEX:-<default>} GRAPH_STRONG_OUTPUT=${VLLM_XPU_CUDAGRAPH_STRONG_OUTPUT:-<default>} GRAPH_PER_WRAPPER_POOL=${VLLM_XPU_CUDAGRAPH_PER_WRAPPER_POOL:-<default>} GRAPH_NO_GLOBAL_POOL=${VLLM_XPU_CUDAGRAPH_NO_GLOBAL_POOL:-<default>} EAGER_EVERY_REQUESTS=${VLLM_XPU_DECODE_CUDAGRAPH_REPLAY_EAGER_EVERY_N_REQUESTS:-<default>} ALLOW_RUNTIME_RECAPTURE=${VLLM_XPU_CUDAGRAPH_ALLOW_RUNTIME_RECAPTURE:-<default>} SYNC_REPLAY=${VLLM_XPU_SYNC_CUDAGRAPH_REPLAY:-<default>} TRACE_FILE=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_FILE:-<default>} TRACE_SUBMOD=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_SUBMOD_REGEX:-<default>} TRACE_RANK=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_RANK:-<default>} TRACE_INPUTS=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_INPUTS:-<default>} TRACE_DIGEST=${VLLM_XPU_CUDAGRAPH_REPLAY_TRACE_DIGEST:-<default>} ZERO_REPLAY_REGEX=${VLLM_XPU_CUDAGRAPH_ZERO_REPLAY_OUTPUT_REGEX:-<default>} ZERO_REPLAY_INDICES=${VLLM_XPU_CUDAGRAPH_ZERO_REPLAY_OUTPUT_INDICES:-<default>} CLONE_REPLAY_REGEX=${VLLM_XPU_CUDAGRAPH_CLONE_REPLAY_OUTPUT_REGEX:-<default>} CLONE_REPLAY_INDICES=${VLLM_XPU_CUDAGRAPH_CLONE_REPLAY_OUTPUT_INDICES:-<default>} STATIC_INPUT_REGEX=${VLLM_XPU_CUDAGRAPH_STATIC_INPUT_REGEX:-<default>} STATIC_INPUT_INDICES=${VLLM_XPU_CUDAGRAPH_STATIC_INPUT_INDICES:-<default>} STATIC_INPUT_MAX=${VLLM_XPU_CUDAGRAPH_STATIC_INPUT_MAX_NUMEL:-<default>} COMPARE_DIRECT_REGEX=${VLLM_XPU_CUDAGRAPH_COMPARE_DIRECT_REGEX:-<default>} COMPARE_DIRECT_RETURN=${VLLM_XPU_CUDAGRAPH_COMPARE_DIRECT_RETURN_DIRECT:-<default>} W8A8_ALLOW=${VLLM_XPU_W8A8_EXPERIMENTAL_ALLOW:-<default>} W8A8_OFFSETS=${VLLM_XPU_W8A8_USE_OFFSETS:-<default>} W8A8_PREFIX=${VLLM_XPU_W8A8_OFFSETS_PREFIX_OP:-<default>} W8A8_LAYERLET=${VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET:-<default>} W8A8_FULL=${VLLM_XPU_MOE_W8A8_FULL_LAYERLET:-<default>} W8A8_Q1=${VLLM_XPU_MOE_W8A8_FUSED_Q1:-<default>} W8A8_FAST_GATHER=${VLLM_XPU_MOE_W8A8_FAST_GATHER:-<default>} W8A8_DIRECT_GEMM2_GATHER=${VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER:-<default>} W8A8_DPAS_GEMM2_GATHER=${VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER:-<default>} W8A8_DPAS_GEMM2_GATHER_NTILE=${VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE:-<default>} W8A8_WORKSPACE_ATOMIC=${VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC:-<default>} W8A8_ROUTE_GEMM1=${VLLM_XPU_MOE_W8A8_ROUTE_GEMM1:-<default>} W8A8_ROUTE_GEMM1_MTILE=${VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE:-<default>} INT8_MIXED_WS=${VLLM_XPU_INT8_MOE_MIXED_WORKSPACE:-<default>} INT8_PERSIST_WS=${VLLM_XPU_INT8_MOE_PERSISTENT_SCRATCH:-<default>} INT8_ACTIVE_OFFSET=${VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM:-<default>} XPU_SHARED_EXP=${VLLM_XPU_SHARED_EXPERTS_STREAM:-<default>} XPU_SHARED_FUSED_ACT_QUANT=${VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT:-<default>} XPU_SHARED_FUSED_ACT_QUANT_OUT=${VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT:-<default>} XPU_SHARED_BOUNDARY_OUT=${VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT:-<default>} XPU_SHARED_GATE_MUL=${VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL:-<default>} XPU_SHARED_ADD_AR=${VLLM_XPU_MOE_SHARED_ADD_ALLREDUCE_CUSTOM_OP:-<default>} GMEM=${GPU_MEMORY_UTILIZATION:-<default>} COMPILATION_CONFIG=${COMPILATION_CONFIG:-<default>} SPEC_CONFIG=${SPEC_CONFIG:-<default>} FAST_GRAPH_AUTOCONFIG=${ABLATION_FAST_GRAPH_AUTOCONFIG:-1} EXTRA_ARGS=${VLLM_EXTRA_ARGS:-<default>}"
- 
- echo "[ablation:$LABEL] fused-prologue: OFFSET=${VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET:-<unset>} ALLOW_CAPTURE=${VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE:-<unset>} SKIP_LAYERS=${VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_SKIP_LAYERS:-<unset>} LAYER_REGEX=${VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_LAYER_REGEX:-<unset>}"
--echo "[ablation:$LABEL] server_launcher=${SERVER_LAUNCHER:-launch-qwen36-quark-int8-accepted.sh}"
-+echo "[ablation:$LABEL] server_launcher=$SERVER_LAUNCHER"
- 
--"${SERVER_LAUNCHER:-/home/steve/llm-optimizations/scripts/launch-qwen36-quark-int8-accepted.sh}" &
-+"$SERVER_LAUNCHER" &
- SERVER_PID=$!
- 
- ready=0
-@@ -294,6 +314,21 @@ out = {
-         "log": Path(log_path).exists(),
-     },
-     "env": {
-+        "MODEL_PATH": os.environ.get("MODEL_PATH"),
-+        "SERVED_MODEL_NAME": os.environ.get("SERVED_MODEL_NAME"),
-+        "SERVER_LAUNCHER": os.environ.get("SERVER_LAUNCHER"),
-+        "TP_SIZE": os.environ.get("TP_SIZE"),
-+        "MAX_MODEL_LEN": os.environ.get("MAX_MODEL_LEN"),
-+        "MAX_NUM_BATCHED_TOKENS": os.environ.get("MAX_NUM_BATCHED_TOKENS"),
-+        "MAX_NUM_SEQS": os.environ.get("MAX_NUM_SEQS"),
-+        "ONEAPI_DEVICE_SELECTOR": os.environ.get("ONEAPI_DEVICE_SELECTOR"),
-+        "ZE_AFFINITY_MASK": os.environ.get("ZE_AFFINITY_MASK"),
-+        "QWEN36_XPU_PREFLIGHT": os.environ.get("QWEN36_XPU_PREFLIGHT"),
-+        "CACHE_LABEL": os.environ.get("CACHE_LABEL"),
-+        "TORCHINDUCTOR_CACHE_DIR": os.environ.get("TORCHINDUCTOR_CACHE_DIR"),
-+        "VLLM_CACHE_ROOT": os.environ.get("VLLM_CACHE_ROOT"),
-+        "BASE_URL": os.environ.get("BASE_URL"),
-+        "PORT": os.environ.get("PORT"),
-         "VLLM_XPU_GDN_NATIVE_FALLBACK": os.environ.get("VLLM_XPU_GDN_NATIVE_FALLBACK"),
-         "VLLM_XPU_GDN_NATIVE_PREFILL_FALLBACK": os.environ.get("VLLM_XPU_GDN_NATIVE_PREFILL_FALLBACK"),
-         "VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK": os.environ.get("VLLM_XPU_GDN_PREFILL_RECURRENT_FALLBACK"),
-@@ -366,20 +401,34 @@ out = {
-         "VLLM_XPU_W8A8_USE_OFFSETS": os.environ.get("VLLM_XPU_W8A8_USE_OFFSETS"),
-         "VLLM_XPU_W8A8_OFFSETS_PREFIX_OP": os.environ.get("VLLM_XPU_W8A8_OFFSETS_PREFIX_OP"),
-         "VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET": os.environ.get("VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET"),
-+        "VLLM_XPU_MOE_W8A8_FULL_LAYERLET": os.environ.get("VLLM_XPU_MOE_W8A8_FULL_LAYERLET"),
-+        "VLLM_XPU_MOE_W8A8_FUSED_Q1": os.environ.get("VLLM_XPU_MOE_W8A8_FUSED_Q1"),
-+        "VLLM_XPU_MOE_W8A8_FAST_GATHER": os.environ.get("VLLM_XPU_MOE_W8A8_FAST_GATHER"),
-+        "VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER": os.environ.get("VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER"),
-+        "VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER": os.environ.get("VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER"),
-+        "VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE": os.environ.get("VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE"),
-+        "VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC": os.environ.get("VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC"),
-+        "VLLM_XPU_MOE_W8A8_ROUTE_GEMM1": os.environ.get("VLLM_XPU_MOE_W8A8_ROUTE_GEMM1"),
-+        "VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE": os.environ.get("VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE"),
-         "VLLM_XPU_INT8_MOE_MIXED_WORKSPACE": os.environ.get("VLLM_XPU_INT8_MOE_MIXED_WORKSPACE"),
-         "VLLM_XPU_INT8_MOE_PERSISTENT_SCRATCH": os.environ.get("VLLM_XPU_INT8_MOE_PERSISTENT_SCRATCH"),
-         "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET": os.environ.get("VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET"),
-         "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE": os.environ.get("VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE"),
-         "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_SKIP_LAYERS": os.environ.get("VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_SKIP_LAYERS"),
-         "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_LAYER_REGEX": os.environ.get("VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_LAYER_REGEX"),
-+        "VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM": os.environ.get("VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM"),
-         "VLLM_XPU_SHARED_EXPERTS_STREAM": os.environ.get("VLLM_XPU_SHARED_EXPERTS_STREAM"),
-         "VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT": os.environ.get("VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT"),
-+        "VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT": os.environ.get("VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT"),
-+        "VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT": os.environ.get("VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT"),
-+        "VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL": os.environ.get("VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL"),
-         "VLLM_XPU_MOE_SHARED_ADD_ALLREDUCE_CUSTOM_OP": os.environ.get("VLLM_XPU_MOE_SHARED_ADD_ALLREDUCE_CUSTOM_OP"),
-         "VLLM_XPU_METADATA_COPY_ALLOW": os.environ.get("VLLM_XPU_METADATA_COPY_ALLOW"),
-         "VLLM_XPU_BLOCK_TABLE_DIRTY_COMMIT": os.environ.get("VLLM_XPU_BLOCK_TABLE_DIRTY_COMMIT"),
-         "VLLM_XPU_BLOCK_TABLE_DIRTY_COMMIT_LOG_EVERY": os.environ.get("VLLM_XPU_BLOCK_TABLE_DIRTY_COMMIT_LOG_EVERY"),
-         "GPU_MEMORY_UTILIZATION": os.environ.get("GPU_MEMORY_UTILIZATION"),
-         "COMPILATION_CONFIG": os.environ.get("COMPILATION_CONFIG"),
-+        "SPEC_CONFIG": os.environ.get("SPEC_CONFIG"),
-         "ABLATION_FAST_GRAPH_AUTOCONFIG": os.environ.get("ABLATION_FAST_GRAPH_AUTOCONFIG", "1"),
-         "VLLM_EXTRA_ARGS": os.environ.get("VLLM_EXTRA_ARGS"),
-         "METRICS_PROMPT_KIND": os.environ.get("METRICS_PROMPT_KIND"),
-diff --git a/scripts/run-qwen36-decisive-timing.sh b/scripts/run-qwen36-decisive-timing.sh
-index f78ed2a..aa54580 100755
---- a/scripts/run-qwen36-decisive-timing.sh
-+++ b/scripts/run-qwen36-decisive-timing.sh
-@@ -202,10 +202,26 @@ payload = {
-         "VLLM_XPU_W8A8_USE_OFFSETS": os.environ.get("VLLM_XPU_W8A8_USE_OFFSETS"),
-         "VLLM_XPU_W8A8_OFFSETS_PREFIX_OP": os.environ.get("VLLM_XPU_W8A8_OFFSETS_PREFIX_OP"),
-         "VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET": os.environ.get("VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET"),
-+        "VLLM_XPU_MOE_W8A8_FULL_LAYERLET": os.environ.get("VLLM_XPU_MOE_W8A8_FULL_LAYERLET"),
-+        "VLLM_XPU_MOE_W8A8_FUSED_Q1": os.environ.get("VLLM_XPU_MOE_W8A8_FUSED_Q1"),
-+        "VLLM_XPU_MOE_W8A8_FAST_GATHER": os.environ.get("VLLM_XPU_MOE_W8A8_FAST_GATHER"),
-+        "VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER": os.environ.get("VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER"),
-+        "VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER": os.environ.get("VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER"),
-+        "VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE": os.environ.get("VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE"),
-+        "VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC": os.environ.get("VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC"),
-+        "VLLM_XPU_MOE_W8A8_ROUTE_GEMM1": os.environ.get("VLLM_XPU_MOE_W8A8_ROUTE_GEMM1"),
-+        "VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE": os.environ.get("VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE"),
-         "VLLM_XPU_INT8_MOE_MIXED_WORKSPACE": os.environ.get("VLLM_XPU_INT8_MOE_MIXED_WORKSPACE"),
-+        "VLLM_XPU_INT8_MOE_PERSISTENT_SCRATCH": os.environ.get("VLLM_XPU_INT8_MOE_PERSISTENT_SCRATCH"),
-+        "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET": os.environ.get("VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET"),
-+        "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE": os.environ.get("VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE"),
-         "VLLM_XPU_SHARED_EXPERTS_STREAM": os.environ.get("VLLM_XPU_SHARED_EXPERTS_STREAM"),
-         "VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT": os.environ.get("VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT"),
-+        "VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT": os.environ.get("VLLM_XPU_SHARED_EXPERT_FUSED_ACT_QUANT_OUT"),
-+        "VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT": os.environ.get("VLLM_XPU_SHARED_EXPERT_BOUNDARY_OUT"),
-         "VLLM_XPU_DECODE_TIMING_LABEL_REGEX": os.environ.get("VLLM_XPU_DECODE_TIMING_LABEL_REGEX"),
-+        "VLLM_EXTRA_ARGS": os.environ.get("VLLM_EXTRA_ARGS"),
-+        "GPU_MEMORY_UTILIZATION": os.environ.get("GPU_MEMORY_UTILIZATION"),
-     },
- }
- if run_canaries == "1":
-diff --git a/scripts/run-qwen36-oracle-parity-gate.sh b/scripts/run-qwen36-oracle-parity-gate.sh
-index c0c02a7..7bedfd2 100755
---- a/scripts/run-qwen36-oracle-parity-gate.sh
-+++ b/scripts/run-qwen36-oracle-parity-gate.sh
-@@ -35,6 +35,7 @@ REQUIRE_SPEC_JOIN="${REQUIRE_SPEC_JOIN:-1}"
- MIN_DRAFT_TOKENS="${MIN_DRAFT_TOKENS:-1}"
- MIN_ACCEPTED_TOKENS="${MIN_ACCEPTED_TOKENS:-1}"
- MIN_ACCEPT_RATE_PCT="${MIN_ACCEPT_RATE_PCT:-}"
-+ALLOW_REPLAY_ACCOUNTING_MISMATCH="${ALLOW_REPLAY_ACCOUNTING_MISMATCH:-0}"
- 
- mkdir -p "$DATA_DIR"
- 
-@@ -114,6 +115,9 @@ fi
- if [[ "$REQUIRE_SPEC_JOIN" == "1" ]]; then
-   check_args+=(--require-spec-join)
- fi
-+if [[ "$ALLOW_REPLAY_ACCOUNTING_MISMATCH" == "1" ]]; then
-+  check_args+=(--allow-replay-accounting-mismatch)
-+fi
- if [[ "$MIN_DRAFT_TOKENS" != "0" ]]; then
-   check_args+=(--min-draft-tokens "$MIN_DRAFT_TOKENS")
- fi
-diff --git a/scripts/run-qwen36-spec-parity-candidate.sh b/scripts/run-qwen36-spec-parity-candidate.sh
-new file mode 100755
-index 0000000..e2d51a0
---- /dev/null
-+++ b/scripts/run-qwen36-spec-parity-candidate.sh
-@@ -0,0 +1,162 @@
-+#!/usr/bin/env bash
-+set -uo pipefail
-+
-+if [[ $# -lt 1 ]]; then
-+  echo "usage: $0 <label>" >&2
-+  echo "set SPEC_CONFIG to the speculative config JSON to test" >&2
-+  exit 2
-+fi
-+
-+LABEL="$1"
-+ROOT="${ROOT:-/home/steve/llm-optimizations}"
-+DATA="${DATA:-$ROOT/data}"
-+PY="${PY:-/home/steve/.venvs/vllm-xpu/bin/python}"
-+TOKENIZER="${TOKENIZER:-/mnt/fast-ai/llm-cache/hf/models--nameistoken--Qwen3.6-35B-A3B-Quark-W8A8-INT8/snapshots/cced56592e8c8935f8220836b4baa04dfd389118}"
-+BASE="${BASE:-$DATA/qwen36-nospec-notrace-fixture-eager-tp2-20260617ao-candidate.json}"
-+PORT="${PORT:-18080}"
-+STAMP="${STAMP:-$(date -u +%Y%m%d%H%M%S)}"
-+TAG="${TAG:-$LABEL-$STAMP}"
-+
-+LOG="$DATA/$TAG.log"
-+SPEC="$DATA/$TAG-spec-trace.jsonl"
-+CAND="$DATA/$TAG-candidate.json"
-+FIXTURE="$DATA/$TAG-fixture.json"
-+FIXTURE_MD="$DATA/$TAG-fixture.md"
-+SUMMARY="$DATA/$TAG-spec-summary.json"
-+GATE="$DATA/$TAG-gate-summary.json"
-+REPLAY="$DATA/$TAG-replay.json"
-+REPLAY_MD="$DATA/$TAG-replay.md"
-+
-+mkdir -p "$DATA"
-+rm -f "$LOG" "$SPEC" "$CAND" "$FIXTURE" "$FIXTURE_MD" \
-+  "$SUMMARY" "$GATE" "$REPLAY" "$REPLAY_MD"
-+
-+cleanup() {
-+  if [[ -n "${SERVER_PID:-}" ]]; then
-+    kill "$SERVER_PID" 2>/dev/null || true
-+    wait "$SERVER_PID" 2>/dev/null || true
-+  fi
-+  local pids
-+  pids=$(ps -eo pid,ppid,cmd \
-+    | rg "$PORT|VLLM::|vllm serve|launch-qwen36" \
-+    | rg -v 'rg ' \
-+    | awk '{print $1}' || true)
-+  if [[ -n "$pids" ]]; then
-+    kill -9 $pids 2>/dev/null || true
-+  fi
-+}
-+trap cleanup EXIT
-+
-+echo "[spec-parity:$LABEL] tag=$TAG"
-+echo "[spec-parity:$LABEL] base=$BASE"
-+echo "[spec-parity:$LABEL] spec_config=${SPEC_CONFIG:-<launcher-default>}"
-+echo "[spec-parity:$LABEL] log=$LOG"
-+
-+TAG="$TAG" \
-+SPEC_TRACE_FILE="$SPEC" \
-+LOG_PATH="$LOG" \
-+PORT="$PORT" \
-+TENSOR_PARALLEL_SIZE="${TENSOR_PARALLEL_SIZE:-2}" \
-+XPU_DEVICE_LIST="${XPU_DEVICE_LIST:-0,1}" \
-+GPU_MEMORY_UTILIZATION="${GPU_MEMORY_UTILIZATION:-0.82}" \
-+ENABLE_XPU_GRAPH="${ENABLE_XPU_GRAPH:-0}" \
-+ENFORCE_EAGER="${ENFORCE_EAGER:-1}" \
-+COMPILE_CONFIG="${COMPILE_CONFIG:-$(printf '{"cudagraph_mode":"PIECEWISE","max_cudagraph_capture_size":%s}' "${MAX_CUDAGRAPH_CAPTURE_SIZE:-128}")}" \
-+"${SERVER_LAUNCHER:-$ROOT/scripts/launch-qwen36-quark-int8-ngram-trace.sh}" &
-+SERVER_PID=$!
-+
-+ready=0
-+for _ in $(seq 1 "${READINESS_TIMEOUT_STEPS:-240}"); do
-+  if curl -fsS "http://127.0.0.1:$PORT/v1/models" >/dev/null 2>&1; then
-+    ready=1
-+    break
-+  fi
-+  if ! kill -0 "$SERVER_PID" 2>/dev/null; then
-+    echo "[spec-parity:$LABEL] server exited before readiness; log follows" >&2
-+    tail -120 "$LOG" >&2 || true
-+    exit 1
-+  fi
-+  sleep "${READINESS_SLEEP_S:-2}"
-+done
-+
-+if [[ "$ready" != "1" ]]; then
-+  echo "[spec-parity:$LABEL] server did not become ready; log follows" >&2
-+  tail -160 "$LOG" >&2 || true
-+  exit 1
-+fi
-+
-+set +e
-+"$PY" "$ROOT/scripts/qwen36-completion-oracle-trace.py" \
-+  --base-url "http://127.0.0.1:$PORT" \
-+  --tokenizer "$TOKENIZER" \
-+  --prompt-tokens "${PROMPT_TOKENS:-512}" \
-+  --output-tokens "${OUTPUT_TOKENS:-32}" \
-+  --baseline-json "$BASE" \
-+  --case "${CASE_NAME:-natural_latency_plan}" \
-+  --request-id-prefix "$TAG" \
-+  --output-json "$CAND"
-+trace_rc=$?
-+
-+SPEC_TRACE_JSONL="$SPEC" \
-+SPEC_SUMMARY_JSON="$SUMMARY" \
-+ACCEPTED_TRACE_JSON="$BASE" \
-+CANDIDATE_TRACE_JSON="$CAND" \
-+FIXTURE_JSON="$FIXTURE" \
-+FIXTURE_MD="$FIXTURE_MD" \
-+REPLAY_OUT_JSON="$REPLAY" \
-+REPLAY_OUT_MD="$REPLAY_MD" \
-+SUMMARY_JSON="$GATE" \
-+MODE="${MODE:-exact}" \
-+EXPECT_SPEC_ACTIVE="${EXPECT_SPEC_ACTIVE:-1}" \
-+REQUIRE_SPEC_JOIN="${REQUIRE_SPEC_JOIN:-1}" \
-+MIN_DRAFT_TOKENS="${MIN_DRAFT_TOKENS:-1}" \
-+MIN_ACCEPTED_TOKENS="${MIN_ACCEPTED_TOKENS:-1}" \
-+MIN_ACCEPT_RATE_PCT="${MIN_ACCEPT_RATE_PCT:-}" \
-+ALLOW_REPLAY_ACCOUNTING_MISMATCH="${ALLOW_REPLAY_ACCOUNTING_MISMATCH:-0}" \
-+"$ROOT/scripts/run-qwen36-oracle-parity-gate.sh" "$TAG"
-+check_rc=$?
-+
-+"$PY" - "$BASE" "$CAND" "$GATE" "$trace_rc" "$TAG" <<'PY'
-+import json
-+import sys
-+from pathlib import Path
-+
-+base_path = Path(sys.argv[1])
-+cand_path = Path(sys.argv[2])
-+gate_path = Path(sys.argv[3])
-+base = json.load(open(base_path)) if base_path.exists() else {"cases": []}
-+cand = json.load(open(cand_path)) if cand_path.exists() else {"cases": []}
-+gate = json.load(open(gate_path)) if gate_path.exists() else {}
-+
-+base_cases = {case.get("name"): case for case in base.get("cases", [])}
-+rows = []
-+for case in cand.get("cases", []):
-+    name = case.get("name")
-+    b = base_cases.get(name, {}).get("output_token_ids", [])
-+    c = case.get("output_token_ids", [])
-+    first = None
-+    for i, (x, y) in enumerate(zip(b, c)):
-+        if x != y:
-+            first = i
-+            break
-+    if first is None and len(b) != len(c):
-+        first = min(len(b), len(c))
-+    rows.append({
-+        "case": name,
-+        "first_diff": first,
-+        "baseline_window": b[max(0, (first or 0) - 8):(first or 0) + 12] if first is not None else [],
-+        "candidate_window": c[max(0, (first or 0) - 8):(first or 0) + 12] if first is not None else [],
-+        "candidate_count": len(c),
-+        "baseline_count": len(b),
-+    })
-+
-+print(json.dumps({
-+    "tag": sys.argv[5],
-+    "trace_rc": int(sys.argv[4]),
-+    "gate_pass": gate.get("pass"),
-+    "gate_return_codes": gate.get("return_codes"),
-+    "cases": rows,
-+}, indent=2))
-+PY
-+
-+exit "$check_rc"
diff --git a/patches/vllm-xpu-kernels-qwen36-routegemm1-blayoutfix-20260620.patch b/patches/vllm-xpu-kernels-qwen36-routegemm1-blayoutfix-20260620.patch
index 384ac7b..e10340e 100644
--- a/patches/vllm-xpu-kernels-qwen36-routegemm1-blayoutfix-20260620.patch
+++ b/patches/vllm-xpu-kernels-qwen36-routegemm1-blayoutfix-20260620.patch
@@ -1,3114 +1,117 @@
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 5f8835a..9340c77 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -544,7 +544,9 @@ if(XPU_SPECIFIC_KERNELS_ENABLED)
-   if(MOE_KERNELS_ENABLED)
-     list(APPEND VLLM_EXT_XPU_SRC
-          "csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp"
--         "csrc/xpu/moe_layerlet.cpp")
-+         "csrc/xpu/moe_layerlet.cpp"
-+         "csrc/moe/fused_moe_prologue.cpp"
-+         "csrc/moe/moe_gather.cpp")
-   endif()
-   if(GDN_KERNELS_ENABLED)
-     list(APPEND VLLM_EXT_XPU_SRC "csrc/xpu/gdn_attn/gdn_attn_interface.cpp")
-diff --git a/csrc/activation.cpp b/csrc/activation.cpp
-index f957136..309b6fd 100644
---- a/csrc/activation.cpp
-+++ b/csrc/activation.cpp
-@@ -1,6 +1,7 @@
- #include <sycl/sycl.hpp>
- #include <cmath>
- #include <algorithm>
-+#include <cstdlib>
- #include <numeric>
- #include "utils.h"
- #include "dispatch_utils.h"
-@@ -376,6 +377,40 @@ class swiglustep_and_mul_kernel {
-   const float limit;
- };
- 
-+inline int forced_act_and_mul_vec_size() {
-+  static const int forced = []() {
-+    const char* value = std::getenv("VLLM_XPU_ACT_AND_MUL_VEC_SIZE");
-+    if (value == nullptr || value[0] == '\0') {
-+      return 0;
-+    }
-+    const int parsed = std::atoi(value);
-+    if (parsed == 1 || parsed == 2 || parsed == 4 || parsed == 8 ||
-+        parsed == 16) {
-+      return parsed;
-+    }
-+    return 0;
-+  }();
-+  return forced;
-+}
-+
-+inline int select_act_and_mul_vec_size(const int d, const int scalar_size) {
-+  const int forced = forced_act_and_mul_vec_size();
-+  if (forced > 0 && d % forced == 0) {
-+    return forced;
-+  }
-+
-+  int vec_size = static_cast<int>(sizeof(float) * 4 / scalar_size);
-+  int64_t tmp_wg =
-+      std::min(static_cast<int64_t>(d), static_cast<int64_t>(1024));
-+  while (vec_size > 1 && (vec_size >> 1) * tmp_wg >= d) {
-+    vec_size = vec_size >> 1;
-+  }
-+  if (d % vec_size != 0) {
-+    vec_size = 1;
-+  }
-+  return vec_size;
-+}
-+
- }  // namespace vllm
- 
- // Launch activation and gating kernel.
-@@ -435,15 +470,7 @@ class swiglustep_and_mul_kernel {
-   auto input_ptr = input.data_ptr<scalar_t>();                           \
-   at::DeviceGuard device_guard(input.device());                          \
-   auto& queue = vllm::xpu::vllmGetQueue();                               \
--  int vec_size = static_cast<int>(sizeof(float) * 4 / sizeof(scalar_t)); \
--  {                                                                      \
--    int64_t tmp_wg =                                                     \
--        std::min(static_cast<int64_t>(d), static_cast<int64_t>(1024));   \
--    while (vec_size > 1 && (vec_size >> 1) * tmp_wg >= d) {              \
--      vec_size = vec_size >> 1;                                          \
--    }                                                                    \
--  }                                                                      \
--  if (d % vec_size != 0) vec_size = 1;                                   \
-+  int vec_size = vllm::select_act_and_mul_vec_size(d, sizeof(scalar_t)); \
-   int64_t wg_size = std::min(                                            \
-       static_cast<int64_t>(d / vec_size), static_cast<int64_t>(1024));   \
-   switch (vec_size) {                                                    \
-@@ -468,15 +495,7 @@ class swiglustep_and_mul_kernel {
-   const float param = static_cast<float>(PARAM);                         \
-   at::DeviceGuard device_guard(input.device());                          \
-   auto& queue = vllm::xpu::vllmGetQueue();                               \
--  int vec_size = static_cast<int>(sizeof(float) * 4 / sizeof(scalar_t)); \
--  {                                                                      \
--    int64_t tmp_wg =                                                     \
--        std::min(static_cast<int64_t>(d), static_cast<int64_t>(1024));   \
--    while (vec_size > 1 && (vec_size >> 1) * tmp_wg >= d) {              \
--      vec_size = vec_size >> 1;                                          \
--    }                                                                    \
--  }                                                                      \
--  if (d % vec_size != 0) vec_size = 1;                                   \
-+  int vec_size = vllm::select_act_and_mul_vec_size(d, sizeof(scalar_t)); \
-   int64_t wg_size = std::min(                                            \
-       static_cast<int64_t>(d / vec_size), static_cast<int64_t>(1024));   \
-   switch (vec_size) {                                                    \
-@@ -529,16 +548,7 @@ void silu_and_mul(
-   auto scale_ptr = scale.data_ptr<float>();                                  \
-   at::DeviceGuard device_guard(input.device());                              \
-   auto& queue = vllm::xpu::vllmGetQueue();                                   \
--  /* Compute vec_size like non-quant path: gcd(4*sizeof(float)/sizeof, d) */ \
--  int vec_size = static_cast<int>(sizeof(float) * 4 / sizeof(sycl_t));       \
--  {                                                                          \
--    int64_t tmp_wg =                                                         \
--        std::min(static_cast<int64_t>(d), static_cast<int64_t>(1024));       \
--    while (vec_size > 1 && (vec_size >> 1) * tmp_wg >= d) {                  \
--      vec_size = vec_size >> 1;                                              \
--    }                                                                        \
--  }                                                                          \
--  if (d % vec_size != 0) vec_size = 1;                                       \
-+  int vec_size = vllm::select_act_and_mul_vec_size(d, sizeof(sycl_t));       \
-   switch (vec_size) {                                                        \
-     LAUNCH_ACT_AND_MUL_QUANT_VEC(KERNEL, 1);                                 \
-     LAUNCH_ACT_AND_MUL_QUANT_VEC(KERNEL, 2);                                 \
-diff --git a/csrc/moe/fused_moe_prologue.hpp b/csrc/moe/fused_moe_prologue.hpp
-index 473e997..28d7c79 100644
---- a/csrc/moe/fused_moe_prologue.hpp
-+++ b/csrc/moe/fused_moe_prologue.hpp
-@@ -429,14 +429,16 @@ class MergeExpertPrefixSumKernel {
-       int* permuted_token_selected_experts,
-       int* permuted_row_to_unpermuted_row,
-       int* unpermuted_row_to_permuted_row,
--      int num_tokens)
-+      int num_tokens,
-+      int num_experts_per_token)
-       : blocked_expert_counts(blocked_expert_counts),
-         blocked_expert_counts_cumsum(blocked_expert_counts_cumsum),
-         blocked_row_to_unpermuted_row(blocked_row_to_unpermuted_row),
-         permuted_token_selected_experts(permuted_token_selected_experts),
-         permuted_row_to_unpermuted_row(permuted_row_to_unpermuted_row),
-         unpermuted_row_to_permuted_row(unpermuted_row_to_permuted_row),
--        num_tokens(num_tokens) {}
-+        num_tokens(num_tokens),
-+        num_experts_per_token(num_experts_per_token) {}
- 
-   void operator()
-       [[sycl::reqd_sub_group_size(32)]] (const sycl::nd_item<3>& item) const {
-@@ -454,10 +456,13 @@ class MergeExpertPrefixSumKernel {
-       int const unpermuted_row = blocked_row_to_unpermuted_row
-           [target_expert_id * num_tokens + token_id];
-       int const permuted_row = offset + item.get_local_id(2);
-+      int const source_k_rank = unpermuted_row / num_tokens;
-+      int const source_row = unpermuted_row % num_tokens;
- 
-       permuted_row_to_unpermuted_row[permuted_row] = unpermuted_row;
-       permuted_token_selected_experts[permuted_row] = target_expert_id;
--      unpermuted_row_to_permuted_row[unpermuted_row] = permuted_row;
-+      unpermuted_row_to_permuted_row
-+          [source_row * num_experts_per_token + source_k_rank] = permuted_row;
-     }
-   }
- 
-@@ -469,6 +474,7 @@ class MergeExpertPrefixSumKernel {
-   int* permuted_row_to_unpermuted_row;
-   int* unpermuted_row_to_permuted_row;
-   const int num_tokens;
-+  const int num_experts_per_token;
- };
- 
- void mergeExpertPrefixSum(
-@@ -479,6 +485,7 @@ void mergeExpertPrefixSum(
-     int* permuted_row_to_unpermuted_row,
-     int* unpermuted_row_to_permuted_row,
-     int64_t const num_tokens,
-+    int64_t const num_experts_per_token,
-     int64_t const num_experts_per_node,
-     int64_t const num_tokens_per_block,
-     int64_t const num_blocks_per_seq,
-@@ -495,7 +502,8 @@ void mergeExpertPrefixSum(
-             permuted_token_selected_experts,
-             permuted_row_to_unpermuted_row,
-             unpermuted_row_to_permuted_row,
--            num_tokens));
-+            num_tokens,
-+            num_experts_per_token));
-   });
- }
- 
-@@ -546,6 +554,7 @@ void threeStepBuildExpertMapsSortFirstToken(
-       permuted_row_to_unpermuted_row,
-       unpermuted_row_to_permuted_row,
-       num_tokens,
-+      num_experts_per_token,
-       num_experts_per_node,
-       num_tokens_per_block,
-       num_blocks_per_seq,
-diff --git a/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp b/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp
-index b9c0d1a..25e808c 100644
---- a/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp
-+++ b/csrc/xpu/grouped_gemm/grouped_gemm_interface.cpp
-@@ -140,6 +140,47 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_offsets_interface(
-   }
- }
- 
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_offsets_atomic_interface(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor expert_first_token_offset,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts,
-+    int* atomic_buffer) {
-+  if (vllm::xpu::force_xe_default_kernel()) {
-+    TORCH_CHECK(
-+        false,
-+        "W8A8 INT8 grouped GEMM offsets requires the XE2 cutlass kernel; XE "
-+        "default does not implement this path.");
-+  } else if (vllm::xpu::is_xe2_arch()) {
-+#ifdef VLLM_XPU_ENABLE_XE2
-+    return cutlass_grouped_gemm_w8a8_int8_xe2_offsets_atomic(
-+        ptr_A,
-+        ptr_A_scales,
-+        ptr_B,
-+        ptr_B_scales,
-+        ptr_bias,
-+        ptr_D,
-+        expert_first_token_offset,
-+        N,
-+        K,
-+        num_experts,
-+        atomic_buffer);
-+#else
-+    TORCH_CHECK(false, "XE2 cutlass kernel is not enabled in this build.");
-+#endif
-+  } else {
-+    TORCH_CHECK(
-+        false,
-+        "W8A8 INT8 grouped GEMM offsets requires an XE2 XPU architecture.");
-+  }
-+}
-+
- torch::Tensor cutlass_grouped_gemm_w8a8_int8_active_offsets_interface(
-     torch::Tensor ptr_A,
-     torch::Tensor ptr_A_scales,
-@@ -183,3 +224,87 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_active_offsets_interface(
-         "architecture.");
-   }
- }
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_topk8_gather_interface(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor topk_weights,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts) {
-+  if (vllm::xpu::force_xe_default_kernel()) {
-+    TORCH_CHECK(
-+        false,
-+        "W8A8 INT8 topk8 gather GEMM requires the XE2 cutlass kernel; XE "
-+        "default does not implement this path.");
-+  } else if (vllm::xpu::is_xe2_arch()) {
-+#ifdef VLLM_XPU_ENABLE_XE2
-+    return cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gather(
-+        ptr_A,
-+        ptr_A_scales,
-+        ptr_B,
-+        ptr_B_scales,
-+        ptr_bias,
-+        ptr_D,
-+        topk_ids,
-+        topk_weights,
-+        unpermuted_row_to_permuted_row,
-+        N,
-+        K,
-+        num_experts);
-+#else
-+    TORCH_CHECK(false, "XE2 cutlass kernel is not enabled in this build.");
-+#endif
-+  } else {
-+    TORCH_CHECK(
-+        false,
-+        "W8A8 INT8 topk8 gather GEMM requires an XE2 XPU architecture.");
-+  }
-+}
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_topk8_gemm1_interface(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts) {
-+  if (vllm::xpu::force_xe_default_kernel()) {
-+    TORCH_CHECK(
-+        false,
-+        "W8A8 INT8 topk8 GEMM1 requires the XE2 cutlass kernel; XE default "
-+        "does not implement this path.");
-+  } else if (vllm::xpu::is_xe2_arch()) {
-+#ifdef VLLM_XPU_ENABLE_XE2
-+    return cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gemm1(
-+        ptr_A,
-+        ptr_A_scales,
-+        ptr_B,
-+        ptr_B_scales,
-+        ptr_bias,
-+        ptr_D,
-+        topk_ids,
-+        unpermuted_row_to_permuted_row,
-+        N,
-+        K,
-+        num_experts);
-+#else
-+    TORCH_CHECK(false, "XE2 cutlass kernel is not enabled in this build.");
-+#endif
-+  } else {
-+    TORCH_CHECK(
-+        false,
-+        "W8A8 INT8 topk8 GEMM1 requires an XE2 XPU architecture.");
-+  }
-+}
-diff --git a/csrc/xpu/grouped_gemm/grouped_gemm_interface.h b/csrc/xpu/grouped_gemm/grouped_gemm_interface.h
-index 2a45e65..5c9370c 100644
---- a/csrc/xpu/grouped_gemm/grouped_gemm_interface.h
-+++ b/csrc/xpu/grouped_gemm/grouped_gemm_interface.h
-@@ -37,6 +37,19 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_offsets_interface(
-     int64_t K,
-     int64_t num_experts);
- 
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_offsets_atomic_interface(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor expert_first_token_offset,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts,
-+    int* atomic_buffer);
-+
- torch::Tensor cutlass_grouped_gemm_w8a8_int8_active_offsets_interface(
-     torch::Tensor ptr_A,
-     torch::Tensor ptr_A_scales,
-@@ -50,3 +63,30 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_active_offsets_interface(
-     int64_t K,
-     int64_t num_experts,
-     int64_t num_active_experts);
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_topk8_gather_interface(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor topk_weights,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts);
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_topk8_gemm1_interface(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts);
-diff --git a/csrc/xpu/grouped_gemm/xe_2/gemm_xe2_policy.hpp b/csrc/xpu/grouped_gemm/xe_2/gemm_xe2_policy.hpp
-index 208477d..df1aeed 100644
---- a/csrc/xpu/grouped_gemm/xe_2/gemm_xe2_policy.hpp
-+++ b/csrc/xpu/grouped_gemm/xe_2/gemm_xe2_policy.hpp
-@@ -74,6 +74,18 @@ class w8a16_policy_m_8 : public xe_gemm_policy_base {
-   using SGLayout = Layout<Shape<_1, _4, _1>, Stride<_4, _1, _0>>;
- };
- 
-+class w8a8_topk8_policy_n_32 : public xe_gemm_policy_base {
-+ public:
-+  using WGTile = Shape<_8, _32, _32>;
-+  using SGLayout = Layout<Shape<_1, _2, _1>, Stride<_2, _1, _0>>;
-+};
-+
-+class w8a8_topk8_policy_n_16 : public xe_gemm_policy_base {
-+ public:
-+  using WGTile = Shape<_8, _16, _32>;
-+  using SGLayout = Layout<Shape<_1, _1, _1>, Stride<_1, _1, _0>>;
-+};
-+
- class w8a16_policy_m_16 : public xe_gemm_policy_base {
-  public:
-   using WGTile = Shape<_16, _64, _32>;
-diff --git a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp
-index 1cad1a3..0774df5 100644
---- a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp
-+++ b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.cpp
-@@ -76,6 +76,32 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets(
-       num_experts);
- }
- 
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets_atomic(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor expert_first_token_offset,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts,
-+    int* atomic_buffer) {
-+  return MoE::cutlass_grouped_gemm_w8a8_int8_xe2_offsets_impl(
-+      ptr_A,
-+      ptr_A_scales,
-+      ptr_B,
-+      ptr_B_scales,
-+      ptr_bias,
-+      ptr_D,
-+      expert_first_token_offset,
-+      N,
-+      K,
-+      num_experts,
-+      atomic_buffer);
-+}
-+
- torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_active_offsets(
-     torch::Tensor ptr_A,
-     torch::Tensor ptr_A_scales,
-@@ -103,3 +129,57 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_active_offsets(
-       num_experts,
-       num_active_experts);
- }
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gather(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor topk_weights,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts) {
-+  return MoE::cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gather_impl(
-+      ptr_A,
-+      ptr_A_scales,
-+      ptr_B,
-+      ptr_B_scales,
-+      ptr_bias,
-+      ptr_D,
-+      topk_ids,
-+      topk_weights,
-+      unpermuted_row_to_permuted_row,
-+      N,
-+      K,
-+      num_experts);
-+}
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gemm1(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts) {
-+  return MoE::cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gemm1_impl(
-+      ptr_A,
-+      ptr_A_scales,
-+      ptr_B,
-+      ptr_B_scales,
-+      ptr_bias,
-+      ptr_D,
-+      topk_ids,
-+      unpermuted_row_to_permuted_row,
-+      N,
-+      K,
-+      num_experts);
-+}
-diff --git a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h
-index cc4574b..23e81fe 100644
---- a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h
-+++ b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.h
-@@ -37,6 +37,19 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets(
-     int64_t K,
-     int64_t num_experts);
- 
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets_atomic(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor expert_first_token_offset,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts,
-+    int* atomic_buffer);
-+
- torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_active_offsets(
-     torch::Tensor ptr_A,
-     torch::Tensor ptr_A_scales,
-@@ -50,3 +63,30 @@ torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_active_offsets(
-     int64_t K,
-     int64_t num_experts,
-     int64_t num_active_experts);
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gather(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor topk_weights,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts);
-+
-+torch::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gemm1(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor topk_ids,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts);
-diff --git a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp
-index dbeb772..8405004 100644
---- a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp
-+++ b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2.hpp
-@@ -58,6 +58,328 @@ CUTE_DEVICE auto make_moe_tensor(T* ptr, int r, int c) {
-         make_gmem_ptr(ptr), make_layout(shape, make_stride(c, _1{})));
- }
- 
-+template <
-+    class GmemTiledCopyA,
-+    class GmemTiledCopyB,
-+    class GmemTiledCopyD,
-+    class TiledMMA,
-+    typename ElementD>
-+CUTE_DEVICE void xe_gemm_w8a8_topk8_gather(
-+    const int8_t* Activations,
-+    const int8_t* Weights,
-+    const float* Scales,
-+    const float* ActivationScales,
-+    const float* Bias,
-+    ElementD* Outputs,
-+    const int64_t* TopkIds,
-+    const float* TopkWeights,
-+    const int* UnpermutedRowToPermutedRow,
-+    const int32_t gemm_n,
-+    const int32_t gemm_k,
-+    TiledMMA const& mma) {
-+  auto item = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
-+  const int wg_n = item.get_group(1);
-+  const int local_id = item.get_local_linear_id();
-+
-+  auto C_tensor = make_moe_tensor<ElementD, 'R'>(Outputs, 1, gemm_n);
-+  Tensor cC = make_identity_tensor(C_tensor.shape());
-+  auto wg_tile = mma.tile_mnk();
-+  auto wg_coord = make_coord(0, wg_n, 0);
-+  Tensor gC =
-+      local_tile(cC, wg_tile, wg_coord, Step<_1, _1, X>{});  // (1,BLK_N)
-+
-+  auto copy_c = get_block_2d_copy_D<GmemTiledCopyD>(mma, C_tensor);
-+  auto thr_mma = mma.get_slice(local_id);
-+  auto thr_copy_c = copy_c.get_slice(local_id);
-+  auto tCrC_template = thr_mma.partition_sg_fragment_C(gC);
-+  auto tCrAccum = make_subgroup_tensor(
-+      make_tensor_like<float>(tCrC_template.tensor()),
-+      tCrC_template.tv_layout());
-+  auto tCrC_out = thr_copy_c.partition_sg_fragment_S(gC);
-+  auto tCgC = thr_copy_c.partition_D(gC);
-+  clear(tCrAccum);
-+
-+  static constexpr auto ATOM_M =
-+      get<1>(typename TiledMMA::ThrLayoutVMNK{}.shape());
-+  static constexpr auto ATOM_N =
-+      get<2>(typename TiledMMA::ThrLayoutVMNK{}.shape());
-+
-+  auto sg_local_m_coord = cutlass::get_sub_group_id() / ATOM_N;
-+  auto sg_local_n_coord = cutlass::get_sub_group_id() % ATOM_N;
-+
-+  static constexpr auto tile_m = get<0>(wg_tile);
-+  static constexpr auto tile_n = get<1>(wg_tile);
-+  static constexpr auto SG_M = tile_m / ATOM_M;
-+  static constexpr auto SG_N = tile_n / ATOM_N;
-+  const int sg_local_id = cutlass::get_sub_group_local_id();
-+  static constexpr int sg_local_range = 16;
-+
-+  const int m_sg_start = sg_local_m_coord * SG_M;
-+  const int n_tile_start = wg_n * tile_n;
-+  const int n_sg_start = sg_local_n_coord * SG_N;
-+
-+  CUTE_UNROLL
-+  for (int topk_idx = 0; topk_idx < 8; ++topk_idx) {
-+    const int permuted_row = UnpermutedRowToPermutedRow[topk_idx];
-+    const int64_t expert = TopkIds[topk_idx];
-+    const float route_weight = TopkWeights[topk_idx];
-+
-+    auto A_tensor = make_moe_tensor<int8_t, 'R'>(
-+        const_cast<int8_t*>(Activations) + permuted_row * gemm_k,
-+        1,
-+        gemm_k);
-+    auto B_tensor = make_moe_tensor<int8_t, 'C'>(
-+        const_cast<int8_t*>(Weights) +
-+            expert * static_cast<int64_t>(gemm_n) *
-+                static_cast<int64_t>(gemm_k),
-+        gemm_n,
-+        gemm_k);
-+
-+    Tensor cA = make_identity_tensor(A_tensor.shape());
-+    Tensor cB = make_identity_tensor(B_tensor.shape());
-+    Tensor gA = local_tile(
-+        cA, select<0, 2>(wg_tile), make_coord(0, _));  // (BLK_M,BLK_K,k)
-+    Tensor gB = local_tile(
-+        cB, select<1, 2>(wg_tile), make_coord(wg_n, _));  // (BLK_N,BLK_K,k)
-+
-+    auto copy_a = get_block_2d_copy_A<GmemTiledCopyA>(mma, A_tensor);
-+    auto copy_b = get_block_2d_copy_B<GmemTiledCopyB>(mma, B_tensor);
-+    auto thr_copy_a = copy_a.get_slice(local_id);
-+    auto thr_copy_b = copy_b.get_slice(local_id);
-+
-+    auto tCrA = thr_mma.partition_sg_fragment_A(gA(_, _, 0));
-+    auto tCrB = thr_mma.partition_sg_fragment_B(gB(_, _, 0));
-+    auto tArA = thr_copy_a.partition_sg_fragment_D(gA(_, _, 0));
-+    auto tBrB = thr_copy_b.partition_sg_fragment_D(gB(_, _, 0));
-+    Tensor tAgA = thr_copy_a.partition_S(gA);
-+    Tensor tBgB = thr_copy_b.partition_S(gB);
-+    auto tCrC = thr_mma.partition_sg_fragment_C(gC);
-+
-+    auto prefetch_a = make_block_2d_prefetch(copy_a);
-+    auto prefetch_b = make_block_2d_prefetch(copy_b);
-+    auto thr_prefetch_A = prefetch_a.get_slice(local_id);
-+    auto thr_prefetch_B = prefetch_b.get_slice(local_id);
-+    auto pAgA = thr_prefetch_A.partition_S(gA);
-+    auto pBgB = thr_prefetch_B.partition_S(gB);
-+
-+    constexpr int prefetch_dist = 3;
-+    constexpr int barrier_scope = 2;
-+    const int k_tile_count = ceil_div(shape<1>(A_tensor), get<2>(wg_tile));
-+    int k_tile_prefetch = 0;
-+    clear(tCrC);
-+
-+    CUTE_UNROLL
-+    for (; k_tile_prefetch < prefetch_dist; k_tile_prefetch++) {
-+      prefetch(prefetch_a, pAgA(_, _, _, k_tile_prefetch));
-+      prefetch(prefetch_b, pBgB(_, _, _, k_tile_prefetch));
-+    }
-+
-+    for (int k_tile = 0; k_tile < k_tile_count;
-+         k_tile++, k_tile_prefetch++) {
-+      barrier_arrive(barrier_scope);
-+
-+      copy(copy_a, tAgA(_, _, _, k_tile), tArA);
-+      copy(copy_b, tBgB(_, _, _, k_tile), tBrB);
-+
-+      if (k_tile_prefetch < k_tile_count) {
-+        prefetch(prefetch_a, pAgA(_, _, _, k_tile_prefetch));
-+        prefetch(prefetch_b, pBgB(_, _, _, k_tile_prefetch));
-+      }
-+
-+      reorder(tArA, tCrA);
-+      reorder(tBrB, tCrB);
-+
-+      cute::gemm(mma, tCrA, tCrB, tCrC);
-+
-+      barrier_wait(barrier_scope);
-+    }
-+
-+    CUTLASS_PRAGMA_UNROLL
-+    for (int sn = 0; sn < SG_N / sg_local_range; ++sn) {
-+      const int sg_local_n = sn * sg_local_range + sg_local_id;
-+      const int col = n_tile_start + n_sg_start + sg_local_n;
-+      const float b_scale =
-+          (Scales != nullptr && col < gemm_n)
-+              ? Scales[expert * static_cast<int64_t>(gemm_n) + col]
-+              : 1.0f;
-+      const float b_float =
-+          (Bias != nullptr && col < gemm_n)
-+              ? Bias[expert * static_cast<int64_t>(gemm_n) + col]
-+              : 0.0f;
-+      CUTLASS_PRAGMA_UNROLL
-+      for (int sm = 0; sm < SG_M; ++sm) {
-+        const int idx = sn * SG_M + sm;
-+        const int row = m_sg_start + sm;
-+        if (row == 0 && col < gemm_n) {
-+          const float a_scale =
-+              ActivationScales != nullptr ? ActivationScales[permuted_row]
-+                                          : 1.0f;
-+          const float value =
-+              static_cast<float>(tCrC(idx)) * a_scale * b_scale + b_float;
-+          const ElementD rounded = static_cast<ElementD>(value);
-+          tCrAccum(idx) += static_cast<float>(rounded) * route_weight;
-+        }
-+      }
-+    }
-+  }
-+
-+  reorder(tCrAccum, tCrC_out);
-+  copy(copy_c, tCrC_out, tCgC);
-+}
-+
-+template <
-+    class GmemTiledCopyA,
-+    class GmemTiledCopyB,
-+    class GmemTiledCopyD,
-+    class TiledMMA,
-+    typename ElementD>
-+CUTE_DEVICE void xe_gemm_w8a8_topk8_gemm1(
-+    const int8_t* Activations,
-+    const int8_t* Weights,
-+    const float* Scales,
-+    const float* ActivationScales,
-+    const float* Bias,
-+    ElementD* Outputs,
-+    const int64_t* TopkIds,
-+    const int* UnpermutedRowToPermutedRow,
-+    const int32_t gemm_n,
-+    const int32_t gemm_k,
-+    TiledMMA const& mma) {
-+  auto item = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
-+  const int topk_idx = item.get_group(0);
-+  const int wg_n = item.get_group(1);
-+  const int local_id = item.get_local_linear_id();
-+  const int permuted_row = UnpermutedRowToPermutedRow[topk_idx];
-+  const int64_t expert = TopkIds[topk_idx];
-+
-+  auto A_tensor = make_moe_tensor<int8_t, 'R'>(
-+      const_cast<int8_t*>(Activations) + permuted_row * gemm_k, 1, gemm_k);
-+  auto B_tensor = make_moe_tensor<int8_t, 'C'>(
-+      const_cast<int8_t*>(Weights) +
-+          expert * static_cast<int64_t>(gemm_n) *
-+              static_cast<int64_t>(gemm_k),
-+      gemm_n,
-+      gemm_k);
-+  auto D_tensor = make_moe_tensor<ElementD, 'R'>(
-+      Outputs + permuted_row * gemm_n, 1, gemm_n);
-+
-+  Tensor cA = make_identity_tensor(A_tensor.shape());
-+  Tensor cB = make_identity_tensor(B_tensor.shape());
-+  Tensor cD = make_identity_tensor(D_tensor.shape());
-+  auto wg_tile = mma.tile_mnk();
-+  Tensor gA =
-+      local_tile(cA, select<0, 2>(wg_tile), make_coord(0, _));
-+  Tensor gB =
-+      local_tile(cB, select<1, 2>(wg_tile), make_coord(wg_n, _));
-+  Tensor gD =
-+      local_tile(cD, wg_tile, make_coord(0, wg_n, 0), Step<_1, _1, X>{});
-+
-+  auto copy_a = get_block_2d_copy_A<GmemTiledCopyA>(mma, A_tensor);
-+  auto copy_b = get_block_2d_copy_B<GmemTiledCopyB>(mma, B_tensor);
-+  auto copy_d = get_block_2d_copy_D<GmemTiledCopyD>(mma, D_tensor);
-+  auto thr_mma = mma.get_slice(local_id);
-+  auto thr_copy_a = copy_a.get_slice(local_id);
-+  auto thr_copy_b = copy_b.get_slice(local_id);
-+  auto thr_copy_d = copy_d.get_slice(local_id);
-+
-+  auto tCrA = thr_mma.partition_sg_fragment_A(gA(_, _, 0));
-+  auto tCrB = thr_mma.partition_sg_fragment_B(gB(_, _, 0));
-+  auto tArA = thr_copy_a.partition_sg_fragment_D(gA(_, _, 0));
-+  auto tBrB = thr_copy_b.partition_sg_fragment_D(gB(_, _, 0));
-+  Tensor tAgA = thr_copy_a.partition_S(gA);
-+  Tensor tBgB = thr_copy_b.partition_S(gB);
-+  auto tCrC = thr_mma.partition_sg_fragment_C(gD);
-+  auto tCrD_template = thr_mma.partition_sg_fragment_C(gD);
-+  auto tCrD_float = make_subgroup_tensor(
-+      make_tensor_like<float>(tCrD_template.tensor()),
-+      tCrD_template.tv_layout());
-+  auto tDrD = thr_copy_d.partition_sg_fragment_S(gD);
-+  auto tDgD = thr_copy_d.partition_D(gD);
-+
-+  auto prefetch_a = make_block_2d_prefetch(copy_a);
-+  auto prefetch_b = make_block_2d_prefetch(copy_b);
-+  auto thr_prefetch_A = prefetch_a.get_slice(local_id);
-+  auto thr_prefetch_B = prefetch_b.get_slice(local_id);
-+  auto pAgA = thr_prefetch_A.partition_S(gA);
-+  auto pBgB = thr_prefetch_B.partition_S(gB);
-+
-+  constexpr int prefetch_dist = 3;
-+  constexpr int barrier_scope = 2;
-+  const int k_tile_count = ceil_div(shape<1>(A_tensor), get<2>(wg_tile));
-+  int k_tile_prefetch = 0;
-+  clear(tCrC);
-+  clear(tCrD_float);
-+
-+  CUTE_UNROLL
-+  for (; k_tile_prefetch < prefetch_dist; k_tile_prefetch++) {
-+    prefetch(prefetch_a, pAgA(_, _, _, k_tile_prefetch));
-+    prefetch(prefetch_b, pBgB(_, _, _, k_tile_prefetch));
-+  }
-+
-+  for (int k_tile = 0; k_tile < k_tile_count; k_tile++, k_tile_prefetch++) {
-+    barrier_arrive(barrier_scope);
-+
-+    copy(copy_a, tAgA(_, _, _, k_tile), tArA);
-+    copy(copy_b, tBgB(_, _, _, k_tile), tBrB);
-+
-+    if (k_tile_prefetch < k_tile_count) {
-+      prefetch(prefetch_a, pAgA(_, _, _, k_tile_prefetch));
-+      prefetch(prefetch_b, pBgB(_, _, _, k_tile_prefetch));
-+    }
-+
-+    reorder(tArA, tCrA);
-+    reorder(tBrB, tCrB);
-+
-+    cute::gemm(mma, tCrA, tCrB, tCrC);
-+
-+    barrier_wait(barrier_scope);
-+  }
-+
-+  static constexpr auto ATOM_M =
-+      get<1>(typename TiledMMA::ThrLayoutVMNK{}.shape());
-+  static constexpr auto ATOM_N =
-+      get<2>(typename TiledMMA::ThrLayoutVMNK{}.shape());
-+  auto sg_local_m_coord = cutlass::get_sub_group_id() / ATOM_N;
-+  auto sg_local_n_coord = cutlass::get_sub_group_id() % ATOM_N;
-+  static constexpr auto tile_m = get<0>(wg_tile);
-+  static constexpr auto tile_n = get<1>(wg_tile);
-+  static constexpr auto SG_M = tile_m / ATOM_M;
-+  static constexpr auto SG_N = tile_n / ATOM_N;
-+  const int sg_local_id = cutlass::get_sub_group_local_id();
-+  static constexpr int sg_local_range = 16;
-+  const int m_sg_start = sg_local_m_coord * SG_M;
-+  const int n_tile_start = wg_n * tile_n;
-+  const int n_sg_start = sg_local_n_coord * SG_N;
-+  const float a_scale =
-+      ActivationScales != nullptr ? ActivationScales[permuted_row] : 1.0f;
-+
-+  CUTLASS_PRAGMA_UNROLL
-+  for (int sn = 0; sn < SG_N / sg_local_range; ++sn) {
-+    const int sg_local_n = sn * sg_local_range + sg_local_id;
-+    const int col = n_tile_start + n_sg_start + sg_local_n;
-+    const float b_scale =
-+        (Scales != nullptr && col < gemm_n)
-+            ? Scales[expert * static_cast<int64_t>(gemm_n) + col]
-+            : 1.0f;
-+    const float b_float =
-+        (Bias != nullptr && col < gemm_n)
-+            ? Bias[expert * static_cast<int64_t>(gemm_n) + col]
-+            : 0.0f;
-+    CUTLASS_PRAGMA_UNROLL
-+    for (int sm = 0; sm < SG_M; ++sm) {
-+      const int idx = sn * SG_M + sm;
-+      const int row = m_sg_start + sm;
-+      if (row == 0 && col < gemm_n) {
-+        tCrD_float(idx) =
-+            static_cast<float>(tCrC(idx)) * a_scale * b_scale + b_float;
-+      }
-+    }
-+  }
-+
-+  reorder(tCrD_float, tDrD);
-+  copy(copy_d, tDrD, tDgD);
-+}
-+
- template <
-     bool UseOffsets,
-     bool UseActiveExpertList,
-diff --git a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp
-index b38a34f..ed7456b 100644
---- a/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp
-+++ b/csrc/xpu/grouped_gemm/xe_2/grouped_gemm_xe2_interface.hpp
-@@ -63,12 +63,15 @@
- namespace MoE {
- using namespace cute;
- 
--static inline int get_w8a8_grouped_gemm_policy_override() {
--  const char* env_val = std::getenv("VLLM_XPU_W8A8_GROUPED_GEMM_POLICY");
-+static inline int parse_w8a8_grouped_gemm_policy_override(
-+    const char* env_val) {
-   if (env_val == nullptr) {
-     return 0;
-   }
-   const std::string value(env_val);
-+  if (value == "m8" || value == "M8" || value == "8") {
-+    return 8;
-+  }
-   if (value == "m16" || value == "M16" || value == "16") {
-     return 16;
-   }
-@@ -82,6 +85,30 @@ static inline int get_w8a8_grouped_gemm_policy_override() {
-   return 0;
- }
- 
-+static inline int get_w8a8_grouped_gemm_policy_override(
-+    const int gemm_n,
-+    const int gemm_k) {
-+  const char* shape_env = nullptr;
-+  if (gemm_n < gemm_k) {
-+    shape_env = std::getenv("VLLM_XPU_W8A8_GROUPED_GEMM_N_LT_K_POLICY");
-+  } else if (gemm_n > gemm_k) {
-+    shape_env = std::getenv("VLLM_XPU_W8A8_GROUPED_GEMM_N_GT_K_POLICY");
-+  }
-+  int shape_override = parse_w8a8_grouped_gemm_policy_override(shape_env);
-+  if (gemm_n > gemm_k && shape_override == 8) {
-+    return 0;
-+  }
-+  if (shape_override != 0) {
-+    return shape_override;
-+  }
-+  int override = parse_w8a8_grouped_gemm_policy_override(
-+      std::getenv("VLLM_XPU_W8A8_GROUPED_GEMM_POLICY"));
-+  if (gemm_n > gemm_k && override == 8) {
-+    return 0;
-+  }
-+  return override;
-+}
-+
- // type tag to define a unique sycl kernel name
- template <typename, typename, typename, typename, char, char, class>
- class GemmCuteName;
-@@ -92,6 +119,12 @@ class GemmCuteNameOffsets;
- template <typename, typename, typename, typename, char, char, class>
- class GemmCuteNameActiveOffsets;
- 
-+template <typename, class>
-+class GemmCuteNameTopK8Gather;
-+
-+template <typename, class>
-+class GemmCuteNameTopK8Gemm1;
-+
- template <
-     char layoutA,
-     char layoutB,
-@@ -753,8 +786,12 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_impl(
-     W8A8MoEGEMMLauncherCallER(policy, out_t);  \
-   }
- 
--  const int policy_override = get_w8a8_grouped_gemm_policy_override();
--  if (policy_override == 16) {
-+  const int policy_override =
-+      get_w8a8_grouped_gemm_policy_override(N, K);
-+  if (policy_override == 8) {
-+    using policy = w8a16_policy_m_8;
-+    W8A8LauncherCallER(policy);
-+  } else if (policy_override == 16) {
-     using policy = w8a16_policy_m_16;
-     W8A8LauncherCallER(policy);
-   } else if (policy_override == 32) {
-@@ -791,7 +828,8 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets_impl(
-     at::Tensor& expert_first_token_offset,
-     int64_t N,
-     int64_t K,
--    int64_t num_experts) {
-+    int64_t num_experts,
-+    int* external_atomic_buffer = nullptr) {
-   auto& dpcpp_queue =
-       at::xpu::getCurrentXPUStream(ptr_A.device().index()).queue();
-   auto A_dtype = ptr_A.dtype();
-@@ -874,8 +912,13 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets_impl(
-     TORCH_CHECK(ptr_bias->size(1) == N, "ptr_bias.size(1) must match N");
-   }
- 
--  at::Tensor atomic_buffer =
--      at::empty({static_cast<long>(1)}, ptr_A.options().dtype(at::kInt));
-+  at::Tensor owned_atomic_buffer;
-+  int* atomic_buffer_ptr = external_atomic_buffer;
-+  if (atomic_buffer_ptr == nullptr) {
-+    owned_atomic_buffer =
-+        at::empty({static_cast<long>(1)}, ptr_A.options().dtype(at::kInt));
-+    atomic_buffer_ptr = static_cast<int*>(owned_atomic_buffer.data_ptr());
-+  }
- 
- #define W8A8MoEGEMMLauncherOffsetsCallER(Policy, ElementD)                  \
-   MoEGEMMLauncherOffsets<'R', 'R', Policy>(                                  \
-@@ -892,7 +935,7 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets_impl(
-       reinterpret_cast<int64_t*>(expert_first_token_offset.data_ptr()),      \
-       num_experts,                                                           \
-       group_size,                                                            \
--      static_cast<int*>(atomic_buffer.data_ptr()));
-+      atomic_buffer_ptr);
- 
- #define W8A8OffsetsLauncherCallER(policy)       \
-   if (D_dtype == at::kBFloat16) {               \
-@@ -903,8 +946,12 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_offsets_impl(
-     W8A8MoEGEMMLauncherOffsetsCallER(policy, out_t); \
-   }
- 
--  const int policy_override = get_w8a8_grouped_gemm_policy_override();
--  if (policy_override == 16) {
-+  const int policy_override =
-+      get_w8a8_grouped_gemm_policy_override(N, K);
-+  if (policy_override == 8) {
-+    using policy = w8a16_policy_m_8;
-+    W8A8OffsetsLauncherCallER(policy);
-+  } else if (policy_override == 16) {
-     using policy = w8a16_policy_m_16;
-     W8A8OffsetsLauncherCallER(policy);
-   } else if (policy_override == 32) {
-@@ -1066,8 +1113,12 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_active_offsets_impl(
-     W8A8MoEGEMMLauncherActiveOffsetsCallER(policy, out_t); \
-   }
- 
--  const int policy_override = get_w8a8_grouped_gemm_policy_override();
--  if (policy_override == 16) {
-+  const int policy_override =
-+      get_w8a8_grouped_gemm_policy_override(N, K);
-+  if (policy_override == 8) {
-+    using policy = w8a16_policy_m_8;
-+    W8A8ActiveOffsetsLauncherCallER(policy);
-+  } else if (policy_override == 16) {
-     using policy = w8a16_policy_m_16;
-     W8A8ActiveOffsetsLauncherCallER(policy);
-   } else if (policy_override == 32) {
-@@ -1093,4 +1144,411 @@ at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_active_offsets_impl(
- 
-   return ptr_D;
- }
-+
-+template <class policy, typename ElementD>
-+void MoEGEMMTopK8GatherLauncher(
-+    sycl::queue& stream,
-+    const int8_t* activations,
-+    const int8_t* weights,
-+    const float* scales,
-+    const float* activation_scales,
-+    const float* bias,
-+    ElementD* outputs,
-+    const int64_t* topk_ids,
-+    const float* topk_weights,
-+    const int* unpermuted_row_to_permuted_row,
-+    const int gemm_n,
-+    const int gemm_k) {
-+  auto op = XE_DPAS_TT<8, int32_t, int8_t>{};
-+
-+  using WGTile = typename policy::WGTile;
-+  using SGLayout = typename policy::SGLayout;
-+  using MMA = typename TiledMMAHelper<
-+      MMA_Atom<decltype(op)>,
-+      Layout<WGTile>,
-+      SGLayout>::TiledMMA;
-+  auto mma = MMA{};
-+
-+  auto MaxThreadsPerWorkgroup = size(mma);
-+
-+  static constexpr int MaxThreadsPerSM = 512;
-+
-+  TORCH_CHECK(
-+      MaxThreadsPerSM % MaxThreadsPerWorkgroup == 0,
-+      "MaxThreadsPerSM must be divisible by MaxThreadsPerWorkgroup")
-+
-+  const int wg_tile_n = get<1>(mma.tile_mnk());
-+  const int n_tiles = (gemm_n + wg_tile_n - 1) / wg_tile_n;
-+  sycl::range<3> local(1, 1, MaxThreadsPerWorkgroup);
-+  sycl::range<3> global(1, n_tiles, 1);
-+
-+  namespace syclex = sycl::ext::oneapi::experimental;
-+  namespace intelex = sycl::ext::intel::experimental;
-+
-+  syclex::properties kernel_props{
-+      syclex::sub_group_size<16>, intelex::grf_size<256>};
-+
-+  using GmemTiledCopyA = typename policy::GmemTiledCopyA;
-+  using GmemTiledCopyB = typename policy::GmemTiledCopyB;
-+  using GmemTiledCopyD = typename policy::GmemTiledCopyD;
-+
-+  stream.submit([&](sycl::handler& cgh) {
-+    cgh.parallel_for<GemmCuteNameTopK8Gather<ElementD, policy>>(
-+        sycl::nd_range<3>{global * local, local}, kernel_props, [=](auto) {
-+          xe_gemm_w8a8_topk8_gather<
-+              GmemTiledCopyA,
-+              GmemTiledCopyB,
-+              GmemTiledCopyD>(
-+              activations,
-+              weights,
-+              scales,
-+              activation_scales,
-+              bias,
-+              outputs,
-+              topk_ids,
-+              topk_weights,
-+              unpermuted_row_to_permuted_row,
-+              gemm_n,
-+              gemm_k,
-+              mma);
-+        });
-+  });
-+}
-+
-+template <class policy, typename ElementD>
-+void MoEGEMMTopK8Gemm1Launcher(
-+    sycl::queue& stream,
-+    const int8_t* activations,
-+    const int8_t* weights,
-+    const float* scales,
-+    const float* activation_scales,
-+    const float* bias,
-+    ElementD* outputs,
-+    const int64_t* topk_ids,
-+    const int* unpermuted_row_to_permuted_row,
-+    const int gemm_n,
-+    const int gemm_k) {
-+  auto op = XE_DPAS_TT<8, int32_t, int8_t>{};
-+
-+  using WGTile = typename policy::WGTile;
-+  using SGLayout = typename policy::SGLayout;
-+  using MMA = typename TiledMMAHelper<
-+      MMA_Atom<decltype(op)>,
-+      Layout<WGTile>,
-+      SGLayout>::TiledMMA;
-+  auto mma = MMA{};
-+
-+  auto MaxThreadsPerWorkgroup = size(mma);
-+
-+  static constexpr int MaxThreadsPerSM = 512;
-+
-+  TORCH_CHECK(
-+      MaxThreadsPerSM % MaxThreadsPerWorkgroup == 0,
-+      "MaxThreadsPerSM must be divisible by MaxThreadsPerWorkgroup")
-+
-+  const int wg_tile_n = get<1>(mma.tile_mnk());
-+  const int n_tiles = (gemm_n + wg_tile_n - 1) / wg_tile_n;
-+  sycl::range<3> local(1, 1, MaxThreadsPerWorkgroup);
-+  sycl::range<3> global(8, n_tiles, 1);
-+
-+  namespace syclex = sycl::ext::oneapi::experimental;
-+  namespace intelex = sycl::ext::intel::experimental;
-+
-+  syclex::properties kernel_props{
-+      syclex::sub_group_size<16>, intelex::grf_size<256>};
-+
-+  using GmemTiledCopyA = typename policy::GmemTiledCopyA;
-+  using GmemTiledCopyB = typename policy::GmemTiledCopyB;
-+  using GmemTiledCopyD = typename policy::GmemTiledCopyD;
-+
-+  stream.submit([&](sycl::handler& cgh) {
-+    cgh.parallel_for<GemmCuteNameTopK8Gemm1<ElementD, policy>>(
-+        sycl::nd_range<3>{global * local, local}, kernel_props, [=](auto) {
-+          xe_gemm_w8a8_topk8_gemm1<
-+              GmemTiledCopyA,
-+              GmemTiledCopyB,
-+              GmemTiledCopyD>(
-+              activations,
-+              weights,
-+              scales,
-+              activation_scales,
-+              bias,
-+              outputs,
-+              topk_ids,
-+              unpermuted_row_to_permuted_row,
-+              gemm_n,
-+              gemm_k,
-+              mma);
-+        });
-+  });
-+}
-+
-+at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gather_impl(
-+    at::Tensor& ptr_A,
-+    at::Tensor& ptr_A_scales,
-+    at::Tensor& ptr_B,
-+    at::Tensor& ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    at::Tensor& ptr_D,
-+    at::Tensor& topk_ids,
-+    at::Tensor& topk_weights,
-+    at::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts) {
-+  auto& dpcpp_queue =
-+      at::xpu::getCurrentXPUStream(ptr_A.device().index()).queue();
-+  auto A_dtype = ptr_A.dtype();
-+  auto B_dtype = ptr_B.dtype();
-+  auto D_dtype = ptr_D.dtype();
-+
-+  TORCH_CHECK(N % 32 == 0, "N must be divisible by 32");
-+  TORCH_CHECK(A_dtype == at::kChar, "ptr_A must be int8");
-+  TORCH_CHECK(B_dtype == at::kChar, "ptr_B must be int8");
-+  TORCH_CHECK(
-+      D_dtype == at::kBFloat16 || D_dtype == at::kHalf,
-+      "ptr_D must be bfloat16 or float16");
-+  TORCH_CHECK(ptr_A_scales.dtype() == at::kFloat, "ptr_A_scales must be float");
-+  TORCH_CHECK(ptr_B_scales.dtype() == at::kFloat, "ptr_B_scales must be float");
-+  TORCH_CHECK(topk_ids.dtype() == at::kLong, "topk_ids must be int64");
-+  TORCH_CHECK(topk_weights.dtype() == at::kFloat, "topk_weights must be float");
-+  TORCH_CHECK(
-+      unpermuted_row_to_permuted_row.dtype() == at::kInt,
-+      "unpermuted_row_to_permuted_row must be int32");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(ptr_bias->dtype() == at::kFloat, "ptr_bias must be float");
-+  }
-+
-+  TORCH_CHECK(ptr_A.dim() == 2, "ptr_A must be 2D [Total_M, K]");
-+  TORCH_CHECK(ptr_A.size(0) >= 8, "ptr_A must contain at least topk rows");
-+  TORCH_CHECK(ptr_A.size(1) == K, "ptr_A.size(1) must match K");
-+  TORCH_CHECK(ptr_B.dim() == 3, "ptr_B must be 3D [num_experts, K, N]");
-+  TORCH_CHECK(ptr_D.dim() == 2, "ptr_D must be 2D [1, N]");
-+  TORCH_CHECK(ptr_D.size(0) == 1, "ptr_D first dim must be one token");
-+  TORCH_CHECK(ptr_D.size(1) == N, "ptr_D.size(1) must match N");
-+  TORCH_CHECK(
-+      ptr_A_scales.dim() == 1 ||
-+          (ptr_A_scales.dim() == 2 && ptr_A_scales.size(1) == 1),
-+      "ptr_A_scales must be 1D [Total_M] or 2D [Total_M, 1]");
-+  TORCH_CHECK(
-+      ptr_A_scales.size(0) >= 8,
-+      "ptr_A_scales must contain at least topk rows");
-+  TORCH_CHECK(
-+      ptr_B_scales.dim() == 2,
-+      "ptr_B_scales must be 2D [num_experts, N]");
-+  TORCH_CHECK(topk_ids.dim() == 2, "topk_ids must be 2D [1, 8]");
-+  TORCH_CHECK(topk_ids.size(0) == 1, "topk_ids first dim must be one token");
-+  TORCH_CHECK(topk_ids.size(1) == 8, "topk_ids second dim must be topk=8");
-+  TORCH_CHECK(
-+      topk_weights.sizes() == topk_ids.sizes(),
-+      "topk_weights shape must match topk_ids");
-+  TORCH_CHECK(
-+      unpermuted_row_to_permuted_row.numel() >= 8,
-+      "unpermuted_row_to_permuted_row must cover topk=8");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(ptr_bias->dim() == 2, "ptr_bias must be 2D [num_experts, N]");
-+  }
-+
-+  TORCH_CHECK(ptr_A.is_contiguous(), "ptr_A must be contiguous");
-+  TORCH_CHECK(ptr_A_scales.is_contiguous(), "ptr_A_scales must be contiguous");
-+  TORCH_CHECK(ptr_B.is_contiguous(), "ptr_B must be contiguous");
-+  TORCH_CHECK(ptr_B_scales.is_contiguous(), "ptr_B_scales must be contiguous");
-+  TORCH_CHECK(ptr_D.is_contiguous(), "ptr_D must be contiguous");
-+  TORCH_CHECK(topk_ids.is_contiguous(), "topk_ids must be contiguous");
-+  TORCH_CHECK(topk_weights.is_contiguous(), "topk_weights must be contiguous");
-+  TORCH_CHECK(
-+      unpermuted_row_to_permuted_row.is_contiguous(),
-+      "unpermuted_row_to_permuted_row must be contiguous");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(ptr_bias->is_contiguous(), "ptr_bias must be contiguous");
-+  }
-+
-+  TORCH_CHECK(ptr_B.size(0) == num_experts, "ptr_B.size(0) mismatch");
-+  TORCH_CHECK(ptr_B.size(1) == K, "ptr_B.size(1) mismatch");
-+  TORCH_CHECK(ptr_B.size(2) == N, "ptr_B.size(2) mismatch");
-+  TORCH_CHECK(
-+      ptr_B_scales.size(0) == num_experts,
-+      "ptr_B_scales.size(0) must match num_experts");
-+  TORCH_CHECK(ptr_B_scales.size(1) == N, "ptr_B_scales.size(1) mismatch");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(
-+        ptr_bias->size(0) == num_experts,
-+        "ptr_bias.size(0) must match num_experts");
-+    TORCH_CHECK(ptr_bias->size(1) == N, "ptr_bias.size(1) mismatch");
-+  }
-+
-+#define W8A8TopK8GatherLauncherCallER(Policy, ElementDType)                 \
-+  MoEGEMMTopK8GatherLauncher<Policy, ElementDType>(                         \
-+      dpcpp_queue,                                                          \
-+      reinterpret_cast<int8_t*>(ptr_A.data_ptr()),                          \
-+      reinterpret_cast<int8_t*>(ptr_B.data_ptr()),                          \
-+      reinterpret_cast<float*>(ptr_B_scales.data_ptr()),                    \
-+      reinterpret_cast<float*>(ptr_A_scales.data_ptr()),                    \
-+      ptr_bias.has_value() ? reinterpret_cast<float*>(ptr_bias->data_ptr()) \
-+                           : static_cast<float*>(nullptr),                  \
-+      reinterpret_cast<ElementDType*>(ptr_D.data_ptr()),                    \
-+      reinterpret_cast<int64_t*>(topk_ids.data_ptr()),                      \
-+      reinterpret_cast<float*>(topk_weights.data_ptr()),                    \
-+      reinterpret_cast<int*>(unpermuted_row_to_permuted_row.data_ptr()),    \
-+      N,                                                                    \
-+      K);
-+
-+#define W8A8TopK8GatherDispatch(policy)            \
-+  if (D_dtype == at::kBFloat16) {                  \
-+    using out_t = bfloat16_t;                      \
-+    W8A8TopK8GatherLauncherCallER(policy, out_t);  \
-+  } else if (D_dtype == at::kHalf) {               \
-+    using out_t = half_t;                          \
-+    W8A8TopK8GatherLauncherCallER(policy, out_t);  \
-+  }
-+
-+  const char* ntile_env =
-+      std::getenv("VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER_NTILE");
-+  if (ntile_env != nullptr && std::string(ntile_env) == "16") {
-+    using policy = w8a8_topk8_policy_n_16;
-+    W8A8TopK8GatherDispatch(policy);
-+  } else if (ntile_env != nullptr && std::string(ntile_env) == "32") {
-+    using policy = w8a8_topk8_policy_n_32;
-+    W8A8TopK8GatherDispatch(policy);
-+  } else {
-+    using policy = w8a16_policy_m_8;
-+    W8A8TopK8GatherDispatch(policy);
-+  }
-+
-+#undef W8A8TopK8GatherDispatch
-+#undef W8A8TopK8GatherLauncherCallER
-+
-+  return ptr_D;
-+}
-+
-+at::Tensor cutlass_grouped_gemm_w8a8_int8_xe2_topk8_gemm1_impl(
-+    at::Tensor& ptr_A,
-+    at::Tensor& ptr_A_scales,
-+    at::Tensor& ptr_B,
-+    at::Tensor& ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    at::Tensor& ptr_D,
-+    at::Tensor& topk_ids,
-+    at::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts) {
-+  auto& dpcpp_queue =
-+      at::xpu::getCurrentXPUStream(ptr_A.device().index()).queue();
-+  auto A_dtype = ptr_A.dtype();
-+  auto B_dtype = ptr_B.dtype();
-+  auto D_dtype = ptr_D.dtype();
-+
-+  TORCH_CHECK(N % 32 == 0, "N must be divisible by 32");
-+  TORCH_CHECK(A_dtype == at::kChar, "ptr_A must be int8");
-+  TORCH_CHECK(B_dtype == at::kChar, "ptr_B must be int8");
-+  TORCH_CHECK(
-+      D_dtype == at::kBFloat16 || D_dtype == at::kHalf,
-+      "ptr_D must be bfloat16 or float16");
-+  TORCH_CHECK(ptr_A_scales.dtype() == at::kFloat, "ptr_A_scales must be float");
-+  TORCH_CHECK(ptr_B_scales.dtype() == at::kFloat, "ptr_B_scales must be float");
-+  TORCH_CHECK(topk_ids.dtype() == at::kLong, "topk_ids must be int64");
-+  TORCH_CHECK(
-+      unpermuted_row_to_permuted_row.dtype() == at::kInt,
-+      "unpermuted_row_to_permuted_row must be int32");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(ptr_bias->dtype() == at::kFloat, "ptr_bias must be float");
-+  }
-+
-+  TORCH_CHECK(ptr_A.dim() == 2, "ptr_A must be 2D [Total_M, K]");
-+  TORCH_CHECK(ptr_A.size(0) >= 8, "ptr_A must contain at least topk rows");
-+  TORCH_CHECK(ptr_A.size(1) == K, "ptr_A.size(1) must match K");
-+  TORCH_CHECK(ptr_B.dim() == 3, "ptr_B must be 3D [num_experts, K, N]");
-+  TORCH_CHECK(ptr_D.dim() == 2, "ptr_D must be 2D [Total_M, N]");
-+  TORCH_CHECK(ptr_D.size(0) >= 8, "ptr_D must contain at least topk rows");
-+  TORCH_CHECK(ptr_D.size(1) == N, "ptr_D.size(1) must match N");
-+  TORCH_CHECK(
-+      ptr_A_scales.dim() == 1 ||
-+          (ptr_A_scales.dim() == 2 && ptr_A_scales.size(1) == 1),
-+      "ptr_A_scales must be 1D [Total_M] or 2D [Total_M, 1]");
-+  TORCH_CHECK(
-+      ptr_A_scales.size(0) >= 8,
-+      "ptr_A_scales must contain at least topk rows");
-+  TORCH_CHECK(
-+      ptr_B_scales.dim() == 2,
-+      "ptr_B_scales must be 2D [num_experts, N]");
-+  TORCH_CHECK(topk_ids.dim() == 2, "topk_ids must be 2D [1, 8]");
-+  TORCH_CHECK(topk_ids.size(0) == 1, "topk_ids first dim must be one token");
-+  TORCH_CHECK(topk_ids.size(1) == 8, "topk_ids second dim must be topk=8");
-+  TORCH_CHECK(
-+      unpermuted_row_to_permuted_row.numel() >= 8,
-+      "unpermuted_row_to_permuted_row must cover topk=8");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(ptr_bias->dim() == 2, "ptr_bias must be 2D [num_experts, N]");
-+  }
-+
-+  TORCH_CHECK(ptr_A.is_contiguous(), "ptr_A must be contiguous");
-+  TORCH_CHECK(ptr_A_scales.is_contiguous(), "ptr_A_scales must be contiguous");
-+  TORCH_CHECK(ptr_B.is_contiguous(), "ptr_B must be contiguous");
-+  TORCH_CHECK(ptr_B_scales.is_contiguous(), "ptr_B_scales must be contiguous");
-+  TORCH_CHECK(ptr_D.is_contiguous(), "ptr_D must be contiguous");
-+  TORCH_CHECK(topk_ids.is_contiguous(), "topk_ids must be contiguous");
-+  TORCH_CHECK(
-+      unpermuted_row_to_permuted_row.is_contiguous(),
-+      "unpermuted_row_to_permuted_row must be contiguous");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(ptr_bias->is_contiguous(), "ptr_bias must be contiguous");
-+  }
-+
-+  TORCH_CHECK(ptr_B.size(0) == num_experts, "ptr_B.size(0) mismatch");
-+  TORCH_CHECK(ptr_B.size(1) == K, "ptr_B.size(1) mismatch");
-+  TORCH_CHECK(ptr_B.size(2) == N, "ptr_B.size(2) mismatch");
-+  TORCH_CHECK(
-+      ptr_B_scales.size(0) == num_experts,
-+      "ptr_B_scales.size(0) must match num_experts");
-+  TORCH_CHECK(ptr_B_scales.size(1) == N, "ptr_B_scales.size(1) mismatch");
-+  if (ptr_bias.has_value()) {
-+    TORCH_CHECK(
-+        ptr_bias->size(0) == num_experts,
-+        "ptr_bias.size(0) must match num_experts");
-+    TORCH_CHECK(ptr_bias->size(1) == N, "ptr_bias.size(1) mismatch");
-+  }
-+
-+#define W8A8TopK8Gemm1LauncherCallER(Policy, ElementDType)                  \
-+  MoEGEMMTopK8Gemm1Launcher<Policy, ElementDType>(                          \
-+      dpcpp_queue,                                                          \
-+      reinterpret_cast<int8_t*>(ptr_A.data_ptr()),                          \
-+      reinterpret_cast<int8_t*>(ptr_B.data_ptr()),                          \
-+      reinterpret_cast<float*>(ptr_B_scales.data_ptr()),                    \
-+      reinterpret_cast<float*>(ptr_A_scales.data_ptr()),                    \
-+      ptr_bias.has_value() ? reinterpret_cast<float*>(ptr_bias->data_ptr()) \
-+                           : static_cast<float*>(nullptr),                  \
-+      reinterpret_cast<ElementDType*>(ptr_D.data_ptr()),                    \
-+      reinterpret_cast<int64_t*>(topk_ids.data_ptr()),                      \
-+      reinterpret_cast<int*>(unpermuted_row_to_permuted_row.data_ptr()),    \
-+      N,                                                                    \
-+      K);
-+
-+#define W8A8TopK8Gemm1Dispatch(policy)             \
-+  if (D_dtype == at::kBFloat16) {                  \
-+    using out_t = bfloat16_t;                      \
-+    W8A8TopK8Gemm1LauncherCallER(policy, out_t);   \
-+  } else if (D_dtype == at::kHalf) {               \
-+    using out_t = half_t;                          \
-+    W8A8TopK8Gemm1LauncherCallER(policy, out_t);   \
-+  }
-+
-+  const char* mtile_env =
-+      std::getenv("VLLM_XPU_MOE_W8A8_ROUTE_GEMM1_MTILE");
-+  if (mtile_env != nullptr && std::string(mtile_env) == "8") {
-+    using policy = w8a16_policy_m_8;
-+    W8A8TopK8Gemm1Dispatch(policy);
-+  } else if (mtile_env != nullptr && std::string(mtile_env) == "32") {
-+    using policy = w8a16_policy_m_32;
-+    W8A8TopK8Gemm1Dispatch(policy);
-+  } else {
-+    using policy = w8a16_policy_m_16;
-+    W8A8TopK8Gemm1Dispatch(policy);
-+  }
-+
-+#undef W8A8TopK8Gemm1Dispatch
-+#undef W8A8TopK8Gemm1LauncherCallER
-+
-+  return ptr_D;
-+}
- }  // namespace MoE
-diff --git a/csrc/xpu/moe_layerlet.cpp b/csrc/xpu/moe_layerlet.cpp
-index 40289f7..c0cde0e 100644
---- a/csrc/xpu/moe_layerlet.cpp
-+++ b/csrc/xpu/moe_layerlet.cpp
-@@ -1,6 +1,11 @@
- #include <sycl/sycl.hpp>
- #include <torch/all.h>
- 
-+#include <cstdlib>
-+#include <cstdint>
-+#include <optional>
-+
-+#include "csrc/moe/moe_ops.h"
- #include "grouped_gemm/grouped_gemm_interface.h"
- #include "ops.h"
- #include "utils.h"
-@@ -9,6 +14,34 @@ namespace {
- 
- class Qwen36RowsPerExpertOffsetsInt64Kernel;
- 
-+class Qwen36TopkIdsToActiveExpertsInt32Kernel;
-+
-+template <typename scalar_t>
-+class Qwen36SingleTokenPrologueQuant1Kernel;
-+
-+template <typename scalar_t>
-+class Qwen36SingleTokenGatherTopK8Kernel;
-+
-+template <typename scalar_t>
-+class Qwen36SingleTokenGemm2GatherTopK8Kernel;
-+
-+template <typename scalar_t>
-+class Qwen36SharedExpertGateMulKernel;
-+
-+template <typename scalar_t>
-+float qwen36_to_float(scalar_t value) {
-+  return static_cast<float>(value);
-+}
-+
-+bool qwen36_shared_expert_fused_gate_mul_enabled() {
-+  const char* value = std::getenv("VLLM_XPU_SHARED_EXPERT_FUSED_GATE_MUL");
-+  if (value == nullptr) {
-+    return false;
-+  }
-+  return value[0] == '1' || value[0] == 'T' || value[0] == 't' ||
-+         value[0] == 'Y' || value[0] == 'y';
-+}
-+
- void require_xpu_contiguous(const torch::Tensor& tensor, const char* name) {
-   TORCH_CHECK(tensor.defined(), name, " must be defined");
-   TORCH_CHECK(tensor.is_xpu(), name, " must be an XPU tensor");
-@@ -49,6 +82,720 @@ void require_optional_same_device(
-   require_same_device(reference, tensor.value(), name);
- }
- 
-+template <typename scalar_t>
-+void qwen36_single_token_prologue_quant1_out_impl(
-+    const scalar_t* hidden_states,
-+    const int64_t* topk_ids,
-+    int64_t* expert_first_token_offset,
-+    int* unpermuted_row_to_permuted_row,
-+    int8_t* gemm1_a,
-+    float* gemm1_a_scales,
-+    int64_t hidden_size,
-+    int64_t topk,
-+    int64_t num_experts) {
-+  constexpr int kBlockSize = 256;
-+  auto& queue = vllm::xpu::vllmGetQueue();
-+  sycl::range<1> local(kBlockSize);
-+  sycl::range<1> global(kBlockSize);
-+
-+  queue.submit([&](sycl::handler& cgh) {
-+    sycl::local_accessor<float, 1> local_max(local, cgh);
-+    sycl::local_accessor<int, 1> local_permuted(sycl::range<1>(topk), cgh);
-+    cgh.parallel_for(
-+        sycl::nd_range<1>(global, local),
-+        [=](sycl::nd_item<1> item)
-+            [[sycl::reqd_sub_group_size(16)]] {
-+              const int local_id = item.get_local_id(0);
-+              const int local_range = item.get_local_range(0);
-+
-+              for (int64_t expert = local_id; expert <= num_experts;
-+                   expert += local_range) {
-+                int count = 0;
-+                for (int k = 0; k < topk; ++k) {
-+                  if (topk_ids[k] < expert) {
-+                    count += 1;
-+                  }
-+                }
-+                expert_first_token_offset[expert] = count;
-+              }
-+
-+              for (int row_id = local_id; row_id < topk;
-+                   row_id += local_range) {
-+                const int64_t selected_expert = topk_ids[row_id];
-+                int less = 0;
-+                int prior_equal = 0;
-+                for (int k = 0; k < topk; ++k) {
-+                  const int64_t other = topk_ids[k];
-+                  if (other < selected_expert) {
-+                    less += 1;
-+                  }
-+                  if (k < row_id && other == selected_expert) {
-+                    prior_equal += 1;
-+                  }
-+                }
-+                const int permuted_row = less + prior_equal;
-+                local_permuted[row_id] = permuted_row;
-+                unpermuted_row_to_permuted_row[row_id] = permuted_row;
-+              }
-+
-+              float thread_max = 0.0f;
-+              for (int64_t col = local_id; col < hidden_size;
-+                   col += local_range) {
-+                const float value = qwen36_to_float(hidden_states[col]);
-+                thread_max = sycl::fmax(thread_max, sycl::fabs(value));
-+              }
-+
-+              local_max[local_id] = thread_max;
-+              item.barrier(sycl::access::fence_space::local_space);
-+
-+              for (int stride = local_range / 2; stride > 0; stride >>= 1) {
-+                if (local_id < stride) {
-+                  local_max[local_id] =
-+                      sycl::fmax(local_max[local_id],
-+                                 local_max[local_id + stride]);
-+                }
-+                item.barrier(sycl::access::fence_space::local_space);
-+              }
-+
-+              const float absmax = sycl::fmax(local_max[0], 1.0e-10f);
-+              const float scale = absmax / 127.0f;
-+              const float inv_scale = 127.0f / absmax;
-+
-+              for (int row_id = local_id; row_id < topk;
-+                   row_id += local_range) {
-+                gemm1_a_scales[local_permuted[row_id]] = scale;
-+              }
-+
-+              for (int64_t col = local_id; col < hidden_size;
-+                   col += local_range) {
-+                float value = qwen36_to_float(hidden_states[col]) * inv_scale;
-+                value = sycl::round(value);
-+                value = sycl::fmin(127.0f, sycl::fmax(-127.0f, value));
-+                const int8_t qvalue = static_cast<int8_t>(value);
-+                for (int row_id = 0; row_id < topk; ++row_id) {
-+                  gemm1_a[local_permuted[row_id] * hidden_size + col] =
-+                      qvalue;
-+                }
-+              }
-+            });
-+  });
-+}
-+
-+bool qwen36_can_use_single_token_prologue_quant1(
-+    const torch::Tensor& hidden_states,
-+    const torch::Tensor& topk_ids,
-+    const torch::Tensor& topk_weights,
-+    const torch::Tensor& expert_first_token_offset,
-+    const torch::Tensor& unpermuted_row_to_permuted_row,
-+    const torch::Tensor& gemm1_a,
-+    const torch::Tensor& gemm1_a_scales,
-+    int64_t hidden_size,
-+    int64_t num_experts) {
-+  return hidden_states.size(0) == 1 && hidden_states.size(1) == hidden_size &&
-+         topk_ids.size(0) == 1 && topk_ids.size(1) == 8 &&
-+         topk_weights.size(0) == 1 && topk_weights.size(1) == 8 &&
-+         expert_first_token_offset.dim() == 1 &&
-+         expert_first_token_offset.numel() >= num_experts + 1 &&
-+         unpermuted_row_to_permuted_row.dim() == 1 &&
-+         unpermuted_row_to_permuted_row.numel() >= 8 &&
-+         gemm1_a.dim() == 2 && gemm1_a.size(0) >= 8 &&
-+         gemm1_a.size(1) == hidden_size &&
-+         gemm1_a_scales.numel() >= 8;
-+}
-+
-+bool qwen36_fused_q1_enabled() {
-+  const char* value = std::getenv("VLLM_XPU_MOE_W8A8_FUSED_Q1");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+bool qwen36_fast_gather_enabled() {
-+  const char* value = std::getenv("VLLM_XPU_MOE_W8A8_FAST_GATHER");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+bool qwen36_direct_gemm2_gather_enabled() {
-+  const char* value =
-+      std::getenv("VLLM_XPU_MOE_W8A8_DIRECT_GEMM2_GATHER");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+bool qwen36_dpas_gemm2_gather_enabled() {
-+  const char* value = std::getenv("VLLM_XPU_MOE_W8A8_DPAS_GEMM2_GATHER");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+bool qwen36_workspace_atomic_enabled() {
-+  const char* value = std::getenv("VLLM_XPU_MOE_W8A8_WORKSPACE_ATOMIC");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+bool qwen36_route_gemm1_enabled() {
-+  const char* value = std::getenv("VLLM_XPU_MOE_W8A8_ROUTE_GEMM1");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+bool qwen36_unchecked_full_layerlet_enabled() {
-+  const char* value =
-+      std::getenv("VLLM_XPU_MOE_W8A8_UNCHECKED_FULL_LAYERLET");
-+  return value && value[0] != '\0' && value[0] != '0' && value[0] != 'f' &&
-+         value[0] != 'F';
-+}
-+
-+int* qwen36_workspace_atomic_ptr(torch::Tensor& workspace) {
-+  TORCH_CHECK(
-+      workspace.scalar_type() == torch::kUInt8,
-+      "qwen36 workspace atomic reuse expects a uint8 workspace");
-+  TORCH_CHECK(
-+      workspace.numel() >= static_cast<int64_t>(sizeof(int)),
-+      "qwen36 workspace is too small for atomic reuse");
-+  auto* ptr = workspace.data_ptr<uint8_t>();
-+  TORCH_CHECK(
-+      reinterpret_cast<std::uintptr_t>(ptr) % alignof(int) == 0,
-+      "qwen36 workspace pointer is not int aligned");
-+  return reinterpret_cast<int*>(ptr);
-+}
-+
-+torch::Tensor qwen36_grouped_gemm_offsets_maybe_atomic(
-+    torch::Tensor ptr_A,
-+    torch::Tensor ptr_A_scales,
-+    torch::Tensor ptr_B,
-+    torch::Tensor ptr_B_scales,
-+    const c10::optional<at::Tensor>& ptr_bias,
-+    torch::Tensor ptr_D,
-+    torch::Tensor expert_first_token_offset,
-+    int64_t N,
-+    int64_t K,
-+    int64_t num_experts,
-+    int* atomic_buffer) {
-+  if (atomic_buffer != nullptr) {
-+    return cutlass_grouped_gemm_w8a8_int8_offsets_atomic_interface(
-+        ptr_A,
-+        ptr_A_scales,
-+        ptr_B,
-+        ptr_B_scales,
-+        ptr_bias,
-+        ptr_D,
-+        expert_first_token_offset,
-+        N,
-+        K,
-+        num_experts,
-+        atomic_buffer);
-+  }
-+  return cutlass_grouped_gemm_w8a8_int8_offsets_interface(
-+      ptr_A,
-+      ptr_A_scales,
-+      ptr_B,
-+      ptr_B_scales,
-+      ptr_bias,
-+      ptr_D,
-+      expert_first_token_offset,
-+      N,
-+      K,
-+      num_experts);
-+}
-+
-+void qwen36_single_token_prologue_quant1_out(
-+    const torch::Tensor& hidden_states,
-+    const torch::Tensor& topk_ids,
-+    torch::Tensor& expert_first_token_offset,
-+    torch::Tensor& unpermuted_row_to_permuted_row,
-+    torch::Tensor& gemm1_a,
-+    torch::Tensor& gemm1_a_scales,
-+    int64_t hidden_size,
-+    int64_t num_experts) {
-+  TORCH_CHECK(
-+      hidden_states.scalar_type() == torch::kBFloat16 ||
-+          hidden_states.scalar_type() == torch::kFloat16 ||
-+          hidden_states.scalar_type() == torch::kFloat32,
-+      "qwen36 fused prologue+quant1 only supports bf16, fp16, and fp32 hidden_states");
-+  require_dtype(gemm1_a, "gemm1_a", torch::kInt8);
-+  require_dtype(gemm1_a_scales, "gemm1_a_scales", torch::kFloat32);
-+
-+  if (hidden_states.scalar_type() == torch::kBFloat16) {
-+    qwen36_single_token_prologue_quant1_out_impl(
-+        reinterpret_cast<const sycl::ext::oneapi::bfloat16*>(
-+            hidden_states.data_ptr()),
-+        topk_ids.data_ptr<int64_t>(),
-+        expert_first_token_offset.data_ptr<int64_t>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        gemm1_a.data_ptr<int8_t>(),
-+        gemm1_a_scales.data_ptr<float>(),
-+        hidden_size,
-+        8,
-+        num_experts);
-+  } else if (hidden_states.scalar_type() == torch::kFloat16) {
-+    qwen36_single_token_prologue_quant1_out_impl(
-+        reinterpret_cast<const sycl::half*>(hidden_states.data_ptr()),
-+        topk_ids.data_ptr<int64_t>(),
-+        expert_first_token_offset.data_ptr<int64_t>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        gemm1_a.data_ptr<int8_t>(),
-+        gemm1_a_scales.data_ptr<float>(),
-+        hidden_size,
-+        8,
-+        num_experts);
-+  } else {
-+    qwen36_single_token_prologue_quant1_out_impl(
-+        hidden_states.data_ptr<float>(),
-+        topk_ids.data_ptr<int64_t>(),
-+        expert_first_token_offset.data_ptr<int64_t>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        gemm1_a.data_ptr<int8_t>(),
-+        gemm1_a_scales.data_ptr<float>(),
-+        hidden_size,
-+        8,
-+        num_experts);
-+  }
-+}
-+
-+template <typename scalar_t>
-+void qwen36_single_token_gather_topk8_out_impl(
-+    scalar_t* output,
-+    const scalar_t* moe_output,
-+    const float* topk_weights,
-+    const int* unpermuted_row_to_permuted_row,
-+    int64_t hidden_size) {
-+  constexpr int kBlockSize = 256;
-+  constexpr int kElemsPerItem = 8;
-+  constexpr int kTopK = 8;
-+  constexpr int kStride = kBlockSize * kElemsPerItem;
-+  auto& queue = vllm::xpu::vllmGetQueue();
-+  sycl::range<1> local(kBlockSize);
-+  sycl::range<1> global(kBlockSize);
-+
-+  queue.submit([&](sycl::handler& cgh) {
-+    cgh.parallel_for(
-+        sycl::nd_range<1>(global, local),
-+        [=](sycl::nd_item<1> item)
-+            [[sycl::reqd_sub_group_size(16)]] {
-+              const int local_id = item.get_local_id(0);
-+              int moe_ids[kTopK];
-+              float scores[kTopK];
-+#pragma unroll
-+              for (int k = 0; k < kTopK; ++k) {
-+                moe_ids[k] = unpermuted_row_to_permuted_row[k];
-+                scores[k] = topk_weights[k];
-+              }
-+
-+              for (int64_t hidden_idx = local_id * kElemsPerItem;
-+                   hidden_idx < hidden_size;
-+                   hidden_idx += kStride) {
-+                float accum[kElemsPerItem];
-+#pragma unroll
-+                for (int e = 0; e < kElemsPerItem; ++e) {
-+                  accum[e] = 0.0f;
-+                }
-+#pragma unroll
-+                for (int k = 0; k < kTopK; ++k) {
-+                  const int row = moe_ids[k];
-+#pragma unroll
-+                  for (int e = 0; e < kElemsPerItem; ++e) {
-+                    accum[e] += qwen36_to_float(
-+                                    moe_output[row * hidden_size + hidden_idx +
-+                                               e]) *
-+                                scores[k];
-+                  }
-+                }
-+#pragma unroll
-+                for (int e = 0; e < kElemsPerItem; ++e) {
-+                  output[hidden_idx + e] = accum[e];
-+                }
-+              }
-+            });
-+  });
-+}
-+
-+bool qwen36_can_use_single_token_fast_gather(
-+    const torch::Tensor& output,
-+    const torch::Tensor& gemm2_output,
-+    const torch::Tensor& topk_weights,
-+    const torch::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t hidden_size) {
-+  return output.dim() == 2 && output.size(0) == 1 &&
-+         output.size(1) == hidden_size && hidden_size % 8 == 0 &&
-+         gemm2_output.dim() == 2 && gemm2_output.size(0) >= 8 &&
-+         gemm2_output.size(1) == hidden_size && topk_weights.dim() == 2 &&
-+         topk_weights.size(0) == 1 && topk_weights.size(1) == 8 &&
-+         unpermuted_row_to_permuted_row.dim() == 1 &&
-+         unpermuted_row_to_permuted_row.numel() >= 8;
-+}
-+
-+void qwen36_single_token_gather_topk8_out(
-+    torch::Tensor& output,
-+    const torch::Tensor& gemm2_output,
-+    const torch::Tensor& topk_weights,
-+    const torch::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t hidden_size) {
-+  if (output.scalar_type() == torch::kBFloat16) {
-+    qwen36_single_token_gather_topk8_out_impl(
-+        reinterpret_cast<sycl::ext::oneapi::bfloat16*>(output.data_ptr()),
-+        reinterpret_cast<const sycl::ext::oneapi::bfloat16*>(
-+            gemm2_output.data_ptr()),
-+        topk_weights.data_ptr<float>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        hidden_size);
-+  } else if (output.scalar_type() == torch::kFloat16) {
-+    qwen36_single_token_gather_topk8_out_impl(
-+        reinterpret_cast<sycl::half*>(output.data_ptr()),
-+        reinterpret_cast<const sycl::half*>(gemm2_output.data_ptr()),
-+        topk_weights.data_ptr<float>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        hidden_size);
-+  } else {
-+    qwen36_single_token_gather_topk8_out_impl(
-+        output.data_ptr<float>(),
-+        gemm2_output.data_ptr<float>(),
-+        topk_weights.data_ptr<float>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        hidden_size);
-+  }
-+}
-+
-+template <typename scalar_t>
-+void qwen36_single_token_gemm2_gather_topk8_out_impl(
-+    scalar_t* output,
-+    const int8_t* gemm2_a,
-+    const float* gemm2_a_scales,
-+    const int8_t* w2,
-+    const float* w2_scales,
-+    const float* w2_bias,
-+    const int64_t* topk_ids,
-+    const float* topk_weights,
-+    const int* unpermuted_row_to_permuted_row,
-+    int64_t hidden_size,
-+    int64_t inter_size,
-+    int64_t topk) {
-+  constexpr int kBlockSize = 256;
-+  auto& queue = vllm::xpu::vllmGetQueue();
-+  sycl::range<1> local(kBlockSize);
-+  sycl::range<1> global(hidden_size * kBlockSize);
-+
-+  queue.submit([&](sycl::handler& cgh) {
-+    sycl::local_accessor<int32_t, 1> partial(local, cgh);
-+    cgh.parallel_for<
-+        Qwen36SingleTokenGemm2GatherTopK8Kernel<scalar_t>>(
-+        sycl::nd_range<1>(global, local),
-+        [=](sycl::nd_item<1> item)
-+            [[sycl::reqd_sub_group_size(16)]] {
-+              const int64_t col = item.get_group(0);
-+              const int local_id = item.get_local_id(0);
-+              const int local_range = item.get_local_range(0);
-+              float accum = 0.0f;
-+
-+              for (int k = 0; k < topk; ++k) {
-+                const int row = unpermuted_row_to_permuted_row[k];
-+                const int64_t expert = topk_ids[k];
-+                int32_t thread_sum = 0;
-+                for (int64_t kk = local_id; kk < inter_size;
-+                     kk += local_range) {
-+                  const int32_t a =
-+                      static_cast<int32_t>(gemm2_a[row * inter_size + kk]);
-+                  const int32_t b = static_cast<int32_t>(
-+                      w2[(expert * inter_size + kk) * hidden_size + col]);
-+                  thread_sum += a * b;
-+                }
-+
-+                partial[local_id] = thread_sum;
-+                item.barrier(sycl::access::fence_space::local_space);
-+
-+                for (int stride = local_range / 2; stride > 0; stride >>= 1) {
-+                  if (local_id < stride) {
-+                    partial[local_id] += partial[local_id + stride];
-+                  }
-+                  item.barrier(sycl::access::fence_space::local_space);
-+                }
-+
-+                if (local_id == 0) {
-+                  float value = static_cast<float>(partial[0]) *
-+                      gemm2_a_scales[row] *
-+                      w2_scales[expert * hidden_size + col];
-+                  if (w2_bias != nullptr) {
-+                    value += w2_bias[expert * hidden_size + col];
-+                  }
-+
-+                  // Match the accepted exact path: GEMM2 first materializes a
-+                  // BF16/FP16 row; gather then converts that row back to float.
-+                  const scalar_t intermediate = static_cast<scalar_t>(value);
-+                  accum += qwen36_to_float(intermediate) * topk_weights[k];
-+                }
-+
-+                item.barrier(sycl::access::fence_space::local_space);
-+              }
-+
-+              if (local_id == 0) {
-+                output[col] = static_cast<scalar_t>(accum);
-+              }
-+            });
-+  });
-+}
-+
-+bool qwen36_can_use_single_token_direct_gemm2_gather(
-+    const torch::Tensor& output,
-+    const torch::Tensor& gemm2_a,
-+    const torch::Tensor& gemm2_a_scales,
-+    const torch::Tensor& w2,
-+    const torch::Tensor& w2_scales,
-+    const c10::optional<at::Tensor>& w2_bias,
-+    const torch::Tensor& topk_ids,
-+    const torch::Tensor& topk_weights,
-+    const torch::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t hidden_size,
-+    int64_t inter_size,
-+    int64_t num_experts) {
-+  const bool bias_ok = !w2_bias.has_value() ||
-+      (w2_bias.value().defined() && w2_bias.value().dim() == 2 &&
-+       w2_bias.value().size(0) == num_experts &&
-+       w2_bias.value().size(1) == hidden_size &&
-+       w2_bias.value().scalar_type() == torch::kFloat32);
-+  return output.dim() == 2 && output.size(0) == 1 &&
-+         output.size(1) == hidden_size &&
-+         (output.scalar_type() == torch::kBFloat16 ||
-+          output.scalar_type() == torch::kFloat16) &&
-+         gemm2_a.dim() == 2 && gemm2_a.size(0) >= 8 &&
-+         gemm2_a.size(1) == inter_size &&
-+         gemm2_a.scalar_type() == torch::kInt8 &&
-+         gemm2_a_scales.numel() >= 8 &&
-+         gemm2_a_scales.scalar_type() == torch::kFloat32 &&
-+         w2.dim() == 3 && w2.size(0) == num_experts &&
-+         w2.size(1) == inter_size && w2.size(2) == hidden_size &&
-+         w2.scalar_type() == torch::kInt8 &&
-+         w2_scales.dim() == 2 && w2_scales.size(0) == num_experts &&
-+         w2_scales.size(1) == hidden_size &&
-+         w2_scales.scalar_type() == torch::kFloat32 && bias_ok &&
-+         topk_ids.dim() == 2 && topk_ids.size(0) == 1 &&
-+         topk_ids.size(1) == 8 &&
-+         topk_ids.scalar_type() == torch::kInt64 &&
-+         topk_weights.dim() == 2 && topk_weights.size(0) == 1 &&
-+         topk_weights.size(1) == 8 &&
-+         topk_weights.scalar_type() == torch::kFloat32 &&
-+         unpermuted_row_to_permuted_row.dim() == 1 &&
-+         unpermuted_row_to_permuted_row.numel() >= 8 &&
-+         unpermuted_row_to_permuted_row.scalar_type() == torch::kInt32;
-+}
-+
-+bool qwen36_can_use_single_token_route_gemm1(
-+    const torch::Tensor& gemm1_a,
-+    const torch::Tensor& gemm1_a_scales,
-+    const torch::Tensor& w13,
-+    const torch::Tensor& w13_scales,
-+    const c10::optional<at::Tensor>& w13_bias,
-+    const torch::Tensor& gemm1_output,
-+    const torch::Tensor& topk_ids,
-+    const torch::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t hidden_size,
-+    int64_t inter_size,
-+    int64_t num_experts) {
-+  const int64_t gemm1_n = 2 * inter_size;
-+  const bool bias_ok = !w13_bias.has_value() ||
-+      (w13_bias.value().defined() && w13_bias.value().dim() == 2 &&
-+       w13_bias.value().size(0) == num_experts &&
-+       w13_bias.value().size(1) == gemm1_n &&
-+       w13_bias.value().scalar_type() == torch::kFloat32);
-+  return gemm1_a.dim() == 2 && gemm1_a.size(0) >= 8 &&
-+         gemm1_a.size(1) == hidden_size &&
-+         gemm1_a.scalar_type() == torch::kInt8 &&
-+         gemm1_a_scales.numel() >= 8 &&
-+         gemm1_a_scales.scalar_type() == torch::kFloat32 &&
-+         w13.dim() == 3 && w13.size(0) == num_experts &&
-+         w13.size(1) == hidden_size && w13.size(2) == gemm1_n &&
-+         w13.scalar_type() == torch::kInt8 &&
-+         w13_scales.dim() == 2 && w13_scales.size(0) == num_experts &&
-+         w13_scales.size(1) == gemm1_n &&
-+         w13_scales.scalar_type() == torch::kFloat32 && bias_ok &&
-+         gemm1_output.dim() == 2 && gemm1_output.size(0) >= 8 &&
-+         gemm1_output.size(1) == gemm1_n &&
-+         (gemm1_output.scalar_type() == torch::kBFloat16 ||
-+          gemm1_output.scalar_type() == torch::kFloat16) &&
-+         topk_ids.dim() == 2 && topk_ids.size(0) == 1 &&
-+         topk_ids.size(1) == 8 &&
-+         topk_ids.scalar_type() == torch::kInt64 &&
-+         unpermuted_row_to_permuted_row.dim() == 1 &&
-+         unpermuted_row_to_permuted_row.numel() >= 8 &&
-+         unpermuted_row_to_permuted_row.scalar_type() == torch::kInt32;
-+}
-+
-+void qwen36_single_token_gemm2_gather_topk8_out(
-+    torch::Tensor& output,
-+    const torch::Tensor& gemm2_a,
-+    const torch::Tensor& gemm2_a_scales,
-+    const torch::Tensor& w2,
-+    const torch::Tensor& w2_scales,
-+    const c10::optional<at::Tensor>& w2_bias,
-+    const torch::Tensor& topk_ids,
-+    const torch::Tensor& topk_weights,
-+    const torch::Tensor& unpermuted_row_to_permuted_row,
-+    int64_t hidden_size,
-+    int64_t inter_size,
-+    int64_t topk) {
-+  const float* bias_ptr = w2_bias.has_value()
-+      ? w2_bias.value().data_ptr<float>()
-+      : static_cast<float*>(nullptr);
-+
-+  if (output.scalar_type() == torch::kBFloat16) {
-+    qwen36_single_token_gemm2_gather_topk8_out_impl(
-+        reinterpret_cast<sycl::ext::oneapi::bfloat16*>(output.data_ptr()),
-+        gemm2_a.data_ptr<int8_t>(),
-+        gemm2_a_scales.data_ptr<float>(),
-+        w2.data_ptr<int8_t>(),
-+        w2_scales.data_ptr<float>(),
-+        bias_ptr,
-+        topk_ids.data_ptr<int64_t>(),
-+        topk_weights.data_ptr<float>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        hidden_size,
-+        inter_size,
-+        topk);
-+  } else {
-+    qwen36_single_token_gemm2_gather_topk8_out_impl(
-+        reinterpret_cast<sycl::half*>(output.data_ptr()),
-+        gemm2_a.data_ptr<int8_t>(),
-+        gemm2_a_scales.data_ptr<float>(),
-+        w2.data_ptr<int8_t>(),
-+        w2_scales.data_ptr<float>(),
-+        bias_ptr,
-+        topk_ids.data_ptr<int64_t>(),
-+        topk_weights.data_ptr<float>(),
-+        unpermuted_row_to_permuted_row.data_ptr<int>(),
-+        hidden_size,
-+        inter_size,
-+        topk);
-+  }
-+}
-+
-+template <typename scalar_t>
-+void qwen36_shared_expert_gate_mul_out_impl(
-+    const scalar_t* hidden_states,
-+    const scalar_t* expert_gate_w,
-+    const scalar_t* down_out,
-+    scalar_t* output,
-+    int64_t rows,
-+    int64_t hidden_size) {
-+  constexpr int kBlockSize = 256;
-+  auto& queue = vllm::xpu::vllmGetQueue();
-+  sycl::range<1> local(kBlockSize);
-+  sycl::range<1> global(rows * kBlockSize);
-+
-+  queue.submit([&](sycl::handler& cgh) {
-+    sycl::local_accessor<float, 1> partial(local, cgh);
-+    cgh.parallel_for<Qwen36SharedExpertGateMulKernel<scalar_t>>(
-+        sycl::nd_range<1>(global, local),
-+        [=](sycl::nd_item<1> item)
-+            [[sycl::reqd_sub_group_size(16)]] {
-+              const int64_t row = item.get_group(0);
-+              const int local_id = item.get_local_id(0);
-+              const int local_range = item.get_local_range(0);
-+
-+              float thread_sum = 0.0f;
-+              for (int64_t col = local_id; col < hidden_size;
-+                   col += local_range) {
-+                thread_sum +=
-+                    qwen36_to_float(hidden_states[row * hidden_size + col]) *
-+                    qwen36_to_float(expert_gate_w[col]);
-+              }
-+
-+              partial[local_id] = thread_sum;
-+              item.barrier(sycl::access::fence_space::local_space);
-+
-+              for (int stride = local_range / 2; stride > 0; stride >>= 1) {
-+                if (local_id < stride) {
-+                  partial[local_id] += partial[local_id + stride];
-+                }
-+                item.barrier(sycl::access::fence_space::local_space);
-+              }
-+
-+              const scalar_t gate_t = static_cast<scalar_t>(partial[0]);
-+              const float gate_f = qwen36_to_float(gate_t);
-+              const scalar_t sigmoid_t = static_cast<scalar_t>(
-+                  1.0f / (1.0f + sycl::exp(-gate_f)));
-+              const float sigmoid_f = qwen36_to_float(sigmoid_t);
-+
-+              for (int64_t col = local_id; col < hidden_size;
-+                   col += local_range) {
-+                const float value =
-+                    sigmoid_f *
-+                    qwen36_to_float(down_out[row * hidden_size + col]);
-+                output[row * hidden_size + col] =
-+                    static_cast<scalar_t>(value);
-+              }
-+            });
-+  });
-+}
-+
-+void qwen36_shared_expert_gate_mul_out(
-+    const torch::Tensor& hidden_states,
-+    const torch::Tensor& expert_gate_w,
-+    const torch::Tensor& down_out,
-+    torch::Tensor& output) {
-+  require_xpu_contiguous(hidden_states, "hidden_states");
-+  require_xpu_contiguous(expert_gate_w, "expert_gate_w");
-+  require_xpu_contiguous(down_out, "down_out");
-+  require_xpu_contiguous(output, "output");
-+  require_same_device(hidden_states, expert_gate_w, "expert_gate_w");
-+  require_same_device(hidden_states, down_out, "down_out");
-+  require_same_device(hidden_states, output, "output");
-+  require_dtype(expert_gate_w, "expert_gate_w", hidden_states.scalar_type());
-+  require_dtype(down_out, "down_out", hidden_states.scalar_type());
-+  require_dtype(output, "output", hidden_states.scalar_type());
-+
-+  TORCH_CHECK(hidden_states.dim() == 2, "hidden_states must be [rows, hidden]");
-+  TORCH_CHECK(down_out.sizes() == hidden_states.sizes(),
-+              "down_out shape must match hidden_states");
-+  TORCH_CHECK(output.sizes() == hidden_states.sizes(),
-+              "output shape must match hidden_states");
-+  TORCH_CHECK(expert_gate_w.dim() == 2,
-+              "expert_gate_w must be [hidden, 1] or [1, hidden]");
-+  const int64_t rows = hidden_states.size(0);
-+  const int64_t hidden = hidden_states.size(1);
-+  TORCH_CHECK(
-+      (expert_gate_w.size(0) == hidden && expert_gate_w.size(1) == 1) ||
-+          (expert_gate_w.size(0) == 1 && expert_gate_w.size(1) == hidden),
-+      "expert_gate_w shape mismatch: expected [",
-+      hidden,
-+      ", 1] or [1, ",
-+      hidden,
-+      "]");
-+  TORCH_CHECK(
-+      hidden_states.scalar_type() == torch::kBFloat16 ||
-+          hidden_states.scalar_type() == torch::kFloat16 ||
-+          hidden_states.scalar_type() == torch::kFloat32,
-+      "qwen36 shared expert fused gate/mul only supports bf16, fp16, and fp32");
-+
-+  if (hidden_states.scalar_type() == torch::kBFloat16) {
-+    qwen36_shared_expert_gate_mul_out_impl(
-+        reinterpret_cast<const sycl::ext::oneapi::bfloat16*>(
-+            hidden_states.data_ptr()),
-+        reinterpret_cast<const sycl::ext::oneapi::bfloat16*>(
-+            expert_gate_w.data_ptr()),
-+        reinterpret_cast<const sycl::ext::oneapi::bfloat16*>(
-+            down_out.data_ptr()),
-+        reinterpret_cast<sycl::ext::oneapi::bfloat16*>(output.data_ptr()),
-+        rows,
-+        hidden);
-+  } else if (hidden_states.scalar_type() == torch::kFloat16) {
-+    qwen36_shared_expert_gate_mul_out_impl(
-+        reinterpret_cast<const sycl::half*>(hidden_states.data_ptr()),
-+        reinterpret_cast<const sycl::half*>(expert_gate_w.data_ptr()),
-+        reinterpret_cast<const sycl::half*>(down_out.data_ptr()),
-+        reinterpret_cast<sycl::half*>(output.data_ptr()),
-+        rows,
-+        hidden);
-+  } else {
-+    qwen36_shared_expert_gate_mul_out_impl(
-+        hidden_states.data_ptr<float>(),
-+        expert_gate_w.data_ptr<float>(),
-+        down_out.data_ptr<float>(),
-+        output.data_ptr<float>(),
-+        rows,
-+        hidden);
-+  }
-+}
-+
- }  // namespace
- 
- torch::Tensor qwen36_rows_per_expert_offsets_int64_out(
-@@ -84,6 +831,50 @@ torch::Tensor qwen36_rows_per_expert_offsets_int64_out(
-   return offsets;
- }
- 
-+torch::Tensor qwen36_topk_ids_to_active_expert_ids_int32_out(
-+    torch::Tensor topk_ids,
-+    torch::Tensor active_expert_ids,
-+    int64_t topk) {
-+  require_xpu_contiguous(topk_ids, "topk_ids");
-+  require_xpu_contiguous(active_expert_ids, "active_expert_ids");
-+  require_same_device(topk_ids, active_expert_ids, "active_expert_ids");
-+  require_dtype(topk_ids, "topk_ids", at::ScalarType::Long);
-+  require_dtype(active_expert_ids, "active_expert_ids", at::ScalarType::Int);
-+  TORCH_CHECK(topk >= 0, "topk must be non-negative");
-+  TORCH_CHECK(topk <= 64, "topk helper supports at most 64 experts");
-+  TORCH_CHECK(topk_ids.numel() >= topk, "topk_ids must cover topk");
-+  TORCH_CHECK(
-+      active_expert_ids.numel() >= topk,
-+      "active_expert_ids must cover topk");
-+
-+  const int64_t* topk_ptr = topk_ids.data_ptr<int64_t>();
-+  int32_t* active_ptr = active_expert_ids.data_ptr<int32_t>();
-+  auto& queue = vllm::xpu::vllmGetQueue();
-+
-+  queue.submit([&](sycl::handler& cgh) {
-+    cgh.single_task<Qwen36TopkIdsToActiveExpertsInt32Kernel>([=]() {
-+      int32_t values[64];
-+      for (int64_t i = 0; i < topk; ++i) {
-+        values[i] = static_cast<int32_t>(topk_ptr[i]);
-+      }
-+      for (int64_t i = 1; i < topk; ++i) {
-+        const int32_t value = values[i];
-+        int64_t j = i - 1;
-+        while (j >= 0 && values[j] > value) {
-+          values[j + 1] = values[j];
-+          --j;
-+        }
-+        values[j + 1] = value;
-+      }
-+      for (int64_t i = 0; i < topk; ++i) {
-+        active_ptr[i] = values[i];
-+      }
-+    });
-+  });
-+
-+  return active_expert_ids;
-+}
-+
- torch::Tensor qwen36_moe_w8a8_middle_layerlet(
-     torch::Tensor gemm1_a,
-     torch::Tensor gemm1_a_scales,
-@@ -194,3 +985,387 @@ torch::Tensor qwen36_moe_w8a8_middle_layerlet(
- 
-   return gemm2_output;
- }
-+
-+torch::Tensor qwen36_moe_w8a8_full_layerlet(
-+    torch::Tensor hidden_states,
-+    torch::Tensor topk_ids,
-+    torch::Tensor topk_weights,
-+    torch::Tensor workspace,
-+    torch::Tensor remapped_hidden_states,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    torch::Tensor expert_first_token_offset,
-+    torch::Tensor gemm1_a,
-+    torch::Tensor gemm1_a_scales,
-+    torch::Tensor w13,
-+    torch::Tensor w13_scales,
-+    const c10::optional<at::Tensor>& w13_bias,
-+    torch::Tensor gemm1_output,
-+    torch::Tensor gemm2_a,
-+    torch::Tensor gemm2_a_scales,
-+    torch::Tensor w2,
-+    torch::Tensor w2_scales,
-+    const c10::optional<at::Tensor>& w2_bias,
-+    torch::Tensor gemm2_output,
-+    torch::Tensor output,
-+    int64_t hidden_size,
-+    int64_t inter_size,
-+    int64_t num_experts) {
-+  if (!qwen36_unchecked_full_layerlet_enabled()) {
-+    require_xpu_contiguous(hidden_states, "hidden_states");
-+    require_xpu_contiguous(topk_ids, "topk_ids");
-+    require_xpu_contiguous(topk_weights, "topk_weights");
-+    require_xpu_contiguous(workspace, "workspace");
-+    require_xpu_contiguous(remapped_hidden_states, "remapped_hidden_states");
-+    require_xpu_contiguous(
-+        unpermuted_row_to_permuted_row, "unpermuted_row_to_permuted_row");
-+    require_xpu_contiguous(expert_first_token_offset,
-+                           "expert_first_token_offset");
-+    require_xpu_contiguous(output, "output");
-+
-+    require_same_device(hidden_states, topk_ids, "topk_ids");
-+    require_same_device(hidden_states, topk_weights, "topk_weights");
-+    require_same_device(hidden_states, workspace, "workspace");
-+    require_same_device(hidden_states, remapped_hidden_states,
-+                        "remapped_hidden_states");
-+    require_same_device(hidden_states, unpermuted_row_to_permuted_row,
-+                        "unpermuted_row_to_permuted_row");
-+    require_same_device(hidden_states, expert_first_token_offset,
-+                        "expert_first_token_offset");
-+    require_same_device(hidden_states, output, "output");
-+
-+    require_dtype(topk_ids, "topk_ids", torch::kInt64);
-+    require_dtype(topk_weights, "topk_weights", torch::kFloat32);
-+    require_dtype(workspace, "workspace", torch::kUInt8);
-+    require_dtype(
-+        unpermuted_row_to_permuted_row,
-+        "unpermuted_row_to_permuted_row",
-+        torch::kInt32);
-+    require_dtype(expert_first_token_offset,
-+                  "expert_first_token_offset",
-+                  torch::kInt64);
-+
-+    TORCH_CHECK(hidden_states.dim() == 2, "hidden_states must be 2D");
-+    TORCH_CHECK(topk_ids.dim() == 2, "topk_ids must be 2D");
-+    TORCH_CHECK(topk_weights.dim() == 2, "topk_weights must be 2D");
-+    TORCH_CHECK(output.dim() == 2, "output must be 2D");
-+    TORCH_CHECK(
-+        hidden_states.size(0) == topk_ids.size(0),
-+        "topk_ids row count must match hidden_states");
-+    TORCH_CHECK(
-+        topk_weights.sizes() == topk_ids.sizes(),
-+        "topk_weights shape must match topk_ids");
-+    TORCH_CHECK(
-+        hidden_states.size(1) == hidden_size,
-+        "hidden_states last dim must match hidden_size");
-+    TORCH_CHECK(
-+        output.size(0) == hidden_states.size(0),
-+        "output row count must match hidden_states");
-+    TORCH_CHECK(
-+        output.size(1) == hidden_size,
-+        "output last dim must match hidden_size");
-+  }
-+
-+  if (qwen36_fused_q1_enabled() &&
-+      qwen36_can_use_single_token_prologue_quant1(
-+          hidden_states,
-+          topk_ids,
-+          topk_weights,
-+          expert_first_token_offset,
-+          unpermuted_row_to_permuted_row,
-+          gemm1_a,
-+          gemm1_a_scales,
-+          hidden_size,
-+          num_experts)) {
-+    qwen36_single_token_prologue_quant1_out(
-+        hidden_states,
-+        topk_ids,
-+        expert_first_token_offset,
-+        unpermuted_row_to_permuted_row,
-+        gemm1_a,
-+        gemm1_a_scales,
-+        hidden_size,
-+        num_experts);
-+  } else {
-+    c10::optional<torch::Tensor> input_scales = c10::nullopt;
-+    fused_moe_prologue(
-+        hidden_states,
-+        input_scales,
-+        topk_ids,
-+        topk_weights,
-+        workspace,
-+        hidden_size,
-+        inter_size,
-+        1,
-+        0,
-+        1,
-+        num_experts);
-+
-+    per_token_quant_int8_xpu_out(
-+        remapped_hidden_states, gemm1_a, gemm1_a_scales);
-+  }
-+
-+  const bool can_use_gemm2_gather =
-+      qwen36_can_use_single_token_direct_gemm2_gather(
-+          output,
-+          gemm2_a,
-+          gemm2_a_scales,
-+          w2,
-+          w2_scales,
-+          w2_bias,
-+          topk_ids,
-+          topk_weights,
-+          unpermuted_row_to_permuted_row,
-+          hidden_size,
-+          inter_size,
-+          num_experts);
-+  const bool use_dpas_gemm2_gather =
-+      qwen36_dpas_gemm2_gather_enabled() && can_use_gemm2_gather;
-+  const bool use_direct_gemm2_gather =
-+      qwen36_direct_gemm2_gather_enabled() && can_use_gemm2_gather;
-+  int* workspace_atomic_buffer =
-+      qwen36_workspace_atomic_enabled() ? qwen36_workspace_atomic_ptr(workspace)
-+                                        : nullptr;
-+  const bool use_route_gemm1 =
-+      qwen36_route_gemm1_enabled() &&
-+      qwen36_can_use_single_token_route_gemm1(
-+          gemm1_a,
-+          gemm1_a_scales,
-+          w13,
-+          w13_scales,
-+          w13_bias,
-+          gemm1_output,
-+          topk_ids,
-+          unpermuted_row_to_permuted_row,
-+          hidden_size,
-+          inter_size,
-+          num_experts);
-+
-+  auto run_gemm1 = [&]() {
-+    if (use_route_gemm1) {
-+      cutlass_grouped_gemm_w8a8_int8_topk8_gemm1_interface(
-+          gemm1_a,
-+          gemm1_a_scales,
-+          w13,
-+          w13_scales,
-+          w13_bias,
-+          gemm1_output,
-+          topk_ids,
-+          unpermuted_row_to_permuted_row,
-+          2 * inter_size,
-+          hidden_size,
-+          num_experts);
-+    } else {
-+      qwen36_grouped_gemm_offsets_maybe_atomic(
-+          gemm1_a,
-+          gemm1_a_scales,
-+          w13,
-+          w13_scales,
-+          w13_bias,
-+          gemm1_output,
-+          expert_first_token_offset,
-+          2 * inter_size,
-+          hidden_size,
-+          num_experts,
-+          workspace_atomic_buffer);
-+    }
-+  };
-+
-+  if (use_dpas_gemm2_gather || use_direct_gemm2_gather) {
-+    run_gemm1();
-+
-+    silu_and_mul_quant_int8_xpu_out(gemm1_output, gemm2_a, gemm2_a_scales);
-+
-+    if (use_dpas_gemm2_gather) {
-+      cutlass_grouped_gemm_w8a8_int8_topk8_gather_interface(
-+          gemm2_a,
-+          gemm2_a_scales,
-+          w2,
-+          w2_scales,
-+          w2_bias,
-+          output,
-+          topk_ids,
-+          topk_weights,
-+          unpermuted_row_to_permuted_row,
-+          hidden_size,
-+          inter_size,
-+          num_experts);
-+    } else {
-+      qwen36_single_token_gemm2_gather_topk8_out(
-+          output,
-+          gemm2_a,
-+          gemm2_a_scales,
-+          w2,
-+          w2_scales,
-+          w2_bias,
-+          topk_ids,
-+          topk_weights,
-+          unpermuted_row_to_permuted_row,
-+          hidden_size,
-+          inter_size,
-+          8);
-+    }
-+  } else {
-+    if (workspace_atomic_buffer != nullptr || use_route_gemm1) {
-+      run_gemm1();
-+      silu_and_mul_quant_int8_xpu_out(gemm1_output, gemm2_a, gemm2_a_scales);
-+
-+      qwen36_grouped_gemm_offsets_maybe_atomic(
-+          gemm2_a,
-+          gemm2_a_scales,
-+          w2,
-+          w2_scales,
-+          w2_bias,
-+          gemm2_output,
-+          expert_first_token_offset,
-+          hidden_size,
-+          inter_size,
-+          num_experts,
-+          workspace_atomic_buffer);
-+    } else {
-+      qwen36_moe_w8a8_middle_layerlet(
-+          gemm1_a,
-+          gemm1_a_scales,
-+          w13,
-+          w13_scales,
-+          w13_bias,
-+          gemm1_output,
-+          gemm2_a,
-+          gemm2_a_scales,
-+          w2,
-+          w2_scales,
-+          w2_bias,
-+          gemm2_output,
-+          expert_first_token_offset,
-+          2 * inter_size,
-+          hidden_size,
-+          hidden_size,
-+          inter_size,
-+          num_experts);
-+    }
-+
-+    if (qwen36_fast_gather_enabled() &&
-+        qwen36_can_use_single_token_fast_gather(
-+            output,
-+            gemm2_output,
-+            topk_weights,
-+            unpermuted_row_to_permuted_row,
-+            hidden_size)) {
-+      qwen36_single_token_gather_topk8_out(
-+          output,
-+          gemm2_output,
-+          topk_weights,
-+          unpermuted_row_to_permuted_row,
-+          hidden_size);
-+    } else {
-+      moe_gather(
-+          output, gemm2_output, topk_weights, unpermuted_row_to_permuted_row,
-+          num_experts);
-+    }
-+  }
-+  return output;
-+}
-+
-+torch::Tensor qwen36_shared_expert_w8a8_out(
-+    const torch::Tensor& hidden_states,
-+    torch::Tensor& hidden_q,
-+    torch::Tensor& hidden_scales,
-+    const torch::Tensor& gate_up_w,
-+    const torch::Tensor& gate_up_w_scales,
-+    torch::Tensor& gate_up_out,
-+    torch::Tensor& act_q,
-+    torch::Tensor& act_scales,
-+    const torch::Tensor& down_w,
-+    const torch::Tensor& down_w_scales,
-+    torch::Tensor& down_out,
-+    const torch::Tensor& expert_gate_w,
-+    torch::Tensor& output) {
-+  require_xpu_contiguous(hidden_states, "hidden_states");
-+  require_xpu_contiguous(hidden_q, "hidden_q");
-+  require_xpu_contiguous(hidden_scales, "hidden_scales");
-+  require_xpu_contiguous(gate_up_w, "gate_up_w");
-+  require_xpu_contiguous(gate_up_w_scales, "gate_up_w_scales");
-+  require_xpu_contiguous(gate_up_out, "gate_up_out");
-+  require_xpu_contiguous(act_q, "act_q");
-+  require_xpu_contiguous(act_scales, "act_scales");
-+  require_xpu_contiguous(down_w, "down_w");
-+  require_xpu_contiguous(down_w_scales, "down_w_scales");
-+  require_xpu_contiguous(down_out, "down_out");
-+  require_xpu_contiguous(expert_gate_w, "expert_gate_w");
-+  require_xpu_contiguous(output, "output");
-+  require_same_device(hidden_states, hidden_q, "hidden_q");
-+  require_same_device(hidden_states, hidden_scales, "hidden_scales");
-+  require_same_device(hidden_states, gate_up_w, "gate_up_w");
-+  require_same_device(hidden_states, gate_up_w_scales, "gate_up_w_scales");
-+  require_same_device(hidden_states, gate_up_out, "gate_up_out");
-+  require_same_device(hidden_states, act_q, "act_q");
-+  require_same_device(hidden_states, act_scales, "act_scales");
-+  require_same_device(hidden_states, down_w, "down_w");
-+  require_same_device(hidden_states, down_w_scales, "down_w_scales");
-+  require_same_device(hidden_states, down_out, "down_out");
-+  require_same_device(hidden_states, expert_gate_w, "expert_gate_w");
-+  require_same_device(hidden_states, output, "output");
-+  require_dtype(hidden_q, "hidden_q", torch::kInt8);
-+  require_dtype(act_q, "act_q", torch::kInt8);
-+  require_dtype(hidden_scales, "hidden_scales", torch::kFloat32);
-+  require_dtype(act_scales, "act_scales", torch::kFloat32);
-+  TORCH_CHECK(hidden_states.dim() == 2, "hidden_states must be [rows, hidden]");
-+  TORCH_CHECK(gate_up_w.dim() == 2, "gate_up_w must be [hidden, 2*inter]");
-+  TORCH_CHECK(down_w.dim() == 2, "down_w must be [inter, hidden]");
-+  TORCH_CHECK(expert_gate_w.dim() == 2,
-+              "expert_gate_w must be [hidden, 1] or [1, hidden]");
-+  const int64_t rows = hidden_states.size(0);
-+  const int64_t hidden = hidden_states.size(1);
-+  const int64_t inter = down_w.size(0);
-+  TORCH_CHECK(gate_up_w.size(0) == hidden, "gate_up_w K mismatch");
-+  TORCH_CHECK(gate_up_w.size(1) == 2 * inter, "gate_up_w N mismatch");
-+  TORCH_CHECK(down_w.size(1) == hidden, "down_w N mismatch");
-+  const bool expert_gate_col_major =
-+      expert_gate_w.size(0) == hidden && expert_gate_w.size(1) == 1;
-+  const bool expert_gate_linear_layout =
-+      expert_gate_w.size(0) == 1 && expert_gate_w.size(1) == hidden;
-+  TORCH_CHECK(expert_gate_col_major || expert_gate_linear_layout,
-+              "expert_gate_w shape mismatch: expected [",
-+              hidden,
-+              ", 1] or [1, ",
-+              hidden,
-+              "], got [",
-+              expert_gate_w.size(0),
-+              ", ",
-+              expert_gate_w.size(1),
-+              "]");
-+  TORCH_CHECK(hidden_q.sizes() == hidden_states.sizes(), "hidden_q shape mismatch");
-+  TORCH_CHECK(hidden_scales.sizes() == at::IntArrayRef({rows, 1}),
-+              "hidden_scales shape mismatch");
-+  TORCH_CHECK(gate_up_out.sizes() == at::IntArrayRef({rows, 2 * inter}),
-+              "gate_up_out shape mismatch");
-+  TORCH_CHECK(act_q.sizes() == at::IntArrayRef({rows, inter}),
-+              "act_q shape mismatch");
-+  TORCH_CHECK(act_scales.sizes() == at::IntArrayRef({rows, 1}),
-+              "act_scales shape mismatch");
-+  TORCH_CHECK(down_out.sizes() == at::IntArrayRef({rows, hidden}),
-+              "down_out shape mismatch");
-+  TORCH_CHECK(output.sizes() == at::IntArrayRef({rows, hidden}),
-+              "output shape mismatch");
-+
-+  per_token_quant_int8_xpu_out(hidden_states, hidden_q, hidden_scales);
-+  int8_gemm_w8a8_out(hidden_q,
-+                     hidden_scales,
-+                     gate_up_w,
-+                     gate_up_w_scales,
-+                     gate_up_out,
-+                     std::nullopt);
-+  silu_and_mul_quant_int8_xpu_out(gate_up_out, act_q, act_scales);
-+  int8_gemm_w8a8_out(
-+      act_q, act_scales, down_w, down_w_scales, down_out, std::nullopt);
-+
-+  if (qwen36_shared_expert_fused_gate_mul_enabled()) {
-+    qwen36_shared_expert_gate_mul_out(
-+        hidden_states, expert_gate_w, down_out, output);
-+  } else {
-+    auto gate = expert_gate_col_major
-+        ? at::matmul(hidden_states, expert_gate_w)
-+        : at::matmul(hidden_states, expert_gate_w.t());
-+    output.copy_(at::sigmoid(gate) * down_out);
-+  }
-+  return output;
-+}
-diff --git a/csrc/xpu/onednn/onednn_matmul.cpp b/csrc/xpu/onednn/onednn_matmul.cpp
-index cfb3f9a..5f5b2b4 100644
---- a/csrc/xpu/onednn/onednn_matmul.cpp
-+++ b/csrc/xpu/onednn/onednn_matmul.cpp
-@@ -188,3 +188,31 @@ torch::Tensor int8_gemm_w8a8(
-   oneDNN::dnnl_matmul_w8a8_int8(result, A, A_scale, B, B_scale, is_nt, bias_);
-   return result;
- }
-+
-+torch::Tensor int8_gemm_w8a8_out(
-+    const torch::Tensor& A,
-+    const torch::Tensor& A_scale,
-+    const torch::Tensor& B,
-+    const torch::Tensor& B_scale,
-+    torch::Tensor& output,
-+    const std::optional<torch::Tensor>& bias_) {
-+  const at::DeviceGuard device_guard(A.device());
-+  torch::Tensor expected = check_and_create_output_tensor(
-+      A, B, output.scalar_type());
-+  TORCH_CHECK(output.is_xpu(), "int8_gemm_w8a8_out output must be XPU");
-+  TORCH_CHECK(output.is_contiguous(), "int8_gemm_w8a8_out output must be contiguous");
-+  TORCH_CHECK(
-+      output.sizes() == expected.sizes(),
-+      "int8_gemm_w8a8_out output shape mismatch: expected ",
-+      expected.sizes(),
-+      " got ",
-+      output.sizes());
-+  TORCH_CHECK(
-+      output.scalar_type() == torch::kFloat16 ||
-+          output.scalar_type() == torch::kBFloat16,
-+      "int8_gemm_w8a8_out output must be float16 or bfloat16");
-+  bool is_nt = B.strides()[B.dim() - 2] == 1;
-+  oneDNN::dnnl_matmul_w8a8_int8(
-+      output, A, A_scale, B, B_scale, is_nt, bias_);
-+  return output;
-+}
-diff --git a/csrc/xpu/ops.h b/csrc/xpu/ops.h
-index 5df3126..c7cfb97 100644
---- a/csrc/xpu/ops.h
-+++ b/csrc/xpu/ops.h
-@@ -60,6 +60,14 @@ torch::Tensor int8_gemm_w8a8(
-     std::optional<c10::ScalarType> out_dtype,
-     const std::optional<torch::Tensor>& bias);
- 
-+torch::Tensor int8_gemm_w8a8_out(
-+    const torch::Tensor& A,
-+    const torch::Tensor& A_scale,
-+    const torch::Tensor& B,
-+    const torch::Tensor& B_scale,
-+    torch::Tensor& output,
-+    const std::optional<torch::Tensor>& bias);
-+
- std::tuple<torch::Tensor, torch::Tensor> per_token_quant_int8_xpu(
-     const torch::Tensor& x);
- 
-@@ -156,6 +164,11 @@ torch::Tensor qwen36_rows_per_expert_offsets_int64_out(
-     torch::Tensor rows_per_expert,
-     torch::Tensor offsets);
- 
-+torch::Tensor qwen36_topk_ids_to_active_expert_ids_int32_out(
-+    torch::Tensor topk_ids,
-+    torch::Tensor active_expert_ids,
-+    int64_t topk);
-+
- torch::Tensor qwen36_moe_w8a8_middle_layerlet(
-     torch::Tensor gemm1_a,
-     torch::Tensor gemm1_a_scales,
-@@ -175,6 +188,46 @@ torch::Tensor qwen36_moe_w8a8_middle_layerlet(
-     int64_t gemm2_n,
-     int64_t gemm2_k,
-     int64_t num_experts);
-+
-+torch::Tensor qwen36_moe_w8a8_full_layerlet(
-+    torch::Tensor hidden_states,
-+    torch::Tensor topk_ids,
-+    torch::Tensor topk_weights,
-+    torch::Tensor workspace,
-+    torch::Tensor remapped_hidden_states,
-+    torch::Tensor unpermuted_row_to_permuted_row,
-+    torch::Tensor expert_first_token_offset,
-+    torch::Tensor gemm1_a,
-+    torch::Tensor gemm1_a_scales,
-+    torch::Tensor w13,
-+    torch::Tensor w13_scales,
-+    const c10::optional<at::Tensor>& w13_bias,
-+    torch::Tensor gemm1_output,
-+    torch::Tensor gemm2_a,
-+    torch::Tensor gemm2_a_scales,
-+    torch::Tensor w2,
-+    torch::Tensor w2_scales,
-+    const c10::optional<at::Tensor>& w2_bias,
-+    torch::Tensor gemm2_output,
-+    torch::Tensor output,
-+    int64_t hidden_size,
-+    int64_t inter_size,
-+    int64_t num_experts);
-+
-+torch::Tensor qwen36_shared_expert_w8a8_out(
-+    const torch::Tensor& hidden_states,
-+    torch::Tensor& hidden_q,
-+    torch::Tensor& hidden_scales,
-+    const torch::Tensor& gate_up_w,
-+    const torch::Tensor& gate_up_w_scales,
-+    torch::Tensor& gate_up_out,
-+    torch::Tensor& act_q,
-+    torch::Tensor& act_scales,
-+    const torch::Tensor& down_w,
-+    const torch::Tensor& down_w_scales,
-+    torch::Tensor& down_out,
-+    const torch::Tensor& expert_gate_w,
-+    torch::Tensor& output);
- #endif
- 
- std::tuple<at::Tensor, at::Tensor> deepseek_scaling_rope(
-diff --git a/csrc/xpu/torch_bindings.cpp b/csrc/xpu/torch_bindings.cpp
-index dfc21de..3c1df6e 100644
---- a/csrc/xpu/torch_bindings.cpp
-+++ b/csrc/xpu/torch_bindings.cpp
-@@ -42,6 +42,11 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, xpu_ops) {
-       "ScalarType? out_dtype, Tensor? bias) -> Tensor");
-   xpu_ops.impl("int8_gemm_w8a8", torch::kXPU, &int8_gemm_w8a8);
- 
-+  xpu_ops.def(
-+      "int8_gemm_w8a8_out(Tensor A, Tensor A_scale, Tensor B, Tensor B_scale, "
-+      "Tensor! output, Tensor? bias) -> Tensor");
-+  xpu_ops.impl("int8_gemm_w8a8_out", torch::kXPU, &int8_gemm_w8a8_out);
-+
-   xpu_ops.def("per_token_quant_int8_xpu(Tensor x) -> (Tensor, Tensor)");
-   xpu_ops.impl("per_token_quant_int8_xpu", torch::kXPU, &per_token_quant_int8_xpu);
- 
-@@ -113,6 +118,17 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, xpu_ops) {
-       torch::kXPU,
-       &cutlass_grouped_gemm_w8a8_int8_active_offsets_interface);
- 
-+  xpu_ops.def(
-+      "cutlass_grouped_gemm_w8a8_int8_topk8_gemm1_interface(Tensor ptr_A, "
-+      "Tensor ptr_A_scales, Tensor ptr_B, Tensor ptr_B_scales, Tensor? "
-+      "ptr_bias, Tensor ptr_D, Tensor topk_ids, Tensor "
-+      "unpermuted_row_to_permuted_row, int N, int K, int num_experts) -> "
-+      "Tensor");
-+  xpu_ops.impl(
-+      "cutlass_grouped_gemm_w8a8_int8_topk8_gemm1_interface",
-+      torch::kXPU,
-+      &cutlass_grouped_gemm_w8a8_int8_topk8_gemm1_interface);
-+
-   xpu_ops.def(
-       "qwen36_moe_onednn_sidecar_probe(Tensor hidden_states, Tensor "
-       "topk_weights, Tensor topk_ids, Tensor w13, Tensor w13_scales, Tensor "
-@@ -135,6 +151,14 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, xpu_ops) {
-       torch::kXPU,
-       &qwen36_rows_per_expert_offsets_int64_out);
- 
-+  xpu_ops.def(
-+      "qwen36_topk_ids_to_active_expert_ids_int32_out(Tensor topk_ids, "
-+      "Tensor! active_expert_ids, int topk) -> Tensor");
-+  xpu_ops.impl(
-+      "qwen36_topk_ids_to_active_expert_ids_int32_out",
-+      torch::kXPU,
-+      &qwen36_topk_ids_to_active_expert_ids_int32_out);
-+
-   xpu_ops.def(
-       "qwen36_moe_w8a8_middle_layerlet(Tensor gemm1_a, Tensor "
-       "gemm1_a_scales, Tensor w13, Tensor w13_scales, Tensor? w13_bias, "
-@@ -146,6 +170,30 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, xpu_ops) {
-       "qwen36_moe_w8a8_middle_layerlet",
-       torch::kXPU,
-       &qwen36_moe_w8a8_middle_layerlet);
-+  xpu_ops.def(
-+      "qwen36_moe_w8a8_full_layerlet(Tensor hidden_states, Tensor topk_ids, "
-+      "Tensor topk_weights, Tensor workspace, Tensor remapped_hidden_states, "
-+      "Tensor unpermuted_row_to_permuted_row, Tensor "
-+      "expert_first_token_offset, Tensor gemm1_a, Tensor gemm1_a_scales, "
-+      "Tensor w13, Tensor w13_scales, Tensor? w13_bias, Tensor gemm1_output, "
-+      "Tensor gemm2_a, Tensor gemm2_a_scales, Tensor w2, Tensor w2_scales, "
-+      "Tensor? w2_bias, Tensor gemm2_output, Tensor output, int hidden_size, "
-+      "int inter_size, int num_experts) -> Tensor");
-+  xpu_ops.impl(
-+      "qwen36_moe_w8a8_full_layerlet",
-+      torch::kXPU,
-+      &qwen36_moe_w8a8_full_layerlet);
-+
-+  xpu_ops.def(
-+      "qwen36_shared_expert_w8a8_out(Tensor hidden_states, Tensor! hidden_q, "
-+      "Tensor! hidden_scales, Tensor gate_up_w, Tensor gate_up_w_scales, "
-+      "Tensor! gate_up_out, Tensor! act_q, Tensor! act_scales, Tensor down_w, "
-+      "Tensor down_w_scales, Tensor! down_out, Tensor expert_gate_w, "
-+      "Tensor! output) -> Tensor");
-+  xpu_ops.impl(
-+      "qwen36_shared_expert_w8a8_out",
-+      torch::kXPU,
-+      &qwen36_shared_expert_w8a8_out);
- #endif
- 
-   xpu_ops.def(
 diff --git a/vllm_xpu_kernels/fused_moe_interface.py b/vllm_xpu_kernels/fused_moe_interface.py
-index b0ed365..2e3ab4a 100755
+index 2e3ab4a..327562f 100755
 --- a/vllm_xpu_kernels/fused_moe_interface.py
 +++ b/vllm_xpu_kernels/fused_moe_interface.py
-@@ -27,6 +27,7 @@ W8A8_OFFSETS_PREFIX_OP_ENV = "VLLM_XPU_W8A8_OFFSETS_PREFIX_OP"
- INT8_FUSED_PROLOGUE_OFFSET_ENV = "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET"
- INT8_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE_ENV = (
-     "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_ALLOW_CAPTURE")
-+INT8_ACTIVE_OFFSET_GEMM_ENV = "VLLM_XPU_INT8_MOE_ACTIVE_OFFSET_GEMM"
- INT8_FUSED_PROLOGUE_OFFSET_SKIP_LAYERS_ENV = (
-     "VLLM_XPU_INT8_MOE_FUSED_PROLOGUE_OFFSET_SKIP_LAYERS")
- INT8_FUSED_PROLOGUE_OFFSET_LAYER_REGEX_ENV = (
-@@ -62,6 +63,7 @@ ONEDNN_SIDECAR_NO_WAIT_ENV = "VLLM_XPU_MOE_ONEDNN_SIDECAR_NO_WAIT"
- ONEDNN_SIDECAR_ALLOW_GRAPH_CAPTURE_ENV = (
+@@ -64,6 +64,10 @@ ONEDNN_SIDECAR_ALLOW_GRAPH_CAPTURE_ENV = (
      "VLLM_XPU_MOE_ONEDNN_SIDECAR_ALLOW_GRAPH_CAPTURE")
  W8A8_MIDDLE_LAYERLET_ENV = "VLLM_XPU_MOE_W8A8_MIDDLE_LAYERLET"
-+W8A8_FULL_LAYERLET_ENV = "VLLM_XPU_MOE_W8A8_FULL_LAYERLET"
+ W8A8_FULL_LAYERLET_ENV = "VLLM_XPU_MOE_W8A8_FULL_LAYERLET"
++W8A8_FULL_LAYERLET_GATE_TRACE_ENV = (
++    "VLLM_XPU_MOE_W8A8_FULL_LAYERLET_GATE_TRACE_FILE")
++W8A8_FULL_LAYERLET_GATE_TRACE_MAX_LINES_ENV = (
++    "VLLM_XPU_MOE_W8A8_FULL_LAYERLET_GATE_TRACE_MAX_LINES")
  
  _live_abi_lock = threading.Lock()
  _live_abi_writes = 0
-@@ -895,6 +897,17 @@ def _should_use_int8_fused_prologue_offset(diagnostic_context=None):
-                         "cutlass_grouped_gemm_w8a8_int8_offsets_interface"))
+@@ -76,6 +80,8 @@ _sidecar_probe_writes = 0
+ _sidecar_reference_parity_calls = 0
+ _sidecar_probe_disabled = False
+ _sidecar_probe_warned = False
++_full_layerlet_gate_lock = threading.Lock()
++_full_layerlet_gate_writes = 0
  
  
-+def _should_use_int8_active_offset_gemm():
-+    return (_is_env_enabled(INT8_ACTIVE_OFFSET_GEMM_ENV)
-+            and FUSEDMOE_AVAILABLE
-+            and hasattr(
-+                torch.ops._xpu_C,
-+                "cutlass_grouped_gemm_w8a8_int8_active_offsets_interface")
-+            and hasattr(
-+                torch.ops._xpu_C,
-+                "qwen36_topk_ids_to_active_expert_ids_int32_out"))
-+
-+
- def _should_use_w8a8_middle_layerlet():
-     return (_is_env_enabled(W8A8_MIDDLE_LAYERLET_ENV)
-             and FUSEDMOE_AVAILABLE
-@@ -902,6 +915,12 @@ def _should_use_w8a8_middle_layerlet():
-                         "qwen36_moe_w8a8_middle_layerlet"))
+ try:
+@@ -938,6 +944,29 @@ def _maybe_log_sidecar_probe(record):
+         return
  
  
-+def _should_use_w8a8_full_layerlet():
-+    return (_is_env_enabled(W8A8_FULL_LAYERLET_ENV)
-+            and FUSEDMOE_AVAILABLE
-+            and hasattr(torch.ops._xpu_C, "qwen36_moe_w8a8_full_layerlet"))
-+
++def _maybe_log_full_layerlet_gate(record):
++    global _full_layerlet_gate_writes
 +
- def _maybe_log_sidecar_probe(record):
-     global _sidecar_probe_writes
- 
-@@ -1239,6 +1258,21 @@ if FUSEDMOE_AVAILABLE:
-     except RuntimeError:
-         pass
- 
++    path = os.environ.get(W8A8_FULL_LAYERLET_GATE_TRACE_ENV)
++    if not path:
++        return
++    max_lines = max(0, _int_env(W8A8_FULL_LAYERLET_GATE_TRACE_MAX_LINES_ENV,
++                                256))
++    if max_lines == 0:
++        return
 +    try:
-+
-+        @torch.library.register_fake("_xpu_C::qwen36_moe_w8a8_full_layerlet")
-+        def _fake_qwen36_moe_w8a8_full_layerlet(
-+                hidden_states, topk_ids, topk_weights, workspace,
-+                remapped_hidden_states, unpermuted_row_to_permuted_row,
-+                expert_first_token_offset, gemm1_a, gemm1_a_scales, w13,
-+                w13_scales, w13_bias, gemm1_output, gemm2_a,
-+                gemm2_a_scales, w2, w2_scales, w2_bias, gemm2_output, output,
-+                hidden_size, inter_size, num_experts):
-+            return output
-+
-+    except RuntimeError:
-+        pass
-+
-     try:
- 
-         @torch.library.register_fake("_xpu_C::silu_and_mul_quant_int8_xpu")
-@@ -1355,6 +1389,57 @@ def _w8a8_middle_layerlet_out(*,
-     )
- 
- 
-+def _w8a8_full_layerlet_out(*,
-+                            hidden_states,
-+                            topk_ids,
-+                            topk_weights,
-+                            workspace,
-+                            remapped_hidden_states,
-+                            unpermuted_row_to_permuted_row,
-+                            expert_first_token_offset,
-+                            gemm1_a,
-+                            gemm1_a_scales,
-+                            w13,
-+                            w13_scales,
-+                            w13_bias,
-+                            gemm1_output,
-+                            gemm2_a,
-+                            gemm2_a_scales,
-+                            w2,
-+                            w2_scales,
-+                            w2_bias,
-+                            gemm2_output,
-+                            output,
-+                            hidden_size,
-+                            inter_size,
-+                            num_experts):
-+    return torch.ops._xpu_C.qwen36_moe_w8a8_full_layerlet(
-+        hidden_states,
-+        topk_ids,
-+        topk_weights,
-+        workspace,
-+        remapped_hidden_states,
-+        unpermuted_row_to_permuted_row,
-+        expert_first_token_offset,
-+        gemm1_a,
-+        gemm1_a_scales,
-+        w13,
-+        w13_scales,
-+        w13_bias,
-+        gemm1_output,
-+        gemm2_a,
-+        gemm2_a_scales,
-+        w2,
-+        w2_scales,
-+        w2_bias,
-+        gemm2_output,
-+        output,
-+        hidden_size,
-+        inter_size,
-+        num_experts,
-+    )
-+
-+
- def _normalize_int8_weight_scales(scales, out_features):
-     scales = scales.squeeze(-1) if scales is not None and scales.dim() == 3 else scales
-     if scales is None:
-@@ -2039,6 +2124,11 @@ def xpu_fused_moe(hidden_states,
-         and int8_scratch.get("prologue_workspace") is not None
-         and int8_scratch.get("w8a8_offsets") is not None
-         and _should_use_int8_fused_prologue_offset(diagnostic_context))
-+    use_int8_active_offset_gemm = (
-+        use_int8_fused_prologue_offset
-+        and _should_use_int8_active_offset_gemm()
-+        and int8_scratch.get("active_expert_ids") is not None
-+        and int8_scratch["active_expert_ids"].numel() >= n_experts_per_token)
- 
-     if int8_scratch is None:
-         remapped_hidden_states = torch.empty(
-@@ -2058,6 +2148,49 @@ def xpu_fused_moe(hidden_states,
++        line = json.dumps(record, sort_keys=True)
++        with _full_layerlet_gate_lock:
++            if _full_layerlet_gate_writes >= max_lines:
++                return
++            os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
++            with open(path, "a", encoding="utf-8") as handle:
++                handle.write(line + "\n")
++            _full_layerlet_gate_writes += 1
++    except Exception:
++        return
++
++
+ def _maybe_probe_onednn_sidecar(*,
+                                 hidden_states,
+                                 w13,
+@@ -2148,6 +2177,9 @@ def xpu_fused_moe(hidden_states,
          unpermuted_row_to_permuted_row = int8_scratch[
              "unpermuted_row_to_permuted_row"]
  
-+    use_w8a8_full_layerlet = (
-+        is_int8 and activation == "silu" and num_rows == 1
-+        and expert_map is None and ep_size == 1 and int8_scratch is not None
-+        and int8_scratch.get("prologue_workspace") is not None
-+        and int8_scratch.get("w8a8_offsets") is not None
-+        and int8_scratch.get("gemm1_a") is not None
-+        and int8_scratch.get("gemm1_a_scales") is not None
-+        and int8_scratch.get("gemm2_a") is not None
-+        and int8_scratch.get("gemm2_a_scales") is not None
-+        and int8_scratch.get("gemm2_output") is not None
-+        and _should_use_int8_fused_prologue_offset(diagnostic_context)
-+        and _should_use_w8a8_full_layerlet())
-+    if use_w8a8_full_layerlet:
-+        with timed_region("xpu_moe.w8a8_full_layerlet"):
-+            _w8a8_full_layerlet_out(
-+                hidden_states=hidden_states,
-+                topk_ids=topk_ids,
-+                topk_weights=topk_weights,
-+                workspace=int8_scratch["prologue_workspace"],
-+                remapped_hidden_states=remapped_hidden_states,
-+                unpermuted_row_to_permuted_row=unpermuted_row_to_permuted_row,
-+                expert_first_token_offset=int8_scratch["w8a8_offsets"],
-+                gemm1_a=int8_scratch["gemm1_a"],
-+                gemm1_a_scales=int8_scratch["gemm1_a_scales"],
-+                w13=w13,
-+                w13_scales=_normalize_int8_weight_scales(
-+                    gemm1_scales, 2 * inter_size),
-+                w13_bias=w13_bias,
-+                gemm1_output=gemm1_output,
-+                gemm2_a=int8_scratch["gemm2_a"],
-+                gemm2_a_scales=int8_scratch["gemm2_a_scales"],
-+                w2=w2,
-+                w2_scales=_normalize_int8_weight_scales(
-+                    gemm2_scales, hidden_size),
-+                w2_bias=w2_bias,
-+                gemm2_output=int8_scratch["gemm2_output"],
-+                output=output,
-+                hidden_size=hidden_size,
-+                inter_size=inter_size,
-+                num_experts=num_experts,
-+            )
-+        return output
-+
-     if use_int8_fused_prologue_offset:
-         with timed_region("xpu_moe.fused_prologue_offset"):
-             torch.ops._moe_C.fused_moe_prologue(
-@@ -2088,8 +2221,18 @@ def xpu_fused_moe(hidden_states,
-                 local_experts_num=local_experts_num)
- 
-     w8a8_grouped_gemm_offsets = None
-+    w8a8_active_expert_ids = None
-+    w8a8_num_active_experts = 0
-     if use_int8_fused_prologue_offset:
-         w8a8_grouped_gemm_offsets = int8_scratch["w8a8_offsets"]
-+        if use_int8_active_offset_gemm:
-+            w8a8_active_expert_ids = int8_scratch["active_expert_ids"]
-+            w8a8_num_active_experts = int(n_experts_per_token)
-+            with timed_region("xpu_moe.active_expert_ids"):
-+                torch.ops._xpu_C.qwen36_topk_ids_to_active_expert_ids_int32_out(
-+                    topk_ids,
-+                    w8a8_active_expert_ids,
-+                    w8a8_num_active_experts)
-         if _live_abi_path() is not None:
-             rows_per_expert.copy_(
-                 (w8a8_grouped_gemm_offsets[1:1 + num_experts] -
-@@ -2286,7 +2429,21 @@ def xpu_fused_moe(hidden_states,
-                 w8a8_middle_layerlet_replaced = True
-         if not gemm1_replaced_with_sidecar and not w8a8_middle_layerlet_replaced:
-             with timed_region("xpu_moe.gemm1_w8a8"):
--                if w8a8_grouped_gemm_offsets is not None:
-+                if w8a8_active_expert_ids is not None:
-+                    torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_active_offsets_interface(
-+                        ptr_A=remapped_hidden_states,
-+                        ptr_A_scales=gemm1_a_scales,
-+                        ptr_B=input_B,
-+                        ptr_B_scales=gemm1_scales,
-+                        ptr_bias=w13_bias,
-+                        ptr_D=gemm1_output,
-+                        expert_first_token_offset=w8a8_grouped_gemm_offsets,
-+                        active_expert_ids=w8a8_active_expert_ids,
-+                        N=2 * inter_size,
-+                        K=hidden_size,
-+                        num_experts=num_experts,
-+                        num_active_experts=w8a8_num_active_experts)
-+                elif w8a8_grouped_gemm_offsets is not None:
-                     torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_offsets_interface(
-                         ptr_A=remapped_hidden_states,
-                         ptr_A_scales=gemm1_a_scales,
-@@ -2499,7 +2656,21 @@ def xpu_fused_moe(hidden_states,
-                         ) is not None)
-         if not gemm2_replaced_with_sidecar and not w8a8_middle_layerlet_replaced:
-             with timed_region("xpu_moe.gemm2_w8a8"):
--                if w8a8_grouped_gemm_offsets is not None:
-+                if w8a8_active_expert_ids is not None:
-+                    torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_active_offsets_interface(
-+                        ptr_A=input_A,
-+                        ptr_A_scales=gemm2_a_scales,
-+                        ptr_B=input_B,
-+                        ptr_B_scales=gemm2_scales,
-+                        ptr_bias=w2_bias,
-+                        ptr_D=gemm2_output,
-+                        expert_first_token_offset=w8a8_grouped_gemm_offsets,
-+                        active_expert_ids=w8a8_active_expert_ids,
-+                        N=hidden_size,
-+                        K=inter_size * inter_size_scale,
-+                        num_experts=num_experts,
-+                        num_active_experts=w8a8_num_active_experts)
-+                elif w8a8_grouped_gemm_offsets is not None:
-                     torch.ops._xpu_C.cutlass_grouped_gemm_w8a8_int8_offsets_interface(
-                         ptr_A=input_A,
-                         ptr_A_scales=gemm2_a_scales,
++    full_layerlet_fused_offset_gate = _should_use_int8_fused_prologue_offset(
++        diagnostic_context)
++    full_layerlet_op_gate = _should_use_w8a8_full_layerlet()
+     use_w8a8_full_layerlet = (
+         is_int8 and activation == "silu" and num_rows == 1
+         and expert_map is None and ep_size == 1 and int8_scratch is not None
+@@ -2158,8 +2190,50 @@ def xpu_fused_moe(hidden_states,
+         and int8_scratch.get("gemm2_a") is not None
+         and int8_scratch.get("gemm2_a_scales") is not None
+         and int8_scratch.get("gemm2_output") is not None
+-        and _should_use_int8_fused_prologue_offset(diagnostic_context)
+-        and _should_use_w8a8_full_layerlet())
++        and full_layerlet_fused_offset_gate
++        and full_layerlet_op_gate)
++    if os.environ.get(W8A8_FULL_LAYERLET_GATE_TRACE_ENV):
++        scratch_keys = []
++        if isinstance(int8_scratch, dict):
++            scratch_keys = sorted(str(key) for key in int8_scratch.keys())
++        _maybe_log_full_layerlet_gate({
++            "event": "w8a8_full_layerlet_gate",
++            "use_w8a8_full_layerlet": bool(use_w8a8_full_layerlet),
++            "is_int8": bool(is_int8),
++            "activation": str(activation),
++            "num_rows": int(num_rows),
++            "hidden_size": int(hidden_size),
++            "n_experts_per_token": int(n_experts_per_token),
++            "expert_map_is_none": expert_map is None,
++            "ep_size": int(ep_size),
++            "has_int8_scratch": int8_scratch is not None,
++            "scratch_keys": scratch_keys,
++            "has_prologue_workspace": (
++                int8_scratch is not None
++                and int8_scratch.get("prologue_workspace") is not None),
++            "has_w8a8_offsets": (
++                int8_scratch is not None
++                and int8_scratch.get("w8a8_offsets") is not None),
++            "has_gemm1_a": (
++                int8_scratch is not None
++                and int8_scratch.get("gemm1_a") is not None),
++            "has_gemm1_a_scales": (
++                int8_scratch is not None
++                and int8_scratch.get("gemm1_a_scales") is not None),
++            "has_gemm2_a": (
++                int8_scratch is not None
++                and int8_scratch.get("gemm2_a") is not None),
++            "has_gemm2_a_scales": (
++                int8_scratch is not None
++                and int8_scratch.get("gemm2_a_scales") is not None),
++            "has_gemm2_output": (
++                int8_scratch is not None
++                and int8_scratch.get("gemm2_output") is not None),
++            "fused_offset_gate": bool(full_layerlet_fused_offset_gate),
++            "full_layerlet_op_gate": bool(full_layerlet_op_gate),
++            "stream_capture_active": _stream_capture_active(),
++            "diagnostic_context": str(diagnostic_context),
++        })
+     if use_w8a8_full_layerlet:
+         with timed_region("xpu_moe.w8a8_full_layerlet"):
+             _w8a8_full_layerlet_out(
