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}