stemedb/crates/stemedb-api/tests/admission_integration.rs
jordan d3a88585fe feat: Phase 6 UAT - Admission control, HLC recency, cluster coordination
This commit includes comprehensive work on Phase 6 features:

## Admission Control (Phase 6 admission middleware)
- AdmissionStore implementation backed by TrustRankStore
- PoW verification with tier-based difficulty computation
- Trust tier progression (Newcomer → Established → Trusted → Authority)
- API integration with admission status endpoints

## HLC Recency Lens (Phase 6C)
- HlcRecencyLens for distributed system ordering
- Hybrid logical clock integration with causality preservation

## Cluster Coordination (Phase 6C)
- Multi-node cluster tests (availability, partition tolerance)
- CRDT convergence tests for anti-entropy sync
- Gateway handler improvements

## Aphoria Code Linter (Phase 2A)
- RFC/OWASP corpus builders with network fetching and caching
- Concept hierarchy with auto-alias creation on conflict detection
- Multiple security extractors (TLS, JWT, CORS, secrets, rate limiting)

## Code Organization
- Split large files into modules to comply with 500-line limit
- Improved test organization with separate test modules
- Fixed rkyv serialization for EigenTrustState (AgentScore struct)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 00:43:37 -07:00

126 lines
4.5 KiB
Rust

//! Integration tests for admission control (The Shield).
//!
//! These tests verify the DTO conversion and response formatting.
//! The core admission logic is tested in stemedb-storage unit tests.
use stemedb_api::dto::{AdmissionStatusResponse, TrustTierDto};
use stemedb_core::types::{AdmissionConfig, TrustTier};
use stemedb_storage::AdmissionStatus;
#[test]
fn test_trust_tier_dto_conversion() {
// Test all tier conversions
assert_eq!(TrustTierDto::from(TrustTier::Untrusted), TrustTierDto::Untrusted);
assert_eq!(TrustTierDto::from(TrustTier::Limited), TrustTierDto::Limited);
assert_eq!(TrustTierDto::from(TrustTier::Verified), TrustTierDto::Verified);
assert_eq!(TrustTierDto::from(TrustTier::Trusted), TrustTierDto::Trusted);
assert_eq!(TrustTierDto::from(TrustTier::Authority), TrustTierDto::Authority);
}
#[test]
fn test_admission_status_response_new_agent() {
let status = AdmissionStatus::new(0.5, 0, 16);
let config = AdmissionConfig::default();
let response = AdmissionStatusResponse::from_status("abc123".to_string(), &status, &config);
assert_eq!(response.tier, TrustTierDto::Verified);
assert!((response.trust_score - 0.5).abs() < f32::EPSILON);
assert_eq!(response.assertions_count, 0);
assert_eq!(response.pow_difficulty, 16);
assert!(response.pow_required);
assert_eq!(response.base_quota_limit, 10_000);
assert_eq!(response.effective_quota_limit, 10_000);
assert!((response.quota_multiplier - 1.0).abs() < f32::EPSILON);
// New agent should see milestones
assert_eq!(response.assertions_until_reduced_difficulty, Some(10));
assert_eq!(response.assertions_until_exemption, Some(50));
}
#[test]
fn test_admission_status_response_graduated() {
let status = AdmissionStatus::new(0.7, 100, 0);
let config = AdmissionConfig::default();
let response = AdmissionStatusResponse::from_status("graduated".to_string(), &status, &config);
assert_eq!(response.tier, TrustTierDto::Trusted);
assert!(!response.pow_required);
assert_eq!(response.pow_difficulty, 0);
assert_eq!(response.effective_quota_limit, 20_000);
// Graduated agent shouldn't see milestones
assert_eq!(response.assertions_until_reduced_difficulty, None);
assert_eq!(response.assertions_until_exemption, None);
}
#[test]
fn test_admission_status_response_partially_graduated() {
// Agent with 25 assertions (past initial, not yet graduated)
let status = AdmissionStatus::new(0.4, 25, 1);
let config = AdmissionConfig::default();
let response = AdmissionStatusResponse::from_status("partial".to_string(), &status, &config);
assert_eq!(response.tier, TrustTierDto::Limited);
assert!(response.pow_required);
assert_eq!(response.pow_difficulty, 1);
// Past initial threshold, so no "until reduced" milestone
assert_eq!(response.assertions_until_reduced_difficulty, None);
// Still 25 assertions until exemption
assert_eq!(response.assertions_until_exemption, Some(25));
}
#[test]
fn test_all_tier_quotas() {
let config = AdmissionConfig::default();
// Test each tier
let test_cases = [
(0.1, TrustTierDto::Untrusted, 1_000),
(0.4, TrustTierDto::Limited, 5_000),
(0.5, TrustTierDto::Verified, 10_000),
(0.8, TrustTierDto::Trusted, 20_000),
(0.95, TrustTierDto::Authority, 100_000),
];
for (score, expected_tier, expected_quota) in test_cases {
let status = AdmissionStatus::new(score, 100, 0);
let response = AdmissionStatusResponse::from_status("test".to_string(), &status, &config);
assert_eq!(response.tier, expected_tier, "Wrong tier for score {}", score);
assert_eq!(
response.effective_quota_limit, expected_quota,
"Wrong quota for score {}",
score
);
}
}
#[test]
fn test_pow_difficulty_graduation() {
let config = AdmissionConfig::default();
// First 10 assertions: 16 bits
for count in 0..10 {
let difficulty = config.compute_difficulty(count, 0.3);
assert_eq!(difficulty, 16, "Wrong difficulty for {} assertions", count);
}
// 10-49: 1 bit
for count in 10..50 {
let difficulty = config.compute_difficulty(count, 0.3);
assert_eq!(difficulty, 1, "Wrong difficulty for {} assertions", count);
}
// 50+: exempt
let difficulty = config.compute_difficulty(50, 0.3);
assert_eq!(difficulty, 0);
// Trust exemption
let difficulty = config.compute_difficulty(5, 0.6);
assert_eq!(difficulty, 0, "High trust should be exempt");
}