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

Function infer_verification_passed

atomic-agent/src/provenance/classify.rs:580–748  ·  view source on GitHub ↗

Infer whether a verification command passed. Exit status and normalized tool status are authoritative. Text output is a fallback for hook payloads that expose only display output. Zero-failure summaries must be recognized before generic `fail` / `error` tokens.

(
    tool_input: Option<&serde_json::Value>,
    tool_output: Option<&str>,
    status: Option<&str>,
)

Source from the content-addressed store, hash-verified

578/// fallback for hook payloads that expose only display output. Zero-failure
579/// summaries must be recognized before generic `fail` / `error` tokens.
580pub(crate) fn infer_verification_passed(
581 tool_input: Option<&serde_json::Value>,
582 tool_output: Option<&str>,
583 status: Option<&str>,
584) -> Option<bool> {
585 if let Some(exit_code) = tool_input
586 .and_then(|value| value.get("exit_code"))
587 .and_then(|value| value.as_i64())
588 {
589 return Some(exit_code == 0);
590 }
591
592 match status.map(str::to_ascii_lowercase).as_deref() {
593 Some("error" | "failed" | "failure") => return Some(false),
594 // `completed` commonly means only that the tool call returned. Its
595 // command may still have failed, so let output inference decide.
596 Some("success" | "succeeded" | "passed" | "ok") => return Some(true),
597 _ => {}
598 }
599
600 tool_output.and_then(|output| {
601 let lower = output.to_ascii_lowercase();
602 let mut has_zero_failure_count = false;
603 let mut has_nonzero_failure_count = false;
604 let mut has_unquantified_failure = false;
605 let mut has_negative_tap_result = false;
606 let mut has_success_token = false;
607
608 for line in lower.lines() {
609 // Reporters decorate summary lines differently (`# fail 0`,
610 // `ℹ fail 0`, `0 failures`, etc.). Tokenize away decoration and
611 // inspect nearby count/label pairs in either order.
612 let tokens: Vec<&str> = line
613 .split(|c: char| !c.is_ascii_alphanumeric())
614 .filter(|token| !token.is_empty())
615 .collect();
616 let line_has_negative_tap_result = tokens
617 .windows(2)
618 .any(|pair| pair[0] == "not" && pair[1] == "ok");
619 has_negative_tap_result |= line_has_negative_tap_result;
620 has_success_token |= tokens.iter().any(|token| {
621 matches!(
622 *token,
623 "ok" | "pass" | "passed" | "success" | "succeeded" | "successful"
624 )
625 });
626 let trimmed = line.trim_start();
627 let line_is_successful_test = !line_has_negative_tap_result
628 && ((tokens.first() == Some(&"test")
629 && matches!(tokens.last(), Some(&("ok" | "pass" | "passed"))))
630 || matches!(tokens.first(), Some(&("ok" | "pass" | "passed")))
631 || trimmed.starts_with('✓')
632 || trimmed.starts_with('✔'));
633 for (index, token) in tokens.iter().enumerate() {
634 if !matches!(
635 *token,
636 "fail" | "failed" | "failing" | "failure" | "failures" | "error" | "errors"
637 ) {

Callers 2

summarize_verificationFunction · 0.85
build_tool_detailFunction · 0.85

Calls 4

getMethod · 0.65
linesMethod · 0.45
is_emptyMethod · 0.45
iterMethod · 0.45

Tested by

no test coverage detected