Skip to main content

cuke_dedup/source_adapter/
finalization.rs

1//! Typed authority boundaries for frontend completion.
2
3use super::SourceLanguage;
4use crate::model::{SourceLocation, StepDefinition};
5use std::path::PathBuf;
6
7/// The broadest source authority affected by unresolved static evidence.
8#[non_exhaustive]
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum UncertaintyScope {
11    /// One handler or registration.
12    Definition(SourceLocation),
13    /// One source, only when frontend evidence proves its effects cannot escape.
14    File(PathBuf),
15    /// Every registration in a comparison domain; source-local syntax alone cannot narrow this.
16    Registry(SourceLanguage),
17}
18
19/// What authority cannot be established without executing project code.
20#[non_exhaustive]
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum UncertaintyCause {
23    /// Registration ownership or execution effects may change the registry.
24    Registration,
25    /// Handler values or execution effects cannot establish equivalence.
26    Handler,
27    /// Source or dependency evidence is missing, without proof of registration invalidation.
28    Source,
29}
30
31/// One conservative frontend limitation, independent of its diagnostic wording.
32#[non_exhaustive]
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct SourceUncertainty {
35    /// Authority affected by this limitation.
36    pub scope: UncertaintyScope,
37    /// Missing proof and its effect on comparisons.
38    pub cause: UncertaintyCause,
39    /// Human-readable diagnostic.
40    pub message: String,
41}
42
43impl SourceUncertainty {
44    /// Creates an explicitly scoped limitation; narrowing requires frontend isolation evidence.
45    pub fn new(
46        scope: UncertaintyScope,
47        cause: UncertaintyCause,
48        message: impl Into<String>,
49    ) -> Self {
50        Self {
51            scope,
52            cause,
53            message: message.into(),
54        }
55    }
56
57    fn affects(&self, definition: &StepDefinition) -> bool {
58        match &self.scope {
59            UncertaintyScope::Definition(location) => &definition.location == location,
60            UncertaintyScope::File(path) => &definition.location.path == path,
61            UncertaintyScope::Registry(language) => {
62                definition.analysis_profile().comparison_domain == language.comparison_domain()
63            }
64        }
65    }
66}
67
68/// Optional explanation of a frontend trust decision, without authority or completeness effects.
69#[non_exhaustive]
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct SourceAdvisory {
72    /// Source decision being explained.
73    pub location: SourceLocation,
74    /// Explanation for callers that opt into frontend diagnostics.
75    pub message: String,
76}
77
78impl SourceAdvisory {
79    /// Creates an advisory; use [`SourceUncertainty`] for unresolved analysis completeness.
80    pub fn new(location: SourceLocation, message: impl Into<String>) -> Self {
81        Self {
82            location,
83            message: message.into(),
84        }
85    }
86}
87
88/// Cross-source limitations collected after extraction, before shared analysis.
89#[non_exhaustive]
90#[derive(Debug, Clone, Default, PartialEq, Eq)]
91pub struct SourceFinalization {
92    /// Limitations remain incomplete even when independent definitions can be retained.
93    pub uncertainties: Vec<SourceUncertainty>,
94    /// Optional frontend advisories for embedders; applying finalization does not emit them.
95    /// Advisory diagnostics do not remove authority or affect completeness.
96    pub advisories: Vec<SourceAdvisory>,
97}
98
99impl SourceFinalization {
100    /// Applies only the authority removal declared by the frontend; uncertainty never grants trust.
101    pub fn apply(&self, definitions: &mut Vec<StepDefinition>) {
102        for uncertainty in &self.uncertainties {
103            match uncertainty.cause {
104                UncertaintyCause::Registration => {
105                    definitions.retain(|definition| !uncertainty.affects(definition))
106                }
107                UncertaintyCause::Handler => {
108                    for definition in definitions
109                        .iter_mut()
110                        .filter(|definition| uncertainty.affects(definition))
111                    {
112                        definition.handler.comparable = false;
113                    }
114                }
115                UncertaintyCause::Source => {}
116            }
117        }
118    }
119}