pub trait DecodeBackbone: PersistentDecodeModel {
// Required methods
fn decode_family(&self) -> &'static str;
fn decode_dims(&self) -> DecodeDims;
fn decode_shape_key(&self) -> u64;
fn decode_mask_plan(&self) -> MaskPlan;
fn decode_rope_plan(&self) -> RopePlan;
fn decode_token_embedding(&self) -> Arc<[f32]> ⓘ;
fn decode_apply_layer(
&self,
layer_idx: usize,
inputs: &DecodeLayerInputs<'_>,
) -> Result<Tensor>;
fn decode_final_norm_and_head(&self, h: &Tensor) -> Result<Tensor>;
}Expand description
Everything the shared build path needs from one model family.
Four of increment 3’s seven per-family items are served through this trait rather than copied; the two that are genuinely per-family — the attention block and the token-data hook — are the two methods that take real work.
Required Methods§
Sourcefn decode_family(&self) -> &'static str
fn decode_family(&self) -> &'static str
Family name, threaded into every error this shared path raises.
Not cosmetic. The 23 hunks that made collapsing two build bodies look
hard turned out to be mostly error-message prefixes, so sharing the body
makes diagnostics lie by default: without this, a Qwen3Moe failure
reports "forward_with_kv_context: …" and reads as a Llama bug.
fn decode_dims(&self) -> DecodeDims
Sourcefn decode_shape_key(&self) -> u64
fn decode_shape_key(&self) -> u64
Identity of the held decode plan — family + the config values that change
graph structure + this weight set. Must fold in
MaskPlan::mix_into.
fn decode_mask_plan(&self) -> MaskPlan
Sourcefn decode_rope_plan(&self) -> RopePlan
fn decode_rope_plan(&self) -> RopePlan
Per-layer RoPE-base assignment. Required, not defaulted, on purpose: a default would be silently correct for the single-base families and silently WRONG for a multi-base one that forgot to override it. Every family stating it is the compiler enumerating them.
Sourcefn decode_token_embedding(&self) -> Arc<[f32]> ⓘ
fn decode_token_embedding(&self) -> Arc<[f32]> ⓘ
The [vocab, hidden] embedding table the token lookup reads.
Sourcefn decode_apply_layer(
&self,
layer_idx: usize,
inputs: &DecodeLayerInputs<'_>,
) -> Result<Tensor>
fn decode_apply_layer( &self, layer_idx: usize, inputs: &DecodeLayerInputs<'_>, ) -> Result<Tensor>
One transformer layer: attention (writing this step’s K/V into the cache buffers) plus the FFN. This is the per-family architecture — partial rotary, GQA replication, norm placement, bias presence, MoE routing all live here and nowhere else on this path.
layer_idx is passed because per-layer variation is real (mask variant
selection is resolved by the caller, but Gemma3’s RoPE base and LFM2’s
state kind are not).
Sourcefn decode_final_norm_and_head(&self, h: &Tensor) -> Result<Tensor>
fn decode_final_norm_and_head(&self, h: &Tensor) -> Result<Tensor>
Final norm + LM head → [batch, seq, vocab].
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".