use crate::report::AttackResult;
use serde::Serialize;
#[path = "memory_poison_next/mod.rs"]
mod memory_poison_next;
#[derive(Debug, Clone, Serialize)]
pub struct PoisonResult {
pub vector_id: String,
pub condition: String,
pub phase_a_injected: bool,
pub phase_b_delay_turns: u32,
pub phase_c_triggered: bool,
pub poison_retained: bool,
pub activation_succeeded: bool,
pub expected_classification: String,
pub observed_classification: String,
pub outcome: PoisonOutcome,
pub hypothesis_tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum PoisonOutcome {
NoEffect,
RetainedNoActivation,
ActivationWithCorrectDetection,
ActivationWithMisclassification,
ActivationWithPolicyShift,
}
pub fn vector1_replay_baseline_poisoning(delay_turns: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::vector1_replay_baseline_poisoning(delay_turns)
}
pub fn vector2_deny_convergence_poisoning(delay_turns: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::vector2_deny_convergence_poisoning(delay_turns)
}
pub fn vector3_context_envelope_poisoning(delay_turns: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::vector3_context_envelope_poisoning(delay_turns)
}
pub fn vector4_decay_escape(decay_runs: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::vector4_decay_escape(decay_runs)
}
pub fn control_b1_run_metadata_recall(delay_turns: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::control_b1_run_metadata_recall(delay_turns)
}
pub fn control_b2_tool_observation_recall(delay_turns: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::control_b2_tool_observation_recall(delay_turns)
}
pub fn control_b3_approval_context_recall(delay_turns: u32) -> (PoisonResult, AttackResult) {
memory_poison_next::control_b3_approval_context_recall(delay_turns)
}
pub fn run_memory_poison_matrix() -> (Vec<PoisonResult>, Vec<AttackResult>) {
memory_poison_next::run_memory_poison_matrix()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vector1_activates_under_condition_a() {
let (pr, _) = vector1_replay_baseline_poisoning(1);
assert!(pr.activation_succeeded);
assert_eq!(pr.outcome, PoisonOutcome::ActivationWithMisclassification);
}
#[test]
fn vector2_activates_under_condition_a() {
let (pr, _) = vector2_deny_convergence_poisoning(1);
assert!(pr.phase_c_triggered);
}
#[test]
fn vector3_activates_under_condition_a() {
let (pr, _) = vector3_context_envelope_poisoning(1);
assert!(pr.activation_succeeded);
assert_eq!(pr.outcome, PoisonOutcome::ActivationWithPolicyShift);
}
#[test]
fn vector4_snapshot_diverges() {
let (pr, _) = vector4_decay_escape(1);
assert!(pr.activation_succeeded);
}
#[test]
fn controls_produce_no_false_positives() {
for delay in [1, 2, 3] {
let (pr1, _) = control_b1_run_metadata_recall(delay);
assert_eq!(pr1.outcome, PoisonOutcome::NoEffect);
let (pr2, _) = control_b2_tool_observation_recall(delay);
assert_eq!(pr2.outcome, PoisonOutcome::NoEffect);
let (pr3, _) = control_b3_approval_context_recall(delay);
assert_eq!(pr3.outcome, PoisonOutcome::NoEffect);
}
}
#[test]
fn full_matrix_runs_without_panic() {
let (results, attacks) = run_memory_poison_matrix();
assert_eq!(results.len(), 45);
assert_eq!(attacks.len(), 45);
}
#[test]
fn condition_b_blocks_v1_and_v2() {
let (results, _) = run_memory_poison_matrix();
for pr in results.iter().filter(|r| r.condition == "condition_b") {
if pr.vector_id == "v1_replay_baseline" || pr.vector_id == "v2_deny_convergence" {
assert_eq!(
pr.outcome,
PoisonOutcome::ActivationWithCorrectDetection,
"{} should be detected under Condition B",
pr.vector_id
);
}
}
}
#[test]
fn condition_c_blocks_v3() {
let (results, _) = run_memory_poison_matrix();
for pr in results
.iter()
.filter(|r| r.condition == "condition_c" && r.vector_id == "v3_context_envelope")
{
assert_eq!(
pr.outcome,
PoisonOutcome::ActivationWithCorrectDetection,
"V3 should be detected under Condition C"
);
}
}
#[test]
fn overarching_invariant_controls_never_misclassify() {
let (results, _) = run_memory_poison_matrix();
for pr in &results {
if pr.vector_id.starts_with("control_") {
assert_ne!(
pr.outcome,
PoisonOutcome::ActivationWithMisclassification,
"control {} had false positive",
pr.vector_id
);
assert_ne!(
pr.outcome,
PoisonOutcome::ActivationWithPolicyShift,
"control {} had policy shift",
pr.vector_id
);
}
}
}
}