f108291b7f
Architect drift review (scope 77ad046..HEAD): What holds — the #343 reference-semantics hash is code-backed on both output surfaces (record line + trace index), the RiskRegime::Fixed stamp/re-derive lockstep is complete both ways, and both new guide examples build against the binary. Drift resolved in this commit: C24's root-name-gated intake enumeration gains the introspect --taps FILE branch plus its missing per-site pin (byte-identical refusal to the register sibling — the #331 class-enumeration lesson applied); C27 gains the #337 realization note (positive discovery view closes the recovery-only gap); C12's inline-hash sentence updated to the topo parameter; five stale dispatch_run comments reworded to name exec_blueprint_leg as the surviving owner. Remaining drift routed: the unpinned guide op-scripts are a durable debt class, filed as #344 (idea) rather than swept here. Regression gate: aura-bench all five fingerprints OK (report-only deltas within noise on a loaded box; no baseline move, nothing to ratify). refs #337 refs #343
95 lines
5.8 KiB
Markdown
95 lines
5.8 KiB
Markdown
# C12 — The atomic sim unit and the four orchestration axes
|
||
|
||
**Guarantee.** The atomic unit is `(frozen topology + param-set + data-window +
|
||
RNG-seed) → deterministic run → metrics`. Parameters are typed, ranged, runtime
|
||
values injected at graph build — no recompile per param-set; the optimizer sees a
|
||
generic vector of typed ranges. A **bound blueprint param is that param's
|
||
default**: "open" means *must be bound by an axis*, "bound" means *default,
|
||
overridable by an axis*, so a campaign axis (param-sweep) may name a bound
|
||
param — the family boundary re-opens it on the probe and on every member
|
||
reload, and the axis binds it per cell; `exec`'s blueprint leg still requires
|
||
every param resolved (a truly open param refuses), and its own `--override
|
||
NODE.PARAM=VALUE` (#246 residue, #319) reopens exactly the named bound param
|
||
for that one execution — the single-member analogue of a campaign axis. The
|
||
reopened execution's `topology_hash` stays the base document's own — reference
|
||
semantics, not the reopened topology's (#343, revised; full clause in
|
||
[C24](c24-blueprint-data.md)'s "Reproduction identity"). Identity is untouched: `content_id_of` (`crates/aura-research/src/lib.rs`) is
|
||
the one hashing primitive, read directly off the authored document by
|
||
`aura_runner::member`'s `run_signal_r`/`run_blueprint_member` — where the
|
||
manifest's `topology_hash` is computed inline by default (`run_signal_r`'s
|
||
`topo: Option<&str>` parameter's `None` arm, every caller but one; #319 Task 9
|
||
retired the CLI-side wrapper that used to duplicate this one call), or
|
||
supplied by the caller as a ready reference-semantics hash (`Some`, #343
|
||
revised — `exec`'s override branch passes the loaded base document's own id,
|
||
computed before `reopen_all`, so the SAME value reaches both the record line
|
||
and the trace-store persistence) — never a re-opened probe either way, and
|
||
each member manifest records its per-cell bindings (#246, ratified
|
||
2026-07-12; the restriction this amends — axes bind only open knobs — was an
|
||
implementation consequence of `bind()` shrinking the param surface, not a recorded
|
||
decision). Raw data is shared read-only across sims via `Arc<[T]>` (the
|
||
data-server is built for this). Four axes orchestrate the atomic unit:
|
||
(1) param-sweep (grid/random), (2) optimization (argmax metric), (3) walk-forward
|
||
(rolling in-sample optimize + out-of-sample test), (4) Monte-Carlo (N seeded
|
||
realizations perturbing input). **MC = sweep over seeds**; each realization is
|
||
itself deterministic given its seed.
|
||
|
||
**Forbids.** Baking a specific search strategy (Bayesian/genetic) into the
|
||
primitive — those are pluggable policies atop the atomic unit; recompiling on a
|
||
param change.
|
||
|
||
**Why.** A stable primitive + orchestration axes keeps "wahnsinnig schnell"
|
||
(embarrassingly parallel across the unit) cleanly separated from search policy.
|
||
Seed-as-input reconciles Monte-Carlo with C1. The "frozen topology" of the atomic
|
||
unit is one harness instance, selected by the harness's **structural axes** (C20);
|
||
the structural experiment matrix is the outer orchestration over this dimension,
|
||
the tuning sweep the inner (C19/C20).
|
||
|
||
## Current state
|
||
`Harness::run` is typed as a **producer seam** — the object-safe `Source` trait
|
||
(`peek`/`next`, plus `bounds` and a `resident_records()` residency probe;
|
||
`crates/aura-engine/src/harness.rs`) that the k-way merge drives (C3). Two source
|
||
shapes back it. The eager `load_m1_window`/`close_stream` path
|
||
(`crates/aura-ingest/src/lib.rs`), wrapped as `VecSource`, materializes a whole
|
||
stream and is retained for bounded loads. The streaming `M1FieldSource`
|
||
(`crates/aura-ingest/src/lib.rs`) pulls a data-server window lazily, borrowing one
|
||
`Arc<[M1Parsed]>` chunk per pull (zero-copy *within* a source) and decoding each
|
||
`Scalar` on demand, so its **source ring** is resident O(one chunk), not
|
||
O(window length) — `resident_records()` is a *per-source* bound, not
|
||
whole-process RSS.
|
||
|
||
Raw-data sharing is realized both within and across sims. The data-server's
|
||
`FileCache` retains each window's parsed chunks read-only for the pass, so process
|
||
residency is O(records-touched) — the **replay-many** sharing model, not a leak.
|
||
Across sims, the sweep / Monte-Carlo / walk-forward families (axes 2–4) build their
|
||
members over **one** shared `Arc<DataServer>` (one `FileCache`;
|
||
`crates/aura-ingest/src/lib.rs`), so a window is parsed once and every member's
|
||
`M1FieldSource` borrows the same cached `Arc<[M1Parsed]>` chunks. The single-pass
|
||
*parse* cost of a window is tracked as #95.
|
||
|
||
Axis 1 (param-sweep) is built. `GridSpace` enumerates a cartesian lattice over
|
||
discrete per-slot value-lists; `RandomSpace` draws `N` seeded points over typed
|
||
continuous `ParamRange`s (I64 inclusive `[lo,hi]`, F64 half-open `[lo,hi)`),
|
||
validated against the param-space before any run; a `ListSpace` enumerates an
|
||
explicit point list. All implement the `Space` trait the disjoint `sweep` /
|
||
`run_indexed` core is generic over (`crates/aura-engine/src/sweep.rs`), so every
|
||
enumeration runs through one execution path (C1: results in enumeration order, not
|
||
completion order). The other axes are realized as families over that core:
|
||
`walk_forward` + `WindowRoller` (`crates/aura-engine/src/walkforward.rs`) for the
|
||
rolling in-sample/out-of-sample split, `monte_carlo`
|
||
(`crates/aura-backtest/src/mc.rs`) for the seed sweep; optimization is argmax over
|
||
a sweep's metrics, a policy atop the core rather than a baked-in strategy. The
|
||
seeded sampler reuses the bit-stable `SplitMix64`
|
||
(`crates/aura-analysis/src/lib.rs`) as a **code-path-disjoint** instance from the
|
||
data-edge seed RNG (the source-seam firewall, #52/#71: they share only the `u64`
|
||
type, never a path).
|
||
|
||
## See also
|
||
- [C1](c01-determinism.md)
|
||
- [C11](c11-sources-record-replay.md)
|
||
- [C18](c18-registry.md)
|
||
- [C19](c19-bootstrap.md)
|
||
- [C20](c20-strategy-harness.md)
|
||
- [C23](c23-graph-compilation.md)
|
||
|
||
> History: [c12-atomic-sim-unit.history.md](c12-atomic-sim-unit.history.md)
|