CONTRACT-01 landed its crate, so the local stand-in module goes away and the domain scalars, method payloads, their validation, the canonical digests and the trace format all come from the contract. `src/types.rs` is a facade over that crate plus the few things a coordinator needs that are not part of the type contract: a session-side DomainError, the synthetic composition's schema and event-id derivations, and the coordinator-local ControllerIntent, PortBinding and AgentOutcome that never cross the bus. Consequences worth naming: - Payloads are read and written through DomainType::from_json / to_json instead of serde derives, so a misspelled required field fails where the contract says it should. serde, sha2 and ryu-js leave this crate's dependencies with them. - The step-v1 section 8 trace is the contract's TransitionTrace, with behaviour and operational metadata already separated; the dispatch-order comparison now runs over the contract's own behaviour encoding. - Two things the migration found. IN_PROGRESS is raised strictly before any mutation, so its certainty is "none", not "unknown"; the local module had it wrong. WorldObservation::validate_against checks the views a result carries but does not require every declared view to be present, so requiring them is made explicit in the coordinator's phase C check, where step-v1 puts it. - The lost-Advance-result injection now waits for the worker to report the operation before abandoning the call, so the case it injects really is a loss after dispatch rather than a cancellation before it. Gates: cargo test -p fly-session (61 tests, both transports), cargo clippy --all-targets clean, and the runnable example produces the same behaviour trace over both transports.
55 lines
2.3 KiB
Rust
55 lines
2.3 KiB
Rust
//! The synthetic sequential transaction, run over both transports and printed.
|
|
//!
|
|
//! ```text
|
|
//! cargo run -p fly-session --example session
|
|
//! ```
|
|
//!
|
|
//! Two fake agents, one counter arena, one coordinator, one router. Nothing here needs a ROM,
|
|
//! a dataset, a GPU or a network.
|
|
|
|
use fly_session::types::*;
|
|
use fly_session::harness::{HarnessConfig, SessionHarness, Via};
|
|
|
|
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
|
|
async fn main() {
|
|
for via in [Via::Memory, Via::Unix] {
|
|
let dir = tempfile::tempdir().expect("a temporary directory");
|
|
let mut harness = SessionHarness::start(via, dir.path(), HarnessConfig::default())
|
|
.await
|
|
.expect("the session starts");
|
|
harness.coordinator.bootstrap().await.expect("bootstrap");
|
|
println!("--- {via:?}: Ready(0) with the world stopped at boundary 0");
|
|
let reports = harness.coordinator.run(3).await.expect("three transitions");
|
|
|
|
for (k, transition) in harness.coordinator.trace.transitions.iter().enumerate() {
|
|
let ticks: Vec<String> = transition
|
|
.behaviour
|
|
.agents
|
|
.iter()
|
|
.map(|a| format!("{}={} ticks", a.agent_id, a.ticks_advanced))
|
|
.collect();
|
|
println!(
|
|
"step {k}: {} batch={} boundary={} events={}",
|
|
ticks.join(" "),
|
|
transition.behaviour.batch_id,
|
|
transition.behaviour.acknowledged_boundary,
|
|
transition.behaviour.event_ids.len()
|
|
);
|
|
}
|
|
let progress = harness.coordinator.task_progress();
|
|
println!(
|
|
"{via:?}: {} advances, counter {}, reward {}, {} publications, last boundary {}",
|
|
harness.coordinator.stats().advances,
|
|
progress.integer("counter").unwrap_or_default(),
|
|
progress.number("totalReward").unwrap_or_default(),
|
|
harness.coordinator.stats().publications,
|
|
reports.last().map(|r| r.boundary).unwrap_or_default(),
|
|
);
|
|
// The behaviour trace is what two runs in different dispatch orders must agree on.
|
|
for line in harness.coordinator.trace.behavior() {
|
|
println!(" behaviour: {line}");
|
|
}
|
|
harness.shutdown().await;
|
|
drop(dir);
|
|
}
|
|
}
|