use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
pub const MAX_SCORE: u32 = 1000;
pub const SWARM_COORDINATOR_THRESHOLD: u32 = 500;
pub const COLLATERAL_THRESHOLD: u32 = 300;
pub const DECAY_HALF_LIFE_DAYS: u64 = 90;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum CaptureLayer {
Shopping = 1,
Referral = 2,
Attention = 3,
Data = 4,
Insurance = 5,
Compute = 6,
Network = 7,
Energy = 8,
DePINAggregator = 9,
InferenceArbitrage = 10,
StorageDePIN = 11,
Skill = 12,
CurationSignal = 13,
Social = 14,
KnowledgeAPI = 15,
PersonalModelLicensing = 16,
Liquidity = 17,
GovernanceProxy = 18,
InventoryArbitrage = 19,
SubAgentManager = 20,
ReputationCollateral = 21,
SwarmCoordinationFee = 22,
}
impl CaptureLayer {
pub fn group(&self) -> LayerGroup {
match *self as u8 {
1..=5 => LayerGroup::PassiveUtility,
6..=11 => LayerGroup::Infrastructure,
12..=16 => LayerGroup::Intelligence,
17..=22 => LayerGroup::AggressiveAutopilot,
_ => LayerGroup::PassiveUtility,
}
}
pub fn reputation_weight(&self) -> f64 {
match self {
CaptureLayer::Shopping => 1.0,
CaptureLayer::Referral => 0.8,
CaptureLayer::Attention => 0.5,
CaptureLayer::Data => 1.2,
CaptureLayer::Insurance => 0.7,
CaptureLayer::Compute => 1.5,
CaptureLayer::Network => 2.0,
CaptureLayer::Energy => 1.3,
CaptureLayer::DePINAggregator => 1.4,
CaptureLayer::InferenceArbitrage => 1.8,
CaptureLayer::StorageDePIN => 1.2,
CaptureLayer::Skill => 2.5,
CaptureLayer::CurationSignal => 2.0,
CaptureLayer::Social => 1.5,
CaptureLayer::KnowledgeAPI => 2.2,
CaptureLayer::PersonalModelLicensing => 3.0,
CaptureLayer::Liquidity => 1.8,
CaptureLayer::GovernanceProxy => 1.5,
CaptureLayer::InventoryArbitrage => 1.2,
CaptureLayer::SubAgentManager => 2.5,
CaptureLayer::ReputationCollateral => 2.0,
CaptureLayer::SwarmCoordinationFee => 3.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum LayerGroup {
PassiveUtility,
Infrastructure,
Intelligence,
AggressiveAutopilot,
}
pub trait Attestation: Send + Sync {
fn layer(&self) -> CaptureLayer;
fn timestamp(&self) -> u64;
fn is_positive(&self) -> bool;
fn magnitude(&self) -> u64;
fn metadata(&self) -> Option<&AttestationMetadata>;
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AttestationMetadata {
pub lock_duration_days: Option<u16>,
pub held_to_maturity: Option<bool>,
pub accuracy_percent: Option<u8>,
pub conversion_rate: Option<u8>,
pub referral_successful: Option<bool>,
pub network_reach: Option<u32>,
pub uptime_percent: Option<u8>,
pub yield_bps: Option<u16>,
pub completion_rate: Option<u8>,
pub difficulty_tier: Option<u8>,
pub verification_multiplier: Option<f32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CredentialCategory {
ProfessionalLicense,
TechnicalCertification,
AcademicDegree,
ProfessionalExperience,
SkillDemonstration,
ApiContribution,
}
impl CredentialCategory {
pub fn base_weight(&self) -> u32 {
match self {
CredentialCategory::ProfessionalLicense => 100,
CredentialCategory::TechnicalCertification => 75,
CredentialCategory::AcademicDegree => 80,
CredentialCategory::ProfessionalExperience => 10, CredentialCategory::SkillDemonstration => 50,
CredentialCategory::ApiContribution => 5, }
}
pub fn is_per_unit(&self) -> bool {
matches!(
self,
CredentialCategory::ProfessionalExperience | CredentialCategory::ApiContribution
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum DifficultyTier {
EntryLevel = 1,
Intermediate = 2,
Professional = 3,
Advanced = 4,
Expert = 5,
}
impl DifficultyTier {
pub fn multiplier(&self) -> f64 {
match self {
DifficultyTier::EntryLevel => 0.5,
DifficultyTier::Intermediate => 0.75,
DifficultyTier::Professional => 1.0,
DifficultyTier::Advanced => 1.5,
DifficultyTier::Expert => 2.0,
}
}
pub fn from_u8(val: u8) -> Self {
match val {
1 => DifficultyTier::EntryLevel,
2 => DifficultyTier::Intermediate,
4 => DifficultyTier::Advanced,
5 => DifficultyTier::Expert,
_ => DifficultyTier::Professional,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum VerificationLevel {
SelfAttested,
DocumentSubmitted,
ThirdPartyVerified,
OnChainVerified,
}
impl VerificationLevel {
pub fn multiplier(&self) -> f64 {
match self {
VerificationLevel::SelfAttested => 0.5,
VerificationLevel::DocumentSubmitted => 0.7,
VerificationLevel::ThirdPartyVerified => 1.0,
VerificationLevel::OnChainVerified => 1.25,
}
}
pub fn auto_verify(&self) -> bool {
matches!(
self,
VerificationLevel::ThirdPartyVerified | VerificationLevel::OnChainVerified
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProfessionalAttestation {
pub category: CredentialCategory,
pub credential_name: String,
pub issuing_authority: Option<String>,
pub credential_id: Option<String>,
pub difficulty: DifficultyTier,
pub verification: VerificationLevel,
pub quantity: Option<u32>,
pub timestamp: u64,
pub api_weight: Option<u32>,
}
impl ProfessionalAttestation {
pub fn calculate_weight(&self) -> u32 {
if let Some(w) = self.api_weight {
return w.min(500);
}
let mut weight = self.category.base_weight() as f64;
if self.category.is_per_unit() {
if let Some(qty) = self.quantity {
weight *= (qty as f64).sqrt();
}
}
weight *= self.difficulty.multiplier();
weight *= self.verification.multiplier();
(weight as u32).min(500)
}
}
impl Attestation for ProfessionalAttestation {
fn layer(&self) -> CaptureLayer {
match self.category {
CredentialCategory::ApiContribution => CaptureLayer::KnowledgeAPI,
_ => CaptureLayer::Skill,
}
}
fn timestamp(&self) -> u64 {
self.timestamp
}
fn is_positive(&self) -> bool {
true }
fn magnitude(&self) -> u64 {
self.calculate_weight() as u64 * 10_000
}
fn metadata(&self) -> Option<&AttestationMetadata> {
None }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttestationRecord {
pub layer: CaptureLayer,
pub timestamp: u64,
pub positive: bool,
pub magnitude: u64,
pub metadata: Option<AttestationMetadata>,
}
impl Attestation for AttestationRecord {
fn layer(&self) -> CaptureLayer {
self.layer
}
fn timestamp(&self) -> u64 {
self.timestamp
}
fn is_positive(&self) -> bool {
self.positive
}
fn magnitude(&self) -> u64 {
self.magnitude
}
fn metadata(&self) -> Option<&AttestationMetadata> {
self.metadata.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct VaultAttestation {
pub action: VaultAction,
pub timestamp: u64,
pub amount: u64,
pub duration_days: Option<u16>,
pub held_to_maturity: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VaultAction {
Initialize,
Stack,
Unstack,
ClaimYield,
EarlyWithdrawal,
}
impl Attestation for VaultAttestation {
fn layer(&self) -> CaptureLayer {
CaptureLayer::Shopping }
fn timestamp(&self) -> u64 {
self.timestamp
}
fn is_positive(&self) -> bool {
match self.action {
VaultAction::Initialize => true,
VaultAction::Stack => true,
VaultAction::ClaimYield => true,
VaultAction::Unstack => self.held_to_maturity,
VaultAction::EarlyWithdrawal => false,
}
}
fn magnitude(&self) -> u64 {
self.amount
}
fn metadata(&self) -> Option<&AttestationMetadata> {
None
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ReputationDimension {
pub score: u32,
pub positive_signals: u64,
pub negative_signals: u64,
pub last_updated: u64,
pub cumulative_magnitude: u64,
}
impl ReputationDimension {
pub fn new() -> Self {
Self::default()
}
pub fn apply_decay(&mut self, current_time: u64) {
if self.last_updated == 0 {
return;
}
let days_inactive = (current_time - self.last_updated) / 86400;
if days_inactive > 0 {
let decay_factor = 0.5_f64.powf(days_inactive as f64 / DECAY_HALF_LIFE_DAYS as f64);
self.score = ((self.score as f64) * decay_factor) as u32;
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrustScore {
pub composite: u32,
pub reliability: u32,
pub skill: u32,
pub social: u32,
pub tenure: u32,
pub infrastructure: u32,
pub tier: TrustTier,
pub calculated_at: u64,
pub zk_commitment: String,
pub threshold_proofs: HashMap<String, bool>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TrustTier {
Newcomer,
Established,
Trusted,
Power,
Elite,
}
impl TrustTier {
pub fn from_score(score: u32) -> Self {
match score {
0..=199 => TrustTier::Newcomer,
200..=399 => TrustTier::Established,
400..=599 => TrustTier::Trusted,
600..=799 => TrustTier::Power,
_ => TrustTier::Elite,
}
}
pub fn collateral_discount_bps(&self) -> u16 {
match self {
TrustTier::Newcomer => 0,
TrustTier::Established => 50, TrustTier::Trusted => 100, TrustTier::Power => 200, TrustTier::Elite => 350, }
}
pub fn max_sub_agents(&self) -> u8 {
match self {
TrustTier::Newcomer => 0,
TrustTier::Established => 1,
TrustTier::Trusted => 3,
TrustTier::Power => 10,
TrustTier::Elite => 50,
}
}
}
#[derive(Debug)]
pub struct ReputationEngine {
pub user_pubkey: String,
pub layer_scores: HashMap<CaptureLayer, ReputationDimension>,
pub account_created: u64,
pub total_attestations: u64,
zk_salt: [u8; 32],
}
impl ReputationEngine {
pub fn new(user_pubkey: String) -> Self {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let mut salt = [0u8; 32];
let hash = Sha256::digest(format!("{}:{}", user_pubkey, now).as_bytes());
salt.copy_from_slice(&hash);
Self {
user_pubkey,
layer_scores: HashMap::new(),
account_created: now,
total_attestations: 0,
zk_salt: salt,
}
}
pub fn process_attestation<A: Attestation>(&mut self, attestation: &A) {
let layer = attestation.layer();
let delta = self.calculate_score_delta(attestation);
let timestamp = attestation.timestamp();
let magnitude = attestation.magnitude();
let is_positive = attestation.is_positive();
let dimension = self.layer_scores.entry(layer).or_default();
if is_positive {
dimension.positive_signals += 1;
} else {
dimension.negative_signals += 1;
}
dimension.cumulative_magnitude += magnitude;
if delta > 0 {
dimension.score = (dimension.score + delta as u32).min(MAX_SCORE);
} else {
dimension.score = dimension.score.saturating_sub((-delta) as u32);
}
dimension.last_updated = timestamp;
self.total_attestations += 1;
}
fn calculate_score_delta<A: Attestation>(&self, attestation: &A) -> i32 {
let layer = attestation.layer();
let weight = layer.reputation_weight();
let base_delta: i32;
if attestation.is_positive() {
base_delta = match layer.group() {
LayerGroup::PassiveUtility => 15,
LayerGroup::Infrastructure => 30,
LayerGroup::Intelligence => 45,
LayerGroup::AggressiveAutopilot => 60,
};
let magnitude = attestation.magnitude();
let magnitude_bonus = if magnitude > 0 {
((magnitude as f64).ln() * 3.0) as i32
} else {
0
};
let metadata_bonus = self.calculate_metadata_bonus(attestation);
((base_delta + magnitude_bonus + metadata_bonus) as f64 * weight) as i32
} else {
base_delta = match layer.group() {
LayerGroup::PassiveUtility => -50,
LayerGroup::Infrastructure => -80,
LayerGroup::Intelligence => -100,
LayerGroup::AggressiveAutopilot => -150,
};
(base_delta as f64 * weight) as i32
}
}
fn calculate_metadata_bonus<A: Attestation>(&self, attestation: &A) -> i32 {
let mut bonus = 0i32;
if let Some(meta) = attestation.metadata() {
if let Some(days) = meta.lock_duration_days {
bonus += match days {
0..=29 => 0,
30..=89 => 5,
90..=179 => 15,
180..=364 => 30,
_ => 50,
};
}
if meta.held_to_maturity == Some(true) {
bonus += 25;
}
if let Some(accuracy) = meta.accuracy_percent {
bonus += (accuracy as i32 - 50) / 5; }
if let Some(uptime) = meta.uptime_percent {
if uptime >= 99 {
bonus += 20;
} else if uptime >= 95 {
bonus += 10;
}
}
if let Some(rate) = meta.completion_rate {
bonus += (rate as i32 - 70) / 3; }
}
bonus
}
pub fn calculate_trust_score(&mut self) -> TrustScore {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
for dimension in self.layer_scores.values_mut() {
dimension.apply_decay(now);
}
let reliability = self.calculate_reliability_score();
let skill = self.calculate_skill_score();
let social = self.calculate_social_score();
let tenure = self.calculate_tenure_score(now);
let infrastructure = self.calculate_infrastructure_score();
let composite = (
(reliability as f64 * 0.30) +
(skill as f64 * 0.25) +
(infrastructure as f64 * 0.20) +
(social as f64 * 0.15) +
(tenure as f64 * 0.10)
) as u32;
let composite = composite.min(MAX_SCORE);
let tier = TrustTier::from_score(composite);
let zk_commitment = self.generate_zk_commitment(composite, reliability, skill);
let mut threshold_proofs = HashMap::new();
threshold_proofs.insert(
"swarm_coordinator".to_string(),
composite >= SWARM_COORDINATOR_THRESHOLD,
);
threshold_proofs.insert(
"collateral_eligible".to_string(),
composite >= COLLATERAL_THRESHOLD,
);
threshold_proofs.insert("trusted".to_string(), composite >= 400);
threshold_proofs.insert("power".to_string(), composite >= 600);
threshold_proofs.insert("elite".to_string(), composite >= 800);
TrustScore {
composite,
reliability,
skill,
social,
tenure,
infrastructure,
tier,
calculated_at: now,
zk_commitment,
threshold_proofs,
}
}
fn calculate_reliability_score(&self) -> u32 {
let mut score = 0u32;
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Shopping) {
score += (dim.positive_signals * 20).min(500) as u32;
let penalty = (dim.negative_signals * 50).min(400) as u32;
score = score.saturating_sub(penalty);
let cred_stacked = dim.cumulative_magnitude / 1_000_000; score += ((cred_stacked as f64).sqrt() * 8.0) as u32;
score += dim.score / 5;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Insurance) {
score += (dim.positive_signals * 8).min(150) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Liquidity) {
score += (dim.positive_signals * 12).min(200) as u32;
}
score.min(MAX_SCORE)
}
fn calculate_skill_score(&self) -> u32 {
let mut score = 0u32;
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Skill) {
score += (dim.positive_signals * 20).min(400) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Data) {
let accuracy_ratio = if dim.positive_signals + dim.negative_signals > 0 {
dim.positive_signals as f64
/ (dim.positive_signals + dim.negative_signals) as f64
} else {
0.5
};
score += (accuracy_ratio * 200.0) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::CurationSignal) {
score += (dim.positive_signals * 15).min(200) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::KnowledgeAPI) {
score += (dim.positive_signals * 12).min(150) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::PersonalModelLicensing) {
if dim.positive_signals > 0 {
score += 100; }
}
score.min(MAX_SCORE)
}
fn calculate_social_score(&self) -> u32 {
let mut score = 0u32;
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Social) {
score += (dim.positive_signals * 15).min(400) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::Referral) {
score += (dim.positive_signals * 10).min(200) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::SubAgentManager) {
score += (dim.positive_signals * 20).min(250) as u32;
}
if let Some(dim) = self.layer_scores.get(&CaptureLayer::SwarmCoordinationFee) {
score += (dim.positive_signals * 25).min(200) as u32;
}
score.min(MAX_SCORE)
}
fn calculate_tenure_score(&self, now: u64) -> u32 {
let account_age_days = (now - self.account_created) / 86400;
let tenure_score = ((account_age_days as f64).ln() * 50.0) as u32;
let activity_bonus = (self.total_attestations as f64 / 10.0).min(200.0) as u32;
(tenure_score + activity_bonus).min(MAX_SCORE)
}
fn calculate_infrastructure_score(&self) -> u32 {
let mut score = 0u32;
let infra_layers = [
CaptureLayer::Compute,
CaptureLayer::Network,
CaptureLayer::Energy,
CaptureLayer::DePINAggregator,
CaptureLayer::InferenceArbitrage,
CaptureLayer::StorageDePIN,
];
for layer in infra_layers {
if let Some(dim) = self.layer_scores.get(&layer) {
score += (dim.positive_signals * 25).min(200) as u32;
let penalty = (dim.negative_signals * 50).min(100) as u32;
score = score.saturating_sub(penalty);
}
}
score.min(MAX_SCORE)
}
fn generate_zk_commitment(&self, composite: u32, reliability: u32, skill: u32) -> String {
let data = format!(
"{}:{}:{}:{}",
composite,
reliability,
skill,
hex::encode(&self.zk_salt)
);
let hash = Sha256::digest(data.as_bytes());
hex::encode(hash)
}
pub fn verify_threshold(
&mut self,
threshold_name: &str,
commitment: &str,
) -> Option<bool> {
let trust_score = self.calculate_trust_score();
if trust_score.zk_commitment != commitment {
return None;
}
trust_score.threshold_proofs.get(threshold_name).copied()
}
pub fn can_coordinate_swarm(&mut self) -> bool {
let score = self.calculate_trust_score();
score.composite >= SWARM_COORDINATOR_THRESHOLD
}
pub fn qualifies_for_collateral(&mut self) -> bool {
let score = self.calculate_trust_score();
score.composite >= COLLATERAL_THRESHOLD
}
pub fn collateral_discount_bps(&mut self) -> u16 {
let score = self.calculate_trust_score();
score.tier.collateral_discount_bps()
}
pub fn max_sub_agents(&mut self) -> u8 {
let score = self.calculate_trust_score();
score.tier.max_sub_agents()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ReputationResponse {
pub user: String,
pub trust_score: TrustScore,
pub capabilities: ReputationCapabilities,
pub layer_activity: HashMap<String, LayerActivity>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ReputationCapabilities {
pub can_coordinate_swarm: bool,
pub qualifies_for_collateral: bool,
pub collateral_discount_bps: u16,
pub max_sub_agents: u8,
pub available_layers: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LayerActivity {
pub score: u32,
pub positive_signals: u64,
pub negative_signals: u64,
pub last_active: u64,
}
impl ReputationEngine {
pub fn to_api_response(&mut self) -> ReputationResponse {
let trust_score = self.calculate_trust_score();
let capabilities = ReputationCapabilities {
can_coordinate_swarm: self.can_coordinate_swarm(),
qualifies_for_collateral: self.qualifies_for_collateral(),
collateral_discount_bps: self.collateral_discount_bps(),
max_sub_agents: self.max_sub_agents(),
available_layers: self.get_available_layers(),
};
let mut layer_activity = HashMap::new();
for (layer, dim) in &self.layer_scores {
layer_activity.insert(
format!("{:?}", layer),
LayerActivity {
score: dim.score,
positive_signals: dim.positive_signals,
negative_signals: dim.negative_signals,
last_active: dim.last_updated,
},
);
}
ReputationResponse {
user: self.user_pubkey.clone(),
trust_score,
capabilities,
layer_activity,
}
}
fn get_available_layers(&mut self) -> Vec<String> {
let score = self.calculate_trust_score();
let mut layers = vec![
"Shopping",
"Referral",
"Attention",
"Data",
];
if score.composite >= 200 {
layers.extend(["Insurance", "Compute", "Storage"]);
}
if score.composite >= 400 {
layers.extend([
"Network",
"Energy",
"DePINAggregator",
"Skill",
"CurationSignal",
]);
}
if score.composite >= 600 {
layers.extend([
"InferenceArbitrage",
"Social",
"KnowledgeAPI",
"Liquidity",
"GovernanceProxy",
]);
}
if score.composite >= 800 {
layers.extend([
"PersonalModelLicensing",
"InventoryArbitrage",
"SubAgentManager",
"ReputationCollateral",
"SwarmCoordinationFee",
]);
}
layers.into_iter().map(String::from).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_user_starts_at_zero() {
let engine = ReputationEngine::new("test_user".to_string());
assert_eq!(engine.total_attestations, 0);
assert!(engine.layer_scores.is_empty());
}
#[test]
fn test_vault_attestation_increases_reliability() {
let mut engine = ReputationEngine::new("test_user".to_string());
let attestation = VaultAttestation {
action: VaultAction::Stack,
timestamp: 1711497600,
amount: 100_000_000, duration_days: Some(90),
held_to_maturity: true,
};
engine.process_attestation(&attestation);
let score = engine.calculate_trust_score();
assert!(score.reliability > 0);
assert!(score.composite > 0);
}
#[test]
fn test_early_withdrawal_decreases_score() {
let mut engine = ReputationEngine::new("test_user".to_string());
for i in 0..10 {
let stack = VaultAttestation {
action: VaultAction::Stack,
timestamp: 1711497600 + i * 86400,
amount: 100_000_000,
duration_days: Some(90),
held_to_maturity: true,
};
engine.process_attestation(&stack);
}
let score_before = engine.calculate_trust_score().composite;
println!("Score before early withdrawal: {}", score_before);
assert!(score_before > 0);
let early = VaultAttestation {
action: VaultAction::EarlyWithdrawal,
timestamp: 1711584000,
amount: 100_000_000,
duration_days: None,
held_to_maturity: false,
};
engine.process_attestation(&early);
let score_after = engine.calculate_trust_score().composite;
println!("Score after early withdrawal: {}", score_after);
let dim = engine.layer_scores.get(&CaptureLayer::Shopping).unwrap();
assert!(dim.negative_signals > 0, "Should have recorded negative signal");
}
#[test]
fn test_swarm_threshold() {
let mut engine = ReputationEngine::new("test_user".to_string());
assert!(!engine.can_coordinate_swarm());
for i in 0..30 {
let attestation = AttestationRecord {
layer: CaptureLayer::Shopping,
timestamp: 1711497600 + i * 86400,
positive: true,
magnitude: 100_000_000, metadata: Some(AttestationMetadata {
lock_duration_days: Some(365),
held_to_maturity: Some(true),
..Default::default()
}),
};
engine.process_attestation(&attestation);
}
for i in 0..20 {
let attestation = AttestationRecord {
layer: CaptureLayer::Skill,
timestamp: 1711497600 + i * 86400,
positive: true,
magnitude: 10_000_000,
metadata: Some(AttestationMetadata {
accuracy_percent: Some(95),
..Default::default()
}),
};
engine.process_attestation(&attestation);
}
for i in 0..20 {
let attestation = AttestationRecord {
layer: CaptureLayer::Network,
timestamp: 1711497600 + i * 86400,
positive: true,
magnitude: 5_000_000,
metadata: Some(AttestationMetadata {
uptime_percent: Some(99),
..Default::default()
}),
};
engine.process_attestation(&attestation);
}
let score = engine.calculate_trust_score();
println!("Score after multi-layer attestations: {}", score.composite);
println!(" Reliability: {}", score.reliability);
println!(" Skill: {}", score.skill);
println!(" Infrastructure: {}", score.infrastructure);
assert!(score.composite >= 400, "Expected score >= 400, got {}", score.composite);
}
#[test]
fn test_tier_classification() {
assert_eq!(TrustTier::from_score(0), TrustTier::Newcomer);
assert_eq!(TrustTier::from_score(199), TrustTier::Newcomer);
assert_eq!(TrustTier::from_score(200), TrustTier::Established);
assert_eq!(TrustTier::from_score(400), TrustTier::Trusted);
assert_eq!(TrustTier::from_score(600), TrustTier::Power);
assert_eq!(TrustTier::from_score(800), TrustTier::Elite);
assert_eq!(TrustTier::from_score(1000), TrustTier::Elite);
}
#[test]
fn test_zk_commitment_deterministic() {
let mut engine = ReputationEngine::new("test_user".to_string());
let score1 = engine.calculate_trust_score();
let score2 = engine.calculate_trust_score();
assert_eq!(score1.zk_commitment, score2.zk_commitment);
}
}