Files
wifi-densepose/crates/ruvector-mincut-gated-transformer/tests/gate.rs
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

432 lines
11 KiB
Rust

//! Gate decision tests.
//!
//! Verifies that synthetic lambda traces produce expected tier changes.
use ruvector_mincut_gated_transformer::{
gate::GateController, GateDecision, GatePacket, GatePolicy, GateReason, SpikePacket,
};
fn create_controller() -> GateController {
GateController::new(GatePolicy::default())
}
// ============ Lambda-based decisions ============
#[test]
fn test_lambda_above_min_allows() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100, // Well above min (30)
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::Allow);
assert_eq!(decision.tier, 0);
}
#[test]
fn test_lambda_below_min_quarantines() {
let controller = create_controller();
let gate = GatePacket {
lambda: 20, // Below min (30)
lambda_prev: 100,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::QuarantineUpdates);
assert_eq!(decision.reason, GateReason::LambdaBelowMin);
assert_eq!(decision.tier, 2);
}
#[test]
fn test_lambda_drop_flushes_kv() {
let controller = create_controller();
let gate = GatePacket {
lambda: 40,
lambda_prev: 100, // 60% drop - exceeds default max ~37.5%
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::FlushKv);
assert_eq!(decision.reason, GateReason::LambdaDroppedFast);
}
#[test]
fn test_lambda_gradual_drop_allows() {
let controller = create_controller();
let gate = GatePacket {
lambda: 90,
lambda_prev: 100, // 10% drop - within tolerance
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::Allow);
}
// ============ Boundary-based decisions ============
#[test]
fn test_boundary_spike_reduces_scope() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 30, // Above max (20)
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::ReduceScope);
assert_eq!(decision.reason, GateReason::BoundarySpike);
assert_eq!(decision.tier, 1);
}
#[test]
fn test_boundary_concentration_reduces_scope() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 25000, // Above max (~62.5%)
partition_count: 3,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::ReduceScope);
assert_eq!(decision.reason, GateReason::BoundaryConcentrationSpike);
}
// ============ Partition-based decisions ============
#[test]
fn test_partition_drift_reduces_scope() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 15, // Above max (10)
flags: 0,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::ReduceScope);
assert_eq!(decision.reason, GateReason::PartitionDrift);
}
// ============ Flag-based decisions ============
#[test]
fn test_force_safe_flag() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: GatePacket::FLAG_FORCE_SAFE,
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.decision, GateDecision::FreezeWrites);
assert_eq!(decision.reason, GateReason::ForcedByFlag);
assert_eq!(decision.tier, 2);
}
#[test]
fn test_skip_flag() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: GatePacket::FLAG_SKIP,
};
let decision = controller.evaluate(&gate, None);
assert!(decision.skip);
assert_eq!(decision.tier, 3);
}
// ============ Spike-based decisions ============
#[test]
fn test_spike_inactive_skips() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let spike = SpikePacket {
fired: 0, // Not fired
rate_q15: 10000,
novelty_q15: 15000,
..Default::default()
};
let decision = controller.evaluate(&gate, Some(&spike));
assert!(decision.skip);
assert_eq!(decision.tier, 3);
}
#[test]
fn test_spike_active_allows() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let spike = SpikePacket {
fired: 1, // Fired
rate_q15: 10000, // Normal rate
novelty_q15: 15000,
..Default::default()
};
let decision = controller.evaluate(&gate, Some(&spike));
assert!(!decision.skip);
assert_eq!(decision.decision, GateDecision::Allow);
}
#[test]
fn test_spike_storm_freezes() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
boundary_concentration_q15: 8192,
partition_count: 3,
flags: 0,
};
let spike = SpikePacket {
fired: 1,
rate_q15: 30000, // Very high - exceeds max
novelty_q15: 5000,
..Default::default()
};
let decision = controller.evaluate(&gate, Some(&spike));
assert_eq!(decision.decision, GateDecision::FreezeWrites);
assert_eq!(decision.reason, GateReason::SpikeStorm);
assert_eq!(decision.tier, 2);
}
// ============ Policy variants ============
#[test]
fn test_conservative_policy() {
let controller = GateController::new(GatePolicy::conservative());
// Same conditions that would pass with default policy
let gate = GatePacket {
lambda: 40, // Below conservative min (50) but above default (30)
lambda_prev: 45,
boundary_edges: 8, // Below conservative max (10)
boundary_concentration_q15: 12000,
partition_count: 4,
flags: 0,
};
let decision = controller.evaluate(&gate, None);
// Conservative should intervene
assert_eq!(decision.decision, GateDecision::QuarantineUpdates);
}
#[test]
fn test_permissive_policy() {
let controller = GateController::new(GatePolicy::permissive());
// Conditions that would trigger intervention with default policy
let gate = GatePacket {
lambda: 25, // Above permissive min (20) but below default (30)
lambda_prev: 35,
boundary_edges: 40, // Above default max (20) but below permissive (50)
boundary_concentration_q15: 20000,
partition_count: 15, // Above default max (10) but below permissive (20)
flags: 0,
};
let decision = controller.evaluate(&gate, None);
// Permissive should allow
assert_eq!(decision.decision, GateDecision::Allow);
}
// ============ Tier decision properties ============
#[test]
fn test_tier0_full_layers() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 5,
..Default::default()
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.tier, 0);
assert!(!decision.skip);
// In default controller, layers_to_run should be layers_normal (4)
assert_eq!(decision.layers_to_run, 4);
}
#[test]
fn test_tier1_reduced_layers() {
let controller = create_controller();
let gate = GatePacket {
lambda: 100,
lambda_prev: 95,
boundary_edges: 30, // Triggers ReduceScope
..Default::default()
};
let decision = controller.evaluate(&gate, None);
assert_eq!(decision.tier, 1);
// Should have reduced layers
assert!(decision.layers_to_run < 4);
}
#[test]
fn test_kv_writes_permission() {
let controller = create_controller();
// Allow case - KV writes enabled
let gate_allow = GatePacket {
lambda: 100,
lambda_prev: 95,
..Default::default()
};
let decision = controller.evaluate(&gate_allow, None);
assert!(decision.decision.allows_kv_writes());
// FreezeWrites case - KV writes disabled
let gate_freeze = GatePacket {
lambda: 100,
flags: GatePacket::FLAG_FORCE_SAFE,
..Default::default()
};
let decision = controller.evaluate(&gate_freeze, None);
assert!(!decision.decision.allows_kv_writes());
}
#[test]
fn test_external_writes_permission() {
let controller = create_controller();
// Allow case - external writes enabled
let gate_allow = GatePacket {
lambda: 100,
lambda_prev: 95,
..Default::default()
};
let decision = controller.evaluate(&gate_allow, None);
assert!(decision.decision.allows_external_writes());
// ReduceScope case - external writes disabled
let gate_reduce = GatePacket {
lambda: 100,
boundary_edges: 30,
..Default::default()
};
let decision = controller.evaluate(&gate_reduce, None);
assert!(!decision.decision.allows_external_writes());
}
// ============ Lambda delta calculation ============
#[test]
fn test_lambda_delta_positive() {
let gate = GatePacket {
lambda: 100,
lambda_prev: 80,
..Default::default()
};
assert_eq!(gate.lambda_delta(), 20);
}
#[test]
fn test_lambda_delta_negative() {
let gate = GatePacket {
lambda: 80,
lambda_prev: 100,
..Default::default()
};
assert_eq!(gate.lambda_delta(), -20);
}
#[test]
fn test_drop_ratio_calculation() {
let gate = GatePacket {
lambda: 50,
lambda_prev: 100, // 50% drop
..Default::default()
};
let ratio = gate.drop_ratio_q15();
// Should be around 16384 (50% of 32768)
assert!(ratio > 16000 && ratio < 17000);
}
#[test]
fn test_drop_ratio_no_drop() {
let gate = GatePacket {
lambda: 100,
lambda_prev: 80, // Increase, not drop
..Default::default()
};
let ratio = gate.drop_ratio_q15();
assert_eq!(ratio, 0);
}