1use crate::runtime::mesh::{build_conformance_vector, AutonomicMesh};
2use crate::runtime::mesh_types::{InstanceId, MaxMethod, MeshAction};
3use crate::runtime::sha256::sha256;
4use crate::runtime::typestate::DeterministicSnapshot;
5
6impl AutonomicMesh {
7 pub fn dispatch_rpc(
8 &mut self,
9 instance_id: &str,
10 method: &str,
11 params: serde_json::Value,
12 ) -> Result<serde_json::Value, String> {
13 if !self.instances.contains_key(instance_id) {
14 return Err(format!("Instance {} not found", instance_id));
15 }
16
17 let max_method = MaxMethod::try_from(method)
18 .map_err(|_| format!("Method {} not supported on local RPC surface", method))?;
19
20 match max_method {
21 MaxMethod::VerifyLedger => {
22 self.verify_instance_ledger(instance_id)?;
23 Ok(serde_json::Value::Null)
24 }
25 MaxMethod::LedgerReport => {
26 let report = self.get_ledger_diagnostic_report(instance_id);
27 Ok(serde_json::Value::String(report))
28 }
29 MaxMethod::Snapshot => {
30 let snap = DeterministicSnapshot::new();
31 serde_json::to_value(snap.id).map_err(|e| e.to_string())
32 }
33 MaxMethod::ConformanceVector => {
34 let instance = self
35 .instances
36 .get(instance_id)
37 .ok_or_else(|| format!("Instance not found: {}", instance_id))?;
38
39 let vec = build_conformance_vector(&instance.diagnostics);
40 serde_json::to_value(vec).map_err(|e| e.to_string())
41 }
42 MaxMethod::ClearDiagnostic => {
43 let diag_id: String =
44 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
45
46 self.execute_action(MeshAction::ClearDiagnostic {
47 instance_id: InstanceId::from(instance_id),
48 diagnostic_id: diag_id,
49 });
50 Ok(serde_json::Value::Null)
51 }
52 MaxMethod::ExplainDiagnostic => {
53 let diag_id: String =
54 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
55 let inst = self
56 .instances
57 .get(instance_id)
58 .ok_or_else(|| format!("Instance not found: {}", instance_id))?;
59 let diag = inst
60 .diagnostics
61 .iter()
62 .find(|d| d.diagnostic_id == diag_id)
63 .ok_or_else(|| format!("Diagnostic not found: {}", diag_id))?;
64 serde_json::to_value(diag.clone()).map_err(|e| e.to_string())
65 }
66 MaxMethod::RepairPlan => self.handle_repair_plan(instance_id, params),
67 MaxMethod::ApplyRepairTransaction => {
68 let code_action: lsp_max_protocol::MaxCodeAction =
69 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
70 self.apply_repair_transaction(instance_id, code_action)
71 }
72 MaxMethod::ExportAnalysisBundle => self.handle_export_bundle(instance_id, params),
73 MaxMethod::RunGate => {
74 let gate_str: String =
75 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
76 let inst = self
77 .instances
78 .get(instance_id)
79 .ok_or_else(|| format!("Instance not found: {}", instance_id))?;
80 let gate_blocked = inst
81 .diagnostics
82 .iter()
83 .any(|d| d.verification_gates.iter().any(|g| g.0 == gate_str));
84 serde_json::to_value(!gate_blocked).map_err(|e| e.to_string())
85 }
86 MaxMethod::Receipt => {
87 let receipt_id: String =
88 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
89 let inst = self
90 .instances
91 .get(instance_id)
92 .ok_or_else(|| format!("Instance not found: {}", instance_id))?;
93 let receipt = inst
94 .receipts
95 .iter()
96 .find(|r| r.receipt_id == receipt_id)
97 .ok_or_else(|| format!("Receipt not found: {}", receipt_id))?;
98 serde_json::to_value(receipt.clone()).map_err(|e| e.to_string())
99 }
100 MaxMethod::Hook => {
101 let hook_names: Vec<serde_json::Value> = self
102 .hooks
103 .iter()
104 .map(|h| serde_json::json!({ "name": h.name() }))
105 .collect();
106 serde_json::to_value(hook_names).map_err(|e| e.to_string())
107 }
108 MaxMethod::HookGraph => self.handle_hook_graph(instance_id),
109 MaxMethod::Chain => self.handle_chain(),
110 MaxMethod::Propagate => {
111 let receipt: lsp_max_protocol::Receipt =
112 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
113 self.execute_action(MeshAction::EmitReceipt {
114 instance_id: InstanceId::from(instance_id),
115 receipt,
116 });
117 Ok(serde_json::json!({ "propagated": true }))
118 }
119 MaxMethod::AutonomicLoop => {
120 let status = serde_json::json!({
121 "instances": self.instances.keys().collect::<Vec<_>>(),
122 "hook_count": self.hooks.len(),
123 "event_log_size": self.event_log.len(),
124 "executed_actions": self.executed_bounded_actions.len(),
125 });
126 Ok(status)
127 }
128 MaxMethod::ManifoldSnapshot => {
129 let snapshot = serde_json::json!({
130 "instances": self.instances.iter().map(|(id, inst)| {
131 serde_json::json!({
132 "id": id,
133 "phase": inst.phase,
134 "policy_state": inst.policy_state,
135 "diagnostic_count": inst.diagnostics.len(),
136 "receipt_count": inst.receipts.len(),
137 "conformance_score": inst.conformance_score(),
138 "conformance_grade": inst.conformance_grade().as_str(),
139 })
140 }).collect::<Vec<_>>(),
141 "hook_count": self.hooks.len(),
142 "event_log_size": self.event_log.len(),
143 });
144 Ok(snapshot)
145 }
146 MaxMethod::LawfulTransition => self.handle_lawful_transition(instance_id, params),
147 MaxMethod::Admission => {
148 let inst = self
149 .instances
150 .get(instance_id)
151 .ok_or_else(|| format!("Instance not found: {}", instance_id))?;
152 let verdict = if inst.diagnostics.is_empty() {
153 "Admitted"
154 } else if inst.diagnostics.iter().any(|d| {
155 matches!(
156 d.lsp.severity,
157 Some(lsp_types_max::DiagnosticSeverity::ERROR)
158 )
159 }) {
160 "Refused"
161 } else {
162 "Unknown"
163 };
164 Ok(serde_json::json!({
165 "instance_id": instance_id,
166 "verdict": verdict,
167 "diagnostic_count": inst.diagnostics.len(),
168 }))
169 }
170 MaxMethod::Refusal => {
171 let diag_id: String =
172 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
173 let receipt_id = format!("rcpt-refusal-{}", diag_id);
174 let hash = sha256(receipt_id.as_bytes());
175 let receipt = lsp_max_protocol::Receipt {
176 receipt_id: receipt_id.clone(),
177 hash,
178 prev_receipt_hash: None,
179 };
180 self.execute_action(MeshAction::EmitReceipt {
181 instance_id: InstanceId::from(instance_id),
182 receipt: receipt.clone(),
183 });
184 Ok(serde_json::json!({
185 "refused": true,
186 "diagnostic_id": diag_id,
187 "receipt": receipt,
188 }))
189 }
190 MaxMethod::Replay => self.handle_replay(instance_id),
191 MaxMethod::ReleaseActuation => self.handle_release_actuation(instance_id),
192 MaxMethod::InstanceList => {
193 let mut list: Vec<serde_json::Value> = self
194 .instances
195 .values()
196 .map(|inst| {
197 serde_json::json!({
198 "id": inst.id,
199 "phase": inst.phase,
200 "conformance_score": inst.conformance_score(),
201 "conformance_grade": inst.conformance_grade().as_str(),
202 })
203 })
204 .collect();
205 list.sort_by_key(|v| v["id"].as_str().unwrap_or("").to_string());
206 serde_json::to_value(list).map_err(|e| e.to_string())
207 }
208 MaxMethod::DumpState => {
209 let state = self.to_state();
210 serde_json::to_value(&state).map_err(|e| format!("Serialization failed: {}", e))
211 }
212 MaxMethod::RestoreState => {
213 let state: crate::runtime::mesh_types::AutonomicMeshState =
214 serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
215 self.load_state(state);
216 Ok(serde_json::Value::Null)
217 }
218 MaxMethod::Reset => {
219 self.execute_action(MeshAction::ResetInstance {
220 instance_id: InstanceId::from(instance_id),
221 });
222 Ok(serde_json::json!({
223 "reset": true,
224 "instance_id": instance_id,
225 }))
226 }
227 MaxMethod::ConformanceDelta => {
228 let since_seq: u64 = params
229 .as_object()
230 .and_then(|o| o.get("since_seq"))
231 .and_then(|v| v.as_u64())
232 .unwrap_or(0);
233 let deltas: Vec<&crate::runtime::mesh_types::ConformanceDeltaEntry> = self
234 .conformance_delta_log
235 .iter()
236 .filter(|e| e.seq > since_seq)
237 .collect();
238 Ok(serde_json::json!({
239 "deltas": deltas,
240 "current_seq": self.action_seq,
241 }))
242 }
243 }
244 }
245
246 pub fn apply_repair_transaction(
247 &mut self,
248 instance_id: &str,
249 code_action: lsp_max_protocol::MaxCodeAction,
250 ) -> Result<serde_json::Value, String> {
251 {
252 let inst = self
253 .instances
254 .get(instance_id)
255 .ok_or_else(|| format!("Instance not found: {}", instance_id))?;
256 let existing: std::collections::HashSet<&str> = inst
257 .receipts
258 .iter()
259 .map(|r| r.receipt_id.as_str())
260 .collect();
261 for expected in &code_action.receipt_plan.expected_receipts {
262 if !existing.contains(expected.as_str()) {
263 return Err(format!(
264 "Receipt integrity violation: required receipt '{}' not found",
265 expected
266 ));
267 }
268 }
269 }
270 let action_id = format!("repair-{}", code_action.action.title.replace(' ', "-"));
271 let receipt_id = format!("rcpt-repair-{}", code_action.action.title.replace(' ', "-"));
272 let hash = sha256(receipt_id.as_bytes());
273 let receipt = lsp_max_protocol::Receipt {
274 receipt_id: receipt_id.clone(),
275 hash,
276 prev_receipt_hash: None,
277 };
278 self.execute_action(MeshAction::ExecuteBoundedAction {
279 instance_id: InstanceId::from(instance_id),
280 action_id,
281 description: code_action.action.title.clone(),
282 });
283 self.execute_action(MeshAction::EmitReceipt {
284 instance_id: InstanceId::from(instance_id),
285 receipt: receipt.clone(),
286 });
287 serde_json::to_value(receipt).map_err(|e| e.to_string())
288 }
289}