Skip to main content

lsp_max/runtime/rpc/
dispatch.rs

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}