use antigen_fingerprint::{Constraint, Fingerprint};
use crate::finding::Provenance;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ToleranceVerdict {
Spared,
BindsCleanItem {
clean_index: Option<usize>,
},
NotCorpusWitnessable,
}
impl ToleranceVerdict {
#[must_use]
pub const fn is_safe(&self) -> bool {
matches!(self, Self::Spared)
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
pub struct PromotedDraft {
fingerprint: Fingerprint,
tier: Provenance,
}
impl PromotedDraft {
#[must_use]
pub const fn fingerprint(&self) -> &Fingerprint {
&self.fingerprint
}
#[must_use]
pub const fn tier(&self) -> Provenance {
self.tier
}
#[must_use]
pub fn into_fingerprint(self) -> Fingerprint {
self.fingerprint
}
}
impl AsRef<Fingerprint> for PromotedDraft {
fn as_ref(&self) -> &Fingerprint {
&self.fingerprint
}
}
#[must_use]
pub fn evaluate(draft: &Fingerprint, clean_corpus: &[syn::Item]) -> ToleranceVerdict {
for (i, item) in clean_corpus.iter().enumerate() {
if draft.matches(item) {
return ToleranceVerdict::BindsCleanItem {
clean_index: Some(i),
};
}
}
ToleranceVerdict::Spared
}
#[must_use]
pub fn spare_clean(draft: &Fingerprint, clean_corpus: &[syn::Item]) -> bool {
evaluate(draft, clean_corpus).is_safe()
}
fn normalized_top_level(draft: &Fingerprint) -> Vec<Constraint> {
let mut out = Vec::with_capacity(draft.constraints.len());
flatten_all_of_into(&draft.constraints, &mut out);
out
}
fn flatten_all_of_into(constraints: &[Constraint], out: &mut Vec<Constraint>) {
for c in constraints {
match c {
Constraint::AllOf(inner) => flatten_all_of_into(inner, out),
other => out.push(other.clone()),
}
}
}
#[must_use]
pub fn has_discriminating_conjunct(draft: &Fingerprint) -> bool {
normalized_top_level(draft).iter().any(is_discriminating)
}
const fn is_discriminating(c: &Constraint) -> bool {
match c {
Constraint::Item(_) | Constraint::ImplOfTrait(_) | Constraint::NameMatches(_) => false,
Constraint::Variants(_)
| Constraint::HasMethod(_)
| Constraint::AttrPresent(_)
| Constraint::DocContains(_)
| Constraint::BodyContainsMacro(_)
| Constraint::BodyCalls(_)
| Constraint::Qualifier(_)
| Constraint::Derives(_)
| Constraint::SerdeArg(_)
| Constraint::AllOf(_)
| Constraint::AnyOf(_)
| Constraint::Not(_) => true,
}
}
#[must_use]
pub fn is_near_miss(draft: &Fingerprint, item: &syn::Item) -> bool {
let conjuncts = normalized_top_level(draft);
if conjuncts.len() < 2 {
return false;
}
if draft.matches(item) {
return false;
}
(0..conjuncts.len()).any(|i| {
let mut cs = conjuncts.clone();
cs.remove(i);
let remainder = Fingerprint { constraints: cs };
remainder.matches(item) && has_discriminating_conjunct(&remainder)
})
}
#[must_use]
pub fn corpus_witnesses_draft(draft: &Fingerprint, corpus: &[syn::Item]) -> bool {
corpus.iter().any(|item| is_near_miss(draft, item))
}
pub fn promote_if_safe(
draft: Fingerprint,
clean_corpus: &[syn::Item],
) -> Result<PromotedDraft, ToleranceVerdict> {
if clean_corpus.is_empty() {
return Err(ToleranceVerdict::BindsCleanItem { clean_index: None });
}
if !has_discriminating_conjunct(&draft) {
return Err(ToleranceVerdict::BindsCleanItem { clean_index: None });
}
if !corpus_witnesses_draft(&draft, clean_corpus) {
return Err(ToleranceVerdict::NotCorpusWitnessable);
}
match evaluate(&draft, clean_corpus) {
ToleranceVerdict::Spared => Ok(PromotedDraft {
fingerprint: draft,
tier: Provenance::DEFAULT,
}),
verdict @ ToleranceVerdict::BindsCleanItem { .. } => Err(verdict),
ToleranceVerdict::NotCorpusWitnessable => Err(ToleranceVerdict::NotCorpusWitnessable),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn drop_family() -> Vec<syn::Item> {
let src = r#"
pub struct GuardA;
impl Drop for GuardA {
fn drop(&mut self) { let _ = flush().take().unwrap(); }
}
pub struct GuardB;
impl Drop for GuardB {
fn drop(&mut self) { let _ = flush().take().expect("must"); }
}
pub struct CleanGuard;
impl Drop for CleanGuard {
fn drop(&mut self) { let _ = flush().take().ok(); }
}
"#;
syn::parse_file(src).expect("parses").items
}
fn impl_drop_for(items: &[syn::Item], ty: &str) -> syn::Item {
items
.iter()
.find(|it| {
let syn::Item::Impl(i) = it else { return false };
let Some((_, tp, _)) = &i.trait_ else {
return false;
};
let is_drop = tp.segments.last().is_some_and(|s| s.ident == "Drop");
let syn::Type::Path(p) = &*i.self_ty else {
return false;
};
let on = p.path.segments.last().is_some_and(|s| s.ident == ty);
is_drop && on
})
.expect("found")
.clone()
}
fn flat(src: &str) -> Fingerprint {
let parsed = Fingerprint::parse(src).unwrap();
match parsed.constraints.as_slice() {
[Constraint::AllOf(inner)] => Fingerprint {
constraints: inner.clone(),
},
_ => parsed,
}
}
fn naive_draft() -> Fingerprint {
flat(r#"all_of([item = impl, impl_of_trait("Drop")])"#)
}
fn disjunction_draft() -> Fingerprint {
flat(
r#"all_of([item = impl, impl_of_trait("Drop"), body_calls("take"), any_of([body_calls("unwrap"), body_calls("expect")])])"#,
)
}
#[test]
fn rejects_the_naive_autoimmune_draft() {
let items = drop_family();
let clean = vec![impl_drop_for(&items, "CleanGuard")];
let v = evaluate(&naive_draft(), &clean);
assert_eq!(
v,
ToleranceVerdict::BindsCleanItem {
clean_index: Some(0)
}
);
assert!(!v.is_safe());
assert!(!spare_clean(&naive_draft(), &clean));
assert_eq!(
promote_if_safe(naive_draft(), &clean),
Err(ToleranceVerdict::BindsCleanItem { clean_index: None })
);
}
#[test]
fn accepts_the_disjunction_draft() {
let items = drop_family();
let clean = vec![impl_drop_for(&items, "CleanGuard")];
let v = evaluate(&disjunction_draft(), &clean);
assert_eq!(v, ToleranceVerdict::Spared);
assert!(v.is_safe());
assert!(spare_clean(&disjunction_draft(), &clean));
let promoted = promote_if_safe(disjunction_draft(), &clean).expect("near-miss-witnessed");
assert_eq!(promoted.fingerprint(), &disjunction_draft());
assert_eq!(promoted.tier(), Provenance::DEFAULT);
}
#[test]
fn empty_corpus_spare_clean_predicate_is_vacuously_true() {
assert!(spare_clean(&naive_draft(), &[]));
}
#[test]
fn promote_if_safe_refuses_an_empty_corpus_the_gate_g_hazard() {
assert!(promote_if_safe(naive_draft(), &[]).is_err());
assert!(promote_if_safe(disjunction_draft(), &[]).is_err());
}
#[test]
fn rejects_when_any_clean_item_binds_not_just_the_first() {
let items = drop_family();
let nonbinding: syn::Item = syn::parse_quote! { pub struct NotEvenADrop; };
let clean = vec![nonbinding, impl_drop_for(&items, "CleanGuard")];
assert_eq!(
evaluate(&naive_draft(), &clean),
ToleranceVerdict::BindsCleanItem {
clean_index: Some(1)
}
);
}
#[test]
fn single_conjunct_draft_is_not_near_miss_via_empty_drop() {
let single = Fingerprint {
constraints: vec![Constraint::BodyCalls("unwrap".into())],
};
let clean: syn::Item = syn::parse_str("fn clean() { let _ = ok(); }").unwrap();
assert!(
!is_near_miss(&single, &clean),
"a single-conjunct draft has no valid near-miss (len < 2 guard, ATK-047-N4)"
);
assert_eq!(
promote_if_safe(single, std::slice::from_ref(&clean)),
Err(ToleranceVerdict::NotCorpusWitnessable)
);
}
#[test]
fn bare_structural_draft_rejected_as_autoimmune() {
let items = drop_family();
let clean = vec![impl_drop_for(&items, "CleanGuard")];
assert!(
!has_discriminating_conjunct(&naive_draft()),
"the bare-structural draft carries no discriminating conjunct"
);
assert_eq!(
promote_if_safe(naive_draft(), &clean),
Err(ToleranceVerdict::BindsCleanItem { clean_index: None }),
"bare-structural over-general → (A)-binary refusal"
);
}
#[test]
fn twins_collapsed_draft_is_near_miss_witnessed_and_spares_clean() {
let twins_draft = flat(
r#"all_of([item = impl, impl_of_trait("Drop"), body_calls("flush"), body_calls("unwrap")])"#,
);
let clean: syn::Item =
syn::parse_str("impl Drop for Clean { fn drop(&mut self) { let _ = flush().ok(); } }")
.unwrap();
assert!(
is_near_miss(&twins_draft, &clean),
"the .ok() sibling is one constraint (unwrap) from binding → near-miss"
);
let promoted = promote_if_safe(twins_draft, std::slice::from_ref(&clean));
assert!(
promoted.is_ok(),
"a precise near-miss-witnessed spare-clean draft is SAFE → promotes"
);
}
#[test]
fn single_discriminator_draft_routes_to_human() {
let single_disc =
flat(r#"all_of([item = impl, impl_of_trait("Drop"), body_calls("unwrap")])"#);
let bare: syn::Item =
syn::parse_str("impl Drop for Far { fn drop(&mut self) { log(); } }").unwrap();
assert!(has_discriminating_conjunct(&single_disc));
assert!(
!is_near_miss(&single_disc, &bare),
"dropping the SOLE discriminator leaves a bare-structural remainder → not a \
near-miss (ATK-047-1 trivial-skeleton vacuity, Amd2-closed)"
);
assert_eq!(
promote_if_safe(single_disc, std::slice::from_ref(&bare)),
Err(ToleranceVerdict::NotCorpusWitnessable),
"a single-discriminator draft routes-to-human, never silently promotes"
);
}
#[test]
fn precise_no_disjunction_draft_with_two_discriminators_promotes() {
let precise = flat(
r#"all_of([item = impl, impl_of_trait("Drop"), body_calls("flush"), body_calls("unwrap")])"#,
);
let clean: syn::Item =
syn::parse_str("impl Drop for Clean { fn drop(&mut self) { let _ = flush().ok(); } }")
.unwrap();
assert!(has_discriminating_conjunct(&precise));
assert!(
is_near_miss(&precise, &clean),
"the .ok() sibling matches [impl, Drop, flush] and fails only unwrap → near-miss"
);
assert!(
promote_if_safe(precise, std::slice::from_ref(&clean)).is_ok(),
"a precise ≥2-discriminator draft with a real near-miss must promote"
);
}
#[test]
fn near_miss_verdict_invariant_to_corpus_item_class() {
let draft = disjunction_draft();
let a_struct: syn::Item = syn::parse_str("struct JustAStruct;").unwrap();
assert!(
!is_near_miss(&draft, &a_struct),
"a struct cannot witness an impl-shaped draft (no Undefined-collapse spurious witness)"
);
assert_eq!(
promote_if_safe(draft, std::slice::from_ref(&a_struct)),
Err(ToleranceVerdict::NotCorpusWitnessable)
);
}
#[test]
fn near_miss_promotes_the_good_drop_family() {
let items = drop_family();
let clean = vec![impl_drop_for(&items, "CleanGuard")];
assert!(
corpus_witnesses_draft(&disjunction_draft(), &clean),
"the good family's CleanGuard is a near-miss"
);
assert!(promote_if_safe(disjunction_draft(), &clean).is_ok());
}
#[test]
fn promote_if_safe_returns_promoted_draft_not_fingerprint() {
let items = drop_family();
let clean = vec![impl_drop_for(&items, "CleanGuard")];
let promoted: PromotedDraft =
promote_if_safe(disjunction_draft(), &clean).expect("promotes");
let fp: &Fingerprint = promoted.fingerprint();
assert_eq!(fp, &disjunction_draft());
assert_eq!(promoted.as_ref(), &disjunction_draft());
}
#[test]
fn into_fingerprint_downgrades_capability() {
let items = drop_family();
let clean = vec![impl_drop_for(&items, "CleanGuard")];
let promoted = promote_if_safe(disjunction_draft(), &clean).expect("promotes");
let downgraded: Fingerprint = promoted.into_fingerprint();
assert_eq!(downgraded, disjunction_draft());
assert!(promote_if_safe(downgraded, &clean).is_ok());
}
}