Skip to main content

semantic_memory/
quantize_governed.rs

1//! Governed compression pipeline integration for semantic-memory.
2//!
3//! This module evaluates `quant-governor` policy and produces an artifact only
4//! when the selected runtime codec has a real encoder. It never relabels raw
5//! bytes as a compressed representation.
6
7#[cfg(feature = "turbo-quant-codec")]
8pub mod governed {
9    use quant_governor::{
10        AdmissibilityClass, CodecProfile, ContentType, GovernancePolicy, GovernanceRequest,
11    };
12
13    /// Result of governed encoding — encoded bytes plus policy metadata.
14    #[derive(Debug, Clone)]
15    pub struct GovernedEncodeResult {
16        /// Bytes in the representation selected by `codec_profile`.
17        pub compressed_bytes: Vec<u8>,
18        /// Codec profile selected by the governance policy.
19        pub codec_profile: CodecProfile,
20        /// Governance receipt ID for the audit trail.
21        pub governance_receipt_id: String,
22        /// Allowed degradation budget from the policy decision.
23        pub degradation_budget: f64,
24    }
25
26    /// Encode only profiles backed by a concrete runtime encoder.
27    ///
28    /// `scr-runtime-compression` currently provides strict decode adapters but
29    /// no registered TurboQuant/FibQuant encoder. Returning an error for those
30    /// profiles preserves artifact truth: callers cannot mistake raw f32 bytes
31    /// for a compressed representation.
32    pub(super) fn encode_selected_profile(
33        embedding: &[f32],
34        profile: &CodecProfile,
35    ) -> Result<Vec<u8>, String> {
36        match profile {
37            CodecProfile::Raw => Ok(bytemuck::cast_slice(embedding).to_vec()),
38            CodecProfile::Q8 => Err("governed q8 encoding is not implemented".to_string()),
39            CodecProfile::Q4 => Err("governed q4 encoding is not implemented".to_string()),
40            CodecProfile::Turbo => Err(
41                "governed turbo-quant encoding is unavailable: no runtime encoder is registered"
42                    .to_string(),
43            ),
44            CodecProfile::Fib => Err(
45                "governed fib-quant encoding is unavailable: no runtime encoder is registered"
46                    .to_string(),
47            ),
48            // Keep compatibility with newer quant-governor enums without
49            // relabeling an unsupported profile as raw or compressed bytes.
50            _ => Err(
51                "governed codec profile is unavailable: no runtime encoder is registered"
52                    .to_string(),
53            ),
54        }
55    }
56
57    /// Encode an embedding vector through the governed compression pipeline.
58    ///
59    /// The caller receives bytes only when their representation is truthful.
60    /// Unsupported compression decisions fail explicitly instead of silently
61    /// substituting the uncompressed representation.
62    pub fn encode_governed(
63        embedding: &[f32],
64        policy: &GovernancePolicy,
65    ) -> Result<GovernedEncodeResult, String> {
66        let request = GovernanceRequest {
67            content_type: ContentType::Structured,
68            size_bytes: (embedding.len() * std::mem::size_of::<f32>()) as u64,
69            accuracy_requirement: 0.99,
70            latency_tolerance_ms: 500,
71            admissibility: AdmissibilityClass::Standard,
72        };
73
74        let decision = policy.evaluate(request).map_err(|e| e.to_string())?;
75        let encoded = encode_selected_profile(embedding, &decision.codec)?;
76
77        Ok(GovernedEncodeResult {
78            compressed_bytes: encoded,
79            codec_profile: decision.codec,
80            governance_receipt_id: format!("gr-{}", uuid::Uuid::new_v4()),
81            degradation_budget: decision.degradation_budget,
82        })
83    }
84
85    /// Encode with governance using the default policy.
86    pub fn encode_governed_default(embedding: &[f32]) -> Result<GovernedEncodeResult, String> {
87        encode_governed(embedding, &GovernancePolicy::default())
88    }
89}
90
91#[cfg(not(feature = "turbo-quant-codec"))]
92pub mod governed {
93    //! Stub module when `turbo-quant-codec` is not enabled.
94
95    /// Stub result type — codec_profile is a string when feature is disabled.
96    #[derive(Debug, Clone)]
97    pub struct GovernedEncodeResult {
98        pub compressed_bytes: Vec<u8>,
99        pub codec_profile: String,
100        pub governance_receipt_id: String,
101        pub degradation_budget: f64,
102    }
103
104    /// Returns an error indicating the turbo-quant-codec feature is not enabled.
105    pub fn encode_governed(
106        _embedding: &[f32],
107        _policy: (),
108    ) -> Result<GovernedEncodeResult, String> {
109        Err("turbo-quant-codec feature is not enabled".to_string())
110    }
111
112    /// Returns an error indicating the turbo-quant-codec feature is not enabled.
113    pub fn encode_governed_default(_embedding: &[f32]) -> Result<GovernedEncodeResult, String> {
114        Err("turbo-quant-codec feature is not enabled".to_string())
115    }
116}
117
118pub use governed::{encode_governed, encode_governed_default, GovernedEncodeResult};
119
120#[cfg(all(test, feature = "turbo-quant-codec"))]
121mod tests {
122    use super::governed::{encode_governed_default, encode_selected_profile};
123    use quant_governor::CodecProfile;
124
125    #[test]
126    fn raw_governed_encoding_preserves_f32_wire_bytes() {
127        let embedding = vec![1.25_f32, -2.5, 0.0, 4.75];
128        let result = encode_governed_default(&embedding).expect("default policy selects raw");
129        assert_eq!(result.codec_profile, CodecProfile::Raw);
130        assert_eq!(
131            result.compressed_bytes,
132            bytemuck::cast_slice::<f32, u8>(&embedding)
133        );
134        assert!(result.governance_receipt_id.starts_with("gr-"));
135    }
136
137    #[test]
138    fn unavailable_compression_profiles_fail_closed() {
139        let embedding = vec![0.25_f32; 16];
140        for profile in [
141            CodecProfile::Q8,
142            CodecProfile::Q4,
143            CodecProfile::Turbo,
144            CodecProfile::Fib,
145        ] {
146            let error = encode_selected_profile(&embedding, &profile)
147                .expect_err("unsupported profile must not be relabeled as raw bytes");
148            assert!(error.contains("encoding"));
149        }
150    }
151}