metrale_model_layers/layer/transformer_layer/
capabilities.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-26: `LayerCapabilities`, the side-effect-free questions the model asks a layer when it
4//! picks a route: graph eligibility, batched decode and verify support, rollback, SSM
5//! pool use and the MLA prefill mode.
6//!
7//! Owner: model-layers.
8//! Invariants: none beyond the types.
9
10/// 2026-09-26: A supertrait of `TransformerLayer`; see the module header.
11pub trait LayerCapabilities {
12    /// 2026-09-25: True when this layer's prefill attends only over the tokens it is
13    /// handed, so skipping a cached prefix would hide it from attention. The Qwen3
14    /// attention layer returns true when it runs MLA; the prefix lookup then matches
15    /// nothing unless `METRALE_MLA_PREFIX_SKIP=1` (`mla_prefill_needs_full_recompute`).
16    fn uses_local_mla_prefill(&self) -> bool {
17        false
18    }
19
20    /// 2026-09-25: Whether this layer's online FP8-KV calibration has frozen its scale;
21    /// `None` when the layer runs no online calibration (the default). The model lifts its
22    /// CUDA-graph suppression once no layer reports `Some(false)`
23    /// (`graphs_ready_after_fp8_kv_cal`).
24    fn fp8_calibration_frozen(&self) -> Option<bool> {
25        None
26    }
27
28    /// 2026-09-25: True when this layer's decode cannot run inside a CUDA graph, such as
29    /// the QSA indexer's host top-k. The model ORs it across layers into
30    /// `decode_graph_veto` when it is built.
31    fn decode_graph_unsupported(&self) -> bool {
32        false
33    }
34
35    /// 2026-09-25: True when this layer cannot serve a batched multi-sequence decode step.
36    /// The batched decode ORs it across layers into `hc_perseq` (`decode_a2.rs`) and then
37    /// runs each sequence through `decode`; the single-GPU fused decode+prefill ORs it into
38    /// `hc_qsa_perseq` (`decode_b.rs`) and then runs the batched decode and the prefill
39    /// separately.
40    fn decode_multi_seq_unsupported(&self) -> bool {
41        false
42    }
43
44    /// 2026-09-25: True when this layer keeps per-sequence state that lowering the
45    /// sequence's KV cursor does not rewind, such as a monotonic cache count or an n-gram
46    /// history. The model ORs it across layers, and the scheduler's `rollback_to_boundary`
47    /// then declines the rollback (`LayerStateNotRewindable`).
48    fn decode_rollback_unsupported(&self) -> bool {
49        false
50    }
51
52    /// 2026-09-25: True when this layer cannot serve a batched multi-sequence verify
53    /// (`decode_verify_multi`); `can_batch_verify_dispatch` then refuses the batch. It is
54    /// separate from [`Self::decode_multi_seq_unsupported`] because the answers can
55    /// differ.
56    fn decode_verify_multi_unsupported(&self) -> bool {
57        false
58    }
59
60    #[allow(clippy::too_many_arguments)]
61    /// 2026-09-25: True when a captured decode graph goes stale once a new sequence takes
62    /// this slot. Decode graphs are keyed by `slot_idx`, which is safe only while every
63    /// per-sequence address a capture bakes lives in the slot-addressed SSM pool. A layer
64    /// that allocates its own per-sequence buffers (GLM-5.3's DSA indexer cache) returns
65    /// true, and `free_sequence_dispatch` then drops that slot's graphs, except for a slot
66    /// index past the SSM pool's `max_slots`.
67    fn graph_stale_on_new_sequence(&self) -> bool {
68        false
69    }
70
71    /// 2026-09-25: True for an SSM layer. The model's split prefill then runs
72    /// `prefill_phase1`, `prefill_gdn_full` and `prefill_phase3` instead of `prefill`.
73    fn is_ssm_layer(&self) -> bool {
74        false
75    }
76
77    /// 2026-09-25: Whether this layer's recurrent state lives in the shared SSM pool. When
78    /// true (the default), sequence setup hands a linear-attention layer an `SsmLayerState`
79    /// with pool addresses and never calls its `alloc_state`. A linear-attention layer with
80    /// its own state type returns false; the Kimi K3 layer (`kimi_k3/bound.rs`) does, and
81    /// downcasts its state to `K3CpuFallbackState`.
82    fn uses_ssm_pool(&self) -> bool {
83        true
84    }
85
86    /// 2026-10-01: True when this layer's `prefill` honours a replay-tail capture
87    /// (`ForwardContext::midchunk_capture` with `replay_tail`) on every build: the rows
88    /// from `cap_local` on get the bits a prefill pass starting at `cap_local` gives them
89    /// (an SSM layer splits its conv and recurrence there and copies its state into the
90    /// plan's slots; an attention layer runs those rows as their own paged call). The
91    /// model plans a replay-tail capture only when every layer says so
92    /// (`TransformerModel::inpass_cut_capture_supported`); otherwise it keeps the
93    /// two-pass tail split.
94    fn supports_replay_tail_split(&self) -> bool {
95        false
96    }
97}