fieldtest: milestone the-world-orchestration-families — 4 examples, 4 findings
Milestone-close gate for "The World, part II — orchestration families".
Four end-to-end scenarios derived top-down from the milestone promise,
each built from HEAD and run as a downstream consumer through the public
API + CLI only (no crates/*/src read):
- mw_3 (headline): real EURUSD-M1 walk-forward composing all four axes
(grid sweep + optimize in-sample, OOS stitch) over the M1FieldSource
seam + lineage — 5 windows, 145 200-pt stitched curve, C2 held.
- mw_2: monte_carlo over 128 seeds, reproducible McFamily (C1) + aggregate.
- mw_1: random sweep -> optimize -> 64-member lineage round-trip.
- mw_4: family-lineage CLI transcript.
Findings: 4 working (promise empirically delivered), 1 bug, 3 friction.
- bug F5: `aura runs list`/`rank` cannot read a pre-0047 runs.jsonl — the
cycle-0047 typed-Scalar params migration (86746e3) left the persisted
flat store unmigrated; load() fails at the first bare float (+ exits 0).
- friction F6: no epoch_ns_to_unix_ms inverse for real-data walk-forward.
- friction F7: DataServer/DEFAULT_DATA_PATH not re-exported by aura-ingest.
- friction F8: family store is directory-keyed, undocumented on Registry::open.
Spec: docs/specs/fieldtest-milestone-the-world-orchestration-families.md
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
# Fieldtest — milestone "The World, part II — orchestration families" — 2026-06-17
|
||||
|
||||
**Status:** Draft — awaiting orchestrator triage
|
||||
**Author:** fieldtester (dispatched by fieldtest skill, milestone-close gate)
|
||||
|
||||
## Scope
|
||||
|
||||
Milestone-18 promised the four C12 orchestration-family axes — parameter-sweep
|
||||
(grid + random), optimize/argmax, walk-forward, Monte-Carlo — delivered
|
||||
end-to-end through aura's public Rust API and CLI, resting on three substrate
|
||||
guarantees: a lazy `Source` ingestion seam (synthetic + real M1), seed-as-input
|
||||
reproducibility, and registry lineage that persists each family as a queryable
|
||||
unit (`aura runs families` / `aura runs family <id> [rank <metric>]`). This
|
||||
field test composes those axes top-down from the promise into four realistic
|
||||
downstream tasks, run from a standalone consumer crate (path-deps only; public
|
||||
interface = design ledger + glossary + specs 0041–0049 + `cargo doc` rustdoc; no
|
||||
`crates/*/src` was read) plus the `aura` CLI driven as a researcher would. Every
|
||||
binary was rebuilt from HEAD (`8b22fa6`) and run; the real-data scenario streamed
|
||||
the local EURUSD M1 archive.
|
||||
|
||||
## Examples
|
||||
|
||||
### fieldtests/milestone-the-world-orchestration-families/mw_3_walkforward_real.rs — real-data walk-forward (THE HEADLINE)
|
||||
- Walk-forward over real EURUSD M1 close bars: roll 4-month IS / 1-month OOS over
|
||||
a 9-month span; per window, grid-sweep + `optimize` the in-sample slice by
|
||||
total_pips, run the chosen params out-of-sample, stitch the OOS months into one
|
||||
continuous pip curve, then persist the per-window OOS reports as a WalkForward
|
||||
lineage family.
|
||||
- Fits the milestone: composes axes 1 (in-sample grid) + 2 (optimize) + 3
|
||||
(walk-forward) over the **real-data** Source seam (`M1FieldSource`) plus
|
||||
registry lineage — exactly the promise's headline scenario.
|
||||
- Outcome: built ✓, ran ✓, matched expected ✓. 5 windows; per-window optimize
|
||||
reacted to the data (window 4 chose slow=50, the others slow=20); stitched curve
|
||||
145 200 points, final cumulative −2.2884 pips; C2 no-look-ahead held on every
|
||||
window; lineage round-tripped 5 members as `eurusd-wfo-0`.
|
||||
|
||||
### fieldtests/milestone-the-world-orchestration-families/mw_2_monte_carlo_robustness.rs — Monte-Carlo robustness over a seed set
|
||||
- `monte_carlo` over 128 seeds with a fixed strategy and `SyntheticSpec::source(seed)`;
|
||||
read the aggregate metric distribution (mean + p5/p50/p95), confirm same seed
|
||||
set reproduces the whole `McFamily`, persist + round-trip the MC family.
|
||||
- Fits the milestone: axis 4 + seed-as-input + lineage.
|
||||
- Outcome: built ✓, ran ✓, matched expected ✓. 128 distinct draws (seed truly
|
||||
perturbs), ordered quantiles, byte-identical re-run (`family == family2`, C1),
|
||||
128-member MonteCarlo lineage family.
|
||||
|
||||
### fieldtests/milestone-the-world-orchestration-families/mw_1_random_tune_lineage.rs — random tune → optimize → lineage
|
||||
- Draw 64 seeded random points over continuous `ParamRange`s, run the SAME `sweep`
|
||||
the grid uses (the "one unified sweep path"), `optimize` the best by total_pips,
|
||||
persist as a named Sweep family, round-trip, re-run mints a fresh id.
|
||||
- Fits the milestone: axis 1 (random) + axis 2 + lineage over the synthetic seam.
|
||||
- Outcome: built ✓, ran ✓, matched expected ✓ (after a fixture cleanup fix — see
|
||||
finding F8). 33 distinct total_pips over 64 points (family spreads); `optimize`
|
||||
== manual argmax; 64-member round-trip; re-run → `eurusd-tune-1`.
|
||||
|
||||
### fieldtests/milestone-the-world-orchestration-families/out_mw_4_cli_lineage.txt — family-lineage CLI surface (CLI transcript)
|
||||
- The family-lineage CLI driven end-to-end against the repo `runs/` store:
|
||||
`aura sweep --name`, `aura mc --name`, `aura runs families`, `aura runs family
|
||||
<id>`, `aura runs family <id> rank total_pips`, unknown-id, and `aura runs list`.
|
||||
- Fits the milestone: the registry-lineage CLI surface the promise names verbatim.
|
||||
- Outcome: ran ✓; the family surface (sweep/mc persist, `runs families`,
|
||||
`runs family`, within-family `rank`) all worked; **`runs list` / `runs rank`
|
||||
surfaced a bug** (finding F5).
|
||||
|
||||
## Findings
|
||||
|
||||
### [working] Real-data walk-forward composes all four axes end-to-end
|
||||
- Example: mw_3.
|
||||
- What happened: `walk_forward(roller, space, |bounds| { sweep+optimize in-sample;
|
||||
run OOS })` over `M1FieldSource`-streamed EURUSD M1 produced 5 windows, a
|
||||
145 200-point stitched OOS curve, per-window chosen params that vary with the
|
||||
data, and a 5-member WalkForward lineage family — correct on first run.
|
||||
- Why working: this is the milestone's central promise (the differentiator over a
|
||||
single backtest). The composition a researcher reaches for — roller + in-sample
|
||||
optimize + held-out OOS + stitch + persist — reads as ordinary code and runs
|
||||
deterministically over real data with no look-ahead (C2 structural).
|
||||
- Recommended action: carry-on. Protect with a milestone-level integration test if
|
||||
one does not already exist.
|
||||
|
||||
### [working] Monte-Carlo over a seed set is reproducible and yields a real distribution
|
||||
- Example: mw_2.
|
||||
- What happened: 128 seeds → 128 distinct draws, ordered aggregate quantiles, and
|
||||
`monte_carlo(...) == monte_carlo(...)` byte-for-byte (C1). Each draw's
|
||||
`manifest.seed` equals its input seed.
|
||||
- Why working: seed-as-input (Fork B) plus the MC family delivers the robustness
|
||||
question directly; reproducibility is checkable in one `assert_eq!`.
|
||||
- Recommended action: carry-on.
|
||||
|
||||
### [working] Random sweep + optimize + lineage round-trip
|
||||
- Example: mw_1.
|
||||
- What happened: the random half of the sweep path drives the same `sweep` core,
|
||||
`optimize` returns the exact argmax, and the family persists + round-trips as a
|
||||
64-member unit; a same-name re-run mints `-1`.
|
||||
- Why working: confirms the "one unified sweep path" (grid and random both feed
|
||||
one enumeration-agnostic core) and the lineage round-trip empirically.
|
||||
- Recommended action: carry-on.
|
||||
|
||||
### [working] The family-lineage CLI surface lists and ranks families as units
|
||||
- Example: mw_4 transcript.
|
||||
- What happened: `aura sweep --name mw-grid` and `aura mc --name mw-robust` persist
|
||||
families; `aura runs families` lists `{mw-grid-0 Sweep 4}` + `{mw-robust-0
|
||||
MonteCarlo 3}`; `aura runs family mw-grid-0 rank total_pips` ranks the members
|
||||
best-first; an unknown id prints nothing and exits 0 (per spec 0045).
|
||||
- Why working: the CLI half of the lineage promise behaves exactly as the spec's
|
||||
worked console session shows.
|
||||
- Recommended action: carry-on.
|
||||
|
||||
### [bug] `aura runs list` / `aura runs rank` cannot read the existing runs.jsonl (typed-params schema break, unmigrated store)
|
||||
- Example: mw_4 transcript (last two invocations).
|
||||
- What happened, verbatim:
|
||||
```
|
||||
$ aura runs list
|
||||
aura: registry parse error at line 1: expected value at line 1 column 94
|
||||
(exit 0)
|
||||
$ aura runs rank total_pips
|
||||
aura: registry parse error at line 1: expected value at line 1 column 94
|
||||
```
|
||||
`runs/runs.jsonl` line 1 column 94 is the bare float `2.0` in
|
||||
`["sma_cross.fast",2.0]`. `RunManifest.params` was migrated to typed `Scalar`
|
||||
(`{"I64":2}` / `{"F64":2.0}`) in cycle 0047 (commit 86746e3, inside the milestone
|
||||
range), but the persisted flat store was not migrated, so `Registry::load`
|
||||
fails to deserialize any pre-0047 line. The lineage path is unaffected
|
||||
(`families.jsonl` is written fresh in the new format — `runs families` /
|
||||
`runs family` succeeded).
|
||||
- Why bug: `aura runs list` is documented to list the stored runs; on the
|
||||
repo's own checked-in store it instead errors out. The store is a real artefact
|
||||
(`runs/runs.jsonl` is in the tree, albeit under a gitignored dir), so a
|
||||
researcher who ran `aura sweep`/`aura run` before the 0047 upgrade loses read
|
||||
access to their run history. Secondary: a parse error prints to stderr but the
|
||||
process exits **0**, so a script cannot detect the failure by status.
|
||||
- Repro: `cargo run -p aura-cli -- runs list` against the current `runs/runs.jsonl`.
|
||||
- Recommended action: debug. RED test: `Registry::load` over a pre-0047
|
||||
`Vec<(String, f64)>`-params line. The fix is a migration/back-compat read (accept
|
||||
both the bare-float and the typed forms) or a one-shot store migration; separately
|
||||
decide whether a parse error should exit non-zero.
|
||||
|
||||
### [friction] Real-data walk-forward must hand-invert the ms↔ns time convention
|
||||
- Example: mw_3.
|
||||
- What happened: `WindowRoller` / `WindowBounds` / `RunManifest.window` are in
|
||||
epoch-ns, but `M1FieldSource::open(from_ms, to_ms)` wants Unix-ms. aura-ingest
|
||||
exports `unix_ms_to_epoch_ns` (ms→ns) but **no inverse**, so the closure
|
||||
hand-writes `ts.0 / 1_000_000` to feed the roller's ns bounds back into the
|
||||
ms-typed source — re-deriving a normalization the seam already owns.
|
||||
- Why friction: the task completes, but a real-data walk-forward (the headline
|
||||
composition) forces the consumer to re-implement the ns→ms half of a convention
|
||||
the public surface only provides in one direction. A transposed divisor is a
|
||||
silent wrong-window bug class the seam was built to prevent.
|
||||
- Recommended action: plan (tidy iteration) — export an `epoch_ns_to_unix_ms`
|
||||
inverse beside `unix_ms_to_epoch_ns`, or have `M1FieldSource::open` accept a
|
||||
`Timestamp` window directly so the roller's bounds feed straight in.
|
||||
|
||||
### [friction] DataServer / DEFAULT_DATA_PATH are not re-exported by aura-ingest
|
||||
- Example: mw_3 (Cargo.toml + `use data_server::{DataServer, DEFAULT_DATA_PATH}`).
|
||||
- What happened: `M1FieldSource::open` takes `&Arc<DataServer>`, but aura-ingest
|
||||
re-exports neither `DataServer` nor the data path constant. To construct the
|
||||
required server, the consumer crate must add the external
|
||||
`data-server` git dependency directly and import from it — discovered only by
|
||||
reading the `--real` commit body (`data_server::DEFAULT_DATA_PATH`), not from any
|
||||
aura-ingest rustdoc or example.
|
||||
- Why friction: the headline real-data task is reachable only if the consumer
|
||||
knows to pull and name a transitive external crate whose construction is
|
||||
undocumented in aura's public surface. The data path `/mnt/tickdata/Pepperstone`
|
||||
appears only in plan/spec prose, never in the API docs a consumer reads.
|
||||
- Recommended action: plan — re-export `data_server::DataServer` (and a data-path
|
||||
accessor) from aura-ingest, or add an aura-ingest constructor
|
||||
(`M1FieldSource::open_default_archive(symbol, from, to, field)`) so a real-data
|
||||
source is buildable from aura-ingest alone.
|
||||
|
||||
### [friction] The family store is keyed by the runs DIRECTORY, not the runs path; Registry::open rustdoc is silent
|
||||
- Example: mw_1 (the round-trip assert first found 2 families instead of 1).
|
||||
- What happened: `append_family` writes to `path.with_file_name("families.jsonl")`
|
||||
— a fixed filename in the runs path's directory. Two `Registry::open` calls with
|
||||
different runs filenames in the same directory therefore share **one** family
|
||||
store. A first fixture attempt isolated runs by a per-process *filename*
|
||||
(`mw1-runs-<pid>.jsonl`) and got a shared `/tmp/families.jsonl`, so the round-trip
|
||||
recovered 2 families. The sibling path is documented on `append_family`, but
|
||||
`Registry::open`'s own rustdoc ("Bind to a JSONL path") does not mention that a
|
||||
second, directory-keyed store rides along.
|
||||
- Why friction: the natural "isolate a temp store by unique filename" reflex
|
||||
silently fails for families; the consumer must know to isolate by directory. The
|
||||
fixture had to switch to a per-process temp *directory*.
|
||||
- Recommended action: ratify or tighten the design ledger — note on
|
||||
`Registry::open` (and/or the C18 ledger entry) that a `Registry` owns two
|
||||
directory-co-located stores (`runs.jsonl` + `families.jsonl`), so isolation is
|
||||
per-directory. (Behaviour itself is a reasonable design; the silence is the gap.)
|
||||
|
||||
## Recommendation summary
|
||||
|
||||
| Finding | Class | Action |
|
||||
|---|---|---|
|
||||
| F1 real-data walk-forward composes all axes | working | carry-on |
|
||||
| F2 Monte-Carlo reproducible + distribution | working | carry-on |
|
||||
| F3 random sweep + optimize + lineage | working | carry-on |
|
||||
| F4 family-lineage CLI lists/ranks units | working | carry-on |
|
||||
| F5 `runs list`/`rank` break on pre-0047 store | bug | debug |
|
||||
| F6 no ns→ms inverse for real-data WFO | friction | plan |
|
||||
| F7 DataServer not re-exported by aura-ingest | friction | plan |
|
||||
| F8 family store keyed by directory, undocumented on `open` | friction | ratify / tighten ledger |
|
||||
@@ -0,0 +1,985 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aura-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aura-engine"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aura-core",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aura-ingest"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aura-core",
|
||||
"aura-engine",
|
||||
"data-server",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aura-registry"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aura-engine",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aura-std"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aura-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.13+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-server"
|
||||
version = "0.1.0"
|
||||
source = "git+http://192.168.178.103:3000/Brummel/data-server.git?branch=main#0f5e6655b90eeab0f43a8b0f330b8d1632e80ed4"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"regex",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate64"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||
|
||||
[[package]]
|
||||
name = "lzma-rs"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lzma-sys"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mw18-fieldtest"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"aura-core",
|
||||
"aura-engine",
|
||||
"aura-ingest",
|
||||
"aura-registry",
|
||||
"aura-std",
|
||||
"data-server",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde_core",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.4+wasi-0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
|
||||
[[package]]
|
||||
name = "xz2"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
|
||||
dependencies = [
|
||||
"lzma-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arbitrary",
|
||||
"bzip2",
|
||||
"constant_time_eq",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"deflate64",
|
||||
"displaydoc",
|
||||
"flate2",
|
||||
"getrandom",
|
||||
"hmac",
|
||||
"indexmap",
|
||||
"lzma-rs",
|
||||
"memchr",
|
||||
"pbkdf2",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"time",
|
||||
"xz2",
|
||||
"zeroize",
|
||||
"zopfli",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"log",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.16+zstd.1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
@@ -0,0 +1,56 @@
|
||||
# Standalone downstream-consumer crate for the milestone-18 fieldtest
|
||||
# ("The World, part II — orchestration families").
|
||||
#
|
||||
# This is the MILESTONE-close fieldtest: it composes the four orchestration-family
|
||||
# axes (sweep / optimize / walk-forward / Monte-Carlo) end to end, the way a
|
||||
# downstream researcher would, exercising the three substrate guarantees (Source
|
||||
# ingestion seam, seed-as-input, registry lineage) underneath them.
|
||||
#
|
||||
# Like the per-cycle fixtures, this is NOT a member of the aura workspace — it
|
||||
# path-deps the engine crates exactly as a real C16 research project would, then
|
||||
# drives the public surface ONLY (design ledger + glossary + specs 0041-0049 +
|
||||
# `cargo doc` rustdoc; no crates/*/src was read). The real-data scenario depends
|
||||
# on `data-server` directly (the git dep aura-ingest itself uses), because
|
||||
# `M1FieldSource::open` takes `&Arc<DataServer>` and aura-ingest does not
|
||||
# re-export DataServer — a downstream consumer must reach for the external crate.
|
||||
#
|
||||
# Built/run via, e.g.:
|
||||
# cargo run --manifest-path fieldtests/milestone-the-world-orchestration-families/Cargo.toml --bin mw_3_walkforward_real
|
||||
# so HEAD source is always what runs.
|
||||
#
|
||||
# Empty [workspace] table: marks this fixture crate as its OWN workspace root.
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "mw18-fieldtest"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
aura-core = { path = "../../crates/aura-core" }
|
||||
aura-engine = { path = "../../crates/aura-engine" }
|
||||
aura-registry = { path = "../../crates/aura-registry" }
|
||||
aura-ingest = { path = "../../crates/aura-ingest" }
|
||||
aura-std = { path = "../../crates/aura-std" }
|
||||
# Reached for directly: M1FieldSource::open wants &Arc<DataServer>, and aura-ingest
|
||||
# re-exports neither DataServer nor DEFAULT_DATA_PATH. A real-data consumer must
|
||||
# pull the same external git dep aura-ingest uses.
|
||||
data-server = { git = "http://192.168.178.103:3000/Brummel/data-server.git", branch = "main" }
|
||||
|
||||
[[bin]]
|
||||
name = "mw_1_random_tune_lineage"
|
||||
path = "mw_1_random_tune_lineage.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "mw_2_monte_carlo_robustness"
|
||||
path = "mw_2_monte_carlo_robustness.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "mw_3_walkforward_real"
|
||||
path = "mw_3_walkforward_real.rs"
|
||||
|
||||
# Scenario 4 (the family-lineage CLI surface) is exercised directly through the
|
||||
# `aura` binary, since the canonical consumer form for a CLI tool is the CLI
|
||||
# invocation itself, not a Rust program. Its transcript lives in
|
||||
# out_mw_4_cli_lineage.txt; there is no [[bin]] for it.
|
||||
@@ -0,0 +1,198 @@
|
||||
// Milestone-18 fieldtest — scenario 1: RANDOM PARAM-SWEEP, optimized, persisted
|
||||
// as a lineage family, round-tripped.
|
||||
//
|
||||
// Composes: axis 1 (random sample, the "one unified sweep path"), axis 2
|
||||
// (optimize / argmax by a named metric), the Source ingestion seam (synthetic
|
||||
// VecSource), and registry lineage (append_family + group_families round-trip).
|
||||
//
|
||||
// The task a downstream researcher does: "tune a 2-SMA-cross strategy by drawing
|
||||
// 64 seeded random points over continuous ranges, pick the best by total_pips,
|
||||
// then persist the whole sweep as ONE named family I can re-list and rank later."
|
||||
//
|
||||
// PUBLIC INTERFACE ONLY: API discovered from the design ledger (C12), glossary,
|
||||
// specs 0028/0045/0046/0048/0049, and `cargo doc --workspace --no-deps` rustdoc.
|
||||
// No crates/*/src was read.
|
||||
|
||||
use std::sync::mpsc;
|
||||
|
||||
use aura_core::{Cell, Firing, Scalar, ScalarKind, Timestamp};
|
||||
use aura_engine::{
|
||||
f64_field, summarize, sweep, BlueprintNode, Composite, Edge, OutField, ParamRange, RandomSpace,
|
||||
Role, RunManifest, RunReport, SweepFamily, Target, VecSource,
|
||||
};
|
||||
use aura_registry::{group_families, optimize, sweep_member_reports, FamilyKind, Registry};
|
||||
use aura_std::{Exposure, Recorder, SimBroker, Sma, Sub};
|
||||
|
||||
fn sma_cross() -> Composite {
|
||||
Composite::new(
|
||||
"sma_cross",
|
||||
vec![
|
||||
Sma::builder().named("fast").into(),
|
||||
Sma::builder().named("slow").into(),
|
||||
Sub::builder().into(),
|
||||
],
|
||||
vec![
|
||||
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
|
||||
],
|
||||
vec![Role {
|
||||
name: "price".into(),
|
||||
targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }],
|
||||
source: None,
|
||||
}],
|
||||
vec![OutField { node: 2, field: 0, name: "out".into() }],
|
||||
)
|
||||
}
|
||||
|
||||
fn harness_with_sinks() -> (
|
||||
Composite,
|
||||
mpsc::Receiver<(Timestamp, Vec<Scalar>)>,
|
||||
mpsc::Receiver<(Timestamp, Vec<Scalar>)>,
|
||||
) {
|
||||
let (tx_eq, rx_eq) = mpsc::channel();
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let bp = Composite::new(
|
||||
"harness",
|
||||
vec![
|
||||
BlueprintNode::Composite(sma_cross()),
|
||||
Exposure::builder().into(),
|
||||
SimBroker::builder(1e-4).into(),
|
||||
Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_eq).into(),
|
||||
Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_ex).into(),
|
||||
],
|
||||
vec![
|
||||
Edge { from: 0, to: 1, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 2, slot: 0, from_field: 0 },
|
||||
Edge { from: 2, to: 3, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 4, slot: 0, from_field: 0 },
|
||||
],
|
||||
vec![Role {
|
||||
name: "price".into(),
|
||||
targets: vec![Target { node: 0, slot: 0 }, Target { node: 2, slot: 1 }],
|
||||
source: Some(ScalarKind::F64),
|
||||
}],
|
||||
vec![],
|
||||
);
|
||||
(bp, rx_eq, rx_ex)
|
||||
}
|
||||
|
||||
fn synthetic_prices() -> Vec<(Timestamp, Scalar)> {
|
||||
let prices = [
|
||||
1.00, 1.01, 1.02, 1.03, 1.05, 1.08, 1.11, 1.10, 1.06, 1.04, 1.02, 1.01, 1.03, 1.07, 1.12,
|
||||
1.15, 1.13, 1.09, 1.05, 1.02,
|
||||
];
|
||||
prices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &p)| (Timestamp(60_000_000_000 * i as i64), Scalar::f64(p)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn run_one(point: &[Cell], prices: &[(Timestamp, Scalar)]) -> RunReport {
|
||||
let (bp, rx_eq, rx_ex) = harness_with_sinks();
|
||||
let mut h = bp
|
||||
.bootstrap_with_cells(point)
|
||||
.expect("random point is kind-checked against the param-space");
|
||||
// The Source ingestion seam: run() consumes Vec<Box<dyn Source>>, not a Vec.
|
||||
h.run(vec![Box::new(VecSource::new(prices.to_vec()))]);
|
||||
drop(h);
|
||||
let equity = f64_field(&rx_eq.try_iter().collect::<Vec<_>>(), 0);
|
||||
let exposure = f64_field(&rx_ex.try_iter().collect::<Vec<_>>(), 0);
|
||||
RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "fieldtest".into(),
|
||||
params: vec![],
|
||||
window: (Timestamp(0), Timestamp(60_000_000_000 * 20)),
|
||||
seed: 0,
|
||||
broker: "sim-optimal".into(),
|
||||
},
|
||||
metrics: summarize(&equity, &exposure),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let prices = synthetic_prices();
|
||||
let space = harness_with_sinks().0.param_space();
|
||||
|
||||
// axis 1 (random): draw 64 seeded points over continuous ranges (positional,
|
||||
// parallel to param_space()). RandomBinder would let me name them; here the
|
||||
// grid-style positional ParamRange is what the headline sweep uses.
|
||||
let ranges = vec![
|
||||
ParamRange::i64(2, 8), // sma_cross.fast.length
|
||||
ParamRange::i64(10, 30), // sma_cross.slow.length
|
||||
ParamRange::f64(0.5, 4.0), // exposure.scale
|
||||
];
|
||||
let seed = 0xA11CE;
|
||||
let rand_space =
|
||||
RandomSpace::new(&space, ranges, 64, seed).expect("ranges well-formed for the space");
|
||||
println!("axis 1 (random): {} points, seed {:#x}", rand_space.len(), seed);
|
||||
|
||||
// The SAME sweep core the grid uses — `sweep` is generic over impl Space.
|
||||
let family: SweepFamily = sweep(&rand_space, |point: &[Cell]| run_one(point, &prices));
|
||||
assert_eq!(family.points.len(), 64);
|
||||
|
||||
// Did the random sweep actually spread, or collapse? (the "one unified sweep
|
||||
// path" must produce a real family over the synthetic source).
|
||||
let distinct: std::collections::BTreeSet<String> = family
|
||||
.points
|
||||
.iter()
|
||||
.map(|p| format!("{:.6}", p.report.metrics.total_pips))
|
||||
.collect();
|
||||
println!("distinct total_pips across 64 points: {}", distinct.len());
|
||||
|
||||
// axis 2 (optimize): pick the best point by total_pips — argmax over the family.
|
||||
let best = optimize(&family, "total_pips").expect("total_pips is a known metric");
|
||||
println!(
|
||||
"axis 2 (optimize): best total_pips = {:.4}",
|
||||
best.report.metrics.total_pips
|
||||
);
|
||||
// Confirm optimize really returned the argmax of the family.
|
||||
let manual_max = family
|
||||
.points
|
||||
.iter()
|
||||
.map(|p| p.report.metrics.total_pips)
|
||||
.fold(f64::NEG_INFINITY, f64::max);
|
||||
assert_eq!(best.report.metrics.total_pips, manual_max, "optimize == argmax");
|
||||
|
||||
// Lineage: persist the whole sweep as ONE named family to a fresh temp store.
|
||||
// NOTE: the family store lives at `<dir>/families.jsonl` — keyed by the runs
|
||||
// path's DIRECTORY, not its filename (spec 0045: `path.with_file_name(
|
||||
// "families.jsonl")`). So a fresh, per-process *directory* is needed to isolate
|
||||
// the family store, not just a per-process runs *filename*. (A first attempt
|
||||
// that varied only the filename shared one /tmp/families.jsonl across runs and
|
||||
// round-tripped 2 families instead of 1 — recorded as a finding.)
|
||||
let dir = std::env::temp_dir().join(format!("mw1-{}", std::process::id()));
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let tmp = dir.join("runs.jsonl");
|
||||
let reg = Registry::open(&tmp);
|
||||
let id = reg
|
||||
.append_family("eurusd-tune", FamilyKind::Sweep, &sweep_member_reports(&family))
|
||||
.expect("family append");
|
||||
println!("lineage: persisted family id = {id}");
|
||||
assert_eq!(id, "eurusd-tune-0", "first family of this name is -0");
|
||||
|
||||
// Round-trip: the stored links re-derive the family as a unit.
|
||||
let families = group_families(reg.load_family_members().expect("load members"));
|
||||
assert_eq!(families.len(), 1, "one family round-tripped");
|
||||
let f = &families[0];
|
||||
println!(
|
||||
"round-trip: family {} kind={:?} members={}",
|
||||
f.id,
|
||||
f.kind,
|
||||
f.members.len()
|
||||
);
|
||||
assert_eq!(f.id, "eurusd-tune-0");
|
||||
assert_eq!(f.kind, FamilyKind::Sweep);
|
||||
assert_eq!(f.members.len(), 64, "all 64 sweep points are members");
|
||||
|
||||
// A second run of the same name mints a fresh family id (a new experiment run).
|
||||
let id2 = reg
|
||||
.append_family("eurusd-tune", FamilyKind::Sweep, &sweep_member_reports(&family))
|
||||
.expect("second family append");
|
||||
println!("re-run mints fresh id = {id2}");
|
||||
assert_eq!(id2, "eurusd-tune-1");
|
||||
|
||||
let _ = std::fs::remove_dir_all(&dir); // removes runs.jsonl + the sibling families.jsonl
|
||||
|
||||
println!("\nOK: random tune -> optimize -> persisted+round-tripped lineage family.");
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// Milestone-18 fieldtest — scenario 2: MONTE-CARLO robustness over a seed set.
|
||||
//
|
||||
// Composes: axis 4 (Monte-Carlo = sweep over seeds), seed-as-input (SyntheticSpec
|
||||
// ::source(seed) — the stream is fully seed-determined), the aggregate metric
|
||||
// distribution (mean + quantiles), reproducibility (same seed set -> same family),
|
||||
// and registry lineage (persist the MC family + round-trip).
|
||||
//
|
||||
// The task a downstream researcher does: "how robust is this fixed strategy's
|
||||
// tail across 128 stochastic market realizations? give me the median and p95 of
|
||||
// the metrics, and persist the run so I can re-list it later."
|
||||
//
|
||||
// PUBLIC INTERFACE ONLY: API from the design ledger (C12 axis 4), glossary, specs
|
||||
// 0042/0043/0045, and `cargo doc` rustdoc. No crates/*/src was read.
|
||||
|
||||
use std::sync::mpsc;
|
||||
|
||||
use aura_core::{Firing, Scalar, ScalarKind, Timestamp};
|
||||
use aura_engine::{
|
||||
f64_field, monte_carlo, summarize, BlueprintNode, Composite, Edge, McFamily, OutField, Role,
|
||||
RunManifest, RunReport, SyntheticSpec, Target,
|
||||
};
|
||||
use aura_registry::{group_families, mc_member_reports, FamilyKind, Registry};
|
||||
use aura_std::{Exposure, Recorder, SimBroker, Sma, Sub};
|
||||
|
||||
fn sma_cross() -> Composite {
|
||||
Composite::new(
|
||||
"sma_cross",
|
||||
vec![
|
||||
Sma::builder().named("fast").into(),
|
||||
Sma::builder().named("slow").into(),
|
||||
Sub::builder().into(),
|
||||
],
|
||||
vec![
|
||||
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
|
||||
],
|
||||
vec![Role {
|
||||
name: "price".into(),
|
||||
targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }],
|
||||
source: None,
|
||||
}],
|
||||
vec![OutField { node: 2, field: 0, name: "out".into() }],
|
||||
)
|
||||
}
|
||||
|
||||
fn harness_with_sinks() -> (
|
||||
Composite,
|
||||
mpsc::Receiver<(Timestamp, Vec<Scalar>)>,
|
||||
mpsc::Receiver<(Timestamp, Vec<Scalar>)>,
|
||||
) {
|
||||
let (tx_eq, rx_eq) = mpsc::channel();
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let bp = Composite::new(
|
||||
"harness",
|
||||
vec![
|
||||
BlueprintNode::Composite(sma_cross()),
|
||||
Exposure::builder().into(),
|
||||
SimBroker::builder(1e-4).into(),
|
||||
Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_eq).into(),
|
||||
Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_ex).into(),
|
||||
],
|
||||
vec![
|
||||
Edge { from: 0, to: 1, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 2, slot: 0, from_field: 0 },
|
||||
Edge { from: 2, to: 3, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 4, slot: 0, from_field: 0 },
|
||||
],
|
||||
vec![Role {
|
||||
name: "price".into(),
|
||||
targets: vec![Target { node: 0, slot: 0 }, Target { node: 2, slot: 1 }],
|
||||
source: Some(ScalarKind::F64),
|
||||
}],
|
||||
vec![],
|
||||
);
|
||||
(bp, rx_eq, rx_ex)
|
||||
}
|
||||
|
||||
// The per-draw closure: the SEED perturbs the synthetic market (seed-as-input,
|
||||
// Fork B — the seed lives at the data-generation edge, never inside the engine).
|
||||
// The strategy (base_point) is fixed across draws.
|
||||
fn run_draw(seed: u64, point: &[Scalar]) -> RunReport {
|
||||
let (bp, rx_eq, rx_ex) = harness_with_sinks();
|
||||
let mut h = bp
|
||||
.bootstrap_with_params(point.to_vec())
|
||||
.expect("base point kind-checked against param_space");
|
||||
let spec = SyntheticSpec { start: 1.0, len: 256, step: 60_000 };
|
||||
let window = (Timestamp(1), Timestamp((spec.len as i64 - 1) * spec.step + 1));
|
||||
// The seed -> Source construction lives inside the closure body (#71 firewall):
|
||||
// a seeded *Source*, never a materialized Vec crossing the monte_carlo boundary.
|
||||
h.run(vec![Box::new(spec.source(seed))]);
|
||||
drop(h);
|
||||
let equity = f64_field(&rx_eq.try_iter().collect::<Vec<_>>(), 0);
|
||||
let exposure = f64_field(&rx_ex.try_iter().collect::<Vec<_>>(), 0);
|
||||
RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "fieldtest".into(),
|
||||
params: vec![],
|
||||
window,
|
||||
seed, // <- the seed that drove this draw is recorded (C12)
|
||||
broker: "sim-optimal(pip_size=0.0001)".into(),
|
||||
},
|
||||
metrics: summarize(&equity, &exposure),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// The strategy is fixed; only the market realization (the seed) varies.
|
||||
let base_point = vec![Scalar::I64(3), Scalar::I64(8), Scalar::F64(1.0)];
|
||||
let seeds: Vec<u64> = (0..128).collect();
|
||||
|
||||
// axis 4: monte_carlo varies the SEED across the seed set.
|
||||
let family: McFamily = monte_carlo(&base_point, &seeds, run_draw);
|
||||
assert_eq!(family.draws.len(), 128, "one draw per seed");
|
||||
|
||||
// Each draw recorded the seed that drove it, in seed-INPUT order.
|
||||
for (i, d) in family.draws.iter().enumerate() {
|
||||
assert_eq!(d.seed, i as u64, "draw order == seed input order");
|
||||
assert_eq!(d.report.manifest.seed, i as u64, "seed captured in manifest");
|
||||
}
|
||||
println!("axis 4: {} draws, seeds {}..{}", family.draws.len(), 0, 127);
|
||||
|
||||
// The aggregate metric distribution — the robustness answer (mean + quantiles).
|
||||
let tp = &family.aggregate.total_pips;
|
||||
let dd = &family.aggregate.max_drawdown;
|
||||
println!("total_pips: mean {:.4} p5 {:.4} p50 {:.4} p95 {:.4}", tp.mean, tp.p5, tp.p50, tp.p95);
|
||||
println!("max_drawdown: mean {:.4} p50 {:.4} p95 (tail) {:.4}", dd.mean, dd.p50, dd.p95);
|
||||
// The aggregate is a pure reduction over the retained draws (recomputable):
|
||||
assert!(tp.p5 <= tp.p50 && tp.p50 <= tp.p95, "quantiles ordered");
|
||||
// Custom statistics always read the raw draws directly:
|
||||
let worst_dd = family.draws.iter().map(|d| d.report.metrics.max_drawdown).fold(0.0_f64, f64::max);
|
||||
println!("worst single-draw drawdown (raw draws): {worst_dd:.4}");
|
||||
|
||||
// The family must not collapse: distinct seeds perturb the run.
|
||||
let distinct: std::collections::BTreeSet<String> = family
|
||||
.draws
|
||||
.iter()
|
||||
.map(|d| format!("{:.6}", d.report.metrics.total_pips))
|
||||
.collect();
|
||||
println!("distinct total_pips across 128 draws: {}", distinct.len());
|
||||
assert!(distinct.len() > 1, "a Monte-Carlo over distinct seeds must spread");
|
||||
|
||||
// Reproducibility (C1): same seed set -> same McFamily, byte-for-byte.
|
||||
let family2: McFamily = monte_carlo(&base_point, &seeds, run_draw);
|
||||
assert_eq!(family, family2, "same seed set reproduces the whole family (C1)");
|
||||
println!("reproducibility: re-run produced an identical McFamily (C1) ✓");
|
||||
|
||||
// Lineage: persist the MC family + round-trip.
|
||||
let tmp = std::env::temp_dir().join(format!("mw2-runs-{}.jsonl", std::process::id()));
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
let _ = std::fs::remove_file(tmp.with_file_name("families.jsonl"));
|
||||
let reg = Registry::open(&tmp);
|
||||
let id = reg
|
||||
.append_family("eurusd-robustness", FamilyKind::MonteCarlo, &mc_member_reports(&family))
|
||||
.expect("mc family append");
|
||||
let families = group_families(reg.load_family_members().expect("load"));
|
||||
let f = families.iter().find(|f| f.id == id).expect("our family is present");
|
||||
println!("lineage: family {} kind={:?} members={}", f.id, f.kind, f.members.len());
|
||||
assert_eq!(f.kind, FamilyKind::MonteCarlo);
|
||||
assert_eq!(f.members.len(), 128);
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
|
||||
println!("\nOK: monte-carlo robustness -> aggregate distribution -> reproducible -> persisted lineage.");
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
// Milestone-18 fieldtest — scenario 3 (THE HEADLINE): walk-forward over a real
|
||||
// M1 data window, with per-window grid-optimize and a stitched OOS equity curve.
|
||||
//
|
||||
// Composes: axis 3 (walk-forward = vary the data window), axis 1 (grid sweep
|
||||
// in-sample), axis 2 (optimize the in-sample grid by total_pips), the Source
|
||||
// ingestion seam over REAL M1 close bars (M1FieldSource, lazy chunk streaming),
|
||||
// and registry lineage (persist the per-window OOS reports as a WalkForward
|
||||
// family). This is the milestone's headline promise end to end.
|
||||
//
|
||||
// The task a downstream researcher does: "validate my SMA-cross strategy
|
||||
// out-of-sample on real EURUSD M1 — roll 6-month in-sample / 1-month OOS windows,
|
||||
// re-optimize the params in each in-sample slice, run the chosen params on the
|
||||
// held-out month, and stitch the OOS months into one continuous pip curve."
|
||||
//
|
||||
// PUBLIC INTERFACE ONLY: API from the design ledger (C12 axis 3, source seam),
|
||||
// glossary, specs 0041/0044/0045/0048, and `cargo doc` rustdoc. No crates/*/src
|
||||
// was read. DataServer is reached for from the external `data-server` crate
|
||||
// directly, because M1FieldSource::open takes &Arc<DataServer> and aura-ingest
|
||||
// re-exports neither DataServer nor DEFAULT_DATA_PATH.
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use aura_core::{Cell, Firing, Scalar, ScalarKind, Timestamp};
|
||||
use aura_engine::{
|
||||
f64_field, summarize, sweep, walk_forward, BlueprintNode, Composite, Edge, GridSpace, OutField,
|
||||
RollMode, Role, RunManifest, RunReport, Source, SweepFamily, Target, WindowBounds, WindowRoller,
|
||||
WindowRun,
|
||||
};
|
||||
use aura_ingest::{M1Field, M1FieldSource};
|
||||
use aura_registry::{group_families, optimize, walkforward_member_reports, FamilyKind, Registry};
|
||||
use aura_std::{Exposure, Recorder, SimBroker, Sma, Sub};
|
||||
use data_server::{DataServer, DEFAULT_DATA_PATH};
|
||||
|
||||
const SYMBOL: &str = "EURUSD";
|
||||
|
||||
fn sma_cross() -> Composite {
|
||||
Composite::new(
|
||||
"sma_cross",
|
||||
vec![
|
||||
Sma::builder().named("fast").into(),
|
||||
Sma::builder().named("slow").into(),
|
||||
Sub::builder().into(),
|
||||
],
|
||||
vec![
|
||||
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
|
||||
],
|
||||
vec![Role {
|
||||
name: "price".into(),
|
||||
targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }],
|
||||
source: None,
|
||||
}],
|
||||
vec![OutField { node: 2, field: 0, name: "out".into() }],
|
||||
)
|
||||
}
|
||||
|
||||
fn harness_with_sinks() -> (
|
||||
Composite,
|
||||
mpsc::Receiver<(Timestamp, Vec<Scalar>)>,
|
||||
mpsc::Receiver<(Timestamp, Vec<Scalar>)>,
|
||||
) {
|
||||
let (tx_eq, rx_eq) = mpsc::channel();
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let bp = Composite::new(
|
||||
"harness",
|
||||
vec![
|
||||
BlueprintNode::Composite(sma_cross()),
|
||||
Exposure::builder().into(),
|
||||
SimBroker::builder(1e-4).into(),
|
||||
Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_eq).into(),
|
||||
Recorder::builder(vec![ScalarKind::F64], Firing::Any, tx_ex).into(),
|
||||
],
|
||||
vec![
|
||||
Edge { from: 0, to: 1, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 2, slot: 0, from_field: 0 },
|
||||
Edge { from: 2, to: 3, slot: 0, from_field: 0 },
|
||||
Edge { from: 1, to: 4, slot: 0, from_field: 0 },
|
||||
],
|
||||
vec![Role {
|
||||
name: "price".into(),
|
||||
targets: vec![Target { node: 0, slot: 0 }, Target { node: 2, slot: 1 }],
|
||||
source: Some(ScalarKind::F64),
|
||||
}],
|
||||
vec![],
|
||||
);
|
||||
(bp, rx_eq, rx_ex)
|
||||
}
|
||||
|
||||
// epoch-ns (the roller / WindowBounds unit, == RunManifest.window) back to the
|
||||
// Unix-ms M1FieldSource::open wants. aura-ingest exports unix_ms_to_epoch_ns but
|
||||
// NOT its inverse, so a real-data walk-forward must hand-divide here.
|
||||
fn ns_to_ms(ts: Timestamp) -> i64 {
|
||||
ts.0 / 1_000_000
|
||||
}
|
||||
|
||||
// One run of the harness over a real [from, to] M1 close window. Returns the OOS
|
||||
// equity stream and the folded RunReport. The bounds-keyed producer the #71
|
||||
// firewall wants lives right here in the closure body.
|
||||
fn run_window_real(
|
||||
server: &Arc<DataServer>,
|
||||
params: &[Cell],
|
||||
from: Timestamp,
|
||||
to: Timestamp,
|
||||
) -> (Vec<(Timestamp, f64)>, RunReport) {
|
||||
let (bp, rx_eq, rx_ex) = harness_with_sinks();
|
||||
let mut h = bp
|
||||
.bootstrap_with_cells(params)
|
||||
.expect("chosen params kind-checked against param_space");
|
||||
let src = M1FieldSource::open(server, SYMBOL, Some(ns_to_ms(from)), Some(ns_to_ms(to)), M1Field::Close)
|
||||
.expect("real EURUSD window overlaps archived data");
|
||||
// Producer-supplied window (C18): the source knows its bounds without
|
||||
// materializing the stream.
|
||||
let window = src.bounds().unwrap_or((from, to));
|
||||
h.run(vec![Box::new(src)]);
|
||||
drop(h);
|
||||
let eq_rows: Vec<_> = rx_eq.try_iter().collect();
|
||||
let ex_rows: Vec<_> = rx_ex.try_iter().collect();
|
||||
let equity = f64_field(&eq_rows, 0);
|
||||
let exposure = f64_field(&ex_rows, 0);
|
||||
let oos_equity: Vec<(Timestamp, f64)> = eq_rows.iter().map(|(t, v)| (*t, v[0].as_f64())).collect();
|
||||
let report = RunReport {
|
||||
manifest: RunManifest {
|
||||
commit: "fieldtest".into(),
|
||||
params: vec![],
|
||||
window,
|
||||
seed: 0,
|
||||
broker: "sim-optimal(pip_size=0.0001)".into(),
|
||||
},
|
||||
metrics: summarize(&equity, &exposure),
|
||||
};
|
||||
(oos_equity, report)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let server = Arc::new(DataServer::new(DEFAULT_DATA_PATH));
|
||||
if !server.has_symbol(SYMBOL) {
|
||||
eprintln!("no local {SYMBOL} archive under {DEFAULT_DATA_PATH}; skipping real-data scenario");
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// A 9-month span of EURUSD starting 2015-01-01. is=4 months, oos=1 month,
|
||||
// step=1 month, rolling — yields several windows. Units are epoch-ns
|
||||
// (RunManifest.window / WindowBounds unit). 1 month ~= 30 days of ns.
|
||||
let day_ns: i64 = 86_400_000 * 1_000_000;
|
||||
let month_ns: i64 = 30 * day_ns;
|
||||
let origin = aura_ingest::unix_ms_to_epoch_ns(1_420_070_400_000); // 2015-01-01 UTC
|
||||
let span = (origin, Timestamp(origin.0 + 9 * month_ns));
|
||||
let roller = WindowRoller::new(span, 4 * month_ns, month_ns, month_ns, RollMode::Rolling)
|
||||
.expect("span fits at least one window");
|
||||
|
||||
// The in-sample grid we re-optimize per window.
|
||||
let space = harness_with_sinks().0.param_space();
|
||||
println!("param-space slots:");
|
||||
for ps in &space {
|
||||
println!(" {} : {:?}", ps.name, ps.kind);
|
||||
}
|
||||
let grid: GridSpace = GridSpace::new(
|
||||
&space,
|
||||
vec![
|
||||
vec![Scalar::I64(3), Scalar::I64(5)], // sma_cross.fast.length
|
||||
vec![Scalar::I64(20), Scalar::I64(50)], // sma_cross.slow.length
|
||||
vec![Scalar::F64(1.0)], // exposure.scale
|
||||
],
|
||||
)
|
||||
.expect("grid well-formed for the space");
|
||||
|
||||
let server_for_closure = Arc::clone(&server);
|
||||
let space_for_result = space.clone();
|
||||
|
||||
// axis 3: walk_forward varies the DATA WINDOW. Inside the closure: axis 1
|
||||
// (grid sweep on the in-sample slice) + axis 2 (optimize by total_pips) +
|
||||
// an OOS run on the held-out window. All over REAL M1 close bars.
|
||||
let result = walk_forward(roller, space_for_result, move |w: WindowBounds| -> WindowRun {
|
||||
// in-sample: sweep the grid over the in-sample window, pick the best params.
|
||||
let is_family: SweepFamily = sweep(&grid, |pt: &[Cell]| {
|
||||
let (_eq, report) = run_window_real(&server_for_closure, pt, w.is.0, w.is.1);
|
||||
report
|
||||
});
|
||||
let best = optimize(&is_family, "total_pips").expect("total_pips known");
|
||||
// out-of-sample: run the chosen params on the held-out window, record equity.
|
||||
let (oos_equity, oos_report) =
|
||||
run_window_real(&server_for_closure, &best.params, w.oos.0, w.oos.1);
|
||||
WindowRun { chosen_params: best.params, oos_equity, oos_report }
|
||||
});
|
||||
|
||||
println!("\naxis 3: walk-forward produced {} windows", result.windows.len());
|
||||
assert!(!result.windows.is_empty(), "the roll yields at least one window");
|
||||
|
||||
// C2: no look-ahead — every OOS window starts strictly after its IS window ends.
|
||||
for (k, w) in result.windows.iter().enumerate() {
|
||||
let b = w.bounds;
|
||||
assert!(b.oos.0 > b.is.1, "window {k}: oos.0 > is.1 (no look-ahead, C2)");
|
||||
let named = result.named_params(k);
|
||||
let chosen: Vec<String> = named.iter().map(|(n, v)| format!("{n}={}", scalar_str(v))).collect();
|
||||
println!(
|
||||
" window {k}: is=[{}..{}] oos=[{}..{}] chosen {{ {} }} oos_pips={:.4}",
|
||||
ns_to_ms(b.is.0), ns_to_ms(b.is.1), ns_to_ms(b.oos.0), ns_to_ms(b.oos.1),
|
||||
chosen.join(", "),
|
||||
w.run.oos_report.metrics.total_pips,
|
||||
);
|
||||
}
|
||||
|
||||
// The stitched OOS curve — one continuous pip equity across all OOS months.
|
||||
let stitched = &result.stitched_oos_equity;
|
||||
println!(
|
||||
"\nstitched OOS curve: {} points, final cumulative = {:.4}",
|
||||
stitched.len(),
|
||||
stitched.last().map(|(_, v)| *v).unwrap_or(0.0),
|
||||
);
|
||||
assert!(!stitched.is_empty(), "real OOS windows produced equity points");
|
||||
// Stitched curve is monotone in timestamp (carried forward across windows).
|
||||
for w in stitched.windows(2) {
|
||||
assert!(w[1].0 .0 >= w[0].0 .0, "stitched timestamps are non-decreasing");
|
||||
}
|
||||
|
||||
// Lineage: persist the per-window OOS reports as a WalkForward family.
|
||||
let tmp = std::env::temp_dir().join(format!("mw3-runs-{}.jsonl", std::process::id()));
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
let _ = std::fs::remove_file(tmp.with_file_name("families.jsonl"));
|
||||
let reg = Registry::open(&tmp);
|
||||
let id = reg
|
||||
.append_family("eurusd-wfo", FamilyKind::WalkForward, &walkforward_member_reports(&result))
|
||||
.expect("wfo family append");
|
||||
let families = group_families(reg.load_family_members().expect("load"));
|
||||
let f = families.iter().find(|f| f.id == id).expect("our family present");
|
||||
println!(
|
||||
"\nlineage: family {} kind={:?} members={} (one OOS report per window)",
|
||||
f.id, f.kind, f.members.len()
|
||||
);
|
||||
assert_eq!(f.kind, FamilyKind::WalkForward);
|
||||
assert_eq!(f.members.len(), result.windows.len());
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
|
||||
println!("\nOK: real-data walk-forward -> per-window grid-optimize -> stitched OOS -> lineage.");
|
||||
}
|
||||
|
||||
fn scalar_str(s: &Scalar) -> String {
|
||||
match s {
|
||||
Scalar::I64(v) => v.to_string(),
|
||||
Scalar::F64(v) => format!("{v:.2}"),
|
||||
Scalar::Bool(v) => v.to_string(),
|
||||
Scalar::Timestamp(t) => t.0.to_string(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
axis 1 (random): 64 points, seed 0xa11ce
|
||||
distinct total_pips across 64 points: 33
|
||||
axis 2 (optimize): best total_pips = 0.0000
|
||||
lineage: persisted family id = eurusd-tune-0
|
||||
round-trip: family eurusd-tune-0 kind=Sweep members=64
|
||||
re-run mints fresh id = eurusd-tune-1
|
||||
|
||||
OK: random tune -> optimize -> persisted+round-tripped lineage family.
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
axis 4: 128 draws, seeds 0..127
|
||||
total_pips: mean 0.0046 p5 -0.3840 p50 -0.0320 p95 0.4423
|
||||
max_drawdown: mean 0.2471 p50 0.2213 p95 (tail) 0.4691
|
||||
worst single-draw drawdown (raw draws): 0.7044
|
||||
distinct total_pips across 128 draws: 128
|
||||
reproducibility: re-run produced an identical McFamily (C1) ✓
|
||||
lineage: family eurusd-robustness-0 kind=MonteCarlo members=128
|
||||
|
||||
OK: monte-carlo robustness -> aggregate distribution -> reproducible -> persisted lineage.
|
||||
@@ -0,0 +1,17 @@
|
||||
param-space slots:
|
||||
sma_cross.fast.length : I64
|
||||
sma_cross.slow.length : I64
|
||||
exposure.scale : F64
|
||||
|
||||
axis 3: walk-forward produced 5 windows
|
||||
window 0: is=[1420070400000..1430438399999] oos=[1430438400000..1433030399999] chosen { sma_cross.fast.length=5, sma_cross.slow.length=20, exposure.scale=1.00 } oos_pips=-0.7245
|
||||
window 1: is=[1422662400000..1433030399999] oos=[1433030400000..1435622399999] chosen { sma_cross.fast.length=5, sma_cross.slow.length=20, exposure.scale=1.00 } oos_pips=-0.5109
|
||||
window 2: is=[1425254400000..1435622399999] oos=[1435622400000..1438214399999] chosen { sma_cross.fast.length=5, sma_cross.slow.length=20, exposure.scale=1.00 } oos_pips=-0.6869
|
||||
window 3: is=[1427846400000..1438214399999] oos=[1438214400000..1440806399999] chosen { sma_cross.fast.length=5, sma_cross.slow.length=20, exposure.scale=1.00 } oos_pips=-0.2823
|
||||
window 4: is=[1430438400000..1440806399999] oos=[1440806400000..1443398399999] chosen { sma_cross.fast.length=5, sma_cross.slow.length=50, exposure.scale=1.00 } oos_pips=-0.0838
|
||||
|
||||
stitched OOS curve: 145200 points, final cumulative = -2.2884
|
||||
|
||||
lineage: family eurusd-wfo-0 kind=WalkForward members=5 (one OOS report per window)
|
||||
|
||||
OK: real-data walk-forward -> per-window grid-optimize -> stitched OOS -> lineage.
|
||||
@@ -0,0 +1,45 @@
|
||||
=== Milestone-18 fieldtest scenario 4 — family-lineage CLI surface, end to end ===
|
||||
(driven against the repo runs/ store; sweep family mw-grid-0 already persisted above)
|
||||
|
||||
$ cargo run -q -p aura-cli -- mc --name mw-robust 2>&1 | tail -4
|
||||
{"family_id":"mw-robust-0","report":{"manifest":{"broker":"sim-optimal(pip_size=0.0001)","commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["sma_fast",{"I64":2}],["sma_slow",{"I64":4}],["exposure_scale",{"F64":0.5}]],"seed":1,"window":[1,32]},"metrics":{"exposure_sign_flips":6,"max_drawdown":0.05492042518617829,"total_pips":0.033219795137322934}},"seed":1}
|
||||
{"family_id":"mw-robust-0","report":{"manifest":{"broker":"sim-optimal(pip_size=0.0001)","commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["sma_fast",{"I64":2}],["sma_slow",{"I64":4}],["exposure_scale",{"F64":0.5}]],"seed":2,"window":[1,32]},"metrics":{"exposure_sign_flips":10,"max_drawdown":0.050384043775853884,"total_pips":-0.025017958181714973}},"seed":2}
|
||||
{"family_id":"mw-robust-0","report":{"manifest":{"broker":"sim-optimal(pip_size=0.0001)","commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["sma_fast",{"I64":2}],["sma_slow",{"I64":4}],["exposure_scale",{"F64":0.5}]],"seed":3,"window":[1,32]},"metrics":{"exposure_sign_flips":9,"max_drawdown":0.13931444672911716,"total_pips":-0.07233362336360569}},"seed":3}
|
||||
{"mc_aggregate":{"exposure_sign_flips":{"mean":8.333333333333334,"p25":7.5,"p5":6.3,"p50":9.0,"p75":9.5,"p95":9.9},"max_drawdown":{"mean":0.08153963856371645,"p25":0.05265223448101609,"p5":0.050837681916886326,"p50":0.05492042518617829,"p75":0.09711743595764773,"p95":0.13087504457482327},"total_pips":{"mean":-0.021377262135999237,"p25":-0.04867579077266033,"p5":-0.06760205684541662,"p50":-0.025017958181714973,"p75":0.004100918477803982,"p95":0.027396019805419138}}}
|
||||
(exit 0)
|
||||
|
||||
$ cargo run -q -p aura-cli -- runs families
|
||||
{"family_id":"mw-grid-0","kind":"Sweep","members":4}
|
||||
{"family_id":"mw-robust-0","kind":"MonteCarlo","members":3}
|
||||
(exit 0)
|
||||
|
||||
$ cargo run -q -p aura-cli -- runs family mw-grid-0 2>&1 | head -2
|
||||
{"manifest":{"commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["signals.trend.fast.length",{"I64":2}],["signals.trend.slow.length",{"I64":4}],["signals.momentum.fast.length",{"I64":2}],["signals.momentum.slow.length",{"I64":4}],["signals.momentum.signal.length",{"I64":3}],["signals.blend.weights[0]",{"F64":1.0}],["signals.blend.weights[1]",{"F64":1.0}],["exposure.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":0.26428361277333234,"max_drawdown":0.15423679012344482,"exposure_sign_flips":2}}
|
||||
{"manifest":{"commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["signals.trend.fast.length",{"I64":2}],["signals.trend.slow.length",{"I64":5}],["signals.momentum.fast.length",{"I64":2}],["signals.momentum.slow.length",{"I64":4}],["signals.momentum.signal.length",{"I64":3}],["signals.blend.weights[0]",{"F64":1.0}],["signals.blend.weights[1]",{"F64":1.0}],["exposure.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":0.1605136127733241,"max_drawdown":0.22647145679012357,"exposure_sign_flips":2}}
|
||||
(exit 0)
|
||||
|
||||
$ cargo run -q -p aura-cli -- runs family mw-grid-0 rank total_pips 2>&1 | head -4
|
||||
{"manifest":{"commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["signals.trend.fast.length",{"I64":2}],["signals.trend.slow.length",{"I64":4}],["signals.momentum.fast.length",{"I64":2}],["signals.momentum.slow.length",{"I64":4}],["signals.momentum.signal.length",{"I64":3}],["signals.blend.weights[0]",{"F64":1.0}],["signals.blend.weights[1]",{"F64":1.0}],["exposure.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":0.26428361277333234,"max_drawdown":0.15423679012344482,"exposure_sign_flips":2}}
|
||||
{"manifest":{"commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["signals.trend.fast.length",{"I64":2}],["signals.trend.slow.length",{"I64":5}],["signals.momentum.fast.length",{"I64":2}],["signals.momentum.slow.length",{"I64":4}],["signals.momentum.signal.length",{"I64":3}],["signals.blend.weights[0]",{"F64":1.0}],["signals.blend.weights[1]",{"F64":1.0}],["exposure.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":0.1605136127733241,"max_drawdown":0.22647145679012357,"exposure_sign_flips":2}}
|
||||
{"manifest":{"commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["signals.trend.fast.length",{"I64":3}],["signals.trend.slow.length",{"I64":4}],["signals.momentum.fast.length",{"I64":2}],["signals.momentum.slow.length",{"I64":4}],["signals.momentum.signal.length",{"I64":3}],["signals.blend.weights[0]",{"F64":1.0}],["signals.blend.weights[1]",{"F64":1.0}],["exposure.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":0.10228361277332589,"max_drawdown":0.11347145679010996,"exposure_sign_flips":2}}
|
||||
{"manifest":{"commit":"8b22fa6c7307e266bc31a2d997d23d19720c8971","params":[["signals.trend.fast.length",{"I64":3}],["signals.trend.slow.length",{"I64":5}],["signals.momentum.fast.length",{"I64":2}],["signals.momentum.slow.length",{"I64":4}],["signals.momentum.signal.length",{"I64":3}],["signals.blend.weights[0]",{"F64":1.0}],["signals.blend.weights[1]",{"F64":1.0}],["exposure.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal(pip_size=0.0001)"},"metrics":{"total_pips":-0.0014863872266822969,"max_drawdown":0.20567145679011695,"exposure_sign_flips":2}}
|
||||
(exit 0)
|
||||
|
||||
$ cargo run -q -p aura-cli -- runs family no-such-family-99
|
||||
(exit 0)
|
||||
|
||||
$ cargo run -q -p aura-cli -- runs list 2>&1 | head -2
|
||||
aura: registry parse error at line 1: expected value at line 1 column 94
|
||||
(exit 0)
|
||||
|
||||
$ cargo run -q -p aura-cli -- runs rank total_pips # also load()s runs.jsonl
|
||||
aura: registry parse error at line 1: expected value at line 1 column 94
|
||||
(exit 0)
|
||||
|
||||
=== FINDING (bug): aura runs list / runs rank cannot read the pre-existing runs/runs.jsonl ===
|
||||
runs.jsonl line 1 col 94 is the bare-float 2.0 in ["sma_cross.fast",2.0]; the manifest
|
||||
params field was migrated to typed Scalar ({"I64":2}/{"F64":2.0}) in cycle 0047 (commit
|
||||
86746e3, inside the milestone range), but the persisted store was not migrated, so load()
|
||||
now fails to deserialize any pre-0047 line. The lineage path (families.jsonl, written fresh
|
||||
in the new format) is unaffected — runs families / runs family both succeeded above.
|
||||
Also: the parse error prints to stderr but the process exits 0.
|
||||
Reference in New Issue
Block a user