use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::index::{IdNamespace, IndexEntry, IndexFile, Status, VerifyLevel, VerifyMethod};
const ART_CAP: usize = 3;
const ART_PER_INTENT: f64 = 0.05;
const APPRENTICE_CUTOFF: f64 = 0.10;
const ADEPT_CUTOFF: f64 = 0.35;
const ASCENDENT_CUTOFF: f64 = 0.65;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Tier {
Aspirant,
Apprentice,
Adept,
Ascendent,
Arete,
}
impl Tier {
pub fn label(self) -> &'static str {
match self {
Tier::Aspirant => "Aspirant",
Tier::Apprentice => "Apprentice",
Tier::Adept => "Adept",
Tier::Ascendent => "Ascendent",
Tier::Arete => "✦ Areté",
}
}
pub fn color_hex(self) -> &'static str {
match self {
Tier::Aspirant => "#8a8378",
Tier::Apprentice => "#c9a87c",
Tier::Adept => "#C0362C",
Tier::Ascendent => "#8c2913",
Tier::Arete => "#d4a017",
}
}
}
#[derive(Debug, Clone)]
pub struct TierComputation {
pub verifiable: usize,
pub verification_ratio: f64,
pub coverage_score: f64,
pub articulation_floor: f64,
pub visible_score: f64,
pub arete_gate_met: bool,
pub tier: Tier,
}
pub fn score_to_visible_tier(score: f64) -> Tier {
if score < APPRENTICE_CUTOFF {
Tier::Aspirant
} else if score < ADEPT_CUTOFF {
Tier::Apprentice
} else if score < ASCENDENT_CUTOFF {
Tier::Adept
} else {
Tier::Ascendent
}
}
pub fn compute_tier(
index: &IndexFile,
fn_counts: &BTreeMap<PathBuf, u32>,
default_method: Option<VerifyMethod>,
) -> TierComputation {
let mut verifiable = 0usize;
let mut contribution_sum = 0.0f64;
let mut arete_gate_met = false;
let mut intents_by_file: BTreeMap<PathBuf, u32> = BTreeMap::new();
for (id, entry) in &index.entries {
let IndexEntry::Intent(e) = entry else {
continue;
};
if matches!(e.verify, VerifyLevel::Bool(false)) {
continue;
}
verifiable += 1;
let resolved = resolve_verify(&e.verify, default_method);
let weight = depth_weight(resolved, e.status);
contribution_sum += weight;
*intents_by_file.entry(PathBuf::from(&e.file)).or_default() += 1;
if matches!(resolved, Some(VerifyMethod::Full))
&& e.status == Status::Verified
&& matches!(id.namespace(), IdNamespace::Aristos)
{
arete_gate_met = true;
}
}
let verification_ratio = if verifiable == 0 {
0.0
} else {
contribution_sum / verifiable as f64
};
let coverage_score = compute_coverage_score(fn_counts, &intents_by_file);
let articulation_floor = (verifiable.min(ART_CAP)) as f64 * ART_PER_INTENT;
let raw = (verification_ratio * coverage_score).max(articulation_floor);
let visible_score = raw.clamp(0.0, 1.0);
let visible_tier = score_to_visible_tier(visible_score);
let tier = if arete_gate_met {
Tier::Arete
} else {
visible_tier
};
TierComputation {
verifiable,
verification_ratio,
coverage_score,
articulation_floor,
visible_score,
arete_gate_met,
tier,
}
}
fn compute_coverage_score(
fn_counts: &BTreeMap<PathBuf, u32>,
intents_by_file: &BTreeMap<PathBuf, u32>,
) -> f64 {
let mut local_credits = Vec::new();
for (module, &fn_count) in fn_counts {
if fn_count == 0 {
continue;
}
let target = ((fn_count as f64).sqrt().ceil() as u32).max(1);
let intents_here = intents_by_file.get(module.as_path()).copied().unwrap_or(0);
let local = (intents_here as f64 / target as f64).min(1.0);
local_credits.push(local);
}
if local_credits.is_empty() {
return 0.0;
}
local_credits.iter().copied().sum::<f64>() / local_credits.len() as f64
}
fn resolve_verify(
level: &VerifyLevel,
default_method: Option<VerifyMethod>,
) -> Option<VerifyMethod> {
match level {
VerifyLevel::Bool(false) => None,
VerifyLevel::Bool(true) => default_method,
VerifyLevel::Method(m) => Some(*m),
}
}
fn depth_weight(resolved: Option<VerifyMethod>, status: Status) -> f64 {
if !matches!(status, Status::Verified | Status::Tested | Status::Neural) {
return 0.0;
}
match resolved {
Some(VerifyMethod::Full) => 1.0,
Some(VerifyMethod::Test) => 0.8,
Some(VerifyMethod::Neural) => 0.6,
None => 0.0,
}
}
pub fn count_fns_for_root(
root: &Path,
opts: &crate::walk::WalkOptions,
) -> Result<BTreeMap<PathBuf, u32>, crate::walk::FsWalkError> {
crate::walk::count_fns_per_module_with(root, opts)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::index::{
AnnotationId, ArtaId, AssumeEntry, BindingState, CommitHash, CoveredRegion, IntentEntry,
Meta, Sha256, VerifiedOutcome,
};
fn sha(c: char) -> Sha256 {
Sha256::parse(&format!("sha256:{}", c.to_string().repeat(64))).unwrap()
}
fn intent(file: &str, verify: VerifyLevel, status: Status, server_bound: bool) -> IndexEntry {
IndexEntry::Intent(IntentEntry {
text: "x".into(),
verify,
status,
text_hash: sha('a'),
body_hash: sha('b'),
file: file.into(),
site: format!("fn x in {file}"),
covered_region: CoveredRegion::Function,
binding: if server_bound {
BindingState::Certified {
linked: ArtaId::parse("arta_op4q3z9NbV").unwrap(),
verified_outcome: VerifiedOutcome::parse(&format!("v1:{}", "A".repeat(86)))
.unwrap(),
last_verified_at_commit: CommitHash::parse(&"a".repeat(40)).unwrap(),
}
} else {
BindingState::Local
},
parent: None,
last_critiqued_at_text_hash: None,
last_critique_finding_count: None,
})
}
fn assume() -> IndexEntry {
IndexEntry::Assume(AssumeEntry {
text: "y".into(),
status: Status::Unknown,
text_hash: sha('a'),
body_hash: sha('b'),
file: "src/lib.rs".into(),
site: "fn y".into(),
covered_region: CoveredRegion::Function,
linked: None,
parent: None,
})
}
fn make_index(entries: Vec<(&str, IndexEntry)>) -> IndexFile {
let mut map = std::collections::BTreeMap::new();
for (id, e) in entries {
map.insert(AnnotationId::parse(id).unwrap(), e);
}
IndexFile {
meta: Meta {
schema_version: 1,
generated_by: None,
generated_at: None,
source_root: None,
},
entries: map,
}
}
fn fn_counts(pairs: &[(&str, u32)]) -> BTreeMap<PathBuf, u32> {
pairs.iter().map(|(p, n)| (PathBuf::from(p), *n)).collect()
}
#[test]
fn tier_labels_match_d1_scheme() {
assert_eq!(Tier::Aspirant.label(), "Aspirant");
assert_eq!(Tier::Apprentice.label(), "Apprentice");
assert_eq!(Tier::Adept.label(), "Adept");
assert_eq!(Tier::Ascendent.label(), "Ascendent");
assert_eq!(Tier::Arete.label(), "✦ Areté");
}
#[test]
fn tier_colors_match_d11_palette() {
assert_eq!(Tier::Adept.color_hex(), "#C0362C"); assert_eq!(Tier::Arete.color_hex(), "#d4a017");
let all = [
Tier::Aspirant.color_hex(),
Tier::Apprentice.color_hex(),
Tier::Adept.color_hex(),
Tier::Ascendent.color_hex(),
Tier::Arete.color_hex(),
];
for c in all {
assert!(c.starts_with('#'));
assert_eq!(c.len(), 7);
}
let unique: std::collections::HashSet<&str> = all.into_iter().collect();
assert_eq!(unique.len(), 5, "tier colors must be distinct");
}
#[test]
fn score_to_visible_tier_respects_d8_cutoffs() {
assert_eq!(score_to_visible_tier(0.00), Tier::Aspirant);
assert_eq!(score_to_visible_tier(0.099), Tier::Aspirant);
assert_eq!(score_to_visible_tier(0.10), Tier::Apprentice);
assert_eq!(score_to_visible_tier(0.349), Tier::Apprentice);
assert_eq!(score_to_visible_tier(0.35), Tier::Adept);
assert_eq!(score_to_visible_tier(0.649), Tier::Adept);
assert_eq!(score_to_visible_tier(0.65), Tier::Ascendent);
assert_eq!(score_to_visible_tier(1.0), Tier::Ascendent);
}
#[test]
fn empty_index_is_aspirant_with_zero_score() {
let r = compute_tier(&make_index(vec![]), &BTreeMap::new(), None);
assert_eq!(r.verifiable, 0);
assert_eq!(r.verification_ratio, 0.0);
assert_eq!(r.coverage_score, 0.0);
assert_eq!(r.articulation_floor, 0.0);
assert_eq!(r.visible_score, 0.0);
assert!(!r.arete_gate_met);
assert_eq!(r.tier, Tier::Aspirant);
}
#[test]
fn assumes_excluded_from_verifiable_count() {
let index = make_index(vec![
("a", assume()),
("b", assume()),
(
"c",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
),
]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert_eq!(r.verifiable, 1);
}
#[test]
fn verify_false_intents_excluded_entirely() {
let index = make_index(vec![
(
"a",
intent(
"src/lib.rs",
VerifyLevel::Bool(false),
Status::Unknown,
false,
),
),
(
"b",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
),
]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert_eq!(r.verifiable, 1);
assert!((r.verification_ratio - 0.6).abs() < 1e-9);
}
#[test]
fn articulation_floor_one_intent_gives_five_pct() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Bool(true),
Status::Unknown,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!((r.articulation_floor - 0.05).abs() < 1e-9);
assert_eq!(r.tier, Tier::Aspirant);
}
#[test]
fn articulation_floor_saturates_at_three_intents() {
let mut entries = Vec::new();
for i in 0..10 {
let id = format!("intent_{i}");
entries.push((
Box::leak(id.into_boxed_str()) as &str,
intent(
"src/lib.rs",
VerifyLevel::Bool(true),
Status::Unknown,
false,
),
));
}
let index = make_index(entries);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!((r.articulation_floor - 0.15).abs() < 1e-9);
assert_eq!(r.tier, Tier::Apprentice);
}
#[test]
fn full_verified_intent_contributes_one_point_oh() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Full),
Status::Verified,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!((r.verification_ratio - 1.0).abs() < 1e-9);
}
#[test]
fn test_verified_intent_contributes_zero_eight() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Test),
Status::Tested,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!((r.verification_ratio - 0.8).abs() < 1e-9);
}
#[test]
fn neural_verified_intent_contributes_zero_six() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!((r.verification_ratio - 0.6).abs() < 1e-9);
}
#[test]
fn non_clean_verified_status_contributes_zero() {
let dirty = [
Status::Unknown,
Status::Stale,
Status::Orphan,
Status::Forged,
Status::Counterexample,
Status::PendingDeepen,
Status::Inconclusive,
];
for s in dirty {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Full),
s,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert_eq!(
r.verification_ratio, 0.0,
"status {s:?} should contribute 0 to verification_ratio"
);
}
}
#[test]
fn verify_true_uses_default_method_for_weight() {
let index = make_index(vec![(
"a",
intent("src/lib.rs", VerifyLevel::Bool(true), Status::Tested, false),
)]);
let r = compute_tier(
&index,
&fn_counts(&[("src/lib.rs", 1)]),
Some(VerifyMethod::Test),
);
assert!((r.verification_ratio - 0.8).abs() < 1e-9);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert_eq!(r.verification_ratio, 0.0);
}
#[test]
fn coverage_score_zero_when_no_fn_modules() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 0)]), None);
assert_eq!(r.coverage_score, 0.0);
}
#[test]
fn coverage_score_saturates_at_local_target() {
let mut entries = Vec::new();
for i in 0..5 {
let id = format!("intent_{i}");
entries.push((
Box::leak(id.into_boxed_str()) as &str,
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
));
}
let r = compute_tier(&make_index(entries), &fn_counts(&[("src/lib.rs", 4)]), None);
assert!((r.coverage_score - 1.0).abs() < 1e-9);
}
#[test]
fn coverage_score_averages_per_module() {
let index = make_index(vec![
(
"a",
intent(
"src/a.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
),
(
"b",
intent(
"src/a.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
),
]);
let r = compute_tier(
&index,
&fn_counts(&[("src/a.rs", 4), ("src/b.rs", 4)]),
None,
);
assert!((r.coverage_score - 0.5).abs() < 1e-9);
}
#[test]
fn coverage_target_uses_ceiling_of_sqrt() {
let mut entries = Vec::new();
for i in 0..4 {
let id = format!("intent_{i}");
entries.push((
Box::leak(id.into_boxed_str()) as &str,
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
));
}
let r = compute_tier(
&make_index(entries),
&fn_counts(&[("src/lib.rs", 10)]),
None,
);
assert!((r.coverage_score - 1.0).abs() < 1e-9);
let mut entries = Vec::new();
for i in 0..3 {
let id = format!("intent_{i}");
entries.push((
Box::leak(id.into_boxed_str()) as &str,
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
));
}
let r = compute_tier(
&make_index(entries),
&fn_counts(&[("src/lib.rs", 10)]),
None,
);
assert!((r.coverage_score - 0.75).abs() < 1e-9);
}
#[test]
fn visible_score_takes_max_of_floor_and_product() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!((r.visible_score - 0.6).abs() < 1e-9);
assert_eq!(r.tier, Tier::Adept);
}
#[test]
fn visible_score_clamps_to_one() {
let index = make_index(vec![(
"a",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Full),
Status::Verified,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!(r.visible_score <= 1.0 + 1e-9);
assert!(r.visible_score >= 1.0 - 1e-9);
assert_eq!(r.tier, Tier::Ascendent);
}
#[test]
fn arete_gate_requires_full_verified_and_aristos_namespace() {
let index = make_index(vec![(
"aristos:foo",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Full),
Status::Verified,
true,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!(r.arete_gate_met);
assert_eq!(r.tier, Tier::Arete);
}
#[test]
fn arete_gate_local_namespace_does_not_unlock() {
let index = make_index(vec![(
"foo",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Full),
Status::Verified,
false,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!(!r.arete_gate_met);
assert_eq!(r.tier, Tier::Ascendent);
}
#[test]
fn arete_gate_non_full_method_does_not_unlock_even_with_namespace() {
let index = make_index(vec![(
"aristos:foo",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Neural),
Status::Neural,
true,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!(!r.arete_gate_met);
assert_eq!(r.tier, Tier::Adept); }
#[test]
fn arete_gate_non_verified_status_does_not_unlock() {
let index = make_index(vec![(
"aristos:foo",
intent(
"src/lib.rs",
VerifyLevel::Method(VerifyMethod::Full),
Status::Stale,
true,
),
)]);
let r = compute_tier(&index, &fn_counts(&[("src/lib.rs", 1)]), None);
assert!(!r.arete_gate_met);
assert_eq!(r.tier, Tier::Aspirant);
}
}