Skip to main content

ferrum_types/
auto_config.rs

1//! Startup auto-configuration and selector decision trace types.
2//!
3//! This is the typed control-plane surface for gradually replacing M3 shell
4//! env bundles with validated model/hardware/workload driven selections.
5
6use crate::{
7    is_sha256_digest, parse_bool_env_value, parse_usize_env_value, AttentionExecutionPolicy,
8    CompiledNativeOperatorIdentity, ExecutionResourceAuthority, RuntimeConfigEffect,
9    RuntimeConfigEntry, RuntimeConfigSnapshot, RuntimeConfigSource,
10    CUDA_NATIVE_ADAPTIVE_V1_MAX_SEQUENCE_TOKENS,
11};
12use serde::{Deserialize, Serialize};
13use std::collections::BTreeMap;
14use thiserror::Error;
15
16pub const M3_QWEN3_30B_A3B_INT4_PRESET: &str = "m3_qwen3_30b_a3b_int4";
17pub const QWEN25_72B_GPTQ_INT4_2X4090_LAYER_SPLIT_PRESET: &str =
18    "qwen25_72b_gptq_int4_2x4090_layer_split";
19const DEFAULT_KV_BLOCK_SIZE_TOKENS: usize = 16;
20const DEFAULT_KV_BLOCKS: usize = 2048;
21const GIB: u64 = 1024 * 1024 * 1024;
22const FA2_NATIVE_MANIFEST_KEY: &str = "FERRUM_FA2_NATIVE_MANIFEST";
23const FA2_NATIVE_ARTIFACT_KEY: &str = "FERRUM_FA2_NATIVE_ARTIFACT";
24const FA2_NATIVE_SOURCE_SHA256_KEY: &str = "FERRUM_FA2_NATIVE_SOURCE_SHA256";
25const FA2_NATIVE_INPUTS_SHA256_KEY: &str = "FERRUM_FA2_NATIVE_INPUTS_SHA256";
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct ModelCapabilities {
29    pub architecture: String,
30    pub quantization: Option<String>,
31    pub moe: Option<MoeCapabilities>,
32    pub max_context_len: Option<usize>,
33    pub num_hidden_layers: Option<usize>,
34    pub head_dim: Option<usize>,
35    pub kv_heads: Option<usize>,
36    pub estimated_weight_bytes: Option<u64>,
37    pub recurrent_state_bytes_per_sequence: Option<u64>,
38    pub supported_dtypes: Vec<String>,
39    pub graph_safe_moe: bool,
40}
41
42impl ModelCapabilities {
43    pub fn unknown() -> Self {
44        Self {
45            architecture: "unknown".to_string(),
46            quantization: None,
47            moe: None,
48            max_context_len: None,
49            num_hidden_layers: None,
50            head_dim: None,
51            kv_heads: None,
52            estimated_weight_bytes: None,
53            recurrent_state_bytes_per_sequence: None,
54            supported_dtypes: vec!["fp16".to_string(), "fp32".to_string()],
55            graph_safe_moe: false,
56        }
57    }
58
59    pub fn qwen3_30b_a3b_gptq_int4() -> Self {
60        Self {
61            architecture: "qwen3_moe".to_string(),
62            quantization: Some("gptq_int4".to_string()),
63            moe: Some(MoeCapabilities {
64                num_experts: 128,
65                experts_per_token: 8,
66                moe_intermediate_size: Some(768),
67            }),
68            max_context_len: Some(40960),
69            num_hidden_layers: Some(48),
70            head_dim: Some(128),
71            kv_heads: Some(4),
72            // Conservative GPTQ int4 weight footprint including quant scales
73            // and loader/runtime overhead. This keeps the RTX 4090 M3 preset
74            // at the historical 2048 KV blocks while still allowing smaller
75            // GPUs to be downgraded before startup allocation.
76            estimated_weight_bytes: Some(18 * GIB),
77            recurrent_state_bytes_per_sequence: None,
78            supported_dtypes: vec!["fp16".to_string()],
79            graph_safe_moe: false,
80        }
81    }
82
83    pub fn qwen25_72b_gptq_int4() -> Self {
84        Self {
85            architecture: "qwen2".to_string(),
86            quantization: Some("gptq_int4".to_string()),
87            moe: None,
88            max_context_len: Some(32_768),
89            num_hidden_layers: Some(80),
90            head_dim: Some(128),
91            kv_heads: Some(8),
92            estimated_weight_bytes: Some(39 * GIB),
93            recurrent_state_bytes_per_sequence: None,
94            supported_dtypes: vec!["fp16".to_string()],
95            graph_safe_moe: false,
96        }
97    }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
101pub struct MoeCapabilities {
102    pub num_experts: usize,
103    pub experts_per_token: usize,
104    pub moe_intermediate_size: Option<usize>,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct HardwareCapabilities {
109    pub backend: String,
110    pub cuda_runtime: Option<String>,
111    pub compute_capability: Option<String>,
112    pub vram_bytes: Option<u64>,
113    pub sm_count: Option<u32>,
114    pub supported_dtypes: Vec<String>,
115    pub supported_kv_dtypes: Vec<String>,
116    pub graph_support: bool,
117    pub compiled_features: CompiledKernelFeatures,
118}
119
120impl HardwareCapabilities {
121    pub fn unknown() -> Self {
122        Self {
123            backend: "unknown".to_string(),
124            cuda_runtime: None,
125            compute_capability: None,
126            vram_bytes: None,
127            sm_count: None,
128            supported_dtypes: vec!["fp16".to_string(), "fp32".to_string()],
129            supported_kv_dtypes: vec!["fp16".to_string()],
130            graph_support: false,
131            compiled_features: CompiledKernelFeatures::default(),
132        }
133    }
134
135    pub fn rtx4090_cuda(features: CompiledKernelFeatures) -> Self {
136        Self {
137            backend: "cuda".to_string(),
138            cuda_runtime: None,
139            compute_capability: Some("8.9".to_string()),
140            vram_bytes: Some(24 * 1024 * 1024 * 1024),
141            sm_count: Some(128),
142            supported_dtypes: vec!["fp16".to_string(), "fp32".to_string()],
143            supported_kv_dtypes: vec!["fp16".to_string(), "int8".to_string()],
144            graph_support: true,
145            compiled_features: features,
146        }
147    }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
151pub struct CompiledNativeOperatorArtifact {
152    pub manifest_path: String,
153    pub artifact_path: String,
154    pub source_package_sha256: String,
155    pub inputs_sha256: String,
156    pub binary_sha256: String,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
160pub struct CompiledKernelFeatures {
161    pub cuda: bool,
162    pub vllm_paged_attn: bool,
163    pub vllm_moe_marlin: bool,
164    pub cuda_graph: bool,
165    pub greedy_argmax: bool,
166    pub fa2_source: bool,
167    pub fa2_direct_ffi: bool,
168    pub fa2_native_operator_artifact: bool,
169    #[serde(default, skip_serializing_if = "Option::is_none")]
170    pub fa2_native_operator_artifact_metadata: Option<CompiledNativeOperatorArtifact>,
171    #[serde(default, skip_serializing_if = "Vec::is_empty")]
172    pub native_operator_artifacts: Vec<CompiledNativeOperatorIdentity>,
173}
174
175impl Default for CompiledKernelFeatures {
176    fn default() -> Self {
177        Self {
178            cuda: false,
179            vllm_paged_attn: false,
180            vllm_moe_marlin: false,
181            cuda_graph: false,
182            greedy_argmax: false,
183            fa2_source: false,
184            fa2_direct_ffi: false,
185            fa2_native_operator_artifact: false,
186            fa2_native_operator_artifact_metadata: None,
187            native_operator_artifacts: Vec::new(),
188        }
189    }
190}
191
192impl CompiledKernelFeatures {
193    pub fn m3_fast_path_without_fa2() -> Self {
194        Self {
195            cuda: true,
196            vllm_paged_attn: true,
197            vllm_moe_marlin: true,
198            cuda_graph: true,
199            greedy_argmax: true,
200            fa2_source: false,
201            fa2_direct_ffi: false,
202            fa2_native_operator_artifact: false,
203            fa2_native_operator_artifact_metadata: None,
204            native_operator_artifacts: Vec::new(),
205        }
206    }
207
208    pub fn m3_fast_path_with_source_fa2() -> Self {
209        Self {
210            fa2_source: true,
211            ..Self::m3_fast_path_without_fa2()
212        }
213    }
214
215    pub fn m3_fast_path_with_native_fa2_artifact() -> Self {
216        Self {
217            fa2_native_operator_artifact: true,
218            fa2_native_operator_artifact_metadata: Some(CompiledNativeOperatorArtifact {
219                manifest_path: "/tmp/native/fa2/native_operator_manifest.json".to_string(),
220                artifact_path: "/tmp/native/fa2/libferrum_native_fa2.a".to_string(),
221                source_package_sha256:
222                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_string(),
223                inputs_sha256: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
224                    .to_string(),
225                binary_sha256: "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
226                    .to_string(),
227            }),
228            ..Self::m3_fast_path_without_fa2()
229        }
230    }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
234pub struct WorkloadProfile {
235    pub preset: Option<String>,
236    pub serving_mode: String,
237    pub target_concurrency: usize,
238    pub prompt_length_class: String,
239    pub output_length_class: String,
240    pub priority: WorkloadPriority,
241}
242
243impl WorkloadProfile {
244    pub fn serving_default() -> Self {
245        Self {
246            preset: None,
247            serving_mode: "openai_chat".to_string(),
248            target_concurrency: 1,
249            prompt_length_class: "unknown".to_string(),
250            output_length_class: "unknown".to_string(),
251            priority: WorkloadPriority::Balanced,
252        }
253    }
254
255    pub fn serving_default_for_hardware(hardware: &HardwareCapabilities) -> Self {
256        let mut profile = Self::serving_default();
257        if hardware.backend.eq_ignore_ascii_case("cuda")
258            || hardware.backend.eq_ignore_ascii_case("metal")
259        {
260            profile.target_concurrency = hardware
261                .vram_bytes
262                .map(vram_default_max_sequences)
263                .unwrap_or(4)
264                .max(1);
265        }
266        profile
267    }
268
269    pub fn m3_qwen3_30b_a3b_int4() -> Self {
270        Self {
271            preset: Some(M3_QWEN3_30B_A3B_INT4_PRESET.to_string()),
272            serving_mode: "bench_serve".to_string(),
273            target_concurrency: 32,
274            prompt_length_class: "random_256".to_string(),
275            output_length_class: "random_128".to_string(),
276            priority: WorkloadPriority::Throughput,
277        }
278    }
279
280    pub fn qwen25_72b_gptq_int4_2x4090_layer_split() -> Self {
281        Self {
282            preset: Some(QWEN25_72B_GPTQ_INT4_2X4090_LAYER_SPLIT_PRESET.to_string()),
283            serving_mode: "bench_serve".to_string(),
284            target_concurrency: 16,
285            prompt_length_class: "random_256".to_string(),
286            output_length_class: "random_128".to_string(),
287            priority: WorkloadPriority::Throughput,
288        }
289    }
290
291    fn is_m3_preset(&self) -> bool {
292        self.is_preset(M3_QWEN3_30B_A3B_INT4_PRESET)
293    }
294
295    fn is_preset(&self, preset: &str) -> bool {
296        self.preset.as_deref() == Some(preset)
297    }
298}
299
300impl Default for WorkloadProfile {
301    fn default() -> Self {
302        Self::serving_default()
303    }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
307#[serde(rename_all = "snake_case")]
308pub enum WorkloadPriority {
309    Latency,
310    Throughput,
311    Balanced,
312}
313
314#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
315pub struct ResolvedFerrumConfig {
316    pub schema_version: u32,
317    pub preset: Option<String>,
318    #[serde(default)]
319    pub execution_resource_authority: ExecutionResourceAuthority,
320    #[serde(default)]
321    pub requested_attention_policy: Option<AttentionExecutionPolicy>,
322    #[serde(default)]
323    pub compiled_attention_policy: Option<AttentionExecutionPolicy>,
324    pub runtime_config: RuntimeConfigSnapshot,
325    pub model_capabilities: ModelCapabilities,
326    pub hardware_capabilities: HardwareCapabilities,
327    pub workload_profile: WorkloadProfile,
328    pub decisions: Vec<AutoConfigDecision>,
329    #[serde(default, skip_serializing_if = "Option::is_none")]
330    pub startup_memory_plan: Option<crate::StartupMemoryPlan>,
331}
332
333impl ResolvedFerrumConfig {
334    /// Publish the same selected limits that the compiled executor and engine
335    /// use. Preserve explicit provenance; only inferred values become memory
336    /// profile decisions.
337    pub fn apply_startup_memory_plan(&mut self, plan: &crate::StartupMemoryPlan) {
338        for (key, selection, value) in [
339            (
340                "FERRUM_MAX_MODEL_LEN",
341                "max_model_len",
342                plan.selected.context_tokens as u64,
343            ),
344            (
345                "FERRUM_PAGED_MAX_SEQS",
346                "max_sequences",
347                plan.selected.max_sequences as u64,
348            ),
349            (
350                "FERRUM_MAX_BATCHED_TOKENS",
351                "max_batched_tokens",
352                plan.selected.max_batch_tokens as u64,
353            ),
354            (
355                "FERRUM_RUNTIME_MEMORY_BUDGET_BYTES",
356                "runtime_memory_budget_bytes",
357                plan.request.usable_capacity_bytes,
358            ),
359        ] {
360            let source = self
361                .runtime_config
362                .entries
363                .iter()
364                .find(|entry| entry.key == key)
365                .map(|entry| entry.source)
366                .filter(|source| {
367                    matches!(
368                        source,
369                        RuntimeConfigSource::Cli
370                            | RuntimeConfigSource::Env
371                            | RuntimeConfigSource::ConfigFile
372                            | RuntimeConfigSource::ScriptCase
373                    )
374                })
375                .unwrap_or(RuntimeConfigSource::MemoryProfile);
376            self.runtime_config.upsert(key, value.to_string(), source);
377            self.decisions
378                .retain(|decision| decision.selection != selection);
379            self.decisions.push(AutoConfigDecision {
380                schema_version: 1,
381                selection: selection.to_owned(),
382                selected: value.to_string(),
383                source: auto_config_source_from_runtime(source),
384                source_key: Some(key.to_owned()),
385                candidates: vec![value.to_string()],
386                rejected: Vec::new(),
387                affects: vec![
388                    RuntimeConfigEffect::Memory,
389                    RuntimeConfigEffect::Performance,
390                ],
391            });
392        }
393        self.startup_memory_plan = Some(plan.clone());
394    }
395
396    pub fn effective_config_document(&self) -> serde_json::Value {
397        let backend = self.hardware_capabilities.backend.clone();
398        let requested_gpu_devices = self
399            .runtime_csv_usize("FERRUM_REQUESTED_GPU_DEVICES")
400            .or_else(|| default_gpu_devices_for_backend(&backend));
401        let selected_gpu_devices = self
402            .runtime_csv_usize("FERRUM_SELECTED_GPU_DEVICES")
403            .or_else(|| requested_gpu_devices.clone())
404            .or_else(|| default_gpu_devices_for_backend(&backend));
405        let cuda_device_count = self
406            .runtime_usize("FERRUM_CUDA_DEVICE_COUNT")
407            .or_else(|| {
408                backend.eq_ignore_ascii_case("cuda").then(|| {
409                    selected_gpu_devices
410                        .as_ref()
411                        .map(|devices| devices.len())
412                        .unwrap_or(1)
413                })
414            })
415            .unwrap_or(0);
416        let selected_distributed_strategy = self
417            .runtime_entry_value("FERRUM_SELECTED_DISTRIBUTED_STRATEGY")
418            .unwrap_or_else(|| {
419                if selected_gpu_devices
420                    .as_ref()
421                    .map(|devices| devices.len() > 1)
422                    .unwrap_or(false)
423                {
424                    "layer_split".to_string()
425                } else if backend.eq_ignore_ascii_case("cuda") {
426                    "single_gpu".to_string()
427                } else {
428                    "none".to_string()
429                }
430            });
431        let selected_layer_split_plan =
432            self.runtime_entry_value("FERRUM_SELECTED_LAYER_SPLIT_PLAN");
433        let selected_layer_split_stages =
434            self.runtime_json_value("FERRUM_SELECTED_LAYER_SPLIT_STAGES");
435        let selected_layer_split_stage_count = selected_layer_split_stages
436            .as_ref()
437            .and_then(|value| value.as_array().map(|stages| stages.len()))
438            .or_else(|| {
439                selected_layer_split_plan
440                    .as_ref()
441                    .and_then(|_| selected_gpu_devices.as_ref().map(Vec::len))
442            });
443        let requested_pipeline_mode = self.runtime_entry_value("FERRUM_LAYER_SPLIT_PIPELINE_MODE");
444        let selected_pipeline_mode = if selected_layer_split_plan.is_some() {
445            requested_pipeline_mode.unwrap_or_else(|| {
446                if selected_layer_split_stage_count == Some(2) {
447                    "overlapped".to_string()
448                } else {
449                    "batch".to_string()
450                }
451            })
452        } else {
453            "sequential".to_string()
454        };
455        let selected_max_sequences = self.selected_usize("max_sequences");
456        let selected_microbatch_size = if selected_layer_split_plan.is_some() {
457            selected_max_sequences.map(|max_sequences| {
458                if selected_pipeline_mode == "overlapped" {
459                    max_sequences.div_ceil(2).max(1)
460                } else {
461                    max_sequences
462                }
463            })
464        } else {
465            Some(1)
466        };
467        let selected_stage_bridge = selected_layer_split_plan.as_ref().map(|_| "host");
468        let selected_max_model_len = self.selected_usize("max_model_len");
469        let selected_kv_capacity = self.runtime_usize("FERRUM_KV_CAPACITY");
470        let selected_max_batched_tokens = self.selected_usize("max_batched_tokens");
471        let selected_recurrent_state_max_slots = self.selected_recurrent_state_max_slots();
472        let selected_admission_limit = effective_admission_limit(
473            self.execution_resource_authority,
474            selected_max_sequences,
475            selected_recurrent_state_max_slots,
476        );
477        let selected_attention_policy = self.selected_string("attention_execution_policy");
478        let selected_attention_impl = self.selected_string("attention_decode_backend");
479        serde_json::json!({
480            "schema_version": 1,
481            "preset": self.preset,
482            "env_hash": self.runtime_env_hash(),
483            "backend": backend.clone(),
484            "execution_resource_authority": self.execution_resource_authority,
485            "startup_memory_plan": self.startup_memory_plan,
486            "requested_gpu_devices": requested_gpu_devices.clone(),
487            "selected_gpu_devices": selected_gpu_devices.clone(),
488            "cuda_device_count": cuda_device_count,
489            "selected_distributed_strategy": selected_distributed_strategy.clone(),
490            "selected_layer_split_plan": selected_layer_split_plan.clone(),
491            "selected_layer_split_stages": selected_layer_split_stages,
492            "selected_pipeline_mode": selected_pipeline_mode,
493            "selected_microbatch_size": selected_microbatch_size,
494            "selected_stage_bridge": selected_stage_bridge,
495            "selected_weight_placement": if selected_layer_split_plan.is_some() { "layer_split" } else { "single_device" },
496            "selected_kv_layout": if backend.eq_ignore_ascii_case("cpu") { "contiguous" } else { "paged" },
497            "selected_attention_impl": selected_attention_impl,
498            "selected_attention_policy": selected_attention_policy,
499            "attention_execution": self.attention_execution_document(),
500            "selected_graph_mode": self.selected_graph_mode(),
501            "selected_max_sequences": selected_max_sequences,
502            "selected_max_model_len": selected_max_model_len,
503            "selected_kv_capacity": selected_kv_capacity,
504            "selected_kv_capacity_source": "configured_token_limit",
505            "selected_max_batched_tokens": selected_max_batched_tokens,
506            "selected_recurrent_state_max_slots": selected_recurrent_state_max_slots,
507            "selected_admission_limit": selected_admission_limit,
508            "entries": self.runtime_config.entries,
509            "model_capabilities": self.model_capabilities,
510            "hardware_capabilities": self.hardware_capabilities,
511            "workload_profile": self.workload_profile,
512            "admission": self.admission_summary_document(),
513            "decisions": self.decisions,
514        })
515    }
516
517    pub fn admission_summary_document(&self) -> serde_json::Value {
518        let max_sequences = self.selected_usize("max_sequences");
519        let recurrent_state_max_slots = self.selected_recurrent_state_max_slots();
520        let effective_max_concurrent = effective_admission_limit(
521            self.execution_resource_authority,
522            max_sequences,
523            recurrent_state_max_slots,
524        );
525        let kv_blocks = self.selected_usize("kv_block_count");
526        let max_batched_tokens = self.selected_usize("max_batched_tokens");
527        let max_model_len = self.selected_usize("max_model_len");
528        let kv_capacity_tokens =
529            kv_blocks.map(|blocks| blocks.saturating_mul(DEFAULT_KV_BLOCK_SIZE_TOKENS));
530        let kv_bytes_per_token = kv_cache_bytes_per_token_for_model(&self.model_capabilities);
531        let recurrent_budget =
532            recurrent_state_budget_for(&self.model_capabilities, &self.hardware_capabilities);
533        let scheduler_policy = self
534            .selected_string("scheduler_admission_policy")
535            .unwrap_or_else(|| "unknown".to_string());
536        let memory_estimate = serde_json::json!({
537            "source": "legacy_f16_geometry_estimate",
538            "applies_to_selected_state_layout": false,
539            "is_resident_usage": false,
540            "selected_state_evidence_source": if self.execution_resource_authority == ExecutionResourceAuthority::PlanRuntime { "executor.kv_storage.logical_sequence_state" } else { "legacy_runtime" },
541            "vram_bytes": self.hardware_capabilities.vram_bytes,
542            "estimated_weight_bytes": self.model_capabilities.estimated_weight_bytes,
543            "kv_bytes_per_token": kv_bytes_per_token,
544            "recurrent_state_bytes_per_sequence": self.model_capabilities.recurrent_state_bytes_per_sequence,
545            "recurrent_state_budget_bytes": recurrent_budget.map(|budget| budget.remaining_bytes),
546            "recurrent_state_budget_raw_slots": recurrent_budget.map(|budget| budget.raw_slots),
547            "recurrent_state_budget_max_slots": recurrent_budget.map(|budget| budget.floored_slots),
548            "recurrent_state_capacity_bytes": match (recurrent_state_max_slots, self.model_capabilities.recurrent_state_bytes_per_sequence) {
549                (Some(slots), Some(bytes_per_sequence)) => {
550                    (slots as u64).checked_mul(bytes_per_sequence)
551                }
552                _ => None,
553            },
554            "kv_capacity_bytes": match (kv_capacity_tokens, kv_bytes_per_token) {
555                (Some(tokens), Some(bytes_per_token)) => {
556                    (tokens as u64).checked_mul(bytes_per_token)
557                }
558                _ => None,
559            },
560        });
561        serde_json::json!({
562            "schema_version": 1,
563            "backend": self.hardware_capabilities.backend,
564            "model_architecture": self.model_capabilities.architecture,
565            "resource_authority": self.execution_resource_authority,
566            "source": "startup_preflight",
567            "scheduler_policy": scheduler_policy,
568            "effective_max_concurrent": effective_max_concurrent,
569            "maximum_active_sequences": max_sequences,
570            "maximum_scheduled_tokens": max_batched_tokens,
571            "queue_depth": 0u64,
572            "active_prefill": 0u64,
573            "active_decode": 0u64,
574            "current_batch_size": 0u64,
575            "rejected_requests_total": 0u64,
576            "failed_requests_total": 0u64,
577            "completed_requests_total": 0u64,
578            "max_sequences": max_sequences,
579            "recurrent_state_max_slots": if self.execution_resource_authority == ExecutionResourceAuthority::LegacyEngine {
580                recurrent_state_max_slots
581            } else {
582                None
583            },
584            "legacy_recurrent_state_max_slots_estimate": recurrent_state_max_slots,
585            "legacy_recurrent_state_limit_applies": self.execution_resource_authority == ExecutionResourceAuthority::LegacyEngine,
586            "kv_capacity_source": "legacy_block_preflight_estimate",
587            "kv_capacity_applies_to_selected_state_layout": self.execution_resource_authority == ExecutionResourceAuthority::LegacyEngine,
588            "kv_capacity_is_resident_usage": false,
589            "kv_block_count": kv_blocks,
590            "kv_block_size_tokens": DEFAULT_KV_BLOCK_SIZE_TOKENS,
591            "kv_capacity_tokens": kv_capacity_tokens,
592            "max_model_length": max_model_len,
593            "max_batched_tokens": max_batched_tokens,
594            "memory_estimate": memory_estimate,
595        })
596    }
597
598    pub fn decision_trace_jsonl(&self) -> Result<String, serde_json::Error> {
599        let mut out = String::new();
600        for decision in &self.decisions {
601            out.push_str(&serde_json::to_string(decision)?);
602            out.push('\n');
603        }
604        Ok(out)
605    }
606
607    pub fn runtime_env_hash(&self) -> String {
608        use sha2::{Digest, Sha256};
609
610        let bytes = serde_json::to_vec(&self.runtime_config.entries).unwrap_or_default();
611        let digest = Sha256::digest(bytes);
612        format!("sha256:{digest:x}")
613    }
614
615    fn selected_usize(&self, selection: &str) -> Option<usize> {
616        self.selected_string(selection)?.parse().ok()
617    }
618
619    fn selected_string(&self, selection: &str) -> Option<String> {
620        self.decisions
621            .iter()
622            .find(|decision| decision.selection == selection)
623            .map(|decision| decision.selected.clone())
624    }
625
626    fn selected_recurrent_state_max_slots(&self) -> Option<usize> {
627        self.selected_usize("recurrent_state_max_slots")
628            .or_else(|| self.runtime_usize("FERRUM_RECURRENT_STATE_MAX_SLOTS"))
629    }
630
631    fn selected_graph_mode(&self) -> Option<String> {
632        let decode_graph = self.selected_string("decode_graph_policy");
633        if decode_graph
634            .as_deref()
635            .is_some_and(|mode| mode != "graph_disabled")
636        {
637            return decode_graph;
638        }
639        self.selected_string("moe_graph_policy")
640    }
641
642    fn attention_execution_document(&self) -> serde_json::Value {
643        let compiled_policy = self
644            .compiled_attention_policy
645            .map(AttentionExecutionPolicy::as_runtime_value);
646        let requested_policy = self
647            .requested_attention_policy
648            .map(AttentionExecutionPolicy::as_runtime_value);
649        if self.execution_resource_authority != ExecutionResourceAuthority::PlanRuntime {
650            return serde_json::json!({
651                "schema_version": 1,
652                "resource_authority": self.execution_resource_authority,
653                "requested_policy": null,
654                "compiled_policy": null,
655                "selection_scope": "legacy_runtime",
656                "observed_variant_source": "legacy_backend_profile",
657                "legacy_attention_keys_apply": true,
658            });
659        }
660        let native_adaptive =
661            compiled_policy == Some(AttentionExecutionPolicy::NativeAdaptive.as_runtime_value());
662        serde_json::json!({
663            "schema_version": 1,
664            "resource_authority": self.execution_resource_authority,
665            "requested_policy": requested_policy,
666            "compiled_policy": compiled_policy,
667            "selection_scope": "per_invocation",
668            "observed_variant_source": "vnext.device_native_work",
669            "legacy_attention_keys_apply": false,
670            "decode": if native_adaptive && self.hardware_capabilities.backend.eq_ignore_ascii_case("cuda") {
671                serde_json::json!({
672                    "selector": "sequence_frontier",
673                    "short_variant": "vllm_paged_attention_v1_addressed",
674                    "long_variant": "vllm_paged_attention_v2_addressed",
675                    "short_max_sequence_tokens": CUDA_NATIVE_ADAPTIVE_V1_MAX_SEQUENCE_TOKENS,
676                })
677            } else {
678                serde_json::json!({
679                    "selector": "compiled_provider",
680                })
681            },
682            "prefill": {
683                "selector": "admitted_shape",
684                "variants_are_observed_at_runtime": true,
685            },
686        })
687    }
688
689    fn runtime_entry_value(&self, key: &str) -> Option<String> {
690        self.runtime_config
691            .entries
692            .iter()
693            .find(|entry| entry.key == key)
694            .map(|entry| entry.effective_value.clone())
695    }
696
697    fn runtime_usize(&self, key: &str) -> Option<usize> {
698        self.runtime_entry_value(key)?.parse().ok()
699    }
700
701    fn runtime_csv_usize(&self, key: &str) -> Option<Vec<usize>> {
702        let raw = self.runtime_entry_value(key)?;
703        let mut out = Vec::new();
704        for part in raw.split(',') {
705            let value = part.trim();
706            if value.is_empty() {
707                return None;
708            }
709            out.push(value.parse().ok()?);
710        }
711        Some(out)
712    }
713
714    fn runtime_json_value(&self, key: &str) -> Option<serde_json::Value> {
715        serde_json::from_str(&self.runtime_entry_value(key)?).ok()
716    }
717}
718
719#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
720pub struct AutoConfigDecision {
721    pub schema_version: u32,
722    pub selection: String,
723    pub selected: String,
724    pub source: AutoConfigSource,
725    pub source_key: Option<String>,
726    pub candidates: Vec<String>,
727    pub rejected: Vec<RejectedCandidate>,
728    pub affects: Vec<RuntimeConfigEffect>,
729}
730
731#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
732pub struct RejectedCandidate {
733    pub value: String,
734    pub reason: String,
735}
736
737#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
738#[serde(rename_all = "snake_case")]
739pub enum AutoConfigSource {
740    Default,
741    Cli,
742    ConfigFile,
743    Env,
744    ScriptCase,
745    ModelMetadata,
746    HardwareCapability,
747    MemoryProfile,
748    WorkloadPreset,
749    CompiledFeature,
750}
751
752#[derive(Debug, Clone, PartialEq, Eq, Error)]
753pub enum AutoConfigError {
754    #[error("{key}: invalid override: {reason}")]
755    InvalidOverride { key: String, reason: String },
756    #[error("{selection}: unsupported combination: {reason}")]
757    UnsupportedCombination { selection: String, reason: String },
758}
759
760pub struct FerrumConfigBuilder {
761    runtime_config: RuntimeConfigSnapshot,
762    model: ModelCapabilities,
763    hardware: HardwareCapabilities,
764    workload: WorkloadProfile,
765    execution_resource_authority: ExecutionResourceAuthority,
766}
767
768impl FerrumConfigBuilder {
769    pub fn new(runtime_config: RuntimeConfigSnapshot) -> Self {
770        Self {
771            runtime_config,
772            model: ModelCapabilities::unknown(),
773            hardware: HardwareCapabilities::unknown(),
774            workload: WorkloadProfile::default(),
775            execution_resource_authority: ExecutionResourceAuthority::LegacyEngine,
776        }
777    }
778
779    pub fn m3_qwen3_30b_a3b_int4(runtime_config: RuntimeConfigSnapshot) -> Self {
780        Self::new(runtime_config)
781            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
782            .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(
783                CompiledKernelFeatures::m3_fast_path_without_fa2(),
784            ))
785            .with_workload_profile(WorkloadProfile::m3_qwen3_30b_a3b_int4())
786    }
787
788    pub fn with_model_capabilities(mut self, model: ModelCapabilities) -> Self {
789        self.model = model;
790        self
791    }
792
793    pub fn with_hardware_capabilities(mut self, hardware: HardwareCapabilities) -> Self {
794        self.hardware = hardware;
795        self
796    }
797
798    pub fn with_workload_profile(mut self, workload: WorkloadProfile) -> Self {
799        self.workload = workload;
800        self
801    }
802
803    pub fn with_execution_resource_authority(
804        mut self,
805        authority: ExecutionResourceAuthority,
806    ) -> Self {
807        self.execution_resource_authority = authority;
808        self
809    }
810
811    pub fn resolve(self) -> Result<ResolvedFerrumConfig, AutoConfigError> {
812        let mut decisions = Vec::new();
813        let cuda_backend = self.is_cuda_backend();
814        let plan_runtime =
815            self.execution_resource_authority == ExecutionResourceAuthority::PlanRuntime;
816        if plan_runtime {
817            for key in [
818                "FERRUM_USE_VLLM_PAGED_ATTN",
819                "FERRUM_VLLM_PAGED_ATTN_V1_SHORT",
820            ] {
821                if self.entry(key).is_some() {
822                    return Err(AutoConfigError::InvalidOverride {
823                        key: key.to_owned(),
824                        reason: format!(
825                            "legacy attention control does not apply to PlanRuntime; use FERRUM_ATTENTION_POLICY=auto|portable|native-adaptive"
826                        ),
827                    });
828                }
829            }
830        }
831        let plan_attention = plan_runtime
832            .then(|| self.resolve_plan_attention_policy())
833            .transpose()?;
834        // Any CUDA GPTQ/INT4 MoE model gets the vLLM-Marlin fast MoE path when
835        // the kernel is compiled — not only the m3 bench preset. `ferrum run`
836        // resolves with the serving-default workload (not the m3 preset), so
837        // without this it silently fell back to the slow host-route MoE
838        // (~9.7 vs ~59 tok/s on a 4090 for Qwen3-30B-A3B). Capability-gated,
839        // never model-name-gated.
840        let cuda_gptq_moe = cuda_backend
841            && self.model.moe.is_some()
842            && self.model.quantization.as_deref().is_some_and(|q| {
843                let q = q.to_ascii_lowercase();
844                q.contains("gptq") || q.contains("int4")
845            });
846        let cuda_qwen_moe = cuda_backend
847            && self.model.moe.is_some()
848            && qwen_moe_architecture_uses_vllm_paged_attn(&self.model.architecture);
849        let use_vllm_paged_attn = self.bool_value(
850            "FERRUM_USE_VLLM_PAGED_ATTN",
851            (self.workload.is_m3_preset() || cuda_qwen_moe)
852                && cuda_backend
853                && self.hardware.compiled_features.vllm_paged_attn,
854            AutoConfigSource::WorkloadPreset,
855        )?;
856        let fa_layout =
857            self.bool_value("FERRUM_FA_LAYOUT_VARLEN", false, AutoConfigSource::Default)?;
858        let fa2_source = self.bool_value("FERRUM_FA2_SOURCE", false, AutoConfigSource::Default)?;
859        let shim_present = self.raw("FERRUM_FA2_DIRECT_FFI_SHIM").is_some();
860        let fa2_direct_ffi = self.bool_value(
861            "FERRUM_FA2_DIRECT_FFI",
862            shim_present,
863            if shim_present {
864                AutoConfigSource::Env
865            } else {
866                AutoConfigSource::Default
867            },
868        )?;
869        let fa2_native_manifest = self.optional_string_value(FA2_NATIVE_MANIFEST_KEY)?;
870        let fa2_native_artifact = self.optional_string_value(FA2_NATIVE_ARTIFACT_KEY)?;
871        let fa2_native_source_sha256 = self.optional_string_value(FA2_NATIVE_SOURCE_SHA256_KEY)?;
872        let fa2_native_inputs_sha256 = self.optional_string_value(FA2_NATIVE_INPUTS_SHA256_KEY)?;
873        let vllm_v1_short = self.bool_value(
874            "FERRUM_VLLM_PAGED_ATTN_V1_SHORT",
875            use_vllm_paged_attn.value && self.model.head_dim.unwrap_or(128) <= 128,
876            AutoConfigSource::Default,
877        )?;
878        let vllm_moe = self.bool_value(
879            "FERRUM_VLLM_MOE",
880            (cuda_gptq_moe || (self.workload.is_m3_preset() && cuda_backend))
881                && self.hardware.compiled_features.vllm_moe_marlin,
882            AutoConfigSource::WorkloadPreset,
883        )?;
884        let device_route = self.bool_value(
885            "FERRUM_MOE_DEVICE_ROUTE",
886            vllm_moe.value,
887            AutoConfigSource::WorkloadPreset,
888        )?;
889        let pair_ids = self.bool_value(
890            "FERRUM_VLLM_MOE_PAIR_IDS",
891            vllm_moe.value,
892            AutoConfigSource::WorkloadPreset,
893        )?;
894        let graph = self.bool_value("FERRUM_MOE_GRAPH", false, AutoConfigSource::WorkloadPreset)?;
895        let batched_graph =
896            self.bool_value("FERRUM_BATCHED_GRAPH", false, AutoConfigSource::Default)?;
897        let reusable_execution = self.bool_value(
898            "FERRUM_REUSABLE_EXECUTION",
899            cuda_backend
900                && self.hardware.graph_support
901                && self.hardware.compiled_features.cuda_graph,
902            AutoConfigSource::HardwareCapability,
903        )?;
904        let unified_graph =
905            self.bool_value("FERRUM_UNIFIED_GRAPH", false, AutoConfigSource::Default)?;
906        let unified_graph_layers_only = self.bool_value(
907            "FERRUM_UNIFIED_GRAPH_LAYERS_ONLY",
908            false,
909            AutoConfigSource::Default,
910        )?;
911        let unified_graph_lm_head_eager = self.bool_value(
912            "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER",
913            false,
914            AutoConfigSource::Default,
915        )?;
916        let greedy = self.bool_value(
917            "FERRUM_GREEDY_ARGMAX",
918            (cuda_backend || self.hardware.backend.eq_ignore_ascii_case("metal"))
919                && self.hardware.compiled_features.greedy_argmax,
920            AutoConfigSource::HardwareCapability,
921        )?;
922        let prefix_cache = self.bool_value(
923            "FERRUM_PREFIX_CACHE",
924            false,
925            if self.workload.is_m3_preset() {
926                AutoConfigSource::WorkloadPreset
927            } else {
928                AutoConfigSource::Default
929            },
930        )?;
931        let default_max_sequences = self.default_max_sequences();
932        let mut max_sequences = self.usize_value(
933            "FERRUM_PAGED_MAX_SEQS",
934            default_max_sequences.value,
935            default_max_sequences.source,
936        )?;
937        if plan_runtime
938            && !matches!(
939                max_sequences.source,
940                AutoConfigSource::Cli
941                    | AutoConfigSource::Env
942                    | AutoConfigSource::ConfigFile
943                    | AutoConfigSource::ScriptCase
944            )
945        {
946            if let Some(batch) = self.optional_usize_value("FERRUM_MAX_BATCHED_TOKENS")? {
947                // A configured batch bounds automatic decode width. Explicit
948                // concurrency still reaches validation unchanged.
949                max_sequences.value = max_sequences.value.min(batch.value.max(1));
950            }
951        }
952        if plan_runtime && self.entry("FERRUM_RECURRENT_STATE_MAX_SLOTS").is_some() {
953            return self.invalid(
954                "FERRUM_RECURRENT_STATE_MAX_SLOTS",
955                "legacy engine recurrent-state slots do not control the plan runtime; use max sequences as the protocol ceiling and let dynamic resource admission defer on live capacity",
956            );
957        }
958        let default_recurrent_state_max_slots = (!plan_runtime)
959            .then(|| self.default_recurrent_state_max_slots(&max_sequences))
960            .flatten();
961        let recurrent_state_max_slots = if default_recurrent_state_max_slots.is_some()
962            || self.entry("FERRUM_RECURRENT_STATE_MAX_SLOTS").is_some()
963        {
964            let default = default_recurrent_state_max_slots
965                .as_ref()
966                .unwrap_or(&max_sequences);
967            Some(self.usize_value(
968                "FERRUM_RECURRENT_STATE_MAX_SLOTS",
969                default.value,
970                default.source,
971            )?)
972        } else {
973            None
974        };
975        let default_kv_blocks = self.default_kv_blocks(&max_sequences);
976        let kv_blocks = self.usize_value(
977            "FERRUM_KV_MAX_BLOCKS",
978            default_kv_blocks.value,
979            default_kv_blocks.source,
980        )?;
981        let default_max_batched_tokens =
982            self.default_max_batched_tokens(&max_sequences, &kv_blocks);
983        let max_batched_tokens = self.usize_value(
984            "FERRUM_MAX_BATCHED_TOKENS",
985            default_max_batched_tokens.value,
986            default_max_batched_tokens.source,
987        )?;
988        let max_model_len = self
989            .optional_usize_value("FERRUM_MAX_MODEL_LEN")?
990            .or_else(|| {
991                plan_runtime
992                    .then_some(self.model.max_context_len)
993                    .flatten()
994                    .map(|value| ResolvedValue {
995                        value,
996                        source: AutoConfigSource::ModelMetadata,
997                        source_key: None,
998                    })
999            });
1000        let default_prefill_first_until_active =
1001            self.default_prefill_first_until_active(&max_sequences);
1002        let default_active_decode_prefill_chunk =
1003            self.default_active_decode_prefill_chunk(&max_sequences);
1004        if !plan_runtime {
1005            self.validate_attention(
1006                use_vllm_paged_attn.value,
1007                fa_layout.value,
1008                fa2_source.value,
1009                fa2_direct_ffi.value,
1010                shim_present,
1011                vllm_v1_short.value,
1012            )?;
1013            self.validate_fa2_native_artifact(
1014                fa2_native_manifest.as_ref(),
1015                fa2_native_artifact.as_ref(),
1016                fa2_native_source_sha256.as_ref(),
1017                fa2_native_inputs_sha256.as_ref(),
1018                fa2_source.value,
1019                fa2_direct_ffi.value,
1020            )?;
1021        }
1022        self.validate_moe(
1023            vllm_moe.value,
1024            device_route.value,
1025            pair_ids.value,
1026            graph.value,
1027        )?;
1028        self.validate_batched_graph(batched_graph.value)?;
1029        self.validate_unified_graph(
1030            unified_graph.value,
1031            unified_graph_layers_only.value,
1032            unified_graph_lm_head_eager.value,
1033        )?;
1034        self.validate_memory(
1035            kv_blocks.value,
1036            max_sequences.value,
1037            recurrent_state_max_slots.as_ref().map(|slots| slots.value),
1038            max_batched_tokens.value,
1039            max_model_len.as_ref().map(|value| value.value),
1040        )?;
1041        self.validate_dtypes()?;
1042        self.validate_layer_split_pipeline_mode()?;
1043        self.validate_sampling(greedy.value)?;
1044
1045        if let Some((_, compiled_attention)) = plan_attention.as_ref() {
1046            decisions.push(self.plan_attention_execution_decision(compiled_attention));
1047            decisions.push(self.plan_attention_phase_decision(
1048                "attention_prefill_mixed_backend",
1049                compiled_attention,
1050            ));
1051            decisions.push(
1052                self.plan_attention_phase_decision("attention_decode_backend", compiled_attention),
1053            );
1054        } else {
1055            decisions.push(self.attention_prefill_decision(
1056                use_vllm_paged_attn.clone(),
1057                fa_layout,
1058                fa2_source,
1059                fa2_direct_ffi,
1060            ));
1061            decisions.push(self.fa2_native_artifact_decision(
1062                fa2_native_manifest.as_ref(),
1063                fa2_native_artifact.as_ref(),
1064            ));
1065            decisions.push(self.fa2_native_runtime_selection_decision(
1066                fa2_native_manifest.as_ref(),
1067                fa2_native_artifact.as_ref(),
1068            ));
1069            decisions.push(
1070                self.attention_decode_decision(use_vllm_paged_attn.clone(), vllm_v1_short.clone()),
1071            );
1072        }
1073        // Materialize the auto-resolved fast-path MoE knobs into the effective
1074        // config BEFORE moe_decision consumes them, so they reach the model
1075        // (which reads FERRUM_*, not the decisions). Only auto-derived values —
1076        // user/env entries are already present. Without this, `ferrum run`'s
1077        // non-preset path resolved FERRUM_VLLM_MOE as a decision only and the
1078        // model never saw it (~9.7 vs ~59 tok/s on a 4090 for Qwen3-30B-A3B).
1079        let mut runtime_config = self.runtime_config.clone();
1080        // Native resource selection is one typed decision. A diagnostic-only
1081        // decision must never leave the engine running a different default.
1082        if plan_runtime {
1083            for (key, resolved) in [
1084                ("FERRUM_PAGED_MAX_SEQS", Some(&max_sequences)),
1085                ("FERRUM_MAX_BATCHED_TOKENS", Some(&max_batched_tokens)),
1086                ("FERRUM_MAX_MODEL_LEN", max_model_len.as_ref()),
1087            ] {
1088                if let Some(resolved) = resolved {
1089                    let value = resolved.value.to_string();
1090                    if self
1091                        .entry(key)
1092                        .is_none_or(|entry| entry.effective_value != value)
1093                    {
1094                        runtime_config.upsert(
1095                            key,
1096                            value,
1097                            if let Some(entry) = self.entry(key) {
1098                                entry.source
1099                            } else if resolved.source == AutoConfigSource::HardwareCapability {
1100                                RuntimeConfigSource::MemoryProfile
1101                            } else {
1102                                RuntimeConfigSource::Default
1103                            },
1104                        );
1105                    }
1106                }
1107            }
1108        }
1109        let legacy_attention_values = [
1110            ("FERRUM_USE_VLLM_PAGED_ATTN", &use_vllm_paged_attn),
1111            ("FERRUM_VLLM_PAGED_ATTN_V1_SHORT", &vllm_v1_short),
1112        ];
1113        for (key, resolved) in legacy_attention_values
1114            .into_iter()
1115            .filter(|_| !plan_runtime)
1116            .chain([
1117                ("FERRUM_VLLM_MOE", &vllm_moe),
1118                ("FERRUM_MOE_DEVICE_ROUTE", &device_route),
1119                ("FERRUM_VLLM_MOE_PAIR_IDS", &pair_ids),
1120                ("FERRUM_BATCHED_GRAPH", &batched_graph),
1121                ("FERRUM_REUSABLE_EXECUTION", &reusable_execution),
1122                ("FERRUM_UNIFIED_GRAPH", &unified_graph),
1123                (
1124                    "FERRUM_UNIFIED_GRAPH_LAYERS_ONLY",
1125                    &unified_graph_layers_only,
1126                ),
1127                (
1128                    "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER",
1129                    &unified_graph_lm_head_eager,
1130                ),
1131                ("FERRUM_GREEDY_ARGMAX", &greedy),
1132            ])
1133        {
1134            if self.entry(key).is_none() {
1135                runtime_config.upsert(
1136                    key,
1137                    if resolved.value { "1" } else { "0" },
1138                    RuntimeConfigSource::MemoryProfile,
1139                );
1140            }
1141        }
1142        if self.entry("FERRUM_ATTENTION_POLICY").is_none() {
1143            if let Some((_, compiled_attention)) = plan_attention.as_ref() {
1144                runtime_config.upsert(
1145                    "FERRUM_ATTENTION_POLICY",
1146                    compiled_attention.value.as_runtime_value(),
1147                    RuntimeConfigSource::Default,
1148                );
1149            }
1150        }
1151        if let Some(until) = default_prefill_first_until_active.as_ref() {
1152            if self
1153                .entry("FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE")
1154                .is_none()
1155                && self.entry("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE").is_none()
1156            {
1157                runtime_config.upsert(
1158                    "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE",
1159                    until.value.to_string(),
1160                    RuntimeConfigSource::Default,
1161                );
1162            }
1163        }
1164        if let Some(chunk) = default_active_decode_prefill_chunk.as_ref() {
1165            if self.entry("FERRUM_ACTIVE_DECODE_PREFILL_CHUNK").is_none() {
1166                runtime_config.upsert(
1167                    "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK",
1168                    chunk.value.to_string(),
1169                    RuntimeConfigSource::Default,
1170                );
1171            }
1172        }
1173        if let Some(slots) = recurrent_state_max_slots.as_ref() {
1174            if self.entry("FERRUM_RECURRENT_STATE_MAX_SLOTS").is_none() {
1175                runtime_config.upsert(
1176                    "FERRUM_RECURRENT_STATE_MAX_SLOTS",
1177                    slots.value.to_string(),
1178                    RuntimeConfigSource::MemoryProfile,
1179                );
1180            }
1181        }
1182        decisions.push(self.moe_decision(vllm_moe, device_route, pair_ids));
1183        decisions.push(self.graph_decision(graph));
1184        decisions.push(self.reusable_execution_decision(reusable_execution));
1185        decisions.push(self.decode_graph_decision(
1186            batched_graph,
1187            unified_graph,
1188            unified_graph_layers_only,
1189            unified_graph_lm_head_eager,
1190        ));
1191        decisions.push(self.scalar_decision(
1192            "kv_block_count",
1193            kv_blocks,
1194            RuntimeConfigEffect::Memory,
1195        ));
1196        decisions.push(self.scalar_decision(
1197            "max_sequences",
1198            max_sequences,
1199            RuntimeConfigEffect::Memory,
1200        ));
1201        if let Some(slots) = recurrent_state_max_slots {
1202            decisions.push(self.scalar_decision(
1203                "recurrent_state_max_slots",
1204                slots,
1205                RuntimeConfigEffect::Memory,
1206            ));
1207        }
1208        decisions.push(self.scalar_decision(
1209            "max_batched_tokens",
1210            max_batched_tokens,
1211            RuntimeConfigEffect::Performance,
1212        ));
1213        if let Some(max_model_len) = max_model_len {
1214            decisions.push(self.scalar_decision(
1215                "max_model_len",
1216                max_model_len,
1217                RuntimeConfigEffect::Memory,
1218            ));
1219        }
1220        decisions.push(self.prefix_cache_decision(prefix_cache));
1221        decisions.push(self.scheduler_decision(
1222            default_prefill_first_until_active,
1223            default_active_decode_prefill_chunk,
1224        )?);
1225        decisions.push(self.sampling_decision(greedy));
1226
1227        Ok(ResolvedFerrumConfig {
1228            schema_version: 1,
1229            preset: self.workload.preset.clone(),
1230            execution_resource_authority: self.execution_resource_authority,
1231            requested_attention_policy: plan_attention
1232                .as_ref()
1233                .map(|(requested, _)| requested.value),
1234            compiled_attention_policy: plan_attention.as_ref().map(|(_, compiled)| compiled.value),
1235            runtime_config,
1236            model_capabilities: self.model.clone(),
1237            hardware_capabilities: self.hardware.clone(),
1238            workload_profile: self.workload.clone(),
1239            decisions,
1240            startup_memory_plan: None,
1241        })
1242    }
1243
1244    fn entries(&self) -> BTreeMap<&str, &str> {
1245        self.runtime_config
1246            .entries
1247            .iter()
1248            .map(|entry| (entry.key.as_str(), entry.effective_value.as_str()))
1249            .collect()
1250    }
1251
1252    fn raw(&self, key: &str) -> Option<&str> {
1253        self.entry(key).map(|entry| entry.effective_value.as_str())
1254    }
1255
1256    fn entry(&self, key: &str) -> Option<&RuntimeConfigEntry> {
1257        self.runtime_config
1258            .entries
1259            .iter()
1260            .find(|entry| entry.key == key)
1261    }
1262
1263    fn source_for_key(&self, key: &str, default_source: AutoConfigSource) -> AutoConfigSource {
1264        self.entry(key)
1265            .map(|entry| auto_config_source_from_runtime(entry.source))
1266            .unwrap_or(default_source)
1267    }
1268
1269    fn is_cuda_backend(&self) -> bool {
1270        self.hardware.backend.eq_ignore_ascii_case("cuda")
1271    }
1272
1273    fn is_accelerator_backend(&self) -> bool {
1274        self.is_cuda_backend() || self.hardware.backend.eq_ignore_ascii_case("metal")
1275    }
1276
1277    fn cuda_compute_capability_at_least(&self, major: u32, minor: u32) -> Option<bool> {
1278        let (actual_major, actual_minor) =
1279            parse_compute_capability(self.hardware.compute_capability.as_deref()?)?;
1280        Some((actual_major, actual_minor) >= (major, minor))
1281    }
1282
1283    fn default_max_sequences(&self) -> ResolvedValue<usize> {
1284        let target = self.workload.target_concurrency.max(1);
1285        let mut selected = target;
1286        if self.workload.is_m3_preset() {
1287            if let Some(sm_count) = self.hardware.sm_count {
1288                // The M3 throughput preset assumes a large GPU. On smaller
1289                // known GPUs, avoid auto-selecting a c32-sized admission
1290                // window before memory profiling has a chance to refine KV.
1291                selected = selected.min((sm_count as usize / 4).max(1));
1292            }
1293            if let Some(vram_bytes) = self.hardware.vram_bytes {
1294                selected = selected.min(vram_default_max_sequences(vram_bytes));
1295            }
1296        }
1297        ResolvedValue {
1298            value: selected.max(1),
1299            source: if selected < target {
1300                AutoConfigSource::HardwareCapability
1301            } else {
1302                AutoConfigSource::WorkloadPreset
1303            },
1304            source_key: None,
1305        }
1306    }
1307
1308    fn default_max_batched_tokens(
1309        &self,
1310        max_sequences: &ResolvedValue<usize>,
1311        kv_blocks: &ResolvedValue<usize>,
1312    ) -> ResolvedValue<usize> {
1313        let kv_token_capacity = kv_blocks
1314            .value
1315            .saturating_mul(DEFAULT_KV_BLOCK_SIZE_TOKENS)
1316            .max(max_sequences.value.max(1));
1317        let target = if self
1318            .workload
1319            .is_preset(QWEN25_72B_GPTQ_INT4_2X4090_LAYER_SPLIT_PRESET)
1320        {
1321            1536
1322        } else {
1323            max_sequences.value.max(1).saturating_mul(64)
1324        };
1325        // PlanRuntime admits exact typed states and workspace against its
1326        // device budget. Legacy block estimates do not cap its token work.
1327        let value = if self.execution_resource_authority == ExecutionResourceAuthority::PlanRuntime
1328        {
1329            target
1330        } else {
1331            target.min(kv_token_capacity)
1332        }
1333        .max(max_sequences.value.max(1));
1334        ResolvedValue {
1335            value,
1336            source: if max_sequences.source == AutoConfigSource::HardwareCapability
1337                || kv_blocks.source == AutoConfigSource::HardwareCapability
1338            {
1339                AutoConfigSource::HardwareCapability
1340            } else {
1341                AutoConfigSource::WorkloadPreset
1342            },
1343            source_key: None,
1344        }
1345    }
1346
1347    fn default_prefill_first_until_active(
1348        &self,
1349        max_sequences: &ResolvedValue<usize>,
1350    ) -> Option<ResolvedValue<usize>> {
1351        if max_sequences.value <= 1 || !self.is_accelerator_backend() {
1352            return None;
1353        }
1354        Some(ResolvedValue {
1355            value: max_sequences.value,
1356            source: AutoConfigSource::Default,
1357            source_key: None,
1358        })
1359    }
1360
1361    fn default_active_decode_prefill_chunk(
1362        &self,
1363        max_sequences: &ResolvedValue<usize>,
1364    ) -> Option<ResolvedValue<usize>> {
1365        if self.execution_resource_authority != ExecutionResourceAuthority::PlanRuntime
1366            || !self.hardware.backend.eq_ignore_ascii_case("metal")
1367            || max_sequences.value <= 1
1368        {
1369            return None;
1370        }
1371        // Bound mixed-prefill work even with only one active decoder. Cold
1372        // prefills keep their elastic token budget; explicit limits still win.
1373        Some(ResolvedValue {
1374            value: 128,
1375            source: AutoConfigSource::Default,
1376            source_key: None,
1377        })
1378    }
1379
1380    fn default_kv_blocks(&self, max_sequences: &ResolvedValue<usize>) -> ResolvedValue<usize> {
1381        let min_blocks = ceil_div(max_sequences.value.max(1), DEFAULT_KV_BLOCK_SIZE_TOKENS);
1382        if self
1383            .workload
1384            .is_preset(QWEN25_72B_GPTQ_INT4_2X4090_LAYER_SPLIT_PRESET)
1385        {
1386            return ResolvedValue {
1387                value: 1024.max(min_blocks),
1388                source: AutoConfigSource::WorkloadPreset,
1389                source_key: None,
1390            };
1391        }
1392        let target = DEFAULT_KV_BLOCKS.max(min_blocks);
1393        let selected = match (
1394            self.hardware.vram_bytes,
1395            self.model.estimated_weight_bytes,
1396            self.kv_cache_bytes_per_token(),
1397        ) {
1398            (Some(vram_bytes), Some(weight_bytes), Some(kv_bytes_per_token))
1399                if kv_bytes_per_token > 0 =>
1400            {
1401                let headroom = (vram_bytes / 10).max(2 * GIB);
1402                let available = vram_bytes.saturating_sub(weight_bytes.saturating_add(headroom));
1403                let kv_token_budget = (available / kv_bytes_per_token) as usize;
1404                let block_budget = kv_token_budget / DEFAULT_KV_BLOCK_SIZE_TOKENS;
1405                target.min(block_budget.max(min_blocks))
1406            }
1407            _ => target,
1408        };
1409        ResolvedValue {
1410            value: selected.max(1),
1411            source: if selected < target {
1412                AutoConfigSource::HardwareCapability
1413            } else {
1414                AutoConfigSource::WorkloadPreset
1415            },
1416            source_key: None,
1417        }
1418    }
1419
1420    fn default_recurrent_state_max_slots(
1421        &self,
1422        max_sequences: &ResolvedValue<usize>,
1423    ) -> Option<ResolvedValue<usize>> {
1424        let limit = self.recurrent_state_budget_max_slots()?;
1425        let selected = max_sequences.value.min(limit.max(1));
1426        Some(ResolvedValue {
1427            value: selected.max(1),
1428            source: if selected < max_sequences.value {
1429                AutoConfigSource::MemoryProfile
1430            } else {
1431                max_sequences.source
1432            },
1433            source_key: None,
1434        })
1435    }
1436
1437    fn recurrent_state_budget_max_slots(&self) -> Option<usize> {
1438        self.recurrent_state_budget()
1439            .map(|budget| budget.floored_slots)
1440    }
1441
1442    fn recurrent_state_budget(&self) -> Option<RecurrentStateBudget> {
1443        recurrent_state_budget_for(&self.model, &self.hardware)
1444    }
1445
1446    fn kv_cache_bytes_per_token(&self) -> Option<u64> {
1447        kv_cache_bytes_per_token_for_model(&self.model)
1448    }
1449
1450    fn bool_value(
1451        &self,
1452        key: &str,
1453        default: bool,
1454        default_source: AutoConfigSource,
1455    ) -> Result<ResolvedValue<bool>, AutoConfigError> {
1456        match self.entry(key) {
1457            Some(entry) => Ok(ResolvedValue {
1458                value: parse_bool_env_value(&entry.effective_value).map_err(|reason| {
1459                    AutoConfigError::InvalidOverride {
1460                        key: key.to_string(),
1461                        reason,
1462                    }
1463                })?,
1464                source: auto_config_source_from_runtime(entry.source),
1465                source_key: Some(key.to_string()),
1466            }),
1467            None => Ok(ResolvedValue {
1468                value: default,
1469                source: default_source,
1470                source_key: None,
1471            }),
1472        }
1473    }
1474
1475    fn usize_value(
1476        &self,
1477        key: &str,
1478        default: usize,
1479        default_source: AutoConfigSource,
1480    ) -> Result<ResolvedValue<usize>, AutoConfigError> {
1481        match self.entry(key) {
1482            Some(entry) => Ok(ResolvedValue {
1483                value: parse_usize_env_value(&entry.effective_value).map_err(|reason| {
1484                    AutoConfigError::InvalidOverride {
1485                        key: key.to_string(),
1486                        reason,
1487                    }
1488                })?,
1489                source: auto_config_source_from_runtime(entry.source),
1490                source_key: Some(key.to_string()),
1491            }),
1492            None => Ok(ResolvedValue {
1493                value: default,
1494                source: default_source,
1495                source_key: None,
1496            }),
1497        }
1498    }
1499
1500    fn optional_usize_value(
1501        &self,
1502        key: &str,
1503    ) -> Result<Option<ResolvedValue<usize>>, AutoConfigError> {
1504        match self.entry(key) {
1505            Some(entry) => Ok(Some(ResolvedValue {
1506                value: parse_usize_env_value(&entry.effective_value).map_err(|reason| {
1507                    AutoConfigError::InvalidOverride {
1508                        key: key.to_string(),
1509                        reason,
1510                    }
1511                })?,
1512                source: auto_config_source_from_runtime(entry.source),
1513                source_key: Some(key.to_string()),
1514            })),
1515            None => Ok(None),
1516        }
1517    }
1518
1519    fn optional_string_value(
1520        &self,
1521        key: &str,
1522    ) -> Result<Option<ResolvedValue<String>>, AutoConfigError> {
1523        match self.entry(key) {
1524            Some(entry) if entry.effective_value.trim().is_empty() => {
1525                Err(AutoConfigError::InvalidOverride {
1526                    key: key.to_string(),
1527                    reason: "must be non-empty".to_string(),
1528                })
1529            }
1530            Some(entry) => Ok(Some(ResolvedValue {
1531                value: entry.effective_value.clone(),
1532                source: auto_config_source_from_runtime(entry.source),
1533                source_key: Some(key.to_string()),
1534            })),
1535            None => Ok(None),
1536        }
1537    }
1538
1539    fn validate_attention(
1540        &self,
1541        use_vllm_paged_attn: bool,
1542        fa_layout: bool,
1543        fa2_source: bool,
1544        fa2_direct_ffi: bool,
1545        shim_present: bool,
1546        vllm_v1_short: bool,
1547    ) -> Result<(), AutoConfigError> {
1548        if use_vllm_paged_attn && !self.hardware.compiled_features.vllm_paged_attn {
1549            return self.invalid(
1550                "FERRUM_USE_VLLM_PAGED_ATTN",
1551                "vLLM paged attention is not compiled",
1552            );
1553        }
1554        if use_vllm_paged_attn && !self.is_cuda_backend() {
1555            return self.invalid(
1556                "FERRUM_USE_VLLM_PAGED_ATTN",
1557                "vLLM paged attention requires CUDA backend",
1558            );
1559        }
1560        if fa_layout && !use_vllm_paged_attn {
1561            return self.invalid(
1562                "FERRUM_FA_LAYOUT_VARLEN",
1563                "FA layout requires vLLM paged attention layout",
1564            );
1565        }
1566        if fa2_source {
1567            return self.invalid(
1568                "FERRUM_FA2_SOURCE",
1569                "source-linked FA2 path has been removed; use a native operator artifact",
1570            );
1571        }
1572        if fa2_direct_ffi && !self.hardware.compiled_features.fa2_direct_ffi {
1573            return self.invalid(
1574                "FERRUM_FA2_DIRECT_FFI",
1575                "direct FA2 FFI shim support is not compiled",
1576            );
1577        }
1578        if fa2_direct_ffi && !self.is_cuda_backend() {
1579            return self.invalid(
1580                "FERRUM_FA2_DIRECT_FFI",
1581                "direct FA2 FFI shim requires CUDA backend",
1582            );
1583        }
1584        if fa2_direct_ffi && self.cuda_compute_capability_at_least(8, 0) == Some(false) {
1585            return self.invalid(
1586                "FERRUM_FA2_DIRECT_FFI",
1587                "direct FA2 FFI shim requires CUDA compute capability >= 8.0",
1588            );
1589        }
1590        if fa2_direct_ffi && !shim_present {
1591            return self.invalid(
1592                "FERRUM_FA2_DIRECT_FFI",
1593                "requires FERRUM_FA2_DIRECT_FFI_SHIM",
1594            );
1595        }
1596        if fa2_source && fa2_direct_ffi {
1597            return self.unsupported(
1598                "attention_prefill_mixed_backend",
1599                "FA2 source and direct FFI shim cannot both own the prefill path",
1600            );
1601        }
1602        if vllm_v1_short && !use_vllm_paged_attn {
1603            return self.invalid(
1604                "FERRUM_VLLM_PAGED_ATTN_V1_SHORT",
1605                "short-context v1 requires vLLM paged attention",
1606            );
1607        }
1608        Ok(())
1609    }
1610
1611    fn validate_fa2_native_artifact(
1612        &self,
1613        manifest: Option<&ResolvedValue<String>>,
1614        artifact: Option<&ResolvedValue<String>>,
1615        source_sha256: Option<&ResolvedValue<String>>,
1616        inputs_sha256: Option<&ResolvedValue<String>>,
1617        fa2_source: bool,
1618        fa2_direct_ffi: bool,
1619    ) -> Result<(), AutoConfigError> {
1620        let configured = manifest.is_some() || artifact.is_some();
1621        if manifest.is_some() != artifact.is_some() {
1622            let key = if manifest.is_none() {
1623                FA2_NATIVE_MANIFEST_KEY
1624            } else {
1625                FA2_NATIVE_ARTIFACT_KEY
1626            };
1627            return self.invalid(
1628                key,
1629                "FA2 native operator manifest and artifact must be configured together",
1630            );
1631        }
1632        for (key, value) in [
1633            (FA2_NATIVE_SOURCE_SHA256_KEY, source_sha256),
1634            (FA2_NATIVE_INPUTS_SHA256_KEY, inputs_sha256),
1635        ] {
1636            if let Some(value) = value {
1637                if !is_sha256_digest(&value.value) {
1638                    return self.invalid(key, "must be a lowercase hex sha256 digest");
1639                }
1640                if !configured {
1641                    return self.invalid(
1642                        key,
1643                        "sha256 pins require FA2 native operator manifest and artifact",
1644                    );
1645                }
1646            }
1647        }
1648        if configured && !self.is_cuda_backend() {
1649            return self.invalid(
1650                FA2_NATIVE_MANIFEST_KEY,
1651                "FA2 native operator artifacts require CUDA backend",
1652            );
1653        }
1654        if configured && !self.hardware.compiled_features.fa2_native_operator_artifact {
1655            return self.invalid(
1656                FA2_NATIVE_MANIFEST_KEY,
1657                "FA2 native operator artifact config requires a binary built with a validated native operator artifact",
1658            );
1659        }
1660        if configured {
1661            let metadata = self
1662                .hardware
1663                .compiled_features
1664                .fa2_native_operator_artifact_metadata
1665                .as_ref()
1666                .ok_or_else(|| AutoConfigError::InvalidOverride {
1667                    key: FA2_NATIVE_MANIFEST_KEY.to_string(),
1668                    reason: "FA2 native operator artifact capability is missing build metadata"
1669                        .to_string(),
1670                })?;
1671            let manifest = manifest.expect("configured manifest is present");
1672            let artifact = artifact.expect("configured artifact is present");
1673            if manifest.value != metadata.manifest_path {
1674                return self.invalid(
1675                    FA2_NATIVE_MANIFEST_KEY,
1676                    "FA2 native operator manifest does not match the artifact linked into this binary",
1677                );
1678            }
1679            if artifact.value != metadata.artifact_path {
1680                return self.invalid(
1681                    FA2_NATIVE_ARTIFACT_KEY,
1682                    "FA2 native operator artifact does not match the artifact linked into this binary",
1683                );
1684            }
1685            if let Some(source_sha256) = source_sha256 {
1686                if source_sha256.value != metadata.source_package_sha256 {
1687                    return self.invalid(
1688                        FA2_NATIVE_SOURCE_SHA256_KEY,
1689                        "FA2 native operator source_package sha256 does not match the artifact linked into this binary",
1690                    );
1691                }
1692            }
1693            if let Some(inputs_sha256) = inputs_sha256 {
1694                if inputs_sha256.value != metadata.inputs_sha256 {
1695                    return self.invalid(
1696                        FA2_NATIVE_INPUTS_SHA256_KEY,
1697                        "FA2 native operator inputs sha256 does not match the artifact linked into this binary",
1698                    );
1699                }
1700            }
1701        }
1702        if configured && fa2_source {
1703            return self.unsupported(
1704                "attention_prefill_mixed_backend",
1705                "FA2 native operator artifact cannot be combined with removed source-linked FA2",
1706            );
1707        }
1708        if configured && fa2_direct_ffi {
1709            return self.unsupported(
1710                "attention_prefill_mixed_backend",
1711                "FA2 native operator artifact and diagnostic direct FFI shim cannot both own the prefill path",
1712            );
1713        }
1714        Ok(())
1715    }
1716
1717    fn validate_moe(
1718        &self,
1719        vllm_moe: bool,
1720        device_route: bool,
1721        pair_ids: bool,
1722        graph: bool,
1723    ) -> Result<(), AutoConfigError> {
1724        if vllm_moe && !self.hardware.compiled_features.vllm_moe_marlin {
1725            return self.invalid("FERRUM_VLLM_MOE", "vLLM Marlin MoE is not compiled");
1726        }
1727        if vllm_moe && !self.is_cuda_backend() {
1728            return self.invalid("FERRUM_VLLM_MOE", "vLLM Marlin MoE requires CUDA backend");
1729        }
1730        if device_route && !vllm_moe {
1731            return self.invalid(
1732                "FERRUM_MOE_DEVICE_ROUTE",
1733                "device route currently requires vLLM MoE",
1734            );
1735        }
1736        if pair_ids && !vllm_moe {
1737            return self.invalid(
1738                "FERRUM_VLLM_MOE_PAIR_IDS",
1739                "pair-id routing requires vLLM MoE",
1740            );
1741        }
1742        let graph_relevant = self.model.moe.is_some() || self.workload.is_m3_preset();
1743        if graph && graph_relevant && !self.hardware.graph_support {
1744            return self.invalid(
1745                "FERRUM_MOE_GRAPH",
1746                "hardware/backend does not support CUDA graph replay",
1747            );
1748        }
1749        if graph && graph_relevant && !self.hardware.compiled_features.cuda_graph {
1750            return self.invalid("FERRUM_MOE_GRAPH", "CUDA graph support is not compiled");
1751        }
1752        if graph && graph_relevant && !vllm_moe {
1753            return self.invalid(
1754                "FERRUM_MOE_GRAPH",
1755                "graph decode requires the graph-clean vLLM MoE path",
1756            );
1757        }
1758        if graph && graph_relevant && self.model.moe.is_some() && !self.model.graph_safe_moe {
1759            return self.unsupported(
1760                "moe_graph_policy",
1761                "model MoE path is not marked graph-safe",
1762            );
1763        }
1764        Ok(())
1765    }
1766
1767    fn validate_batched_graph(&self, graph: bool) -> Result<(), AutoConfigError> {
1768        if !graph {
1769            return Ok(());
1770        }
1771        if self.model.moe.is_some() {
1772            return self.invalid(
1773                "FERRUM_BATCHED_GRAPH",
1774                "legacy batched decode graph does not apply to MoE models",
1775            );
1776        }
1777        if !self.is_cuda_backend() {
1778            return self.invalid(
1779                "FERRUM_BATCHED_GRAPH",
1780                "legacy batched decode graph requires CUDA backend",
1781            );
1782        }
1783        if !self.hardware.graph_support {
1784            return self.invalid(
1785                "FERRUM_BATCHED_GRAPH",
1786                "hardware/backend does not support CUDA graph replay",
1787            );
1788        }
1789        if !self.hardware.compiled_features.cuda_graph {
1790            return self.invalid("FERRUM_BATCHED_GRAPH", "CUDA graph support is not compiled");
1791        }
1792        Ok(())
1793    }
1794
1795    fn validate_unified_graph(
1796        &self,
1797        graph: bool,
1798        layers_only: bool,
1799        lm_head_eager: bool,
1800    ) -> Result<(), AutoConfigError> {
1801        if layers_only && !graph {
1802            return self.invalid(
1803                "FERRUM_UNIFIED_GRAPH_LAYERS_ONLY",
1804                "layers-only unified graph capture requires FERRUM_UNIFIED_GRAPH=1",
1805            );
1806        }
1807        if lm_head_eager && !graph {
1808            return self.invalid(
1809                "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER",
1810                "lm-head-eager unified graph capture requires FERRUM_UNIFIED_GRAPH=1",
1811            );
1812        }
1813        if layers_only && lm_head_eager {
1814            return self.invalid(
1815                "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER",
1816                "lm-head-eager unified graph capture conflicts with layers-only capture",
1817            );
1818        }
1819        if !graph {
1820            return Ok(());
1821        }
1822        if self.model.moe.is_some() {
1823            return self.invalid(
1824                "FERRUM_UNIFIED_GRAPH",
1825                "unified decode graph does not apply to MoE models",
1826            );
1827        }
1828        if self.model.architecture.eq_ignore_ascii_case("gemma3") && !layers_only && !lm_head_eager
1829        {
1830            return self.invalid(
1831                "FERRUM_UNIFIED_GRAPH",
1832                "full unified decode graph is disabled for Gemma3 sandwich-norm models",
1833            );
1834        }
1835        if !self.is_cuda_backend() {
1836            return self.invalid(
1837                "FERRUM_UNIFIED_GRAPH",
1838                "unified decode graph requires CUDA backend",
1839            );
1840        }
1841        if !self.hardware.graph_support {
1842            return self.invalid(
1843                "FERRUM_UNIFIED_GRAPH",
1844                "hardware/backend does not support CUDA graph replay",
1845            );
1846        }
1847        if !self.hardware.compiled_features.cuda_graph {
1848            return self.invalid("FERRUM_UNIFIED_GRAPH", "CUDA graph support is not compiled");
1849        }
1850        Ok(())
1851    }
1852
1853    fn validate_sampling(&self, greedy: bool) -> Result<(), AutoConfigError> {
1854        if greedy && !self.hardware.compiled_features.greedy_argmax {
1855            return self.invalid("FERRUM_GREEDY_ARGMAX", "GPU argmax is not compiled");
1856        }
1857        if greedy
1858            && !(self.is_cuda_backend() || self.hardware.backend.eq_ignore_ascii_case("metal"))
1859        {
1860            return self.invalid(
1861                "FERRUM_GREEDY_ARGMAX",
1862                "greedy argmax requires CUDA or Metal backend",
1863            );
1864        }
1865        Ok(())
1866    }
1867
1868    fn validate_memory(
1869        &self,
1870        kv_blocks: usize,
1871        max_sequences: usize,
1872        recurrent_state_max_slots: Option<usize>,
1873        max_batched_tokens: usize,
1874        requested_max_model_len: Option<usize>,
1875    ) -> Result<(), AutoConfigError> {
1876        if kv_blocks == 0 {
1877            return self.invalid("FERRUM_KV_MAX_BLOCKS", "must be greater than zero");
1878        }
1879        if max_sequences == 0 {
1880            return self.invalid("FERRUM_PAGED_MAX_SEQS", "must be greater than zero");
1881        }
1882        if recurrent_state_max_slots == Some(0) {
1883            return self.invalid(
1884                "FERRUM_RECURRENT_STATE_MAX_SLOTS",
1885                "must be greater than zero",
1886            );
1887        }
1888        if self.execution_resource_authority == ExecutionResourceAuthority::LegacyEngine {
1889            if let Some(limit) = self.recurrent_state_budget_max_slots() {
1890                let recurrent_slots = recurrent_state_max_slots.unwrap_or(max_sequences);
1891                if recurrent_slots > limit {
1892                    let key = if self.entry("FERRUM_RECURRENT_STATE_MAX_SLOTS").is_some() {
1893                        "FERRUM_RECURRENT_STATE_MAX_SLOTS"
1894                    } else {
1895                        "FERRUM_PAGED_MAX_SEQS"
1896                    };
1897                    return Err(AutoConfigError::InvalidOverride {
1898                        key: key.to_string(),
1899                        reason: format!(
1900                            "recurrent-state slot pool exceeds the model/hardware memory budget: slots={recurrent_slots}, budget={limit}; use FERRUM_RECURRENT_STATE_MAX_SLOTS={limit}, lower --max-num-seqs, or a larger-memory GPU."
1901                        ),
1902                    });
1903                }
1904            }
1905        }
1906        if max_batched_tokens < max_sequences {
1907            return self.invalid(
1908                "FERRUM_MAX_BATCHED_TOKENS",
1909                "must be at least FERRUM_PAGED_MAX_SEQS",
1910            );
1911        }
1912        let kv_token_capacity = kv_blocks.saturating_mul(DEFAULT_KV_BLOCK_SIZE_TOKENS);
1913        if self.execution_resource_authority == ExecutionResourceAuthority::LegacyEngine
1914            && max_batched_tokens > kv_token_capacity
1915        {
1916            return self.invalid(
1917                "FERRUM_MAX_BATCHED_TOKENS",
1918                "exceeds KV cache token capacity",
1919            );
1920        }
1921        if let Some(max_model_len) = requested_max_model_len {
1922            if max_model_len == 0 {
1923                return self.invalid("FERRUM_MAX_MODEL_LEN", "must be greater than zero");
1924            }
1925            if let Some(model_max) = self.model.max_context_len {
1926                if max_model_len > model_max {
1927                    return self.invalid(
1928                        "FERRUM_MAX_MODEL_LEN",
1929                        "exceeds model metadata max context length",
1930                    );
1931                }
1932            }
1933            if self.execution_resource_authority == ExecutionResourceAuthority::LegacyEngine
1934                && max_model_len > kv_token_capacity
1935            {
1936                return self.invalid(
1937                    "FERRUM_KV_MAX_BLOCKS",
1938                    "KV cache token capacity is smaller than FERRUM_MAX_MODEL_LEN",
1939                );
1940            }
1941        }
1942        Ok(())
1943    }
1944
1945    fn validate_dtypes(&self) -> Result<(), AutoConfigError> {
1946        if let Some(dtype) = self.raw("FERRUM_DTYPE") {
1947            let dtype = dtype.to_ascii_lowercase();
1948            if !self.hardware.supported_dtypes.iter().any(|d| d == &dtype) {
1949                return self.invalid("FERRUM_DTYPE", "dtype is not supported by hardware profile");
1950            }
1951        }
1952        if let Some(dtype) = self.raw("FERRUM_KV_DTYPE") {
1953            let dtype = dtype.to_ascii_lowercase();
1954            if !self
1955                .hardware
1956                .supported_kv_dtypes
1957                .iter()
1958                .any(|d| d == &dtype)
1959            {
1960                return self.invalid(
1961                    "FERRUM_KV_DTYPE",
1962                    "KV dtype is not supported by hardware profile",
1963                );
1964            }
1965        }
1966        Ok(())
1967    }
1968
1969    fn validate_layer_split_pipeline_mode(&self) -> Result<(), AutoConfigError> {
1970        let Some(mode) = self.raw("FERRUM_LAYER_SPLIT_PIPELINE_MODE") else {
1971            return Ok(());
1972        };
1973        match mode.trim().to_ascii_lowercase().as_str() {
1974            "batch" | "overlapped" => Ok(()),
1975            _ => self.invalid(
1976                "FERRUM_LAYER_SPLIT_PIPELINE_MODE",
1977                "must be batch or overlapped",
1978            ),
1979        }
1980    }
1981
1982    fn resolve_plan_attention_policy(
1983        &self,
1984    ) -> Result<
1985        (
1986            ResolvedValue<AttentionExecutionPolicy>,
1987            ResolvedValue<AttentionExecutionPolicy>,
1988        ),
1989        AutoConfigError,
1990    > {
1991        let requested = match self.entry("FERRUM_ATTENTION_POLICY") {
1992            Some(entry) => ResolvedValue {
1993                value: AttentionExecutionPolicy::parse_runtime_value(&entry.effective_value)
1994                    .map_err(|reason| AutoConfigError::InvalidOverride {
1995                        key: "FERRUM_ATTENTION_POLICY".to_owned(),
1996                        reason,
1997                    })?,
1998                source: auto_config_source_from_runtime(entry.source),
1999                source_key: Some("FERRUM_ATTENTION_POLICY".to_owned()),
2000            },
2001            None => ResolvedValue {
2002                value: AttentionExecutionPolicy::Auto,
2003                source: AutoConfigSource::Default,
2004                source_key: None,
2005            },
2006        };
2007        let kv_dtype = self
2008            .raw("FERRUM_KV_DTYPE")
2009            .map(|raw| {
2010                crate::KvCacheDtype::parse(raw).ok_or_else(|| AutoConfigError::InvalidOverride {
2011                    key: "FERRUM_KV_DTYPE".to_owned(),
2012                    reason: format!("unknown KV dtype {raw}"),
2013                })
2014            })
2015            .transpose()?
2016            .unwrap_or_default();
2017        let kv_storage = crate::KvStorageFormat::try_from(kv_dtype).map_err(|reason| {
2018            AutoConfigError::InvalidOverride {
2019                key: "FERRUM_KV_DTYPE".to_owned(),
2020                reason,
2021            }
2022        })?;
2023        // The native CUDA ABI consumes F16 pages. Resolve Auto within the
2024        // requested typed storage before materializing a default policy into
2025        // the runtime snapshot, or a later stage mistakes that default for an
2026        // explicit incompatible NativeAdaptive request.
2027        if kv_storage != crate::KvStorageFormat::F16
2028            && requested.value == AttentionExecutionPolicy::NativeAdaptive
2029        {
2030            return Err(AutoConfigError::UnsupportedCombination {
2031                selection: "attention_execution_policy".to_owned(),
2032                reason: "native-adaptive attention does not implement the requested INT8 KV storage; use auto or portable".to_owned(),
2033            });
2034        }
2035        let native_adaptive_supported = self.is_cuda_backend()
2036            && self.hardware.compiled_features.vllm_paged_attn
2037            && kv_storage == crate::KvStorageFormat::F16;
2038        let compiled = requested
2039            .value
2040            .resolve(native_adaptive_supported)
2041            .map_err(|reason| AutoConfigError::UnsupportedCombination {
2042                selection: "attention_execution_policy".to_owned(),
2043                reason,
2044            })?;
2045        Ok((
2046            requested.clone(),
2047            ResolvedValue {
2048                value: compiled,
2049                source: if requested.value == AttentionExecutionPolicy::Auto {
2050                    AutoConfigSource::CompiledFeature
2051                } else {
2052                    requested.source
2053                },
2054                source_key: requested.source_key.clone(),
2055            },
2056        ))
2057    }
2058
2059    fn plan_attention_execution_decision(
2060        &self,
2061        compiled: &ResolvedValue<AttentionExecutionPolicy>,
2062    ) -> AutoConfigDecision {
2063        let selected = compiled.value.as_runtime_value();
2064        self.decision(
2065            "attention_execution_policy",
2066            selected,
2067            compiled.source,
2068            compiled.source_key.clone(),
2069            ["native-adaptive", "portable"],
2070            self.rejected_except(
2071                selected,
2072                [
2073                    (
2074                        "native-adaptive",
2075                        "native adaptive provider is not selected or compiled",
2076                    ),
2077                    ("portable", "portable provider is not selected"),
2078                ],
2079            ),
2080            vec![
2081                RuntimeConfigEffect::Correctness,
2082                RuntimeConfigEffect::Performance,
2083            ],
2084        )
2085    }
2086
2087    fn plan_attention_phase_decision(
2088        &self,
2089        selection: &str,
2090        compiled: &ResolvedValue<AttentionExecutionPolicy>,
2091    ) -> AutoConfigDecision {
2092        let selected = match (
2093            self.hardware.backend.to_ascii_lowercase().as_str(),
2094            compiled.value,
2095        ) {
2096            ("cuda", AttentionExecutionPolicy::NativeAdaptive) => "cuda_native_adaptive",
2097            ("metal", AttentionExecutionPolicy::NativeAdaptive) => "metal_native_adaptive",
2098            (_, AttentionExecutionPolicy::Portable) => "portable",
2099            (_, AttentionExecutionPolicy::Auto) => "unresolved",
2100            _ => "portable",
2101        };
2102        self.decision(
2103            selection,
2104            selected,
2105            compiled.source,
2106            compiled.source_key.clone(),
2107            ["cuda_native_adaptive", "metal_native_adaptive", "portable"],
2108            self.rejected_except(
2109                selected,
2110                [
2111                    (
2112                        "cuda_native_adaptive",
2113                        "CUDA native adaptive provider is not selected",
2114                    ),
2115                    (
2116                        "metal_native_adaptive",
2117                        "Metal native adaptive provider is not selected",
2118                    ),
2119                    ("portable", "portable provider is not selected"),
2120                ],
2121            ),
2122            vec![
2123                RuntimeConfigEffect::Correctness,
2124                RuntimeConfigEffect::Performance,
2125            ],
2126        )
2127    }
2128
2129    fn attention_prefill_decision(
2130        &self,
2131        use_vllm_paged_attn: ResolvedValue<bool>,
2132        fa_layout: ResolvedValue<bool>,
2133        fa2_source: ResolvedValue<bool>,
2134        fa2_direct_ffi: ResolvedValue<bool>,
2135    ) -> AutoConfigDecision {
2136        let (selected, source, source_key) = if fa2_source.value {
2137            ("fa2_source", fa2_source.source, fa2_source.source_key)
2138        } else if fa2_direct_ffi.value {
2139            (
2140                "fa2_direct_ffi",
2141                fa2_direct_ffi.source,
2142                fa2_direct_ffi.source_key,
2143            )
2144        } else if fa_layout.value {
2145            ("fa_layout_varlen", fa_layout.source, fa_layout.source_key)
2146        } else if use_vllm_paged_attn.value {
2147            (
2148                "vllm_paged_varlen",
2149                use_vllm_paged_attn.source,
2150                use_vllm_paged_attn.source_key,
2151            )
2152        } else {
2153            ("legacy_paged_varlen", AutoConfigSource::Default, None)
2154        };
2155        self.decision(
2156            "attention_prefill_mixed_backend",
2157            selected,
2158            source,
2159            source_key,
2160            [
2161                "fa2_source",
2162                "fa2_direct_ffi",
2163                "fa_layout_varlen",
2164                "vllm_paged_varlen",
2165                "legacy_paged_varlen",
2166            ],
2167            self.rejected_except(
2168                selected,
2169                [
2170                    ("fa2_source", "source-linked FA2 path not selected"),
2171                    ("fa2_direct_ffi", "diagnostic direct FFI shim not selected"),
2172                    ("fa_layout_varlen", "FA-compatible layout not selected"),
2173                    ("vllm_paged_varlen", "vLLM paged varlen bridge not selected"),
2174                    (
2175                        "legacy_paged_varlen",
2176                        "a higher-priority attention path was selected",
2177                    ),
2178                ],
2179            ),
2180            vec![
2181                RuntimeConfigEffect::Performance,
2182                RuntimeConfigEffect::Memory,
2183            ],
2184        )
2185    }
2186
2187    fn fa2_native_artifact_decision(
2188        &self,
2189        manifest: Option<&ResolvedValue<String>>,
2190        artifact: Option<&ResolvedValue<String>>,
2191    ) -> AutoConfigDecision {
2192        let configured = manifest.is_some() && artifact.is_some();
2193        let selected = if configured {
2194            "configured"
2195        } else {
2196            "not_configured"
2197        };
2198        let (source, source_key) = manifest
2199            .map(|manifest| (manifest.source, manifest.source_key.clone()))
2200            .unwrap_or((AutoConfigSource::Default, None));
2201        self.decision(
2202            "fa2_native_operator_artifact",
2203            selected,
2204            source,
2205            source_key,
2206            ["configured", "not_configured"],
2207            self.rejected_except(
2208                selected,
2209                [
2210                    (
2211                        "configured",
2212                        "no typed FA2 native operator manifest/artifact was configured",
2213                    ),
2214                    (
2215                        "not_configured",
2216                        "typed FA2 native operator manifest/artifact is present",
2217                    ),
2218                ],
2219            ),
2220            vec![
2221                RuntimeConfigEffect::Correctness,
2222                RuntimeConfigEffect::Performance,
2223            ],
2224        )
2225    }
2226
2227    fn fa2_native_runtime_selection_decision(
2228        &self,
2229        manifest: Option<&ResolvedValue<String>>,
2230        artifact: Option<&ResolvedValue<String>>,
2231    ) -> AutoConfigDecision {
2232        let configured = manifest.is_some() && artifact.is_some();
2233        let selected = if configured {
2234            "not_selected"
2235        } else {
2236            "not_configured"
2237        };
2238        let (source, source_key) = manifest
2239            .map(|manifest| (manifest.source, manifest.source_key.clone()))
2240            .unwrap_or((AutoConfigSource::Default, None));
2241        self.decision(
2242            "fa2_native_operator_runtime_selection",
2243            selected,
2244            source,
2245            source_key,
2246            ["selected", "not_selected", "not_configured"],
2247            self.rejected_except(
2248                selected,
2249                [
2250                    (
2251                        "selected",
2252                        "FA2 native runtime dispatch requires artifact-selected actual model smoke and retention evidence",
2253                    ),
2254                    (
2255                        "not_selected",
2256                        "typed FA2 native operator manifest/artifact is present",
2257                    ),
2258                    (
2259                        "not_configured",
2260                        "no typed FA2 native operator manifest/artifact was configured",
2261                    ),
2262                ],
2263            ),
2264            vec![
2265                RuntimeConfigEffect::Correctness,
2266                RuntimeConfigEffect::Performance,
2267            ],
2268        )
2269    }
2270
2271    fn attention_decode_decision(
2272        &self,
2273        use_vllm_paged_attn: ResolvedValue<bool>,
2274        vllm_v1_short: ResolvedValue<bool>,
2275    ) -> AutoConfigDecision {
2276        let (selected, source, source_key) = if use_vllm_paged_attn.value {
2277            if vllm_v1_short.value {
2278                (
2279                    "vllm_paged_attn_v1_short",
2280                    vllm_v1_short.source,
2281                    vllm_v1_short.source_key,
2282                )
2283            } else {
2284                (
2285                    "vllm_paged_attn_v2",
2286                    vllm_v1_short.source,
2287                    vllm_v1_short.source_key,
2288                )
2289            }
2290        } else {
2291            ("legacy_paged_decode", use_vllm_paged_attn.source, None)
2292        };
2293        self.decision(
2294            "attention_decode_backend",
2295            selected,
2296            source,
2297            source_key,
2298            [
2299                "vllm_paged_attn_v1_short",
2300                "vllm_paged_attn_v2",
2301                "legacy_paged_decode",
2302            ],
2303            self.rejected_except(
2304                selected,
2305                [
2306                    (
2307                        "vllm_paged_attn_v1_short",
2308                        "short-context v1 decode not selected",
2309                    ),
2310                    ("vllm_paged_attn_v2", "v2 decode not selected"),
2311                    ("legacy_paged_decode", "legacy decode not selected"),
2312                ],
2313            ),
2314            vec![RuntimeConfigEffect::Performance],
2315        )
2316    }
2317
2318    fn moe_decision(
2319        &self,
2320        vllm_moe: ResolvedValue<bool>,
2321        device_route: ResolvedValue<bool>,
2322        pair_ids: ResolvedValue<bool>,
2323    ) -> AutoConfigDecision {
2324        let selected = if vllm_moe.value && device_route.value && pair_ids.value {
2325            "vllm_marlin_moe_device_route_pair_ids"
2326        } else if vllm_moe.value && device_route.value {
2327            "vllm_marlin_moe_device_route"
2328        } else if vllm_moe.value {
2329            "vllm_marlin_moe"
2330        } else {
2331            "legacy_moe"
2332        };
2333        self.decision(
2334            "moe_implementation",
2335            selected,
2336            vllm_moe.source,
2337            vllm_moe.source_key,
2338            [
2339                "vllm_marlin_moe_device_route_pair_ids",
2340                "vllm_marlin_moe_device_route",
2341                "vllm_marlin_moe",
2342                "legacy_moe",
2343            ],
2344            self.rejected_except(
2345                selected,
2346                [
2347                    (
2348                        "vllm_marlin_moe_device_route_pair_ids",
2349                        "pair-id device route not selected",
2350                    ),
2351                    (
2352                        "vllm_marlin_moe_device_route",
2353                        "device-route MoE not selected",
2354                    ),
2355                    ("vllm_marlin_moe", "vLLM Marlin MoE not selected"),
2356                    ("legacy_moe", "legacy MoE not selected"),
2357                ],
2358            ),
2359            vec![RuntimeConfigEffect::Performance],
2360        )
2361    }
2362
2363    fn graph_decision(&self, graph: ResolvedValue<bool>) -> AutoConfigDecision {
2364        let selected = if graph.value {
2365            "graph_clean_decode"
2366        } else {
2367            "graph_disabled"
2368        };
2369        self.decision(
2370            "moe_graph_policy",
2371            selected,
2372            graph.source,
2373            graph.source_key,
2374            ["graph_clean_decode", "graph_disabled"],
2375            self.rejected_except(
2376                selected,
2377                [
2378                    ("graph_clean_decode", "graph decode not selected"),
2379                    ("graph_disabled", "graph decode selected"),
2380                ],
2381            ),
2382            vec![
2383                RuntimeConfigEffect::Performance,
2384                RuntimeConfigEffect::Correctness,
2385            ],
2386        )
2387    }
2388
2389    fn decode_graph_decision(
2390        &self,
2391        batched_graph: ResolvedValue<bool>,
2392        unified_graph: ResolvedValue<bool>,
2393        unified_graph_layers_only: ResolvedValue<bool>,
2394        unified_graph_lm_head_eager: ResolvedValue<bool>,
2395    ) -> AutoConfigDecision {
2396        let selected = if unified_graph.value && unified_graph_layers_only.value {
2397            "unified_decode_graph_layers_only"
2398        } else if unified_graph.value && unified_graph_lm_head_eager.value {
2399            "unified_decode_graph_lm_head_eager"
2400        } else if unified_graph.value {
2401            "unified_decode_graph"
2402        } else if batched_graph.value {
2403            "legacy_batched_decode_graph"
2404        } else {
2405            "graph_disabled"
2406        };
2407        let source_value = if unified_graph_layers_only.value {
2408            unified_graph_layers_only
2409        } else if unified_graph_lm_head_eager.value {
2410            unified_graph_lm_head_eager
2411        } else if unified_graph.value
2412            || (!batched_graph.value && unified_graph.source != AutoConfigSource::Default)
2413        {
2414            unified_graph
2415        } else {
2416            batched_graph
2417        };
2418        self.decision(
2419            "decode_graph_policy",
2420            selected,
2421            source_value.source,
2422            source_value.source_key,
2423            [
2424                "unified_decode_graph_layers_only",
2425                "unified_decode_graph_lm_head_eager",
2426                "unified_decode_graph",
2427                "legacy_batched_decode_graph",
2428                "graph_disabled",
2429            ],
2430            self.rejected_except(
2431                selected,
2432                [
2433                    (
2434                        "unified_decode_graph_layers_only",
2435                        "layers-only unified decode graph not selected",
2436                    ),
2437                    (
2438                        "unified_decode_graph_lm_head_eager",
2439                        "lm-head-eager unified decode graph not selected",
2440                    ),
2441                    ("unified_decode_graph", "unified decode graph not selected"),
2442                    (
2443                        "legacy_batched_decode_graph",
2444                        "legacy batched decode graph not selected",
2445                    ),
2446                    ("graph_disabled", "decode graph selected"),
2447                ],
2448            ),
2449            vec![
2450                RuntimeConfigEffect::Performance,
2451                RuntimeConfigEffect::Correctness,
2452            ],
2453        )
2454    }
2455
2456    fn reusable_execution_decision(
2457        &self,
2458        reusable_execution: ResolvedValue<bool>,
2459    ) -> AutoConfigDecision {
2460        let selected = if reusable_execution.value {
2461            "enabled_when_runtime_capable"
2462        } else {
2463            "disabled"
2464        };
2465        self.decision(
2466            "reusable_execution_policy",
2467            selected,
2468            reusable_execution.source,
2469            reusable_execution.source_key,
2470            ["enabled_when_runtime_capable", "disabled"],
2471            self.rejected_except(
2472                selected,
2473                [
2474                    (
2475                        "enabled_when_runtime_capable",
2476                        "reusable device programs are disabled",
2477                    ),
2478                    ("disabled", "reusable device programs are enabled"),
2479                ],
2480            ),
2481            vec![
2482                RuntimeConfigEffect::Performance,
2483                RuntimeConfigEffect::Correctness,
2484            ],
2485        )
2486    }
2487
2488    fn scalar_decision(
2489        &self,
2490        selection: &str,
2491        value: ResolvedValue<usize>,
2492        effect: RuntimeConfigEffect,
2493    ) -> AutoConfigDecision {
2494        self.decision(
2495            selection,
2496            &value.value.to_string(),
2497            value.source,
2498            value.source_key,
2499            [value.value.to_string()],
2500            Vec::new(),
2501            vec![effect],
2502        )
2503    }
2504
2505    fn scheduler_decision(
2506        &self,
2507        default_prefill_first_until_active: Option<ResolvedValue<usize>>,
2508        default_active_decode_prefill_chunk: Option<ResolvedValue<usize>>,
2509    ) -> Result<AutoConfigDecision, AutoConfigError> {
2510        let entries = self.entries();
2511        let prompt_scheduler =
2512            || -> Result<(String, AutoConfigSource, Option<String>), AutoConfigError> {
2513                let prompt_token_estimate = self.bool_value(
2514                    "FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE",
2515                    true,
2516                    AutoConfigSource::Default,
2517                )?;
2518                let selected = if prompt_token_estimate.value {
2519                    "prompt_token_estimate"
2520                } else {
2521                    "continuous_default"
2522                };
2523                Ok((
2524                    selected.to_string(),
2525                    prompt_token_estimate.source,
2526                    prompt_token_estimate.source_key,
2527                ))
2528            };
2529        let explicit_prefill_first = entries.get("FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE");
2530        let explicit_prefill_first_present = explicit_prefill_first.is_some();
2531        let implicit_prefill_first = if explicit_prefill_first.is_none()
2532            && !entries.contains_key("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE")
2533        {
2534            default_prefill_first_until_active
2535                .as_ref()
2536                .map(|until| until.value.to_string())
2537        } else {
2538            None
2539        };
2540        let prefill_first = explicit_prefill_first
2541            .copied()
2542            .or(implicit_prefill_first.as_deref());
2543        let explicit_active_decode_chunk = entries.get("FERRUM_ACTIVE_DECODE_PREFILL_CHUNK");
2544        let implicit_active_decode_chunk = default_active_decode_prefill_chunk
2545            .as_ref()
2546            .map(|chunk| chunk.value.to_string());
2547        let active_decode_chunk = explicit_active_decode_chunk
2548            .copied()
2549            .or(implicit_active_decode_chunk.as_deref());
2550        let active_decode_chunk_source = if explicit_active_decode_chunk.is_some() {
2551            let key = "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK";
2552            (
2553                self.source_for_key(key, AutoConfigSource::Default),
2554                Some(key.to_owned()),
2555            )
2556        } else {
2557            (AutoConfigSource::Default, None)
2558        };
2559        if let Some(chunk) = active_decode_chunk {
2560            let chunk_value = parse_usize_env_value(chunk).map_err(|reason| {
2561                AutoConfigError::InvalidOverride {
2562                    key: "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK".to_string(),
2563                    reason,
2564                }
2565            })?;
2566            self.unsupported_if(
2567                chunk_value == 0,
2568                "scheduler_admission_policy",
2569                "active decode prefill chunk must be greater than zero",
2570            )?;
2571        }
2572        let explicit_prefill_step_chunk = entries.get("FERRUM_SCHED_PREFILL_STEP_CHUNK");
2573        let explicit_prefill_step_chunk_present = explicit_prefill_step_chunk.is_some();
2574        let prefill_step_chunk = explicit_prefill_step_chunk.copied();
2575        if let Some(chunk) = prefill_step_chunk {
2576            let chunk_value = parse_usize_env_value(chunk).map_err(|reason| {
2577                AutoConfigError::InvalidOverride {
2578                    key: "FERRUM_SCHED_PREFILL_STEP_CHUNK".to_string(),
2579                    reason,
2580                }
2581            })?;
2582            self.unsupported_if(
2583                chunk_value == 0,
2584                "scheduler_admission_policy",
2585                "scheduler prefill step chunk must be greater than zero",
2586            )?;
2587        }
2588        let (mut selected, mut source, mut source_key) = if let (Some(until), Some(chunk)) =
2589            (prefill_first, active_decode_chunk)
2590        {
2591            parse_usize_env_value(until).map_err(|reason| AutoConfigError::InvalidOverride {
2592                key: "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE".to_string(),
2593                reason,
2594            })?;
2595            parse_usize_env_value(chunk).map_err(|reason| AutoConfigError::InvalidOverride {
2596                key: "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK".to_string(),
2597                reason,
2598            })?;
2599            let (source, source_key) =
2600                if explicit_active_decode_chunk.is_none() && explicit_prefill_first_present {
2601                    let key = "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE";
2602                    (
2603                        self.source_for_key(key, AutoConfigSource::Default),
2604                        Some(key.to_owned()),
2605                    )
2606                } else {
2607                    active_decode_chunk_source.clone()
2608                };
2609            (
2610                format!("prefill_first_until_active:{until}+active_decode_prefill_chunk:{chunk}"),
2611                source,
2612                source_key,
2613            )
2614        } else if let Some(chunk) = active_decode_chunk {
2615            parse_usize_env_value(chunk).map_err(|reason| AutoConfigError::InvalidOverride {
2616                key: "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK".to_string(),
2617                reason,
2618            })?;
2619            (
2620                format!("active_decode_prefill_chunk:{chunk}"),
2621                active_decode_chunk_source.0,
2622                active_decode_chunk_source.1,
2623            )
2624        } else if let Some(until) = prefill_first {
2625            parse_usize_env_value(until).map_err(|reason| AutoConfigError::InvalidOverride {
2626                key: "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE".to_string(),
2627                reason,
2628            })?;
2629            let key = "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE";
2630            let (source, source_key) = if explicit_prefill_first_present {
2631                (
2632                    self.source_for_key(key, AutoConfigSource::Default),
2633                    Some(key.to_string()),
2634                )
2635            } else if let Some(default) = default_prefill_first_until_active.as_ref() {
2636                (default.source, default.source_key.clone())
2637            } else {
2638                (AutoConfigSource::Default, None)
2639            };
2640            (
2641                format!("prefill_first_until_active:{until}"),
2642                source,
2643                source_key,
2644            )
2645        } else if !entries.contains_key("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE") {
2646            if let Some(until) = default_prefill_first_until_active.as_ref() {
2647                (
2648                    format!("prefill_first_until_active:{}", until.value),
2649                    until.source,
2650                    until.source_key.clone(),
2651                )
2652            } else {
2653                prompt_scheduler()?
2654            }
2655        } else {
2656            prompt_scheduler()?
2657        };
2658        if let Some(chunk) = prefill_step_chunk {
2659            selected.push_str(&format!("+prefill_step_chunk:{chunk}"));
2660            if explicit_prefill_step_chunk_present && source_key.is_none() {
2661                let key = "FERRUM_SCHED_PREFILL_STEP_CHUNK";
2662                source = self.source_for_key(key, AutoConfigSource::Default);
2663                source_key = Some(key.to_string());
2664            }
2665        } else if default_prefill_first_until_active.is_some()
2666            && !entries.contains_key("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE")
2667        {
2668            selected.push_str("+prefill_token_budget:elastic");
2669        }
2670        Ok(self.decision(
2671            "scheduler_admission_policy",
2672            &selected,
2673            source,
2674            source_key,
2675            [
2676                "continuous_default",
2677                "prompt_token_estimate",
2678                "prefill_first_until_active",
2679                "prefill_first_until_active+active_decode_prefill_chunk",
2680                "active_decode_prefill_chunk",
2681                "prefill_step_chunk",
2682                "prefill_token_budget:elastic",
2683            ],
2684            Vec::new(),
2685            vec![RuntimeConfigEffect::Performance],
2686        ))
2687    }
2688
2689    fn prefix_cache_decision(&self, prefix_cache: ResolvedValue<bool>) -> AutoConfigDecision {
2690        let selected = if prefix_cache.value {
2691            "prefix_cache_enabled"
2692        } else {
2693            "prefix_cache_disabled"
2694        };
2695        self.decision(
2696            "prefix_cache_policy",
2697            selected,
2698            prefix_cache.source,
2699            prefix_cache.source_key,
2700            ["prefix_cache_enabled", "prefix_cache_disabled"],
2701            self.rejected_except(
2702                selected,
2703                [
2704                    ("prefix_cache_enabled", "prefix cache not selected"),
2705                    ("prefix_cache_disabled", "prefix cache enabled"),
2706                ],
2707            ),
2708            vec![
2709                RuntimeConfigEffect::Correctness,
2710                RuntimeConfigEffect::Performance,
2711                RuntimeConfigEffect::Memory,
2712            ],
2713        )
2714    }
2715
2716    fn sampling_decision(&self, greedy: ResolvedValue<bool>) -> AutoConfigDecision {
2717        let selected = if greedy.value {
2718            "gpu_greedy_argmax"
2719        } else {
2720            "logits_readback"
2721        };
2722        self.decision(
2723            "sampling_readback_path",
2724            selected,
2725            greedy.source,
2726            greedy.source_key,
2727            ["gpu_greedy_argmax", "logits_readback"],
2728            self.rejected_except(
2729                selected,
2730                [
2731                    ("gpu_greedy_argmax", "GPU argmax not selected"),
2732                    ("logits_readback", "logits readback not selected"),
2733                ],
2734            ),
2735            vec![
2736                RuntimeConfigEffect::Performance,
2737                RuntimeConfigEffect::Correctness,
2738            ],
2739        )
2740    }
2741
2742    fn decision<I, C>(
2743        &self,
2744        selection: &str,
2745        selected: &str,
2746        source: AutoConfigSource,
2747        source_key: Option<String>,
2748        candidates: I,
2749        rejected: Vec<RejectedCandidate>,
2750        affects: Vec<RuntimeConfigEffect>,
2751    ) -> AutoConfigDecision
2752    where
2753        I: IntoIterator<Item = C>,
2754        C: Into<String>,
2755    {
2756        AutoConfigDecision {
2757            schema_version: 1,
2758            selection: selection.to_string(),
2759            selected: selected.to_string(),
2760            source,
2761            source_key,
2762            candidates: candidates.into_iter().map(Into::into).collect(),
2763            rejected,
2764            affects,
2765        }
2766    }
2767
2768    fn rejected_except<I>(&self, selected: &str, candidates: I) -> Vec<RejectedCandidate>
2769    where
2770        I: IntoIterator<Item = (&'static str, &'static str)>,
2771    {
2772        candidates
2773            .into_iter()
2774            .filter(|(value, _)| *value != selected)
2775            .map(|(value, reason)| RejectedCandidate {
2776                value: value.to_string(),
2777                reason: reason.to_string(),
2778            })
2779            .collect()
2780    }
2781
2782    fn invalid<T>(&self, key: &str, reason: &str) -> Result<T, AutoConfigError> {
2783        Err(AutoConfigError::InvalidOverride {
2784            key: key.to_string(),
2785            reason: reason.to_string(),
2786        })
2787    }
2788
2789    fn unsupported<T>(&self, selection: &str, reason: &str) -> Result<T, AutoConfigError> {
2790        Err(AutoConfigError::UnsupportedCombination {
2791            selection: selection.to_string(),
2792            reason: reason.to_string(),
2793        })
2794    }
2795
2796    fn unsupported_if(
2797        &self,
2798        condition: bool,
2799        selection: &str,
2800        reason: &str,
2801    ) -> Result<(), AutoConfigError> {
2802        if condition {
2803            self.unsupported(selection, reason)
2804        } else {
2805            Ok(())
2806        }
2807    }
2808}
2809
2810fn kv_cache_bytes_per_token_for_model(model: &ModelCapabilities) -> Option<u64> {
2811    let layers = model.num_hidden_layers? as u64;
2812    let kv_heads = model.kv_heads? as u64;
2813    let head_dim = model.head_dim? as u64;
2814    layers
2815        .checked_mul(2)?
2816        .checked_mul(kv_heads)?
2817        .checked_mul(head_dim)?
2818        .checked_mul(2)
2819}
2820
2821fn qwen_moe_architecture_uses_vllm_paged_attn(architecture: &str) -> bool {
2822    architecture.eq_ignore_ascii_case("qwen3_moe")
2823        || architecture.eq_ignore_ascii_case("qwen3_5_moe")
2824}
2825
2826#[derive(Debug, Clone, PartialEq, Eq)]
2827struct ResolvedValue<T> {
2828    value: T,
2829    source: AutoConfigSource,
2830    source_key: Option<String>,
2831}
2832
2833#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2834struct RecurrentStateBudget {
2835    remaining_bytes: u64,
2836    bytes_per_sequence: u64,
2837    raw_slots: usize,
2838    floored_slots: usize,
2839}
2840
2841fn recurrent_state_budget_for(
2842    model: &ModelCapabilities,
2843    hardware: &HardwareCapabilities,
2844) -> Option<RecurrentStateBudget> {
2845    if !(hardware.backend.eq_ignore_ascii_case("cuda")
2846        || hardware.backend.eq_ignore_ascii_case("metal"))
2847    {
2848        return None;
2849    }
2850    let bytes_per_sequence = model.recurrent_state_bytes_per_sequence?.max(1);
2851    let vram_bytes = hardware.vram_bytes?;
2852    let weight_bytes = model.estimated_weight_bytes?;
2853    let remaining = vram_bytes.saturating_sub(weight_bytes);
2854    let raw_slots = (remaining / bytes_per_sequence) as usize;
2855    Some(RecurrentStateBudget {
2856        remaining_bytes: remaining,
2857        bytes_per_sequence,
2858        raw_slots,
2859        floored_slots: floor_power_of_two(raw_slots.max(1)),
2860    })
2861}
2862
2863fn parse_compute_capability(value: &str) -> Option<(u32, u32)> {
2864    let value = value.trim();
2865    if value.is_empty() {
2866        return None;
2867    }
2868    let (major, minor) = value.split_once('.').unwrap_or((value, "0"));
2869    Some((major.trim().parse().ok()?, minor.trim().parse().ok()?))
2870}
2871
2872fn vram_default_max_sequences(vram_bytes: u64) -> usize {
2873    match vram_bytes {
2874        bytes if bytes >= 20 * GIB => 32,
2875        bytes if bytes >= 12 * GIB => 16,
2876        bytes if bytes >= 8 * GIB => 8,
2877        _ => 4,
2878    }
2879}
2880
2881fn default_gpu_devices_for_backend(backend: &str) -> Option<Vec<usize>> {
2882    backend.eq_ignore_ascii_case("cuda").then(|| vec![0])
2883}
2884
2885fn ceil_div(value: usize, divisor: usize) -> usize {
2886    value.div_ceil(divisor)
2887}
2888
2889fn effective_admission_limit(
2890    authority: ExecutionResourceAuthority,
2891    max_sequences: Option<usize>,
2892    recurrent_state_max_slots: Option<usize>,
2893) -> Option<usize> {
2894    if authority == ExecutionResourceAuthority::PlanRuntime {
2895        return max_sequences;
2896    }
2897    match (max_sequences, recurrent_state_max_slots) {
2898        (Some(max_sequences), Some(recurrent_slots)) => Some(max_sequences.min(recurrent_slots)),
2899        (Some(max_sequences), None) => Some(max_sequences),
2900        (None, Some(recurrent_slots)) => Some(recurrent_slots),
2901        (None, None) => None,
2902    }
2903}
2904
2905fn floor_power_of_two(value: usize) -> usize {
2906    if value <= 1 {
2907        return 1;
2908    }
2909    1usize << (usize::BITS - 1 - value.leading_zeros())
2910}
2911
2912fn auto_config_source_from_runtime(source: RuntimeConfigSource) -> AutoConfigSource {
2913    match source {
2914        RuntimeConfigSource::Default => AutoConfigSource::Default,
2915        RuntimeConfigSource::ConfigFile => AutoConfigSource::ConfigFile,
2916        RuntimeConfigSource::Cli => AutoConfigSource::Cli,
2917        RuntimeConfigSource::Env => AutoConfigSource::Env,
2918        RuntimeConfigSource::ScriptCase => AutoConfigSource::ScriptCase,
2919        RuntimeConfigSource::MemoryProfile => AutoConfigSource::MemoryProfile,
2920    }
2921}
2922
2923#[cfg(test)]
2924mod tests {
2925    use super::*;
2926
2927    fn snapshot(vars: &[(&str, &str)]) -> RuntimeConfigSnapshot {
2928        RuntimeConfigSnapshot::from_env_vars(vars.iter().copied())
2929    }
2930
2931    fn snapshot_with_sources(vars: &[(&str, &str, RuntimeConfigSource)]) -> RuntimeConfigSnapshot {
2932        let mut entries: Vec<_> = vars
2933            .iter()
2934            .map(|(key, effective_value, source)| RuntimeConfigEntry {
2935                key: (*key).to_string(),
2936                effective_value: (*effective_value).to_string(),
2937                source: *source,
2938                affects: vec![RuntimeConfigEffect::Performance],
2939            })
2940            .collect();
2941        entries.sort_by(|a, b| a.key.cmp(&b.key));
2942        RuntimeConfigSnapshot { entries }
2943    }
2944
2945    fn m3(vars: &[(&str, &str)], features: CompiledKernelFeatures) -> FerrumConfigBuilder {
2946        FerrumConfigBuilder::new(snapshot(vars))
2947            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
2948            .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(features))
2949            .with_workload_profile(WorkloadProfile::m3_qwen3_30b_a3b_int4())
2950    }
2951
2952    fn m3_with_hardware(
2953        vars: &[(&str, &str)],
2954        hardware: HardwareCapabilities,
2955    ) -> FerrumConfigBuilder {
2956        FerrumConfigBuilder::new(snapshot(vars))
2957            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
2958            .with_hardware_capabilities(hardware)
2959            .with_workload_profile(WorkloadProfile::m3_qwen3_30b_a3b_int4())
2960    }
2961
2962    fn qwen35_moe_gptq_int4_model() -> ModelCapabilities {
2963        let mut model = ModelCapabilities::qwen3_30b_a3b_gptq_int4();
2964        model.architecture = "qwen3_5_moe".to_string();
2965        model.head_dim = Some(256);
2966        model.num_hidden_layers = Some(40);
2967        model.kv_heads = Some(8);
2968        model.estimated_weight_bytes = Some(24_419_939_760);
2969        model.recurrent_state_bytes_per_sequence = Some(32_931_840);
2970        model
2971    }
2972
2973    fn synthetic_tight_recurrent_state_model() -> ModelCapabilities {
2974        ModelCapabilities {
2975            architecture: "synthetic_recurrent_state".to_string(),
2976            quantization: None,
2977            moe: None,
2978            max_context_len: Some(262_144),
2979            num_hidden_layers: Some(40),
2980            head_dim: Some(256),
2981            kv_heads: Some(8),
2982            estimated_weight_bytes: Some(24_419_939_760),
2983            recurrent_state_bytes_per_sequence: Some(65_863_680),
2984            supported_dtypes: vec!["fp16".to_string()],
2985            graph_safe_moe: false,
2986        }
2987    }
2988
2989    fn qwen25_layer_split_runtime_entries(source: RuntimeConfigSource) -> RuntimeConfigSnapshot {
2990        snapshot_with_sources(&[
2991            ("FERRUM_REQUESTED_GPU_DEVICES", "0,1", source),
2992            ("FERRUM_SELECTED_GPU_DEVICES", "0,1", source),
2993            ("FERRUM_CUDA_DEVICE_COUNT", "2", source),
2994            (
2995                "FERRUM_SELECTED_DISTRIBUTED_STRATEGY",
2996                "layer_split",
2997                source,
2998            ),
2999            (
3000                "FERRUM_SELECTED_LAYER_SPLIT_PLAN",
3001                "stage0:cuda:0:layers=0-39;stage1:cuda:1:layers=40-79",
3002                source,
3003            ),
3004            ("FERRUM_LAYER_SPLIT_PIPELINE_MODE", "batch", source),
3005            ("FERRUM_MAX_MODEL_LEN", "4096", source),
3006            ("FERRUM_KV_MAX_BLOCKS", "1024", source),
3007            ("FERRUM_KV_CAPACITY", "1024", source),
3008            ("FERRUM_PAGED_MAX_SEQS", "16", source),
3009            ("FERRUM_MAX_BATCHED_TOKENS", "1536", source),
3010            ("FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE", "16", source),
3011        ])
3012    }
3013
3014    fn gemma3_gptq_model() -> ModelCapabilities {
3015        ModelCapabilities {
3016            architecture: "gemma3".to_string(),
3017            quantization: Some("gptq_int4".to_string()),
3018            moe: None,
3019            max_context_len: Some(131_072),
3020            num_hidden_layers: Some(62),
3021            head_dim: Some(256),
3022            kv_heads: Some(16),
3023            estimated_weight_bytes: Some(15 * GIB),
3024            recurrent_state_bytes_per_sequence: None,
3025            supported_dtypes: vec!["fp16".to_string()],
3026            graph_safe_moe: false,
3027        }
3028    }
3029
3030    fn expect_invalid_key(vars: &[(&str, &str)], key: &str) {
3031        expect_invalid_key_with_features(
3032            vars,
3033            key,
3034            CompiledKernelFeatures::m3_fast_path_without_fa2(),
3035        );
3036    }
3037
3038    fn expect_invalid_key_with_features(
3039        vars: &[(&str, &str)],
3040        key: &str,
3041        features: CompiledKernelFeatures,
3042    ) {
3043        expect_invalid_key_with_hardware(vars, key, HardwareCapabilities::rtx4090_cuda(features));
3044    }
3045
3046    fn expect_invalid_key_with_hardware(
3047        vars: &[(&str, &str)],
3048        key: &str,
3049        hardware: HardwareCapabilities,
3050    ) {
3051        let err = m3_with_hardware(vars, hardware)
3052            .resolve()
3053            .expect_err("override should fail");
3054        match err {
3055            AutoConfigError::InvalidOverride { key: actual, .. } => assert_eq!(actual, key),
3056            other => panic!("expected invalid override for {key}, got {other:?}"),
3057        }
3058    }
3059
3060    fn cpu_hardware_with_features(features: CompiledKernelFeatures) -> HardwareCapabilities {
3061        HardwareCapabilities {
3062            backend: "cpu".to_string(),
3063            supported_dtypes: vec!["fp32".to_string()],
3064            supported_kv_dtypes: vec!["fp16".to_string()],
3065            compiled_features: features,
3066            ..HardwareCapabilities::unknown()
3067        }
3068    }
3069
3070    #[test]
3071    fn m3_preset_selects_current_safe_fast_path_without_fa2() {
3072        let resolved = m3(&[], CompiledKernelFeatures::m3_fast_path_without_fa2())
3073            .resolve()
3074            .unwrap();
3075        let decisions: BTreeMap<_, _> = resolved
3076            .decisions
3077            .iter()
3078            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
3079            .collect();
3080        assert_eq!(
3081            decisions["attention_prefill_mixed_backend"],
3082            "vllm_paged_varlen"
3083        );
3084        assert_eq!(
3085            decisions["attention_decode_backend"],
3086            "vllm_paged_attn_v1_short"
3087        );
3088        assert_eq!(
3089            decisions["moe_implementation"],
3090            "vllm_marlin_moe_device_route_pair_ids"
3091        );
3092        assert_eq!(decisions["moe_graph_policy"], "graph_disabled");
3093        assert_eq!(decisions["decode_graph_policy"], "graph_disabled");
3094        assert_eq!(decisions["prefix_cache_policy"], "prefix_cache_disabled");
3095        assert_eq!(decisions["sampling_readback_path"], "gpu_greedy_argmax");
3096        assert_eq!(
3097            resolved.preset.as_deref(),
3098            Some(M3_QWEN3_30B_A3B_INT4_PRESET)
3099        );
3100    }
3101
3102    #[test]
3103    fn cuda_gptq_moe_enables_vllm_marlin_without_m3_preset() {
3104        // `ferrum run` resolves with the serving-default workload, NOT the m3
3105        // bench preset, so the old `is_m3_preset()`-gated FERRUM_VLLM_MOE never
3106        // fired and the 30B fell back to the slow host-route MoE (~9.7 vs ~59
3107        // tok/s on a 4090). A CUDA GPTQ MoE must get the vLLM-Marlin fast path
3108        // on capability alone.
3109        let hardware =
3110            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3111        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3112        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
3113            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
3114            .with_hardware_capabilities(hardware)
3115            .with_workload_profile(workload)
3116            .resolve()
3117            .unwrap();
3118        let decisions: BTreeMap<_, _> = resolved
3119            .decisions
3120            .iter()
3121            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
3122            .collect();
3123        assert_ne!(
3124            resolved.preset.as_deref(),
3125            Some(M3_QWEN3_30B_A3B_INT4_PRESET),
3126            "serving-default workload must not be the m3 preset"
3127        );
3128        assert_eq!(
3129            decisions["moe_implementation"], "vllm_marlin_moe_device_route_pair_ids",
3130            "CUDA GPTQ MoE should get the fast vLLM-Marlin path without the m3 preset"
3131        );
3132        // The decision is not enough — the model reads FERRUM_VLLM_MOE from the
3133        // effective config, not the decisions. The resolved knob must be a
3134        // runtime_config entry so `ferrum run`'s materialize/apply propagates it.
3135        let entry = resolved
3136            .runtime_config
3137            .entries
3138            .iter()
3139            .find(|e| e.key == "FERRUM_VLLM_MOE");
3140        assert_eq!(
3141            entry.map(|e| e.effective_value.as_str()),
3142            Some("1"),
3143            "resolved FERRUM_VLLM_MOE must be materialized into the effective config"
3144        );
3145    }
3146
3147    #[test]
3148    fn cuda_qwen3_moe_enables_vllm_paged_attn_without_m3_preset() {
3149        // `ferrum run` and ordinary `serve` use the serving-default workload,
3150        // not the m3 preset. Qwen3-MoE on CUDA with the VPA kernel compiled
3151        // must still select and materialize the paged-attention runtime knob,
3152        // otherwise the effective config/decision trace says "legacy" while
3153        // the model runtime can take the VPA path through its own defaults.
3154        let hardware =
3155            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3156        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3157        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
3158            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
3159            .with_hardware_capabilities(hardware)
3160            .with_workload_profile(workload)
3161            .resolve()
3162            .unwrap();
3163        let decisions: BTreeMap<_, _> = resolved
3164            .decisions
3165            .iter()
3166            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
3167            .collect();
3168        assert_eq!(
3169            decisions["attention_decode_backend"], "vllm_paged_attn_v1_short",
3170            "CUDA Qwen3-MoE should get VPA decode without the m3 preset"
3171        );
3172        let entry = |key: &str| {
3173            resolved
3174                .runtime_config
3175                .entries
3176                .iter()
3177                .find(|entry| entry.key == key)
3178                .unwrap_or_else(|| panic!("missing runtime config entry {key}"))
3179        };
3180        assert_eq!(entry("FERRUM_USE_VLLM_PAGED_ATTN").effective_value, "1");
3181        assert_eq!(
3182            entry("FERRUM_VLLM_PAGED_ATTN_V1_SHORT").effective_value,
3183            "1"
3184        );
3185    }
3186
3187    #[test]
3188    fn cuda_qwen35_moe_enables_vllm_paged_attn_v2_without_m3_preset() {
3189        // Qwen3.5-MoE shares the Qwen MoE CUDA fast-path requirements, but its
3190        // full-attention head_dim is 256. The H256 path uses the v2 paged
3191        // attention launcher, so the default decision trace must not report
3192        // the H128-oriented v1-short path.
3193        let mut hardware =
3194            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3195        hardware.vram_bytes = Some(48 * GIB);
3196        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3197        let model = qwen35_moe_gptq_int4_model();
3198        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
3199            .with_model_capabilities(model)
3200            .with_hardware_capabilities(hardware)
3201            .with_workload_profile(workload)
3202            .resolve()
3203            .unwrap();
3204        let decisions: BTreeMap<_, _> = resolved
3205            .decisions
3206            .iter()
3207            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
3208            .collect();
3209        assert_eq!(
3210            decisions["attention_prefill_mixed_backend"],
3211            "vllm_paged_varlen"
3212        );
3213        assert_eq!(decisions["attention_decode_backend"], "vllm_paged_attn_v2");
3214        let entry = |key: &str| {
3215            resolved
3216                .runtime_config
3217                .entries
3218                .iter()
3219                .find(|entry| entry.key == key)
3220                .unwrap_or_else(|| panic!("missing runtime config entry {key}"))
3221        };
3222        assert_eq!(entry("FERRUM_USE_VLLM_PAGED_ATTN").effective_value, "1");
3223        assert_eq!(
3224            entry("FERRUM_VLLM_PAGED_ATTN_V1_SHORT").effective_value,
3225            "0"
3226        );
3227    }
3228
3229    #[test]
3230    fn recurrent_state_budget_caps_default_slots_without_model_vram_special_case() {
3231        let hardware =
3232            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3233        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3234        let resolved = FerrumConfigBuilder::new(snapshot(&[("FERRUM_PAGED_MAX_SEQS", "32")]))
3235            .with_model_capabilities(synthetic_tight_recurrent_state_model())
3236            .with_hardware_capabilities(hardware)
3237            .with_workload_profile(workload)
3238            .resolve()
3239            .unwrap();
3240        let decision = |selection: &str| {
3241            resolved
3242                .decisions
3243                .iter()
3244                .find(|decision| decision.selection == selection)
3245                .unwrap_or_else(|| panic!("missing decision {selection}"))
3246        };
3247
3248        assert_eq!(decision("max_sequences").selected, "32");
3249        assert_eq!(decision("recurrent_state_max_slots").selected, "16");
3250        assert_eq!(
3251            decision("recurrent_state_max_slots").source,
3252            AutoConfigSource::MemoryProfile
3253        );
3254        let entry = resolved
3255            .runtime_config
3256            .entries
3257            .iter()
3258            .find(|entry| entry.key == "FERRUM_RECURRENT_STATE_MAX_SLOTS")
3259            .expect("memory-profile recurrent slot cap should reach effective runtime config");
3260        assert_eq!(entry.effective_value, "16");
3261        assert_eq!(entry.source, RuntimeConfigSource::MemoryProfile);
3262        let doc = resolved.effective_config_document();
3263        assert_eq!(doc["selected_max_sequences"], serde_json::json!(32));
3264        assert_eq!(
3265            doc["selected_recurrent_state_max_slots"],
3266            serde_json::json!(16)
3267        );
3268        assert_eq!(doc["selected_admission_limit"], serde_json::json!(16));
3269        assert_eq!(
3270            doc["admission"]["effective_max_concurrent"],
3271            serde_json::json!(16)
3272        );
3273        assert_eq!(
3274            doc["admission"]["recurrent_state_max_slots"],
3275            serde_json::json!(16)
3276        );
3277        assert_eq!(
3278            doc["admission"]["memory_estimate"]["recurrent_state_bytes_per_sequence"],
3279            serde_json::json!(65_863_680u64)
3280        );
3281        assert_eq!(
3282            doc["admission"]["memory_estimate"]["recurrent_state_budget_bytes"],
3283            serde_json::json!(24u64 * GIB - 24_419_939_760u64)
3284        );
3285        assert_eq!(
3286            doc["admission"]["memory_estimate"]["recurrent_state_budget_raw_slots"],
3287            serde_json::json!(20)
3288        );
3289        assert_eq!(
3290            doc["admission"]["memory_estimate"]["recurrent_state_budget_max_slots"],
3291            serde_json::json!(16)
3292        );
3293        assert_eq!(
3294            doc["admission"]["memory_estimate"]["recurrent_state_capacity_bytes"],
3295            serde_json::json!(16u64 * 65_863_680u64)
3296        );
3297    }
3298
3299    #[test]
3300    fn qwen35_fast_recurrent_state_budget_selects_default_slots_without_vram_special_case() {
3301        let hardware =
3302            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3303        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3304        let resolved = FerrumConfigBuilder::new(snapshot(&[("FERRUM_PAGED_MAX_SEQS", "32")]))
3305            .with_model_capabilities(qwen35_moe_gptq_int4_model())
3306            .with_hardware_capabilities(hardware)
3307            .with_workload_profile(workload)
3308            .resolve()
3309            .unwrap();
3310        let decision = |selection: &str| {
3311            resolved
3312                .decisions
3313                .iter()
3314                .find(|decision| decision.selection == selection)
3315                .unwrap_or_else(|| panic!("missing decision {selection}"))
3316        };
3317
3318        assert_eq!(decision("max_sequences").selected, "32");
3319        assert_eq!(decision("recurrent_state_max_slots").selected, "32");
3320        assert_eq!(
3321            decision("recurrent_state_max_slots").source,
3322            AutoConfigSource::Env
3323        );
3324        let doc = resolved.effective_config_document();
3325        assert_eq!(doc["selected_max_sequences"], serde_json::json!(32));
3326        assert_eq!(
3327            doc["selected_recurrent_state_max_slots"],
3328            serde_json::json!(32)
3329        );
3330        assert_eq!(doc["selected_admission_limit"], serde_json::json!(32));
3331        assert_eq!(
3332            doc["admission"]["memory_estimate"]["recurrent_state_bytes_per_sequence"],
3333            serde_json::json!(32_931_840u64)
3334        );
3335        assert_eq!(
3336            doc["admission"]["memory_estimate"]["recurrent_state_budget_raw_slots"],
3337            serde_json::json!(40)
3338        );
3339        assert_eq!(
3340            doc["admission"]["memory_estimate"]["recurrent_state_budget_max_slots"],
3341            serde_json::json!(32)
3342        );
3343        assert_eq!(
3344            doc["admission"]["memory_estimate"]["recurrent_state_capacity_bytes"],
3345            serde_json::json!(32u64 * 32_931_840u64)
3346        );
3347    }
3348
3349    #[test]
3350    fn recurrent_state_budget_rejects_explicit_slot_pool_above_budget() {
3351        let hardware =
3352            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3353        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3354        let err = FerrumConfigBuilder::new(snapshot(&[
3355            ("FERRUM_PAGED_MAX_SEQS", "32"),
3356            ("FERRUM_RECURRENT_STATE_MAX_SLOTS", "32"),
3357        ]))
3358        .with_model_capabilities(synthetic_tight_recurrent_state_model())
3359        .with_hardware_capabilities(hardware)
3360        .with_workload_profile(workload)
3361        .resolve()
3362        .unwrap_err();
3363
3364        match err {
3365            AutoConfigError::InvalidOverride { key, reason } => {
3366                assert_eq!(key, "FERRUM_RECURRENT_STATE_MAX_SLOTS");
3367                assert!(
3368                    reason.contains("recurrent-state slot pool exceeds"),
3369                    "{reason}"
3370                );
3371                assert!(
3372                    reason.contains("FERRUM_RECURRENT_STATE_MAX_SLOTS=16"),
3373                    "{reason}"
3374                );
3375            }
3376            other => panic!("unexpected error: {other:?}"),
3377        }
3378    }
3379
3380    #[test]
3381    fn effective_admission_limit_respects_resource_authority() {
3382        let legacy = ExecutionResourceAuthority::LegacyEngine;
3383        let plan = ExecutionResourceAuthority::PlanRuntime;
3384        assert_eq!(
3385            effective_admission_limit(legacy, Some(32), Some(16)),
3386            Some(16)
3387        );
3388        assert_eq!(
3389            effective_admission_limit(legacy, Some(16), Some(32)),
3390            Some(16)
3391        );
3392        assert_eq!(effective_admission_limit(legacy, Some(32), None), Some(32));
3393        assert_eq!(effective_admission_limit(legacy, None, Some(16)), Some(16));
3394        assert_eq!(effective_admission_limit(legacy, None, None), None);
3395        assert_eq!(
3396            effective_admission_limit(plan, Some(32), Some(16)),
3397            Some(32)
3398        );
3399    }
3400
3401    #[test]
3402    fn plan_runtime_uses_dynamic_admission_and_typed_attention_authority() {
3403        let hardware =
3404            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3405        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3406        let resolved = FerrumConfigBuilder::new(snapshot(&[("FERRUM_PAGED_MAX_SEQS", "32")]))
3407            .with_model_capabilities(synthetic_tight_recurrent_state_model())
3408            .with_hardware_capabilities(hardware)
3409            .with_workload_profile(workload)
3410            .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3411            .resolve()
3412            .unwrap();
3413
3414        assert_eq!(
3415            resolved.execution_resource_authority,
3416            ExecutionResourceAuthority::PlanRuntime
3417        );
3418        assert_eq!(
3419            resolved.requested_attention_policy,
3420            Some(AttentionExecutionPolicy::Auto)
3421        );
3422        assert_eq!(
3423            resolved.compiled_attention_policy,
3424            Some(AttentionExecutionPolicy::NativeAdaptive)
3425        );
3426        assert!(resolved
3427            .decisions
3428            .iter()
3429            .all(|decision| decision.selection != "recurrent_state_max_slots"));
3430        assert!(resolved
3431            .runtime_config
3432            .entries
3433            .iter()
3434            .all(|entry| !matches!(
3435                entry.key.as_str(),
3436                "FERRUM_RECURRENT_STATE_MAX_SLOTS"
3437                    | "FERRUM_USE_VLLM_PAGED_ATTN"
3438                    | "FERRUM_VLLM_PAGED_ATTN_V1_SHORT"
3439            )));
3440
3441        let document = resolved.effective_config_document();
3442        assert_eq!(document["selected_max_sequences"], serde_json::json!(32));
3443        assert_eq!(document["selected_admission_limit"], serde_json::json!(32));
3444        assert_eq!(
3445            document["selected_attention_policy"],
3446            serde_json::json!("native-adaptive")
3447        );
3448        assert_eq!(
3449            document["attention_execution"]["requested_policy"],
3450            serde_json::json!("auto")
3451        );
3452        assert_eq!(
3453            document["attention_execution"]["compiled_policy"],
3454            serde_json::json!("native-adaptive")
3455        );
3456        assert_eq!(
3457            document["attention_execution"]["legacy_attention_keys_apply"],
3458            serde_json::json!(false)
3459        );
3460        assert_eq!(
3461            document["admission"]["resource_authority"],
3462            serde_json::json!("plan_runtime")
3463        );
3464        assert_eq!(
3465            document["admission"]["effective_max_concurrent"],
3466            serde_json::json!(32)
3467        );
3468        assert_eq!(
3469            document["admission"]["legacy_recurrent_state_limit_applies"],
3470            serde_json::json!(false)
3471        );
3472    }
3473
3474    #[test]
3475    fn plan_runtime_preflight_labels_legacy_estimates_without_breaking_capacity_consumers() {
3476        let hardware =
3477            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3478        let model = synthetic_tight_recurrent_state_model();
3479        for authority in [
3480            ExecutionResourceAuthority::PlanRuntime,
3481            ExecutionResourceAuthority::LegacyEngine,
3482        ] {
3483            let document = FerrumConfigBuilder::new(snapshot(&[
3484                ("FERRUM_KV_DTYPE", "int8"),
3485                ("FERRUM_KV_CAPACITY", "512"),
3486            ]))
3487            .with_model_capabilities(model.clone())
3488            .with_hardware_capabilities(hardware.clone())
3489            .with_execution_resource_authority(authority)
3490            .resolve()
3491            .unwrap()
3492            .effective_config_document();
3493            assert_eq!(document["selected_kv_capacity"], 512);
3494            assert_eq!(
3495                document["selected_kv_capacity_source"],
3496                "configured_token_limit"
3497            );
3498            let admission = &document["admission"];
3499            for field in [
3500                "kv_block_count",
3501                "kv_block_size_tokens",
3502                "kv_capacity_tokens",
3503            ] {
3504                assert!(
3505                    admission[field].as_u64().is_some(),
3506                    "missing compatibility field {field}"
3507                );
3508            }
3509            assert_eq!(
3510                admission["kv_capacity_source"],
3511                "legacy_block_preflight_estimate"
3512            );
3513            assert_eq!(admission["kv_capacity_is_resident_usage"], false);
3514            assert_eq!(
3515                admission["kv_capacity_applies_to_selected_state_layout"],
3516                authority == ExecutionResourceAuthority::LegacyEngine
3517            );
3518            let estimate = &admission["memory_estimate"];
3519            assert_eq!(
3520                estimate["kv_bytes_per_token"],
3521                kv_cache_bytes_per_token_for_model(&model).unwrap()
3522            );
3523            assert_eq!(estimate["source"], "legacy_f16_geometry_estimate");
3524            assert_eq!(estimate["applies_to_selected_state_layout"], false);
3525            assert_eq!(estimate["is_resident_usage"], false);
3526            if authority == ExecutionResourceAuthority::PlanRuntime {
3527                assert_eq!(
3528                    estimate["selected_state_evidence_source"],
3529                    "executor.kv_storage.logical_sequence_state"
3530                );
3531            }
3532        }
3533    }
3534
3535    #[test]
3536    fn plan_runtime_int8_implicit_and_explicit_auto_resolve_to_compatible_attention() {
3537        let hardware =
3538            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3539        let resolve = |dtype, attention: Option<&str>| {
3540            let mut entries = vec![("FERRUM_KV_DTYPE", dtype)];
3541            if let Some(attention) = attention {
3542                entries.push(("FERRUM_ATTENTION_POLICY", attention));
3543            }
3544            FerrumConfigBuilder::new(snapshot(&entries))
3545                .with_hardware_capabilities(hardware.clone())
3546                .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3547                .resolve()
3548        };
3549        for requested in [None, Some("auto"), Some("portable")] {
3550            let resolved = resolve("int8", requested).unwrap();
3551            assert_eq!(
3552                resolved.compiled_attention_policy,
3553                Some(AttentionExecutionPolicy::Portable)
3554            );
3555            let mut engine = crate::EngineConfig::default();
3556            engine
3557                .apply_runtime_config_snapshot(&resolved.runtime_config)
3558                .unwrap();
3559            assert_eq!(
3560                engine
3561                    .runtime
3562                    .attention_execution_policy
3563                    .resolve(false)
3564                    .unwrap(),
3565                AttentionExecutionPolicy::Portable
3566            );
3567            assert_eq!(
3568                resolved.requested_attention_policy,
3569                Some(if requested == Some("portable") {
3570                    AttentionExecutionPolicy::Portable
3571                } else {
3572                    AttentionExecutionPolicy::Auto
3573                })
3574            );
3575        }
3576        assert!(
3577            matches!(resolve("int8", Some("native-adaptive")), Err(AutoConfigError::UnsupportedCombination {
3578            selection, reason,
3579        }) if selection == "attention_execution_policy" && reason.contains("INT8 KV"))
3580        );
3581        assert_eq!(
3582            resolve("fp16", None).unwrap().compiled_attention_policy,
3583            Some(AttentionExecutionPolicy::NativeAdaptive)
3584        );
3585    }
3586
3587    #[test]
3588    fn plan_runtime_context_and_batch_limits_do_not_inherit_legacy_kv_block_estimates() {
3589        let hardware =
3590            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3591        let mut model = ModelCapabilities::unknown();
3592        model.max_context_len = Some(131_072);
3593        // A tiny legacy block count is not vNext capacity authority. This is
3594        // preflight acceptance only: native admission still charges both INT8
3595        // payload and scales, physical alignment and operation workspace.
3596        for max_batched in ["16", "32"] {
3597            let entries = snapshot(&[
3598                ("FERRUM_KV_DTYPE", "int8"),
3599                ("FERRUM_KV_MAX_BLOCKS", "1"),
3600                ("FERRUM_PAGED_MAX_SEQS", "1"),
3601                ("FERRUM_MAX_BATCHED_TOKENS", max_batched),
3602                ("FERRUM_MAX_MODEL_LEN", "65536"),
3603            ]);
3604            let builder = FerrumConfigBuilder::new(entries.clone())
3605                .with_hardware_capabilities(hardware.clone())
3606                .with_model_capabilities(model.clone());
3607            assert!(
3608                builder.resolve().is_err(),
3609                "legacy capacity must remain enforced"
3610            );
3611            let resolved = FerrumConfigBuilder::new(entries)
3612                .with_hardware_capabilities(hardware.clone())
3613                .with_model_capabilities(model.clone())
3614                .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3615                .resolve()
3616                .unwrap();
3617            let mut engine = crate::EngineConfig::default();
3618            engine
3619                .apply_runtime_config_snapshot(&resolved.runtime_config)
3620                .unwrap();
3621            assert_eq!(engine.runtime.max_model_len, Some(65_536));
3622            assert_eq!(
3623                engine.batching.max_num_batched_tokens,
3624                max_batched.parse::<usize>().unwrap()
3625            );
3626        }
3627        let invalid = FerrumConfigBuilder::new(snapshot(&[("FERRUM_MAX_MODEL_LEN", "131073")]))
3628            .with_hardware_capabilities(hardware)
3629            .with_model_capabilities(model)
3630            .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3631            .resolve()
3632            .unwrap_err();
3633        assert!(
3634            matches!(invalid, AutoConfigError::InvalidOverride { key, .. } if key == "FERRUM_MAX_MODEL_LEN")
3635        );
3636    }
3637
3638    #[test]
3639    fn plan_runtime_rejects_legacy_attention_overrides() {
3640        let hardware =
3641            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3642        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3643        for key in [
3644            "FERRUM_USE_VLLM_PAGED_ATTN",
3645            "FERRUM_VLLM_PAGED_ATTN_V1_SHORT",
3646        ] {
3647            let error = FerrumConfigBuilder::new(snapshot(&[(key, "0")]))
3648                .with_model_capabilities(synthetic_tight_recurrent_state_model())
3649                .with_hardware_capabilities(hardware.clone())
3650                .with_workload_profile(workload.clone())
3651                .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3652                .resolve()
3653                .unwrap_err();
3654            assert!(matches!(
3655                error,
3656                AutoConfigError::InvalidOverride {
3657                    key: rejected_key,
3658                    reason,
3659                } if rejected_key == key && reason.contains("FERRUM_ATTENTION_POLICY")
3660            ));
3661        }
3662    }
3663
3664    #[test]
3665    fn plan_runtime_rejects_legacy_recurrent_slot_override() {
3666        let hardware =
3667            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3668        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3669        let error = FerrumConfigBuilder::new(snapshot(&[
3670            ("FERRUM_PAGED_MAX_SEQS", "32"),
3671            ("FERRUM_RECURRENT_STATE_MAX_SLOTS", "16"),
3672        ]))
3673        .with_model_capabilities(synthetic_tight_recurrent_state_model())
3674        .with_hardware_capabilities(hardware)
3675        .with_workload_profile(workload)
3676        .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3677        .resolve()
3678        .unwrap_err();
3679
3680        assert!(matches!(
3681            error,
3682            AutoConfigError::InvalidOverride { key, .. }
3683                if key == "FERRUM_RECURRENT_STATE_MAX_SLOTS"
3684        ));
3685    }
3686
3687    #[test]
3688    fn metal_plan_runtime_preflight_matches_portable_runtime_capability() {
3689        let mut hardware = HardwareCapabilities::unknown();
3690        hardware.backend = "metal".to_owned();
3691        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3692        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
3693            .with_model_capabilities(synthetic_tight_recurrent_state_model())
3694            .with_hardware_capabilities(hardware)
3695            .with_workload_profile(workload)
3696            .with_execution_resource_authority(ExecutionResourceAuthority::PlanRuntime)
3697            .resolve()
3698            .unwrap();
3699
3700        assert_eq!(
3701            resolved.compiled_attention_policy,
3702            Some(AttentionExecutionPolicy::Portable)
3703        );
3704        assert_eq!(
3705            resolved
3706                .decisions
3707                .iter()
3708                .find(|decision| decision.selection == "attention_decode_backend")
3709                .map(|decision| decision.selected.as_str()),
3710            Some("portable")
3711        );
3712    }
3713
3714    #[test]
3715    fn explicit_recurrent_state_slot_cap_can_keep_scheduler_width_above_state_pool() {
3716        let hardware =
3717            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3718        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3719        let resolved = FerrumConfigBuilder::new(snapshot(&[
3720            ("FERRUM_PAGED_MAX_SEQS", "32"),
3721            ("FERRUM_RECURRENT_STATE_MAX_SLOTS", "16"),
3722        ]))
3723        .with_model_capabilities(synthetic_tight_recurrent_state_model())
3724        .with_hardware_capabilities(hardware)
3725        .with_workload_profile(workload)
3726        .resolve()
3727        .unwrap();
3728        let decision = |selection: &str| {
3729            resolved
3730                .decisions
3731                .iter()
3732                .find(|decision| decision.selection == selection)
3733                .unwrap_or_else(|| panic!("missing decision {selection}"))
3734        };
3735        assert_eq!(decision("max_sequences").selected, "32");
3736        assert_eq!(decision("recurrent_state_max_slots").selected, "16");
3737        let entry = resolved
3738            .runtime_config
3739            .entries
3740            .iter()
3741            .find(|entry| entry.key == "FERRUM_RECURRENT_STATE_MAX_SLOTS")
3742            .expect("recurrent-state slot cap should reach effective runtime config");
3743        assert_eq!(entry.effective_value, "16");
3744    }
3745
3746    #[test]
3747    fn recurrent_state_budget_ignores_removed_qwen35_slot_alias() {
3748        let hardware =
3749            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3750        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3751        let resolved = FerrumConfigBuilder::new(snapshot(&[
3752            ("FERRUM_PAGED_MAX_SEQS", "32"),
3753            ("FERRUM_QWEN35_LINEAR_STATE_MAX_SLOTS", "7"),
3754        ]))
3755        .with_model_capabilities(synthetic_tight_recurrent_state_model())
3756        .with_hardware_capabilities(hardware)
3757        .with_workload_profile(workload)
3758        .resolve()
3759        .unwrap();
3760        let decision = resolved
3761            .decisions
3762            .iter()
3763            .find(|decision| decision.selection == "recurrent_state_max_slots")
3764            .expect("missing recurrent_state_max_slots decision");
3765        assert_eq!(decision.selected, "16");
3766        assert_eq!(decision.source, AutoConfigSource::MemoryProfile);
3767        assert_eq!(decision.source_key, None);
3768        assert!(resolved
3769            .runtime_config
3770            .entries
3771            .iter()
3772            .any(|entry| entry.key == "FERRUM_RECURRENT_STATE_MAX_SLOTS"
3773                && entry.effective_value == "16"));
3774    }
3775
3776    #[test]
3777    fn recurrent_state_budget_rejects_zero_slot_pool() {
3778        let hardware =
3779            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3780        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3781        let err = FerrumConfigBuilder::new(snapshot(&[
3782            ("FERRUM_PAGED_MAX_SEQS", "16"),
3783            ("FERRUM_RECURRENT_STATE_MAX_SLOTS", "0"),
3784        ]))
3785        .with_model_capabilities(synthetic_tight_recurrent_state_model())
3786        .with_hardware_capabilities(hardware)
3787        .with_workload_profile(workload)
3788        .resolve()
3789        .unwrap_err();
3790
3791        assert!(matches!(
3792            err,
3793            AutoConfigError::InvalidOverride { key, .. }
3794                if key == "FERRUM_RECURRENT_STATE_MAX_SLOTS"
3795        ));
3796    }
3797
3798    #[test]
3799    fn recurrent_state_budget_allows_c32_when_memory_budget_fits() {
3800        let mut hardware =
3801            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3802        hardware.vram_bytes = Some(48 * GIB);
3803        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3804        let resolved = FerrumConfigBuilder::new(snapshot(&[("FERRUM_PAGED_MAX_SEQS", "32")]))
3805            .with_model_capabilities(synthetic_tight_recurrent_state_model())
3806            .with_hardware_capabilities(hardware)
3807            .with_workload_profile(workload)
3808            .resolve()
3809            .unwrap();
3810        let max_sequences = resolved
3811            .decisions
3812            .iter()
3813            .find(|decision| decision.selection == "max_sequences")
3814            .unwrap();
3815        assert_eq!(max_sequences.selected, "32");
3816    }
3817
3818    #[test]
3819    fn cuda_qwen3_moe_vllm_paged_attn_env_opt_out_is_materialized() {
3820        let hardware =
3821            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
3822        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
3823        let resolved = FerrumConfigBuilder::new(snapshot(&[("FERRUM_USE_VLLM_PAGED_ATTN", "0")]))
3824            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
3825            .with_hardware_capabilities(hardware)
3826            .with_workload_profile(workload)
3827            .resolve()
3828            .unwrap();
3829        let decisions: BTreeMap<_, _> = resolved
3830            .decisions
3831            .iter()
3832            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
3833            .collect();
3834        assert_eq!(decisions["attention_decode_backend"], "legacy_paged_decode");
3835        let entry = resolved
3836            .runtime_config
3837            .entries
3838            .iter()
3839            .find(|entry| entry.key == "FERRUM_USE_VLLM_PAGED_ATTN")
3840            .expect("env opt-out should stay in effective config");
3841        assert_eq!(entry.effective_value, "0");
3842        assert_eq!(entry.source, RuntimeConfigSource::Env);
3843    }
3844
3845    #[test]
3846    fn qwen25_72b_layer_split_preset_selects_batch_tuned_defaults() {
3847        let resolved = FerrumConfigBuilder::new(qwen25_layer_split_runtime_entries(
3848            RuntimeConfigSource::Default,
3849        ))
3850        .with_model_capabilities(ModelCapabilities::qwen25_72b_gptq_int4())
3851        .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(
3852            CompiledKernelFeatures::m3_fast_path_without_fa2(),
3853        ))
3854        .with_workload_profile(WorkloadProfile::qwen25_72b_gptq_int4_2x4090_layer_split())
3855        .resolve()
3856        .unwrap();
3857        let decision = |selection: &str| {
3858            resolved
3859                .decisions
3860                .iter()
3861                .find(|decision| decision.selection == selection)
3862                .unwrap_or_else(|| panic!("missing decision {selection}"))
3863        };
3864
3865        assert_eq!(
3866            resolved.preset.as_deref(),
3867            Some(QWEN25_72B_GPTQ_INT4_2X4090_LAYER_SPLIT_PRESET)
3868        );
3869        assert_eq!(decision("kv_block_count").selected, "1024");
3870        assert_eq!(decision("max_sequences").selected, "16");
3871        assert_eq!(decision("max_batched_tokens").selected, "1536");
3872        assert_eq!(decision("max_model_len").selected, "4096");
3873        assert_eq!(
3874            decision("scheduler_admission_policy").selected,
3875            "prefill_first_until_active:16+prefill_token_budget:elastic"
3876        );
3877        assert_eq!(
3878            decision("scheduler_admission_policy").source,
3879            AutoConfigSource::Default
3880        );
3881
3882        let doc = resolved.effective_config_document();
3883        assert_eq!(doc["selected_pipeline_mode"], "batch");
3884        assert_eq!(doc["selected_microbatch_size"], 16);
3885        assert_eq!(doc["selected_kv_capacity"], 1024);
3886    }
3887
3888    #[test]
3889    fn source_fa2_is_rejected_even_when_legacy_feature_is_compiled() {
3890        let err = m3(
3891            &[("FERRUM_FA2_SOURCE", "1")],
3892            CompiledKernelFeatures::m3_fast_path_with_source_fa2(),
3893        )
3894        .resolve()
3895        .unwrap_err();
3896
3897        match err {
3898            AutoConfigError::InvalidOverride { key, reason } => {
3899                assert_eq!(key, "FERRUM_FA2_SOURCE");
3900                assert!(reason.contains("native operator artifact"));
3901            }
3902            AutoConfigError::UnsupportedCombination { .. } => {
3903                panic!("expected invalid FERRUM_FA2_SOURCE override")
3904            }
3905        }
3906    }
3907
3908    #[test]
3909    fn source_fa2_is_rejected_when_not_compiled() {
3910        expect_invalid_key(&[("FERRUM_FA2_SOURCE", "1")], "FERRUM_FA2_SOURCE");
3911    }
3912
3913    #[test]
3914    fn fa2_native_artifact_typed_config_is_recorded_without_selecting_runtime_path() {
3915        let resolved = m3(
3916            &[
3917                (
3918                    FA2_NATIVE_MANIFEST_KEY,
3919                    "/tmp/native/fa2/native_operator_manifest.json",
3920                ),
3921                (
3922                    FA2_NATIVE_ARTIFACT_KEY,
3923                    "/tmp/native/fa2/libferrum_native_fa2.a",
3924                ),
3925                (
3926                    FA2_NATIVE_SOURCE_SHA256_KEY,
3927                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3928                ),
3929                (
3930                    FA2_NATIVE_INPUTS_SHA256_KEY,
3931                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
3932                ),
3933            ],
3934            CompiledKernelFeatures::m3_fast_path_with_native_fa2_artifact(),
3935        )
3936        .resolve()
3937        .unwrap();
3938
3939        let decisions: BTreeMap<_, _> = resolved
3940            .decisions
3941            .iter()
3942            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
3943            .collect();
3944        assert_eq!(decisions["fa2_native_operator_artifact"], "configured");
3945        assert_eq!(
3946            decisions["fa2_native_operator_runtime_selection"],
3947            "not_selected"
3948        );
3949        assert_ne!(decisions["attention_prefill_mixed_backend"], "fa2_native");
3950        assert!(resolved
3951            .runtime_config
3952            .entries
3953            .iter()
3954            .any(|entry| entry.key == FA2_NATIVE_MANIFEST_KEY
3955                && entry.source == RuntimeConfigSource::Env));
3956    }
3957
3958    #[test]
3959    fn fa2_native_runtime_selection_is_explicit_when_not_configured() {
3960        let resolved = m3(&[], CompiledKernelFeatures::m3_fast_path_without_fa2())
3961            .resolve()
3962            .unwrap();
3963        let decision = resolved
3964            .decisions
3965            .iter()
3966            .find(|decision| decision.selection == "fa2_native_operator_runtime_selection")
3967            .unwrap();
3968        assert_eq!(decision.selected, "not_configured");
3969        assert!(decision.rejected.iter().any(|candidate| {
3970            candidate.value == "selected"
3971                && candidate
3972                    .reason
3973                    .contains("artifact-selected actual model smoke")
3974        }));
3975    }
3976
3977    #[test]
3978    fn fa2_native_artifact_requires_manifest_artifact_pair_and_valid_pins() {
3979        expect_invalid_key(
3980            &[(
3981                FA2_NATIVE_MANIFEST_KEY,
3982                "/tmp/native/fa2/native_operator_manifest.json",
3983            )],
3984            FA2_NATIVE_ARTIFACT_KEY,
3985        );
3986        expect_invalid_key(
3987            &[(
3988                FA2_NATIVE_ARTIFACT_KEY,
3989                "/tmp/native/fa2/libferrum_native_fa2.a",
3990            )],
3991            FA2_NATIVE_MANIFEST_KEY,
3992        );
3993        expect_invalid_key(
3994            &[
3995                (
3996                    FA2_NATIVE_MANIFEST_KEY,
3997                    "/tmp/native/fa2/native_operator_manifest.json",
3998                ),
3999                (
4000                    FA2_NATIVE_ARTIFACT_KEY,
4001                    "/tmp/native/fa2/libferrum_native_fa2.a",
4002                ),
4003                (FA2_NATIVE_SOURCE_SHA256_KEY, "not-a-sha"),
4004            ],
4005            FA2_NATIVE_SOURCE_SHA256_KEY,
4006        );
4007        expect_invalid_key(
4008            &[(
4009                FA2_NATIVE_INPUTS_SHA256_KEY,
4010                "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
4011            )],
4012            FA2_NATIVE_INPUTS_SHA256_KEY,
4013        );
4014    }
4015
4016    #[test]
4017    fn fa2_native_artifact_requires_linked_binary_capability() {
4018        expect_invalid_key(
4019            &[
4020                (
4021                    FA2_NATIVE_MANIFEST_KEY,
4022                    "/tmp/native/fa2/native_operator_manifest.json",
4023                ),
4024                (
4025                    FA2_NATIVE_ARTIFACT_KEY,
4026                    "/tmp/native/fa2/libferrum_native_fa2.a",
4027                ),
4028            ],
4029            FA2_NATIVE_MANIFEST_KEY,
4030        );
4031    }
4032
4033    #[test]
4034    fn fa2_native_artifact_requires_linked_binary_metadata() {
4035        let mut features = CompiledKernelFeatures::m3_fast_path_without_fa2();
4036        features.fa2_native_operator_artifact = true;
4037
4038        let err = m3(
4039            &[
4040                (
4041                    FA2_NATIVE_MANIFEST_KEY,
4042                    "/tmp/native/fa2/native_operator_manifest.json",
4043                ),
4044                (
4045                    FA2_NATIVE_ARTIFACT_KEY,
4046                    "/tmp/native/fa2/libferrum_native_fa2.a",
4047                ),
4048            ],
4049            features,
4050        )
4051        .resolve()
4052        .unwrap_err();
4053        match err {
4054            AutoConfigError::InvalidOverride { key, reason } => {
4055                assert_eq!(key, FA2_NATIVE_MANIFEST_KEY);
4056                assert!(reason.contains("missing build metadata"));
4057            }
4058            other => panic!("expected invalid override, got {other:?}"),
4059        }
4060    }
4061
4062    #[test]
4063    fn fa2_native_artifact_must_match_linked_binary_metadata() {
4064        let features = CompiledKernelFeatures::m3_fast_path_with_native_fa2_artifact();
4065        expect_invalid_key_with_features(
4066            &[
4067                (
4068                    FA2_NATIVE_MANIFEST_KEY,
4069                    "/tmp/native/fa2/other_manifest.json",
4070                ),
4071                (
4072                    FA2_NATIVE_ARTIFACT_KEY,
4073                    "/tmp/native/fa2/libferrum_native_fa2.a",
4074                ),
4075            ],
4076            FA2_NATIVE_MANIFEST_KEY,
4077            features.clone(),
4078        );
4079        expect_invalid_key_with_features(
4080            &[
4081                (
4082                    FA2_NATIVE_MANIFEST_KEY,
4083                    "/tmp/native/fa2/native_operator_manifest.json",
4084                ),
4085                (
4086                    FA2_NATIVE_ARTIFACT_KEY,
4087                    "/tmp/native/fa2/libferrum_native_other.a",
4088                ),
4089            ],
4090            FA2_NATIVE_ARTIFACT_KEY,
4091            features.clone(),
4092        );
4093        expect_invalid_key_with_features(
4094            &[
4095                (
4096                    FA2_NATIVE_MANIFEST_KEY,
4097                    "/tmp/native/fa2/native_operator_manifest.json",
4098                ),
4099                (
4100                    FA2_NATIVE_ARTIFACT_KEY,
4101                    "/tmp/native/fa2/libferrum_native_fa2.a",
4102                ),
4103                (
4104                    FA2_NATIVE_SOURCE_SHA256_KEY,
4105                    "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
4106                ),
4107            ],
4108            FA2_NATIVE_SOURCE_SHA256_KEY,
4109            features.clone(),
4110        );
4111        expect_invalid_key_with_features(
4112            &[
4113                (
4114                    FA2_NATIVE_MANIFEST_KEY,
4115                    "/tmp/native/fa2/native_operator_manifest.json",
4116                ),
4117                (
4118                    FA2_NATIVE_ARTIFACT_KEY,
4119                    "/tmp/native/fa2/libferrum_native_fa2.a",
4120                ),
4121                (
4122                    FA2_NATIVE_INPUTS_SHA256_KEY,
4123                    "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
4124                ),
4125            ],
4126            FA2_NATIVE_INPUTS_SHA256_KEY,
4127            features,
4128        );
4129    }
4130
4131    #[test]
4132    fn fa2_native_artifact_requires_cuda_backend() {
4133        let hardware =
4134            cpu_hardware_with_features(CompiledKernelFeatures::m3_fast_path_without_fa2());
4135        expect_invalid_key_with_hardware(
4136            &[
4137                (
4138                    FA2_NATIVE_MANIFEST_KEY,
4139                    "/tmp/native/fa2/native_operator_manifest.json",
4140                ),
4141                (
4142                    FA2_NATIVE_ARTIFACT_KEY,
4143                    "/tmp/native/fa2/libferrum_native_fa2.a",
4144                ),
4145            ],
4146            FA2_NATIVE_MANIFEST_KEY,
4147            hardware,
4148        );
4149    }
4150
4151    #[test]
4152    fn hardware_capabilities_keep_m3_preset_on_compatible_backend_paths() {
4153        let resolved = m3_with_hardware(
4154            &[],
4155            cpu_hardware_with_features(CompiledKernelFeatures::m3_fast_path_with_source_fa2()),
4156        )
4157        .resolve()
4158        .unwrap();
4159        let decisions: BTreeMap<_, _> = resolved
4160            .decisions
4161            .iter()
4162            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
4163            .collect();
4164
4165        assert_eq!(
4166            decisions["attention_prefill_mixed_backend"],
4167            "legacy_paged_varlen"
4168        );
4169        assert_eq!(decisions["attention_decode_backend"], "legacy_paged_decode");
4170        assert_eq!(decisions["moe_implementation"], "legacy_moe");
4171        assert_eq!(decisions["moe_graph_policy"], "graph_disabled");
4172        assert_eq!(decisions["sampling_readback_path"], "logits_readback");
4173    }
4174
4175    #[test]
4176    fn effective_config_document_records_cuda_gpu_device_selection() {
4177        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[
4178            (
4179                "FERRUM_REQUESTED_GPU_DEVICES",
4180                "0,1",
4181                RuntimeConfigSource::Cli,
4182            ),
4183            (
4184                "FERRUM_SELECTED_GPU_DEVICES",
4185                "0,1",
4186                RuntimeConfigSource::Cli,
4187            ),
4188            ("FERRUM_CUDA_DEVICE_COUNT", "2", RuntimeConfigSource::Cli),
4189            (
4190                "FERRUM_SELECTED_DISTRIBUTED_STRATEGY",
4191                "layer_split",
4192                RuntimeConfigSource::Cli,
4193            ),
4194            (
4195                "FERRUM_SELECTED_LAYER_SPLIT_PLAN",
4196                "stage0:cuda:0:layers=0-39;stage1:cuda:1:layers=40-79",
4197                RuntimeConfigSource::Cli,
4198            ),
4199            (
4200                "FERRUM_SELECTED_LAYER_SPLIT_STAGES",
4201                r#"[{"stage":0,"device":0,"layer_start":0,"layer_end":39},{"stage":1,"device":1,"layer_start":40,"layer_end":79}]"#,
4202                RuntimeConfigSource::Cli,
4203            ),
4204            ("FERRUM_KV_CAPACITY", "512", RuntimeConfigSource::Cli),
4205        ]))
4206        .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(
4207            CompiledKernelFeatures::m3_fast_path_without_fa2(),
4208        ))
4209        .resolve()
4210        .unwrap();
4211
4212        let doc = resolved.effective_config_document();
4213        assert_eq!(doc["backend"], "cuda");
4214        assert_eq!(doc["requested_gpu_devices"], serde_json::json!([0, 1]));
4215        assert_eq!(doc["selected_gpu_devices"], serde_json::json!([0, 1]));
4216        assert_eq!(doc["cuda_device_count"], 2);
4217        assert_eq!(doc["selected_distributed_strategy"], "layer_split");
4218        assert_eq!(
4219            doc["selected_layer_split_plan"],
4220            "stage0:cuda:0:layers=0-39;stage1:cuda:1:layers=40-79"
4221        );
4222        assert_eq!(
4223            doc["selected_layer_split_stages"],
4224            serde_json::json!([
4225                {"stage": 0, "device": 0, "layer_start": 0, "layer_end": 39},
4226                {"stage": 1, "device": 1, "layer_start": 40, "layer_end": 79}
4227            ])
4228        );
4229        assert_eq!(doc["selected_weight_placement"], "layer_split");
4230        assert_eq!(doc["selected_pipeline_mode"], "overlapped");
4231        assert_eq!(doc["selected_stage_bridge"], "host");
4232        assert_eq!(
4233            doc["selected_microbatch_size"],
4234            serde_json::json!(doc["selected_max_sequences"].as_u64().unwrap().div_ceil(2))
4235        );
4236        assert_eq!(
4237            doc["selected_admission_limit"],
4238            doc["selected_max_sequences"]
4239        );
4240        assert_eq!(doc["selected_kv_capacity"], 512);
4241    }
4242
4243    #[test]
4244    fn effective_config_document_honors_explicit_layer_split_batch_mode() {
4245        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[
4246            (
4247                "FERRUM_REQUESTED_GPU_DEVICES",
4248                "0,1",
4249                RuntimeConfigSource::Cli,
4250            ),
4251            (
4252                "FERRUM_SELECTED_GPU_DEVICES",
4253                "0,1",
4254                RuntimeConfigSource::Cli,
4255            ),
4256            (
4257                "FERRUM_SELECTED_DISTRIBUTED_STRATEGY",
4258                "layer_split",
4259                RuntimeConfigSource::Cli,
4260            ),
4261            (
4262                "FERRUM_SELECTED_LAYER_SPLIT_PLAN",
4263                "stage0:cuda:0:layers=0-39;stage1:cuda:1:layers=40-79",
4264                RuntimeConfigSource::Cli,
4265            ),
4266            (
4267                "FERRUM_LAYER_SPLIT_PIPELINE_MODE",
4268                "batch",
4269                RuntimeConfigSource::Cli,
4270            ),
4271            ("FERRUM_PAGED_MAX_SEQS", "16", RuntimeConfigSource::Cli),
4272        ]))
4273        .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(
4274            CompiledKernelFeatures::m3_fast_path_without_fa2(),
4275        ))
4276        .resolve()
4277        .unwrap();
4278
4279        let doc = resolved.effective_config_document();
4280        assert_eq!(doc["selected_pipeline_mode"], "batch");
4281        assert_eq!(doc["selected_microbatch_size"], 16);
4282    }
4283
4284    #[test]
4285    fn invalid_layer_split_pipeline_mode_is_rejected() {
4286        expect_invalid_key_with_hardware(
4287            &[("FERRUM_LAYER_SPLIT_PIPELINE_MODE", "serial")],
4288            "FERRUM_LAYER_SPLIT_PIPELINE_MODE",
4289            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2()),
4290        );
4291    }
4292
4293    #[test]
4294    fn hardware_incompatible_attention_and_sampling_overrides_are_rejected() {
4295        let cpu =
4296            cpu_hardware_with_features(CompiledKernelFeatures::m3_fast_path_with_source_fa2());
4297        expect_invalid_key_with_hardware(
4298            &[("FERRUM_USE_VLLM_PAGED_ATTN", "1")],
4299            "FERRUM_USE_VLLM_PAGED_ATTN",
4300            cpu.clone(),
4301        );
4302        expect_invalid_key_with_hardware(
4303            &[("FERRUM_VLLM_MOE", "1")],
4304            "FERRUM_VLLM_MOE",
4305            cpu.clone(),
4306        );
4307        expect_invalid_key_with_hardware(
4308            &[("FERRUM_GREEDY_ARGMAX", "1")],
4309            "FERRUM_GREEDY_ARGMAX",
4310            cpu.clone(),
4311        );
4312        expect_invalid_key_with_hardware(&[("FERRUM_FA2_SOURCE", "1")], "FERRUM_FA2_SOURCE", cpu);
4313
4314        let mut old_cuda = HardwareCapabilities::rtx4090_cuda(
4315            CompiledKernelFeatures::m3_fast_path_with_source_fa2(),
4316        );
4317        old_cuda.compute_capability = Some("7.5".to_string());
4318        expect_invalid_key_with_hardware(
4319            &[("FERRUM_FA2_SOURCE", "1")],
4320            "FERRUM_FA2_SOURCE",
4321            old_cuda,
4322        );
4323    }
4324
4325    #[test]
4326    fn hardware_capacity_sizes_default_sequence_budget_without_overriding_user_values() {
4327        let mut small_gpu =
4328            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4329        small_gpu.sm_count = Some(16);
4330        small_gpu.vram_bytes = Some(24 * 1024 * 1024 * 1024);
4331
4332        let resolved = m3_with_hardware(&[], small_gpu.clone()).resolve().unwrap();
4333        let decision = |selection: &str| {
4334            resolved
4335                .decisions
4336                .iter()
4337                .find(|decision| decision.selection == selection)
4338                .unwrap()
4339        };
4340        let max_sequences = decision("max_sequences");
4341        assert_eq!(max_sequences.selected, "4");
4342        assert_eq!(max_sequences.source, AutoConfigSource::HardwareCapability);
4343        let max_batched_tokens = decision("max_batched_tokens");
4344        assert_eq!(max_batched_tokens.selected, "256");
4345        assert_eq!(
4346            max_batched_tokens.source,
4347            AutoConfigSource::HardwareCapability
4348        );
4349
4350        let resolved = m3_with_hardware(&[("FERRUM_PAGED_MAX_SEQS", "16")], small_gpu)
4351            .resolve()
4352            .unwrap();
4353        let max_sequences = resolved
4354            .decisions
4355            .iter()
4356            .find(|decision| decision.selection == "max_sequences")
4357            .unwrap();
4358        assert_eq!(max_sequences.selected, "16");
4359        assert_eq!(max_sequences.source, AutoConfigSource::Env);
4360        assert_eq!(
4361            max_sequences.source_key.as_deref(),
4362            Some("FERRUM_PAGED_MAX_SEQS")
4363        );
4364    }
4365
4366    #[test]
4367    fn vram_capacity_caps_m3_default_sequence_budget() {
4368        let mut low_vram_gpu =
4369            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4370        low_vram_gpu.sm_count = Some(128);
4371        low_vram_gpu.vram_bytes = Some(7 * 1024 * 1024 * 1024);
4372
4373        let resolved = m3_with_hardware(&[], low_vram_gpu).resolve().unwrap();
4374        let max_sequences = resolved
4375            .decisions
4376            .iter()
4377            .find(|decision| decision.selection == "max_sequences")
4378            .unwrap();
4379        assert_eq!(max_sequences.selected, "4");
4380        assert_eq!(max_sequences.source, AutoConfigSource::HardwareCapability);
4381    }
4382
4383    #[test]
4384    fn memory_budget_keeps_rtx4090_m3_kv_blocks_but_caps_constrained_vram() {
4385        let resolved = m3(&[], CompiledKernelFeatures::m3_fast_path_without_fa2())
4386            .resolve()
4387            .unwrap();
4388        let decision = |selection: &str| {
4389            resolved
4390                .decisions
4391                .iter()
4392                .find(|decision| decision.selection == selection)
4393                .unwrap()
4394        };
4395        assert_eq!(decision("kv_block_count").selected, "2048");
4396        assert_eq!(
4397            decision("kv_block_count").source,
4398            AutoConfigSource::WorkloadPreset
4399        );
4400
4401        let mut constrained =
4402            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4403        constrained.vram_bytes = Some(20 * 1024 * 1024 * 1024);
4404        let resolved = m3_with_hardware(&[], constrained).resolve().unwrap();
4405        let decision = |selection: &str| {
4406            resolved
4407                .decisions
4408                .iter()
4409                .find(|decision| decision.selection == selection)
4410                .unwrap()
4411        };
4412        assert_eq!(decision("kv_block_count").selected, "2");
4413        assert_eq!(
4414            decision("kv_block_count").source,
4415            AutoConfigSource::HardwareCapability
4416        );
4417        assert_eq!(decision("max_batched_tokens").selected, "32");
4418        assert_eq!(
4419            decision("max_batched_tokens").source,
4420            AutoConfigSource::HardwareCapability
4421        );
4422    }
4423
4424    #[test]
4425    fn compute_capability_parser_accepts_major_minor_and_major_only() {
4426        assert_eq!(parse_compute_capability("8.9"), Some((8, 9)));
4427        assert_eq!(parse_compute_capability("9"), Some((9, 0)));
4428        assert_eq!(parse_compute_capability("N/A"), None);
4429    }
4430
4431    #[test]
4432    fn vram_capacity_tiers_are_monotonic() {
4433        assert_eq!(vram_default_max_sequences(24 * 1024 * 1024 * 1024), 32);
4434        assert_eq!(vram_default_max_sequences(16 * 1024 * 1024 * 1024), 16);
4435        assert_eq!(vram_default_max_sequences(8 * 1024 * 1024 * 1024), 8);
4436        assert_eq!(vram_default_max_sequences(6 * 1024 * 1024 * 1024), 4);
4437    }
4438
4439    #[test]
4440    fn accelerator_serving_default_uses_hardware_concurrency_budget() {
4441        let hardware =
4442            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4443        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4444        assert_eq!(workload.target_concurrency, 32);
4445
4446        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
4447            .with_model_capabilities(ModelCapabilities::unknown())
4448            .with_hardware_capabilities(hardware)
4449            .with_workload_profile(workload)
4450            .resolve()
4451            .unwrap();
4452        let max_sequences = resolved
4453            .decisions
4454            .iter()
4455            .find(|decision| decision.selection == "max_sequences")
4456            .unwrap();
4457        assert_eq!(max_sequences.selected, "32");
4458        let scheduler = resolved
4459            .decisions
4460            .iter()
4461            .find(|decision| decision.selection == "scheduler_admission_policy")
4462            .unwrap();
4463        assert_eq!(
4464            scheduler.selected,
4465            "prefill_first_until_active:32+prefill_token_budget:elastic"
4466        );
4467        assert_eq!(scheduler.source, AutoConfigSource::Default);
4468        let scheduler_entry = resolved
4469            .runtime_config
4470            .entries
4471            .iter()
4472            .find(|entry| entry.key == "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE")
4473            .unwrap_or_else(|| panic!("missing FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE entry"));
4474        assert_eq!(scheduler_entry.effective_value, "32");
4475        assert_eq!(scheduler_entry.source, RuntimeConfigSource::Default);
4476        assert!(resolved
4477            .runtime_config
4478            .entries
4479            .iter()
4480            .all(|entry| entry.key != "FERRUM_SCHED_PREFILL_STEP_CHUNK"));
4481    }
4482
4483    #[test]
4484    fn accelerator_serving_default_enables_greedy_argmax_when_compiled() {
4485        let hardware =
4486            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4487        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4488        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
4489            .with_model_capabilities(ModelCapabilities::unknown())
4490            .with_hardware_capabilities(hardware)
4491            .with_workload_profile(workload)
4492            .resolve()
4493            .unwrap();
4494        let sampling = resolved
4495            .decisions
4496            .iter()
4497            .find(|decision| decision.selection == "sampling_readback_path")
4498            .unwrap();
4499        assert_eq!(sampling.selected, "gpu_greedy_argmax");
4500        assert_eq!(sampling.source, AutoConfigSource::HardwareCapability);
4501        let greedy_entry = resolved
4502            .runtime_config
4503            .entries
4504            .iter()
4505            .find(|entry| entry.key == "FERRUM_GREEDY_ARGMAX")
4506            .unwrap_or_else(|| panic!("missing FERRUM_GREEDY_ARGMAX entry"));
4507        assert_eq!(greedy_entry.effective_value, "1");
4508    }
4509
4510    #[test]
4511    fn explicit_greedy_argmax_disable_keeps_logits_readback() {
4512        let hardware =
4513            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4514        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4515        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[(
4516            "FERRUM_GREEDY_ARGMAX",
4517            "0",
4518            RuntimeConfigSource::Cli,
4519        )]))
4520        .with_model_capabilities(ModelCapabilities::unknown())
4521        .with_hardware_capabilities(hardware)
4522        .with_workload_profile(workload)
4523        .resolve()
4524        .unwrap();
4525        let sampling = resolved
4526            .decisions
4527            .iter()
4528            .find(|decision| decision.selection == "sampling_readback_path")
4529            .unwrap();
4530        assert_eq!(sampling.selected, "logits_readback");
4531        assert_eq!(sampling.source, AutoConfigSource::Cli);
4532        let greedy_entry = resolved
4533            .runtime_config
4534            .entries
4535            .iter()
4536            .find(|entry| entry.key == "FERRUM_GREEDY_ARGMAX")
4537            .unwrap_or_else(|| panic!("missing FERRUM_GREEDY_ARGMAX entry"));
4538        assert_eq!(greedy_entry.effective_value, "0");
4539    }
4540
4541    #[test]
4542    fn cpu_serving_default_keeps_single_sequence_budget() {
4543        let hardware = HardwareCapabilities {
4544            backend: "cpu".to_string(),
4545            supported_dtypes: vec!["fp32".to_string()],
4546            ..HardwareCapabilities::unknown()
4547        };
4548        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4549        assert_eq!(workload.target_concurrency, 1);
4550        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
4551            .with_model_capabilities(ModelCapabilities::unknown())
4552            .with_hardware_capabilities(hardware)
4553            .with_workload_profile(workload)
4554            .resolve()
4555            .unwrap();
4556        let scheduler = resolved
4557            .decisions
4558            .iter()
4559            .find(|decision| decision.selection == "scheduler_admission_policy")
4560            .unwrap();
4561        assert_eq!(scheduler.selected, "prompt_token_estimate");
4562        assert!(resolved
4563            .runtime_config
4564            .entries
4565            .iter()
4566            .all(|entry| entry.key != "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE"));
4567        assert!(resolved
4568            .runtime_config
4569            .entries
4570            .iter()
4571            .all(|entry| entry.key != "FERRUM_SCHED_PREFILL_STEP_CHUNK"));
4572    }
4573
4574    #[test]
4575    fn validates_invalid_override_matrix() {
4576        expect_invalid_key(
4577            &[("FERRUM_USE_VLLM_PAGED_ATTN", "maybe")],
4578            "FERRUM_USE_VLLM_PAGED_ATTN",
4579        );
4580        expect_invalid_key(&[("FERRUM_PREFIX_CACHE", "maybe")], "FERRUM_PREFIX_CACHE");
4581        expect_invalid_key(
4582            &[
4583                ("FERRUM_FA_LAYOUT_VARLEN", "1"),
4584                ("FERRUM_USE_VLLM_PAGED_ATTN", "0"),
4585            ],
4586            "FERRUM_FA_LAYOUT_VARLEN",
4587        );
4588        expect_invalid_key(&[("FERRUM_FA2_DIRECT_FFI", "1")], "FERRUM_FA2_DIRECT_FFI");
4589        expect_invalid_key_with_features(
4590            &[("FERRUM_VLLM_MOE", "1")],
4591            "FERRUM_VLLM_MOE",
4592            CompiledKernelFeatures::default(),
4593        );
4594        expect_invalid_key(
4595            &[("FERRUM_MOE_DEVICE_ROUTE", "1"), ("FERRUM_VLLM_MOE", "0")],
4596            "FERRUM_MOE_DEVICE_ROUTE",
4597        );
4598        expect_invalid_key(
4599            &[("FERRUM_VLLM_MOE_PAIR_IDS", "1"), ("FERRUM_VLLM_MOE", "0")],
4600            "FERRUM_VLLM_MOE_PAIR_IDS",
4601        );
4602        expect_invalid_key(
4603            &[("FERRUM_MOE_GRAPH", "1"), ("FERRUM_VLLM_MOE", "0")],
4604            "FERRUM_MOE_GRAPH",
4605        );
4606        expect_invalid_key(&[("FERRUM_KV_MAX_BLOCKS", "0")], "FERRUM_KV_MAX_BLOCKS");
4607        expect_invalid_key(&[("FERRUM_PAGED_MAX_SEQS", "0")], "FERRUM_PAGED_MAX_SEQS");
4608        expect_invalid_key(
4609            &[
4610                ("FERRUM_PAGED_MAX_SEQS", "32"),
4611                ("FERRUM_MAX_BATCHED_TOKENS", "16"),
4612            ],
4613            "FERRUM_MAX_BATCHED_TOKENS",
4614        );
4615        expect_invalid_key(
4616            &[
4617                ("FERRUM_KV_MAX_BLOCKS", "16"),
4618                ("FERRUM_MAX_BATCHED_TOKENS", "512"),
4619            ],
4620            "FERRUM_MAX_BATCHED_TOKENS",
4621        );
4622        expect_invalid_key(&[("FERRUM_MAX_MODEL_LEN", "0")], "FERRUM_MAX_MODEL_LEN");
4623        expect_invalid_key(&[("FERRUM_MAX_MODEL_LEN", "50000")], "FERRUM_MAX_MODEL_LEN");
4624        expect_invalid_key(
4625            &[
4626                ("FERRUM_KV_MAX_BLOCKS", "16"),
4627                ("FERRUM_MAX_MODEL_LEN", "1024"),
4628            ],
4629            "FERRUM_KV_MAX_BLOCKS",
4630        );
4631        expect_invalid_key(&[("FERRUM_DTYPE", "bf16")], "FERRUM_DTYPE");
4632        expect_invalid_key(&[("FERRUM_KV_DTYPE", "fp8")], "FERRUM_KV_DTYPE");
4633        expect_invalid_key(
4634            &[
4635                ("FERRUM_VLLM_PAGED_ATTN_V1_SHORT", "1"),
4636                ("FERRUM_USE_VLLM_PAGED_ATTN", "0"),
4637            ],
4638            "FERRUM_VLLM_PAGED_ATTN_V1_SHORT",
4639        );
4640    }
4641
4642    #[test]
4643    fn requested_max_model_len_is_optional_and_reflected_when_valid() {
4644        let default_resolved = m3(&[], CompiledKernelFeatures::m3_fast_path_without_fa2())
4645            .resolve()
4646            .unwrap();
4647        assert!(!default_resolved
4648            .decisions
4649            .iter()
4650            .any(|decision| decision.selection == "max_model_len"));
4651
4652        let resolved = m3(
4653            &[
4654                ("FERRUM_KV_MAX_BLOCKS", "64"),
4655                ("FERRUM_MAX_MODEL_LEN", "1024"),
4656            ],
4657            CompiledKernelFeatures::m3_fast_path_without_fa2(),
4658        )
4659        .resolve()
4660        .unwrap();
4661        let max_model_len = resolved
4662            .decisions
4663            .iter()
4664            .find(|decision| decision.selection == "max_model_len")
4665            .unwrap();
4666        assert_eq!(max_model_len.selected, "1024");
4667        assert_eq!(
4668            max_model_len.source_key.as_deref(),
4669            Some("FERRUM_MAX_MODEL_LEN")
4670        );
4671    }
4672
4673    #[test]
4674    fn graph_enabled_with_graph_unsafe_moe_is_rejected() {
4675        let mut model = ModelCapabilities::qwen3_30b_a3b_gptq_int4();
4676        model.graph_safe_moe = false;
4677        let err = FerrumConfigBuilder::new(snapshot(&[("FERRUM_MOE_GRAPH", "1")]))
4678            .with_model_capabilities(model)
4679            .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(
4680                CompiledKernelFeatures::m3_fast_path_without_fa2(),
4681            ))
4682            .with_workload_profile(WorkloadProfile::m3_qwen3_30b_a3b_int4())
4683            .resolve()
4684            .expect_err("graph unsafe MoE must fail");
4685        assert!(matches!(
4686            err,
4687            AutoConfigError::UnsupportedCombination {
4688                selection,
4689                ..
4690            } if selection == "moe_graph_policy"
4691        ));
4692    }
4693
4694    #[test]
4695    fn batched_graph_override_materializes_decode_graph_policy() {
4696        let hardware =
4697            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4698        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4699        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[(
4700            "FERRUM_BATCHED_GRAPH",
4701            "1",
4702            RuntimeConfigSource::Cli,
4703        )]))
4704        .with_model_capabilities(ModelCapabilities::unknown())
4705        .with_hardware_capabilities(hardware)
4706        .with_workload_profile(workload)
4707        .resolve()
4708        .unwrap();
4709        let decisions: BTreeMap<_, _> = resolved
4710            .decisions
4711            .iter()
4712            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
4713            .collect();
4714        assert_eq!(
4715            decisions["decode_graph_policy"],
4716            "legacy_batched_decode_graph"
4717        );
4718        let entry = resolved
4719            .runtime_config
4720            .entries
4721            .iter()
4722            .find(|entry| entry.key == "FERRUM_BATCHED_GRAPH")
4723            .expect("batched graph entry");
4724        assert_eq!(entry.effective_value, "1");
4725        assert_eq!(
4726            resolved.effective_config_document()["selected_graph_mode"],
4727            "legacy_batched_decode_graph"
4728        );
4729    }
4730
4731    #[test]
4732    fn reusable_execution_defaults_on_without_enabling_legacy_graphs() {
4733        let hardware =
4734            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4735        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4736        let resolved = FerrumConfigBuilder::new(RuntimeConfigSnapshot::default())
4737            .with_model_capabilities(ModelCapabilities::unknown())
4738            .with_hardware_capabilities(hardware)
4739            .with_workload_profile(workload)
4740            .resolve()
4741            .unwrap();
4742        let entry = |key: &str| {
4743            resolved
4744                .runtime_config
4745                .entries
4746                .iter()
4747                .find(|entry| entry.key == key)
4748                .unwrap_or_else(|| panic!("missing {key} entry"))
4749        };
4750        let decisions: BTreeMap<_, _> = resolved
4751            .decisions
4752            .iter()
4753            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
4754            .collect();
4755
4756        assert_eq!(entry("FERRUM_BATCHED_GRAPH").effective_value, "0");
4757        assert_eq!(entry("FERRUM_REUSABLE_EXECUTION").effective_value, "1");
4758        assert_eq!(decisions["decode_graph_policy"], "graph_disabled");
4759        assert_eq!(
4760            decisions["reusable_execution_policy"],
4761            "enabled_when_runtime_capable"
4762        );
4763    }
4764
4765    #[test]
4766    fn reusable_execution_explicit_disable_is_preserved() {
4767        let hardware =
4768            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4769        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4770        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[(
4771            "FERRUM_REUSABLE_EXECUTION",
4772            "0",
4773            RuntimeConfigSource::Cli,
4774        )]))
4775        .with_model_capabilities(ModelCapabilities::unknown())
4776        .with_hardware_capabilities(hardware)
4777        .with_workload_profile(workload)
4778        .resolve()
4779        .unwrap();
4780        let entry = resolved
4781            .runtime_config
4782            .entries
4783            .iter()
4784            .find(|entry| entry.key == "FERRUM_REUSABLE_EXECUTION")
4785            .expect("reusable execution entry");
4786        let decision = resolved
4787            .decisions
4788            .iter()
4789            .find(|decision| decision.selection == "reusable_execution_policy")
4790            .expect("reusable execution decision");
4791
4792        assert_eq!(entry.effective_value, "0");
4793        assert_eq!(entry.source, RuntimeConfigSource::Cli);
4794        assert_eq!(decision.selected, "disabled");
4795    }
4796
4797    #[test]
4798    fn unified_graph_override_materializes_decode_graph_policy() {
4799        let hardware =
4800            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4801        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4802        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[(
4803            "FERRUM_UNIFIED_GRAPH",
4804            "1",
4805            RuntimeConfigSource::Cli,
4806        )]))
4807        .with_model_capabilities(ModelCapabilities::unknown())
4808        .with_hardware_capabilities(hardware)
4809        .with_workload_profile(workload)
4810        .resolve()
4811        .unwrap();
4812        let decisions: BTreeMap<_, _> = resolved
4813            .decisions
4814            .iter()
4815            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
4816            .collect();
4817        assert_eq!(decisions["decode_graph_policy"], "unified_decode_graph");
4818        let entry = resolved
4819            .runtime_config
4820            .entries
4821            .iter()
4822            .find(|entry| entry.key == "FERRUM_UNIFIED_GRAPH")
4823            .expect("unified graph entry");
4824        assert_eq!(entry.effective_value, "1");
4825        assert_eq!(
4826            resolved.effective_config_document()["selected_graph_mode"],
4827            "unified_decode_graph"
4828        );
4829    }
4830
4831    #[test]
4832    fn unified_graph_layers_only_override_materializes_decode_graph_policy() {
4833        let hardware =
4834            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4835        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4836        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[
4837            ("FERRUM_UNIFIED_GRAPH", "1", RuntimeConfigSource::Cli),
4838            (
4839                "FERRUM_UNIFIED_GRAPH_LAYERS_ONLY",
4840                "1",
4841                RuntimeConfigSource::Cli,
4842            ),
4843        ]))
4844        .with_model_capabilities(gemma3_gptq_model())
4845        .with_hardware_capabilities(hardware)
4846        .with_workload_profile(workload)
4847        .resolve()
4848        .unwrap();
4849        let decisions: BTreeMap<_, _> = resolved
4850            .decisions
4851            .iter()
4852            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
4853            .collect();
4854        assert_eq!(
4855            decisions["decode_graph_policy"],
4856            "unified_decode_graph_layers_only"
4857        );
4858        let entry = resolved
4859            .runtime_config
4860            .entries
4861            .iter()
4862            .find(|entry| entry.key == "FERRUM_UNIFIED_GRAPH_LAYERS_ONLY")
4863            .expect("unified graph layers-only entry");
4864        assert_eq!(entry.effective_value, "1");
4865        assert_eq!(
4866            resolved.effective_config_document()["selected_graph_mode"],
4867            "unified_decode_graph_layers_only"
4868        );
4869    }
4870
4871    #[test]
4872    fn unified_graph_lm_head_eager_override_materializes_decode_graph_policy() {
4873        let hardware =
4874            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4875        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4876        let resolved = FerrumConfigBuilder::new(snapshot_with_sources(&[
4877            ("FERRUM_UNIFIED_GRAPH", "1", RuntimeConfigSource::Cli),
4878            (
4879                "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER",
4880                "1",
4881                RuntimeConfigSource::Cli,
4882            ),
4883        ]))
4884        .with_model_capabilities(gemma3_gptq_model())
4885        .with_hardware_capabilities(hardware)
4886        .with_workload_profile(workload)
4887        .resolve()
4888        .unwrap();
4889        let decisions: BTreeMap<_, _> = resolved
4890            .decisions
4891            .iter()
4892            .map(|decision| (decision.selection.as_str(), decision.selected.as_str()))
4893            .collect();
4894        assert_eq!(
4895            decisions["decode_graph_policy"],
4896            "unified_decode_graph_lm_head_eager"
4897        );
4898        let entry = resolved
4899            .runtime_config
4900            .entries
4901            .iter()
4902            .find(|entry| entry.key == "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER")
4903            .expect("unified graph lm-head-eager entry");
4904        assert_eq!(entry.effective_value, "1");
4905        assert_eq!(
4906            resolved.effective_config_document()["selected_graph_mode"],
4907            "unified_decode_graph_lm_head_eager"
4908        );
4909    }
4910
4911    #[test]
4912    fn unified_graph_layers_only_requires_unified_graph() {
4913        let hardware =
4914            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4915        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4916        let err = FerrumConfigBuilder::new(snapshot(&[("FERRUM_UNIFIED_GRAPH_LAYERS_ONLY", "1")]))
4917            .with_model_capabilities(ModelCapabilities::unknown())
4918            .with_hardware_capabilities(hardware)
4919            .with_workload_profile(workload)
4920            .resolve()
4921            .expect_err("layers-only graph scope should require unified graph");
4922        assert!(matches!(
4923            err,
4924            AutoConfigError::InvalidOverride { key, .. }
4925                if key == "FERRUM_UNIFIED_GRAPH_LAYERS_ONLY"
4926        ));
4927    }
4928
4929    #[test]
4930    fn unified_graph_lm_head_eager_requires_unified_graph() {
4931        let hardware =
4932            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4933        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4934        let err =
4935            FerrumConfigBuilder::new(snapshot(&[("FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER", "1")]))
4936                .with_model_capabilities(ModelCapabilities::unknown())
4937                .with_hardware_capabilities(hardware)
4938                .with_workload_profile(workload)
4939                .resolve()
4940                .expect_err("lm-head-eager graph scope should require unified graph");
4941        assert!(matches!(
4942            err,
4943            AutoConfigError::InvalidOverride { key, .. }
4944                if key == "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER"
4945        ));
4946    }
4947
4948    #[test]
4949    fn unified_graph_lm_head_eager_conflicts_with_layers_only() {
4950        let hardware =
4951            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
4952        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4953        let err = FerrumConfigBuilder::new(snapshot(&[
4954            ("FERRUM_UNIFIED_GRAPH", "1"),
4955            ("FERRUM_UNIFIED_GRAPH_LAYERS_ONLY", "1"),
4956            ("FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER", "1"),
4957        ]))
4958        .with_model_capabilities(ModelCapabilities::unknown())
4959        .with_hardware_capabilities(hardware)
4960        .with_workload_profile(workload)
4961        .resolve()
4962        .expect_err("lm-head-eager graph scope should conflict with layers-only graph scope");
4963        assert!(matches!(
4964            err,
4965            AutoConfigError::InvalidOverride { key, .. }
4966                if key == "FERRUM_UNIFIED_GRAPH_LM_HEAD_EAGER"
4967        ));
4968    }
4969
4970    #[test]
4971    fn batched_graph_requires_cuda_graph_support() {
4972        let mut features = CompiledKernelFeatures::m3_fast_path_without_fa2();
4973        features.cuda_graph = false;
4974        let hardware = HardwareCapabilities::rtx4090_cuda(features);
4975        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4976        let err = FerrumConfigBuilder::new(snapshot(&[("FERRUM_BATCHED_GRAPH", "1")]))
4977            .with_model_capabilities(ModelCapabilities::unknown())
4978            .with_hardware_capabilities(hardware)
4979            .with_workload_profile(workload)
4980            .resolve()
4981            .expect_err("batched graph should require compiled graph support");
4982        assert!(matches!(
4983            err,
4984            AutoConfigError::InvalidOverride { key, .. } if key == "FERRUM_BATCHED_GRAPH"
4985        ));
4986    }
4987
4988    #[test]
4989    fn unified_graph_requires_cuda_graph_support() {
4990        let mut features = CompiledKernelFeatures::m3_fast_path_without_fa2();
4991        features.cuda_graph = false;
4992        let hardware = HardwareCapabilities::rtx4090_cuda(features);
4993        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
4994        let err = FerrumConfigBuilder::new(snapshot(&[("FERRUM_UNIFIED_GRAPH", "1")]))
4995            .with_model_capabilities(ModelCapabilities::unknown())
4996            .with_hardware_capabilities(hardware)
4997            .with_workload_profile(workload)
4998            .resolve()
4999            .expect_err("unified graph should require compiled graph support");
5000        assert!(matches!(
5001            err,
5002            AutoConfigError::InvalidOverride { key, .. } if key == "FERRUM_UNIFIED_GRAPH"
5003        ));
5004    }
5005
5006    #[test]
5007    fn unified_graph_rejects_gemma3_sandwich_models() {
5008        let hardware =
5009            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
5010        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
5011        let err = FerrumConfigBuilder::new(snapshot(&[("FERRUM_UNIFIED_GRAPH", "1")]))
5012            .with_model_capabilities(gemma3_gptq_model())
5013            .with_hardware_capabilities(hardware)
5014            .with_workload_profile(workload)
5015            .resolve()
5016            .expect_err("Gemma3 unified graph should stay disabled until graph instantiate fits");
5017        assert!(matches!(
5018            err,
5019            AutoConfigError::InvalidOverride { key, .. } if key == "FERRUM_UNIFIED_GRAPH"
5020        ));
5021    }
5022
5023    #[test]
5024    fn batched_graph_rejects_non_cuda_backend() {
5025        let hardware =
5026            cpu_hardware_with_features(CompiledKernelFeatures::m3_fast_path_without_fa2());
5027        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
5028        let err = FerrumConfigBuilder::new(snapshot(&[("FERRUM_BATCHED_GRAPH", "1")]))
5029            .with_model_capabilities(ModelCapabilities::unknown())
5030            .with_hardware_capabilities(hardware)
5031            .with_workload_profile(workload)
5032            .resolve()
5033            .expect_err("batched graph should require CUDA");
5034        assert!(matches!(
5035            err,
5036            AutoConfigError::InvalidOverride { key, .. } if key == "FERRUM_BATCHED_GRAPH"
5037        ));
5038    }
5039
5040    #[test]
5041    fn scheduler_active_chunk_combines_with_accelerator_prefill_first_default() {
5042        let resolved = m3(
5043            &[("FERRUM_ACTIVE_DECODE_PREFILL_CHUNK", "64")],
5044            CompiledKernelFeatures::m3_fast_path_without_fa2(),
5045        )
5046        .resolve()
5047        .unwrap();
5048        let scheduler = resolved
5049            .decisions
5050            .iter()
5051            .find(|decision| decision.selection == "scheduler_admission_policy")
5052            .unwrap();
5053        assert_eq!(
5054            scheduler.selected,
5055            "prefill_first_until_active:32+active_decode_prefill_chunk:64+prefill_token_budget:elastic"
5056        );
5057        assert_eq!(
5058            scheduler.source_key.as_deref(),
5059            Some("FERRUM_ACTIVE_DECODE_PREFILL_CHUNK")
5060        );
5061        let prefill_entry = resolved
5062            .runtime_config
5063            .entries
5064            .iter()
5065            .find(|entry| entry.key == "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE")
5066            .expect("accelerator default prefill-first should still be materialized");
5067        assert_eq!(prefill_entry.effective_value, "32");
5068        assert_eq!(prefill_entry.source, RuntimeConfigSource::Default);
5069        assert!(resolved
5070            .runtime_config
5071            .entries
5072            .iter()
5073            .all(|entry| entry.key != "FERRUM_SCHED_PREFILL_STEP_CHUNK"));
5074    }
5075
5076    #[test]
5077    fn scheduler_prefill_step_chunk_override_is_reflected_in_decision_trace() {
5078        let resolved = m3(
5079            &[("FERRUM_SCHED_PREFILL_STEP_CHUNK", "128")],
5080            CompiledKernelFeatures::m3_fast_path_without_fa2(),
5081        )
5082        .resolve()
5083        .unwrap();
5084        let scheduler = resolved
5085            .decisions
5086            .iter()
5087            .find(|decision| decision.selection == "scheduler_admission_policy")
5088            .unwrap();
5089        assert_eq!(
5090            scheduler.selected,
5091            "prefill_first_until_active:32+prefill_step_chunk:128"
5092        );
5093        assert_eq!(scheduler.source, AutoConfigSource::Env);
5094        assert_eq!(
5095            scheduler.source_key.as_deref(),
5096            Some("FERRUM_SCHED_PREFILL_STEP_CHUNK")
5097        );
5098        let step_entry = resolved
5099            .runtime_config
5100            .entries
5101            .iter()
5102            .find(|entry| entry.key == "FERRUM_SCHED_PREFILL_STEP_CHUNK")
5103            .expect("explicit prefill-step chunk should be preserved");
5104        assert_eq!(step_entry.effective_value, "128");
5105        assert_eq!(step_entry.source, RuntimeConfigSource::Env);
5106    }
5107
5108    fn scheduler_resolution(
5109        backend: &str,
5110        authority: ExecutionResourceAuthority,
5111        sequences: usize,
5112        runtime_config: RuntimeConfigSnapshot,
5113    ) -> ResolvedFerrumConfig {
5114        let mut hardware = HardwareCapabilities::unknown();
5115        hardware.backend = backend.to_owned();
5116        let mut workload = WorkloadProfile::serving_default();
5117        workload.target_concurrency = sequences;
5118        FerrumConfigBuilder::new(runtime_config)
5119            .with_hardware_capabilities(hardware)
5120            .with_workload_profile(workload)
5121            .with_execution_resource_authority(authority)
5122            .resolve()
5123            .unwrap()
5124    }
5125
5126    #[test]
5127    fn metal_plan_active_prefill_default_reaches_engine_and_decision_trace() {
5128        let resolved = scheduler_resolution(
5129            "metal",
5130            ExecutionResourceAuthority::PlanRuntime,
5131            4,
5132            snapshot(&[]),
5133        );
5134        let mut engine = crate::EngineConfig::default();
5135        engine
5136            .apply_runtime_config_snapshot(&resolved.runtime_config)
5137            .unwrap();
5138        assert_eq!(engine.scheduler.active_decode_prefill_chunk, Some(128));
5139        assert_eq!(engine.scheduler.prefill_step_chunk, None);
5140        let entry = resolved
5141            .runtime_config
5142            .entries
5143            .iter()
5144            .find(|entry| entry.key == "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK")
5145            .unwrap();
5146        assert_eq!(entry.source, RuntimeConfigSource::Default);
5147        assert_eq!(
5148            entry.effective_value.parse::<usize>().unwrap(),
5149            engine.scheduler.active_decode_prefill_chunk.unwrap()
5150        );
5151        let policy = resolved
5152            .decisions
5153            .iter()
5154            .find(|decision| decision.selection == "scheduler_admission_policy")
5155            .unwrap();
5156        assert_eq!(policy.selected,
5157            "prefill_first_until_active:4+active_decode_prefill_chunk:128+prefill_token_budget:elastic");
5158        assert_eq!(policy.source, AutoConfigSource::Default);
5159        assert_eq!(policy.source_key, None);
5160    }
5161
5162    #[test]
5163    fn active_prefill_default_does_not_change_other_execution_paths() {
5164        for (backend, authority, sequences) in [
5165            ("metal", ExecutionResourceAuthority::PlanRuntime, 1),
5166            ("metal", ExecutionResourceAuthority::LegacyEngine, 4),
5167            ("cpu", ExecutionResourceAuthority::PlanRuntime, 4),
5168            ("cuda", ExecutionResourceAuthority::PlanRuntime, 4),
5169        ] {
5170            let resolved = scheduler_resolution(backend, authority, sequences, snapshot(&[]));
5171            let mut engine = crate::EngineConfig::default();
5172            engine
5173                .apply_runtime_config_snapshot(&resolved.runtime_config)
5174                .unwrap();
5175            assert_eq!(engine.scheduler.active_decode_prefill_chunk, None);
5176            assert!(resolved
5177                .runtime_config
5178                .entries
5179                .iter()
5180                .all(|entry| entry.key != "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK"));
5181            assert!(resolved
5182                .decisions
5183                .iter()
5184                .find(|decision| decision.selection == "scheduler_admission_policy")
5185                .unwrap()
5186                .selected
5187                .split('+')
5188                .all(|part| !part.starts_with("active_decode_prefill_chunk:")));
5189        }
5190    }
5191
5192    #[test]
5193    fn explicit_active_prefill_limits_keep_their_value_and_source() {
5194        for (value, runtime_source, source) in [
5195            (
5196                "24",
5197                RuntimeConfigSource::ConfigFile,
5198                AutoConfigSource::ConfigFile,
5199            ),
5200            ("96", RuntimeConfigSource::Cli, AutoConfigSource::Cli),
5201            ("256", RuntimeConfigSource::Env, AutoConfigSource::Env),
5202        ] {
5203            let resolved = scheduler_resolution(
5204                "metal",
5205                ExecutionResourceAuthority::PlanRuntime,
5206                4,
5207                snapshot_with_sources(&[(
5208                    "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK",
5209                    value,
5210                    runtime_source,
5211                )]),
5212            );
5213            let mut engine = crate::EngineConfig::default();
5214            engine
5215                .apply_runtime_config_snapshot(&resolved.runtime_config)
5216                .unwrap();
5217            assert_eq!(
5218                engine.scheduler.active_decode_prefill_chunk,
5219                Some(value.parse().unwrap())
5220            );
5221            let entry = resolved
5222                .runtime_config
5223                .entries
5224                .iter()
5225                .find(|entry| entry.key == "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK")
5226                .unwrap();
5227            assert_eq!(entry.effective_value, value);
5228            assert_eq!(entry.source, runtime_source);
5229            let policy = resolved
5230                .decisions
5231                .iter()
5232                .find(|decision| decision.selection == "scheduler_admission_policy")
5233                .unwrap();
5234            assert!(policy
5235                .selected
5236                .split('+')
5237                .any(|part| part == format!("active_decode_prefill_chunk:{value}")));
5238            assert_eq!(policy.source, source);
5239            assert_eq!(
5240                policy.source_key.as_deref(),
5241                Some("FERRUM_ACTIVE_DECODE_PREFILL_CHUNK")
5242            );
5243        }
5244    }
5245
5246    #[test]
5247    fn default_active_prefill_limit_preserves_explicit_scheduler_decision_source() {
5248        for (key, value) in [
5249            ("FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE", "3"),
5250            ("FERRUM_SCHED_PREFILL_STEP_CHUNK", "24"),
5251        ] {
5252            let resolved = scheduler_resolution(
5253                "metal",
5254                ExecutionResourceAuthority::PlanRuntime,
5255                4,
5256                snapshot_with_sources(&[(key, value, RuntimeConfigSource::Cli)]),
5257            );
5258            let policy = resolved
5259                .decisions
5260                .iter()
5261                .find(|decision| decision.selection == "scheduler_admission_policy")
5262                .unwrap();
5263            assert_eq!(policy.source, AutoConfigSource::Cli);
5264            assert_eq!(policy.source_key.as_deref(), Some(key));
5265            let mut engine = crate::EngineConfig::default();
5266            engine
5267                .apply_runtime_config_snapshot(&resolved.runtime_config)
5268                .unwrap();
5269            assert_eq!(engine.scheduler.active_decode_prefill_chunk, Some(128));
5270        }
5271    }
5272
5273    #[test]
5274    fn cuda_gemma3_gptq_uses_generic_scheduler_default() {
5275        let hardware =
5276            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
5277        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
5278        let resolved = FerrumConfigBuilder::new(snapshot(&[]))
5279            .with_model_capabilities(gemma3_gptq_model())
5280            .with_hardware_capabilities(hardware)
5281            .with_workload_profile(workload)
5282            .resolve()
5283            .unwrap();
5284        let scheduler = resolved
5285            .decisions
5286            .iter()
5287            .find(|decision| decision.selection == "scheduler_admission_policy")
5288            .unwrap();
5289        assert_eq!(
5290            scheduler.selected,
5291            "prefill_first_until_active:32+prefill_token_budget:elastic"
5292        );
5293        assert_eq!(scheduler.source, AutoConfigSource::Default);
5294        assert!(resolved
5295            .runtime_config
5296            .entries
5297            .iter()
5298            .all(|entry| entry.key != "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK"));
5299        let entry = resolved
5300            .runtime_config
5301            .entries
5302            .iter()
5303            .find(|entry| entry.key == "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE")
5304            .expect("generic scheduler default should be materialized");
5305        assert_eq!(entry.effective_value, "32");
5306        assert_eq!(entry.source, RuntimeConfigSource::Default);
5307    }
5308
5309    #[test]
5310    fn explicit_scheduler_prompt_estimate_is_reflected_for_gemma3() {
5311        let hardware =
5312            HardwareCapabilities::rtx4090_cuda(CompiledKernelFeatures::m3_fast_path_without_fa2());
5313        let workload = WorkloadProfile::serving_default_for_hardware(&hardware);
5314        let resolved =
5315            FerrumConfigBuilder::new(snapshot(&[("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE", "1")]))
5316                .with_model_capabilities(gemma3_gptq_model())
5317                .with_hardware_capabilities(hardware)
5318                .with_workload_profile(workload)
5319                .resolve()
5320                .unwrap();
5321        let scheduler = resolved
5322            .decisions
5323            .iter()
5324            .find(|decision| decision.selection == "scheduler_admission_policy")
5325            .unwrap();
5326        assert_eq!(scheduler.selected, "prompt_token_estimate");
5327        assert_eq!(
5328            scheduler.source_key.as_deref(),
5329            Some("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE")
5330        );
5331        assert!(resolved
5332            .runtime_config
5333            .entries
5334            .iter()
5335            .all(|entry| entry.key != "FERRUM_ACTIVE_DECODE_PREFILL_CHUNK"));
5336    }
5337
5338    #[test]
5339    fn scheduler_prefill_first_is_default_accelerator_policy() {
5340        let resolved = m3(&[], CompiledKernelFeatures::m3_fast_path_without_fa2())
5341            .resolve()
5342            .unwrap();
5343        let scheduler = resolved
5344            .decisions
5345            .iter()
5346            .find(|decision| decision.selection == "scheduler_admission_policy")
5347            .unwrap();
5348        assert_eq!(
5349            scheduler.selected,
5350            "prefill_first_until_active:32+prefill_token_budget:elastic"
5351        );
5352        assert_eq!(scheduler.source, AutoConfigSource::Default);
5353        assert_eq!(scheduler.source_key, None);
5354        let entry = resolved
5355            .runtime_config
5356            .entries
5357            .iter()
5358            .find(|entry| entry.key == "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE")
5359            .expect("generic scheduler default should be materialized");
5360        assert_eq!(entry.effective_value, "32");
5361        assert_eq!(entry.source, RuntimeConfigSource::Default);
5362        assert!(resolved
5363            .runtime_config
5364            .entries
5365            .iter()
5366            .all(|entry| entry.key != "FERRUM_SCHED_PREFILL_STEP_CHUNK"));
5367    }
5368
5369    #[test]
5370    fn scheduler_prompt_token_estimate_can_be_disabled_in_decision_trace() {
5371        let resolved = m3(
5372            &[("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE", "0")],
5373            CompiledKernelFeatures::m3_fast_path_without_fa2(),
5374        )
5375        .resolve()
5376        .unwrap();
5377        let scheduler = resolved
5378            .decisions
5379            .iter()
5380            .find(|decision| decision.selection == "scheduler_admission_policy")
5381            .unwrap();
5382        assert_eq!(scheduler.selected, "continuous_default");
5383        assert_eq!(scheduler.source, AutoConfigSource::Env);
5384        assert_eq!(
5385            scheduler.source_key.as_deref(),
5386            Some("FERRUM_SCHED_PROMPT_TOKEN_ESTIMATE")
5387        );
5388    }
5389
5390    #[test]
5391    fn prefix_cache_override_is_reflected_in_decision_trace() {
5392        let resolved = m3(
5393            &[("FERRUM_PREFIX_CACHE", "1")],
5394            CompiledKernelFeatures::m3_fast_path_without_fa2(),
5395        )
5396        .resolve()
5397        .unwrap();
5398        let prefix_cache = resolved
5399            .decisions
5400            .iter()
5401            .find(|decision| decision.selection == "prefix_cache_policy")
5402            .unwrap();
5403        assert_eq!(prefix_cache.selected, "prefix_cache_enabled");
5404        assert_eq!(
5405            prefix_cache.source_key.as_deref(),
5406            Some("FERRUM_PREFIX_CACHE")
5407        );
5408    }
5409
5410    #[test]
5411    fn non_env_runtime_sources_are_preserved_in_decision_trace() {
5412        let runtime_config = snapshot_with_sources(&[
5413            (
5414                "FERRUM_FA_LAYOUT_VARLEN",
5415                "1",
5416                RuntimeConfigSource::ConfigFile,
5417            ),
5418            ("FERRUM_PAGED_MAX_SEQS", "48", RuntimeConfigSource::Cli),
5419            (
5420                "FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE",
5421                "32",
5422                RuntimeConfigSource::ScriptCase,
5423            ),
5424        ]);
5425        let resolved = FerrumConfigBuilder::new(runtime_config)
5426            .with_model_capabilities(ModelCapabilities::qwen3_30b_a3b_gptq_int4())
5427            .with_hardware_capabilities(HardwareCapabilities::rtx4090_cuda(
5428                CompiledKernelFeatures::m3_fast_path_without_fa2(),
5429            ))
5430            .with_workload_profile(WorkloadProfile::m3_qwen3_30b_a3b_int4())
5431            .resolve()
5432            .unwrap();
5433
5434        let decision = |selection: &str| {
5435            resolved
5436                .decisions
5437                .iter()
5438                .find(|decision| decision.selection == selection)
5439                .unwrap()
5440        };
5441        let attention = decision("attention_prefill_mixed_backend");
5442        assert_eq!(attention.selected, "fa_layout_varlen");
5443        assert_eq!(attention.source, AutoConfigSource::ConfigFile);
5444        assert_eq!(
5445            attention.source_key.as_deref(),
5446            Some("FERRUM_FA_LAYOUT_VARLEN")
5447        );
5448
5449        let max_sequences = decision("max_sequences");
5450        assert_eq!(max_sequences.selected, "48");
5451        assert_eq!(max_sequences.source, AutoConfigSource::Cli);
5452        assert_eq!(
5453            max_sequences.source_key.as_deref(),
5454            Some("FERRUM_PAGED_MAX_SEQS")
5455        );
5456
5457        let scheduler = decision("scheduler_admission_policy");
5458        assert_eq!(
5459            scheduler.selected,
5460            "prefill_first_until_active:32+prefill_token_budget:elastic"
5461        );
5462        assert_eq!(scheduler.source, AutoConfigSource::ScriptCase);
5463        assert_eq!(
5464            scheduler.source_key.as_deref(),
5465            Some("FERRUM_SCHED_PREFILL_FIRST_UNTIL_ACTIVE")
5466        );
5467    }
5468
5469    #[test]
5470    fn renders_effective_config_and_decision_trace_artifacts() {
5471        let resolved = m3(&[], CompiledKernelFeatures::m3_fast_path_without_fa2())
5472            .resolve()
5473            .unwrap();
5474        let effective = resolved.effective_config_document();
5475        assert_eq!(effective["schema_version"], 1);
5476        assert!(effective["env_hash"]
5477            .as_str()
5478            .unwrap()
5479            .starts_with("sha256:"));
5480        assert!(effective["entries"].is_array());
5481        assert_eq!(effective["model_capabilities"]["architecture"], "qwen3_moe");
5482        assert_eq!(effective["hardware_capabilities"]["backend"], "cuda");
5483        assert_eq!(
5484            effective["workload_profile"]["preset"],
5485            M3_QWEN3_30B_A3B_INT4_PRESET
5486        );
5487        assert_eq!(
5488            effective["decisions"].as_array().unwrap().len(),
5489            resolved.decisions.len()
5490        );
5491        let trace = resolved.decision_trace_jsonl().unwrap();
5492        assert_eq!(trace.lines().count(), resolved.decisions.len());
5493        assert!(trace.contains("\"attention_prefill_mixed_backend\""));
5494    }
5495
5496    #[test]
5497    fn auto_config_artifacts_match_locked_schema_shape() {
5498        let resolved = FerrumConfigBuilder::m3_qwen3_30b_a3b_int4(snapshot_with_sources(&[
5499            (
5500                "FERRUM_FA_LAYOUT_VARLEN",
5501                "1",
5502                RuntimeConfigSource::ScriptCase,
5503            ),
5504            ("FERRUM_PAGED_MAX_SEQS", "32", RuntimeConfigSource::Cli),
5505        ]))
5506        .resolve()
5507        .unwrap();
5508
5509        let effective = resolved.effective_config_document();
5510        assert_eq!(effective["schema_version"], 1);
5511        assert!(effective["env_hash"]
5512            .as_str()
5513            .unwrap()
5514            .starts_with("sha256:"));
5515
5516        let entries = effective["entries"].as_array().unwrap();
5517        let keys: Vec<_> = entries
5518            .iter()
5519            .map(|entry| entry["key"].as_str().unwrap())
5520            .collect();
5521        let mut sorted_keys = keys.clone();
5522        sorted_keys.sort_unstable();
5523        assert_eq!(keys, sorted_keys);
5524        for entry in entries {
5525            assert!(entry["key"].as_str().unwrap().starts_with("FERRUM_"));
5526            assert!(entry["effective_value"].is_string());
5527            assert!(matches!(
5528                entry["source"].as_str().unwrap(),
5529                "default" | "config_file" | "cli" | "env" | "script_case" | "memory_profile"
5530            ));
5531            assert!(!entry["affects"].as_array().unwrap().is_empty());
5532        }
5533        assert_eq!(
5534            effective["model_capabilities"]["quantization"].as_str(),
5535            Some("gptq_int4")
5536        );
5537        assert_eq!(
5538            effective["model_capabilities"]["moe"]["experts_per_token"].as_u64(),
5539            Some(8)
5540        );
5541        assert_eq!(
5542            effective["hardware_capabilities"]["compute_capability"].as_str(),
5543            Some("8.9")
5544        );
5545        assert_eq!(
5546            effective["hardware_capabilities"]["compiled_features"]["vllm_moe_marlin"].as_bool(),
5547            Some(true)
5548        );
5549        assert_eq!(
5550            effective["workload_profile"]["target_concurrency"].as_u64(),
5551            Some(32)
5552        );
5553        assert_eq!(
5554            effective["workload_profile"]["priority"].as_str(),
5555            Some("throughput")
5556        );
5557        let admission = &effective["admission"];
5558        for field in [
5559            "effective_max_concurrent",
5560            "queue_depth",
5561            "active_prefill",
5562            "active_decode",
5563            "current_batch_size",
5564            "rejected_requests_total",
5565            "failed_requests_total",
5566            "completed_requests_total",
5567        ] {
5568            assert!(admission[field].is_number(), "admission.{field} missing");
5569        }
5570
5571        let trace = resolved.decision_trace_jsonl().unwrap();
5572        let trace_decisions: Vec<AutoConfigDecision> = trace
5573            .lines()
5574            .map(|line| serde_json::from_str(line).unwrap())
5575            .collect();
5576        assert_eq!(trace_decisions, resolved.decisions);
5577        assert_eq!(
5578            serde_json::from_value::<Vec<AutoConfigDecision>>(effective["decisions"].clone())
5579                .unwrap(),
5580            trace_decisions
5581        );
5582
5583        for decision in &trace_decisions {
5584            assert_eq!(decision.schema_version, 1);
5585            assert!(!decision.selection.trim().is_empty());
5586            assert!(!decision.selected.trim().is_empty());
5587            assert!(!decision.candidates.is_empty());
5588            assert!(!decision.affects.is_empty());
5589            if let Some(source_key) = &decision.source_key {
5590                assert!(source_key.starts_with("FERRUM_"));
5591            }
5592            for rejected in &decision.rejected {
5593                assert!(!rejected.value.trim().is_empty());
5594                assert!(!rejected.reason.trim().is_empty());
5595            }
5596        }
5597    }
5598}