Expand description
MiniMax M2 / M3 refusal, and why the reason it used to give was the wrong one.
This module used to say MiniMax “needs a loader, 256-expert sigmoid MoE routing and MTP draft heads, none of which exist yet”. Checked against llama.cpp, two of those three clauses are false and the third is only true of one of the two architectures:
- MTP does not exist in either model. Neither
.scratch/llama.cpp/src/models/minimax-m2.cppnorminimax-m3.cppcreates a singlenextn.*tensor, andgguf-py’sMODEL_ARCH.MINIMAXM2/.MINIMAXM3tensor lists contain noNEXTN_*entry, so no converter can emit MTP weights for these files.minimax-m3.cpp:9states it: “MTP is not in released model weights.” A refusal naming a tensor family the checkpoint cannot contain is unreachable by construction — glm4moe’sq_lora_rankdefect in a different costume. - Sigmoid MoE routing already exists here.
loader.rsreads{arch}.expert_gating_funcintoGatingFunction::Sigmoid, loadsblk.N.exp_probs_b.bias, and readsexpert_weights_scaleandexpert_weights_norm.ferrox_moe::route_top_k_sigmoidis the routing DeepSeek-V3 and GLM-4-MoE use. “256 experts” is an hparam, not a ceiling. - Block-sparse attention is M3’s, not MiniMax’s.
minimax-m2.cppbuilds ordinary dense GQA attention (:112). The ported selection inferrox_core::block_sparseis relevant only to M3’s MSA, and is the smallest piece of it.
What is actually true, per architecture, is in crate::capability
— and that is deliberately the ONLY copy. The live refusal a user
hits is LoadError::DedicatedArchitectureRequired, built from
ArchPath::DedicatedOnly { reason } in loader.rs; this module’s
MinimaxEngine::reject used to carry a second, longer, different
reason that nothing ever printed. Two copies of one explanation is
how they came to disagree, so reject now reads the catalog’s string
rather than repeating it.
In short: minimax-m2 is UNAUDITED (a fixture or a parity run would
settle it — see tests/minimax_refusal.rs), while minimax-m3 is
genuinely UNIMPLEMENTED (the MSA indexer and its own KV cache).