qualia_core_db/solvers/ontology_align/correspondence.rs
1//! Ontology-alignment result types + the human-ratification guardrail.
2//!
3//! **Hard invariant (identity / out-of-band remainder):** this engine *proposes*
4//! correspondences with a degree; it can emit `CloseMatch` routed to
5//! `RequiresHumanReview`, and is **structurally forbidden** from asserting
6//! `ExactMatch`. `exactMatch` requires signed human ratification — the machine
7//! proposes, the human disposes. The type system enforces it: there is no
8//! constructor here that yields an asserted exact match.
9
10/// The status a *machine-proposed* correspondence may carry. Note the deliberate
11/// absence of an "asserted ExactMatch" — that state is reachable only through the
12/// human-ratification layer, never from an alignment solver.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ProposedStatus {
15 /// A graded `skos:closeMatch` proposal awaiting human ratification.
16 CloseMatch,
17}
18
19/// One proposed correspondence between a source entity and a target entity.
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct Correspondence {
22 pub source: usize,
23 pub target: usize,
24 /// Match degree in `[0,1]` (the fuzzy `closeMatch` strength).
25 pub degree: f64,
26 pub status: ProposedStatus,
27 /// Always `true`: a proposed correspondence MUST be human-reviewed before it can
28 /// become an `exactMatch`. There is no path here that sets this `false`.
29 pub requires_human_review: bool,
30}
31
32impl Correspondence {
33 /// The only constructor — a close-match *proposal*. By construction it is never
34 /// an asserted exact match and always requires human review.
35 pub fn propose(source: usize, target: usize, degree: f64) -> Self {
36 Self {
37 source,
38 target,
39 degree: degree.clamp(0.0, 1.0),
40 status: ProposedStatus::CloseMatch,
41 requires_human_review: true,
42 }
43 }
44}
45
46/// A full alignment: the proposed correspondences plus the total quality earned.
47#[derive(Debug, Clone, PartialEq)]
48pub struct Alignment {
49 pub correspondences: Vec<Correspondence>,
50 pub quality: f64,
51}
52
53impl Alignment {
54 /// Every correspondence is a review-required close-match proposal (the invariant).
55 pub fn all_require_review(&self) -> bool {
56 self.correspondences
57 .iter()
58 .all(|c| c.requires_human_review && c.status == ProposedStatus::CloseMatch)
59 }
60}