use crate::sign::{SignTuple, SignWindow};
use crate::envelope::AdmissibilityEnvelope;
use crate::grammar::{GrammarEvaluator, GrammarState};
use crate::syntax::{classify, SyntaxThresholds, MotifClass};
use crate::heuristics::{HeuristicsBank, SemanticDisposition};
use crate::dsa::DsaWindow;
use crate::policy::{PolicyDecision, PolicyEvaluator};
use crate::platform::{PlatformContext, SnrFloor};
use crate::lyapunov::{LyapunovEstimator, LyapunovResult};
#[derive(Debug, Clone, Copy)]
pub struct NonIntrusiveContract {
pub integration_mode: &'static str,
pub fail_safe_isolation_note: &'static str,
pub write_path_note: &'static str,
pub determinism_note: &'static str,
pub attribution_policy: &'static str,
pub unsafe_count: u32,
pub heap_policy: &'static str,
}
pub const NON_INTRUSIVE_CONTRACT: NonIntrusiveContract = NonIntrusiveContract {
integration_mode: "read_only_side_channel",
fail_safe_isolation_note:
"observer failure cannot alter upstream receiver behaviour; \
observer is a leaf node with no write-back path to any upstream state",
write_path_note:
"observe() takes &[f32] (immutable caller slice); \
no mutable reference to caller-owned data is ever taken",
determinism_note:
"identical ordered inputs produce identical outputs on every replay; \
no PRNG, no OS clock, no hardware entropy source",
attribution_policy:
"grammar states and motif classes are structural observations only; \
no physical cause, emitter identity, or intent is attributed",
unsafe_count: 0,
heap_policy: "no_alloc in core path; heap opt-in via 'alloc' feature only",
};
#[derive(Debug, Clone, Copy)]
pub struct ObservationResult {
pub k: u64,
pub residual_norm: f32,
pub sign: SignTuple,
pub grammar: GrammarState,
pub motif: MotifClass,
pub semantic: SemanticDisposition,
pub dsa_score: f32,
pub policy: PolicyDecision,
pub lyapunov: LyapunovResult,
pub sub_threshold: bool,
pub suppressed: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct DecimationAccumulator {
factor: u32, count: u32, sum_sq: f32, peak: f32, }
impl DecimationAccumulator {
pub const fn new(factor: u32) -> Self {
let f = if factor == 0 { 1 } else { factor };
Self { factor: f, count: 0, sum_sq: 0.0, peak: 0.0 }
}
#[inline]
pub fn push(&mut self, norm: f32) -> Option<f32> {
let n = if norm < 0.0 { -norm } else { norm }; self.sum_sq += n * n;
if n > self.peak { self.peak = n; }
self.count += 1;
if self.count >= self.factor {
let rms = crate::math::sqrt_f32(self.sum_sq / self.count as f32);
self.count = 0;
self.sum_sq = 0.0;
self.peak = 0.0;
Some(rms)
} else {
None
}
}
pub const fn factor(&self) -> u32 { self.factor }
pub const fn count(&self) -> u32 { self.count }
pub fn reset(&mut self) {
self.count = 0;
self.sum_sq = 0.0;
self.peak = 0.0;
}
}
pub struct DsfbRfEngine<const W: usize, const K: usize, const M: usize> {
envelope: AdmissibilityEnvelope,
sign_window: SignWindow<W>,
grammar: GrammarEvaluator<K>,
dsa: DsaWindow<W>,
heuristics: HeuristicsBank<M>,
policy_eval: PolicyEvaluator,
lyapunov: LyapunovEstimator<W>,
snr_floor: SnrFloor,
syn_thresh: SyntaxThresholds,
obs_count: u64,
episode_count: u32,
decim: DecimationAccumulator,
}
impl<const W: usize, const K: usize, const M: usize> DsfbRfEngine<W, K, M> {
pub fn new(rho: f32, tau: f32) -> Self {
use crate::policy::PolicyConfig;
Self {
envelope: AdmissibilityEnvelope::new(rho),
sign_window: SignWindow::new(),
grammar: GrammarEvaluator::new(),
dsa: DsaWindow::new(rho * 0.5),
heuristics: HeuristicsBank::default_rf(),
policy_eval: PolicyEvaluator::with_config(PolicyConfig {
tau,
k: K as u8,
m: 1,
extreme_bypass: true,
}),
lyapunov: LyapunovEstimator::new(),
snr_floor: SnrFloor::default(),
syn_thresh: SyntaxThresholds::default(),
obs_count: 0,
episode_count: 0,
decim: DecimationAccumulator::new(1), }
}
pub fn from_calibration(healthy_norms: &[f32], tau: f32) -> Option<Self> {
let env = AdmissibilityEnvelope::calibrate_from_window(healthy_norms)?;
let mut eng = Self::new(env.rho, tau);
eng.dsa.calibrate_ewma_threshold(healthy_norms);
Some(eng)
}
pub fn with_snr_floor(mut self, db: f32) -> Self {
self.snr_floor = SnrFloor::new(db);
self
}
pub fn with_decimation(mut self, factor: u32) -> Self {
self.decim = DecimationAccumulator::new(factor);
self
}
pub fn decimation_factor(&self) -> u32 { self.decim.factor() }
pub fn observe(
&mut self,
residual_norm: f32,
ctx: PlatformContext,
) -> ObservationResult {
let k = self.obs_count;
self.obs_count += 1;
let sub_threshold = self.snr_floor.is_sub_threshold(ctx.snr_db);
let suppressed = ctx.waveform_state.is_suppressed();
let sign = self.sign_window.push(residual_norm, sub_threshold, self.snr_floor);
let effective_waveform = select_effective_waveform(ctx.waveform_state, sub_threshold);
let grammar = self.grammar.evaluate(&sign, &self.envelope, effective_waveform);
let motif = classify(&sign, grammar, self.envelope.rho, &self.syn_thresh);
let semantic = self.heuristics.lookup(motif, grammar);
let motif_fired = !matches!(motif, MotifClass::Unknown);
let dsa = self.dsa.push(&sign, grammar, motif_fired);
let lyapunov = self.lyapunov.push(residual_norm, self.envelope.rho);
let policy = self.policy_eval.evaluate(grammar, semantic, dsa, 1);
if matches!(policy, PolicyDecision::Escalate) {
self.episode_count = self.episode_count.saturating_add(1);
}
ObservationResult {
k, residual_norm, sign, grammar, motif, semantic,
dsa_score: dsa.0, lyapunov, policy, sub_threshold, suppressed,
}
}
#[cfg(feature = "alloc")]
pub fn observe_batch(
&mut self,
norms: &[f32],
ctx: PlatformContext,
) -> alloc::vec::Vec<ObservationResult> {
norms.iter().map(|&n| self.observe(n, ctx)).collect()
}
#[inline]
pub fn observe_decimated(
&mut self,
residual_norm: f32,
ctx: PlatformContext,
) -> Option<ObservationResult> {
self.decim.push(residual_norm).map(|rms| self.observe(rms, ctx))
}
pub fn obs_count(&self) -> u64 { self.obs_count }
pub fn episode_count(&self) -> u32 { self.episode_count }
pub fn rho(&self) -> f32 { self.envelope.rho }
pub fn grammar_state(&self) -> GrammarState { self.grammar.state() }
#[inline]
pub fn contract(&self) -> NonIntrusiveContract {
NON_INTRUSIVE_CONTRACT
}
pub fn reset(&mut self) {
self.sign_window.reset();
self.grammar.reset();
self.dsa.reset();
self.lyapunov.reset();
self.decim.reset();
self.obs_count = 0;
self.episode_count = 0;
}
}
#[inline]
fn select_effective_waveform(
ctx_waveform: crate::platform::WaveformState,
sub_threshold: bool,
) -> crate::platform::WaveformState {
if sub_threshold {
crate::platform::WaveformState::Calibration
} else {
ctx_waveform
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::platform::PlatformContext;
fn eng() -> DsfbRfEngine<10, 4, 8> {
DsfbRfEngine::new(0.10, 2.0)
}
fn ctx(snr: f32) -> PlatformContext { PlatformContext::with_snr(snr) }
#[test]
fn determinism_identical_inputs_produce_identical_outputs() {
let inputs = [0.01f32, 0.02, 0.04, 0.07, 0.09, 0.08, 0.06, 0.04, 0.03, 0.02,
0.03, 0.05, 0.08, 0.11, 0.10, 0.08, 0.06, 0.03, 0.02, 0.01];
let c = ctx(15.0);
let mut e1 = eng();
let mut e2 = eng();
for &n in &inputs {
let r1 = e1.observe(n, c);
let r2 = e2.observe(n, c);
assert_eq!(r1.policy, r2.policy,
"Theorem 9 violated at k={}: {:?} vs {:?}", r1.k, r1.policy, r2.policy);
assert_eq!(r1.grammar, r2.grammar);
}
}
#[test]
fn observe_does_not_mutate_input() {
let mut e = eng();
let original = 0.07f32;
let copy = original;
let _ = e.observe(original, ctx(15.0));
assert_eq!(original, copy);
}
#[test]
fn sub_threshold_snr_forces_admissible() {
let mut e = eng();
for _ in 0..20 {
let r = e.observe(0.50, PlatformContext::with_snr(-20.0));
assert_eq!(r.grammar, GrammarState::Admissible,
"sub-threshold must force Admissible, got {:?}", r.grammar);
assert_eq!(r.sign.drift, 0.0);
assert_eq!(r.sign.slew, 0.0);
}
}
#[test]
fn transition_window_no_escalation() {
let mut e = eng();
let ctx_t = PlatformContext::transition();
for _ in 0..30 {
let r = e.observe(999.0, ctx_t);
assert!(!matches!(r.policy, PolicyDecision::Review | PolicyDecision::Escalate),
"transition must suppress escalation, got {:?}", r.policy);
}
}
#[test]
fn nominal_signal_stays_silent() {
let mut e = eng();
let c = ctx(20.0);
for _ in 0..30 {
let r = e.observe(0.02, c);
assert_eq!(r.policy, PolicyDecision::Silent,
"nominal signal at k={} must be Silent, got {:?}", r.k, r.policy);
}
}
#[test]
fn sustained_drift_eventually_detected() {
let mut e = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0);
let c = ctx(20.0);
let mut detected = false;
for i in 0..60u32 {
let norm = 0.01 + i as f32 * 0.004;
let r = e.observe(norm, c);
if matches!(r.policy, PolicyDecision::Review | PolicyDecision::Escalate) {
detected = true;
break;
}
}
assert!(detected,
"Theorem 1: sustained drift must be detected in finite observations");
}
#[test]
fn calibration_produces_valid_engine() {
let healthy: [f32; 100] = core::array::from_fn(|i| 0.03 + i as f32 * 0.0002);
let e = DsfbRfEngine::<10, 4, 8>::from_calibration(&healthy, 2.0);
assert!(e.is_some());
let e = e.unwrap();
assert!(e.rho() > 0.0, "calibrated rho must be positive");
}
#[test]
fn reset_clears_observation_count() {
let mut e = eng();
let c = ctx(15.0);
for _ in 0..10 { e.observe(0.05, c); }
assert_eq!(e.obs_count(), 10);
e.reset();
assert_eq!(e.obs_count(), 0);
}
#[test]
fn engine_fits_in_reasonable_stack() {
let size = core::mem::size_of::<DsfbRfEngine<10, 4, 8>>();
assert!(size < 4096, "engine size {} bytes exceeds 4KB stack budget", size);
}
#[test]
fn contract_mode_is_read_only_side_channel() {
let e = eng();
let c = e.contract();
assert_eq!(c.integration_mode, "read_only_side_channel");
}
#[test]
fn contract_unsafe_count_zero() {
let e = eng();
assert_eq!(e.contract().unsafe_count, 0);
}
#[test]
fn contract_heap_policy_no_alloc() {
let e = eng();
let policy = e.contract().heap_policy;
assert!(policy.contains("no_alloc"), "heap policy must assert no_alloc: {}", policy);
}
#[test]
fn non_intrusive_contract_constant_accessible() {
assert_eq!(NON_INTRUSIVE_CONTRACT.integration_mode, "read_only_side_channel");
assert_eq!(NON_INTRUSIVE_CONTRACT.unsafe_count, 0);
}
#[test]
fn decimation_accumulator_emits_once_per_factor() {
let mut d = DecimationAccumulator::new(10);
for i in 0..9 {
assert!(d.push(0.05).is_none(), "expected None at sample {i}");
}
let rms = d.push(0.05);
assert!(rms.is_some(), "expected Some(rms) at 10th sample");
let v = rms.unwrap();
assert!((v - 0.05).abs() < 1e-5, "rms {v} not close to 0.05");
}
#[test]
fn decimation_accumulator_factor_one_emits_every_sample() {
let mut d = DecimationAccumulator::new(1);
for i in 0..20 {
assert!(d.push(0.03).is_some(), "factor=1 must emit at sample {i}");
}
}
#[test]
fn decimation_accumulator_zero_factor_treated_as_one() {
let mut d = DecimationAccumulator::new(0);
assert_eq!(d.factor(), 1, "factor=0 must be normalised to 1");
assert!(d.push(0.05).is_some(), "normalised factor=1 must emit immediately");
}
#[test]
fn decimation_accumulator_rms_of_mixed_norms() {
let mut d = DecimationAccumulator::new(4);
let norms = [0.0f32, 0.0, 0.0, 4.0]; for (i, &n) in norms.iter().enumerate() {
let r = d.push(n);
if i < 3 { assert!(r.is_none()); }
else { assert!((r.unwrap() - 2.0).abs() < 1e-4, "rms mismatch: {r:?}"); }
}
}
#[test]
fn observe_decimated_returns_none_then_some() {
let mut e = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0)
.with_decimation(5);
let c = ctx(20.0);
for _ in 0..4 {
assert!(e.observe_decimated(0.02, c).is_none());
}
assert!(e.observe_decimated(0.02, c).is_some());
}
#[test]
fn observe_decimated_factor_one_equiv_to_observe() {
let mut e1 = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0);
let mut e2 = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0).with_decimation(1);
let c = ctx(20.0);
for _ in 0..20 {
let r1 = e1.observe(0.03, c);
let r2 = e2.observe_decimated(0.03, c).unwrap();
assert_eq!(r1.policy, r2.policy,
"factor=1 observe_decimated must equal observe");
}
}
#[test]
fn decimation_theorem9_determinism_preserved() {
let inputs = [0.02f32, 0.04, 0.03, 0.05, 0.06,
0.07, 0.08, 0.07, 0.05, 0.03];
let c = ctx(20.0);
let mut e1 = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0).with_decimation(5);
let mut e2 = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0).with_decimation(5);
let mut out1: [Option<crate::policy::PolicyDecision>; 10] = [None; 10];
let mut out2: [Option<crate::policy::PolicyDecision>; 10] = [None; 10];
for (i, &n) in inputs.iter().enumerate() {
out1[i] = e1.observe_decimated(n, c).map(|r| r.policy);
out2[i] = e2.observe_decimated(n, c).map(|r| r.policy);
}
assert_eq!(out1, out2, "Theorem 9 must hold for decimated pipeline");
}
#[test]
fn decimation_factor_accessible_after_builder() {
let e = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0).with_decimation(1000);
assert_eq!(e.decimation_factor(), 1000);
}
#[test]
fn reset_clears_decimation_accumulator() {
let mut e = DsfbRfEngine::<10, 4, 8>::new(0.10, 2.0).with_decimation(10);
let c = ctx(20.0);
for _ in 0..5 { e.observe_decimated(0.05, c); }
e.reset();
for _ in 0..9 {
assert!(e.observe_decimated(0.05, c).is_none());
}
assert!(e.observe_decimated(0.05, c).is_some());
}
}