clawft_kernel/
lewm_invariant.rs1use serde::{Deserialize, Serialize};
14
15#[repr(u8)]
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18#[serde(rename_all = "snake_case")]
19pub enum DecouplingRule {
20 EccAuthoritative = 1,
22 WorldModelOptional = 2,
24 ImpulseOnlyWritePath = 3,
26 NoCausalShortCircuit = 4,
28 GracefulDegradation = 5,
30}
31
32impl DecouplingRule {
33 pub const ALL: &'static [DecouplingRule] = &[
34 Self::EccAuthoritative,
35 Self::WorldModelOptional,
36 Self::ImpulseOnlyWritePath,
37 Self::NoCausalShortCircuit,
38 Self::GracefulDegradation,
39 ];
40
41 pub const fn as_str(self) -> &'static str {
42 match self {
43 Self::EccAuthoritative => "ecc_authoritative",
44 Self::WorldModelOptional => "world_model_optional",
45 Self::ImpulseOnlyWritePath => "impulse_only_write_path",
46 Self::NoCausalShortCircuit => "no_causal_short_circuit",
47 Self::GracefulDegradation => "graceful_degradation",
48 }
49 }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub enum WmWriteKind {
56 Impulse,
58 Observation,
60 CausalEdgeMutate,
62 ReasoningOverride,
64 ShortCircuit,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70pub struct InvariantCheck {
71 pub rule: DecouplingRule,
72 pub ok: bool,
73 pub detail: String,
74}
75
76pub fn check_wm_write(kind: WmWriteKind) -> Result<(), InvariantCheck> {
78 match kind {
79 WmWriteKind::Impulse | WmWriteKind::Observation => Ok(()),
80 WmWriteKind::CausalEdgeMutate => Err(InvariantCheck {
81 rule: DecouplingRule::ImpulseOnlyWritePath,
82 ok: false,
83 detail: "world model must not mutate causal edges directly".into(),
84 }),
85 WmWriteKind::ReasoningOverride => Err(InvariantCheck {
86 rule: DecouplingRule::EccAuthoritative,
87 ok: false,
88 detail: "world model must not override ECC reasoning".into(),
89 }),
90 WmWriteKind::ShortCircuit => Err(InvariantCheck {
91 rule: DecouplingRule::NoCausalShortCircuit,
92 ok: false,
93 detail: "world model must not short-circuit causal edges".into(),
94 }),
95 }
96}
97
98pub fn local_ecc_sufficient_without_wm() -> bool {
100 true
101}
102
103#[derive(Debug, Default)]
105pub struct WorldModelFacade {
106 pub enforce: bool,
108 pub rejected: u64,
110 pub accepted: u64,
112}
113
114impl WorldModelFacade {
115 pub fn new(enforce: bool) -> Self {
116 Self {
117 enforce,
118 rejected: 0,
119 accepted: 0,
120 }
121 }
122
123 pub fn submit(&mut self, kind: WmWriteKind) -> Result<(), InvariantCheck> {
125 match check_wm_write(kind) {
126 Ok(()) => {
127 self.accepted += 1;
128 Ok(())
129 }
130 Err(e) => {
131 self.rejected += 1;
132 #[cfg(all(debug_assertions, not(test)))]
137 if self.enforce {
138 panic!(
139 "LeWM decoupling invariant violated: {:?} — {}",
140 e.rule, e.detail
141 );
142 }
143 let _ = self.enforce;
144 Err(e)
145 }
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn five_rules_enumerated() {
156 assert_eq!(DecouplingRule::ALL.len(), 5);
157 assert_eq!(DecouplingRule::EccAuthoritative as u8, 1);
158 assert_eq!(DecouplingRule::GracefulDegradation as u8, 5);
159 }
160
161 #[test]
162 fn allows_impulse_and_observation() {
163 assert!(check_wm_write(WmWriteKind::Impulse).is_ok());
164 assert!(check_wm_write(WmWriteKind::Observation).is_ok());
165 }
166
167 #[test]
168 fn rejects_short_circuit() {
169 let err = check_wm_write(WmWriteKind::ShortCircuit).unwrap_err();
170 assert_eq!(err.rule, DecouplingRule::NoCausalShortCircuit);
171 assert!(!err.ok);
172 }
173
174 #[test]
175 fn rejects_edge_mutate_and_override() {
176 assert_eq!(
177 check_wm_write(WmWriteKind::CausalEdgeMutate)
178 .unwrap_err()
179 .rule,
180 DecouplingRule::ImpulseOnlyWritePath
181 );
182 assert_eq!(
183 check_wm_write(WmWriteKind::ReasoningOverride)
184 .unwrap_err()
185 .rule,
186 DecouplingRule::EccAuthoritative
187 );
188 }
189
190 #[test]
191 fn facade_counts_rejections() {
192 let mut f = WorldModelFacade::new(true);
193 assert!(f.submit(WmWriteKind::Impulse).is_ok());
194 assert!(f.submit(WmWriteKind::ShortCircuit).is_err());
195 assert_eq!(f.accepted, 1);
196 assert_eq!(f.rejected, 1);
197 }
198
199 #[test]
200 fn property_forbidden_short_circuit_never_accepted() {
201 for enforce in [false, true] {
203 let mut f = WorldModelFacade::new(enforce);
204 assert!(f.submit(WmWriteKind::ShortCircuit).is_err());
205 }
206 }
207
208 #[test]
209 fn graceful_degradation_predicate() {
210 assert!(local_ecc_sufficient_without_wm());
211 }
212}