pub const INTERLEAVE_STEP_IS_REQUIRED: &[&str] = &["ernie4_5-moe"];
pub fn interleave_step_refusal(arch: &str, step: Option<u64>) -> Option<String> {
match step {
None if INTERLEAVE_STEP_IS_REQUIRED.contains(&arch) => Some(format!(
"`{arch}.interleave_moe_layer_step` is missing. llama.cpp reads it as a REQUIRED \
key for this architecture (src/models/ernie4-5.cpp:11) and asserts it is positive \
(ernie4-5-moe.cpp:26), so a file without it is one llama.cpp will not load \
either. Every real ERNIE-4.5 MoE export carries it (conversion/ernie.py:88)"
)),
None | Some(1) => None,
Some(0) => Some(format!(
"`{arch}.interleave_moe_layer_step` is 0. llama.cpp asserts \
`hparams.n_moe_layer_step > 0` (src/models/ernie4-5-moe.cpp:26) before building \
the graph, and a step of 0 would divide by zero in its own layer rule at :64"
)),
Some(step) => Some(format!(
"`{arch}.interleave_moe_layer_step` is {step}, and ferrox serves only 1. \
src/models/ernie4-5-moe.cpp:64 makes a layer MoE when \
`il >= n_layer_dense_lead && (il + 1) % n_moe_layer_step == 0`, while \
ModelConfig::layer_is_dense implements only the leading-dense prefix -- but \
NEITHER does llama.cpp load such a file. Its tensor loader \
(src/models/ernie4-5.cpp:49) creates the expert tensors as REQUIRED for EVERY \
layer at or past `n_layer_dense_lead`, with no step in the condition, and \
creates the dense `ffn_gate`/`ffn_up`/`ffn_down` for none of them. The loader \
and the graph therefore agree only when the step changes nothing, so a \
checkpoint whose interleave really interleaves cannot be loaded by llama.cpp \
and there is no reference to check ferrox against. Both published ERNIE-4.5 MoE \
checkpoints carry a step of 1, which ferrox runs and \
tests/one_match_arm_graphs.rs pins against libllama's own logits"
)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_step_of_one_and_an_absent_key_are_both_served() {
assert!(interleave_step_refusal("ernie4_5-moe", Some(1)).is_none());
assert!(interleave_step_refusal("llama", None).is_none());
assert!(interleave_step_refusal("qwen3moe", Some(1)).is_none());
}
#[test]
fn a_step_above_one_is_refused_and_names_llama_cpps_own_contradiction() {
let r = interleave_step_refusal("ernie4_5-moe", Some(2)).expect("refused");
assert!(r.contains("ernie4-5-moe.cpp:64"), "{r}");
assert!(r.contains("ernie4-5.cpp:49"), "{r}");
assert!(r.contains("cannot be loaded by llama.cpp"), "{r}");
}
#[test]
fn the_key_is_required_for_ernie_and_optional_everywhere_else() {
assert!(interleave_step_refusal("ernie4_5-moe", None).is_some());
for arch in ["llama", "qwen3moe", "dots1", "ernie4_5"] {
assert!(
interleave_step_refusal(arch, None).is_none(),
"{arch} must not require the key"
);
}
}
#[test]
fn a_step_of_zero_is_refused_rather_than_dividing_by_zero() {
let r = interleave_step_refusal("ernie4_5-moe", Some(0)).expect("refused");
assert!(r.contains("divide by zero"), "{r}");
}
}