diff --git a/fieldtests/cycle-0106-research-artifacts/FINDINGS.md b/fieldtests/cycle-0106-research-artifacts/FINDINGS.md new file mode 100644 index 0000000..6c74899 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/FINDINGS.md @@ -0,0 +1,111 @@ +# Fieldtest — cycle 0106 — research-artifact document surface — 2026-07-03 + +**Role:** downstream consumer (methodology designer / campaign designer), public +interface only (ledger C18/C20/C22/C25, glossary, CLI help + introspection, the +fieldtests corpus shape). No `crates/` source read. Binary built from HEAD; +referential tier exercised after `cargo build` in the scaffolded `demo_project/`. + +## Fixtures (this directory) + +- `c0106_1_attempt1..3.json`, `c0106_1_partial.json`, `c0106_1_reformatted.json` + — process doc: 3-round envelope discovery + canonicalization + empty-gate probe +- `c0106_2_strategy.json` — SMA-cross op-script (content id `573262…`) +- `c0106_2_campaign_attempt1..2.json`, `c0106_2_campaign_valid.json`, + `c0106_2_campaign_partial.json`, `c0106_2_probe_{barestring,refnull,noref,prefixed}.json` +- `c0106_4_{emptyaxis,floatinint,noinstr,backwardwin,badmetric,badcmp,process_identity}.json` +- `demo_project/` — `aura new` scaffold + campaign/process docs + in-project store +- `runs/{processes,campaigns}/…` — content-addressed store written by `register` + +## Findings + +### F2 [bug] `introspect --block std::process_ref` advertises `identity_id`, which the validator refuses +The slot line prints `ref required, one of { content_id } | { identity_id }` +while validation refuses an identity_id process ref (`process.ref: a process is +referenced by content id in this version`, exit 1); the block header itself says +"(content id)". The 0106 audit fixed the parallel `--unwired` hint but not this +`--block` describe. Repro: `aura campaign introspect --block std::process_ref`. +→ debug (RED-pin content-id-only). + +### F1 [friction] Document envelope not derivable from the introspection contract +Process doc took 3 blind rounds (`stages` → wrong-kind refusal that does not +name the `kind` key → `unknown field stages, expected one of … pipeline`). +Campaign worse: block ids `std::data/std::strategy/std::process_ref/std::presentation` +map to fields `data`/`strategies` (plural)/`process`/`presentation`, and the +required `seed` appears in NO block (`missing field seed`). Introspection +describes block slots but never the envelope composing them. +→ plan (envelope/skeleton introspection; reconcile block ids with field names). + +### F3 [friction] content-id printed `content:`-prefixed, refs need the bare hash — silent referential break +`process|campaign introspect --content-id` print `content:`; `graph +introspect --content-id` prints bare. Pasting the prefixed form into a ref +PASSES intrinsic validation (different id!) then fails referential resolution +without the error naming the prefix as the cause. +→ plan (one display form across verbs; accept/strip the prefix in refs). + +### F4 [friction] `--unwired` open-slot hints fire only when a ref is omitted, which `validate` fails +The ref open-slot hints appear only with the `ref` key removed (then validate +says `missing field ref`); placeholders `{}` / `null` give cryptic serde errors +(`expected map with a single key`; `invalid type: null, expected string or map`) +and `--unwired` reports `no open slots`. One draft file cannot both +validate-so-far and report its open slots. +→ plan (treat `ref: {}`/`null` as the reported open slot). + +### F5 [friction] A campaign's strategy ref cannot be driven to resolve from the public surface +No verb computes a blueprint FILE's content id (`graph introspect --content-id` +is op-list-only), no verb registers a standalone blueprint into the store (only +sweep/mc/walkforward populate it), no verb lists a strategy's `param_space` +(axis names/kinds undiscoverable). The ref stays unresolved unless a sweep +already ran — but the sweep is what the campaign describes (see F7). +→ planner (blueprint register + file content-id + param-space listing; scope +with the executor). + +### F6 [doc-gap] No worked document example anywhere; `metric_vocabulary` unlisted by any verb +Zero process/campaign JSON examples in docs/ or the corpus at test time. Block +hints say "metric name (see metric_vocabulary)" but no verb lists it, and +`unknown metric` does not enumerate valid names. +→ tighten docs (worked example per type; metric enumeration via introspect or +in the refusal). + +### F7 [spec_gap] No executor — a valid campaign has no run path (the pending executor decision) +After registering a campaign whose process declares sweep → gate → walk_forward +over a strategy + 9-point axis, the expected `aura campaign run ` does not +exist; `aura run`/`sweep` take no campaign. The campaign+process pair is a +complete declarative spec of machinery the engine already runs +(sweep_family / optimize_deflated / walkforward_family); what exists is +persisted, content-addressed, legible intent that nothing consumes. The trail +ends at `runs/campaigns/.json`. +→ this run IS the intent-persistence re-test the executor decision waited on; +scope the executor. + +### F8 [working] Content-id canonicalization is exact and stable +Reordered keys + reflowed whitespace + `0` vs `0.0` yield the identical content +id; stored form is compact, declared-key-order, no trailing newline, and +re-derives its id. → carry-on. + +### F9 [working] Intrinsic validation is thorough, path-addressed, house-style +Empty gate, unknown metric/cmp, empty axis, float-in-I64, empty instruments, +backwards window, invalid-doc content-id refusal — all precise prose, exit +codes usage=2 / invalid=1 / ok=0. Minor: the kind-mismatch error omits the axis +path its siblings carry. → carry-on. + +### F10 [working] Referential tier correct across the project boundary +Outside: skip line names the search root. Inside without dylib: actionable +build hint. Inside built: per-store diagnostics, progressive resolution as +documents get registered. → carry-on. + +## Verdict + +The shipped surface delivers standalone value: methodology and experiment +intent are nameable, diffable (byte-exact content id surviving reformatting), +and auditable (content-addressed, referentially checkable, honest +diagnostics) — with no compile and no run. The shortfall concentrates in the +authoring on-ramp (envelope invisible to introspection, no worked example, the +`content:`-vs-bare id trap) and the terminal wall: the campaign+process pair +fully specifies a sweep→gate→walk-forward the engine already runs, yet nothing +consumes it. The single most valuable next capability is an executor +(`aura campaign run ` driving the existing family machinery) — the one +addition that turns persisted intent into a result and retroactively gives +every id, store, axis, and gate its reason to exist. + +Counts: bug 1 (F2), friction 4 (F1/F3/F4/F5), doc-gap 1 (F6), spec-gap 1 (F7), +working 3 (F8/F9/F10). diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt1.json b/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt1.json new file mode 100644 index 0000000..1ecf2da --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt1.json @@ -0,0 +1,9 @@ +{ + "format_version": 1, + "name": "robust-sweep-v1", + "stages": [ + { "block": "std::sweep", "metric": "sqn", "select": "argmax", "deflate": true }, + { "block": "std::gate", "all": [ { "metric": "expectancy_r", "cmp": "gt", "value": 0.0 } ] }, + { "block": "std::walk_forward", "folds": 4, "in_sample_bars": 5000, "out_of_sample_bars": 1000, "metric": "sqn", "select": "argmax" } + ] +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt2.json b/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt2.json new file mode 100644 index 0000000..a6f83c6 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt2.json @@ -0,0 +1,10 @@ +{ + "format_version": 1, + "kind": "process", + "name": "robust-sweep-v1", + "stages": [ + { "block": "std::sweep", "metric": "sqn", "select": "argmax", "deflate": true }, + { "block": "std::gate", "all": [ { "metric": "expectancy_r", "cmp": "gt", "value": 0.0 } ] }, + { "block": "std::walk_forward", "folds": 4, "in_sample_bars": 5000, "out_of_sample_bars": 1000, "metric": "sqn", "select": "argmax" } + ] +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt3.json b/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt3.json new file mode 100644 index 0000000..147724b --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_1_attempt3.json @@ -0,0 +1,11 @@ +{ + "format_version": 1, + "kind": "process", + "name": "robust-sweep-v1", + "description": "Sweep with trials-deflation, gate on positive expectancy, then walk-forward confirm.", + "pipeline": [ + { "block": "std::sweep", "metric": "sqn", "select": "argmax", "deflate": true }, + { "block": "std::gate", "all": [ { "metric": "expectancy_r", "cmp": "gt", "value": 0.0 } ] }, + { "block": "std::walk_forward", "folds": 4, "in_sample_bars": 5000, "out_of_sample_bars": 1000, "metric": "sqn", "select": "argmax" } + ] +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_1_partial.json b/fieldtests/cycle-0106-research-artifacts/c0106_1_partial.json new file mode 100644 index 0000000..6330175 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_1_partial.json @@ -0,0 +1,9 @@ +{ + "format_version": 1, + "kind": "process", + "name": "robust-sweep-v1", + "pipeline": [ + { "block": "std::sweep", "metric": "sqn", "select": "argmax" }, + { "block": "std::gate", "all": [] } + ] +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_1_reformatted.json b/fieldtests/cycle-0106-research-artifacts/c0106_1_reformatted.json new file mode 100644 index 0000000..1bf2a0a --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_1_reformatted.json @@ -0,0 +1,23 @@ +{ + "kind": "process", + "format_version": 1, + "name": "robust-sweep-v1", + "description": "Sweep with trials-deflation, gate on positive expectancy, then walk-forward confirm.", + "pipeline": [ + { + "select": "argmax", + "block": "std::sweep", + "deflate": true, + "metric": "sqn" + }, + { "block": "std::gate", "all": [ { "cmp": "gt", "metric": "expectancy_r", "value": 0 } ] }, + { + "block": "std::walk_forward", + "folds": 4, + "in_sample_bars": 5000, + "out_of_sample_bars": 1000, + "metric": "sqn", + "select": "argmax" + } + ] +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_attempt1.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_attempt1.json new file mode 100644 index 0000000..dc4186a --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_attempt1.json @@ -0,0 +1,15 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "data": { "instruments": ["EURUSD"], "windows": [ { "from_ms": 1704067200000, "to_ms": 1711929600000 } ] }, + "strategy": { + "ref": { "content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777" }, + "axes": { + "fast.length": { "kind": "I64", "values": [4, 8, 12] }, + "slow.length": { "kind": "I64", "values": [16, 24, 32] } + } + }, + "process_ref": { "ref": { "content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f" } }, + "presentation": { "persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"] } +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_attempt2.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_attempt2.json new file mode 100644 index 0000000..ae1dcaf --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_attempt2.json @@ -0,0 +1,18 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { "instruments": ["EURUSD"], "windows": [ { "from_ms": 1704067200000, "to_ms": 1711929600000 } ] }, + "strategies": [ + { + "ref": { "content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777" }, + "axes": { + "fast.length": { "kind": "I64", "values": [4, 8, 12] }, + "slow.length": { "kind": "I64", "values": [16, 24, 32] } + } + } + ], + "process": { "ref": { "content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f" } }, + "presentation": { "persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"] } +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_partial.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_partial.json new file mode 100644 index 0000000..e50c5df --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_partial.json @@ -0,0 +1,17 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { "instruments": ["EURUSD"], "windows": [ { "from_ms": 1704067200000, "to_ms": 1711929600000 } ] }, + "strategies": [ + { + "ref": {}, + "axes": { + "fast.length": { "kind": "I64", "values": [4, 8, 12] } + } + } + ], + "process": { "ref": {} }, + "presentation": { "persist_taps": ["bias"], "emit": ["family_table"] } +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_valid.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_valid.json new file mode 100644 index 0000000..ae1dcaf --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_campaign_valid.json @@ -0,0 +1,18 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { "instruments": ["EURUSD"], "windows": [ { "from_ms": 1704067200000, "to_ms": 1711929600000 } ] }, + "strategies": [ + { + "ref": { "content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777" }, + "axes": { + "fast.length": { "kind": "I64", "values": [4, 8, 12] }, + "slow.length": { "kind": "I64", "values": [16, 24, 32] } + } + } + ], + "process": { "ref": { "content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f" } }, + "presentation": { "persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"] } +} diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_barestring.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_barestring.json new file mode 100644 index 0000000..f8e97cc --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_barestring.json @@ -0,0 +1,53 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { + "instruments": [ + "EURUSD" + ], + "windows": [ + { + "from_ms": 1704067200000, + "to_ms": 1711929600000 + } + ] + }, + "strategies": [ + { + "ref": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777", + "axes": { + "fast.length": { + "kind": "I64", + "values": [ + 4, + 8, + 12 + ] + }, + "slow.length": { + "kind": "I64", + "values": [ + 16, + 24, + 32 + ] + } + } + } + ], + "process": { + "ref": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f" + }, + "presentation": { + "persist_taps": [ + "bias", + "equity" + ], + "emit": [ + "family_table", + "selection_report" + ] + } +} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_noref.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_noref.json new file mode 100644 index 0000000..65cb43f --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_noref.json @@ -0,0 +1,50 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { + "instruments": [ + "EURUSD" + ], + "windows": [ + { + "from_ms": 1704067200000, + "to_ms": 1711929600000 + } + ] + }, + "strategies": [ + { + "axes": { + "fast.length": { + "kind": "I64", + "values": [ + 4, + 8, + 12 + ] + }, + "slow.length": { + "kind": "I64", + "values": [ + 16, + 24, + 32 + ] + } + } + } + ], + "process": {}, + "presentation": { + "persist_taps": [ + "bias", + "equity" + ], + "emit": [ + "family_table", + "selection_report" + ] + } +} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_prefixed.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_prefixed.json new file mode 100644 index 0000000..d4a631a --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_prefixed.json @@ -0,0 +1,57 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { + "instruments": [ + "EURUSD" + ], + "windows": [ + { + "from_ms": 1704067200000, + "to_ms": 1711929600000 + } + ] + }, + "strategies": [ + { + "ref": { + "content_id": "content:573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777" + }, + "axes": { + "fast.length": { + "kind": "I64", + "values": [ + 4, + 8, + 12 + ] + }, + "slow.length": { + "kind": "I64", + "values": [ + 16, + 24, + 32 + ] + } + } + } + ], + "process": { + "ref": { + "content_id": "content:aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f" + } + }, + "presentation": { + "persist_taps": [ + "bias", + "equity" + ], + "emit": [ + "family_table", + "selection_report" + ] + } +} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_refnull.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_refnull.json new file mode 100644 index 0000000..131ae22 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_probe_refnull.json @@ -0,0 +1,53 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { + "instruments": [ + "EURUSD" + ], + "windows": [ + { + "from_ms": 1704067200000, + "to_ms": 1711929600000 + } + ] + }, + "strategies": [ + { + "ref": null, + "axes": { + "fast.length": { + "kind": "I64", + "values": [ + 4, + 8, + 12 + ] + }, + "slow.length": { + "kind": "I64", + "values": [ + 16, + 24, + 32 + ] + } + } + } + ], + "process": { + "ref": null + }, + "presentation": { + "persist_taps": [ + "bias", + "equity" + ], + "emit": [ + "family_table", + "selection_report" + ] + } +} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_2_strategy.json b/fieldtests/cycle-0106-research-artifacts/c0106_2_strategy.json new file mode 100644 index 0000000..9f6372d --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_2_strategy.json @@ -0,0 +1,12 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "SMA", "name": "fast", "bind": {"length": {"I64": 8}}}, + {"op": "add", "type": "SMA", "name": "slow", "bind": {"length": {"I64": 16}}}, + {"op": "feed", "role": "price", "into": ["fast.series", "slow.series"]}, + {"op": "add", "type": "Sub", "name": "sub"}, + {"op": "connect", "from": "fast.value", "to": "sub.lhs"}, + {"op": "connect", "from": "slow.value", "to": "sub.rhs"}, + {"op": "add", "type": "Bias", "name": "bias"}, + {"op": "connect", "from": "sub.value", "to": "bias.signal"}, + {"op": "expose", "from": "bias.bias", "as": "bias"} +] diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_backwardwin.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_backwardwin.json new file mode 100644 index 0000000..2372b50 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_backwardwin.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "campaign", "name": "sma-cross-length-sweep", "seed": 42, "data": {"instruments": ["EURUSD"], "windows": [{"from_ms": 1711929600000, "to_ms": 1704067200000}]}, "strategies": [{"ref": {"content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"}, "axes": {"fast.length": {"kind": "I64", "values": [4, 8, 12]}, "slow.length": {"kind": "I64", "values": [16, 24, 32]}}}], "process": {"ref": {"content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f"}}, "presentation": {"persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_badcmp.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_badcmp.json new file mode 100644 index 0000000..ec80520 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_badcmp.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "process", "name": "robust-sweep-v1", "description": "Sweep with trials-deflation, gate on positive expectancy, then walk-forward confirm.", "pipeline": [{"block": "std::sweep", "metric": "sqn", "select": "argmax", "deflate": true}, {"block": "std::gate", "all": [{"metric": "expectancy_r", "cmp": "between", "value": 0.0}]}, {"block": "std::walk_forward", "folds": 4, "in_sample_bars": 5000, "out_of_sample_bars": 1000, "metric": "sqn", "select": "argmax"}]} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_badmetric.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_badmetric.json new file mode 100644 index 0000000..750d477 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_badmetric.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "process", "name": "robust-sweep-v1", "description": "Sweep with trials-deflation, gate on positive expectancy, then walk-forward confirm.", "pipeline": [{"block": "std::sweep", "metric": "sqn", "select": "argmax", "deflate": true}, {"block": "std::gate", "all": [{"metric": "sharpe_ratio", "cmp": "gt", "value": 0.0}]}, {"block": "std::walk_forward", "folds": 4, "in_sample_bars": 5000, "out_of_sample_bars": 1000, "metric": "sqn", "select": "argmax"}]} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_emptyaxis.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_emptyaxis.json new file mode 100644 index 0000000..6a26ca8 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_emptyaxis.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "campaign", "name": "sma-cross-length-sweep", "seed": 42, "data": {"instruments": ["EURUSD"], "windows": [{"from_ms": 1704067200000, "to_ms": 1711929600000}]}, "strategies": [{"ref": {"content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"}, "axes": {"fast.length": {"kind": "I64", "values": []}, "slow.length": {"kind": "I64", "values": [16, 24, 32]}}}], "process": {"ref": {"content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f"}}, "presentation": {"persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_floatinint.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_floatinint.json new file mode 100644 index 0000000..ec33772 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_floatinint.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "campaign", "name": "sma-cross-length-sweep", "seed": 42, "data": {"instruments": ["EURUSD"], "windows": [{"from_ms": 1704067200000, "to_ms": 1711929600000}]}, "strategies": [{"ref": {"content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"}, "axes": {"fast.length": {"kind": "I64", "values": [4, 8.5, 12]}, "slow.length": {"kind": "I64", "values": [16, 24, 32]}}}], "process": {"ref": {"content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f"}}, "presentation": {"persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_noinstr.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_noinstr.json new file mode 100644 index 0000000..bcb4104 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_noinstr.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "campaign", "name": "sma-cross-length-sweep", "seed": 42, "data": {"instruments": [], "windows": [{"from_ms": 1704067200000, "to_ms": 1711929600000}]}, "strategies": [{"ref": {"content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"}, "axes": {"fast.length": {"kind": "I64", "values": [4, 8, 12]}, "slow.length": {"kind": "I64", "values": [16, 24, 32]}}}], "process": {"ref": {"content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f"}}, "presentation": {"persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/c0106_4_process_identity.json b/fieldtests/cycle-0106-research-artifacts/c0106_4_process_identity.json new file mode 100644 index 0000000..f00d98d --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/c0106_4_process_identity.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "campaign", "name": "sma-cross-length-sweep", "seed": 42, "data": {"instruments": ["EURUSD"], "windows": [{"from_ms": 1704067200000, "to_ms": 1711929600000}]}, "strategies": [{"ref": {"content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"}, "axes": {"fast.length": {"kind": "I64", "values": [4, 8, 12]}, "slow.length": {"kind": "I64", "values": [16, 24, 32]}}}], "process": {"ref": {"identity_id": "d15912eba3f8a9ac8e8f8e510717de92a98c6eb2d9fe5524746e97579cf37ed6"}}, "presentation": {"persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/.gitignore b/fieldtests/cycle-0106-research-artifacts/demo_project/.gitignore new file mode 100644 index 0000000..af5cf3d --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +/runs diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/Aura.toml b/fieldtests/cycle-0106-research-artifacts/demo_project/Aura.toml new file mode 100644 index 0000000..af335c1 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/Aura.toml @@ -0,0 +1,3 @@ +# Static project context only (C17); paths only. +[paths] +runs = "runs" diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/CLAUDE.md b/fieldtests/cycle-0106-research-artifacts/demo_project/CLAUDE.md new file mode 100644 index 0000000..6215473 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/CLAUDE.md @@ -0,0 +1,10 @@ +# demo_project — an aura research project + +This crate is an aura project: a cdylib of node/strategy blueprints the +`aura` host loads during research (see the engine's docs/project-layout.md). + +- Build: `cargo build` (the next `aura` invocation loads the fresh dylib) +- Run: `aura run blueprints/signal.json` (from anywhere inside this dir) +- Nodes live in `src/`; each is registered in `vocabulary()`/`type_ids()` + under the `demo_project::` namespace prefix. +- Topology is data (`blueprints/*.json`), node logic is Rust. diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/Cargo.toml b/fieldtests/cycle-0106-research-artifacts/demo_project/Cargo.toml new file mode 100644 index 0000000..a1a64b5 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "demo_project" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +aura-core = { path = "/home/brummel/dev/aura/crates/aura-core" } + +# Standalone workspace root: never a member of an enclosing workspace. +[workspace] diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/blueprints/signal.json b/fieldtests/cycle-0106-research-artifacts/demo_project/blueprints/signal.json new file mode 100644 index 0000000..f5b0f4e --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/blueprints/signal.json @@ -0,0 +1 @@ +{"format_version":1,"blueprint":{"name":"demo_project_signal","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":2}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":4}}]}},{"primitive":{"type":"Sub"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":0.5}}]}},{"primitive":{"type":"demo_project::Identity"}}],"edges":[{"from":0,"to":2,"slot":0,"from_field":0},{"from":1,"to":2,"slot":1,"from_field":0},{"from":2,"to":3,"slot":0,"from_field":0},{"from":3,"to":4,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0}],"source":"F64"}],"output":[{"node":4,"field":0,"name":"bias"}]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/campaign.json b/fieldtests/cycle-0106-research-artifacts/demo_project/campaign.json new file mode 100644 index 0000000..ae1dcaf --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/campaign.json @@ -0,0 +1,18 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "sma-cross-length-sweep", + "seed": 42, + "data": { "instruments": ["EURUSD"], "windows": [ { "from_ms": 1704067200000, "to_ms": 1711929600000 } ] }, + "strategies": [ + { + "ref": { "content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777" }, + "axes": { + "fast.length": { "kind": "I64", "values": [4, 8, 12] }, + "slow.length": { "kind": "I64", "values": [16, 24, 32] } + } + } + ], + "process": { "ref": { "content_id": "aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f" } }, + "presentation": { "persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"] } +} diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/campaign_prefixed.json b/fieldtests/cycle-0106-research-artifacts/demo_project/campaign_prefixed.json new file mode 100644 index 0000000..1e96bd4 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/campaign_prefixed.json @@ -0,0 +1 @@ +{"format_version": 1, "kind": "campaign", "name": "sma-cross-length-sweep", "seed": 42, "data": {"instruments": ["EURUSD"], "windows": [{"from_ms": 1704067200000, "to_ms": 1711929600000}]}, "strategies": [{"ref": {"content_id": "573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"}, "axes": {"fast.length": {"kind": "I64", "values": [4, 8, 12]}, "slow.length": {"kind": "I64", "values": [16, 24, 32]}}}], "process": {"ref": {"content_id": "content:aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f"}}, "presentation": {"persist_taps": ["bias", "equity"], "emit": ["family_table", "selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/process.json b/fieldtests/cycle-0106-research-artifacts/demo_project/process.json new file mode 100644 index 0000000..147724b --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/process.json @@ -0,0 +1,11 @@ +{ + "format_version": 1, + "kind": "process", + "name": "robust-sweep-v1", + "description": "Sweep with trials-deflation, gate on positive expectancy, then walk-forward confirm.", + "pipeline": [ + { "block": "std::sweep", "metric": "sqn", "select": "argmax", "deflate": true }, + { "block": "std::gate", "all": [ { "metric": "expectancy_r", "cmp": "gt", "value": 0.0 } ] }, + { "block": "std::walk_forward", "folds": 4, "in_sample_bars": 5000, "out_of_sample_bars": 1000, "metric": "sqn", "select": "argmax" } + ] +} diff --git a/fieldtests/cycle-0106-research-artifacts/demo_project/src/lib.rs b/fieldtests/cycle-0106-research-artifacts/demo_project/src/lib.rs new file mode 100644 index 0000000..80ad233 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/demo_project/src/lib.rs @@ -0,0 +1,76 @@ +//! demo_project — an aura research project: node logic + the exported vocabulary. +//! +//! Every node type this crate provides is registered in `vocabulary()` / +//! `type_ids()` under the `demo_project::` namespace prefix; the `aura` host loads +//! this cdylib per invocation and merges it with the std vocabulary. + +use aura_core::{ + Cell, Ctx, FieldSpec, Firing, Node, NodeSchema, PortSpec, PrimitiveBuilder, + ScalarKind, +}; + +/// One-input f64 pass-through. Emits `None` until its input has a value. +pub struct Identity { + out: [Cell; 1], +} + +impl Identity { + pub fn new() -> Self { + Self { out: [Cell::from_f64(0.0)] } + } + pub fn builder() -> PrimitiveBuilder { + PrimitiveBuilder::new( + "demo_project::Identity", + NodeSchema { + inputs: vec![PortSpec { + kind: ScalarKind::F64, + firing: Firing::Any, + name: "value".into(), + }], + output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }], + params: vec![], + }, + |_| Box::new(Identity::new()), + ) + } +} + +impl Default for Identity { + fn default() -> Self { + Self::new() + } +} + +impl Node for Identity { + fn lookbacks(&self) -> Vec { + vec![1] + } + fn eval(&mut self, ctx: Ctx<'_>) -> Option<&[Cell]> { + let w = ctx.f64_in(0); + if w.is_empty() { + return None; + } + self.out[0] = Cell::from_f64(w[0]); + Some(&self.out) + } + fn label(&self) -> String { + "demo_project::Identity".to_string() + } +} + +fn vocabulary(type_id: &str) -> Option { + match type_id { + "demo_project::Identity" => Some(Identity::builder()), + _ => None, + } +} + +fn type_ids() -> &'static [&'static str] { + &["demo_project::Identity"] +} + +aura_core::aura_project! { + namespace: "demo_project", + vocabulary: vocabulary, + type_ids: type_ids, +} diff --git a/fieldtests/cycle-0106-research-artifacts/runs/campaigns/d44f8f4c2c68da8167066c2219b06fe2dcf33e7939ba652255e98443102ab734.json b/fieldtests/cycle-0106-research-artifacts/runs/campaigns/d44f8f4c2c68da8167066c2219b06fe2dcf33e7939ba652255e98443102ab734.json new file mode 100644 index 0000000..5064e18 --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/runs/campaigns/d44f8f4c2c68da8167066c2219b06fe2dcf33e7939ba652255e98443102ab734.json @@ -0,0 +1 @@ +{"format_version":1,"kind":"campaign","name":"sma-cross-length-sweep","data":{"instruments":["EURUSD"],"windows":[{"from_ms":1704067200000,"to_ms":1711929600000}]},"strategies":[{"ref":{"content_id":"573262f2650fd2749427adaec41c148744597c6923fd7e829cb46ceccd105777"},"axes":{"fast.length":{"kind":"I64","values":[4,8,12]},"slow.length":{"kind":"I64","values":[16,24,32]}}}],"process":{"ref":{"content_id":"aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f"}},"seed":42,"presentation":{"persist_taps":["bias","equity"],"emit":["family_table","selection_report"]}} \ No newline at end of file diff --git a/fieldtests/cycle-0106-research-artifacts/runs/processes/aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f.json b/fieldtests/cycle-0106-research-artifacts/runs/processes/aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f.json new file mode 100644 index 0000000..cdc8b3b --- /dev/null +++ b/fieldtests/cycle-0106-research-artifacts/runs/processes/aac13f6e9eecda09364d263ead9174161efb8292d10f15e2f8846b4ee94fd10f.json @@ -0,0 +1 @@ +{"format_version":1,"kind":"process","name":"robust-sweep-v1","description":"Sweep with trials-deflation, gate on positive expectancy, then walk-forward confirm.","pipeline":[{"block":"std::sweep","metric":"sqn","select":"argmax","deflate":true},{"block":"std::gate","all":[{"metric":"expectancy_r","cmp":"gt","value":0.0}]},{"block":"std::walk_forward","folds":4,"in_sample_bars":5000,"out_of_sample_bars":1000,"metric":"sqn","select":"argmax"}]} \ No newline at end of file