1use sim_kernel::Symbol;
8
9use crate::{SourceConformanceCase, SourceConformanceCaseKind, SourceExpectation};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum EvidenceLane {
14 Input,
16 Value,
18 Failure,
20 Event,
22 Receipt,
24 Browse,
26 Conformance,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub struct EvidenceLaneInventory {
33 pub lane: EvidenceLane,
35 pub owner: &'static str,
37 pub canonical_projection: &'static str,
39}
40
41pub const EVIDENCE_LANE_INVENTORY: &[EvidenceLaneInventory] = &[
47 EvidenceLaneInventory {
48 lane: EvidenceLane::Input,
49 owner: "sim-lib-standard-core scenario contract",
50 canonical_projection: "ordered declared input Datum records",
51 },
52 EvidenceLaneInventory {
53 lane: EvidenceLane::Value,
54 owner: "sim-kernel Value and DatumStore",
55 canonical_projection: "canonical Datum or named profile projection",
56 },
57 EvidenceLaneInventory {
58 lane: EvidenceLane::Failure,
59 owner: "sim-kernel Error, Diagnostic, and Origin",
60 canonical_projection: "stable failure class, detail, and source location",
61 },
62 EvidenceLaneInventory {
63 lane: EvidenceLane::Event,
64 owner: "sim-kernel Event and EventLedger",
65 canonical_projection: "ordered typed event records",
66 },
67 EvidenceLaneInventory {
68 lane: EvidenceLane::Receipt,
69 owner: "the operation or library defining each typed receipt",
70 canonical_projection: "ordered receipt identity and semantic fields",
71 },
72 EvidenceLaneInventory {
73 lane: EvidenceLane::Browse,
74 owner: "sim-kernel Card projection",
75 canonical_projection: "ordered Card fields projected to Datum",
76 },
77 EvidenceLaneInventory {
78 lane: EvidenceLane::Conformance,
79 owner: "sim-lib-standard-core ConformanceHarness, ProfileDiff, and FidelityBadge",
80 canonical_projection: "content-addressed test-run Datum and typed profile evidence",
81 },
82];
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub struct ExplicitProjectionField {
88 pub field: &'static str,
90 pub required_projection: &'static str,
92}
93
94pub const EXPLICIT_PROJECTION_FIELDS: &[ExplicitProjectionField] = &[
96 ExplicitProjectionField {
97 field: "Debug or Display rendering",
98 required_projection: "project the typed value or record to canonical Datum",
99 },
100 ExplicitProjectionField {
101 field: "wall-clock time and elapsed duration",
102 required_projection: "omit, or replace with a named deterministic semantic field",
103 },
104 ExplicitProjectionField {
105 field: "random seed and nondeterministic identifiers",
106 required_projection: "declare the seed or map ids through a stable ordered projection",
107 },
108 ExplicitProjectionField {
109 field: "host paths, process state, and environment",
110 required_projection: "replace with scenario-declared logical identities",
111 },
112 ExplicitProjectionField {
113 field: "unordered host collections",
114 required_projection: "project with an explicit semantic ordering",
115 },
116];
117
118pub fn characterization_source_fixtures() -> [SourceConformanceCase; 2] {
124 [
125 SourceConformanceCase {
126 symbol: Symbol::qualified("characterize", "lowering-parity"),
127 organ: Symbol::qualified("standard", "lowering"),
128 source_name: "lowering-parity.sim".to_owned(),
129 source: "answer".to_owned(),
130 kind: SourceConformanceCaseKind::Observed,
131 expectation: SourceExpectation::LowersTo("answer".to_owned()),
132 affects_badge: None,
133 },
134 SourceConformanceCase {
135 symbol: Symbol::qualified("characterize", "declared-gap-parity"),
136 organ: Symbol::qualified("standard", "unsupported"),
137 source_name: "declared-gap-parity.sim".to_owned(),
138 source: "ambient-clock".to_owned(),
139 kind: SourceConformanceCaseKind::Observed,
140 expectation: SourceExpectation::ExpectedGap {
141 code: Symbol::qualified("characterize", "ambient-input"),
142 reason: "ambient time is not a declared scenario input".to_owned(),
143 },
144 affects_badge: None,
145 },
146 ]
147}
148
149#[cfg(test)]
150mod tests {
151 use std::{collections::BTreeSet, sync::Arc};
152
153 use super::*;
154 use crate::{MatrixRunner, SourceObservation};
155 use sim_kernel::{Cx, DefaultFactory, NoopEvalPolicy};
156
157 #[test]
158 fn inventory_has_one_semantic_owner_and_projection_per_lane() {
159 let mut lanes = BTreeSet::new();
160 for entry in EVIDENCE_LANE_INVENTORY {
161 assert!(
162 lanes.insert(entry.lane as u8),
163 "duplicate lane: {:?}",
164 entry.lane
165 );
166 assert!(!entry.owner.is_empty());
167 assert!(!entry.canonical_projection.is_empty());
168 assert!(!entry.canonical_projection.contains("Debug"));
169 assert!(!entry.canonical_projection.contains("debug"));
170 }
171 assert_eq!(lanes.len(), 7);
172 }
173
174 #[test]
175 fn unstable_fields_all_require_explicit_projection() {
176 assert!(
177 EXPLICIT_PROJECTION_FIELDS
178 .iter()
179 .any(|field| field.field.contains("Debug"))
180 );
181 for field in EXPLICIT_PROJECTION_FIELDS {
182 assert!(!field.required_projection.is_empty());
183 }
184 }
185
186 #[test]
187 fn frozen_source_fixtures_preserve_pass_and_gap_matrix_behavior() {
188 let [pass, gap] = characterization_source_fixtures();
189 let profile = crate::LanguageProfile::new(Symbol::qualified("characterize", "profile"));
190 let row = crate::LanguageRowBuilder::new(Symbol::new("characterize"), profile)
191 .with_cases([pass, gap])
192 .build();
193 let mut cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
194 let report = MatrixRunner::run_source_row(&mut cx, &row, |_cx, case| {
195 Ok(match &case.expectation {
196 SourceExpectation::LowersTo(value) => SourceObservation::LowersTo(value.clone()),
197 SourceExpectation::ExpectedGap { code, reason } => SourceObservation::Gap {
198 code: code.clone(),
199 reason: reason.clone(),
200 },
201 })
202 });
203
204 assert_eq!(report.pass_count(), 1);
205 assert_eq!(report.gap_count(), 1);
206 assert_eq!(report.fail_count(), 0);
207 }
208}