evorule_cli/commands/
validate.rs1use std::path::Path;
37
38use crate::error::CliError;
39use crate::io_util;
40
41pub fn run(rules_dir: &Path) -> Result<(), CliError> {
43 let transforms = io_util::load_rules(rules_dir)?;
44 let discipline_n = super::discipline_gate::discipline_len()?;
45
46 println!("=== Validating {} ===", rules_dir.display());
47 println!("Transforms: {}", transforms.len());
48 println!(
49 "Discipline: {} rules (DC-01 .. DC-{:02})",
50 discipline_n, discipline_n
51 );
52 println!();
53
54 let report = super::discipline_gate::check(&transforms)?;
55
56 println!("Nodes: {} (含 branch 内嵌子指令)", report.scanned);
57 println!();
58
59 if report.violations.is_empty() {
60 println!("[OK] rule-set accepted by the discipline gate");
61 } else {
62 for v in &report.violations {
63 let label = if v.node_type.is_empty() {
64 "<missing type>"
65 } else {
66 v.node_type.as_str()
67 };
68 println!(
69 "[ERROR] {:<24} {:<12} <- {} {}",
70 v.path, label, v.code, v.reason
71 );
72 }
73 }
74
75 println!();
76 println!("=== Summary ===");
77 println!("Violations: {}", report.violations.len());
78
79 if report.violations.is_empty() {
80 Ok(())
81 } else {
82 Err(CliError::other(format!(
83 "validation failed with {} violations",
84 report.violations.len()
85 )))
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 #![allow(clippy::unwrap_used)]
92 use evorule_tcb::META_INSTRUCTION_TYPES;
93
94 #[test]
95 fn test_whitelist_excludes_g8_words() {
96 for t in META_INSTRUCTION_TYPES {
99 assert!(
100 !matches!(*t, "conditional" | "while_loop" | "sequence"),
101 "whitelist must not contain G8-forbidden words: {}",
102 t
103 );
104 }
105 }
106
107 #[test]
108 fn test_whitelist_includes_core_meta_instructions() {
109 assert!(META_INSTRUCTION_TYPES.contains(&"branch"));
111 assert!(META_INSTRUCTION_TYPES.contains(&"set"));
112 assert!(META_INSTRUCTION_TYPES.contains(&"push"));
113 assert!(META_INSTRUCTION_TYPES.contains(&"io_request"));
114 assert!(META_INSTRUCTION_TYPES.contains(&"enforce"));
115 assert!(!META_INSTRUCTION_TYPES.contains(&"collect"));
117 assert!(!META_INSTRUCTION_TYPES.contains(&"merge"));
118 assert!(!META_INSTRUCTION_TYPES.contains(&"noop"));
120 assert!(!META_INSTRUCTION_TYPES.contains(&"increment"));
121 assert!(!META_INSTRUCTION_TYPES.contains(&"decrement"));
122 }
123}