Files
wifi-densepose/examples/edge-net/tests/rac_axioms_test.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

956 lines
28 KiB
Rust

//! Comprehensive test suite for RAC 12 Axioms
//!
//! This test suite validates the RuVector Adversarial Coherence implementation
//! against all 12 axioms of the Adversarial Coherence Thesis.
use ruvector_edge_net::rac::*;
use std::collections::HashMap;
// ============================================================================
// Test Utilities
// ============================================================================
/// Create a test event with specified parameters
fn create_test_event(
context: ContextId,
author: PublicKeyBytes,
kind: EventKind,
) -> Event {
Event {
id: [0u8; 32],
prev: None,
ts_unix_ms: 1609459200000, // 2021-01-01
author,
context,
ruvector: Ruvector::new(vec![1.0, 0.0, 0.0]),
kind,
sig: vec![0u8; 64],
}
}
/// Create a test assertion event
fn create_assert_event(proposition: &str, confidence: f32) -> AssertEvent {
AssertEvent {
proposition: proposition.as_bytes().to_vec(),
evidence: vec![EvidenceRef::hash(&[1, 2, 3])],
confidence,
expires_at_unix_ms: None,
}
}
/// Simple verifier for testing
struct TestVerifier;
impl Verifier for TestVerifier {
fn incompatible(&self, _context: &ContextId, a: &AssertEvent, b: &AssertEvent) -> bool {
// Simple incompatibility: different propositions with high confidence
a.proposition != b.proposition && a.confidence > 0.8 && b.confidence > 0.8
}
}
/// Simple authority policy for testing
struct TestAuthorityPolicy {
authorized_contexts: HashMap<String, Vec<PublicKeyBytes>>,
}
impl AuthorityPolicy for TestAuthorityPolicy {
fn authorized(&self, context: &ContextId, resolution: &ResolutionEvent) -> bool {
let context_key = hex::encode(context);
if let Some(authorized_keys) = self.authorized_contexts.get(&context_key) {
// Check if any resolution signature is from authorized key
// In real implementation, would verify signatures
!authorized_keys.is_empty() && !resolution.authority_sigs.is_empty()
} else {
false
}
}
fn quarantine_level(&self, _context: &ContextId, _conflict_id: &[u8; 32]) -> QuarantineLevel {
QuarantineLevel::RequiresWitness
}
}
// ============================================================================
// Axiom 1: Connectivity is not truth
// ============================================================================
#[test]
fn axiom1_connectivity_not_truth() {
// High similarity does not imply correctness
let correct_claim = Ruvector::new(vec![1.0, 0.0, 0.0]);
let similar_wrong = Ruvector::new(vec![0.95, 0.31, 0.0]); // ~95% similar
let dissimilar_correct = Ruvector::new(vec![0.0, 1.0, 0.0]); // 0% similar
let similarity = correct_claim.similarity(&similar_wrong);
assert!(similarity > 0.9, "Claims are highly similar");
// Despite high similarity, semantic verification is required
let verifier = TestVerifier;
let context = [0u8; 32];
let assert_correct = create_assert_event("sky is blue", 0.95);
let assert_similar_wrong = create_assert_event("sky is green", 0.95);
// Verifier detects incompatibility despite structural similarity
assert!(
verifier.incompatible(&context, &assert_correct, &assert_similar_wrong),
"High similarity does not prevent conflict detection"
);
}
#[test]
fn axiom1_structural_metrics_insufficient() {
// Low connectivity (low similarity) can still be correct
let baseline = Ruvector::new(vec![1.0, 0.0, 0.0]);
let low_connectivity = Ruvector::new(vec![0.0, 0.0, 1.0]);
let similarity = baseline.similarity(&low_connectivity);
assert!(similarity < 0.1, "Very low structural connectivity");
// But both can be correct in different contexts
// Connectivity bounds failure modes, not correctness
}
// ============================================================================
// Axiom 2: Everything is an event
// ============================================================================
#[test]
fn axiom2_all_operations_are_events() {
let context = [1u8; 32];
let author = [2u8; 32];
// Test all event types
let assert_event = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("test claim", 0.9)),
);
assert!(matches!(assert_event.kind, EventKind::Assert(_)));
let challenge_event = create_test_event(
context,
author,
EventKind::Challenge(ChallengeEvent {
conflict_id: [3u8; 32],
claim_ids: vec![[4u8; 32]],
reason: "Disputed".to_string(),
requested_proofs: vec!["merkle".to_string()],
}),
);
assert!(matches!(challenge_event.kind, EventKind::Challenge(_)));
let support_event = create_test_event(
context,
author,
EventKind::Support(SupportEvent {
conflict_id: [3u8; 32],
claim_id: [4u8; 32],
evidence: vec![EvidenceRef::url("https://evidence.com")],
cost: 100,
}),
);
assert!(matches!(support_event.kind, EventKind::Support(_)));
let resolution_event = create_test_event(
context,
author,
EventKind::Resolution(ResolutionEvent {
conflict_id: [3u8; 32],
accepted: vec![[4u8; 32]],
deprecated: vec![[5u8; 32]],
rationale: vec![EvidenceRef::hash(&[6, 7, 8])],
authority_sigs: vec![vec![0u8; 64]],
}),
);
assert!(matches!(resolution_event.kind, EventKind::Resolution(_)));
let deprecate_event = create_test_event(
context,
author,
EventKind::Deprecate(DeprecateEvent {
claim_id: [4u8; 32],
by_resolution: [3u8; 32],
superseded_by: Some([7u8; 32]),
}),
);
assert!(matches!(deprecate_event.kind, EventKind::Deprecate(_)));
}
#[test]
fn axiom2_events_appended_to_log() {
let log = EventLog::new();
assert_eq!(log.len(), 0);
let event1 = create_test_event(
[1u8; 32],
[2u8; 32],
EventKind::Assert(create_assert_event("claim 1", 0.8)),
);
let event2 = create_test_event(
[1u8; 32],
[2u8; 32],
EventKind::Assert(create_assert_event("claim 2", 0.9)),
);
log.append(event1);
log.append(event2);
assert_eq!(log.len(), 2, "All events logged");
assert!(!log.is_empty());
}
// ============================================================================
// Axiom 3: No destructive edits
// ============================================================================
#[test]
fn axiom3_deprecation_not_deletion() {
let mut engine = CoherenceEngine::new();
let context = [1u8; 32];
let author = [2u8; 32];
// Create and ingest an assertion
let mut assert_event = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("initial claim", 0.9)),
);
assert_event.id = [10u8; 32];
engine.ingest(assert_event.clone());
assert_eq!(engine.event_count(), 1);
// Deprecate the claim
let deprecate_event = create_test_event(
context,
author,
EventKind::Deprecate(DeprecateEvent {
claim_id: assert_event.id,
by_resolution: [99u8; 32],
superseded_by: Some([11u8; 32]),
}),
);
engine.ingest(deprecate_event);
assert_eq!(engine.event_count(), 2, "Deprecated event still in log");
// Verify claim is quarantined but not deleted
let claim_id_hex = hex::encode(&assert_event.id);
assert_eq!(
engine.get_quarantine_level(&claim_id_hex),
3,
"Deprecated claim is blocked"
);
assert!(!engine.can_use_claim(&claim_id_hex), "Cannot use deprecated claim");
}
#[test]
fn axiom3_append_only_log() {
let log = EventLog::new();
let initial_root = log.get_root();
let event1 = create_test_event(
[1u8; 32],
[2u8; 32],
EventKind::Assert(create_assert_event("claim", 0.9)),
);
log.append(event1);
let root_after_append = log.get_root();
// Root changes after append (events affect history)
assert_ne!(initial_root, root_after_append, "Merkle root changes on append");
// Cannot remove events - only append
// Log length only increases
assert_eq!(log.len(), 1);
}
// ============================================================================
// Axiom 4: Every claim is scoped
// ============================================================================
#[test]
fn axiom4_claims_bound_to_context() {
let context_a = [1u8; 32];
let context_b = [2u8; 32];
let author = [3u8; 32];
let event_a = create_test_event(
context_a,
author,
EventKind::Assert(create_assert_event("claim in context A", 0.9)),
);
let event_b = create_test_event(
context_b,
author,
EventKind::Assert(create_assert_event("claim in context B", 0.9)),
);
assert_eq!(event_a.context, context_a, "Event bound to context A");
assert_eq!(event_b.context, context_b, "Event bound to context B");
assert_ne!(event_a.context, event_b.context, "Different contexts");
}
#[test]
fn axiom4_context_isolation() {
let log = EventLog::new();
let context_a = [1u8; 32];
let context_b = [2u8; 32];
let author = [3u8; 32];
let mut event_a = create_test_event(
context_a,
author,
EventKind::Assert(create_assert_event("claim A", 0.9)),
);
event_a.id = [10u8; 32];
let mut event_b = create_test_event(
context_b,
author,
EventKind::Assert(create_assert_event("claim B", 0.9)),
);
event_b.id = [11u8; 32];
log.append(event_a);
log.append(event_b);
// Filter by context
let events_a = log.for_context(&context_a);
let events_b = log.for_context(&context_b);
assert_eq!(events_a.len(), 1, "One event in context A");
assert_eq!(events_b.len(), 1, "One event in context B");
assert_eq!(events_a[0].context, context_a);
assert_eq!(events_b[0].context, context_b);
}
// ============================================================================
// Axiom 5: Semantics drift is expected
// ============================================================================
#[test]
fn axiom5_drift_measurement() {
let baseline = Ruvector::new(vec![1.0, 0.0, 0.0]);
let slightly_drifted = Ruvector::new(vec![0.95, 0.1, 0.0]);
let heavily_drifted = Ruvector::new(vec![0.5, 0.5, 0.5]);
let slight_drift = slightly_drifted.drift_from(&baseline);
let heavy_drift = heavily_drifted.drift_from(&baseline);
assert!(slight_drift > 0.0, "Drift detected");
assert!(slight_drift < 0.3, "Slight drift is small");
assert!(heavy_drift > 0.4, "Heavy drift is large");
assert!(heavy_drift > slight_drift, "Drift increases over time");
}
#[test]
fn axiom5_drift_not_denied() {
// Drift is expected and measured, not treated as error
let baseline = Ruvector::new(vec![1.0, 0.0, 0.0]);
let drifted = Ruvector::new(vec![0.0, 1.0, 0.0]);
let drift = drifted.drift_from(&baseline);
// Maximum drift (orthogonal vectors)
assert!((drift - 1.0).abs() < 0.001, "Maximum drift measured");
// System should manage drift, not reject it
// This test passes if drift calculation succeeds without error
}
// ============================================================================
// Axiom 6: Disagreement is signal
// ============================================================================
#[test]
fn axiom6_conflict_detection_triggers_quarantine() {
let mut engine = CoherenceEngine::new();
let context = [1u8; 32];
let author = [2u8; 32];
// Create two conflicting claims
let mut claim1 = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("sky is blue", 0.95)),
);
claim1.id = [10u8; 32];
let mut claim2 = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("sky is green", 0.95)),
);
claim2.id = [11u8; 32];
engine.ingest(claim1.clone());
engine.ingest(claim2.clone());
// Issue challenge
let challenge = create_test_event(
context,
author,
EventKind::Challenge(ChallengeEvent {
conflict_id: [99u8; 32],
claim_ids: vec![claim1.id, claim2.id],
reason: "Contradictory color claims".to_string(),
requested_proofs: vec![],
}),
);
engine.ingest(challenge);
// Verify both claims are quarantined
assert_eq!(
engine.get_quarantine_level(&hex::encode(&claim1.id)),
2,
"Claim 1 quarantined"
);
assert_eq!(
engine.get_quarantine_level(&hex::encode(&claim2.id)),
2,
"Claim 2 quarantined"
);
assert_eq!(engine.conflict_count(), 1, "Conflict recorded");
}
#[test]
fn axiom6_epistemic_temperature_tracking() {
let conflict = Conflict {
id: [1u8; 32],
context: [2u8; 32],
claim_ids: vec![[3u8; 32], [4u8; 32]],
detected_at: 1609459200000,
status: ConflictStatus::Challenged,
temperature: 0.5,
escalation_count: 0,
};
assert!(conflict.temperature > 0.0, "Temperature tracked");
assert!(conflict.temperature <= 1.0, "Temperature normalized");
// Sustained contradictions should increase temperature
// (Implementation detail - would need history tracking)
}
// ============================================================================
// Axiom 7: Authority is scoped, not global
// ============================================================================
#[test]
fn axiom7_scoped_authority_verification() {
let context_a = [1u8; 32];
let context_b = [2u8; 32];
let authorized_key = [3u8; 32];
let unauthorized_key = [4u8; 32];
let mut policy = TestAuthorityPolicy {
authorized_contexts: HashMap::new(),
};
policy.authorized_contexts.insert(
hex::encode(&context_a),
vec![authorized_key],
);
// Resolution in authorized context
let authorized_resolution = ResolutionEvent {
conflict_id: [99u8; 32],
accepted: vec![[10u8; 32]],
deprecated: vec![],
rationale: vec![],
authority_sigs: vec![vec![0u8; 64]], // Simulated signature
};
assert!(
policy.authorized(&context_a, &authorized_resolution),
"Authorized in context A"
);
assert!(
!policy.authorized(&context_b, &authorized_resolution),
"Not authorized in context B"
);
}
#[test]
fn axiom7_threshold_authority() {
let context = [1u8; 32];
let key1 = [1u8; 32];
let key2 = [2u8; 32];
let key3 = [3u8; 32];
let authority = ScopedAuthority {
context,
authorized_keys: vec![key1, key2, key3],
threshold: 2, // 2-of-3 required
allowed_evidence: vec!["merkle".to_string()],
};
assert_eq!(authority.threshold, 2, "Threshold set");
assert_eq!(authority.authorized_keys.len(), 3, "3 authorized keys");
// Real implementation would verify k-of-n signatures
}
// ============================================================================
// Axiom 8: Witnesses matter
// ============================================================================
#[test]
fn axiom8_witness_cost_tracking() {
let support = SupportEvent {
conflict_id: [1u8; 32],
claim_id: [2u8; 32],
evidence: vec![
EvidenceRef::url("https://source1.com"),
EvidenceRef::hash(&[3, 4, 5]),
],
cost: 100,
};
assert!(support.cost > 0, "Witness has cost/stake");
assert!(support.evidence.len() > 1, "Multiple evidence sources");
}
#[test]
fn axiom8_evidence_diversity() {
// Different evidence types indicate diversity
let hash_evidence = EvidenceRef::hash(&[1, 2, 3]);
let url_evidence = EvidenceRef::url("https://example.com");
assert_eq!(hash_evidence.kind, "hash");
assert_eq!(url_evidence.kind, "url");
assert_ne!(hash_evidence.kind, url_evidence.kind, "Diverse evidence types");
}
// Note: Full witness path independence verification requires implementation
// ============================================================================
// Axiom 9: Quarantine is mandatory
// ============================================================================
#[test]
fn axiom9_contested_claims_quarantined() {
let manager = QuarantineManager::new();
// Initially no quarantine
assert!(manager.can_use("claim-1"));
assert_eq!(manager.get_level("claim-1"), QuarantineLevel::None as u8);
// Quarantine contested claim
manager.set_level("claim-1", QuarantineLevel::Blocked as u8);
assert!(!manager.can_use("claim-1"), "Quarantined claim cannot be used");
assert_eq!(manager.quarantined_count(), 1);
}
#[test]
fn axiom9_quarantine_levels_enforced() {
let manager = QuarantineManager::new();
// Test all quarantine levels
manager.set_level("claim-none", QuarantineLevel::None as u8);
manager.set_level("claim-conservative", QuarantineLevel::Conservative as u8);
manager.set_level("claim-witness", QuarantineLevel::RequiresWitness as u8);
manager.set_level("claim-blocked", QuarantineLevel::Blocked as u8);
assert!(manager.can_use("claim-none"));
assert!(manager.can_use("claim-conservative"));
assert!(manager.can_use("claim-witness"));
assert!(!manager.can_use("claim-blocked"), "Blocked claims unusable");
assert_eq!(manager.quarantined_count(), 3, "3 quarantined claims");
}
#[test]
fn axiom9_quarantine_prevents_decision_use() {
let mut engine = CoherenceEngine::new();
let context = [1u8; 32];
let author = [2u8; 32];
let mut claim = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("disputed claim", 0.9)),
);
claim.id = [10u8; 32];
engine.ingest(claim.clone());
// Quarantine the claim
let challenge = create_test_event(
context,
author,
EventKind::Challenge(ChallengeEvent {
conflict_id: [99u8; 32],
claim_ids: vec![claim.id],
reason: "Disputed".to_string(),
requested_proofs: vec![],
}),
);
engine.ingest(challenge);
// Create decision trace depending on quarantined claim
let trace = DecisionTrace::new(vec![claim.id], vec![1, 2, 3]);
assert!(!trace.can_replay(&engine), "Decision cannot be replayed with quarantined dependency");
}
// ============================================================================
// Axiom 10: All decisions are replayable
// ============================================================================
#[test]
fn axiom10_decision_trace_completeness() {
let dep1 = [1u8; 32];
let dep2 = [2u8; 32];
let outcome = vec![10, 20, 30];
let trace = DecisionTrace::new(vec![dep1, dep2], outcome.clone());
assert_eq!(trace.dependencies.len(), 2, "All dependencies recorded");
assert_eq!(trace.outcome, outcome, "Outcome recorded");
assert!(trace.timestamp > 0, "Timestamp recorded");
assert!(!trace.has_disputed, "Dispute flag tracked");
assert!(!trace.quarantine_policy.is_empty(), "Policy recorded");
}
#[test]
fn axiom10_decision_replayability() {
let engine = CoherenceEngine::new();
// Decision with no dependencies
let trace = DecisionTrace::new(vec![], vec![1, 2, 3]);
assert!(trace.can_replay(&engine), "Decision with no dependencies is replayable");
// Decision with valid (non-quarantined) dependency
let mut engine2 = CoherenceEngine::new();
let context = [1u8; 32];
let author = [2u8; 32];
let mut claim = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("valid claim", 0.9)),
);
claim.id = [10u8; 32];
engine2.ingest(claim.clone());
let trace2 = DecisionTrace::new(vec![claim.id], vec![1, 2, 3]);
assert!(trace2.can_replay(&engine2), "Decision with valid dependencies is replayable");
}
// ============================================================================
// Axiom 11: Equivocation is detectable
// ============================================================================
#[test]
fn axiom11_merkle_root_changes_on_append() {
let log = EventLog::new();
let root1 = log.get_root();
let event = create_test_event(
[1u8; 32],
[2u8; 32],
EventKind::Assert(create_assert_event("claim", 0.9)),
);
log.append(event);
let root2 = log.get_root();
assert_ne!(root1, root2, "Merkle root changes on append");
// Different histories produce different roots
// Making it hard to show different histories to different peers
}
#[test]
fn axiom11_inclusion_proof_generation() {
let log = EventLog::new();
let mut event = create_test_event(
[1u8; 32],
[2u8; 32],
EventKind::Assert(create_assert_event("claim", 0.9)),
);
event.id = [10u8; 32];
let event_id = log.append(event);
let proof = log.prove_inclusion(&event_id);
assert!(proof.is_some(), "Inclusion proof generated");
let proof = proof.unwrap();
assert_eq!(proof.event_id, event_id, "Proof references correct event");
// Compare root bytes properly (get_root returns hex string)
let expected_root = hex::decode(log.get_root()).unwrap();
assert_eq!(proof.root.to_vec(), expected_root, "Proof includes root");
}
#[test]
fn axiom11_event_chaining() {
let mut prev_id: Option<EventId> = None;
for i in 0..3 {
let mut event = create_test_event(
[1u8; 32],
[2u8; 32],
EventKind::Assert(create_assert_event(&format!("claim {}", i), 0.9)),
);
event.prev = prev_id;
event.id = [i; 32];
if i > 0 {
assert!(event.prev.is_some(), "Event chains to previous");
}
prev_id = Some(event.id);
}
}
// ============================================================================
// Axiom 12: Local learning is allowed
// ============================================================================
#[test]
fn axiom12_learning_attribution() {
let author = [42u8; 32];
let event = create_test_event(
[1u8; 32],
author,
EventKind::Assert(create_assert_event("learned pattern", 0.85)),
);
assert_eq!(event.author, author, "Learning attributed to author");
// Events are signed (in real implementation)
assert!(!event.sig.is_empty(), "Event is signed");
}
#[test]
fn axiom12_learning_is_challengeable() {
let mut engine = CoherenceEngine::new();
let context = [1u8; 32];
let author = [2u8; 32];
// Local learning produces a claim
let mut learned_claim = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("AI learned pattern", 0.9)),
);
learned_claim.id = [20u8; 32];
engine.ingest(learned_claim.clone());
// Learning can be challenged like any other claim
let challenge = create_test_event(
context,
[3u8; 32], // Different author challenges
EventKind::Challenge(ChallengeEvent {
conflict_id: [99u8; 32],
claim_ids: vec![learned_claim.id],
reason: "Learned pattern incorrect".to_string(),
requested_proofs: vec!["training_data".to_string()],
}),
);
engine.ingest(challenge);
// Challenged learning is quarantined
assert_eq!(
engine.get_quarantine_level(&hex::encode(&learned_claim.id)),
2,
"Challenged learning is quarantined"
);
}
#[test]
fn axiom12_learning_is_rollbackable() {
let mut engine = CoherenceEngine::new();
let context = [1u8; 32];
let author = [2u8; 32];
// Original learning
let mut old_learning = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("v1 pattern", 0.8)),
);
old_learning.id = [30u8; 32];
engine.ingest(old_learning.clone());
// New learning supersedes old
let mut new_learning = create_test_event(
context,
author,
EventKind::Assert(create_assert_event("v2 pattern", 0.9)),
);
new_learning.id = [31u8; 32];
engine.ingest(new_learning.clone());
// Deprecate old learning
let deprecate = create_test_event(
context,
author,
EventKind::Deprecate(DeprecateEvent {
claim_id: old_learning.id,
by_resolution: [99u8; 32],
superseded_by: Some(new_learning.id),
}),
);
engine.ingest(deprecate);
// Old learning is rolled back but not deleted (3 events: old, new, deprecate)
assert_eq!(engine.event_count(), 3, "All events preserved");
assert!(!engine.can_use_claim(&hex::encode(&old_learning.id)), "Old learning not usable");
}
// ============================================================================
// Integration Tests
// ============================================================================
#[test]
fn integration_full_dispute_lifecycle() {
let mut engine = CoherenceEngine::new();
let context = [1u8; 32];
let author1 = [2u8; 32];
let author2 = [3u8; 32];
// Step 1: Two agents make conflicting claims
let mut claim1 = create_test_event(
context,
author1,
EventKind::Assert(create_assert_event("answer is 42", 0.95)),
);
claim1.id = [10u8; 32];
let mut claim2 = create_test_event(
context,
author2,
EventKind::Assert(create_assert_event("answer is 43", 0.95)),
);
claim2.id = [11u8; 32];
engine.ingest(claim1.clone());
engine.ingest(claim2.clone());
assert_eq!(engine.event_count(), 2);
// Step 2: Conflict detected and challenged
let challenge = create_test_event(
context,
author1,
EventKind::Challenge(ChallengeEvent {
conflict_id: [99u8; 32],
claim_ids: vec![claim1.id, claim2.id],
reason: "Contradictory answers".to_string(),
requested_proofs: vec!["computation".to_string()],
}),
);
engine.ingest(challenge);
assert_eq!(engine.conflict_count(), 1, "Conflict recorded");
assert_eq!(engine.quarantined_count(), 2, "Both claims quarantined");
// Step 3: Evidence provided
let support = create_test_event(
context,
author1,
EventKind::Support(SupportEvent {
conflict_id: [99u8; 32],
claim_id: claim1.id,
evidence: vec![EvidenceRef::url("https://proof.com/42")],
cost: 100,
}),
);
engine.ingest(support);
// Step 4: Resolution
let resolution = create_test_event(
context,
[4u8; 32], // Authority
EventKind::Resolution(ResolutionEvent {
conflict_id: [99u8; 32],
accepted: vec![claim1.id],
deprecated: vec![claim2.id],
rationale: vec![EvidenceRef::hash(&[1, 2, 3])],
authority_sigs: vec![vec![0u8; 64]],
}),
);
engine.ingest(resolution);
// Step 5: Verify resolution applied
assert!(!engine.can_use_claim(&hex::encode(&claim2.id)), "Rejected claim blocked");
assert!(engine.can_use_claim(&hex::encode(&claim1.id)), "Accepted claim usable");
// All events preserved in log (claim1, claim2, challenge, support, resolution = 5)
assert_eq!(engine.event_count(), 5, "Complete history preserved");
}
#[test]
fn integration_cross_context_isolation() {
let mut engine = CoherenceEngine::new();
let context_math = [1u8; 32];
let context_physics = [2u8; 32];
let author = [3u8; 32];
// Claim in math context
let mut math_claim = create_test_event(
context_math,
author,
EventKind::Assert(create_assert_event("2+2=4", 1.0)),
);
math_claim.id = [10u8; 32];
// Claim in physics context
let mut physics_claim = create_test_event(
context_physics,
author,
EventKind::Assert(create_assert_event("e=mc^2", 1.0)),
);
physics_claim.id = [11u8; 32];
engine.ingest(math_claim.clone());
engine.ingest(physics_claim.clone());
// Challenge in math context
let math_challenge = create_test_event(
context_math,
author,
EventKind::Challenge(ChallengeEvent {
conflict_id: [99u8; 32],
claim_ids: vec![math_claim.id],
reason: "Disputed".to_string(),
requested_proofs: vec![],
}),
);
engine.ingest(math_challenge);
// Only math claim should be quarantined
assert_eq!(
engine.get_quarantine_level(&hex::encode(&math_claim.id)),
2,
"Math claim quarantined"
);
assert_eq!(
engine.get_quarantine_level(&hex::encode(&physics_claim.id)),
0,
"Physics claim unaffected"
);
}