use super::*;
use crate::models::{Finding, FindingCategory, VerifyOutcome};
use crate::pipeline::letter_grade::Grade;
fn finding(effort: Effort, confidence: f32) -> Finding {
Finding::new("src/lib.rs", "test", "desc", "", confidence, effort)
}
fn conformance_finding(effort: Effort, confidence: f32) -> Finding {
finding(effort, confidence).with_category(FindingCategory::MethodConformance)
}
fn verified_finding(effort: Effort, confidence: f32, outcome: VerifyOutcome) -> Finding {
let mut f = finding(effort, confidence);
f.verified = Some(outcome);
f
}
#[test]
fn grade_critical_high_effort_yields_block() {
let findings = vec![finding(Effort::High, 0.9)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Block,
"High-effort finding must floor to BLOCK"
);
}
#[test]
fn grade_high_effort_beats_request_changes() {
let findings = vec![finding(Effort::High, 0.85)];
let verdict = derive_verdict(Verdict::RequestChanges, &findings);
assert_eq!(verdict, Verdict::Block);
}
#[test]
fn grade_two_medium_yields_request_changes() {
let findings = vec![finding(Effort::Medium, 0.85), finding(Effort::Medium, 0.82)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_three_medium_yields_request_changes() {
let findings = vec![
finding(Effort::Medium, 0.85),
finding(Effort::Medium, 0.85),
finding(Effort::Medium, 0.85),
];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_model_approve_caps_medium_count_floor_at_approve_star() {
let findings = vec![
finding(Effort::Medium, 0.85),
finding(Effort::Medium, 0.85),
finding(Effort::Medium, 0.85),
];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::ApproveWithReservations,
"model APPROVE must cap the Medium-count floor at APPROVE* (#1343)"
);
}
#[test]
fn grade_one_medium_yields_approve_star() {
let findings = vec![finding(Effort::Medium, 0.85)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::ApproveWithReservations);
}
#[test]
fn grade_no_findings_yields_approve() {
let verdict = derive_verdict(Verdict::Approve, &[]);
assert_eq!(verdict, Verdict::Approve);
}
#[test]
fn grade_only_low_yields_approve() {
let findings = vec![finding(Effort::Low, 0.9), finding(Effort::Low, 0.7)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::Approve);
}
#[test]
fn grade_unknown_is_preserved() {
let findings = vec![finding(Effort::Low, 0.9)];
let verdict = derive_verdict(Verdict::Unknown, &findings);
assert_eq!(verdict, Verdict::Unknown, "UNKNOWN must be preserved");
}
#[test]
fn grade_unknown_preserved_with_no_findings() {
let verdict = derive_verdict(Verdict::Unknown, &[]);
assert_eq!(verdict, Verdict::Unknown);
}
#[test]
fn grade_floor_overrides_model_approve() {
let findings = vec![finding(Effort::High, 0.95)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Block,
"severity floor must override model-proposed APPROVE"
);
}
#[test]
fn grade_model_block_kept_when_no_critical_finding() {
let findings = vec![finding(Effort::Medium, 0.9)];
let verdict = derive_verdict(Verdict::Block, &findings);
assert_eq!(
verdict,
Verdict::Block,
"model BLOCK must not be downgraded by floor"
);
}
#[test]
fn grade_model_request_changes_preserved_over_lower_floor() {
let findings = vec![finding(Effort::Low, 0.9)];
let verdict = derive_verdict(Verdict::RequestChanges, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_low_confidence_all_medium_yields_approve() {
let findings = vec![finding(Effort::Medium, 0.6), finding(Effort::Medium, 0.55)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"all-low-confidence advisory batch must not fire APPROVE*"
);
}
#[test]
fn grade_confidence_at_threshold_collapses() {
let findings = vec![finding(Effort::Medium, 0.65)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"confidence at threshold must collapse"
);
}
#[test]
fn grade_high_confidence_medium_beats_low_confidence_check() {
let findings = vec![finding(Effort::Medium, 0.66)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::Approve);
}
#[test]
fn grade_mixed_confidence_two_medium_only_one_counts() {
let findings = vec![finding(Effort::Medium, 0.85), finding(Effort::Medium, 0.5)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::ApproveWithReservations);
}
#[test]
fn grade_compile_break_high_effort_flows_to_block() {
let findings = vec![finding(Effort::High, 0.95)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Block,
"compile-break (High effort) must escalate to BLOCK"
);
}
#[test]
fn derive_verdict_with_grade_grade_a_no_findings_approve() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::A, &[]);
assert_eq!(v, Verdict::Approve);
assert_eq!(g, Grade::A);
}
#[test]
fn derive_verdict_with_grade_grade_f_no_findings_block() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::F, &[]);
assert_eq!(v, Verdict::Block);
assert_eq!(g, Grade::F);
}
#[test]
fn derive_verdict_with_grade_severity_overrides_grade_a() {
let findings = vec![finding(Effort::High, 0.9)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::A, &findings);
assert_eq!(v, Verdict::Block, "severity floor must override grade A");
assert_eq!(g, Grade::F, "grade must be clamped to F when verdict=BLOCK");
}
#[test]
fn derive_verdict_with_grade_b_minus_yields_approve() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BMinus, &[]);
assert_eq!(v, Verdict::Approve);
assert_eq!(g, Grade::BMinus);
}
#[test]
fn derive_verdict_with_grade_c_plus_yields_approve_star() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::CPlus, &[]);
assert_eq!(v, Verdict::ApproveWithReservations);
assert_eq!(g, Grade::CPlus);
}
#[test]
fn derive_verdict_with_grade_c_minus_yields_approve_star() {
let (v, _g) = derive_verdict_with_grade(Verdict::Approve, Grade::CMinus, &[]);
assert_eq!(v, Verdict::ApproveWithReservations);
}
#[test]
fn derive_verdict_with_grade_d_plus_yields_request_changes() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::DPlus, &[]);
assert_eq!(v, Verdict::RequestChanges);
assert_eq!(g, Grade::DPlus);
}
#[test]
fn derive_verdict_with_grade_d_minus_yields_request_changes() {
let (v, _g) = derive_verdict_with_grade(Verdict::Approve, Grade::DMinus, &[]);
assert_eq!(v, Verdict::RequestChanges);
}
#[test]
fn derive_verdict_with_grade_model_escalates_above_grade() {
let (v, g) = derive_verdict_with_grade(Verdict::ApproveWithReservations, Grade::A, &[]);
assert_eq!(v, Verdict::ApproveWithReservations);
assert_eq!(g, Grade::CPlus);
}
#[test]
fn derive_verdict_with_grade_floor_stricter_than_grade() {
let findings = vec![finding(Effort::Medium, 0.85), finding(Effort::Medium, 0.85)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::CMinus, &findings);
assert_eq!(v, Verdict::RequestChanges);
assert_eq!(
g,
Grade::DPlus,
"grade must clamp to D+ (ceiling of REQUEST_CHANGES)"
);
}
#[test]
fn grade_approve_b_plus_two_medium_advisory_stays_approve() {
let findings = vec![finding(Effort::Medium, 0.70), finding(Effort::Medium, 0.70)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BPlus, &findings);
assert_eq!(
v,
Verdict::Approve,
"advisory Medium@0.70 must not escalate APPROVE/B+ to REQUEST_CHANGES (#1015)"
);
assert_eq!(g, Grade::BPlus);
}
#[test]
fn grade_advisory_medium_below_floor_threshold_does_not_escalate() {
let findings = vec![
finding(Effort::Medium, 0.70),
finding(Effort::Medium, 0.72),
finding(Effort::Medium, 0.75),
];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"Medium findings below FLOOR_MIN_CONFIDENCE must not force REQUEST_CHANGES"
);
}
#[test]
fn grade_high_confidence_medium_above_floor_threshold_escalates() {
let findings = vec![finding(Effort::Medium, 0.85), finding(Effort::Medium, 0.85)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::RequestChanges,
"Medium findings above FLOOR_MIN_CONFIDENCE must still trigger REQUEST_CHANGES \
when the model did not give a clean APPROVE"
);
}
#[test]
fn floor_excludes_refuted_and_low_confidence_findings() {
let findings = vec![
verified_finding(Effort::High, 0.10, VerifyOutcome::Refuted),
finding(Effort::Medium, 0.10),
];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"refuted + sub-0.50-confidence findings must not harden the verdict (#1343)"
);
}
#[test]
fn approve_b_plus_survives_refuted_and_low_confidence_findings() {
let findings = vec![
verified_finding(Effort::High, 0.10, VerifyOutcome::Refuted),
finding(Effort::Medium, 0.10),
finding(Effort::Low, 0.30),
];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BPlus, &findings);
assert_eq!(
v,
Verdict::Approve,
"APPROVE review_body must not surface structured REQUEST_CHANGES (#1343)"
);
assert_eq!(
g,
Grade::BPlus,
"B+ grade must not be clamped down to D+ (#1343 footer/grade consistency)"
);
}
#[test]
fn approve_b_plus_two_high_conf_medium_caps_at_approve_star() {
let findings = vec![finding(Effort::Medium, 0.85), finding(Effort::Medium, 0.85)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BPlus, &findings);
assert_eq!(
v,
Verdict::ApproveWithReservations,
"clean APPROVE must cap the Medium-count floor at APPROVE* (#1343)"
);
assert_eq!(
g,
Grade::CPlus,
"grade clamps to C+ (APPROVE* ceiling), never D+ (#1343)"
);
}
#[test]
fn model_request_changes_review_body_still_surfaces_request_changes() {
let (v, g) = derive_verdict_with_grade(Verdict::RequestChanges, Grade::DPlus, &[]);
assert_eq!(
v,
Verdict::RequestChanges,
"a genuine REQUEST_CHANGES review_body must still surface REQUEST_CHANGES (#1343)"
);
assert_eq!(g, Grade::DPlus);
}
#[test]
fn high_effort_finding_still_overrides_approve() {
let findings = vec![finding(Effort::High, 0.95)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BPlus, &findings);
assert_eq!(
v,
Verdict::Block,
"a substantive High-effort finding must still BLOCK an APPROVE (#1343)"
);
assert_eq!(g, Grade::F);
}
#[test]
fn low_confidence_high_effort_finding_still_drives_floor() {
let findings = vec![finding(Effort::High, 0.45)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Block,
"a non-refuted High-effort finding below 0.50 confidence must still BLOCK (PR #1350)"
);
}
#[test]
fn low_confidence_high_effort_clamps_grade_to_block() {
let findings = vec![finding(Effort::High, 0.40)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BPlus, &findings);
assert_eq!(
v,
Verdict::Block,
"uncertain critical (High@0.40) must still BLOCK through the grade pipeline (PR #1350)"
);
assert_eq!(g, Grade::F, "grade must clamp to F when verdict=BLOCK");
}
#[test]
fn refuted_high_effort_finding_is_still_excluded() {
let findings = vec![verified_finding(Effort::High, 0.95, VerifyOutcome::Refuted)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"a REFUTED High-effort finding must not harden the verdict, even high-confidence (PR #1350)"
);
}
#[test]
fn is_high_severity_matches_high_effort() {
assert!(is_high_severity(&finding(Effort::High, 0.5)));
assert!(!is_high_severity(&finding(Effort::Medium, 0.5)));
assert!(!is_high_severity(&finding(Effort::Low, 0.5)));
let high_low_conf = vec![finding(Effort::High, 0.30)];
assert_eq!(
derive_verdict(Verdict::Approve, &high_low_conf),
Verdict::Block,
"a low-confidence high-severity finding must still drive the BLOCK floor"
);
let medium_low_conf = vec![finding(Effort::Medium, 0.30)];
assert_eq!(
derive_verdict(Verdict::Approve, &medium_low_conf),
Verdict::Approve,
"a low-confidence Medium is NOT high-severity and must not escalate"
);
}
#[test]
fn grade_confirmed_high_still_blocks_despite_b_plus_grade() {
let findings = vec![finding(Effort::High, 0.90)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BPlus, &findings);
assert_eq!(
v,
Verdict::Block,
"High-effort finding must still BLOCK regardless of grade (#1015 regression)"
);
assert_eq!(g, Grade::F, "grade must clamp to F when verdict=BLOCK");
}
#[test]
fn conformance_finding_caps_at_request_changes() {
let findings = vec![conformance_finding(Effort::Medium, 0.90)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::RequestChanges,
"a confident conformance divergence must floor to REQUEST_CHANGES (AC-8)"
);
}
#[test]
fn conformance_high_effort_never_blocks() {
let findings = vec![conformance_finding(Effort::High, 0.95)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::RequestChanges,
"conformance must cap at REQUEST_CHANGES and NEVER drive BLOCK (AC-8)"
);
assert_ne!(verdict, Verdict::Block, "conformance must never BLOCK");
}
#[test]
fn conformance_below_floor_confidence_is_advisory() {
let findings = vec![conformance_finding(Effort::Medium, 0.75)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"a sub-0.80 conformance finding is advisory only and must not raise the floor (AC-12)"
);
}
#[test]
fn conformance_low_confidence_high_effort_never_blocks() {
let findings = vec![conformance_finding(Effort::High, 0.60)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_ne!(
verdict,
Verdict::Block,
"a conformance finding must never BLOCK regardless of effort/confidence (AC-8/AC-12)"
);
}
#[test]
fn conformance_absent_leaves_verdict_unchanged() {
let findings = vec![finding(Effort::Low, 0.95)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"no conformance finding → unchanged (AC-9)"
);
}
#[test]
fn conformance_never_blocks_via_grade_entry_point() {
let findings = vec![conformance_finding(Effort::High, 0.90)];
let (v, _g) = derive_verdict_with_grade(Verdict::Approve, Grade::B, &findings);
assert_eq!(
v,
Verdict::RequestChanges,
"conformance caps at REQUEST_CHANGES"
);
assert_ne!(v, Verdict::Block, "conformance never BLOCKs (AC-8)");
}
#[test]
fn conformance_cap_does_not_weaken_correctness_block() {
let findings = vec![
finding(Effort::High, 0.90),
conformance_finding(Effort::Medium, 0.90),
];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Block,
"a real correctness High finding still BLOCKs alongside a conformance finding"
);
}