From 599b674ec1e1e518d3ab4779c0005db95d5da665 Mon Sep 17 00:00:00 2001 From: Scott Werner Date: Wed, 7 Oct 2026 17:05:04 -0400 Subject: [PATCH] Build required publication on Petri main's finalization Track Petri main now that required run finalization has merged there, read workflow execution from the engine state, resume the failed-publication regression with its admitted workflow, and keep the worker lifecycle helper usable for rejected appends. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 52 +++++++++---------- Cargo.toml | 14 ++--- docs/internal/run-finalization.md | 9 ++-- lib/apps/fabro-server/src/petri_runs.rs | 19 +++++-- lib/components/fabro-petri/tests/hooks.rs | 28 +++++++--- .../fabro-petri/tests/projection.rs | 2 +- 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab3f80940..fadbd088f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1820,7 +1820,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1934,7 +1934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3774,7 +3774,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.61.2", ] [[package]] @@ -4584,7 +4584,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -5166,7 +5166,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "petri-attractor-steps" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "globset", @@ -5197,7 +5197,7 @@ dependencies = [ [[package]] name = "petri-driver" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "getrandom 0.3.4", @@ -5217,7 +5217,7 @@ dependencies = [ [[package]] name = "petri-engine" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "petri-ir", "serde", @@ -5229,7 +5229,7 @@ dependencies = [ [[package]] name = "petri-execution" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "petri-driver", @@ -5253,7 +5253,7 @@ dependencies = [ [[package]] name = "petri-executor" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "libc", @@ -5268,7 +5268,7 @@ dependencies = [ [[package]] name = "petri-executor-sandbox" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "petri-executor", @@ -5290,7 +5290,7 @@ dependencies = [ [[package]] name = "petri-frontend" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "marked-yaml", "petri-ir", @@ -5304,7 +5304,7 @@ dependencies = [ [[package]] name = "petri-frontend-attractor" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "minijinja", "petri-frontend", @@ -5321,7 +5321,7 @@ dependencies = [ [[package]] name = "petri-frontend-fabro" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "petri-frontend", "petri-frontend-attractor", @@ -5337,7 +5337,7 @@ dependencies = [ [[package]] name = "petri-frontend-native" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "petri-frontend", "petri-ir", @@ -5348,7 +5348,7 @@ dependencies = [ [[package]] name = "petri-ir" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "regex", "serde", @@ -5361,7 +5361,7 @@ dependencies = [ [[package]] name = "petri-runtime" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "petri-driver", @@ -5382,7 +5382,7 @@ dependencies = [ [[package]] name = "petri-steps" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "petri-executor", @@ -5398,7 +5398,7 @@ dependencies = [ [[package]] name = "petri-store" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "getrandom 0.3.4", @@ -5413,7 +5413,7 @@ dependencies = [ [[package]] name = "petri-testkit" version = "0.1.0" -source = "git+https://github.com/lithoscomputer/petri.git?branch=main#e46845bd0139dd04e9e795d3201b5b9b4b8b1026" +source = "git+https://github.com/lithoscomputer/petri.git?branch=main#505a17839987f052ef0a47b799d30c565fd29475" dependencies = [ "async-trait", "petri-driver", @@ -5752,7 +5752,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -6200,7 +6200,7 @@ dependencies = [ "errno 0.3.14", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6259,7 +6259,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6907,7 +6907,7 @@ version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ - "errno 0.2.8", + "errno 0.3.14", "libc", ] @@ -7385,7 +7385,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -7420,7 +7420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -8467,7 +8467,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3a958567f..cbad48387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,13 +108,13 @@ pebble-cli-core = { git = "https://github.com/lithoscomputer/pebble", branch = " # petri: the workflow engine Fabro runs its workflows on. Only `fabro-petri` # and `fabro-dot` (the DOT parser alone) may depend on these packages; the # keys carry the `petri_` prefix so the crate names say where they come from. -petri_runtime = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-runtime" } -petri_execution = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-execution" } -petri_store = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-store" } -petri_attractor_steps = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-attractor-steps" } -petri_frontend_attractor = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-frontend-attractor" } -petri_frontend_fabro = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-frontend-fabro" } -petri_testkit = { git = "https://github.com/lithoscomputer/petri.git", rev = "0198e66f6619e147e461c52c138497863d851969", package = "petri-testkit" } +petri_runtime = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-runtime" } +petri_execution = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-execution" } +petri_store = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-store" } +petri_attractor_steps = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-attractor-steps" } +petri_frontend_attractor = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-frontend-attractor" } +petri_frontend_fabro = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-frontend-fabro" } +petri_testkit = { git = "https://github.com/lithoscomputer/petri.git", branch = "main", package = "petri-testkit" } sentry = { version = "0.35", default-features = false, features = ["backtrace", "contexts", "ureq", "rustls"] } fork = "0.2" exec = "0.3" diff --git a/docs/internal/run-finalization.md b/docs/internal/run-finalization.md index 8ffc0702c..dc896a878 100644 --- a/docs/internal/run-finalization.md +++ b/docs/internal/run-finalization.md @@ -20,14 +20,13 @@ Both HTTP and in-process worker transports store the finish before settling managed status. A rejected append cannot settle the run. The later platform terminal lifecycle record acknowledges the same outcome; it cannot replace a terminal result or conclusion. Early worker failures without a Petri finish -still end through their committed platform lifecycle record. Worker generation, -run scope and lease ownership checks remain required for every worker write. +still end through their committed platform lifecycle record. Run scope, +authorization and lease ownership checks remain required for every worker write. ## Recovery and stored history -This integration pins Petri revision -`0198e66f6619e147e461c52c138497863d851969`, coordinator format 9 and event -contract 6. Petri retains its strict stored-format policy: version-8 coordinator +This integration requires a Petri with required run finalization (coordinator +format 9) and event contract 6. Petri retains its strict stored-format policy: version-8 coordinator logs cannot resume, inspect or replay with this engine. Fabro does not rewrite source history or relax that policy. Existing materialized views and stream rows remain stored; a projector replay failure holds Petri positions and reports diff --git a/lib/apps/fabro-server/src/petri_runs.rs b/lib/apps/fabro-server/src/petri_runs.rs index ff3afd154..9eaa57b2d 100644 --- a/lib/apps/fabro-server/src/petri_runs.rs +++ b/lib/apps/fabro-server/src/petri_runs.rs @@ -574,13 +574,25 @@ mod tests { transition: RunLifecycleKind, status: RunStatus, ) { + let response = append_lifecycle_as_worker(app, run_id, token, transition, status).await; + assert_eq!(response.status(), StatusCode::OK); + } + + /// Append one lifecycle record as the run's worker, and return the + /// server's response whatever it is. + async fn append_lifecycle_as_worker( + app: &axum::Router, + run_id: RunId, + token: &str, + transition: RunLifecycleKind, + status: RunStatus, + ) -> axum::response::Response { let record = PlatformRecord::RunLifecycle(RunLifecycleRecord::new(transition).with_status(status)); let body = json!({ "record": serde_json::to_value(&record).expect("the record encodes"), }); - let response = app - .clone() + app.clone() .oneshot( Request::builder() .method("POST") @@ -591,8 +603,7 @@ mod tests { .expect("the append request builds"), ) .await - .expect("the append request completes"); - assert_eq!(response.status(), StatusCode::OK); + .expect("the append request completes") } /// Petri's own finish of the run, stored the way its worker stores it: diff --git a/lib/components/fabro-petri/tests/hooks.rs b/lib/components/fabro-petri/tests/hooks.rs index 6367f382a..e44e865ff 100644 --- a/lib/components/fabro-petri/tests/hooks.rs +++ b/lib/components/fabro-petri/tests/hooks.rs @@ -1262,16 +1262,24 @@ async fn published_run( let (origin, _) = upstream(&harness.run_dir.with_file_name("upstream"), 2).await; harness.source = Some(file_source(&origin, "main", Some(1))); harness.publisher = Some(Arc::clone(publisher) as Arc); - let workflow = workflow( - &format!(" edit [shape=parallelogram, {attributes}]"), - " start -> edit -> exit", - ); let outcome = harness - .run_on(SandboxProviderKind::LOCAL, &workflow, SETTINGS) + .run_on( + SandboxProviderKind::LOCAL, + &published_workflow(attributes), + SETTINGS, + ) .await; (harness, outcome) } +/// The workflow [`published_run`] runs: one command stage with `attributes`. +fn published_workflow(attributes: &str) -> String { + workflow( + &format!(" edit [shape=parallelogram, {attributes}]"), + " start -> edit -> exit", + ) +} + /// A successful run hands its publisher the run branch, the commit it ends /// on (held by the snapshot repository) and its patch, before the run ends. #[tokio::test] @@ -1308,7 +1316,8 @@ async fn a_successful_run_is_published_with_its_branch_head_and_patch() { #[tokio::test] async fn a_failed_publication_fails_the_run() { let publisher = RecordingPublisher::new(Some("the push was rejected")); - let (harness, outcome) = published_run("script=\"echo edited >> README.md\"", &publisher).await; + let attributes = "script=\"echo edited >> README.md\""; + let (harness, outcome) = published_run(attributes, &publisher).await; assert_eq!(outcome.status, RunStatus::Failed, "{outcome:?}"); assert!(outcome.publish_failed); assert_eq!(outcome.failure.as_deref(), Some("the push was rejected")); @@ -1324,7 +1333,12 @@ async fn a_failed_publication_fails_the_run() { assert_eq!(stored.failure, outcome.failure); assert!(stored.publish_failed); let resumed = harness - .execute_on(SandboxProviderKind::LOCAL, "", SETTINGS, true) + .execute_on( + SandboxProviderKind::LOCAL, + &published_workflow(attributes), + SETTINGS, + true, + ) .await; assert_eq!(resumed.status, outcome.status); assert_eq!(resumed.failure, outcome.failure); diff --git a/lib/components/fabro-petri/tests/projection.rs b/lib/components/fabro-petri/tests/projection.rs index 4b5163da3..71546ed76 100644 --- a/lib/components/fabro-petri/tests/projection.rs +++ b/lib/components/fabro-petri/tests/projection.rs @@ -1449,7 +1449,7 @@ async fn required_finalization_projects_only_the_committed_overall_result() { } finalizer.release.add_permits(1); let report = task.await.unwrap(); - assert_eq!(report.execution_status, PetriRunStatus::Success); + assert_eq!(report.state.folded_status(), PetriRunStatus::Success); assert_eq!( report.status, if rejection.is_some() {