MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / run

Method run

atomic-cli/src/commands/intent/validate.rs:31–104  ·  view source on GitHub ↗
(&self)

Source from the content-addressed store, hash-verified

29
30impl Command for IntentValidate {
31 fn run(&self) -> CliResult<()> {
32 // Resolve the argument. A path-shaped argument (ends in `.md` or
33 // contains a separator) is loaded as a file — and if it doesn't exist
34 // we report FileNotFound rather than misreporting it as a bad ID.
35 // Otherwise the argument is an intent ID read through the vault bridge;
36 // if a FRESH attestation sidecar exists we gate the attested node (so a
37 // previously-attested intent reports conforms), a STALE one warns and
38 // falls back to the raw node.
39 let node = if is_path_shaped(&self.id_or_path) {
40 let path = Path::new(&self.id_or_path);
41 if !path.is_file() {
42 return Err(CliError::FileNotFound {
43 path: path.to_path_buf(),
44 });
45 }
46 let doc = std::fs::read_to_string(path).map_err(CliError::Io)?;
47 let (fm, body) = parse_markdown(&doc).map_err(|e| CliError::InvalidArgument {
48 message: format!("could not parse markdown frontmatter: {e}"),
49 })?;
50 lift_intent(&fm, &body).map_err(|e| CliError::InvalidArgument {
51 message: format!("could not lift intent: {e}"),
52 })?
53 } else {
54 let root = find_repository_root()?;
55 let repo = Repository::open(&root).map_err(CliError::Repository)?;
56 let inputs = bridge::read_intent(&repo, &self.id_or_path)?;
57 match bridge::load_attestation(&repo, &self.id_or_path, &inputs)? {
58 bridge::Attestation::Fresh(node) => *node,
59 bridge::Attestation::Stale(_) => {
60 eprintln!(
61 "warning: the attestation for {} is stale (the intent changed since it \
62 was signed); re-run `atomic intent attest {}`.",
63 self.id_or_path, self.id_or_path
64 );
65 bridge::lift(&inputs)?
66 }
67 bridge::Attestation::None => bridge::lift(&inputs)?,
68 }
69 };
70
71 let mut report = validate_intent(&node);
72
73 // Evidence URNs must RESOLVE to real changes when a repository is
74 // reachable — the gate only checks presence. (Recording the Why: a met
75 // acceptance criterion's evidence must resolve, not just exist.)
76 let evidence: Vec<(String, String)> = node
77 .has_acceptance_criterion
78 .iter()
79 .filter_map(|ac| ac.evidence.clone().map(|e| (ac.id.clone(), e)))
80 .collect();
81 let extra = check_evidence_resolution(&evidence, find_repository_root().ok().as_deref());
82 if !extra.is_empty() {
83 report.conforms = false;
84 report.results.extend(extra);
85 }
86
87 if self.json {
88 println!(

Callers

nothing calls this directly

Calls 15

parse_markdownFunction · 0.85
lift_intentFunction · 0.85
find_repository_rootFunction · 0.85
read_intentFunction · 0.85
validate_intentFunction · 0.85
extendMethod · 0.80
is_path_shapedFunction · 0.70
load_attestationFunction · 0.70
liftFunction · 0.70
validation_failedFunction · 0.70
is_fileMethod · 0.45

Tested by

no test coverage detected