metrale_model_layers/layers/qwen3_ssm/
hc.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-25: mHC (hyper-connection highway) and PLE attachment for the GDN
4//! layer, and the refusal used by the decode paths that have no highway form.
5//!
6//! Owner: model-layers (qwen3_ssm).
7//! Invariants:
8//! - With `hc` set, `TransformerLayer::decode`, `decode_multi_seq` and
9//!   `prefill` run the hc forward paths (`trait_decode_hc.rs`,
10//!   `trait_decode_multi_seq/hc.rs`, `trait_prefill_hc.rs`), and
11//!   `decode_batched` and `decode_verify_multi` return an error.
12
13use super::Qwen3SsmLayer;
14impl Qwen3SsmLayer {
15    /// 2026-09-25: Attach the mHC highway weights; the entry points then route
16    /// as the module header states.
17    pub fn set_hc_weights(&mut self, hc: crate::layers::qwen3_attention::HcWeights) {
18        self.hc = Some(hc);
19    }
20
21    /// 2026-09-25: Attach the PLE n-gram injection. The hc prefill and
22    /// single-sequence decode paths run it before this layer's `hc_pre_site`.
23    pub fn set_ple(&mut self, ple: crate::layers::ple::PleLayer) {
24        self.ple = Some(ple);
25    }
26
27    /// 2026-09-25: Error when the mHC highway is attached. `decode_batched` and
28    /// `decode_verify_multi` call it first: they take the caller's `residual`
29    /// buffer, while the hc paths carry the residual on the highway and take
30    /// none.
31    pub(crate) fn refuse_batched_under_hc(&self, path: &str) -> anyhow::Result<()> {
32        anyhow::ensure!(
33            self.hc.is_none(),
34            "qwen3_ssm::{path}: the mHC highway has no batched GDN path yet. \
35             This model serves at concurrency 1; the batched paths maintain \
36             their own residual, which the highway replaces, so running them \
37             would count every block output twice. Metrale Engine #753 item B."
38        );
39        Ok(())
40    }
41}