#[derive(Clone, Copy)]
pub struct LawGate {
pub name: &'static str,
pub check: fn(&crate::ServerRegistry) -> bool,
}
impl std::fmt::Debug for LawGate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LawGate").field("name", &self.name).finish()
}
}
impl LawGate {
pub fn eval(&self, registry: &crate::ServerRegistry) -> bool {
(self.check)(registry)
}
}
pub fn accept_gates(registry: &crate::ServerRegistry, gates: &[LawGate]) -> bool {
gates.iter().all(|g| g.eval(registry))
}
pub const DEFAULT_GATES: &[LawGate] = &[
LawGate {
name: "not-uninitialized",
check: |r| r.current_state != crate::service::State::Uninitialized,
},
LawGate {
name: "receipt-present",
check: |r| !r.receipts.is_empty(),
},
LawGate {
name: "clean-slate-requires-receipt",
check: |r| !r.diagnostics.is_empty() || !r.receipts.is_empty(),
},
];
pub fn run_gate_logic(
gate_id: &str,
current_state: crate::service::State,
root_path: std::path::PathBuf,
) -> bool {
match gate_id {
"some-gate" => true,
"gate-state-check" => current_state != crate::service::State::Uninitialized,
"gate-receipt-check" | "gate-auth-check" => {
let spec = crate::diagnostics::law_table::law_table()
.iter()
.find(|s| s.gate_id == gate_id);
let Some(spec) = spec else { return false };
let path = root_path.join(spec.receipt_file);
if path.exists() {
std::fs::read_to_string(&path)
.map(|c| c.trim() == spec.receipt_token)
.unwrap_or(false)
} else {
false
}
}
"gate-powl-conformance" => {
let spec = crate::diagnostics::law_table::law_table()
.iter()
.find(|s| s.gate_id == gate_id);
match spec {
Some(spec) => root_path.join(spec.receipt_file).exists(),
None => false, }
}
_ => {
let output = std::process::Command::new("cargo")
.arg("check")
.current_dir(root_path)
.output();
match output {
Ok(out) => {
if !out.status.success() {
eprintln!("cargo check failed!");
eprintln!("stdout: {}", String::from_utf8_lossy(&out.stdout));
eprintln!("stderr: {}", String::from_utf8_lossy(&out.stderr));
}
out.status.success()
}
Err(e) => {
eprintln!("failed to execute cargo check: {:?}", e);
false
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::service::State;
use std::collections::HashMap;
fn minimal_registry(state: State) -> crate::ServerRegistry {
crate::ServerRegistry {
client_capabilities: None,
server_capabilities: None,
diagnostics: HashMap::new(),
repair_plans: HashMap::new(),
gates: HashMap::new(),
receipts: HashMap::new(),
snapshots: HashMap::new(),
cleared_diagnostics: std::collections::HashSet::new(),
current_state: state,
document_versions: HashMap::new(),
root_path: std::path::PathBuf::from("/tmp"),
action_seq: 0,
conformance_delta_log: std::collections::VecDeque::new(),
}
}
#[test]
fn law_gate_eval_returns_true_when_predicate_passes() {
let gate = LawGate {
name: "always-true",
check: |_| true,
};
let reg = minimal_registry(State::Initialized);
assert!(gate.eval(®));
}
#[test]
fn law_gate_eval_returns_false_when_predicate_fails() {
let gate = LawGate {
name: "always-false",
check: |_| false,
};
let reg = minimal_registry(State::Initialized);
assert!(!gate.eval(®));
}
#[test]
fn law_gate_debug_shows_name() {
let gate = LawGate {
name: "my-gate",
check: |_| true,
};
assert!(format!("{gate:?}").contains("my-gate"));
}
#[test]
fn accept_gates_empty_slice_always_passes() {
let reg = minimal_registry(State::Uninitialized);
assert!(accept_gates(®, &[]));
}
#[test]
fn accept_gates_all_pass() {
let gates = [
LawGate {
name: "g1",
check: |_| true,
},
LawGate {
name: "g2",
check: |_| true,
},
];
let reg = minimal_registry(State::Initialized);
assert!(accept_gates(®, &gates));
}
#[test]
fn accept_gates_fails_on_first_false_gate() {
let gates = [
LawGate {
name: "fail",
check: |_| false,
},
LawGate {
name: "pass",
check: |_| true,
},
];
let reg = minimal_registry(State::Initialized);
assert!(!accept_gates(®, &gates));
}
#[test]
fn default_gates_block_uninitialized_state() {
let reg = minimal_registry(State::Uninitialized);
assert!(!accept_gates(®, DEFAULT_GATES));
}
#[test]
fn run_gate_logic_some_gate_always_returns_true() {
let result = run_gate_logic(
"some-gate",
State::Uninitialized,
std::path::PathBuf::from("/tmp"),
);
assert!(result);
}
#[test]
fn run_gate_logic_state_check_passes_when_initialized() {
let result = run_gate_logic(
"gate-state-check",
State::Initialized,
std::path::PathBuf::from("/tmp"),
);
assert!(result);
}
#[test]
fn run_gate_logic_state_check_fails_when_uninitialized() {
let result = run_gate_logic(
"gate-state-check",
State::Uninitialized,
std::path::PathBuf::from("/tmp"),
);
assert!(!result);
}
}