Skip to main content

aidens_contracts/
semantic.rs

1//! Semantic exactness, view disclosure, and degradation records.
2//!
3//! These local envelopes label AiDENs reports. They do not replace canonical
4//! memory, runtime view, or degradation truth systems.
5
6use super::*;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
9#[serde(rename_all = "kebab-case")]
10pub enum SemanticExactnessV1 {
11    Exact,
12    Degraded,
13    Partial,
14    Refuted,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
18pub struct SemanticStateV1 {
19    pub state_id: ArtifactId,
20    pub artifact_ref: ArtifactId,
21    pub provenance_carrier: String,
22    pub truth_carrier: String,
23    pub bitemporal_carrier: String,
24    pub identity_carrier: String,
25    pub execution_carrier: String,
26    pub view_carrier: String,
27    pub exactness: SemanticExactnessV1,
28    pub proof_carrier: String,
29    pub nuisance_or_degradation_carrier: String,
30    pub governance_carrier: String,
31    #[serde(default, skip_serializing_if = "Vec::is_empty")]
32    pub degradation_record_ids: Vec<ArtifactId>,
33    #[serde(default, skip_serializing_if = "Vec::is_empty")]
34    pub view_disclosure_ids: Vec<ArtifactId>,
35    #[serde(default, skip_serializing_if = "Vec::is_empty")]
36    pub contradiction_record_ids: Vec<ArtifactId>,
37    #[serde(default, skip_serializing_if = "Vec::is_empty")]
38    pub execution_contamination_ids: Vec<ArtifactId>,
39    #[serde(default, skip_serializing_if = "Vec::is_empty")]
40    pub reason_codes: Vec<String>,
41}
42
43impl SemanticStateV1 {
44    pub fn exact_supported(artifact_ref: ArtifactId, proof_carrier: impl Into<String>) -> Self {
45        Self {
46            state_id: generated_artifact_id_from_material("semantic-state", &artifact_ref.0),
47            artifact_ref,
48            provenance_carrier: "declared-input-manifest".into(),
49            truth_carrier: "canonical-owner-or-admitted-facade".into(),
50            bitemporal_carrier: "recorded-time-declared".into(),
51            identity_carrier: "stack-id-or-local-artifact-ref".into(),
52            execution_carrier: "execution-context-envelope".into(),
53            view_carrier: "view-disclosure-required".into(),
54            exactness: SemanticExactnessV1::Exact,
55            proof_carrier: proof_carrier.into(),
56            nuisance_or_degradation_carrier: "none".into(),
57            governance_carrier: "no-waiver".into(),
58            degradation_record_ids: Vec::new(),
59            view_disclosure_ids: Vec::new(),
60            contradiction_record_ids: Vec::new(),
61            execution_contamination_ids: Vec::new(),
62            reason_codes: vec!["semantic-state-exact".into()],
63        }
64    }
65
66    pub fn with_degradation(mut self, degradation: &LocalDegradationRecordV1) -> Self {
67        self.exactness = SemanticExactnessV1::Degraded;
68        self.nuisance_or_degradation_carrier = degradation.reason_code.clone();
69        self.degradation_record_ids
70            .push(degradation.degradation_id.clone());
71        self.reason_codes.push("semantic-state-degraded".into());
72        self.reason_codes.sort();
73        self.reason_codes.dedup();
74        self
75    }
76
77    pub fn with_view_disclosure(mut self, disclosure: &ViewDisclosureV1) -> Self {
78        self.view_disclosure_ids
79            .push(disclosure.disclosure_id.clone());
80        self.reason_codes
81            .push("semantic-state-view-disclosed".into());
82        self.reason_codes.sort();
83        self.reason_codes.dedup();
84        self
85    }
86
87    pub fn with_contradiction(mut self, contradiction: &SemanticContradictionRecordV1) -> Self {
88        self.exactness = SemanticExactnessV1::Refuted;
89        self.truth_carrier = "contradiction-disclosed".into();
90        self.contradiction_record_ids
91            .push(contradiction.contradiction_id.clone());
92        self.reason_codes
93            .push("semantic-state-contradiction-disclosed".into());
94        self.reason_codes.sort();
95        self.reason_codes.dedup();
96        self
97    }
98
99    pub fn with_execution_contamination(
100        mut self,
101        contamination: &ExecutionContaminationRecordV1,
102    ) -> Self {
103        self.exactness = SemanticExactnessV1::Degraded;
104        self.execution_carrier = contamination.reason_code.clone();
105        self.execution_contamination_ids
106            .push(contamination.contamination_id.clone());
107        self.reason_codes
108            .push("semantic-state-execution-contamination-disclosed".into());
109        self.reason_codes.sort();
110        self.reason_codes.dedup();
111        self
112    }
113
114    pub fn can_answer_as_exact(&self) -> bool {
115        self.exactness == SemanticExactnessV1::Exact
116            && self.degradation_record_ids.is_empty()
117            && self.contradiction_record_ids.is_empty()
118            && self.execution_contamination_ids.is_empty()
119    }
120
121    pub fn blocks_promotion(&self) -> bool {
122        !self.can_answer_as_exact()
123            || !self.contradiction_record_ids.is_empty()
124            || !self.execution_contamination_ids.is_empty()
125    }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
129pub struct SemanticContradictionRecordV1 {
130    pub contradiction_id: ArtifactId,
131    pub artifact_ref: ArtifactId,
132    #[serde(default, skip_serializing_if = "Vec::is_empty")]
133    pub witness_ids: Vec<ArtifactId>,
134    pub reason_code: String,
135    pub exactness_after: SemanticExactnessV1,
136    pub promotion_blocking: bool,
137    #[serde(default, skip_serializing_if = "Vec::is_empty")]
138    pub canonical_backpointers: Vec<CanonicalBackpointerV1>,
139    pub recorded_at: DateTime<Utc>,
140}
141
142impl SemanticContradictionRecordV1 {
143    pub fn new(
144        artifact_ref: ArtifactId,
145        witness_ids: Vec<ArtifactId>,
146        reason_code: impl Into<String>,
147    ) -> Self {
148        let reason_code = reason_code.into();
149        let material = format!(
150            "{}|{}|{}",
151            artifact_ref.0,
152            witness_ids
153                .iter()
154                .map(|id| id.0.clone())
155                .collect::<Vec<_>>()
156                .join("|"),
157            reason_code
158        );
159        Self {
160            contradiction_id: generated_artifact_id_from_material(
161                "semantic-contradiction",
162                &material,
163            ),
164            artifact_ref,
165            witness_ids,
166            reason_code,
167            exactness_after: SemanticExactnessV1::Refuted,
168            promotion_blocking: true,
169            canonical_backpointers: canonical_owner_backpointer(
170                "verification-adjudication",
171                "VerificationDisposition",
172                "canonical-contradiction-adjudication-owner",
173            ),
174            recorded_at: Utc::now(),
175        }
176    }
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
180pub struct ExecutionContaminationRecordV1 {
181    pub contamination_id: ArtifactId,
182    pub artifact_ref: ArtifactId,
183    pub execution_context_ref: ArtifactId,
184    pub reason_code: String,
185    pub domain_truth_contaminated: bool,
186    pub exactness_after: SemanticExactnessV1,
187    #[serde(default, skip_serializing_if = "Vec::is_empty")]
188    pub canonical_backpointers: Vec<CanonicalBackpointerV1>,
189    pub recorded_at: DateTime<Utc>,
190}
191
192impl ExecutionContaminationRecordV1 {
193    pub fn new(
194        artifact_ref: ArtifactId,
195        execution_context_ref: ArtifactId,
196        reason_code: impl Into<String>,
197    ) -> Self {
198        let reason_code = reason_code.into();
199        Self {
200            contamination_id: generated_artifact_id_from_material(
201                "execution-contamination",
202                &format!(
203                    "{}|{}|{}",
204                    artifact_ref.0, execution_context_ref.0, reason_code
205                ),
206            ),
207            artifact_ref,
208            execution_context_ref,
209            reason_code,
210            domain_truth_contaminated: true,
211            exactness_after: SemanticExactnessV1::Degraded,
212            canonical_backpointers: canonical_owner_backpointer(
213                "llm-tool-runtime",
214                "ExecutionContext",
215                "canonical-execution-context-owner",
216            ),
217            recorded_at: Utc::now(),
218        }
219    }
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
223pub struct ViewDisclosureV1 {
224    pub disclosure_id: ArtifactId,
225    pub view_family: String,
226    pub widening: bool,
227    pub support_label: String,
228    pub exactness: SemanticExactnessV1,
229    pub source_report_id: Option<ArtifactId>,
230    #[serde(default, skip_serializing_if = "Vec::is_empty")]
231    pub reason_codes: Vec<String>,
232    pub recorded_at: DateTime<Utc>,
233}
234
235impl ViewDisclosureV1 {
236    pub fn widening(
237        view_family: impl Into<String>,
238        support_label: impl Into<String>,
239        source_report_id: Option<ArtifactId>,
240    ) -> Self {
241        let view_family = view_family.into();
242        let support_label = support_label.into();
243        Self {
244            disclosure_id: generated_artifact_id_from_material(
245                "view-disclosure",
246                &format!("{view_family}|{support_label}|widening"),
247            ),
248            view_family,
249            widening: true,
250            support_label,
251            exactness: SemanticExactnessV1::Degraded,
252            source_report_id,
253            reason_codes: vec!["view-widening-disclosed".into()],
254            recorded_at: Utc::now(),
255        }
256    }
257}
258
259#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
260pub struct LocalDegradationRecordV1 {
261    pub degradation_id: ArtifactId,
262    pub artifact_ref: ArtifactId,
263    pub reason_code: String,
264    pub guarantee_weakened: String,
265    pub exactness_after: SemanticExactnessV1,
266    pub waived: bool,
267    #[serde(default, skip_serializing_if = "Vec::is_empty")]
268    pub reason_codes: Vec<String>,
269    pub recorded_at: DateTime<Utc>,
270}
271
272impl LocalDegradationRecordV1 {
273    pub fn new(
274        artifact_ref: ArtifactId,
275        reason_code: impl Into<String>,
276        guarantee_weakened: impl Into<String>,
277    ) -> Self {
278        let reason_code = reason_code.into();
279        let guarantee_weakened = guarantee_weakened.into();
280        Self {
281            degradation_id: generated_artifact_id_from_material(
282                "degradation-record",
283                &format!("{}|{}|{}", artifact_ref.0, reason_code, guarantee_weakened),
284            ),
285            artifact_ref,
286            reason_code,
287            guarantee_weakened,
288            exactness_after: SemanticExactnessV1::Degraded,
289            waived: false,
290            reason_codes: vec!["degradation-record-emitted".into()],
291            recorded_at: Utc::now(),
292        }
293    }
294
295    pub fn blocks_readiness_without_waiver(&self) -> bool {
296        !self.waived && self.exactness_after != SemanticExactnessV1::Exact
297    }
298}