From 4ad3d2b793c343728cb7cbe97046c0f4f2adf5dd Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 26 Sep 2026 16:59:22 -0400 Subject: [PATCH] Project a timed-out partial success from Petri's UnderlyingFailure Petri's PartialSuccess now carries Option, which is Failure(FailureInfo) or TimedOut, so a partial success converted from a timeout keeps the timeout (lithoscomputer/petri#51). The projection's failure message reads the new shape: the info's message for a failure, "the step timed out" for a timeout, as for the plain statuses. Lock the Petri crates at the PR head ded1df4, which also moves Petri's run format to 8; the attach snapshot records it. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 30 +++++++-------- lib/apps/fabro-cli/tests/it/cmd/attach.rs | 2 +- .../fabro-petri/src/projection/engine.rs | 37 +++++++++++++++++-- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d48f4d02..541d8f97f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5162,7 +5162,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "petri-attractor-steps" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "globset", @@ -5193,7 +5193,7 @@ dependencies = [ [[package]] name = "petri-driver" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "getrandom 0.3.4", @@ -5213,7 +5213,7 @@ dependencies = [ [[package]] name = "petri-engine" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "petri-ir", "serde", @@ -5225,7 +5225,7 @@ dependencies = [ [[package]] name = "petri-execution" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "petri-driver", @@ -5249,7 +5249,7 @@ dependencies = [ [[package]] name = "petri-executor" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "libc", @@ -5264,7 +5264,7 @@ dependencies = [ [[package]] name = "petri-executor-sandbox" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "petri-executor", @@ -5286,7 +5286,7 @@ dependencies = [ [[package]] name = "petri-frontend" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "marked-yaml", "petri-ir", @@ -5300,7 +5300,7 @@ dependencies = [ [[package]] name = "petri-frontend-attractor" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "minijinja", "petri-frontend", @@ -5317,7 +5317,7 @@ dependencies = [ [[package]] name = "petri-frontend-fabro" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "petri-frontend", "petri-frontend-attractor", @@ -5333,7 +5333,7 @@ dependencies = [ [[package]] name = "petri-frontend-native" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "petri-frontend", "petri-ir", @@ -5344,7 +5344,7 @@ dependencies = [ [[package]] name = "petri-ir" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "regex", "serde", @@ -5357,7 +5357,7 @@ dependencies = [ [[package]] name = "petri-runtime" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "petri-driver", @@ -5378,7 +5378,7 @@ dependencies = [ [[package]] name = "petri-steps" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "petri-executor", @@ -5394,7 +5394,7 @@ dependencies = [ [[package]] name = "petri-store" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "getrandom 0.3.4", @@ -5409,7 +5409,7 @@ dependencies = [ [[package]] name = "petri-testkit" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#62483bad9fbaaa8b6261fc54f6a67b7df57a3212" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#ded1df4f2ad80fa790d807fe4abed89887399392" dependencies = [ "async-trait", "petri-driver", diff --git a/lib/apps/fabro-cli/tests/it/cmd/attach.rs b/lib/apps/fabro-cli/tests/it/cmd/attach.rs index f08238db6..f745b7c31 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/attach.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/attach.rs @@ -904,7 +904,7 @@ fn attach_json_errors_without_prompting_for_human_input() { "recorded_at": "[EPOCH_MS]", "body": { "event": "run.started", - "format_version": 7, + "format_version": 8, "key": "[ULID]", "root": 0, "middleware_chain": [ diff --git a/lib/components/fabro-petri/src/projection/engine.rs b/lib/components/fabro-petri/src/projection/engine.rs index 12fae7891..597737621 100644 --- a/lib/components/fabro-petri/src/projection/engine.rs +++ b/lib/components/fabro-petri/src/projection/engine.rs @@ -13,7 +13,7 @@ use fabro_types::{ use petri_execution::events::{Derived, RunEvent, Subject, ViewEvent, WaitState}; use petri_execution::{ExecutionId, InvocationId}; use petri_runtime::engine::{Admission, Event}; -use petri_runtime::ir::{Metrics, Status}; +use petri_runtime::ir::{Metrics, Status, UnderlyingFailure}; use serde_json::Value; use tracing::debug; @@ -382,9 +382,12 @@ pub(super) fn failure_message(status: &Status) -> Option { match status { Status::Failure(info) | Status::PartialSuccess { - underlying: Some(info), + underlying: Some(UnderlyingFailure::Failure(info)), } => Some(info.message.clone()), - Status::TimedOut => Some("the step timed out".to_string()), + Status::TimedOut + | Status::PartialSuccess { + underlying: Some(UnderlyingFailure::TimedOut), + } => Some("the step timed out".to_string()), Status::Cancelled => Some("the step was cancelled".to_string()), Status::Success | Status::PartialSuccess { underlying: None } | Status::Skipped => None, } @@ -451,3 +454,31 @@ fn apply_metrics(stage: &mut StageProjection, metrics: &Metrics) { } } } + +#[cfg(test)] +mod tests { + use petri_runtime::ir::FailureInfo; + + use super::*; + + /// A partial success reports the failure it was converted from, a + /// timeout included, and its outcome stays a partial success. + #[test] + fn a_partial_success_reports_the_failure_it_came_from() { + let failed = Status::partial(FailureInfo::new("tests failed")); + let timed_out = Status::PartialSuccess { + underlying: Some(UnderlyingFailure::TimedOut), + }; + let unexplained = Status::PartialSuccess { underlying: None }; + + assert_eq!(failure_message(&failed).as_deref(), Some("tests failed")); + assert_eq!( + failure_message(&timed_out).as_deref(), + Some("the step timed out") + ); + assert_eq!(failure_message(&unexplained), None); + for status in [&failed, &timed_out, &unexplained] { + assert_eq!(stage_outcome(status), StageOutcome::PartiallySucceeded); + } + } +}