1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// SPDX-FileCopyrightText: 2026 Bruno Meilick
// SPDX-License-Identifier: LicenseRef-Anapao-FreeUse-NoCopy-NoDerivatives
//
// All rights reserved.
//
// This file is part of Anapao and is proprietary software.
// Unauthorized copying, modification, or distribution is prohibited.
//! Anapao — library-only deterministic simulation testing utility.
//!
//! Compile a declarative [`ScenarioSpec`], run seeded single simulations or Monte
//! Carlo batches, evaluate typed [`Expectation`]s, and persist CI-friendly artifact
//! packs. Prefer [`Simulator`] as the public entrypoint; its compiled execution
//! plan is intentionally opaque.
//!
//! ## Concepts
//! - `ScenarioSpec`: declarative simulation graph (nodes, edges, end conditions, metrics).
//! - `Scenario`: immutable, semantically checked scenario domain value.
//! - `ScenarioBuilder`: conventional checked Rust authoring with duplicate rejection.
//! - `CompiledScenario`: opaque execution plan produced from either scenario representation.
//! - `RunConfig`: deterministic single-run controls (`seed`, `max_steps`, diagnostic capture).
//! - `BatchConfig`: deterministic Monte Carlo controls (`runs`, `base_seed`, execution mode,
//! aggregate metric sampling).
//! - `BatchRunTemplate`: seed-agnostic per-run defaults used by `BatchConfig`.
//! - `Expectation`: typed assertions evaluated against run or batch reports.
//! - Artifacts: manifested CI-friendly outputs (`events.jsonl`, `series.csv`, `summary.csv`, ...).
//!
//! Terminal node and metric maps are always retained. [`CaptureConfig`] controls diagnostic
//! snapshots, transfer records, variable snapshots, and single-run series; [`AggregationConfig`]
//! controls batch metric series only. Event sinks are live streams and do not depend on either
//! retention policy. Final assertions therefore work with no series, while step and series
//! assertions require explicitly retained evidence.
//!
//! ## Stable Documents and Checked Authoring
//!
//! [`ScenarioSpec`] remains the serde wire contract. Deserialize it first, then cross the
//! semantic boundary explicitly with [`Scenario::try_from`]. Checked values are not a second
//! serde format.
//!
//! ```rust
//! use anapao::{Scenario, ScenarioSpec};
//!
//! let document = serde_json::to_string(&anapao::testkit::fixture_scenario()).unwrap();
//! let dto: ScenarioSpec = serde_json::from_str(&document).unwrap();
//! let checked = Scenario::try_from(dto).unwrap();
//!
//! assert_eq!(checked.id().as_str(), "scenario-testkit");
//! ```
//!
//! For conventional Rust authoring, use the checked builder and family constructors. This
//! complete flow creates several node families, resource and state connections, run controls,
//! compiles the checked value, and executes it.
//!
//! ```rust
//! use std::num::NonZeroU64;
//! use anapao::types::{
//! EdgeId, EndConditionSpec, MetricKey, NodeId, ResourceConnection, RunConfig,
//! ScenarioBuilder, ScenarioEdge, ScenarioId, ScenarioNode, StateConnection,
//! StateConnectionRole, StateTarget, TransferSpec,
//! };
//! use anapao::Simulator;
//!
//! let source = NodeId::fixture("source");
//! let pool = NodeId::fixture("pool");
//! let sink = NodeId::fixture("sink");
//! let authored = ScenarioBuilder::new(ScenarioId::fixture("checked-authoring"))
//! .with_title("Checked authoring")
//! .with_description("resource and state flow")
//! .with_tag("docs")
//! .with_node(ScenarioNode::source(source.clone()).with_initial_value(2.0))?
//! .with_node(ScenarioNode::pool(pool.clone(), Default::default()).with_label("buffer"))?
//! .with_node(ScenarioNode::sink(sink.clone()))?
//! .with_edge(ScenarioEdge::resource(
//! EdgeId::fixture("source-pool"), source.clone(), pool.clone(),
//! TransferSpec::Fixed { amount: 1.0 },
//! ResourceConnection::default().with_token_size(NonZeroU64::new(1).unwrap()),
//! ))?
//! .with_edge(ScenarioEdge::resource(
//! EdgeId::fixture("pool-sink"), pool.clone(), sink,
//! TransferSpec::Remaining, ResourceConnection::default(),
//! ))?
//! .with_edge(ScenarioEdge::state(
//! EdgeId::fixture("source-pool-state"), source, pool,
//! TransferSpec::Remaining,
//! StateConnection::new(StateConnectionRole::Modifier, "+1", StateTarget::Node),
//! ))?
//! .with_end_condition(EndConditionSpec::MaxSteps { steps: 2 })
//! .with_tracked_metric(MetricKey::fixture("sink"))
//! .with_metadata("owner", "docs")
//! .build()?;
//!
//! let compiled = Simulator::compile_checked(authored)?;
//! assert_eq!(compiled.source_spec().title.as_deref(), Some("Checked authoring"));
//! let report = Simulator::run(&compiled, &RunConfig::for_seed(39)).unwrap();
//! assert!(report.completed);
//! # Ok::<(), anapao::error::SetupError>(())
//! ```
//!
//! Existing DTO authoring remains supported: pass a [`ScenarioSpec`] to
//! [`Simulator::compile`]. Both compile routes converge on the same opaque plan.
//!
//! ## Declarative checked authoring
//!
//! [`scenario!`] is the single declarative checked-authoring macro. It produces the same checked
//! [`Scenario`] as [`ScenarioBuilder`], rather than a serde document or a second validation path.
//! It returns `Result<Scenario, SetupError>`: use `?` when setup errors should propagate, or
//! match `Err` when a caller needs to handle them. The exact queue-flow intake form is:
//!
//! ```rust
//! let scenario = anapao::scenario! {
//! id: "queue-flow";
//!
//! nodes {
//! source: Source { initial: 64.0 };
//! delay: Delay { steps: 2 };
//! sink: Pool;
//! }
//! edges {
//! source_delay: source -> delay => fixed(1.0);
//! delay_sink: delay -> sink => remaining;
//! }
//! }?;
//! # let _ = scenario;
//! # Ok::<(), anapao::error::SetupError>(())
//! ```
//!
//! The macro takes scenario fields in this canonical order: `id`, optional `title`,
//! `description`, `tags`, `variables`, and `metadata`; required `nodes` and `edges`; then
//! optional `track` and repeated `end` statements. Sections are semicolon-separated. A native
//! node config/mode and `config: ...` are exclusive. Node and edge symbols map to their exact
//! spelling in distinct namespaces; tracked metrics are node-backed, and state targets may use
//! forward edge symbols. It evaluates each expression once, uses `$crate` hygiene (including when
//! this dependency is renamed), and adds no panic path; builder validation supplies semantic
//! errors. These grammar, mapping, evaluation, result/error, and root/prelude paths are public
//! 0.2 compatibility promises.
//!
//! ## Deterministic Single Run
//! ```rust
//! use anapao::{Simulator, testkit};
//! use anapao::types::MetricKey;
//!
//! let compiled = Simulator::compile(testkit::fixture_scenario()).unwrap();
//! let report = Simulator::run(&compiled, &testkit::deterministic_run_config()).unwrap();
//!
//! assert!(report.completed);
//! assert_eq!(report.steps_executed, 3);
//! assert_eq!(report.final_metrics.get(&MetricKey::fixture("sink")), Some(&3.0));
//! ```
//!
//! ## Deterministic Batch (Monte Carlo)
//! ```rust
//! use anapao::{Simulator, testkit};
//! use anapao::types::MetricKey;
//!
//! let compiled = Simulator::compile(testkit::fixture_scenario()).unwrap();
//! let batch = Simulator::run_batch(&compiled, &testkit::deterministic_batch_config()).unwrap();
//!
//! assert_eq!(batch.completed_runs, batch.requested_runs);
//! assert!(batch.runs.windows(2).all(|window| window[0].run_index < window[1].run_index));
//! assert!(batch.aggregate_series.contains_key(&MetricKey::fixture("sink")));
//! ```
//!
//! ## Assertions Plus Event Stream
//! ```rust
//! use anapao::{Simulator, testkit};
//! use anapao::assertions::{Expectation, MetricSelector};
//! use anapao::events::VecEventSink;
//! use anapao::types::MetricKey;
//!
//! let compiled = Simulator::compile(testkit::fixture_scenario()).unwrap();
//! let expectations = vec![Expectation::Equals {
//! metric: MetricKey::fixture("sink"),
//! selector: MetricSelector::Final,
//! expected: 3.0,
//! }];
//!
//! let mut sink = VecEventSink::new();
//! let (_report, assertion_report) = Simulator::run_with_assertions_and_sink(
//! &compiled,
//! &testkit::deterministic_run_config(),
//! &expectations,
//! &mut sink,
//! )
//! .unwrap();
//!
//! assert!(assertion_report.is_success());
//! assert!(sink
//! .events()
//! .iter()
//! .any(|event| event.event_name() == "assertion_checkpoint"));
//! ```
//!
//! ## Full Playbook (Setup -> Run -> Assert -> Artifacts)
//! ```no_run
//! use anapao::{Simulator, testkit};
//! use anapao::artifact::write_run_artifacts_with_assertions;
//! use anapao::assertions::{Expectation, MetricSelector};
//! use anapao::events::VecEventSink;
//! use anapao::types::MetricKey;
//!
//! // 1) Setup scenario + compile.
//! let scenario = testkit::fixture_scenario();
//! let compiled = Simulator::compile(scenario).unwrap();
//!
//! // 2) Setup run config + expectations.
//! let run_config = testkit::deterministic_run_config();
//! let expectations = vec![Expectation::Equals {
//! metric: MetricKey::fixture("sink"),
//! selector: MetricSelector::Final,
//! expected: 3.0,
//! }];
//!
//! // 3) Run simulation and evaluate assertions.
//! let mut sink = VecEventSink::new();
//! let (run_report, assertion_report) = Simulator::run_with_assertions_and_sink(
//! &compiled,
//! &run_config,
//! &expectations,
//! &mut sink,
//! )
//! .unwrap();
//! assert!(assertion_report.is_success());
//!
//! // 4) Persist artifact pack for CI/debugging.
//! let output_dir = std::env::temp_dir().join("anapao-doc-playbook");
//! let manifest = write_run_artifacts_with_assertions(
//! &output_dir,
//! &run_report,
//! sink.events(),
//! Some(&assertion_report),
//! )
//! .unwrap();
//! assert!(manifest.artifacts.contains_key("manifest"));
//! ```
pub use ;
pub use ;
pub use CompiledScenario;
pub use Simulator;
pub use ;