From 885bc9212269dbfe4bc06187e91877f94cf2451d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 1 Aug 2026 12:10:12 -0400 Subject: [PATCH] Fail runs that bypass goal gates --- .../fabro-workflow/src/graph/routing.rs | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/components/fabro-workflow/src/graph/routing.rs b/lib/components/fabro-workflow/src/graph/routing.rs index 23d3087f2..afb0147de 100644 --- a/lib/components/fabro-workflow/src/graph/routing.rs +++ b/lib/components/fabro-workflow/src/graph/routing.rs @@ -5,7 +5,7 @@ use rand::Rng; use crate::condition::evaluate_condition; use crate::context::Context; -use crate::outcome::{Outcome, StageOutcome}; +use crate::outcome::Outcome; /// Result of edge selection: the chosen edge and the reason it was selected. pub(crate) struct SelectedGraphEdge<'a> { @@ -99,14 +99,13 @@ pub(crate) fn check_goal_gates( graph: &GvGraph, node_outcomes: &HashMap, ) -> std::result::Result<(), String> { - for (node_id, outcome) in node_outcomes { - if let Some(node) = graph.nodes.get(node_id) { - if node.goal_gate() - && outcome.status != StageOutcome::Succeeded - && outcome.status != StageOutcome::PartiallySucceeded - { - return Err(node_id.clone()); - } + for (node_id, node) in &graph.nodes { + if node.goal_gate() + && !node_outcomes + .get(node_id) + .is_some_and(|outcome| outcome.status.is_successful()) + { + return Err(node_id.clone()); } } Ok(()) @@ -632,6 +631,19 @@ mod tests { assert_eq!(check_goal_gates(&g, &outcomes), Err("work".to_string())); } + #[test] + fn goal_gates_unvisited_returns_node_id() { + let mut g = Graph::new("test"); + let mut n = Node::new("verify"); + n.attrs + .insert("goal_gate".to_string(), AttrValue::Boolean(true)); + g.nodes.insert("verify".to_string(), n); + + let outcomes = HashMap::new(); + + assert_eq!(check_goal_gates(&g, &outcomes), Err("verify".to_string())); + } + #[test] fn goal_gates_non_gate_nodes_ignored() { let mut g = Graph::new("test");