crtx-core 0.1.1

Core IDs, errors, and schema constants for Cortex.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
//! Semantic provenance and trust classification.
//!
//! Structural proof closure answers whether Cortex can verify a claim's
//! lineage and authority edges. Semantic trust answers a different question:
//! whether the claim is grounded enough to influence future reasoning. ADR
//! 0039 keeps these axes separate so proof, utility, and provenance cannot
//! silently upgrade one another.

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::{ClaimCeiling, PolicyContribution, PolicyError, PolicyOutcome};

/// Provenance family for a memory, principle support edge, or boundary claim.
#[derive(
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum ProvenanceClass {
    /// Provenance is missing, malformed, or not yet classified.
    UnknownProvenance,
    /// Produced by simulation, model inference, planning, or counterfactuals.
    SimulatedOrHypothetical,
    /// Claimed by an external source but not independently verified by Cortex.
    ExternalClaimed,
    /// Derived from summarization or interpretation over prior records.
    SummaryDerived,
    /// Derived from an agent or runtime execution record, including AXIOM.
    RuntimeDerived,
    /// Tool-backed observation with durable invocation provenance.
    ToolObserved,
    /// Direct operator-origin evidence with valid current-use attestation.
    OperatorAttested,
}

impl ProvenanceClass {
    /// Whether this provenance family is intrinsically derived rather than
    /// independently observed.
    #[must_use]
    pub const fn is_derived(self) -> bool {
        matches!(
            self,
            Self::RuntimeDerived | Self::SummaryDerived | Self::SimulatedOrHypothetical
        )
    }

    /// Whether this provenance family can contribute to independent semantic
    /// corroboration.
    #[must_use]
    pub const fn can_corroborate(self) -> bool {
        matches!(self, Self::ToolObserved | Self::OperatorAttested)
    }

    /// Maximum claim ceiling this provenance class can support by itself.
    ///
    /// Provenance is not proof or authority. Even strong provenance is capped
    /// by the separate proof, policy, and runtime ceilings elsewhere.
    #[must_use]
    pub const fn claim_ceiling(self) -> ClaimCeiling {
        match self {
            Self::UnknownProvenance | Self::SimulatedOrHypothetical => ClaimCeiling::DevOnly,
            Self::ExternalClaimed | Self::SummaryDerived | Self::RuntimeDerived => {
                ClaimCeiling::LocalUnsigned
            }
            Self::ToolObserved | Self::OperatorAttested => ClaimCeiling::AuthorityGrade,
        }
    }
}

/// Semantic trust posture for a claim after provenance review.
#[derive(
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum SemanticTrustClass {
    /// Trust posture is missing or cannot be computed.
    Unknown,
    /// The claim is retained only as an unverified candidate.
    CandidateOnly,
    /// The claim has one classified source family but lacks corroboration.
    SingleFamily,
    /// The claim has independent corroboration across acceptable families.
    Corroborated,
    /// The claim has corroboration plus explicit falsification/counterexample
    /// evidence appropriate to the requested use.
    FalsificationTested,
}

impl SemanticTrustClass {
    /// Maximum claim ceiling supported by semantic trust alone.
    #[must_use]
    pub const fn claim_ceiling(self) -> ClaimCeiling {
        match self {
            Self::Unknown => ClaimCeiling::DevOnly,
            Self::CandidateOnly | Self::SingleFamily => ClaimCeiling::LocalUnsigned,
            Self::Corroborated => ClaimCeiling::SignedLocalLedger,
            Self::FalsificationTested => ClaimCeiling::AuthorityGrade,
        }
    }
}

/// Authority surface that wants to consume semantic trust.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SemanticUse {
    /// Candidate memory or diagnostic review.
    CandidateMemory,
    /// Default retrieval or ordinary context use.
    DefaultContext,
    /// Advisory doctrine or weak principle support.
    AdvisoryDoctrine,
    /// High-force doctrine that can condition future behavior or gates.
    HighForceDoctrine,
    /// Trusted export, release, compliance, or external reporting surface.
    TrustedExternalUse,
}

/// Evidence available for semantic trust evaluation.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct SemanticTrustInput {
    /// Intended authority surface.
    pub intended_use: SemanticUse,
    /// Provenance classes represented by the supporting evidence.
    pub provenance_classes: Vec<ProvenanceClass>,
    /// Count of independent source families after deduplication by caller.
    pub independent_source_families: u16,
    /// Whether explicit falsification/counterexample review is attached.
    pub falsification_evidence: bool,
    /// Whether unresolved semantic unknowns remain.
    pub unresolved_unknowns: bool,
}

