scientific_workflow/lib.rs
1//! Rust primitives for reproducible scientific workflows.
2//!
3//! `scientific-workflow` provides the data and execution foundations needed to
4//! describe scientific systems, record their evolution, and organize scoped
5//! computational work. The crate is intentionally divided by responsibility:
6//! state representation, in-memory state time series, storage, orchestration, and
7//! language bridges remain separate modules rather than accumulating behind
8//! one monolithic interface.
9//!
10//! # Module boundaries (public API ownership)
11//!
12//! The boundary map is strict: each module owns only one slice of behavior, and
13//! callers move data between boundaries without duplicating the same concern.
14//!
15//! - `study`: declarative study/phase/task planning and run execution. It owns
16//! declaration validation, scheduling, cancellation, execution timing, and
17//! progress summaries. It does not own model semantics, storage formats, or
18//! schema declarations.
19//! - `configuration`: strict study-level replicate settings, study-wide
20//! `parameters.json`, phase-scoped expansion, named paths, and resolved
21//! combinations. It owns input validation and parameter expansion only. It
22//! does not own task construction, state schemas, or persistence.
23//! - `system_state`: typed heterogeneous fielded state values and schema.
24//! - `time_series`: ordered in-memory complete-state collections for analysis.
25//! - `storage`: asynchronous buffered persistence and completed-run reconstruction.
26//! - `execution`: replicate subprocess dispatch, isolated output scopes, and
27//! directory-scoped recording path derivation.
28//! - `artifact`: immutable input content-addressed publication under an execution
29//! scope, plus strict load-time verification.
30//! - `rng_record`: lazy named replicate-seed derivation and validated
31//! reproducibility metadata for caller-owned RNG sources.
32//! - `prelude`: curated import surfaces that preserve public boundaries.
33//!
34//! # Study vocabulary
35//!
36//! A [`study::Study`] is the largest scope. It owns scheduling, cancellation,
37//! recording, and display for an ordered set of [`study::Phase`] values. A
38//! phase owns many [`study::Task`] values plus their concurrency, delay,
39//! timeout, dependency, and failure policies. A task owns one workload, which
40//! reports progress, detail, messages, and cancellation through
41//! [`study::TaskContext`]. Progress and one-shot work are modes of the same
42//! task type.
43//!
44//! [`configuration`] is deliberately outside that hierarchy. It validates
45//! process-level replicate policy from `study.json`, resolves a study-wide
46//! `parameters.json`, then selects one string-keyed phase whose
47//! global, group-shared, and local choices expand into deterministic
48//! [`configuration::ResolvedConfiguration`] values. The downstream application
49//! decides how each combination becomes a task and owns all schemas, model
50//! inputs, storage, and other effects captured by the workload.
51//!
52//! # Supporting modules
53//!
54//! [`execution`] dispatches isolated replicate subprocesses, creates their
55//! output scopes, and derives deterministic task recording paths. [`artifact`]
56//! atomically publishes and verifies content-addressed immutable bytes.
57//! [`rng_record`] stores validated RNG provenance while leaving random
58//! generation to applications.
59//!
60//! [`system_state`] provides:
61//!
62//! - JSON-defined, immutable field layouts;
63//! - optional natural-language field descriptions without persisted Rust types;
64//! - heterogeneous concrete Rust payloads behind a typed API;
65//! - clone-free payload insertion, mutation, and extraction;
66//! - explicit per-payload cloning of complete states;
67//! - mutable, checked time-point progression.
68//!
69//! Type erasure and boxing remain internal to that module. Consumer crates
70//! work with their original concrete payload types.
71//!
72//! [`time_series`] provides the in-memory analysis collection for complete,
73//! ordered states. It enforces shared-layout identity and increasing simulation
74//! indices, offers a lightweight borrowed view, and permits field-level
75//! mutation without exposing mutable state time. It deliberately performs no
76//! serialization, chunking, or filesystem IO.
77//!
78//! [`storage`] provides named partial-state streams with writer-owned sampling
79//! intervals, borrowed JSON encoding only when due, bounded asynchronous
80//! persistence through one worker per recording, byte-targeted chunking, atomic recording
81//! metadata, automatic operational timing, terminal summaries, name-selected payload
82//! decoders, and verified full-series or latest-state reconstruction.
83//! Import [`prelude::basics`] for these scientific primitives and
84//! [`prelude::study`] only at orchestration boundaries.
85//!
86//! # Basic use
87//!
88//! ```no_run
89//! use scientific_workflow::prelude::basics::*;
90//!
91//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
92//! let spec = SystemStateSchema::load_json_template("state.json")?;
93//! let mut state = spec.create_empty_state(SimulationTime::from_iteration(0));
94//!
95//! assert!(
96//! state
97//! .insert_payload("population", vec![10_u64, 20, 30])?
98//! .is_none()
99//! );
100//! state
101//! .payload_mut::<Vec<u64>>("population")?
102//! .push(40);
103//! let time = state.advance_simulation_time(None)?;
104//! assert_eq!(time.iteration(), 1);
105//! let population = state.take_payload::<Vec<u64>>("population")?;
106//!
107//! assert_eq!(population, vec![10, 20, 30, 40]);
108//! # Ok(())
109//! # }
110//! ```
111//!
112//! Future orchestration-layer features will organize scoped workflow execution
113//! without changing the public state-value ownership or storage contracts.
114//!
115//! # Release stability
116//!
117//! This crate is a test release. Public API behavior is allowed to change across
118//! updates without backward compatibility guarantees.
119//!
120//! ## Downstream no-overlap policy
121//!
122//! For downstream consumers, preserve boundary ownership:
123//! keep orchestration in `study`, persistence in `storage`, and pure state in
124//! `system_state`/`time_series`. Do not implement overlapping behavior in a
125//! downstream layer; if a seam is missing, negotiate an explicit API addition.
126
127#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
128
129mod clock;
130
131pub mod artifact;
132pub mod configuration;
133pub mod execution;
134pub mod prelude;
135pub mod rng_record;
136pub mod storage;
137#[path = "study.rs"]
138pub mod study;
139pub mod system_state;
140pub mod time_series;