1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use stack_ids::{ConstraintId, KernelRunId, OperatorId, OracleSliceId, ScopeKey, SyndromeId};
4
5pub const CONSTRAINT_COMPILER_OPERATOR_ID: &str = "rik.constraint_compiler.v1";
6pub const RECURSIVE_MESSAGE_PASSING_OPERATOR_ID: &str = "rik.message_passing.v1";
7
8pub const CONSTRAINT_COMPILER_OPERATOR_NAME: &str = "constraint_compiler";
9pub const RECURSIVE_MESSAGE_PASSING_OPERATOR_NAME: &str = "recursive_message_passing";
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
12#[serde(rename_all = "snake_case")]
13pub enum ExactnessClass {
14 Exact,
15 Conservative,
16 Approximate,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
20#[serde(rename_all = "snake_case")]
21pub enum ConvergenceKind {
22 AcyclicSinglePass,
23 ResidualBounded,
24 FixedPoint,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
28#[serde(rename_all = "snake_case")]
29pub enum StopRule {
30 MaxIterations { limit: u32 },
31 ResidualBelow { micros: u64 },
32 AcyclicCompletion,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
36#[serde(rename_all = "snake_case")]
37pub enum DegradationBehavior {
38 Blocked,
39 AdvisoryOnly,
40 ConservativeFallback,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
44#[serde(rename_all = "snake_case")]
45pub enum ArtifactAuthorityClass {
46 NonAuthoritativeDerived,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
50pub struct OperatorContract {
51 pub inputs: Vec<String>,
52 pub outputs: Vec<String>,
53 pub exactness: ExactnessClass,
54 pub convergence: ConvergenceKind,
55 pub stop_rule: StopRule,
56 pub degradation: DegradationBehavior,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
60pub struct OperatorMetadata {
61 pub operator_id: OperatorId,
62 pub name: String,
63 pub contract: OperatorContract,
64}
65
66impl OperatorMetadata {
67 pub fn validate(&self) -> Result<(), String> {
69 if self.name.trim().is_empty() {
70 return Err("operator name must not be empty".into());
71 }
72 if self.contract.inputs.is_empty() {
73 return Err("operator inputs must not be empty".into());
74 }
75 if self.contract.outputs.is_empty() {
76 return Err("operator outputs must not be empty".into());
77 }
78 Ok(())
79 }
80}
81
82pub fn constraint_compiler_operator() -> OperatorMetadata {
84 OperatorMetadata {
85 operator_id: OperatorId::new(CONSTRAINT_COMPILER_OPERATOR_ID),
86 name: CONSTRAINT_COMPILER_OPERATOR_NAME.to_string(),
87 contract: OperatorContract {
88 inputs: vec!["projection_import_batch_v3".into()],
89 outputs: vec!["inference_graph".into()],
90 exactness: ExactnessClass::Exact,
91 convergence: ConvergenceKind::AcyclicSinglePass,
92 stop_rule: StopRule::AcyclicCompletion,
93 degradation: DegradationBehavior::AdvisoryOnly,
94 },
95 }
96}
97
98pub fn message_passing_operator() -> OperatorMetadata {
100 OperatorMetadata {
101 operator_id: OperatorId::new(RECURSIVE_MESSAGE_PASSING_OPERATOR_ID),
102 name: RECURSIVE_MESSAGE_PASSING_OPERATOR_NAME.to_string(),
103 contract: OperatorContract {
104 inputs: vec!["inference_graph".into()],
105 outputs: vec!["execution_report".into()],
106 exactness: ExactnessClass::Conservative,
107 convergence: ConvergenceKind::FixedPoint,
108 stop_rule: StopRule::ResidualBelow { micros: 1_000 },
109 degradation: DegradationBehavior::AdvisoryOnly,
110 },
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
115pub struct KernelRun {
116 pub run_id: KernelRunId,
117 pub policy_version: String,
118 pub scope_key: ScopeKey,
119 pub operator_ids: Vec<OperatorId>,
120 pub oracle_slice_id: Option<OracleSliceId>,
121 pub degradation_active: bool,
122}
123
124impl KernelRun {
125 pub fn authority_class(&self) -> ArtifactAuthorityClass {
127 ArtifactAuthorityClass::NonAuthoritativeDerived
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
132pub struct ConstraintUnit {
133 pub constraint_id: ConstraintId,
134 pub kind: String,
135 pub variable_ids: Vec<String>,
136 pub operator_id: OperatorId,
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
140pub struct Syndrome {
141 pub syndrome_id: SyndromeId,
142 pub signature: String,
143 pub blocked_by_degradation: bool,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
147#[serde(rename_all = "snake_case")]
148pub enum KernelArtifactKind {
149 Residual,
150 Syndrome,
151 Witness,
152 Certificate,
153 CalibrationReport,
154 KernelRefutationResult,
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
158pub struct ResidualArtifact {
159 pub constraint_id: ConstraintId,
160 pub residual_micros: u64,
161 pub monotone_nonincreasing: bool,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
165pub struct WitnessArtifact {
166 pub witness_id: String,
167 pub target_node_id: String,
168 pub supporting_constraint_ids: Vec<ConstraintId>,
169 pub belief_micros: u64,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
173pub struct CertificateArtifact {
174 pub certificate_id: String,
175 pub certified_node_id: String,
176 pub satisfied_constraint_ids: Vec<ConstraintId>,
177 pub oracle_slice_id: Option<OracleSliceId>,
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
181pub struct CalibrationReport {
182 pub nuisance_node_ids: Vec<String>,
183 pub caveats: Vec<String>,
184 pub blocked: bool,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
188#[serde(rename_all = "snake_case")]
189pub enum KernelRefutationOutcome {
190 FlipWitnessFound,
191 NoFlipFoundWithinBudget,
192 Unsupported,
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
196pub struct PerturbationWitness {
197 pub changed_node_ids: Vec<String>,
198 pub changed_constraint_ids: Vec<ConstraintId>,
199 pub budget_used: u32,
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
203pub struct KernelRefutationResult {
204 pub target_node_id: String,
205 pub outcome: KernelRefutationOutcome,
206 pub witness: Option<PerturbationWitness>,
207 pub notes: Vec<String>,
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn operator_contract_requires_inputs_outputs_and_stop_rule() {
216 let operator = constraint_compiler_operator();
217 assert_eq!(
218 operator.operator_id.as_str(),
219 CONSTRAINT_COMPILER_OPERATOR_ID
220 );
221 assert_eq!(operator.name, CONSTRAINT_COMPILER_OPERATOR_NAME);
222 assert_eq!(operator.contract.inputs, vec!["projection_import_batch_v3"]);
223 assert_eq!(operator.contract.outputs, vec!["inference_graph"]);
224 assert!(matches!(operator.contract.exactness, ExactnessClass::Exact));
225 operator.validate().unwrap();
226 }
227
228 #[test]
229 fn kernel_artifacts_remain_non_authoritative() {
230 let run = KernelRun {
231 run_id: KernelRunId::new("run-1"),
232 policy_version: "policy-1".into(),
233 scope_key: ScopeKey::namespace_only("ns"),
234 operator_ids: vec![OperatorId::new(CONSTRAINT_COMPILER_OPERATOR_ID)],
235 oracle_slice_id: None,
236 degradation_active: false,
237 };
238
239 assert_eq!(
240 run.authority_class(),
241 ArtifactAuthorityClass::NonAuthoritativeDerived
242 );
243 }
244
245 #[test]
246 fn shared_artifact_schemas_are_serializable() {
247 let witness = WitnessArtifact {
248 witness_id: "wit-1".into(),
249 target_node_id: "node-1".into(),
250 supporting_constraint_ids: vec![ConstraintId::new("constraint:1")],
251 belief_micros: 750_000,
252 };
253 let encoded = serde_json::to_string(&witness).unwrap();
254 assert!(encoded.contains("wit-1"));
255 }
256}