fieldtest: cycle 0106 research-artifact surface — GREEN core, authoring on-ramp findings
Downstream-consumer run (roles 5/6b, public interface only) over the document-authoring loop: canonicalization byte-exact and stable across reformatting (F8), intrinsic validation thorough and path-addressed (F9), referential tier correct across the project boundary with progressive resolution (F10). Findings: one bug (F2: introspect --block advertises an identity_id process ref the validator refuses), four frictions (F1 envelope not derivable from introspection incl. the block-id/field-name mismatch and the un-blocked seed; F3 content:-prefixed id vs bare-hash refs breaking referential resolution silently; F4 --unwired only reports omitted refs, which validate then fails; F5 strategy refs unresolvable from the public surface — no blueprint register/file-content-id/param-space verbs), one doc-gap (F6 no worked examples, metric vocabulary unlisted), and the spec-gap F7: a valid, registered campaign has no run path — the intent-persistence re-test the executor decision waited on. refs #189, #188
This commit is contained in:
@@ -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:<hash>`; `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 <id>` 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/<hash>.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 <id>` 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).
|
||||||
@@ -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" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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": [] }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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"] }
|
||||||
|
}
|
||||||
@@ -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"] }
|
||||||
|
}
|
||||||
@@ -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"] }
|
||||||
|
}
|
||||||
@@ -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"] }
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"}
|
||||||
|
]
|
||||||
@@ -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"]}}
|
||||||
@@ -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"}]}
|
||||||
@@ -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"}]}
|
||||||
@@ -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"]}}
|
||||||
@@ -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"]}}
|
||||||
@@ -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"]}}
|
||||||
@@ -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"]}}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
/runs
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Static project context only (C17); paths only.
|
||||||
|
[paths]
|
||||||
|
runs = "runs"
|
||||||
@@ -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.
|
||||||
@@ -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]
|
||||||
@@ -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"}]}}
|
||||||
@@ -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"] }
|
||||||
|
}
|
||||||
@@ -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"]}}
|
||||||
@@ -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" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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<usize> {
|
||||||
|
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<PrimitiveBuilder> {
|
||||||
|
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,
|
||||||
|
}
|
||||||
+1
@@ -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"]}}
|
||||||
+1
@@ -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"}]}
|
||||||
Reference in New Issue
Block a user