#[cfg(feature = "hdk")]
use hdk::prelude::*;
use serde::{Deserialize, Serialize};
#[cfg(not(feature = "hdk"))]
macro_rules! debug {
($($arg:tt)*) => {};
}
#[cfg(not(feature = "hdk"))]
macro_rules! warn {
($($arg:tt)*) => {};
}
use crate::consciousness_thresholds::{
BOOTSTRAP_COMMUNITY_THRESHOLD, BOOTSTRAP_MIN_IDENTITY, BOOTSTRAP_TTL_US,
};
pub const VOTE_WEIGHT_TEMPERATURE: f64 = 0.05;
pub const VOTE_WEIGHT_MAX_BP: f64 = 10000.0;
pub const TIER_HYSTERESIS_MARGIN: f64 = 0.05;
pub fn continuous_vote_weight(
score: f64,
threshold: f64,
temperature: f64,
max_weight: f64,
) -> f64 {
if !temperature.is_finite()
|| temperature <= 0.0
|| !score.is_finite()
|| !threshold.is_finite()
|| !max_weight.is_finite()
|| max_weight < 0.0
{
warn!("NaN/Inf fallback in continuous_vote_weight: score={}, threshold={}, temperature={}, max_weight={}", score, threshold, temperature, max_weight);
return 0.0;
}
let exponent = -((score - threshold) / temperature);
let exponent = exponent.clamp(-20.0, 20.0);
max_weight / (1.0 + exponent.exp())
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsciousnessProfile {
pub identity: f64,
pub reputation: f64,
pub community: f64,
pub engagement: f64,
}
impl ConsciousnessProfile {
pub fn combined_score(&self) -> f64 {
let i = if self.identity.is_finite() {
self.identity.clamp(0.0, 1.0)
} else {
warn!("NaN/Inf in combined_score: identity={}", self.identity);
0.0
};
let r = if self.reputation.is_finite() {
self.reputation.clamp(0.0, 1.0)
} else {
warn!("NaN/Inf in combined_score: reputation={}", self.reputation);
0.0
};
let c = if self.community.is_finite() {
self.community.clamp(0.0, 1.0)
} else {
warn!("NaN/Inf in combined_score: community={}", self.community);
0.0
};
let e = if self.engagement.is_finite() {
self.engagement.clamp(0.0, 1.0)
} else {
warn!("NaN/Inf in combined_score: engagement={}", self.engagement);
0.0
};
(i * 0.25 + r * 0.25 + c * 0.30 + e * 0.20).clamp(0.0, 1.0)
}
pub fn tier(&self) -> ConsciousnessTier {
ConsciousnessTier::from_score(self.combined_score())
}
pub fn tier_with_hysteresis(&self, current_tier: ConsciousnessTier) -> ConsciousnessTier {
ConsciousnessTier::from_score_with_hysteresis(self.combined_score(), current_tier)
}
pub fn vote_weight_continuous(&self) -> f64 {
continuous_vote_weight(
self.combined_score(),
0.4, VOTE_WEIGHT_TEMPERATURE,
VOTE_WEIGHT_MAX_BP,
)
}
pub fn zero() -> Self {
Self {
identity: 0.0,
reputation: 0.0,
community: 0.0,
engagement: 0.0,
}
}
#[inline]
fn sanitize(v: f64) -> f64 {
if v.is_finite() {
v.clamp(0.0, 1.0)
} else {
warn!("NaN/Inf sanitized to 0.0: input={}", v);
0.0
}
}
pub fn clamped(&self) -> Self {
Self {
identity: Self::sanitize(self.identity),
reputation: Self::sanitize(self.reputation),
community: Self::sanitize(self.community),
engagement: Self::sanitize(self.engagement),
}
}
pub fn is_valid(&self) -> bool {
self.identity.is_finite()
&& self.reputation.is_finite()
&& self.community.is_finite()
&& self.engagement.is_finite()
}
pub fn from_unified_consciousness(
unified_consciousness: f64,
identity: f64,
reputation: f64,
community: f64,
) -> Self {
Self {
identity: identity.clamp(0.0, 1.0),
reputation: reputation.clamp(0.0, 1.0),
community: community.clamp(0.0, 1.0),
engagement: unified_consciousness.clamp(0.0, 1.0),
}
}
pub fn from_symthaea(
phi: f64,
meta_awareness: f64,
coherence: f64,
care_activation: f64,
identity: f64,
reputation: f64,
community: f64,
) -> Self {
let phi_c = phi.clamp(0.0, 1.0);
let meta_c = meta_awareness.clamp(0.0, 1.0);
let coh_c = coherence.clamp(0.0, 1.0);
let care_c = care_activation.clamp(0.0, 1.0);
let engagement =
(0.35 * phi_c + 0.25 * meta_c + 0.20 * coh_c + 0.20 * care_c).clamp(0.0, 1.0);
Self {
identity: identity.clamp(0.0, 1.0),
reputation: reputation.clamp(0.0, 1.0),
community: community.clamp(0.0, 1.0),
engagement,
}
}
}
impl Default for ConsciousnessProfile {
fn default() -> Self {
Self::zero()
}
}
#[deprecated(
since = "0.9.0",
note = "Use sovereign_gate::SovereignCredential (8D) instead"
)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ConsciousnessCredential {
pub did: String,
pub profile: ConsciousnessProfile,
pub tier: ConsciousnessTier,
pub issued_at: u64,
pub expires_at: u64,
pub issuer: String,
#[serde(default)]
pub trajectory_commitment: Option<[u8; 32]>,
#[serde(default)]
pub extensions: std::collections::HashMap<String, Vec<u8>>,
}
pub mod ExtensionKey {
pub const SUBSTRATE_TYPE: &str = "substrate_type";
pub const REGION_FEASIBILITY: &str = "region_feasibility";
pub const SUB_PASSPORT_DID: &str = "sub_passport_did";
pub const FRESHNESS_ATTESTATION: &str = "freshness_attestation";
pub const MORAL_SCORE: &str = "moral_score";
}
impl ConsciousnessCredential {
pub const DEFAULT_TTL_US: u64 = 86_400_000_000;
pub fn is_expired(&self, now_us: u64) -> bool {
now_us >= self.expires_at
}
pub fn from_unified_consciousness(
did: String,
unified_consciousness: f64,
identity: f64,
reputation: f64,
community: f64,
issuer: String,
now_us: u64,
) -> Self {
let profile = ConsciousnessProfile::from_unified_consciousness(
unified_consciousness,
identity,
reputation,
community,
);
let tier = profile.clamped().tier();
Self {
did,
profile,
tier,
issued_at: now_us,
expires_at: now_us + Self::DEFAULT_TTL_US,
issuer,
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
}
}
pub fn from_symthaea(
did: String,
phi: f64,
meta_awareness: f64,
coherence: f64,
care_activation: f64,
identity: f64,
reputation: f64,
community: f64,
issuer: String,
now_us: u64,
) -> Self {
let profile = ConsciousnessProfile::from_symthaea(
phi,
meta_awareness,
coherence,
care_activation,
identity,
reputation,
community,
);
let tier = profile.clamped().tier();
Self {
did,
profile,
tier,
issued_at: now_us,
expires_at: now_us + Self::DEFAULT_TTL_US,
issuer,
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
}
}
pub fn set_extension(&mut self, key: impl Into<String>, value: Vec<u8>) {
self.extensions.insert(key.into(), value);
}
pub fn get_extension(&self, key: &str) -> Option<&Vec<u8>> {
self.extensions.get(key)
}
pub fn remove_extension(&mut self, key: &str) -> Option<Vec<u8>> {
self.extensions.remove(key)
}
pub fn with_trajectory_commitment(mut self, commitment: [u8; 32]) -> Self {
self.trajectory_commitment = Some(commitment);
self
}
pub fn has_trajectory_binding(&self) -> bool {
self.trajectory_commitment.is_some()
}
}
#[deprecated(since = "0.9.0", note = "Use sovereign_gate::CivicTier instead")]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ConsciousnessTier {
Observer,
Participant,
Citizen,
Steward,
Guardian,
}
impl ConsciousnessTier {
pub fn from_score(score: f64) -> Self {
if score >= 0.8 {
Self::Guardian
} else if score >= 0.6 {
Self::Steward
} else if score >= 0.4 {
Self::Citizen
} else if score >= 0.3 {
Self::Participant
} else {
Self::Observer
}
}
pub fn min_score(&self) -> f64 {
match self {
Self::Observer => 0.0,
Self::Participant => 0.3,
Self::Citizen => 0.4,
Self::Steward => 0.6,
Self::Guardian => 0.8,
}
}
pub fn vote_weight_bp(&self) -> u32 {
match self {
Self::Observer => 0,
Self::Participant => 5000,
Self::Citizen => 7500,
Self::Steward => 10000,
Self::Guardian => 10000,
}
}
pub fn from_score_with_hysteresis(
score: f64,
current_tier: ConsciousnessTier,
) -> ConsciousnessTier {
let margin = TIER_HYSTERESIS_MARGIN;
let promoted = if score >= 0.8 + margin {
ConsciousnessTier::Guardian
} else if score >= 0.6 + margin {
ConsciousnessTier::Steward
} else if score >= 0.4 + margin {
ConsciousnessTier::Citizen
} else if score >= 0.3 + margin {
ConsciousnessTier::Participant
} else {
ConsciousnessTier::Observer
};
let demoted = if score < 0.3 - margin {
ConsciousnessTier::Observer
} else if score < 0.4 - margin {
ConsciousnessTier::Participant
} else if score < 0.6 - margin {
ConsciousnessTier::Citizen
} else if score < 0.8 - margin {
ConsciousnessTier::Steward
} else {
ConsciousnessTier::Guardian
};
if promoted > current_tier {
promoted
} else if demoted < current_tier {
demoted
} else {
current_tier
}
}
pub fn degrade(self, levels: u32) -> Self {
let tiers = [
Self::Observer,
Self::Participant,
Self::Citizen,
Self::Steward,
Self::Guardian,
];
let current_idx = tiers.iter().position(|t| *t == self).unwrap_or(0);
let new_idx = current_idx.saturating_sub(levels as usize);
tiers[new_idx]
}
pub fn upgrade_capped(self, max_tier: Self) -> Self {
let tiers = [
Self::Observer,
Self::Participant,
Self::Citizen,
Self::Steward,
Self::Guardian,
];
let current_idx = tiers.iter().position(|t| *t == self).unwrap_or(0);
let max_idx = tiers.iter().position(|t| *t == max_tier).unwrap_or(0);
let new_idx = (current_idx + 1).min(max_idx);
tiers[new_idx]
}
}
#[deprecated(
since = "0.9.0",
note = "Use sovereign_gate::CivicRequirement (8D) instead"
)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GovernanceRequirement {
pub min_tier: ConsciousnessTier,
pub min_identity: Option<f64>,
pub min_community: Option<f64>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GovernanceEligibility {
pub eligible: bool,
pub weight_bp: u32,
pub tier: ConsciousnessTier,
pub profile: ConsciousnessProfile,
pub reasons: Vec<String>,
#[serde(default = "default_restoration_progress")]
pub restoration_progress: f64,
}
fn default_restoration_progress() -> f64 {
1.0
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GateAuditInput {
pub action_name: String,
pub zome_name: String,
pub eligible: bool,
pub actual_tier: String,
pub required_tier: String,
pub weight_bp: u32,
#[serde(default)]
pub correlation_id: Option<String>,
#[serde(default)]
pub credential_source: Option<String>,
}
pub const GRACE_PERIOD_US: u64 = 1_800_000_000;
pub const REFRESH_WINDOW_US: u64 = 7_200_000_000;
pub fn should_audit(
requirement: &GovernanceRequirement,
eligible: bool,
agent_hash: &[u8],
action_name: &str,
) -> bool {
if !eligible {
return true;
}
match requirement.min_tier {
ConsciousnessTier::Steward | ConsciousnessTier::Guardian => true,
ConsciousnessTier::Citizen => true,
_ => {
let sample_byte = agent_hash.last().copied().unwrap_or(0);
let salt: u8 = action_name.bytes().fold(0u8, |acc, b| acc.wrapping_add(b));
sample_byte.wrapping_add(salt) < 26 }
}
}
pub fn needs_refresh(credential: &ConsciousnessCredential, now_us: u64) -> bool {
!credential.is_expired(now_us)
&& credential.expires_at > now_us
&& credential.expires_at - now_us < REFRESH_WINDOW_US
}
pub fn is_bootstrap_eligible(agent_count: u32, identity_score: f64) -> bool {
agent_count < BOOTSTRAP_COMMUNITY_THRESHOLD && identity_score >= BOOTSTRAP_MIN_IDENTITY
}
pub fn bootstrap_credential(
did: String,
identity_score: f64,
now_us: u64,
) -> ConsciousnessCredential {
let clamped_identity = identity_score.clamp(0.0, 1.0);
ConsciousnessCredential {
did,
profile: ConsciousnessProfile {
identity: clamped_identity,
reputation: 0.0,
community: 0.0,
engagement: 0.0,
},
tier: ConsciousnessTier::Participant,
issued_at: now_us,
expires_at: now_us.saturating_add(BOOTSTRAP_TTL_US),
issuer: "did:mycelix:bootstrap".to_string(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
}
}
pub fn evaluate_bootstrap_governance(
credential: &ConsciousnessCredential,
requirement: &GovernanceRequirement,
now_us: u64,
) -> GovernanceEligibility {
if credential.is_expired(now_us) {
return GovernanceEligibility {
eligible: false,
weight_bp: 0,
tier: ConsciousnessTier::Observer,
profile: credential.profile.clone(),
reasons: vec!["Bootstrap credential expired".into()],
restoration_progress: 1.0,
};
}
if requirement.min_tier > ConsciousnessTier::Participant {
return GovernanceEligibility {
eligible: false,
weight_bp: 0,
tier: credential.tier,
profile: credential.profile.clone(),
reasons: vec![format!(
"Bootstrap credentials are capped at Participant; {:?} required",
requirement.min_tier,
)],
restoration_progress: 1.0,
};
}
if let Some(min_id) = requirement.min_identity {
if credential.profile.identity < min_id {
return GovernanceEligibility {
eligible: false,
weight_bp: 0,
tier: credential.tier,
profile: credential.profile.clone(),
reasons: vec![format!(
"Identity {:.2} below required {:.2}",
credential.profile.identity, min_id,
)],
restoration_progress: 1.0,
};
}
}
GovernanceEligibility {
eligible: true,
weight_bp: 5_000,
tier: ConsciousnessTier::Participant,
profile: credential.profile.clone(),
reasons: vec!["Bootstrap credential: temporary Participant access".into()],
restoration_progress: 1.0,
}
}
pub fn evaluate_governance(
credential: &ConsciousnessCredential,
requirement: &GovernanceRequirement,
now_us: u64,
) -> GovernanceEligibility {
if credential.is_expired(now_us) {
let in_grace = now_us < credential.expires_at.saturating_add(GRACE_PERIOD_US);
if in_grace && requirement.min_tier <= ConsciousnessTier::Participant {
let clamped = credential.profile.clamped();
let tier = clamped.tier();
let mut reasons = Vec::new();
if tier < requirement.min_tier {
reasons.push(format!(
"Tier {:?} below required {:?} (score {:.3}, need >= {:.3})",
tier,
requirement.min_tier,
clamped.combined_score(),
requirement.min_tier.min_score(),
));
}
if let Some(min_id) = requirement.min_identity {
if clamped.identity < min_id {
reasons.push(format!(
"Identity {:.3} below required {:.3}",
clamped.identity, min_id
));
}
}
if let Some(min_comm) = requirement.min_community {
if clamped.community < min_comm {
reasons.push(format!(
"Community {:.3} below required {:.3}",
clamped.community, min_comm
));
}
}
let eligible = reasons.is_empty();
let weight_bp = if eligible { tier.vote_weight_bp() } else { 0 };
reasons.push("Credential in grace period — refresh recommended".into());
return GovernanceEligibility {
eligible,
weight_bp,
tier,
profile: clamped,
reasons,
restoration_progress: 1.0,
};
}
return GovernanceEligibility {
eligible: false,
weight_bp: 0,
tier: ConsciousnessTier::Observer,
profile: credential.profile.clone(),
reasons: vec![format!(
"Credential expired at {} (now {})",
credential.expires_at, now_us
)],
restoration_progress: 1.0,
};
}
let clamped = credential.profile.clamped();
let tier = clamped.tier();
let mut reasons = Vec::new();
if tier < requirement.min_tier {
reasons.push(format!(
"Tier {:?} below required {:?} (score {:.3}, need >= {:.3})",
tier,
requirement.min_tier,
clamped.combined_score(),
requirement.min_tier.min_score(),
));
}
if let Some(min_id) = requirement.min_identity {
if clamped.identity < min_id {
reasons.push(format!(
"Identity {:.3} below required {:.3}",
clamped.identity, min_id,
));
}
}
if let Some(min_comm) = requirement.min_community {
if clamped.community < min_comm {
reasons.push(format!(
"Community {:.3} below required {:.3}",
clamped.community, min_comm,
));
}
}
let eligible = reasons.is_empty();
let mut weight_bp = if eligible { tier.vote_weight_bp() } else { 0 };
if eligible && weight_bp > 0 && credential.issued_at > 0 {
let credential_age_us = now_us.saturating_sub(credential.issued_at);
const SYBIL_MATURATION_PERIOD_US: u64 = 72 * 3600 * 1_000_000; if credential_age_us < SYBIL_MATURATION_PERIOD_US {
let maturation_ratio = credential_age_us as f64 / SYBIL_MATURATION_PERIOD_US as f64;
let age_factor = 0.1 + 0.9 * maturation_ratio;
let reduced = (weight_bp as f64 * age_factor) as u32;
if reduced < weight_bp {
reasons.push(format!(
"Young credential: weight reduced to {:.0}% (matures in {:.1}h)",
age_factor * 100.0,
(SYBIL_MATURATION_PERIOD_US - credential_age_us) as f64
/ (3600.0 * 1_000_000.0)
));
weight_bp = reduced.max(1); }
}
}
GovernanceEligibility {
eligible,
weight_bp,
tier,
profile: clamped,
reasons,
restoration_progress: 1.0,
}
}
pub fn requirement_for_basic() -> GovernanceRequirement {
GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: None,
min_community: None,
}
}
pub fn requirement_for_proposal() -> GovernanceRequirement {
GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: Some(0.25),
min_community: None,
}
}
pub fn requirement_for_voting() -> GovernanceRequirement {
GovernanceRequirement {
min_tier: ConsciousnessTier::Citizen,
min_identity: Some(0.25),
min_community: None,
}
}
pub fn requirement_for_constitutional() -> GovernanceRequirement {
GovernanceRequirement {
min_tier: ConsciousnessTier::Steward,
min_identity: Some(0.5),
min_community: Some(0.3),
}
}
pub fn requirement_for_guardian() -> GovernanceRequirement {
GovernanceRequirement {
min_tier: ConsciousnessTier::Guardian,
min_identity: Some(0.7),
min_community: Some(0.5),
}
}
#[deprecated(since = "0.9.0", note = "Use sovereign_gate::gate_civic() instead")]
#[cfg(feature = "hdk")]
pub fn gate_consciousness(
bridge_zome: &str,
requirement: &GovernanceRequirement,
action_name: &str,
) -> ExternResult<GovernanceEligibility> {
let agent = agent_info()?.agent_initial_pubkey;
let did = format!("did:mycelix:{}", agent);
let response = call(
CallTargetCell::Local,
ZomeName::new(bridge_zome),
FunctionName::new("get_consciousness_credential"),
None,
did,
)?;
let credential: ConsciousnessCredential = match response {
ZomeCallResponse::Ok(extern_io) => extern_io.decode().map_err(|e| {
wasm_error!(WasmErrorInner::Guest(format!(
"Failed to decode consciousness credential: {}",
e
)))
})?,
other => {
return Err(wasm_error!(WasmErrorInner::Guest(format!(
"Consciousness credential call failed: {:?}",
other
))));
}
};
let now_us = sys_time()?.as_micros() as u64;
let eligibility = evaluate_governance(&credential, requirement, now_us);
let tier_index = match eligibility.tier {
ConsciousnessTier::Observer => 0,
ConsciousnessTier::Participant => 1,
ConsciousnessTier::Citizen => 2,
ConsciousnessTier::Steward => 3,
ConsciousnessTier::Guardian => 4,
};
crate::metrics::record_gate_check(eligibility.eligible, tier_index, 0);
if should_audit(
requirement,
eligibility.eligible,
agent.as_ref(),
action_name,
) {
let audit = GateAuditInput {
action_name: action_name.to_string(),
zome_name: zome_info()?.name.to_string(),
eligible: eligibility.eligible,
actual_tier: format!("{:?}", eligibility.tier),
required_tier: format!("{:?}", requirement.min_tier),
weight_bp: eligibility.weight_bp,
correlation_id: None,
credential_source: None,
};
match call(
CallTargetCell::Local,
ZomeName::new(bridge_zome),
FunctionName::new("log_governance_gate"),
None,
audit,
) {
Ok(_) => {}
Err(e) => {
debug!("Audit log failed ({}): {:?}", bridge_zome, e);
}
}
}
if needs_refresh(&credential, now_us) {
debug!(
"gate_consciousness: credential nearing expiry, triggering best-effort refresh via {}",
bridge_zome
);
match call(
CallTargetCell::Local,
ZomeName::new(bridge_zome),
FunctionName::new("refresh_consciousness_credential"),
None,
credential.did.clone(),
) {
Ok(_) => {
debug!(
"gate_consciousness: refresh triggered successfully via {}",
bridge_zome
);
}
Err(e) => {
debug!(
"gate_consciousness: refresh failed (non-fatal) via {}: {:?}",
bridge_zome, e
);
}
}
}
if !eligibility.eligible {
return Err(wasm_error!(WasmErrorInner::Guest(format!(
"Consciousness gate: tier {:?} insufficient. Reasons: {}",
eligibility.tier,
eligibility.reasons.join(", ")
))));
}
Ok(eligibility)
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct GovernanceAuditFilter {
#[serde(default)]
pub action_name: Option<String>,
#[serde(default)]
pub zome_name: Option<String>,
#[serde(default)]
pub eligible: Option<bool>,
#[serde(default)]
pub from_us: Option<i64>,
#[serde(default)]
pub to_us: Option<i64>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GovernanceAuditResult {
pub entries: Vec<GateAuditInput>,
pub total_matched: u32,
}
pub const REPUTATION_DECAY_PER_DAY: f64 = 0.998;
pub const REPUTATION_SLASH_FACTOR: f64 = 0.5;
pub const REPUTATION_BLACKLIST_THRESHOLD: f64 = 0.05;
pub const REPUTATION_RESTORATION_INTERACTIONS: u32 = 100;
pub const REPUTATION_MAX_SLASHES: u32 = 5;
pub const REPUTATION_SLASH_COOLDOWN_US: u64 = 7 * 24 * 3600 * 1_000_000;
pub const REPUTATION_SLASH_FREQUENCY_PENALTY: f64 = 0.5;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ReputationState {
pub score: f64,
pub last_updated_us: u64,
pub consecutive_good: u32,
pub total_slashes: u32,
pub blacklisted: bool,
pub blacklisted_since_us: Option<u64>,
#[serde(default)]
pub last_slash_us: Option<u64>,
}
impl Default for ReputationState {
fn default() -> Self {
Self {
score: 0.0,
last_updated_us: 0,
consecutive_good: 0,
total_slashes: 0,
blacklisted: false,
blacklisted_since_us: None,
last_slash_us: None,
}
}
}
impl ReputationState {
pub fn new(initial_score: f64, now_us: u64) -> Self {
let sanitized = if initial_score.is_finite() {
initial_score.clamp(0.0, 1.0)
} else {
warn!(
"NaN/Inf in ReputationState::new: initial_score={}",
initial_score
);
0.0
};
Self {
score: sanitized,
last_updated_us: now_us,
..Default::default()
}
}
pub fn apply_decay(&mut self, now_us: u64) {
if now_us <= self.last_updated_us {
return; }
let elapsed_us = now_us - self.last_updated_us;
let elapsed_days = elapsed_us as f64 / 86_400_000_000.0;
if !elapsed_days.is_finite() || elapsed_days <= 0.0 {
if !elapsed_days.is_finite() {
warn!("NaN/Inf in apply_decay: elapsed_days={}", elapsed_days);
}
return;
}
let decay_factor = REPUTATION_DECAY_PER_DAY.powf(elapsed_days);
if decay_factor.is_finite() {
self.score = (self.score * decay_factor).clamp(0.0, 1.0);
} else {
warn!(
"NaN/Inf decay_factor in apply_decay: elapsed_days={}, decay_factor={}",
elapsed_days, decay_factor
);
self.score = 0.0; }
self.last_updated_us = now_us;
self.check_blacklist(now_us);
}
pub fn record_good_interaction(&mut self, reputation_boost: f64, now_us: u64) {
self.apply_decay(now_us);
self.consecutive_good = self.consecutive_good.saturating_add(1);
let effective_boost = reputation_boost.clamp(0.0, 0.1);
let cap = if self.total_slashes >= REPUTATION_MAX_SLASHES {
0.5 } else {
1.0
};
self.score = (self.score + effective_boost).clamp(0.0, cap);
if self.blacklisted && self.consecutive_good >= REPUTATION_RESTORATION_INTERACTIONS {
self.blacklisted = false;
self.blacklisted_since_us = None;
self.score = self.score.max(0.1);
}
}
pub fn slash(&mut self, now_us: u64) -> f64 {
self.apply_decay(now_us);
self.score *= 1.0 - REPUTATION_SLASH_FACTOR;
self.apply_frequency_penalty(now_us);
self.score = self.score.clamp(0.0, 1.0);
self.consecutive_good = 0;
self.total_slashes = self.total_slashes.saturating_add(1);
self.last_slash_us = Some(now_us);
self.check_blacklist(now_us);
self.score
}
pub fn slash_proportional(&mut self, factor: f64, now_us: u64) -> f64 {
self.apply_decay(now_us);
let clamped_factor = factor.clamp(0.0, 1.0);
self.score *= 1.0 - clamped_factor;
self.apply_frequency_penalty(now_us);
self.score = self.score.clamp(0.0, 1.0);
self.consecutive_good = 0;
self.total_slashes = self.total_slashes.saturating_add(1);
self.last_slash_us = Some(now_us);
self.check_blacklist(now_us);
self.score
}
fn apply_frequency_penalty(&mut self, now_us: u64) {
if let Some(last) = self.last_slash_us {
if now_us <= last + REPUTATION_SLASH_COOLDOWN_US {
let elapsed = now_us.saturating_sub(last) as f64;
let cooldown = REPUTATION_SLASH_COOLDOWN_US as f64;
let recency = 1.0 - (elapsed / cooldown).min(1.0);
let penalty = REPUTATION_SLASH_FREQUENCY_PENALTY * recency;
self.score *= 1.0 - penalty;
}
}
}
fn check_blacklist(&mut self, now_us: u64) {
if self.score < REPUTATION_BLACKLIST_THRESHOLD && !self.blacklisted {
self.blacklisted = true;
self.blacklisted_since_us = Some(now_us);
}
}
pub fn can_participate(&self) -> bool {
!self.blacklisted
}
pub fn restoration_progress(&self) -> f64 {
if !self.blacklisted {
return 1.0;
}
(self.consecutive_good as f64 / REPUTATION_RESTORATION_INTERACTIONS as f64).clamp(0.0, 1.0)
}
}
pub const CARTEL_SLASH_MIN_CONFIDENCE: f64 = 0.7;
pub const CARTEL_MIN_SIZE: usize = 3;
pub fn apply_cartel_slash(
reputation_states: &mut std::collections::HashMap<String, ReputationState>,
member_ids: &[String],
confidence: f64,
now_us: u64,
) -> Vec<(String, f64)> {
if confidence < CARTEL_SLASH_MIN_CONFIDENCE || member_ids.len() < CARTEL_MIN_SIZE {
return Vec::new();
}
let factor = confidence.clamp(0.0, 1.0);
let mut results = Vec::with_capacity(member_ids.len());
for member_id in member_ids {
if let Some(state) = reputation_states.get_mut(member_id) {
let new_score = state.slash_proportional(factor, now_us);
results.push((member_id.clone(), new_score));
}
}
results
}
pub fn decay_reputation(profile: &ConsciousnessProfile, elapsed_days: f64) -> ConsciousnessProfile {
if !elapsed_days.is_finite() || elapsed_days <= 0.0 {
if !elapsed_days.is_finite() {
warn!("NaN/Inf in decay_reputation: elapsed_days={}", elapsed_days);
}
return profile.clone();
}
let decay_factor = REPUTATION_DECAY_PER_DAY.powf(elapsed_days);
let decayed_rep = if decay_factor.is_finite() {
(profile.reputation * decay_factor).clamp(0.0, 1.0)
} else {
warn!(
"NaN/Inf decay_factor in decay_reputation: elapsed_days={}, decay_factor={}",
elapsed_days, decay_factor
);
0.0
};
ConsciousnessProfile {
identity: profile.identity,
reputation: decayed_rep,
community: profile.community,
engagement: profile.engagement,
}
}
pub fn evaluate_governance_with_reputation(
credential: &ConsciousnessCredential,
requirement: &GovernanceRequirement,
reputation_state: &ReputationState,
now_us: u64,
) -> GovernanceEligibility {
if reputation_state.blacklisted {
return GovernanceEligibility {
eligible: false,
weight_bp: 0,
tier: ConsciousnessTier::Observer,
profile: credential.profile.clone(),
reasons: vec![format!(
"Blacklisted: reputation {:.3} below threshold {:.3}. Restoration progress: {:.0}%",
reputation_state.score,
REPUTATION_BLACKLIST_THRESHOLD,
reputation_state.restoration_progress() * 100.0,
)],
restoration_progress: reputation_state.restoration_progress(),
};
}
let mut result = evaluate_governance(credential, requirement, now_us);
if reputation_state.total_slashes > 0 {
let slash_penalty = 1.0 - (reputation_state.total_slashes as f64 * 0.05).min(0.25);
result.weight_bp = (result.weight_bp as f64 * slash_penalty) as u32;
}
result
}
#[cfg(test)]
mod tests {
use super::*;
const NOW: u64 = 1_000_000_000_000;
fn fresh_credential(profile: ConsciousnessProfile) -> ConsciousnessCredential {
let tier = profile.clamped().tier();
ConsciousnessCredential {
did: "did:test:alice".to_string(),
profile,
tier,
issued_at: NOW - 4 * 86_400_000_000, expires_at: NOW + 86_400_000_000,
issuer: "test".to_string(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
}
}
#[test]
fn zero_profile_is_all_zeros() {
let p = ConsciousnessProfile::zero();
assert_eq!(p.identity, 0.0);
assert_eq!(p.reputation, 0.0);
assert_eq!(p.community, 0.0);
assert_eq!(p.engagement, 0.0);
assert_eq!(p.combined_score(), 0.0);
}
#[test]
fn combined_score_weights_correct() {
let p = ConsciousnessProfile {
identity: 1.0,
reputation: 1.0,
community: 1.0,
engagement: 1.0,
};
assert!((p.combined_score() - 1.0).abs() < 1e-10);
}
#[test]
fn combined_score_weighted_average() {
let p = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
assert!((p.combined_score() - 0.5).abs() < 1e-10);
}
#[test]
fn combined_score_identity_only() {
let p = ConsciousnessProfile {
identity: 1.0,
reputation: 0.0,
community: 0.0,
engagement: 0.0,
};
assert!((p.combined_score() - 0.25).abs() < 1e-10);
}
#[test]
fn combined_score_community_only() {
let p = ConsciousnessProfile {
identity: 0.0,
reputation: 0.0,
community: 1.0,
engagement: 0.0,
};
assert!((p.combined_score() - 0.30).abs() < 1e-10);
}
#[test]
fn combined_score_engagement_only() {
let p = ConsciousnessProfile {
identity: 0.0,
reputation: 0.0,
community: 0.0,
engagement: 1.0,
};
assert!((p.combined_score() - 0.20).abs() < 1e-10);
}
#[test]
fn combined_score_reputation_only() {
let p = ConsciousnessProfile {
identity: 0.0,
reputation: 1.0,
community: 0.0,
engagement: 0.0,
};
assert!((p.combined_score() - 0.25).abs() < 1e-10);
}
#[test]
fn clamped_clips_values() {
let p = ConsciousnessProfile {
identity: 1.5,
reputation: -0.3,
community: 2.0,
engagement: -1.0,
};
let c = p.clamped();
assert_eq!(c.identity, 1.0);
assert_eq!(c.reputation, 0.0);
assert_eq!(c.community, 1.0);
assert_eq!(c.engagement, 0.0);
}
#[test]
fn clamped_preserves_valid_values() {
let p = ConsciousnessProfile {
identity: 0.5,
reputation: 0.7,
community: 0.3,
engagement: 0.9,
};
let c = p.clamped();
assert_eq!(c, p);
}
#[test]
fn default_is_zero() {
assert_eq!(
ConsciousnessProfile::default(),
ConsciousnessProfile::zero()
);
}
#[test]
fn tier_from_score_boundaries() {
assert_eq!(
ConsciousnessTier::from_score(0.0),
ConsciousnessTier::Observer
);
assert_eq!(
ConsciousnessTier::from_score(0.29),
ConsciousnessTier::Observer
);
assert_eq!(
ConsciousnessTier::from_score(0.3),
ConsciousnessTier::Participant
);
assert_eq!(
ConsciousnessTier::from_score(0.39),
ConsciousnessTier::Participant
);
assert_eq!(
ConsciousnessTier::from_score(0.4),
ConsciousnessTier::Citizen
);
assert_eq!(
ConsciousnessTier::from_score(0.59),
ConsciousnessTier::Citizen
);
assert_eq!(
ConsciousnessTier::from_score(0.6),
ConsciousnessTier::Steward
);
assert_eq!(
ConsciousnessTier::from_score(0.79),
ConsciousnessTier::Steward
);
assert_eq!(
ConsciousnessTier::from_score(0.8),
ConsciousnessTier::Guardian
);
assert_eq!(
ConsciousnessTier::from_score(1.0),
ConsciousnessTier::Guardian
);
}
#[test]
fn tier_min_scores_are_monotonic() {
let tiers = [
ConsciousnessTier::Observer,
ConsciousnessTier::Participant,
ConsciousnessTier::Citizen,
ConsciousnessTier::Steward,
ConsciousnessTier::Guardian,
];
for i in 1..tiers.len() {
assert!(
tiers[i].min_score() > tiers[i - 1].min_score(),
"{:?} min_score should be > {:?} min_score",
tiers[i],
tiers[i - 1]
);
}
}
#[test]
fn tier_vote_weights_are_progressive() {
assert_eq!(ConsciousnessTier::Observer.vote_weight_bp(), 0);
assert!(ConsciousnessTier::Participant.vote_weight_bp() > 0);
assert!(
ConsciousnessTier::Citizen.vote_weight_bp()
>= ConsciousnessTier::Participant.vote_weight_bp()
);
assert!(
ConsciousnessTier::Steward.vote_weight_bp()
>= ConsciousnessTier::Citizen.vote_weight_bp()
);
assert!(
ConsciousnessTier::Guardian.vote_weight_bp()
>= ConsciousnessTier::Steward.vote_weight_bp()
);
}
#[test]
fn tier_ordering() {
assert!(ConsciousnessTier::Observer < ConsciousnessTier::Participant);
assert!(ConsciousnessTier::Participant < ConsciousnessTier::Citizen);
assert!(ConsciousnessTier::Citizen < ConsciousnessTier::Steward);
assert!(ConsciousnessTier::Steward < ConsciousnessTier::Guardian);
}
#[test]
fn profile_tier_derivation() {
let observer = ConsciousnessProfile::zero();
assert_eq!(observer.tier(), ConsciousnessTier::Observer);
let participant = ConsciousnessProfile {
identity: 0.3,
reputation: 0.3,
community: 0.3,
engagement: 0.3,
};
assert_eq!(participant.tier(), ConsciousnessTier::Participant);
let citizen = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.4,
engagement: 0.2,
};
assert_eq!(citizen.tier(), ConsciousnessTier::Citizen);
let steward = ConsciousnessProfile {
identity: 0.75,
reputation: 0.7,
community: 0.6,
engagement: 0.5,
};
assert_eq!(steward.tier(), ConsciousnessTier::Steward);
let guardian = ConsciousnessProfile {
identity: 1.0,
reputation: 0.9,
community: 0.8,
engagement: 0.7,
};
assert_eq!(guardian.tier(), ConsciousnessTier::Guardian);
}
#[test]
fn evaluate_observer_rejected_for_basic() {
let profile = ConsciousnessProfile::zero();
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_basic(),
NOW,
);
assert!(!result.eligible);
assert_eq!(result.weight_bp, 0);
assert_eq!(result.tier, ConsciousnessTier::Observer);
assert!(!result.reasons.is_empty());
}
#[test]
fn evaluate_participant_passes_basic() {
let profile = ConsciousnessProfile {
identity: 0.3,
reputation: 0.3,
community: 0.3,
engagement: 0.3,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_basic(),
NOW,
);
assert!(result.eligible);
assert_eq!(result.weight_bp, 5000);
assert_eq!(result.tier, ConsciousnessTier::Participant);
assert!(result.reasons.is_empty());
}
#[test]
fn evaluate_participant_rejected_for_voting() {
let profile = ConsciousnessProfile {
identity: 0.3,
reputation: 0.3,
community: 0.3,
engagement: 0.3,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_voting(),
NOW,
);
assert!(!result.eligible);
assert!(!result.reasons.is_empty());
}
#[test]
fn evaluate_citizen_passes_voting() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.4,
engagement: 0.2,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_voting(),
NOW,
);
assert!(result.eligible);
assert_eq!(result.weight_bp, 7500); assert_eq!(result.tier, ConsciousnessTier::Citizen);
}
#[test]
fn evaluate_proposal_requires_identity() {
let profile = ConsciousnessProfile {
identity: 0.0,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_proposal(),
NOW,
);
assert!(!result.eligible);
assert!(result.reasons.iter().any(|r| r.contains("Identity")));
}
#[test]
fn evaluate_constitutional_requires_all() {
let profile = ConsciousnessProfile {
identity: 0.3,
reputation: 0.8,
community: 0.8,
engagement: 0.8,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_constitutional(),
NOW,
);
assert!(!result.eligible);
assert!(result.reasons.iter().any(|r| r.contains("Identity")));
}
#[test]
fn evaluate_constitutional_requires_community() {
let profile = ConsciousnessProfile {
identity: 0.75,
reputation: 0.7,
community: 0.1,
engagement: 0.8,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_constitutional(),
NOW,
);
assert!(!result.eligible);
assert!(result
.reasons
.iter()
.any(|r| r.contains("Community") || r.contains("Tier")));
}
#[test]
fn evaluate_guardian_passes_constitutional() {
let profile = ConsciousnessProfile {
identity: 1.0,
reputation: 0.9,
community: 0.8,
engagement: 0.7,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_constitutional(),
NOW,
);
assert!(result.eligible);
assert_eq!(result.weight_bp, 10000);
assert_eq!(result.tier, ConsciousnessTier::Guardian);
}
#[test]
fn evaluate_clamps_out_of_range_values() {
let profile = ConsciousnessProfile {
identity: 2.0,
reputation: 2.0,
community: 2.0,
engagement: 2.0,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_constitutional(),
NOW,
);
assert!(result.eligible);
assert_eq!(result.tier, ConsciousnessTier::Guardian);
assert_eq!(result.profile.identity, 1.0);
}
#[test]
fn evaluate_multiple_failure_reasons() {
let profile = ConsciousnessProfile::zero();
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_constitutional(),
NOW,
);
assert!(!result.eligible);
assert!(
result.reasons.len() >= 3,
"Expected 3+ reasons, got: {:?}",
result.reasons
);
}
#[test]
fn progressive_weight_composition_with_role() {
let citizen_bp: u64 = ConsciousnessTier::Citizen.vote_weight_bp() as u64;
let adult_role_bp: u64 = 10000; let youth_role_bp: u64 = 5000;
let adult_final = (adult_role_bp * citizen_bp / 10000) as u32;
let youth_final = (youth_role_bp * citizen_bp / 10000) as u32;
assert_eq!(adult_final, 7500);
assert_eq!(youth_final, 3750);
}
#[test]
fn credential_not_expired_when_fresh() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 1_000_000,
expires_at: 1_000_000 + ConsciousnessCredential::DEFAULT_TTL_US,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(!cred.is_expired(1_000_000));
assert!(!cred.is_expired(1_000_000 + ConsciousnessCredential::DEFAULT_TTL_US - 1));
}
#[test]
fn credential_expired_at_boundary() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 1_000_000,
expires_at: 1_000_000 + ConsciousnessCredential::DEFAULT_TTL_US,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(cred.is_expired(cred.expires_at));
assert!(cred.is_expired(cred.expires_at + 1));
}
#[test]
fn default_ttl_is_24_hours() {
assert_eq!(ConsciousnessCredential::DEFAULT_TTL_US, 86_400_000_000);
}
#[test]
fn profile_serde_roundtrip() {
let p = ConsciousnessProfile {
identity: 0.75,
reputation: 0.5,
community: 0.6,
engagement: 0.3,
};
let json = serde_json::to_string(&p).unwrap();
let p2: ConsciousnessProfile = serde_json::from_str(&json).unwrap();
assert_eq!(p, p2);
}
#[test]
fn tier_serde_roundtrip() {
let tiers = [
ConsciousnessTier::Observer,
ConsciousnessTier::Participant,
ConsciousnessTier::Citizen,
ConsciousnessTier::Steward,
ConsciousnessTier::Guardian,
];
for tier in &tiers {
let json = serde_json::to_string(tier).unwrap();
let t2: ConsciousnessTier = serde_json::from_str(&json).unwrap();
assert_eq!(*tier, t2);
}
}
#[test]
fn credential_serde_roundtrip() {
let cred = ConsciousnessCredential {
did: "did:mycelix:abc123".into(),
profile: ConsciousnessProfile {
identity: 0.5,
reputation: 0.6,
community: 0.7,
engagement: 0.4,
},
tier: ConsciousnessTier::Steward,
issued_at: 1_700_000_000_000_000,
expires_at: 1_700_000_000_000_000 + ConsciousnessCredential::DEFAULT_TTL_US,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
let json = serde_json::to_string(&cred).unwrap();
let c2: ConsciousnessCredential = serde_json::from_str(&json).unwrap();
assert_eq!(c2.did, "did:mycelix:abc123");
assert_eq!(c2.tier, ConsciousnessTier::Steward);
assert_eq!(c2.profile.identity, 0.5);
}
#[test]
fn governance_requirement_serde_roundtrip() {
let req = requirement_for_constitutional();
let json = serde_json::to_string(&req).unwrap();
let r2: GovernanceRequirement = serde_json::from_str(&json).unwrap();
assert_eq!(r2.min_tier, ConsciousnessTier::Steward);
assert_eq!(r2.min_identity, Some(0.5));
assert_eq!(r2.min_community, Some(0.3));
}
#[test]
fn governance_eligibility_serde_roundtrip() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.4,
engagement: 0.2,
};
let eligibility = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_voting(),
NOW,
);
let json = serde_json::to_string(&eligibility).unwrap();
let e2: GovernanceEligibility = serde_json::from_str(&json).unwrap();
assert_eq!(e2.eligible, eligibility.eligible);
assert_eq!(e2.weight_bp, eligibility.weight_bp);
assert_eq!(e2.tier, eligibility.tier);
}
#[test]
fn negative_values_clamped_to_zero() {
let profile = ConsciousnessProfile {
identity: -0.5,
reputation: -1.0,
community: -0.1,
engagement: -999.0,
};
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_basic(),
NOW,
);
assert!(!result.eligible);
assert_eq!(result.profile.identity, 0.0);
assert_eq!(result.profile.reputation, 0.0);
assert_eq!(result.profile.community, 0.0);
assert_eq!(result.profile.engagement, 0.0);
}
#[test]
fn exact_threshold_boundary_participant() {
let profile = ConsciousnessProfile {
identity: 0.3,
reputation: 0.3,
community: 0.3,
engagement: 0.3,
};
assert_eq!(profile.tier(), ConsciousnessTier::Participant);
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_basic(),
NOW,
);
assert!(result.eligible);
}
#[test]
fn just_below_participant_threshold() {
let profile = ConsciousnessProfile {
identity: 0.29,
reputation: 0.29,
community: 0.29,
engagement: 0.29,
};
assert_eq!(profile.tier(), ConsciousnessTier::Observer);
let result = evaluate_governance(
&fresh_credential(profile.clone()),
&requirement_for_basic(),
NOW,
);
assert!(!result.eligible);
}
#[test]
fn requirement_presets_are_ordered() {
let basic = requirement_for_basic();
let proposal = requirement_for_proposal();
let voting = requirement_for_voting();
let constitutional = requirement_for_constitutional();
assert!(basic.min_tier <= proposal.min_tier);
assert!(proposal.min_tier <= voting.min_tier);
assert!(voting.min_tier <= constitutional.min_tier);
}
#[test]
fn requirement_identity_thresholds_ordered() {
let proposal_id = requirement_for_proposal().min_identity.unwrap_or(0.0);
let voting_id = requirement_for_voting().min_identity.unwrap_or(0.0);
let const_id = requirement_for_constitutional().min_identity.unwrap_or(0.0);
assert!(proposal_id <= voting_id || proposal_id <= const_id);
assert!(voting_id <= const_id);
}
#[test]
fn credential_not_expired_one_microsecond_before() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 1_000_000,
expires_at: 2_000_000,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(!cred.is_expired(1_999_999));
}
#[test]
fn credential_expired_exactly_at_boundary() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 1_000_000,
expires_at: 2_000_000,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(cred.is_expired(2_000_000));
}
#[test]
fn credential_expired_one_microsecond_after() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 1_000_000,
expires_at: 2_000_000,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(cred.is_expired(2_000_001));
}
#[test]
fn credential_zero_ttl_always_expired() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 1_000_000,
expires_at: 1_000_000, issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(cred.is_expired(1_000_000));
}
#[test]
fn credential_u64_max_expires_at_not_expired() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 0,
expires_at: u64::MAX,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(!cred.is_expired(1_700_000_000_000_000));
}
#[test]
fn credential_u64_max_expires_at_expired_at_max() {
let cred = ConsciousnessCredential {
did: "did:mycelix:test".into(),
profile: ConsciousnessProfile::zero(),
tier: ConsciousnessTier::Observer,
issued_at: 0,
expires_at: u64::MAX,
issuer: "did:mycelix:issuer".into(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
assert!(cred.is_expired(u64::MAX));
}
#[test]
fn evaluate_governance_rejects_expired_credential_past_grace() {
let profile = ConsciousnessProfile {
identity: 1.0,
reputation: 1.0,
community: 1.0,
engagement: 1.0,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - GRACE_PERIOD_US - 1;
let result = evaluate_governance(&cred, &requirement_for_basic(), NOW);
assert!(!result.eligible);
assert!(result.reasons[0].contains("expired"));
}
#[test]
fn evaluate_governance_rejects_expired_credential_for_voting() {
let profile = ConsciousnessProfile {
identity: 1.0,
reputation: 1.0,
community: 1.0,
engagement: 1.0,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - 1; let result = evaluate_governance(&cred, &requirement_for_voting(), NOW);
assert!(!result.eligible);
assert!(result.reasons[0].contains("expired"));
}
#[test]
fn evaluate_governance_accepts_fresh_credential() {
let profile = ConsciousnessProfile {
identity: 1.0,
reputation: 1.0,
community: 1.0,
engagement: 1.0,
};
let cred = fresh_credential(profile);
let result = evaluate_governance(&cred, &requirement_for_constitutional(), NOW);
assert!(result.eligible);
}
#[test]
fn evaluate_governance_rejects_at_expiry_boundary_for_voting() {
let profile = ConsciousnessProfile {
identity: 1.0,
reputation: 1.0,
community: 1.0,
engagement: 1.0,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW; let result = evaluate_governance(&cred, &requirement_for_voting(), NOW);
assert!(!result.eligible);
assert!(result.reasons[0].contains("expired"));
}
#[test]
fn weight_composition_no_overflow_at_max() {
let role_bp: u64 = 10000;
let consciousness_bp: u64 = 10000;
let result = (role_bp * consciousness_bp / 10000) as u32;
assert_eq!(result, 10000);
}
#[test]
fn weight_composition_observer_always_zero() {
let observer_bp = ConsciousnessTier::Observer.vote_weight_bp() as u64;
for role_bp in [0u64, 5000, 10000, u32::MAX as u64] {
let result = (role_bp * observer_bp / 10000) as u32;
assert_eq!(result, 0, "Observer * role {} should be 0", role_bp);
}
}
#[test]
fn weight_composition_zero_role_always_zero() {
for tier in [
ConsciousnessTier::Participant,
ConsciousnessTier::Citizen,
ConsciousnessTier::Steward,
ConsciousnessTier::Guardian,
] {
let tier_bp = tier.vote_weight_bp() as u64;
let result = (0u64 * tier_bp / 10000) as u32;
assert_eq!(result, 0, "Role 0 * {:?} should be 0", tier);
}
}
#[test]
fn weight_composition_all_tiers_all_standard_roles() {
let roles = [(5000u64, "Youth"), (10000u64, "Adult"), (10000u64, "Elder")];
let tiers = [
(ConsciousnessTier::Observer, 0u32),
(ConsciousnessTier::Participant, 5000),
(ConsciousnessTier::Citizen, 7500),
(ConsciousnessTier::Steward, 10000),
(ConsciousnessTier::Guardian, 10000),
];
for (role_bp, role_name) in &roles {
for (tier, tier_bp) in &tiers {
let expected = (*role_bp * *tier_bp as u64 / 10000) as u32;
let actual = (*role_bp * tier.vote_weight_bp() as u64 / 10000) as u32;
assert_eq!(
actual, expected,
"{} ({}) x {:?} ({}): expected {}, got {}",
role_name, role_bp, tier, tier_bp, expected, actual
);
}
}
}
#[test]
fn tier_from_score_negative_is_observer() {
assert_eq!(
ConsciousnessTier::from_score(-1.0),
ConsciousnessTier::Observer
);
assert_eq!(
ConsciousnessTier::from_score(-0.001),
ConsciousnessTier::Observer
);
}
#[test]
fn tier_from_score_above_one_is_guardian() {
assert_eq!(
ConsciousnessTier::from_score(1.5),
ConsciousnessTier::Guardian
);
assert_eq!(
ConsciousnessTier::from_score(100.0),
ConsciousnessTier::Guardian
);
}
#[test]
fn grace_period_allows_basic_operations() {
let profile = ConsciousnessProfile {
identity: 0.3,
reputation: 0.3,
community: 0.3,
engagement: 0.3,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - 600_000_000;
let result = evaluate_governance(&cred, &requirement_for_basic(), NOW);
assert!(result.eligible);
assert!(result.reasons.iter().any(|r| r.contains("grace period")));
}
#[test]
fn grace_period_rejects_voting_operations() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.4,
engagement: 0.2,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - 600_000_000; let result = evaluate_governance(&cred, &requirement_for_voting(), NOW);
assert!(!result.eligible);
assert!(result.reasons[0].contains("expired"));
}
#[test]
fn grace_period_expired_past_window() {
let profile = ConsciousnessProfile {
identity: 0.3,
reputation: 0.3,
community: 0.3,
engagement: 0.3,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - 7_200_000_000;
let result = evaluate_governance(&cred, &requirement_for_basic(), NOW);
assert!(!result.eligible);
}
#[test]
fn should_audit_always_logs_rejections() {
assert!(should_audit(&requirement_for_basic(), false, &[0u8], "any"));
assert!(should_audit(
&requirement_for_basic(),
false,
&[255u8],
"any"
));
}
#[test]
fn should_audit_always_logs_constitutional() {
assert!(should_audit(
&requirement_for_constitutional(),
true,
&[0u8],
"amend"
));
assert!(should_audit(
&requirement_for_constitutional(),
true,
&[255u8],
"amend"
));
}
#[test]
fn should_audit_always_logs_voting() {
assert!(should_audit(
&requirement_for_voting(),
true,
&[0u8],
"vote"
));
assert!(should_audit(
&requirement_for_voting(),
true,
&[255u8],
"vote"
));
}
#[test]
fn should_audit_samples_basic_approvals() {
let z = ""; assert!(should_audit(&requirement_for_basic(), true, &[0u8], z));
assert!(should_audit(&requirement_for_basic(), true, &[25u8], z));
assert!(!should_audit(&requirement_for_basic(), true, &[26u8], z));
assert!(!should_audit(&requirement_for_basic(), true, &[255u8], z));
}
#[test]
fn should_audit_salt_varies_by_action() {
let agent = &[30u8];
assert!(!should_audit(&requirement_for_basic(), true, agent, ""));
assert!(should_audit(&requirement_for_basic(), true, agent, "qq"));
}
#[test]
fn needs_refresh_within_window() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW + 3_600_000_000;
assert!(needs_refresh(&cred, NOW));
}
#[test]
fn needs_refresh_not_within_window() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
let cred = fresh_credential(profile);
assert!(!needs_refresh(&cred, NOW));
}
#[test]
fn needs_refresh_expired_credential() {
let profile = ConsciousnessProfile::zero();
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - 1;
assert!(!needs_refresh(&cred, NOW));
}
#[test]
fn needs_refresh_exactly_at_boundary() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
let mut cred = fresh_credential(profile.clone());
cred.expires_at = NOW + REFRESH_WINDOW_US;
assert!(!needs_refresh(&cred, NOW));
cred.expires_at = NOW + REFRESH_WINDOW_US - 1;
assert!(needs_refresh(&cred, NOW));
}
#[test]
fn needs_refresh_just_expired_not_refreshable() {
let profile = ConsciousnessProfile {
identity: 0.8,
reputation: 0.7,
community: 0.6,
engagement: 0.5,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW; assert!(!needs_refresh(&cred, NOW));
}
#[test]
fn needs_refresh_far_future_not_refreshable() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW + 82_800_000_000; assert!(!needs_refresh(&cred, NOW));
}
#[test]
fn refresh_on_gate_check_flow() {
let profile = ConsciousnessProfile {
identity: 0.8,
reputation: 0.7,
community: 0.6,
engagement: 0.5,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW + 1_800_000_000;
assert!(!cred.is_expired(NOW), "credential should NOT be expired");
let requirement = GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: None,
min_community: None,
};
let eligibility = evaluate_governance(&cred, &requirement, NOW);
assert!(
eligibility.eligible,
"nearing-expiry credential should still pass gate"
);
assert!(
needs_refresh(&cred, NOW),
"credential nearing expiry should trigger refresh"
);
}
#[test]
fn refresh_on_gate_check_fresh_credential_no_refresh() {
let profile = ConsciousnessProfile {
identity: 0.8,
reputation: 0.7,
community: 0.6,
engagement: 0.5,
};
let cred = fresh_credential(profile);
let requirement = GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: None,
min_community: None,
};
let eligibility = evaluate_governance(&cred, &requirement, NOW);
assert!(eligibility.eligible);
assert!(
!needs_refresh(&cred, NOW),
"fresh credential should NOT trigger refresh"
);
}
#[test]
fn refresh_on_gate_check_expired_credential_no_refresh() {
let profile = ConsciousnessProfile {
identity: 0.8,
reputation: 0.7,
community: 0.6,
engagement: 0.5,
};
let mut cred = fresh_credential(profile);
cred.expires_at = NOW - GRACE_PERIOD_US - 1;
let requirement = GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: None,
min_community: None,
};
let eligibility = evaluate_governance(&cred, &requirement, NOW);
assert!(!eligibility.eligible, "expired credential should fail gate");
assert!(
!needs_refresh(&cred, NOW),
"expired credential should NOT trigger refresh"
);
}
#[test]
fn gate_audit_input_serde_with_correlation_id() {
let audit = GateAuditInput {
action_name: "test".into(),
zome_name: "test_zome".into(),
eligible: true,
actual_tier: "Citizen".into(),
required_tier: "Participant".into(),
weight_bp: 7500,
correlation_id: Some("abcdef01:1700000000000000".into()),
credential_source: None,
};
let json = serde_json::to_string(&audit).unwrap();
let a2: GateAuditInput = serde_json::from_str(&json).unwrap();
assert_eq!(a2.correlation_id, Some("abcdef01:1700000000000000".into()));
}
#[test]
fn gate_audit_input_serde_without_correlation_id() {
let json = r#"{"action_name":"test","zome_name":"z","eligible":true,"actual_tier":"Citizen","required_tier":"Participant","weight_bp":7500}"#;
let audit: GateAuditInput = serde_json::from_str(json).unwrap();
assert_eq!(audit.correlation_id, None);
assert_eq!(audit.credential_source, None);
}
#[test]
fn gate_audit_input_serde_with_credential_source() {
let audit = GateAuditInput {
action_name: "create_shelter".into(),
zome_name: "civic_bridge".into(),
eligible: true,
actual_tier: "Citizen".into(),
required_tier: "Participant".into(),
weight_bp: 7500,
correlation_id: None,
credential_source: Some("identity_bridge_fresh".into()),
};
let json = serde_json::to_string(&audit).unwrap();
assert!(json.contains("credential_source"));
assert!(json.contains("identity_bridge_fresh"));
let a2: GateAuditInput = serde_json::from_str(&json).unwrap();
assert_eq!(a2.credential_source, Some("identity_bridge_fresh".into()));
}
#[test]
fn mvb_profile_from_unified_consciousness() {
let profile = ConsciousnessProfile::from_unified_consciousness(
0.65, 0.80, 0.50, 0.40, );
assert_eq!(profile.engagement, 0.65);
assert_eq!(profile.identity, 0.80);
assert_eq!(profile.reputation, 0.50);
assert_eq!(profile.community, 0.40);
let expected = 0.80 * 0.25 + 0.50 * 0.25 + 0.40 * 0.30 + 0.65 * 0.20;
assert!((profile.combined_score() - expected).abs() < 1e-10);
}
#[test]
fn mvb_profile_clamps_out_of_range() {
let profile = ConsciousnessProfile::from_unified_consciousness(1.5, -0.2, 0.5, 0.5);
assert_eq!(profile.engagement, 1.0);
assert_eq!(profile.identity, 0.0);
}
#[test]
fn symthaea_bridge_composite_engagement() {
let profile = ConsciousnessProfile::from_symthaea(
0.8, 0.6, 0.5, 0.7, 0.75, 0.50, 0.40, );
let expected_engagement = 0.35 * 0.8 + 0.25 * 0.6 + 0.20 * 0.5 + 0.20 * 0.7;
assert!((profile.engagement - expected_engagement).abs() < 1e-10);
assert_eq!(profile.identity, 0.75);
assert_eq!(profile.reputation, 0.50);
assert_eq!(profile.community, 0.40);
}
#[test]
fn symthaea_bridge_all_max() {
let profile = ConsciousnessProfile::from_symthaea(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0);
assert_eq!(profile.engagement, 1.0);
assert_eq!(profile.combined_score(), 1.0);
assert_eq!(profile.tier(), ConsciousnessTier::Guardian);
}
#[test]
fn symthaea_bridge_all_zero() {
let profile = ConsciousnessProfile::from_symthaea(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
assert_eq!(profile.engagement, 0.0);
assert_eq!(profile.combined_score(), 0.0);
assert_eq!(profile.tier(), ConsciousnessTier::Observer);
}
#[test]
fn symthaea_bridge_clamps_inputs() {
let profile = ConsciousnessProfile::from_symthaea(
1.5, -0.3, 2.0, -1.0, 0.5, 0.5, 0.5,
);
let expected = 0.35 + 0.20;
assert!((profile.engagement - expected).abs() < 1e-10);
}
#[test]
fn symthaea_credential_from_enriched_bridge() {
let now = 1_000_000_000_000_u64;
let cred = ConsciousnessCredential::from_symthaea(
"did:mycelix:enriched".into(),
0.7,
0.6,
0.5,
0.8, 0.80,
0.50,
0.40, "did:mycelix:bridge".into(),
now,
);
assert_eq!(cred.did, "did:mycelix:enriched");
let expected_engagement = 0.35 * 0.7 + 0.25 * 0.6 + 0.20 * 0.5 + 0.20 * 0.8;
assert!((cred.profile.engagement - expected_engagement).abs() < 1e-10);
assert!(cred.tier >= ConsciousnessTier::Citizen);
}
#[test]
fn mvb_credential_from_unified_consciousness() {
let cred = ConsciousnessCredential::from_unified_consciousness(
"did:mycelix:agent123".into(),
0.65, 0.80,
0.50,
0.40,
"did:mycelix:bridge".into(),
NOW,
);
assert_eq!(cred.did, "did:mycelix:agent123");
assert_eq!(cred.profile.engagement, 0.65);
assert_eq!(cred.issued_at, NOW);
assert_eq!(
cred.expires_at,
NOW + ConsciousnessCredential::DEFAULT_TTL_US
);
assert!(!cred.is_expired(NOW));
assert!(cred.tier >= ConsciousnessTier::Citizen);
}
#[test]
fn mvb_end_to_end_high_consciousness_proposal_eligible() {
let cred = ConsciousnessCredential::from_unified_consciousness(
"did:mycelix:agent_high".into(),
0.70, 0.80, 0.60, 0.50, "did:mycelix:bridge".into(),
NOW,
);
let result = evaluate_governance(&cred, &requirement_for_proposal(), NOW);
assert!(
result.eligible,
"High-consciousness agent should be proposal-eligible"
);
assert!(result.tier >= ConsciousnessTier::Participant);
assert!(result.weight_bp > 0);
let should_log = should_audit(
&requirement_for_proposal(),
result.eligible,
b"agent_high",
"submit_proposal",
);
let _audit = GateAuditInput {
action_name: "submit_proposal".into(),
zome_name: "commons_bridge".into(),
eligible: result.eligible,
actual_tier: format!("{:?}", result.tier),
required_tier: format!("{:?}", ConsciousnessTier::Participant),
weight_bp: result.weight_bp,
correlation_id: Some(format!("mvb:{}", NOW)),
credential_source: Some("identity_bridge_fresh".into()),
};
let json = serde_json::to_string(&_audit).unwrap();
assert!(json.contains("submit_proposal"));
let _ = should_log; }
#[test]
fn mvb_end_to_end_low_consciousness_proposal_rejected() {
let cred = ConsciousnessCredential::from_unified_consciousness(
"did:mycelix:agent_low".into(),
0.10, 0.20, 0.10, 0.15, "did:mycelix:bridge".into(),
NOW,
);
let result = evaluate_governance(&cred, &requirement_for_proposal(), NOW);
assert!(
!result.eligible,
"Low-consciousness agent should NOT be proposal-eligible"
);
assert_eq!(result.tier, ConsciousnessTier::Observer);
assert_eq!(result.weight_bp, 0);
assert!(should_audit(
&requirement_for_proposal(),
false,
b"agent_low",
"submit_proposal"
));
}
#[test]
fn mvb_end_to_end_read_always_allowed() {
let cred = ConsciousnessCredential::from_unified_consciousness(
"did:mycelix:agent_zero".into(),
0.0, 0.0,
0.0,
0.0,
"did:mycelix:bridge".into(),
NOW,
);
assert_eq!(cred.tier, ConsciousnessTier::Observer);
assert_eq!(cred.profile.combined_score(), 0.0);
}
#[test]
fn bootstrap_eligible_small_community() {
assert!(is_bootstrap_eligible(0, 0.25));
assert!(is_bootstrap_eligible(4, 0.50));
}
#[test]
fn bootstrap_ineligible_large_community() {
assert!(!is_bootstrap_eligible(5, 0.50));
assert!(!is_bootstrap_eligible(100, 1.0));
}
#[test]
fn bootstrap_ineligible_low_identity() {
assert!(!is_bootstrap_eligible(2, 0.24));
assert!(!is_bootstrap_eligible(0, 0.0));
}
#[test]
fn bootstrap_boundary() {
assert!(!is_bootstrap_eligible(BOOTSTRAP_COMMUNITY_THRESHOLD, 0.5));
assert!(is_bootstrap_eligible(
BOOTSTRAP_COMMUNITY_THRESHOLD - 1,
0.5
));
assert!(is_bootstrap_eligible(2, BOOTSTRAP_MIN_IDENTITY));
}
#[test]
fn bootstrap_credential_properties() {
let cred = bootstrap_credential("did:mycelix:first".into(), 0.5, NOW);
assert_eq!(cred.tier, ConsciousnessTier::Participant);
assert_eq!(cred.profile.identity, 0.5);
assert_eq!(cred.profile.reputation, 0.0);
assert_eq!(cred.issuer, "did:mycelix:bootstrap");
assert_eq!(cred.expires_at, NOW + BOOTSTRAP_TTL_US);
}
#[test]
fn bootstrap_governance_basic_eligible() {
let cred = bootstrap_credential("did:mycelix:first".into(), 0.5, NOW);
let result = evaluate_bootstrap_governance(&cred, &requirement_for_basic(), NOW);
assert!(result.eligible);
assert_eq!(result.weight_bp, 5_000);
}
#[test]
fn bootstrap_governance_voting_rejected() {
let cred = bootstrap_credential("did:mycelix:first".into(), 0.5, NOW);
let result = evaluate_bootstrap_governance(&cred, &requirement_for_voting(), NOW);
assert!(!result.eligible);
assert!(result.reasons[0].contains("capped at Participant"));
}
#[test]
fn bootstrap_governance_expired_rejected() {
let cred = bootstrap_credential("did:mycelix:first".into(), 0.5, NOW);
let result = evaluate_bootstrap_governance(
&cred,
&requirement_for_basic(),
NOW + BOOTSTRAP_TTL_US + 1,
);
assert!(!result.eligible);
}
#[test]
fn bootstrap_serde_roundtrip() {
let cred = bootstrap_credential("did:mycelix:first".into(), 0.5, NOW);
let json = serde_json::to_string(&cred).unwrap();
let cred2: ConsciousnessCredential = serde_json::from_str(&json).unwrap();
assert_eq!(cred.did, cred2.did);
assert_eq!(cred.tier, cred2.tier);
}
#[test]
fn clamped_sanitizes_nan_to_zero() {
let p = ConsciousnessProfile {
identity: f64::NAN,
reputation: f64::NAN,
community: f64::NAN,
engagement: f64::NAN,
};
let c = p.clamped();
assert_eq!(c.identity, 0.0);
assert_eq!(c.reputation, 0.0);
assert_eq!(c.community, 0.0);
assert_eq!(c.engagement, 0.0);
assert_eq!(c.tier(), ConsciousnessTier::Observer);
}
#[test]
fn clamped_sanitizes_infinity_to_bounds() {
let p = ConsciousnessProfile {
identity: f64::INFINITY,
reputation: f64::NEG_INFINITY,
community: f64::INFINITY,
engagement: f64::NEG_INFINITY,
};
let c = p.clamped();
assert_eq!(c.identity, 0.0);
assert_eq!(c.reputation, 0.0);
assert_eq!(c.community, 0.0);
assert_eq!(c.engagement, 0.0);
}
#[test]
fn clamped_mixed_nan_and_valid() {
let p = ConsciousnessProfile {
identity: 0.75,
reputation: f64::NAN,
community: 0.50,
engagement: f64::INFINITY,
};
let c = p.clamped();
assert_eq!(c.identity, 0.75);
assert_eq!(c.reputation, 0.0);
assert_eq!(c.community, 0.50);
assert_eq!(c.engagement, 0.0);
}
#[test]
fn is_valid_detects_nan() {
let valid = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
assert!(valid.is_valid());
let nan_id = ConsciousnessProfile {
identity: f64::NAN,
..valid.clone()
};
assert!(!nan_id.is_valid());
let inf_rep = ConsciousnessProfile {
reputation: f64::INFINITY,
..valid.clone()
};
assert!(!inf_rep.is_valid());
let neg_inf = ConsciousnessProfile {
community: f64::NEG_INFINITY,
..valid
};
assert!(!neg_inf.is_valid());
}
#[test]
fn nan_credential_evaluates_to_observer() {
let cred = fresh_credential(ConsciousnessProfile {
identity: f64::NAN,
reputation: f64::NAN,
community: f64::NAN,
engagement: f64::NAN,
});
let result = evaluate_governance(&cred, &requirement_for_basic(), NOW);
assert!(!result.eligible);
assert_eq!(result.tier, ConsciousnessTier::Observer);
}
#[test]
fn nan_does_not_bypass_gate() {
let cred = fresh_credential(ConsciousnessProfile {
identity: f64::NAN,
reputation: 0.9,
community: 0.9,
engagement: 0.9,
});
let result = evaluate_governance(&cred, &requirement_for_voting(), NOW);
assert!(!result.eligible);
assert!(result.reasons.iter().any(|r| r.contains("Identity")));
}
use proptest::prelude::*;
fn dimension() -> impl Strategy<Value = f64> {
0.0..=1.0_f64
}
fn profile_strategy() -> impl Strategy<Value = ConsciousnessProfile> {
(dimension(), dimension(), dimension(), dimension()).prop_map(
|(identity, reputation, community, engagement)| ConsciousnessProfile {
identity,
reputation,
community,
engagement,
},
)
}
proptest! {
#[test]
fn test_tier_progression_monotonic(
id_lo in dimension(),
rep_lo in dimension(),
com_lo in dimension(),
eng_lo in dimension(),
id_delta in 0.0..=1.0_f64,
rep_delta in 0.0..=1.0_f64,
com_delta in 0.0..=1.0_f64,
eng_delta in 0.0..=1.0_f64,
) {
let lo = ConsciousnessProfile {
identity: id_lo,
reputation: rep_lo,
community: com_lo,
engagement: eng_lo,
};
let hi = ConsciousnessProfile {
identity: (id_lo + id_delta).min(1.0),
reputation: (rep_lo + rep_delta).min(1.0),
community: (com_lo + com_delta).min(1.0),
engagement: (eng_lo + eng_delta).min(1.0),
};
prop_assert!(hi.tier() >= lo.tier(),
"Higher profile {:?} (tier {:?}) should be >= lower profile {:?} (tier {:?})",
hi, hi.tier(), lo, lo.tier());
}
#[test]
fn test_vote_weight_monotonic_with_tier(
a in profile_strategy(),
b in profile_strategy(),
) {
let tier_a = a.tier();
let tier_b = b.tier();
if tier_a <= tier_b {
prop_assert!(tier_a.vote_weight_bp() <= tier_b.vote_weight_bp(),
"Tier {:?} (weight {}) should have <= weight than {:?} (weight {})",
tier_a, tier_a.vote_weight_bp(), tier_b, tier_b.vote_weight_bp());
}
}
#[test]
fn test_all_zero_profile_is_observer(_seed in 0u32..100) {
let p = ConsciousnessProfile::zero();
prop_assert_eq!(p.tier(), ConsciousnessTier::Observer);
prop_assert_eq!(p.combined_score(), 0.0);
prop_assert_eq!(p.tier().vote_weight_bp(), 0);
}
#[test]
fn test_all_max_profile_no_panic(_seed in 0u32..100) {
let p = ConsciousnessProfile {
identity: 1.0,
reputation: 1.0,
community: 1.0,
engagement: 1.0,
};
let tier = p.tier();
let score = p.combined_score();
let weight = tier.vote_weight_bp();
prop_assert_eq!(tier, ConsciousnessTier::Guardian);
prop_assert!((score - 1.0).abs() < 1e-10);
prop_assert_eq!(weight, 10000);
}
#[test]
fn test_credential_expiry_in_future(
c_unified in dimension(),
identity in dimension(),
reputation in dimension(),
community in dimension(),
now_us in 0u64..=u64::MAX / 2,
) {
let cred = ConsciousnessCredential::from_unified_consciousness(
"did:test:prop".into(),
c_unified,
identity,
reputation,
community,
"did:test:issuer".into(),
now_us,
);
prop_assert!(cred.expires_at > cred.issued_at,
"expires_at ({}) must be > issued_at ({})",
cred.expires_at, cred.issued_at);
prop_assert_eq!(cred.expires_at, now_us + ConsciousnessCredential::DEFAULT_TTL_US);
}
#[test]
fn test_profile_scores_bounded(
identity in -10.0..=10.0_f64,
reputation in -10.0..=10.0_f64,
community in -10.0..=10.0_f64,
engagement in -10.0..=10.0_f64,
) {
let raw = ConsciousnessProfile { identity, reputation, community, engagement };
let clamped = raw.clamped();
prop_assert!(clamped.identity >= 0.0 && clamped.identity <= 1.0);
prop_assert!(clamped.reputation >= 0.0 && clamped.reputation <= 1.0);
prop_assert!(clamped.community >= 0.0 && clamped.community <= 1.0);
prop_assert!(clamped.engagement >= 0.0 && clamped.engagement <= 1.0);
let score = clamped.combined_score();
prop_assert!(score >= 0.0 && score <= 1.0,
"Combined score {} out of bounds for clamped profile {:?}",
score, clamped);
let _tier = clamped.tier();
}
}
#[test]
fn test_reputation_decay_one_day() {
let mut state = ReputationState::new(1.0, 0);
let one_day_us = 86_400_000_000u64;
state.apply_decay(one_day_us);
assert!(
(state.score - REPUTATION_DECAY_PER_DAY).abs() < 1e-6,
"After 1 day, score should be {}, got {}",
REPUTATION_DECAY_PER_DAY,
state.score
);
}
#[test]
fn test_reputation_decay_half_life() {
let mut state = ReputationState::new(1.0, 0);
let days_347_us = 347 * 86_400_000_000u64;
state.apply_decay(days_347_us);
assert!(
state.score > 0.49 && state.score < 0.51,
"After ~347 days, score should be ~0.5, got {}",
state.score
);
}
#[test]
fn test_reputation_no_decay_on_zero_elapsed() {
let mut state = ReputationState::new(0.8, 1000);
state.apply_decay(1000); assert!((state.score - 0.8).abs() < 1e-10);
}
#[test]
fn test_reputation_slash() {
let mut state = ReputationState::new(1.0, 0);
let new_score = state.slash(1000);
assert!(
(new_score - 0.5).abs() < 1e-6,
"After slash, score should be 0.5, got {}",
new_score
);
assert_eq!(state.total_slashes, 1);
assert_eq!(state.consecutive_good, 0);
}
#[test]
fn test_reputation_slash_below_blacklist() {
let mut state = ReputationState::new(0.08, 0);
state.slash(1000);
assert!(state.blacklisted);
assert!(!state.can_participate());
}
#[test]
fn test_reputation_restoration_path() {
let mut state = ReputationState::new(0.03, 0);
state.blacklisted = true;
state.blacklisted_since_us = Some(0);
for i in 0..REPUTATION_RESTORATION_INTERACTIONS {
assert!(
state.blacklisted,
"Should still be blacklisted at interaction {}",
i
);
state.record_good_interaction(0.001, 1000 + i as u64 * 1000);
}
assert!(
!state.blacklisted,
"Should be restored after {} good interactions",
REPUTATION_RESTORATION_INTERACTIONS
);
assert!(
state.score >= 0.1,
"Score should be at least 0.1 after restoration"
);
}
#[test]
fn test_reputation_max_slashes_cap() {
let mut state = ReputationState::new(1.0, 0);
for i in 0..(REPUTATION_MAX_SLASHES + 2) {
state.score = 0.8; state.slash(i as u64 * 1000);
}
state.score = 0.3;
state.blacklisted = false;
for i in 0..200 {
state.record_good_interaction(0.01, 1_000_000 + i as u64 * 1000);
}
assert!(
state.score <= 0.5 + 1e-6,
"Score should be capped at 0.5 after {} slashes, got {}",
REPUTATION_MAX_SLASHES,
state.score
);
}
#[test]
fn test_reputation_proportional_slash() {
let mut state = ReputationState::new(1.0, 0);
state.slash_proportional(0.3, 1000);
assert!((state.score - 0.7).abs() < 1e-6);
}
#[test]
fn test_reputation_restoration_progress() {
let mut state = ReputationState::new(0.01, 0);
state.blacklisted = true;
state.blacklisted_since_us = Some(0);
state.consecutive_good = 50;
let progress = state.restoration_progress();
assert!(
(progress - 0.5).abs() < 1e-6,
"50/{} should be 50% progress, got {}",
REPUTATION_RESTORATION_INTERACTIONS,
progress
);
}
#[test]
fn test_reputation_non_blacklisted_full_progress() {
let state = ReputationState::new(0.8, 0);
assert!((state.restoration_progress() - 1.0).abs() < 1e-10);
}
#[test]
fn test_decay_reputation_profile() {
let profile = ConsciousnessProfile {
identity: 0.9,
reputation: 1.0,
community: 0.7,
engagement: 0.5,
};
let decayed = decay_reputation(&profile, 30.0);
assert!(
(decayed.identity - 0.9).abs() < 1e-10,
"Identity should not decay"
);
assert!(decayed.reputation < 1.0, "Reputation should decay");
assert!(
(decayed.community - 0.7).abs() < 1e-10,
"Community should not decay"
);
}
#[test]
fn test_evaluate_governance_blacklisted() {
let credential = ConsciousnessCredential {
did: "did:mycelix:test".to_string(),
profile: ConsciousnessProfile {
identity: 0.9,
reputation: 0.01,
community: 0.8,
engagement: 0.7,
},
tier: ConsciousnessTier::Citizen,
issued_at: 0,
expires_at: 100_000_000_000,
issuer: "did:mycelix:bridge".to_string(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
let rep_state = ReputationState {
score: 0.01,
blacklisted: true,
blacklisted_since_us: Some(0),
consecutive_good: 20,
total_slashes: 2,
last_updated_us: 0,
last_slash_us: None,
};
let requirement = GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: None,
min_community: None,
};
let result = evaluate_governance_with_reputation(
&credential,
&requirement,
&rep_state,
50_000_000_000,
);
assert!(!result.eligible, "Blacklisted agent should not be eligible");
assert_eq!(result.weight_bp, 0);
}
#[test]
fn test_evaluate_governance_slash_penalty() {
let credential = ConsciousnessCredential {
did: "did:mycelix:test".to_string(),
profile: ConsciousnessProfile {
identity: 0.9,
reputation: 0.8,
community: 0.8,
engagement: 0.7,
},
tier: ConsciousnessTier::Steward,
issued_at: 0,
expires_at: 100_000_000_000,
issuer: "did:mycelix:bridge".to_string(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
let rep_state = ReputationState {
score: 0.8,
blacklisted: false,
blacklisted_since_us: None,
last_slash_us: None,
consecutive_good: 50,
total_slashes: 2, last_updated_us: 0,
};
let requirement = GovernanceRequirement {
min_tier: ConsciousnessTier::Participant,
min_identity: None,
min_community: None,
};
let result = evaluate_governance_with_reputation(
&credential,
&requirement,
&rep_state,
50_000_000_000,
);
assert!(result.eligible);
let base_weight = credential.profile.clamped().tier().vote_weight_bp();
assert!(
result.weight_bp < base_weight,
"Weight {} should be less than base {} due to slash penalty",
result.weight_bp,
base_weight
);
}
#[test]
fn test_reputation_nan_safety() {
let state = ReputationState::new(f64::NAN, 0);
assert!((state.score - 0.0).abs() < 1e-10, "NaN should clamp to 0");
let mut state2 = ReputationState::new(0.5, 0);
state2.apply_decay(u64::MAX); assert!(state2.score.is_finite());
}
#[test]
fn test_sigmoid_at_threshold_returns_half_max() {
let w = continuous_vote_weight(0.4, 0.4, VOTE_WEIGHT_TEMPERATURE, VOTE_WEIGHT_MAX_BP);
assert!(
(w - VOTE_WEIGHT_MAX_BP / 2.0).abs() < 1e-6,
"At threshold, weight should be max/2, got {w}"
);
}
#[test]
fn test_sigmoid_below_threshold_near_zero() {
let w = continuous_vote_weight(0.1, 0.4, VOTE_WEIGHT_TEMPERATURE, VOTE_WEIGHT_MAX_BP);
assert!(
w < 100.0,
"Well below threshold, weight should be near zero, got {w}"
);
}
#[test]
fn test_sigmoid_above_threshold_near_max() {
let w = continuous_vote_weight(0.7, 0.4, VOTE_WEIGHT_TEMPERATURE, VOTE_WEIGHT_MAX_BP);
assert!(
w > 9900.0,
"Well above threshold, weight should be near max, got {w}"
);
}
#[test]
fn test_sigmoid_zero_temperature_returns_zero() {
let w = continuous_vote_weight(0.5, 0.4, 0.0, VOTE_WEIGHT_MAX_BP);
assert!(
(w - 0.0).abs() < 1e-10,
"Zero temperature should return 0.0, got {w}"
);
}
#[test]
fn test_sigmoid_nan_score_returns_zero() {
let w = continuous_vote_weight(f64::NAN, 0.4, VOTE_WEIGHT_TEMPERATURE, VOTE_WEIGHT_MAX_BP);
assert!(
(w - 0.0).abs() < 1e-10,
"NaN score should return 0.0, got {w}"
);
}
#[test]
fn test_sigmoid_infinity_score_returns_zero() {
let w = continuous_vote_weight(
f64::INFINITY,
0.4,
VOTE_WEIGHT_TEMPERATURE,
VOTE_WEIGHT_MAX_BP,
);
assert!(
(w - 0.0).abs() < 1e-10,
"Infinity score should return 0.0, got {w}"
);
}
#[test]
fn test_vote_weight_continuous_on_profile() {
let profile = ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
};
let w = profile.vote_weight_continuous();
assert!(
w > VOTE_WEIGHT_MAX_BP / 2.0,
"Score 0.5 > threshold 0.4 should give > half max"
);
assert!(w < VOTE_WEIGHT_MAX_BP, "Should not exceed max");
}
#[test]
fn test_hysteresis_no_promote_in_deadband() {
let tier =
ConsciousnessTier::from_score_with_hysteresis(0.42, ConsciousnessTier::Participant);
assert_eq!(
tier,
ConsciousnessTier::Participant,
"0.42 should NOT promote from Participant (need 0.45)"
);
}
#[test]
fn test_hysteresis_no_demote_in_deadband() {
let tier = ConsciousnessTier::from_score_with_hysteresis(0.38, ConsciousnessTier::Citizen);
assert_eq!(
tier,
ConsciousnessTier::Citizen,
"0.38 should NOT demote from Citizen (need < 0.35)"
);
}
#[test]
fn test_hysteresis_demotes_below_lower_threshold() {
let tier = ConsciousnessTier::from_score_with_hysteresis(0.34, ConsciousnessTier::Citizen);
assert_eq!(
tier,
ConsciousnessTier::Participant,
"0.34 should demote from Citizen (below 0.35)"
);
}
#[test]
fn test_hysteresis_promotes_above_upper_threshold() {
let tier =
ConsciousnessTier::from_score_with_hysteresis(0.46, ConsciousnessTier::Participant);
assert_eq!(
tier,
ConsciousnessTier::Citizen,
"0.46 should promote from Participant to Citizen (above 0.45)"
);
}
#[test]
fn test_hysteresis_guardian_boundary() {
let tier = ConsciousnessTier::from_score_with_hysteresis(0.83, ConsciousnessTier::Steward);
assert_eq!(
tier,
ConsciousnessTier::Steward,
"0.83 should NOT promote to Guardian (need 0.85)"
);
let tier = ConsciousnessTier::from_score_with_hysteresis(0.86, ConsciousnessTier::Steward);
assert_eq!(
tier,
ConsciousnessTier::Guardian,
"0.86 should promote to Guardian"
);
let tier = ConsciousnessTier::from_score_with_hysteresis(0.74, ConsciousnessTier::Guardian);
assert_eq!(
tier,
ConsciousnessTier::Steward,
"0.74 should demote from Guardian"
);
}
#[test]
fn test_hysteresis_observer_boundary() {
let tier = ConsciousnessTier::from_score_with_hysteresis(0.33, ConsciousnessTier::Observer);
assert_eq!(
tier,
ConsciousnessTier::Observer,
"0.33 should NOT promote from Observer (need 0.35)"
);
let tier = ConsciousnessTier::from_score_with_hysteresis(0.36, ConsciousnessTier::Observer);
assert_eq!(
tier,
ConsciousnessTier::Participant,
"0.36 should promote to Participant"
);
let tier =
ConsciousnessTier::from_score_with_hysteresis(0.24, ConsciousnessTier::Participant);
assert_eq!(
tier,
ConsciousnessTier::Observer,
"0.24 should demote to Observer"
);
}
#[test]
fn extensions_default_empty() {
let cred = ConsciousnessCredential::from_unified_consciousness(
"did:test".into(),
0.5,
0.5,
0.5,
0.5,
"issuer".into(),
1000,
);
assert!(cred.extensions.is_empty());
assert!(cred.trajectory_commitment.is_none());
}
#[test]
fn extensions_set_get_roundtrip() {
let mut cred = ConsciousnessCredential::from_unified_consciousness(
"did:test".into(),
0.5,
0.5,
0.5,
0.5,
"issuer".into(),
1000,
);
cred.set_extension("foo", vec![1, 2, 3]);
assert_eq!(cred.get_extension("foo"), Some(&vec![1, 2, 3]));
assert_eq!(cred.get_extension("bar"), None);
}
#[test]
fn extensions_remove() {
let mut cred = ConsciousnessCredential::from_unified_consciousness(
"did:test".into(),
0.5,
0.5,
0.5,
0.5,
"issuer".into(),
1000,
);
cred.set_extension("key", vec![42]);
let removed = cred.remove_extension("key");
assert_eq!(removed, Some(vec![42]));
assert!(cred.get_extension("key").is_none());
}
mod sybil_proptests {
use super::*;
use proptest::prelude::*;
const MATURATION_US: u64 = 72 * 3600 * 1_000_000;
fn make_credential_at_age(age_us: u64) -> (ConsciousnessCredential, u64) {
let now_us = 1_000_000_000_000u64; let issued_at = now_us.saturating_sub(age_us);
let cred = ConsciousnessCredential {
did: "did:test:prop".to_string(),
profile: ConsciousnessProfile {
identity: 0.5,
reputation: 0.5,
community: 0.5,
engagement: 0.5,
},
tier: ConsciousnessTier::Citizen,
issued_at,
expires_at: now_us + 86_400_000_000,
issuer: "test".to_string(),
trajectory_commitment: None,
extensions: std::collections::HashMap::new(),
};
(cred, now_us)
}
proptest! {
#[test]
fn prop_weight_monotonic_with_age(
age_a_hours in 0u64..200,
age_b_hours in 0u64..200,
) {
let age_a_us = age_a_hours * 3600 * 1_000_000;
let age_b_us = age_b_hours * 3600 * 1_000_000;
let (cred_a, now) = make_credential_at_age(age_a_us);
let (cred_b, _) = make_credential_at_age(age_b_us);
let req = requirement_for_basic();
let result_a = evaluate_governance(&cred_a, &req, now);
let result_b = evaluate_governance(&cred_b, &req, now);
if age_a_us >= age_b_us {
prop_assert!(
result_a.weight_bp >= result_b.weight_bp,
"Older credential should have >= weight than younger: {} vs {}",
result_a.weight_bp, result_b.weight_bp
);
}
}
#[test]
fn prop_mature_credential_full_weight(age_hours in 73u64..1000) {
let age_us = age_hours * 3600 * 1_000_000;
let (cred, now) = make_credential_at_age(age_us);
let req = requirement_for_basic();
let result = evaluate_governance(&cred, &req, now);
let baseline = {
let (fresh_cred, _) = make_credential_at_age(age_us);
evaluate_governance(&fresh_cred, &req, now).weight_bp
};
prop_assert_eq!(
result.weight_bp, baseline,
"Mature credential should have full (unpenalized) weight"
);
}
#[test]
fn prop_new_credential_reduced_weight(age_minutes in 0u64..60) {
let age_us = age_minutes * 60 * 1_000_000;
let (cred, now) = make_credential_at_age(age_us);
let req = requirement_for_basic();
let result = evaluate_governance(&cred, &req, now);
prop_assert!(
result.weight_bp < 3000,
"New credential should have reduced weight: {}",
result.weight_bp
);
}
#[test]
fn prop_sybil_swarm_reduced_total_weight(n_sybils in 3usize..50) {
let age_us = 60 * 1_000_000; let honest_age_us = 100 * 3600 * 1_000_000;
let (sybil_cred, now) = make_credential_at_age(age_us);
let (honest_cred, _) = make_credential_at_age(honest_age_us);
let req = requirement_for_basic();
let sybil_weight = evaluate_governance(&sybil_cred, &req, now).weight_bp;
let honest_weight = evaluate_governance(&honest_cred, &req, now).weight_bp;
let sybil_total = sybil_weight as u64 * n_sybils as u64;
let honest_total = honest_weight as u64 * n_sybils as u64;
let ratio = sybil_total as f64 / honest_total.max(1) as f64;
prop_assert!(
ratio <= 0.3,
"Sybil swarm total weight should be <= 30% of honest: ratio={}",
ratio
);
}
}
}
}