impl SemanticTrustInput {
    /// Construct input for one intended use.
    #[must_use]
    pub fn new(intended_use: SemanticUse) -> Self {
        Self {
            intended_use,
            provenance_classes: Vec::new(),
            independent_source_families: 0,
            falsification_evidence: false,
            unresolved_unknowns: true,
        }
    }

    /// Attach provenance classes.
    #[must_use]
    pub fn with_provenance<I>(mut self, provenance_classes: I) -> Self
    where
        I: IntoIterator<Item = ProvenanceClass>,
    {
        self.provenance_classes = provenance_classes.into_iter().collect();
        self
    }

    /// Attach caller-computed independent source-family count.
    #[must_use]
    pub const fn with_independent_source_families(mut self, count: u16) -> Self {
        self.independent_source_families = count;
        self
    }

    /// Attach falsification evidence state.
    #[must_use]
    pub const fn with_falsification_evidence(mut self, present: bool) -> Self {
        self.falsification_evidence = present;
        self
    }

    /// Attach unresolved semantic unknown state.
    #[must_use]
    pub const fn with_unresolved_unknowns(mut self, present: bool) -> Self {
        self.unresolved_unknowns = present;
        self
    }
}

/// Result of semantic trust evaluation.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct SemanticTrustReport {
    /// Computed semantic trust class.
    pub semantic_trust: SemanticTrustClass,
    /// Weakest provenance family present in the support set.
    pub weakest_provenance: ProvenanceClass,
    /// Policy outcome for the requested use.
    pub policy_outcome: PolicyOutcome,
    /// Maximum claim ceiling supported by semantic trust/provenance.
    pub claim_ceiling: ClaimCeiling,
    /// Stable reasons explaining downgrades or blocks.
    pub reasons: Vec<String>,
}

impl SemanticTrustReport {
    /// Whether this report permits the intended use without warning.
    #[must_use]
    pub const fn is_allow(&self) -> bool {
        matches!(self.policy_outcome, PolicyOutcome::Allow)
    }

    /// Convert this report to an ADR 0026 policy contribution.
    pub fn policy_contribution(&self) -> Result<PolicyContribution, PolicyError> {
        PolicyContribution::new(
            "semantic_trust.provenance",
            self.policy_outcome,
            self.reasons
                .first()
                .cloned()
                .unwrap_or_else(|| "semantic trust evaluated".to_string()),
        )
    }
}

/// Evaluate semantic trust for a requested use.
#[must_use]
pub fn evaluate_semantic_trust(input: &SemanticTrustInput) -> SemanticTrustReport {
    let weakest_provenance = input
        .provenance_classes
        .iter()
        .copied()
        .min()
        .unwrap_or(ProvenanceClass::UnknownProvenance);

    let has_unknown = input.provenance_classes.is_empty()
        || input.unresolved_unknowns
        || input
            .provenance_classes
            .contains(&ProvenanceClass::UnknownProvenance);
    let corroborating_families = input
        .provenance_classes
        .iter()
        .filter(|class| class.can_corroborate())
        .count() as u16;
    let runtime_or_weaker_only = !input.provenance_classes.is_empty()
        && input
            .provenance_classes
            .iter()
            .all(|class| !class.can_corroborate());

    let semantic_trust = if has_unknown {
        SemanticTrustClass::Unknown
    } else if input.falsification_evidence
        && input.independent_source_families >= 2
        && corroborating_families >= 1
    {
        SemanticTrustClass::FalsificationTested
    } else if input.independent_source_families >= 2 && corroborating_families >= 1 {
        SemanticTrustClass::Corroborated
    } else if !input.provenance_classes.is_empty() {
        SemanticTrustClass::SingleFamily
    } else {
        SemanticTrustClass::CandidateOnly
    };

    let mut reasons = Vec::new();
    let policy_outcome = match input.intended_use {
        SemanticUse::CandidateMemory => {
            if has_unknown {
                reasons.push("unknown provenance retained as candidate-only".to_string());
                PolicyOutcome::Warn
            } else {
                reasons
                    .push("candidate memory may retain classified semantic evidence".to_string());
                PolicyOutcome::Allow
            }
        }
        SemanticUse::DefaultContext | SemanticUse::AdvisoryDoctrine => {
            if has_unknown {
                reasons.push("unknown provenance cannot enter default authority use".to_string());
                PolicyOutcome::Quarantine
            } else if runtime_or_weaker_only {
                reasons.push(
                    "runtime-derived or weak-only provenance is advisory/candidate only"
                        .to_string(),
                );
                PolicyOutcome::Warn
            } else {
                reasons.push("semantic provenance permits bounded advisory use".to_string());
                PolicyOutcome::Allow
            }
        }
        SemanticUse::HighForceDoctrine | SemanticUse::TrustedExternalUse => {
            if has_unknown {
                reasons.push("unknown provenance cannot satisfy high-authority use".to_string());
                PolicyOutcome::Reject
            } else if runtime_or_weaker_only {
                reasons.push(
                    "runtime-only or weak-only support cannot satisfy high-authority use"
                        .to_string(),
                );
                PolicyOutcome::Reject
            } else if semantic_trust < SemanticTrustClass::FalsificationTested {
                reasons.push(
                    "high-authority use requires corroboration plus falsification evidence"
                        .to_string(),
                );
                PolicyOutcome::Reject
            } else {
                reasons.push(
                    "semantic trust permits high-authority use subject to other gates".to_string(),
                );
                PolicyOutcome::Allow
            }
        }
    };

    let claim_ceiling = weakest_provenance
        .claim_ceiling()
        .min(semantic_trust.claim_ceiling())
        .min(policy_outcome.claim_ceiling());

    SemanticTrustReport {
        semantic_trust,
        weakest_provenance,
        policy_outcome,
        claim_ceiling,
        reasons,
    }
}

