1use std::collections::BTreeSet;
4use std::fs;
5use std::num::{NonZeroU64, NonZeroUsize};
6use std::path::Path;
7use std::sync::Arc;
8
9use ferrum_interfaces::vnext::{
10 AttributeId, ElementType, ExternalModelMetadataId, ModelFamilyRegistration,
11 ModelFamilyRegistry, ModelSourceKind, OriginalModelSource, OriginalModelSources,
12 PreparedModelFamily, ProgramNode, SemanticValue, StateCapacityDemand, StateLifetime,
13 TypedFamilyRegistration, WeightComponentSource, ROUTED_SHARED_SWIGLU_MOE_OPERATION_ID,
14 ROUTED_SWIGLU_MOE_OPERATION_ID,
15};
16use ferrum_types::{
17 DataType, Device, ModelCapabilities, ModelId, ModelInfo, ModelType, MoeCapabilities,
18};
19use serde_json::Value;
20
21mod hf_metadata;
22pub mod qwen35;
23pub mod qwen3_moe;
24pub mod source;
25mod weight_layout;
26
27pub use source::{
28 huggingface_snapshot_identity, HuggingFaceSnapshotIdentity, ProductionModelSourceBundle,
29 ProductionWeightArtifact,
30};
31
32type PrepareModel =
33 fn(Arc<ProductionModelSourceBundle>) -> ferrum_types::Result<PreparedProductionModel>;
34type ValidateSemanticConfig = fn(&ExternalModelMetadataId, &[u8]) -> ferrum_types::Result<()>;
35type CreateFamilyRegistration = fn() -> ferrum_types::Result<Box<dyn ModelFamilyRegistration>>;
36
37struct ModelLoaderRegistration {
38 external_metadata_ids: &'static [&'static str],
39 gguf_architectures: &'static [&'static str],
40 execution_kind: ProductionExecutionKind,
41 validate_semantic_config: ValidateSemanticConfig,
42 prepare: PrepareModel,
43 create_family_registration: CreateFamilyRegistration,
44}
45
46const MODEL_LOADERS: &[ModelLoaderRegistration] = &[
47 ModelLoaderRegistration {
48 external_metadata_ids: &[
49 qwen35::EXTERNAL_METADATA_ID,
50 qwen35::MOE_EXTERNAL_METADATA_ID,
51 ],
52 gguf_architectures: &["qwen35", "qwen35moe"],
53 execution_kind: ProductionExecutionKind::CausalLanguage,
54 validate_semantic_config: qwen35::validate_semantic_config,
55 prepare: qwen35::prepare_from_sources,
56 create_family_registration: qwen35_family_registration,
57 },
58 ModelLoaderRegistration {
59 external_metadata_ids: &[qwen3_moe::EXTERNAL_METADATA_ID],
60 gguf_architectures: &["qwen3moe"],
61 execution_kind: ProductionExecutionKind::CausalLanguage,
62 validate_semantic_config: qwen3_moe::validate_semantic_config,
63 prepare: qwen3_moe::prepare_from_sources,
64 create_family_registration: qwen3_moe::family_registration,
65 },
66];
67
68pub fn gguf_architecture_requires_typed_product_sources(architecture: &str) -> bool {
73 MODEL_LOADERS
74 .iter()
75 .any(|registration| registration.gguf_architectures.contains(&architecture))
76}
77
78fn qwen35_family_registration() -> ferrum_types::Result<Box<dyn ModelFamilyRegistration>> {
79 let provider = qwen35::Qwen35FamilyProvider::new()
80 .map_err(|error| ferrum_types::FerrumError::model(error.to_string()))?;
81 Ok(Box::new(TypedFamilyRegistration::new(provider)))
82}
83
84pub struct ProductionModelFamilyRegistry {
88 registrations: Vec<Box<dyn ModelFamilyRegistration>>,
89}
90
91impl ProductionModelFamilyRegistry {
92 pub fn new() -> ferrum_types::Result<Self> {
93 let registrations = MODEL_LOADERS
94 .iter()
95 .map(|registration| (registration.create_family_registration)())
96 .collect::<ferrum_types::Result<Vec<_>>>()?;
97 Ok(Self { registrations })
98 }
99}
100
101impl ModelFamilyRegistry for ProductionModelFamilyRegistry {
102 fn registrations(&self) -> Vec<&dyn ModelFamilyRegistration> {
103 self.registrations
104 .iter()
105 .map(|registration| registration.as_ref())
106 .collect()
107 }
108}
109
110struct LegacyModelRegistration {
111 external_metadata_id: &'static str,
112}
113
114const LEGACY_MODELS: &[LegacyModelRegistration] = &[
119 LegacyModelRegistration {
120 external_metadata_id: "hf.architecture.LlamaForCausalLM",
121 },
122 LegacyModelRegistration {
123 external_metadata_id: "hf.architecture.Qwen2ForCausalLM",
124 },
125 LegacyModelRegistration {
126 external_metadata_id: "hf.architecture.Qwen3ForCausalLM",
127 },
128 LegacyModelRegistration {
129 external_metadata_id: "hf.architecture.Gemma3ForCausalLM",
130 },
131 LegacyModelRegistration {
132 external_metadata_id: "hf.architecture.Gemma3ForConditionalGeneration",
133 },
134 LegacyModelRegistration {
135 external_metadata_id: "hf.architecture.MistralForCausalLM",
136 },
137 LegacyModelRegistration {
138 external_metadata_id: "hf.architecture.PhiForCausalLM",
139 },
140 LegacyModelRegistration {
141 external_metadata_id: "hf.architecture.GPT2LMHeadModel",
142 },
143 LegacyModelRegistration {
144 external_metadata_id: "hf.architecture.BertModel",
145 },
146 LegacyModelRegistration {
147 external_metadata_id: "hf.architecture.BertForMaskedLM",
148 },
149 LegacyModelRegistration {
150 external_metadata_id: "hf.architecture.BertForSequenceClassification",
151 },
152 LegacyModelRegistration {
153 external_metadata_id: "hf.architecture.CLIPModel",
154 },
155 LegacyModelRegistration {
156 external_metadata_id: "hf.architecture.ChineseCLIPModel",
157 },
158 LegacyModelRegistration {
159 external_metadata_id: "hf.architecture.SiglipModel",
160 },
161 LegacyModelRegistration {
162 external_metadata_id: "hf.architecture.WhisperForConditionalGeneration",
163 },
164 LegacyModelRegistration {
165 external_metadata_id: "hf.architecture.Qwen3TTSForConditionalGeneration",
166 },
167];
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub enum ProductionExecutionKind {
174 CausalLanguage,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct CausalLanguageModelDescriptor {
184 architecture: String,
185 parameter_count: NonZeroU64,
186 hidden_size: NonZeroUsize,
187 layer_count: NonZeroUsize,
188 attention_head_count: NonZeroUsize,
189 kv_head_count: NonZeroUsize,
190 attention_head_dimension: NonZeroUsize,
191 vocabulary_size: NonZeroUsize,
192 maximum_sequence_tokens: NonZeroUsize,
193 execution_dtype: DataType,
194}
195
196impl CausalLanguageModelDescriptor {
197 #[allow(clippy::too_many_arguments)]
198 pub fn new(
199 architecture: impl Into<String>,
200 parameter_count: u64,
201 hidden_size: usize,
202 layer_count: usize,
203 attention_head_count: usize,
204 kv_head_count: usize,
205 attention_head_dimension: usize,
206 vocabulary_size: usize,
207 maximum_sequence_tokens: usize,
208 execution_dtype: DataType,
209 ) -> ferrum_types::Result<Self> {
210 let architecture = architecture.into();
211 if architecture.trim().is_empty() || architecture.trim() != architecture {
212 return Err(ferrum_types::FerrumError::model(
213 "architecture capability id must be non-empty and canonical",
214 ));
215 }
216 let parameter_count = NonZeroU64::new(parameter_count)
217 .ok_or_else(|| ferrum_types::FerrumError::model("parameter_count must be positive"))?;
218 let hidden_size = NonZeroUsize::new(hidden_size)
219 .ok_or_else(|| ferrum_types::FerrumError::model("hidden_size must be positive"))?;
220 let layer_count = NonZeroUsize::new(layer_count)
221 .ok_or_else(|| ferrum_types::FerrumError::model("layer_count must be positive"))?;
222 let attention_head_count = NonZeroUsize::new(attention_head_count).ok_or_else(|| {
223 ferrum_types::FerrumError::model("attention_head_count must be positive")
224 })?;
225 let kv_head_count = NonZeroUsize::new(kv_head_count)
226 .ok_or_else(|| ferrum_types::FerrumError::model("kv_head_count must be positive"))?;
227 let attention_head_dimension =
228 NonZeroUsize::new(attention_head_dimension).ok_or_else(|| {
229 ferrum_types::FerrumError::model("attention_head_dimension must be positive")
230 })?;
231 let vocabulary_size = NonZeroUsize::new(vocabulary_size)
232 .ok_or_else(|| ferrum_types::FerrumError::model("vocabulary_size must be positive"))?;
233 let maximum_sequence_tokens =
234 NonZeroUsize::new(maximum_sequence_tokens).ok_or_else(|| {
235 ferrum_types::FerrumError::model("maximum_sequence_tokens must be positive")
236 })?;
237 if kv_head_count.get() > attention_head_count.get() {
238 return Err(ferrum_types::FerrumError::model(format!(
239 "kv_head_count {} exceeds attention_head_count {}",
240 kv_head_count, attention_head_count
241 )));
242 }
243 if attention_head_count.get() % kv_head_count.get() != 0 {
244 return Err(ferrum_types::FerrumError::model(format!(
245 "attention_head_count {} is not divisible by kv_head_count {}",
246 attention_head_count, kv_head_count
247 )));
248 }
249 attention_head_count
250 .get()
251 .checked_mul(attention_head_dimension.get())
252 .ok_or_else(|| {
253 ferrum_types::FerrumError::model("attention projection width overflows usize")
254 })?;
255 if !execution_dtype.is_float() {
256 return Err(ferrum_types::FerrumError::model(format!(
257 "causal language execution dtype must be floating point, got {execution_dtype:?}"
258 )));
259 }
260 Ok(Self {
261 architecture,
262 parameter_count,
263 hidden_size,
264 layer_count,
265 attention_head_count,
266 kv_head_count,
267 attention_head_dimension,
268 vocabulary_size,
269 maximum_sequence_tokens,
270 execution_dtype,
271 })
272 }
273
274 pub fn architecture(&self) -> &str {
275 &self.architecture
276 }
277
278 pub const fn parameter_count(&self) -> u64 {
279 self.parameter_count.get()
280 }
281
282 pub const fn hidden_size(&self) -> usize {
283 self.hidden_size.get()
284 }
285
286 pub const fn layer_count(&self) -> usize {
287 self.layer_count.get()
288 }
289
290 pub const fn attention_head_count(&self) -> usize {
291 self.attention_head_count.get()
292 }
293
294 pub const fn kv_head_count(&self) -> usize {
295 self.kv_head_count.get()
296 }
297
298 pub const fn attention_head_dimension(&self) -> usize {
299 self.attention_head_dimension.get()
300 }
301
302 pub const fn vocabulary_size(&self) -> usize {
303 self.vocabulary_size.get()
304 }
305
306 pub const fn maximum_sequence_tokens(&self) -> usize {
307 self.maximum_sequence_tokens.get()
308 }
309
310 pub const fn execution_dtype(&self) -> DataType {
311 self.execution_dtype
312 }
313}
314
315pub struct PreparedProductionModel {
320 family: PreparedModelFamily,
321 weights: Arc<dyn WeightComponentSource>,
322 descriptor: CausalLanguageModelDescriptor,
323 sources: Arc<ProductionModelSourceBundle>,
324}
325
326impl std::fmt::Debug for PreparedProductionModel {
327 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
328 formatter
329 .debug_struct("PreparedProductionModel")
330 .field("family_id", self.family.family_id())
331 .field("descriptor", &self.descriptor)
332 .field("sources", &self.sources)
333 .finish_non_exhaustive()
334 }
335}
336
337impl PreparedProductionModel {
338 pub(super) fn new(
339 family: PreparedModelFamily,
340 weights: impl WeightComponentSource + 'static,
341 descriptor: CausalLanguageModelDescriptor,
342 sources: Arc<ProductionModelSourceBundle>,
343 ) -> Self {
344 Self {
345 family,
346 weights: Arc::new(weights),
347 descriptor,
348 sources,
349 }
350 }
351
352 pub fn family(&self) -> &PreparedModelFamily {
353 &self.family
354 }
355
356 pub fn weights(&self) -> &dyn WeightComponentSource {
357 self.weights.as_ref()
358 }
359
360 pub fn weight_source(&self) -> &Arc<dyn WeightComponentSource> {
361 &self.weights
362 }
363
364 pub fn descriptor(&self) -> &CausalLanguageModelDescriptor {
365 &self.descriptor
366 }
367
368 pub fn sources(&self) -> &Arc<ProductionModelSourceBundle> {
369 &self.sources
370 }
371
372 pub fn product_source_identity(
373 &self,
374 requested_model: impl Into<String>,
375 resolved_model: impl Into<String>,
376 ) -> ferrum_types::Result<ferrum_interfaces::vnext::ProductModelSourceIdentity> {
377 let template = &self.family.metadata().template;
378 self.sources.product_source_identity(
379 requested_model,
380 resolved_model,
381 &template.source_file,
382 &template.template,
383 )
384 }
385
386 pub const fn execution_kind(&self) -> ProductionExecutionKind {
387 ProductionExecutionKind::CausalLanguage
388 }
389
390 pub fn model_capabilities(&self) -> ferrum_types::Result<ModelCapabilities> {
395 let estimated_weight_bytes = self.sources.weight_payload_bytes()?;
396 let recurrent_state_bytes_per_sequence = self
397 .family
398 .program()
399 .states()
400 .iter()
401 .filter(|state| {
402 state.lifetime == StateLifetime::Sequence
403 && state.capacity_demand == StateCapacityDemand::FixedPerScope
404 })
405 .try_fold(0_u64, |total, state| {
406 let bytes = state.tensor.byte_len().map_err(|error| {
407 ferrum_types::FerrumError::model(format!(
408 "fixed per-sequence state {} has invalid storage size: {error}",
409 state.id
410 ))
411 })?;
412 total.checked_add(bytes).ok_or_else(|| {
413 ferrum_types::FerrumError::model(
414 "fixed per-sequence state byte size overflows u64",
415 )
416 })
417 })?;
418 let quantization_formats = self.family.weight_schema().quantization_formats();
419 let quantization = (!quantization_formats.is_empty()).then(|| {
420 quantization_formats
421 .iter()
422 .map(ToString::to_string)
423 .collect::<Vec<_>>()
424 .join("+")
425 });
426 let mut supported_dtypes =
427 BTreeSet::from([data_type_label(self.descriptor.execution_dtype())]);
428 supported_dtypes.extend(
429 self.family
430 .program()
431 .states()
432 .iter()
433 .filter_map(|state| element_type_label(state.tensor.element_type)),
434 );
435 let moe = moe_capabilities_from_program(&self.family)?;
436
437 Ok(ModelCapabilities {
438 architecture: self.descriptor.architecture().to_owned(),
439 quantization,
440 moe,
441 max_context_len: Some(self.descriptor.maximum_sequence_tokens()),
442 num_hidden_layers: Some(self.descriptor.layer_count()),
443 head_dim: Some(self.descriptor.attention_head_dimension()),
444 kv_heads: Some(self.descriptor.kv_head_count()),
445 estimated_weight_bytes: (estimated_weight_bytes > 0).then_some(estimated_weight_bytes),
446 recurrent_state_bytes_per_sequence: (recurrent_state_bytes_per_sequence > 0)
447 .then_some(recurrent_state_bytes_per_sequence),
448 supported_dtypes: supported_dtypes.into_iter().collect(),
449 graph_safe_moe: false,
450 })
451 }
452
453 pub fn model_info(&self, model_id: ModelId, device: Device) -> ModelInfo {
457 ModelInfo {
458 model_id,
459 model_type: ModelType::Custom(self.family.family_id().to_string()),
460 num_parameters: self.descriptor.parameter_count(),
461 hidden_size: self.descriptor.hidden_size(),
462 num_layers: self.descriptor.layer_count(),
463 num_heads: self.descriptor.attention_head_count(),
464 num_kv_heads: self.descriptor.kv_head_count(),
465 vocab_size: self.descriptor.vocabulary_size(),
466 max_sequence_length: self.descriptor.maximum_sequence_tokens(),
467 dtype: self.descriptor.execution_dtype(),
468 device,
469 version: None,
470 license: None,
471 metadata: Default::default(),
472 }
473 }
474}
475
476fn moe_capabilities_from_program(
477 family: &PreparedModelFamily,
478) -> ferrum_types::Result<Option<MoeCapabilities>> {
479 let mut capabilities = None;
480 for node in family
481 .program()
482 .blocks()
483 .iter()
484 .flat_map(|block| &block.nodes)
485 .filter(|node| {
486 matches!(
487 node.operation_id.as_str(),
488 ROUTED_SHARED_SWIGLU_MOE_OPERATION_ID | ROUTED_SWIGLU_MOE_OPERATION_ID
489 )
490 })
491 {
492 let current = MoeCapabilities {
493 num_experts: required_positive_node_attribute(node, "expert_count")?,
494 experts_per_token: required_positive_node_attribute(node, "experts_per_token")?,
495 moe_intermediate_size: Some(required_positive_node_attribute(
496 node,
497 "routed_intermediate_size",
498 )?),
499 };
500 if current.experts_per_token > current.num_experts {
501 return Err(ferrum_types::FerrumError::model(format!(
502 "MoE program node {} routes {} experts per token from only {} experts",
503 node.id, current.experts_per_token, current.num_experts
504 )));
505 }
506 if capabilities
507 .as_ref()
508 .is_some_and(|expected| expected != ¤t)
509 {
510 return Err(ferrum_types::FerrumError::model(format!(
511 "MoE program node {} has capabilities inconsistent with earlier layers",
512 node.id
513 )));
514 }
515 capabilities = Some(current);
516 }
517 Ok(capabilities)
518}
519
520fn required_positive_node_attribute(
521 node: &ProgramNode,
522 attribute: &str,
523) -> ferrum_types::Result<usize> {
524 let attribute_id = AttributeId::new(attribute).map_err(|error| {
525 ferrum_types::FerrumError::internal(format!(
526 "standard MoE attribute id {attribute:?} is invalid: {error}"
527 ))
528 })?;
529 let Some(SemanticValue::Unsigned(value)) = node.attributes.get(&attribute_id) else {
530 return Err(ferrum_types::FerrumError::model(format!(
531 "MoE program node {} lacks unsigned attribute {attribute:?}",
532 node.id
533 )));
534 };
535 let value = usize::try_from(*value).map_err(|_| {
536 ferrum_types::FerrumError::model(format!(
537 "MoE program node {} attribute {attribute:?} exceeds usize",
538 node.id
539 ))
540 })?;
541 if value == 0 {
542 return Err(ferrum_types::FerrumError::model(format!(
543 "MoE program node {} attribute {attribute:?} must be positive",
544 node.id
545 )));
546 }
547 Ok(value)
548}
549
550fn data_type_label(data_type: DataType) -> String {
551 data_type.to_string().to_ascii_lowercase()
552}
553
554fn element_type_label(element_type: ElementType) -> Option<String> {
555 match element_type {
556 ElementType::F16 => Some("fp16".to_owned()),
557 ElementType::Bf16 => Some("bf16".to_owned()),
558 ElementType::F32 => Some("fp32".to_owned()),
559 ElementType::Bool
560 | ElementType::U8
561 | ElementType::U32
562 | ElementType::I8
563 | ElementType::I32 => None,
564 }
565}
566
567pub struct RegisteredProductionModel {
571 registration: &'static ModelLoaderRegistration,
572 external_metadata_id: ExternalModelMetadataId,
573}
574
575impl RegisteredProductionModel {
576 pub fn external_metadata_id(&self) -> &ExternalModelMetadataId {
577 &self.external_metadata_id
578 }
579
580 pub const fn execution_kind(&self) -> ProductionExecutionKind {
581 self.registration.execution_kind
582 }
583
584 pub fn validate_semantic_config(&self, raw: &[u8]) -> ferrum_types::Result<()> {
585 let current = external_metadata_id_from_bytes(raw, "config.json")?;
586 if current != self.external_metadata_id {
587 return Err(ferrum_types::FerrumError::model(format!(
588 "model metadata identity changed between registration and semantic preflight: expected {} got {}",
589 self.external_metadata_id, current
590 )));
591 }
592 (self.registration.validate_semantic_config)(&self.external_metadata_id, raw)
593 }
594
595 pub fn prepare(&self, model_dir: &Path) -> ferrum_types::Result<PreparedProductionModel> {
596 let original = OriginalModelSource {
597 kind: ModelSourceKind::LocalDirectory,
598 location: model_dir.display().to_string(),
599 requested_revision: None,
600 };
601 let sources = Arc::new(ProductionModelSourceBundle::open_with_semantic_preflight(
602 model_dir,
603 model_dir,
604 ProductionWeightArtifact::safetensors_directory(model_dir),
605 OriginalModelSources {
606 semantic: original.clone(),
607 tokenizer: original.clone(),
608 weights: original,
609 },
610 |raw| self.validate_semantic_config(raw),
611 )?);
612 self.prepare_from_sources(sources)
613 }
614
615 pub fn prepare_from_sources(
616 &self,
617 sources: Arc<ProductionModelSourceBundle>,
618 ) -> ferrum_types::Result<PreparedProductionModel> {
619 self.validate_semantic_config(sources.config_json())?;
620 let prepared = (self.registration.prepare)(sources)?;
621 if prepared.family().external_metadata_id() != &self.external_metadata_id {
622 return Err(ferrum_types::FerrumError::model(format!(
623 "registered model loader returned metadata identity {} for resolved identity {}",
624 prepared.family().external_metadata_id(),
625 self.external_metadata_id
626 )));
627 }
628 if prepared.execution_kind() != self.registration.execution_kind {
629 return Err(ferrum_types::FerrumError::model(format!(
630 "registered model loader returned execution kind {:?} for registered kind {:?}",
631 prepared.execution_kind(),
632 self.registration.execution_kind
633 )));
634 }
635 Ok(prepared)
636 }
637}
638
639pub enum ProductionModelRegistration {
646 Registered(RegisteredProductionModel),
647 LegacyRegistered {
648 external_metadata_id: ExternalModelMetadataId,
649 },
650}
651
652impl ProductionModelRegistration {
653 pub fn external_metadata_id(&self) -> &ExternalModelMetadataId {
654 match self {
655 Self::Registered(registration) => registration.external_metadata_id(),
656 Self::LegacyRegistered {
657 external_metadata_id,
658 ..
659 } => external_metadata_id,
660 }
661 }
662
663 fn validate_semantic_config(&self, raw: &[u8]) -> ferrum_types::Result<()> {
664 match self {
665 Self::Registered(registration) => registration.validate_semantic_config(raw),
666 Self::LegacyRegistered {
667 external_metadata_id,
668 ..
669 } => {
670 let current = external_metadata_id_from_bytes(raw, "config.json")?;
671 if ¤t != external_metadata_id {
672 return Err(ferrum_types::FerrumError::model(format!(
673 "model metadata identity changed during semantic preflight: expected {external_metadata_id} got {current}"
674 )));
675 }
676 Ok(())
677 }
678 }
679 }
680
681 pub fn into_required(self) -> ferrum_types::Result<RegisteredProductionModel> {
684 match self {
685 Self::Registered(registration) => Ok(registration),
686 Self::LegacyRegistered {
687 external_metadata_id,
688 ..
689 } => Err(ferrum_types::FerrumError::unsupported(format!(
690 "model family metadata {external_metadata_id} is registered for the legacy runtime only; vNext product fallback is forbidden"
691 ))),
692 }
693 }
694}
695
696pub fn validate_registered_model_semantics(raw: &[u8]) -> ferrum_types::Result<()> {
700 let external_metadata_id = external_metadata_id_from_bytes(raw, "config.json")?;
701 let registration = resolve_registered_model(external_metadata_id)?;
702 registration.validate_semantic_config(raw)
703}
704
705pub fn open_registered_product_sources(
709 semantic_root: impl AsRef<Path>,
710 tokenizer_root: impl AsRef<Path>,
711 weights: ProductionWeightArtifact,
712 original_sources: OriginalModelSources,
713) -> ferrum_types::Result<ProductionModelSourceBundle> {
714 ProductionModelSourceBundle::open_with_semantic_preflight(
715 semantic_root,
716 tokenizer_root,
717 weights,
718 original_sources,
719 validate_registered_model_semantics,
720 )
721}
722
723pub fn open_registered_colocated_safetensors(
724 model_dir: impl AsRef<Path>,
725) -> ferrum_types::Result<ProductionModelSourceBundle> {
726 let model_dir = model_dir.as_ref();
727 let original = OriginalModelSource {
728 kind: ModelSourceKind::LocalDirectory,
729 location: model_dir.display().to_string(),
730 requested_revision: None,
731 };
732 open_registered_product_sources(
733 model_dir,
734 model_dir,
735 ProductionWeightArtifact::safetensors_directory(model_dir),
736 OriginalModelSources {
737 semantic: original.clone(),
738 tokenizer: original.clone(),
739 weights: original,
740 },
741 )
742}
743
744pub fn resolve_registered_model_from_dir(
745 model_dir: &Path,
746) -> ferrum_types::Result<ProductionModelRegistration> {
747 let external_metadata_id = external_metadata_id_from_model_dir(model_dir)?;
748 resolve_registered_model(external_metadata_id)
749}
750
751pub fn resolve_registered_model_from_sources(
752 sources: &ProductionModelSourceBundle,
753) -> ferrum_types::Result<ProductionModelRegistration> {
754 let external_metadata_id =
755 external_metadata_id_from_bytes(sources.config_json(), "config.json")?;
756 resolve_registered_model(external_metadata_id)
757}
758
759fn resolve_registered_model(
760 external_metadata_id: ExternalModelMetadataId,
761) -> ferrum_types::Result<ProductionModelRegistration> {
762 let mut loaders = MODEL_LOADERS.iter().filter(|registration| {
763 registration
764 .external_metadata_ids
765 .contains(&external_metadata_id.as_str())
766 });
767 let loader = loaders.next();
768 if loaders.next().is_some() {
769 return Err(ferrum_types::FerrumError::internal(format!(
770 "model metadata {external_metadata_id} has duplicate vNext production registrations"
771 )));
772 }
773 let mut legacy_rows = LEGACY_MODELS
774 .iter()
775 .filter(|registration| registration.external_metadata_id == external_metadata_id.as_str());
776 let legacy = legacy_rows.next();
777 if legacy_rows.next().is_some() {
778 return Err(ferrum_types::FerrumError::internal(format!(
779 "model metadata {external_metadata_id} has duplicate legacy registrations"
780 )));
781 }
782
783 match (loader, legacy) {
784 (Some(_), Some(_)) => Err(ferrum_types::FerrumError::internal(format!(
785 "model metadata {external_metadata_id} is registered in both vNext and legacy registries"
786 ))),
787 (Some(registration), None) => Ok(ProductionModelRegistration::Registered(
788 RegisteredProductionModel {
789 registration,
790 external_metadata_id,
791 },
792 )),
793 (None, Some(_)) => Ok(ProductionModelRegistration::LegacyRegistered {
794 external_metadata_id,
795 }),
796 (None, None) => Err(ferrum_types::FerrumError::unsupported(format!(
797 "model metadata {external_metadata_id} is absent from both the vNext and explicit legacy registries; implicit architecture fallback is forbidden"
798 ))),
799 }
800}
801
802fn external_metadata_id_from_model_dir(
803 model_dir: &Path,
804) -> ferrum_types::Result<ExternalModelMetadataId> {
805 let path = model_dir.join("config.json");
806 let raw = fs::read(&path)
807 .map_err(|error| ferrum_types::FerrumError::model(format!("read {path:?}: {error}")))?;
808 external_metadata_id_from_bytes(&raw, &path.display().to_string())
809}
810
811fn external_metadata_id_from_bytes(
812 raw: &[u8],
813 source: &str,
814) -> ferrum_types::Result<ExternalModelMetadataId> {
815 let config: Value = serde_json::from_slice(raw)
816 .map_err(|error| ferrum_types::FerrumError::model(format!("parse {source}: {error}")))?;
817 let architectures = config
818 .get("architectures")
819 .and_then(Value::as_array)
820 .ok_or_else(|| {
821 ferrum_types::FerrumError::model(
822 "config.json must declare exactly one architectures entry for typed family resolution",
823 )
824 })?;
825 let architecture = match architectures.as_slice() {
826 [value] => value.as_str().filter(|value| !value.is_empty()),
827 _ => None,
828 }
829 .ok_or_else(|| {
830 ferrum_types::FerrumError::model(
831 "config.json must declare exactly one non-empty architecture identity",
832 )
833 })?;
834 ExternalModelMetadataId::new(format!("hf.architecture.{architecture}"))
835 .map_err(|error| ferrum_types::FerrumError::model(error.to_string()))
836}
837
838#[cfg(test)]
839mod tests {
840 use super::*;
841
842 #[test]
843 fn required_production_selection_rejects_legacy_family() {
844 let metadata = ExternalModelMetadataId::new("hf.architecture.LlamaForCausalLM").unwrap();
845 let selection = ProductionModelRegistration::LegacyRegistered {
846 external_metadata_id: metadata,
847 };
848
849 let error = match selection.into_required() {
850 Ok(_) => panic!("legacy family unexpectedly entered the vNext product path"),
851 Err(error) => error.to_string(),
852 };
853
854 assert!(
855 error.contains("hf.architecture.LlamaForCausalLM"),
856 "{error}"
857 );
858 assert!(
859 error.contains("vNext product fallback is forbidden"),
860 "{error}"
861 );
862 }
863
864 #[test]
865 fn registry_ids_are_unique_and_disjoint() {
866 let mut ids = std::collections::BTreeSet::new();
867 let mut gguf_architectures = std::collections::BTreeSet::new();
868 for registration in MODEL_LOADERS {
869 for external_metadata_id in registration.external_metadata_ids {
870 assert!(
871 ids.insert(*external_metadata_id),
872 "duplicate vNext registration {external_metadata_id}"
873 );
874 }
875 for architecture in registration.gguf_architectures {
876 assert!(
877 gguf_architectures.insert(*architecture),
878 "GGUF architecture {architecture} maps to more than one vNext registration"
879 );
880 }
881 }
882 for registration in LEGACY_MODELS {
883 assert!(
884 ids.insert(registration.external_metadata_id),
885 "registration {} appears in both or more than once",
886 registration.external_metadata_id
887 );
888 }
889 }
890
891 #[test]
892 fn migrated_gguf_architecture_requires_typed_product_sources() {
893 assert!(gguf_architecture_requires_typed_product_sources("qwen35"));
894 assert!(gguf_architecture_requires_typed_product_sources(
895 "qwen35moe"
896 ));
897 assert!(gguf_architecture_requires_typed_product_sources("qwen3moe"));
898 assert!(!gguf_architecture_requires_typed_product_sources("qwen3"));
899 }
900
901 #[test]
902 fn production_family_registry_is_derived_from_loader_rows() {
903 let registry = ProductionModelFamilyRegistry::new().unwrap();
904 assert_eq!(registry.registrations().len(), MODEL_LOADERS.len());
905 let metadata = ExternalModelMetadataId::new(qwen35::EXTERNAL_METADATA_ID).unwrap();
906 let registration = (®istry as &dyn ModelFamilyRegistry)
907 .resolve_external(&metadata)
908 .unwrap();
909 assert_eq!(registration.family_id().as_str(), qwen35::FAMILY_ID);
910 let moe_metadata = ExternalModelMetadataId::new(qwen35::MOE_EXTERNAL_METADATA_ID).unwrap();
911 let moe_registration = (®istry as &dyn ModelFamilyRegistry)
912 .resolve_external(&moe_metadata)
913 .unwrap();
914 assert_eq!(moe_registration.family_id().as_str(), qwen35::FAMILY_ID);
915 let qwen3_moe_metadata =
916 ExternalModelMetadataId::new(qwen3_moe::EXTERNAL_METADATA_ID).unwrap();
917 let qwen3_moe_registration = (®istry as &dyn ModelFamilyRegistry)
918 .resolve_external(&qwen3_moe_metadata)
919 .unwrap();
920 assert_eq!(
921 qwen3_moe_registration.family_id().as_str(),
922 qwen3_moe::FAMILY_ID
923 );
924 }
925
926 #[test]
927 fn qwen35_moe_metadata_resolves_to_vnext_product_loader() {
928 let directory = tempfile::tempdir().unwrap();
929 fs::write(
930 directory.path().join("config.json"),
931 r#"{"architectures":["Qwen3_5MoeForConditionalGeneration"]}"#,
932 )
933 .unwrap();
934
935 let registration = resolve_registered_model_from_dir(directory.path())
936 .unwrap()
937 .into_required()
938 .unwrap();
939 assert_eq!(
940 registration.external_metadata_id().as_str(),
941 qwen35::MOE_EXTERNAL_METADATA_ID
942 );
943 }
944
945 #[test]
946 fn qwen3_moe_metadata_resolves_to_vnext_product_loader() {
947 let directory = tempfile::tempdir().unwrap();
948 fs::write(
949 directory.path().join("config.json"),
950 r#"{"architectures":["Qwen3MoeForCausalLM"]}"#,
951 )
952 .unwrap();
953
954 let registration = resolve_registered_model_from_dir(directory.path())
955 .unwrap()
956 .into_required()
957 .unwrap();
958 assert_eq!(
959 registration.external_metadata_id().as_str(),
960 qwen3_moe::EXTERNAL_METADATA_ID
961 );
962 }
963
964 #[test]
965 fn unknown_metadata_cannot_enter_an_implicit_legacy_path() {
966 let directory = tempfile::tempdir().unwrap();
967 fs::write(
968 directory.path().join("config.json"),
969 r#"{"architectures":["UnregisteredQwenForConditionalGeneration"]}"#,
970 )
971 .unwrap();
972
973 let error = resolve_registered_model_from_dir(directory.path())
974 .err()
975 .expect("unknown architecture must fail closed")
976 .to_string();
977 assert!(
978 error.contains("hf.architecture.UnregisteredQwenForConditionalGeneration"),
979 "{error}"
980 );
981 assert!(
982 error.contains("implicit architecture fallback is forbidden"),
983 "{error}"
984 );
985 }
986
987 #[test]
988 fn registered_source_open_rejects_nested_layout_before_weight_resolution() {
989 let semantic = tempfile::tempdir().unwrap();
990 let tokenizer = tempfile::tempdir().unwrap();
991 fs::write(
992 semantic.path().join("config.json"),
993 r#"{
994 "architectures":["Qwen3_5MoeForConditionalGeneration"],
995 "model_type":"qwen3_5_moe",
996 "text_config":{"model_type":"unsupported_nested_layout"}
997 }"#,
998 )
999 .unwrap();
1000 fs::write(
1001 tokenizer.path().join("tokenizer.json"),
1002 br#"{"version":"1.0"}"#,
1003 )
1004 .unwrap();
1005 let original = OriginalModelSource {
1006 kind: ModelSourceKind::LocalDirectory,
1007 location: "fixture".to_owned(),
1008 requested_revision: None,
1009 };
1010
1011 let error = open_registered_product_sources(
1012 semantic.path(),
1013 tokenizer.path(),
1014 ProductionWeightArtifact::safetensors_directory(
1015 semantic.path().join("missing-weight-root"),
1016 ),
1017 OriginalModelSources {
1018 semantic: original.clone(),
1019 tokenizer: original.clone(),
1020 weights: original,
1021 },
1022 )
1023 .expect_err("invalid nested semantics must fail before resolving weights")
1024 .to_string();
1025
1026 assert!(
1027 error.contains("unsupported Qwen3.5 text model_type"),
1028 "{error}"
1029 );
1030 assert!(
1031 !error.contains("weight source is not a directory"),
1032 "{error}"
1033 );
1034 }
1035
1036 #[test]
1037 fn registered_semantic_preflight_accepts_reference_dense_and_moe_configs() {
1038 let root = Path::new(env!("CARGO_MANIFEST_DIR")).join(
1039 "../../docs/goals/model-coverage-2026-06-12/artifacts/\
1040 w3_hf_config_probe_20260617T131209Z_f97c1d6f",
1041 );
1042 for name in [
1043 "dense_min_reference.config.json",
1044 "moe_shared_expert_reference.config.json",
1045 ] {
1046 let raw = fs::read(root.join(name)).unwrap();
1047 validate_registered_model_semantics(&raw)
1048 .unwrap_or_else(|error| panic!("{name}: {error}"));
1049 }
1050 }
1051
1052 #[test]
1053 fn registration_resolution_does_not_open_weights_and_rechecks_identity() {
1054 let directory = tempfile::tempdir().unwrap();
1055 let config_path = directory.path().join("config.json");
1056 fs::write(
1057 &config_path,
1058 r#"{"architectures":["Qwen3_5ForConditionalGeneration"]}"#,
1059 )
1060 .unwrap();
1061
1062 let registration = resolve_registered_model_from_dir(directory.path())
1063 .unwrap()
1064 .into_required()
1065 .unwrap();
1066 assert_eq!(
1067 registration.external_metadata_id().as_str(),
1068 qwen35::EXTERNAL_METADATA_ID
1069 );
1070 assert_eq!(
1071 registration.execution_kind(),
1072 ProductionExecutionKind::CausalLanguage
1073 );
1074
1075 fs::write(
1076 config_path,
1077 r#"{"architectures":["DifferentForConditionalGeneration"]}"#,
1078 )
1079 .unwrap();
1080 let error = match registration.prepare(directory.path()) {
1081 Ok(_) => panic!("changed metadata unexpectedly prepared"),
1082 Err(error) => error.to_string(),
1083 };
1084 assert!(error.contains("metadata identity changed"), "{error}");
1085 assert!(error.contains(qwen35::EXTERNAL_METADATA_ID), "{error}");
1086 }
1087
1088 #[test]
1089 fn causal_language_descriptor_rejects_invalid_runtime_facts() {
1090 assert!(CausalLanguageModelDescriptor::new(
1091 "test",
1092 0,
1093 16,
1094 2,
1095 2,
1096 1,
1097 4,
1098 32,
1099 128,
1100 DataType::FP16,
1101 )
1102 .is_err());
1103 assert!(CausalLanguageModelDescriptor::new(
1104 "test",
1105 1,
1106 16,
1107 2,
1108 2,
1109 1,
1110 0,
1111 32,
1112 128,
1113 DataType::FP16,
1114 )
1115 .is_err());
1116 assert!(CausalLanguageModelDescriptor::new(
1117 "test",
1118 1,
1119 16,
1120 2,
1121 2,
1122 3,
1123 4,
1124 32,
1125 128,
1126 DataType::FP16,
1127 )
1128 .is_err());
1129 assert!(CausalLanguageModelDescriptor::new(
1130 "test",
1131 1,
1132 16,
1133 2,
1134 3,
1135 2,
1136 4,
1137 32,
1138 128,
1139 DataType::FP16,
1140 )
1141 .is_err());
1142 assert!(CausalLanguageModelDescriptor::new(
1143 "test",
1144 1,
1145 16,
1146 2,
1147 2,
1148 1,
1149 4,
1150 32,
1151 128,
1152 DataType::INT8,
1153 )
1154 .is_err());
1155 assert!(
1156 CausalLanguageModelDescriptor::new("test", 1, 15, 2, 2, 1, 4, 32, 128, DataType::FP16,)
1157 .is_ok(),
1158 "hidden width and explicit attention projection width are independent facts"
1159 );
1160 }
1161}