use crate::runtime::mesh::{build_conformance_vector, AutonomicMesh};
use crate::runtime::mesh_types::{InstanceId, MaxMethod, MeshAction};
use crate::runtime::sha256::sha256;
use crate::runtime::typestate::DeterministicSnapshot;
impl AutonomicMesh {
pub fn dispatch_rpc(
&mut self,
instance_id: &str,
method: &str,
params: serde_json::Value,
) -> Result<serde_json::Value, String> {
if !self.instances.contains_key(instance_id) {
return Err(format!("Instance {} not found", instance_id));
}
let max_method = MaxMethod::try_from(method)
.map_err(|_| format!("Method {} not supported on local RPC surface", method))?;
match max_method {
MaxMethod::VerifyLedger => {
self.verify_instance_ledger(instance_id)?;
Ok(serde_json::Value::Null)
}
MaxMethod::LedgerReport => {
let report = self.get_ledger_diagnostic_report(instance_id);
Ok(serde_json::Value::String(report))
}
MaxMethod::Snapshot => {
let snap = DeterministicSnapshot::new();
serde_json::to_value(snap.id).map_err(|e| e.to_string())
}
MaxMethod::ConformanceVector => {
let instance = self
.instances
.get(instance_id)
.ok_or_else(|| format!("Instance not found: {}", instance_id))?;
let vec = build_conformance_vector(&instance.diagnostics);
serde_json::to_value(vec).map_err(|e| e.to_string())
}
MaxMethod::ClearDiagnostic => {
let diag_id: String =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
self.execute_action(MeshAction::ClearDiagnostic {
instance_id: InstanceId::from(instance_id),
diagnostic_id: diag_id,
});
Ok(serde_json::Value::Null)
}
MaxMethod::ExplainDiagnostic => {
let diag_id: String =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
let inst = self
.instances
.get(instance_id)
.ok_or_else(|| format!("Instance not found: {}", instance_id))?;
let diag = inst
.diagnostics
.iter()
.find(|d| d.diagnostic_id == diag_id)
.ok_or_else(|| format!("Diagnostic not found: {}", diag_id))?;
serde_json::to_value(diag.clone()).map_err(|e| e.to_string())
}
MaxMethod::RepairPlan => self.handle_repair_plan(instance_id, params),
MaxMethod::ApplyRepairTransaction => {
let code_action: lsp_max_protocol::MaxCodeAction =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
self.apply_repair_transaction(instance_id, code_action)
}
MaxMethod::ExportAnalysisBundle => self.handle_export_bundle(instance_id, params),
MaxMethod::RunGate => {
let gate_str: String =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
let inst = self
.instances
.get(instance_id)
.ok_or_else(|| format!("Instance not found: {}", instance_id))?;
let gate_blocked = inst
.diagnostics
.iter()
.any(|d| d.verification_gates.iter().any(|g| g.0 == gate_str));
serde_json::to_value(!gate_blocked).map_err(|e| e.to_string())
}
MaxMethod::Receipt => {
let receipt_id: String =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
let inst = self
.instances
.get(instance_id)
.ok_or_else(|| format!("Instance not found: {}", instance_id))?;
let receipt = inst
.receipts
.iter()
.find(|r| r.receipt_id == receipt_id)
.ok_or_else(|| format!("Receipt not found: {}", receipt_id))?;
serde_json::to_value(receipt.clone()).map_err(|e| e.to_string())
}
MaxMethod::Hook => {
let hook_names: Vec<serde_json::Value> = self
.hooks
.iter()
.map(|h| serde_json::json!({ "name": h.name() }))
.collect();
serde_json::to_value(hook_names).map_err(|e| e.to_string())
}
MaxMethod::HookGraph => self.handle_hook_graph(instance_id),
MaxMethod::Chain => self.handle_chain(),
MaxMethod::Propagate => {
let receipt: lsp_max_protocol::Receipt =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
self.execute_action(MeshAction::EmitReceipt {
instance_id: InstanceId::from(instance_id),
receipt,
});
Ok(serde_json::json!({ "propagated": true }))
}
MaxMethod::AutonomicLoop => {
let status = serde_json::json!({
"instances": self.instances.keys().collect::<Vec<_>>(),
"hook_count": self.hooks.len(),
"event_log_size": self.event_log.len(),
"executed_actions": self.executed_bounded_actions.len(),
});
Ok(status)
}
MaxMethod::ManifoldSnapshot => {
let snapshot = serde_json::json!({
"instances": self.instances.iter().map(|(id, inst)| {
serde_json::json!({
"id": id,
"phase": inst.phase,
"policy_state": inst.policy_state,
"diagnostic_count": inst.diagnostics.len(),
"receipt_count": inst.receipts.len(),
"conformance_score": inst.conformance_score(),
"conformance_grade": inst.conformance_grade().as_str(),
})
}).collect::<Vec<_>>(),
"hook_count": self.hooks.len(),
"event_log_size": self.event_log.len(),
});
Ok(snapshot)
}
MaxMethod::LawfulTransition => self.handle_lawful_transition(instance_id, params),
MaxMethod::Admission => {
let inst = self
.instances
.get(instance_id)
.ok_or_else(|| format!("Instance not found: {}", instance_id))?;
let verdict = if inst.diagnostics.is_empty() {
"Admitted"
} else if inst.diagnostics.iter().any(|d| {
matches!(
d.lsp.severity,
Some(lsp_types_max::DiagnosticSeverity::ERROR)
)
}) {
"Refused"
} else {
"Unknown"
};
Ok(serde_json::json!({
"instance_id": instance_id,
"verdict": verdict,
"diagnostic_count": inst.diagnostics.len(),
}))
}
MaxMethod::Refusal => {
let diag_id: String =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
let receipt_id = format!("rcpt-refusal-{}", diag_id);
let hash = sha256(receipt_id.as_bytes());
let receipt = lsp_max_protocol::Receipt {
receipt_id: receipt_id.clone(),
hash,
prev_receipt_hash: None,
};
self.execute_action(MeshAction::EmitReceipt {
instance_id: InstanceId::from(instance_id),
receipt: receipt.clone(),
});
Ok(serde_json::json!({
"refused": true,
"diagnostic_id": diag_id,
"receipt": receipt,
}))
}
MaxMethod::Replay => self.handle_replay(instance_id),
MaxMethod::ReleaseActuation => self.handle_release_actuation(instance_id),
MaxMethod::InstanceList => {
let mut list: Vec<serde_json::Value> = self
.instances
.values()
.map(|inst| {
serde_json::json!({
"id": inst.id,
"phase": inst.phase,
"conformance_score": inst.conformance_score(),
"conformance_grade": inst.conformance_grade().as_str(),
})
})
.collect();
list.sort_by_key(|v| v["id"].as_str().unwrap_or("").to_string());
serde_json::to_value(list).map_err(|e| e.to_string())
}
MaxMethod::DumpState => {
let state = self.to_state();
serde_json::to_value(&state).map_err(|e| format!("Serialization failed: {}", e))
}
MaxMethod::RestoreState => {
let state: crate::runtime::mesh_types::AutonomicMeshState =
serde_json::from_value(params).map_err(|e| format!("Invalid params: {}", e))?;
self.load_state(state);
Ok(serde_json::Value::Null)
}
MaxMethod::Reset => {
self.execute_action(MeshAction::ResetInstance {
instance_id: InstanceId::from(instance_id),
});
Ok(serde_json::json!({
"reset": true,
"instance_id": instance_id,
}))
}
MaxMethod::ConformanceDelta => {
let since_seq: u64 = params
.as_object()
.and_then(|o| o.get("since_seq"))
.and_then(|v| v.as_u64())
.unwrap_or(0);
let deltas: Vec<&crate::runtime::mesh_types::ConformanceDeltaEntry> = self
.conformance_delta_log
.iter()
.filter(|e| e.seq > since_seq)
.collect();
Ok(serde_json::json!({
"deltas": deltas,
"current_seq": self.action_seq,
}))
}
}
}
pub fn apply_repair_transaction(
&mut self,
instance_id: &str,
code_action: lsp_max_protocol::MaxCodeAction,
) -> Result<serde_json::Value, String> {
{
let inst = self
.instances
.get(instance_id)
.ok_or_else(|| format!("Instance not found: {}", instance_id))?;
let existing: std::collections::HashSet<&str> = inst
.receipts
.iter()
.map(|r| r.receipt_id.as_str())
.collect();
for expected in &code_action.receipt_plan.expected_receipts {
if !existing.contains(expected.as_str()) {
return Err(format!(
"Receipt integrity violation: required receipt '{}' not found",
expected
));
}
}
}
let action_id = format!("repair-{}", code_action.action.title.replace(' ', "-"));
let receipt_id = format!("rcpt-repair-{}", code_action.action.title.replace(' ', "-"));
let hash = sha256(receipt_id.as_bytes());
let receipt = lsp_max_protocol::Receipt {
receipt_id: receipt_id.clone(),
hash,
prev_receipt_hash: None,
};
self.execute_action(MeshAction::ExecuteBoundedAction {
instance_id: InstanceId::from(instance_id),
action_id,
description: code_action.action.title.clone(),
});
self.execute_action(MeshAction::EmitReceipt {
instance_id: InstanceId::from(instance_id),
receipt: receipt.clone(),
});
serde_json::to_value(receipt).map_err(|e| e.to_string())
}
}