#[cfg(test)]
mod tests {
    use serde_json::json;

    use super::*;

    #[test]
    fn provenance_wire_strings_are_stable() {
        assert_eq!(
            serde_json::to_value(ProvenanceClass::OperatorAttested).unwrap(),
            json!("operator_attested")
        );
        assert_eq!(
            serde_json::to_value(ProvenanceClass::ToolObserved).unwrap(),
            json!("tool_observed")
        );
        assert_eq!(
            serde_json::to_value(ProvenanceClass::RuntimeDerived).unwrap(),
            json!("runtime_derived")
        );
        assert_eq!(
            serde_json::to_value(ProvenanceClass::UnknownProvenance).unwrap(),
            json!("unknown_provenance")
        );
    }

    #[test]
    fn unknown_provenance_fails_closed_for_high_force_doctrine() {
        let report = evaluate_semantic_trust(
            &SemanticTrustInput::new(SemanticUse::HighForceDoctrine)
                .with_provenance([ProvenanceClass::UnknownProvenance])
                .with_independent_source_families(1)
                .with_unresolved_unknowns(true),
        );

        assert_eq!(report.semantic_trust, SemanticTrustClass::Unknown);
        assert_eq!(report.policy_outcome, PolicyOutcome::Reject);
        assert_eq!(report.claim_ceiling, ClaimCeiling::DevOnly);
    }

    #[test]
    fn runtime_only_support_cannot_promote_high_force_doctrine() {
        let report = evaluate_semantic_trust(
            &SemanticTrustInput::new(SemanticUse::HighForceDoctrine)
                .with_provenance([
                    ProvenanceClass::RuntimeDerived,
                    ProvenanceClass::SummaryDerived,
                ])
                .with_independent_source_families(2)
                .with_falsification_evidence(true)
                .with_unresolved_unknowns(false),
        );

        assert_eq!(report.policy_outcome, PolicyOutcome::Reject);
        assert_eq!(report.semantic_trust, SemanticTrustClass::SingleFamily);
        assert!(report
            .reasons
            .iter()
            .any(|reason| reason.contains("runtime-only")));
    }

    #[test]
    fn corroborated_and_falsified_support_can_pass_semantic_gate() {
        let report = evaluate_semantic_trust(
            &SemanticTrustInput::new(SemanticUse::HighForceDoctrine)
                .with_provenance([
                    ProvenanceClass::ToolObserved,
                    ProvenanceClass::OperatorAttested,
                ])
                .with_independent_source_families(2)
                .with_falsification_evidence(true)
                .with_unresolved_unknowns(false),
        );

        assert_eq!(
            report.semantic_trust,
            SemanticTrustClass::FalsificationTested
        );
        assert_eq!(report.policy_outcome, PolicyOutcome::Allow);
        assert_eq!(report.claim_ceiling, ClaimCeiling::AuthorityGrade);
    }

    #[test]
    fn policy_contribution_is_machine_readable() {
        let report = evaluate_semantic_trust(
            &SemanticTrustInput::new(SemanticUse::DefaultContext)
                .with_provenance([ProvenanceClass::RuntimeDerived])
                .with_independent_source_families(1)
                .with_unresolved_unknowns(false),
        );

        let contribution = report.policy_contribution().unwrap();
        assert_eq!(contribution.rule_id.as_str(), "semantic_trust.provenance");
        assert_eq!(contribution.outcome, PolicyOutcome::Warn);
    }
}