fieldtest: harvest 2026-07-26 — 4 examples, 2 bugs / 4 friction / 1 spec-gap / 4 working

Source-blind per-cycle fieldtest over the sweep's four axes: the
declared-tap discovery loop closes in three commands without provoked
refusals; fixed{distance} is campaign-reachable with honest R
compression beside the vol regime; the C14 exit partition branches
reliably across sixteen probes; reference-semantics hashes agree
between record line and trace index across bare/no-op/substantive
overrides. Findings routed: both bugs fixed in-cycle (next commit),
frictions bundled as #345, the trace-overwrite spec gap consolidated
onto #311, the guide-rot instance evidenced on #344.
This commit is contained in:
2026-07-26 14:25:26 +02:00
parent f108291b7f
commit 7aac09d49e
20 changed files with 744 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
# Fieldtest corpus — harvest 2026-07-26
Downstream-consumer fixtures for the harvest cycle (`77ad046..f108291`): the
declared-tap discovery view, the `fixed{distance}` risk regime, `exec`'s
refusal families, and the zero-trade notes / override identity.
`TRANSCRIPT.md` is the recorded session — what was written first, what each
command said, and where the two diverged. The findings drawn from it live in
`docs/specs/fieldtest-harvest-2026-07-26.md` (git-ignored working file).
## Layout
| Path | What |
|---|---|
| `hv_1_blend_taps.ops.json` | crossover ⊕ momentum blended through `LinComb`, two declared taps |
| `hv_1b_unnamed_taps.ops.json` | same graph without the `name` op (default root name `"graph"`) |
| `hv_1c_named_notaps.ops.json` | same graph without the `tap` ops |
| `hv_2_cross.ops.json` | SMA crossover with `fast.length` left open (the campaign axis) |
| `hv_3_exec_refusals.sh` | replayable matrix of sixteen `aura exec` refusals |
| `hv_4_flat.ops.json` | deliberately flat bias (`Const 0.0 → Bias`) — never trades |
| `lab/` | a plain `aura new lab` scaffold holding the built blueprints and the process / campaign documents (`lab/runs/` is gitignored) |
## Replaying
From this directory, with the workspace built (`cargo build --workspace`) and
the resulting `aura` on `PATH`:
```sh
cd lab
aura graph build < ../hv_1_blend_taps.ops.json > blueprints/ma-blend.json
aura graph build < ../hv_1b_unnamed_taps.ops.json > blueprints/unnamed.json
aura graph build < ../hv_1c_named_notaps.ops.json > blueprints/notaps.json
aura graph build < ../hv_2_cross.ops.json > blueprints/hv-cross.json
aura graph build < ../hv_4_flat.ops.json > blueprints/hv-flat.json
aura graph register blueprints/ma-blend.json --name ma-blend
aura graph register blueprints/hv-cross.json --name hv-cross
aura graph register blueprints/hv-flat.json --name hv-flat
aura process register blueprints/hv_2_process_sweep.json
aura graph introspect --taps blueprints/ma-blend.json
aura exec blueprints/ma-blend.json --tap spread=mean --tap blend=record
aura exec blueprints/hv_2_campaign_two_regimes.json # two stop regimes, real GER40 data
aura exec blueprints/hv_4_campaign_zero_trade.json # the benign zero-trade cell
sh ../hv_3_exec_refusals.sh
```
The blueprints under `lab/blueprints/` are already built and registered at the
content ids the campaign documents reference; rebuilding them reproduces those
ids byte-identically.
+251
View File
@@ -0,0 +1,251 @@
# Fieldtest transcript — harvest 2026-07-26
Everything below was run against `target/debug/aura` built from the worktree at
`f108291` (`cargo build --workspace`, exit 0). The project is `lab/`, a plain
`aura new lab` scaffold; `lab/runs/` is gitignored by the scaffold's own
`.gitignore` and is not part of the corpus.
Reading order: each section is one axis of the cycle, and each records what was
written first, what the command said, and where the two diverged.
---
## Axis 1 — the declared-tap discovery loop
Task: *a colleague hands you `ma-blend.json`; find out what it measures,
subscribe one tap to a summary fold and one to the full series, and run it.*
Fixture: `hv_1_blend_taps.ops.json` — an SMA crossover spread and a
price-vs-slow momentum term blended through `LinComb` (`args` arity 2, per the
guide's new §1 example), two declared taps, a `name` and a `doc` op.
```
$ aura graph build < ../hv_1_blend_taps.ops.json > blueprints/ma-blend.json
$ aura graph introspect --taps blueprints/ma-blend.json
spread spread_node.value F64
blend combo.value F64
```
Built and introspected on the first try — the op-script needed no correction.
The same view by content id, after registering:
```
$ aura graph register blueprints/ma-blend.json --name ma-blend
registered blueprint ab84251518597f5d06df8fbbaf82572dd5362e06d18af9d33e265e3cc44bf7c6 (…)
label "ma-blend" -> ab84251518597f5d06df8fbbaf82572dd5362e06d18af9d33e265e3cc44bf7c6
$ aura graph introspect --taps ab84251518597f5d06df8fbbaf82572dd5362e06d18af9d33e265e3cc44bf7c6
spread spread_node.value F64
blend combo.value F64
```
The two edge cases, via `hv_1b_unnamed_taps.ops.json` (the same graph with the
`name` op removed) and `hv_1c_named_notaps.ops.json` (named, no taps):
```
$ aura graph introspect --taps blueprints/unnamed.json # default root name "graph"
spread spread_node.value F64
blend combo.value F64
exit=0
$ aura graph introspect --taps blueprints/notaps.json
aura: note: blueprints/notaps.json declares no taps
exit=0
$ aura graph introspect --taps e22a7524f4d41b9e957cb9a2eae15e7fc27488fc9acbd3bd32f06d7ae52b87a3
aura: note: e22a7524…b87a3 declares no taps
exit=0
```
Subscribing and running, with the fold roster discovered rather than guessed
(`aura graph introspect --folds` lists all eight with a doc line each):
```
$ aura exec blueprints/ma-blend.json --tap spread=mean --tap blend=record
{"manifest":{…,"topology_hash":"ab8425…f7c6",…},"metrics":{…}}
exit=0
$ cat runs/traces/ma-blend/spread.json
{"tap":"spread","kinds":["F64"],"ts":[18],"columns":[[0.00001148148148140867]]}
$ head -c 200 runs/traces/ma-blend/blend.json
{"tap":"blend","kinds":["F64"],"ts":[10,11,…,18],"columns":[[-0.00124…,…,0.004526…]]}
```
`mean` landed exactly one row stamped at the last warm instant, `record` the
full nine-row series — as C27 describes. The recovery half still works and is
now redundant rather than load-bearing:
```
$ aura exec blueprints/ma-blend.json --tap spred=mean
aura: the tap plan names 'spred', but the blueprint declares no such tap — declared taps: spread, blend
exit=1
$ aura exec blueprints/ma-blend.json --tap spread=median
aura: unknown fold 'median' — available: count, first, last, max, mean, min, record, sum
exit=1
```
**No refusal was needed to learn a real tap name.** Axis 1 answered yes.
---
## Axis 2 — the fixed-stop campaign regime
Task: *compare a constant 10-point stop against a volatility stop on the same
SMA-crossover signal over a month of GER40.*
Fixtures: `hv_2_cross.ops.json` (crossover, `fast.length` left open),
`hv_2_process_sweep.json` (one `std::sweep`, `sqn`/`argmax`),
`hv_2_campaign_two_regimes.json` (`risk: [vol{3, 2.0}, fixed{10.0}]`,
`fast.length ∈ {5,10,20}`, GER40, 2024-09-01 → 2024-10-01).
All three validate tiers passed on the first authoring, with no iteration:
```
$ aura campaign validate blueprints/hv_2_campaign_two_regimes.json
campaign document valid (intrinsic): 1 strategy(ies), 1 axes (3 points), 1 instrument(s), 1 window(s), 2 regime(s) — 2 cell(s)
campaign document valid (referential): all references resolve, axes are in the param space
campaign document valid (executable): pipeline shape and static guards pass
```
```
$ aura exec blueprints/hv_2_campaign_two_regimes.json
… 6 member lines, 2 selection_report lines, 1 campaign_run line …
aura: campaign run 0 recorded: 2 cells
aura: traces persisted: c6ffe19d-0 (1 tap(s) x 2 cell(s))
exit=0
```
Per-member readout (`family_id`, stamped stop knobs, R metrics):
| family_id | stamped stop | n_trades | E[R] | sqn | avg_win_r | avg_loss_r |
|---|---|---|---|---|---|---|
| `c6ffe19d-0-GER40-w0-r0-s0-0` (fast=5) | `stop_length=3, stop_k=2.0` | 1781 | 0.0306 | 0.508 | 2.239 | 0.974 |
| `c6ffe19d-0-GER40-w0-r0-s0-0` (fast=10) | `stop_length=3, stop_k=2.0` | 1604 | 0.0360 | 0.432 | 2.488 | 1.104 |
| `c6ffe19d-0-GER40-w0-r0-s0-0` (fast=20) | `stop_length=3, stop_k=2.0` | 1648 | 0.1038 | 1.238 | 2.331 | 1.115 |
| `c6ffe19d-0-GER40-w0-r1-s0-0` (fast=5) | `stop_distance=10.0` | 1542 | 0.0439 | 0.994 | 1.646 | 0.776 |
| `c6ffe19d-0-GER40-w0-r1-s0-0` (fast=10) | `stop_distance=10.0` | 1387 | 0.0188 | 0.371 | 1.717 | 0.866 |
| `c6ffe19d-0-GER40-w0-r1-s0-0` (fast=20) | `stop_distance=10.0` | 1449 | 0.0354 | 0.719 | 1.602 | 0.904 |
The R-unit semantics read coherently: under the fixed stop both tails compress
(`avg_win_r` 1.601.72 against 2.242.49, `avg_loss_r` 0.78 to 0.90 against
0.97 to 1.12), which is what a stop that never adapts should do — the R unit
is a constant 10 points rather than a per-cycle volatility multiple, so the same
price excursion buys fewer R in either direction. Both regimes rank the same
winner (`fast.length=20`) with different raw metrics, and the record keys them
separately (`regime_ordinal` absent for the first regime, `1` for the second) —
compared, never pooled, as C10 requires.
Trace dirs follow the documented ordinal rule:
```
runs/traces/c6ffe19d-0/33af5e38-GER40-w0/r_equity.json
runs/traces/c6ffe19d-0/33af5e38-GER40-w0-r1/r_equity.json
```
but the **family ids do not** — see finding B1.
Regime validation refuses cleanly:
```
$ aura exec <doc with risk:[{"fixed":{"distance":-1.0}}]>
aura: campaign document invalid:
risk[0]: stop length must be >= 1, k must be > 0, and a fixed-stop distance must be > 0
exit=1
$ aura exec <doc with risk:[{"trailing":{"distance":5.0}}]>
aura: campaign document: unknown variant `trailing`, expected one of `vol`, `vol_tf`, `fixed`
exit=1
```
`emit` selectors were probed separately (short-window copies of the same doc):
`family_table` produces the per-member `{"family_id","report"}` lines,
`selection_report` the `{"selection_report":…}` line; the `{"campaign_run":…}`
line is unconditional.
---
## Axis 3 — exec's refusal families
Fixture: `hv_3_exec_refusals.sh`, replayable from inside `lab/`. Full output in
that script's own run; the branch table it establishes:
| invocation | exit | class |
|---|---|---|
| op-script array as target | 2 | routing-seam content fault |
| `kind:"process"` document | 2 | routing-seam content fault |
| `kind:"widget"` document | 2 | routing-seam content fault |
| file that is not JSON | 2 | routing-seam content fault |
| missing file | 1 | missing state |
| well-formed unregistered 64-hex id | 1 | missing state |
| bare non-id token | 1 | missing state |
| open (free-knob) blueprint | 2 | blueprint-leg content fault |
| `--override` without `=` | 2 | argv fault |
| `--override nosuch.param=3` | 1 | blueprint-dependent |
| `--override fast.length=abc` | 2 | argv fault (**misdiagnosed** — see B2) |
| `--override fast.length=3.5` | 1 | blueprint-dependent |
| `--override` colliding with a declared axis | 2 | argv fault |
| `--tap` on a campaign target | 2 | argv fault |
| campaign document content fault (empty axis / bad emit / bad regime) | 1 | campaign-leg content fault |
| campaign completing with a failed cell | 3 | completed-with-failures |
The verbatim prose that a script author would branch on, for the three new
routing-seam families:
```
aura: exec: blueprints/opscript-target.json: this document is an op-script (a JSON array of construction ops), not something exec can run directly — build it into a blueprint first with `aura graph build < blueprints/opscript-target.json`, then exec the result
aura: exec: blueprints/hv_2_process_sweep.json: this document's kind is "process", but exec executes only a campaign document or a fully-bound blueprint
aura: exec: blueprints/notjson.json: target file is not valid JSON: expected ident at line 1 column 2
```
Every one names the target, the fault, and (where one exists) the next command.
The exit-3 case was confirmed against a weekend window with no GER40 bars:
```
aura: warning: cell (33af5e38…, GER40, [1725148800000, 1725235200000]) failed at stage 0: no data for instrument GER40 in window … — recorded, campaign continues
aura: campaign run 1 recorded: 1 cells, 1 failed (GER40: no_data)
exit=3
```
---
## Axis 4 — zero-trade notes and the override identity
### The two new notes
`hv_4_flat.ops.json` is a deliberately flat strategy (`Const 0.0 → Bias`), so it
never opens a position. Executed bare, against the built-in synthetic stream:
```
$ aura exec blueprints/hv-flat.json
aura: note: the built-in synthetic stream (18 cycles) is a small smoke fixture; zero trades is expected here — bind real data via a campaign document's `data` section (`aura exec <campaign.json>`) for a meaningful run
exit=0
```
The same strategy over real GER40 bars, as `hv_4_campaign_zero_trade.json` (a
non-walk-forward `std::sweep`, two axis points, both trading zero times):
```
$ aura exec blueprints/hv_4_campaign_zero_trade.json
aura: note: the cell's 2 reports all recorded zero trades; its metrics are vacuous, not a break-even result
aura: campaign run 0 recorded: 1 cells
exit=0
```
Both carry the benign `aura: note: ` marker and leave the exit code at 0 — the
grep-stable class C14 specifies, and the honest reading a consumer needs before
mistaking `expectancy_r: 0.0` for break-even.
### Reference semantics under `--override`
Four executions of the same registered blueprint (`ma-blend`, base content id
`ab8425…f7c6`), each with `--tap blend=record` so the trace store is written:
| run | record-line `topology_hash` | `runs/traces/ma-blend/index.json` hash | manifest `params` |
|---|---|---|---|
| bare | `ab8425…f7c6` | `ab8425…f7c6` | `[]` |
| `--override bias.scale=1.0` (no-op) | `ab8425…f7c6` | `ab8425…f7c6` | `[["bias.scale",{"F64":1.0}]]` |
| `--override bias.scale=2.0` | `ab8425…f7c6` | `ab8425…f7c6` | `[["bias.scale",{"F64":2.0}]]` |
| `--override fast.length=4` | `ab8425…f7c6` | `ab8425…f7c6` | `[["fast.length",{"I64":4}]]` |
This is exactly the revised C24 clause: the executed run stamps the **loaded
base document's** content id on both surfaces, the variation lives in `params`
(moved out of `defaults`), and the hash stays store-resolvable — `ab8425…f7c6`
is the id `graph register` printed. Record line and trace index never diverged.
What the same four runs also show is that all four wrote into the *same*
`runs/traces/ma-blend/` directory, each overwriting the last — see finding S1.
@@ -0,0 +1,23 @@
[
{"op": "name", "name": "ma-blend"},
{"op": "doc", "text": "weighted blend of an SMA crossover spread and a price-vs-slow momentum term"},
{"op": "source", "role": "price", "kind": "F64"},
{"op": "add", "type": "SMA", "name": "fast", "bind": {"length": {"I64": 3}}},
{"op": "add", "type": "SMA", "name": "slow", "bind": {"length": {"I64": 10}}},
{"op": "add", "type": "Sub", "name": "spread_node"},
{"op": "add", "type": "Sub", "name": "mom"},
{"op": "feed", "role": "price", "into": ["fast.series", "slow.series", "mom.lhs"]},
{"op": "connect", "from": "fast.value", "to": "spread_node.lhs"},
{"op": "connect", "from": "slow.value", "to": "spread_node.rhs"},
{"op": "connect", "from": "slow.value", "to": "mom.rhs"},
{"op": "add", "type": "LinComb", "name": "combo",
"args": {"arity": "2"},
"bind": {"weights[0]": {"F64": 0.7}, "weights[1]": {"F64": 0.3}}},
{"op": "connect", "from": "spread_node.value", "to": "combo.term[0]"},
{"op": "connect", "from": "mom.value", "to": "combo.term[1]"},
{"op": "add", "type": "Bias", "name": "bias", "bind": {"scale": {"F64": 1.0}}},
{"op": "connect", "from": "combo.value", "to": "bias.signal"},
{"op": "tap", "from": "spread_node.value", "as": "spread"},
{"op": "tap", "from": "combo.value", "as": "blend"},
{"op": "expose", "from": "bias.bias", "as": "bias"}
]
@@ -0,0 +1,121 @@
[
{
"op": "doc",
"text": "weighted blend of an SMA crossover spread and a price-vs-slow momentum term"
},
{
"op": "source",
"role": "price",
"kind": "F64"
},
{
"op": "add",
"type": "SMA",
"name": "fast",
"bind": {
"length": {
"I64": 3
}
}
},
{
"op": "add",
"type": "SMA",
"name": "slow",
"bind": {
"length": {
"I64": 10
}
}
},
{
"op": "add",
"type": "Sub",
"name": "spread_node"
},
{
"op": "add",
"type": "Sub",
"name": "mom"
},
{
"op": "feed",
"role": "price",
"into": [
"fast.series",
"slow.series",
"mom.lhs"
]
},
{
"op": "connect",
"from": "fast.value",
"to": "spread_node.lhs"
},
{
"op": "connect",
"from": "slow.value",
"to": "spread_node.rhs"
},
{
"op": "connect",
"from": "slow.value",
"to": "mom.rhs"
},
{
"op": "add",
"type": "LinComb",
"name": "combo",
"args": {
"arity": "2"
},
"bind": {
"weights[0]": {
"F64": 0.7
},
"weights[1]": {
"F64": 0.3
}
}
},
{
"op": "connect",
"from": "spread_node.value",
"to": "combo.term[0]"
},
{
"op": "connect",
"from": "mom.value",
"to": "combo.term[1]"
},
{
"op": "add",
"type": "Bias",
"name": "bias",
"bind": {
"scale": {
"F64": 1.0
}
}
},
{
"op": "connect",
"from": "combo.value",
"to": "bias.signal"
},
{
"op": "tap",
"from": "spread_node.value",
"as": "spread"
},
{
"op": "tap",
"from": "combo.value",
"as": "blend"
},
{
"op": "expose",
"from": "bias.bias",
"as": "bias"
}
]
@@ -0,0 +1,115 @@
[
{
"op": "name",
"name": "ma-blend-notaps"
},
{
"op": "doc",
"text": "weighted blend of an SMA crossover spread and a price-vs-slow momentum term"
},
{
"op": "source",
"role": "price",
"kind": "F64"
},
{
"op": "add",
"type": "SMA",
"name": "fast",
"bind": {
"length": {
"I64": 3
}
}
},
{
"op": "add",
"type": "SMA",
"name": "slow",
"bind": {
"length": {
"I64": 10
}
}
},
{
"op": "add",
"type": "Sub",
"name": "spread_node"
},
{
"op": "add",
"type": "Sub",
"name": "mom"
},
{
"op": "feed",
"role": "price",
"into": [
"fast.series",
"slow.series",
"mom.lhs"
]
},
{
"op": "connect",
"from": "fast.value",
"to": "spread_node.lhs"
},
{
"op": "connect",
"from": "slow.value",
"to": "spread_node.rhs"
},
{
"op": "connect",
"from": "slow.value",
"to": "mom.rhs"
},
{
"op": "add",
"type": "LinComb",
"name": "combo",
"args": {
"arity": "2"
},
"bind": {
"weights[0]": {
"F64": 0.7
},
"weights[1]": {
"F64": 0.3
}
}
},
{
"op": "connect",
"from": "spread_node.value",
"to": "combo.term[0]"
},
{
"op": "connect",
"from": "mom.value",
"to": "combo.term[1]"
},
{
"op": "add",
"type": "Bias",
"name": "bias",
"bind": {
"scale": {
"F64": 1.0
}
}
},
{
"op": "connect",
"from": "combo.value",
"to": "bias.signal"
},
{
"op": "expose",
"from": "bias.bias",
"as": "bias"
}
]
@@ -0,0 +1,14 @@
[
{"op": "name", "name": "hv-cross"},
{"op": "doc", "text": "SMA crossover bias: fast minus slow, clamped into the bias contract"},
{"op": "source", "role": "price", "kind": "F64"},
{"op": "add", "type": "SMA", "name": "fast"},
{"op": "add", "type": "SMA", "name": "slow", "bind": {"length": {"I64": 30}}},
{"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", "bind": {"scale": {"F64": 0.5}}},
{"op": "connect", "from": "sub.value", "to": "bias.signal"},
{"op": "expose", "from": "bias.bias", "as": "bias"}
]
@@ -0,0 +1,48 @@
#!/bin/sh
# hv_3 — exec's refusal families as a script author meets them.
#
# Run from inside the sibling `lab/` project (a plain `aura new` scaffold), with
# `aura` on PATH:
#
# cd lab && sh ../hv_3_exec_refusals.sh
#
# The question this fixture answers: can a script author branch on exit code
# alone, without parsing stderr? Each block prints the invocation, its exit
# code, and its verbatim stderr.
set -u
probe() {
printf -- '--- $ aura exec %s\n' "$*"
aura exec "$@" >/dev/null 2>/tmp/aura-hv3.err
printf 'exit=%s\n' "$?"
cat /tmp/aura-hv3.err
printf '\n'
}
# Fixtures the probes need, built in place.
cp ../hv_1_blend_taps.ops.json blueprints/opscript-target.json
printf 'this is not json at all\n' >blueprints/notjson.json
printf '{"format_version":1,"kind":"widget","name":"x"}' >blueprints/wrongkind.json
# --- target classification at the routing seam (C14's pinned partition) ---
probe blueprints/opscript-target.json # op-script array
probe blueprints/hv_2_process_sweep.json # kind:"process"
probe blueprints/wrongkind.json # kind:"widget"
probe blueprints/notjson.json # not JSON at all
probe blueprints/does-not-exist.json # no such file
probe 0000000000000000000000000000000000000000000000000000000000000000 # unregistered id
probe some-random-token # neither file nor id
# --- the blueprint leg's own gates ---
probe blueprints/hv-cross.json # open (free-knob) blueprint
probe blueprints/hv-cross.json --override fast.length=7 # ... and an override that does not close it
# --- --override argument faults ---
probe blueprints/ma-blend.json --override fast.length # no '='
probe blueprints/ma-blend.json --override nosuch.param=3 # no such param
probe blueprints/ma-blend.json --override fast.length=abc # unparseable value
probe blueprints/ma-blend.json --override fast.length=3.5 # wrong scalar kind
# --- flags that do not apply to the chosen leg ---
probe blueprints/hv_2_campaign_two_regimes.json --tap spread=mean
@@ -0,0 +1,11 @@
[
{"op": "name", "name": "hv-flat"},
{"op": "doc", "text": "deliberately flat bias: emits a constant zero signal, so the executor never opens a position"},
{"op": "source", "role": "price", "kind": "F64"},
{"op": "add", "type": "Const", "name": "flat", "bind": {"value": {"F64": 0.0}}},
{"op": "feed", "role": "price", "into": ["flat.clock"]},
{"op": "add", "type": "Bias", "name": "bias", "bind": {"scale": {"F64": 1.0}}},
{"op": "connect", "from": "flat.value", "to": "bias.signal"},
{"op": "tap", "from": "flat.value", "as": "flat_signal"},
{"op": "expose", "from": "bias.bias", "as": "bias"}
]
@@ -0,0 +1 @@
/runs
@@ -0,0 +1,4 @@
# Static project context only (C17); paths only.
[paths]
runs = "runs"
# data = "/path/to/archive" # the recorded-data root; defaults to the built-in path
@@ -0,0 +1,24 @@
# lab — an aura research project (data-only)
This directory is an aura project: blueprints + research documents over the
std vocabulary, anchored by `Aura.toml`. There is no crate and no build step.
- Run: `aura exec blueprints/signal.json` (single smoke run, synthetic stream
— the starter is closed; all params bound; bound values are defaults —
`--override NODE.PARAM=VALUE` may override one for this run (#246))
- Campaign: `aura exec <campaign.json>` executes a registered campaign
document (file or content id) — the multi-cell/axis surface
- Axes: `aura graph introspect --params blueprints/signal.json` lists the
open + bound-overridable axes, RAW `<node>.<param>` names (#328)
- Native nodes: when the project needs its first project-specific node,
`aura nodes new <name>` scaffolds a node crate beside this project and
attaches it via `[nodes]` in `Aura.toml` (build it with `cargo build`).
- Topology is data (`blueprints/*.json`); results land in `runs/`.
- Execution model: a strategy emits a bias in [-1,+1] per cycle, held as the
continuously-tracked target position; a protective stop defines the risk
unit R, and quality metrics are R-based. Entry signals become held state
via the signal-side latch/edge-pulse idiom (see
`aura graph introspect --vocabulary`).
- Data plane: process/campaign documents are authored directly with
`aura process` / `aura campaign`, growing one from a bare `{}` via
`aura campaign introspect --unwired`.
@@ -0,0 +1 @@
{"format_version":1,"blueprint":{"name":"hv-cross","doc":"SMA crossover bias: fast minus slow, clamped into the bias contract","nodes":[{"primitive":{"type":"SMA","name":"fast"}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":30}}]}},{"primitive":{"type":"Sub","name":"sub"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":0.5}}]}}],"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}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0}],"source":"F64"}],"output":[{"node":3,"field":0,"name":"bias"}]}}
@@ -0,0 +1 @@
{"format_version":1,"blueprint":{"name":"hv-flat","doc":"deliberately flat bias: emits a constant zero signal, so the executor never opens a position","nodes":[{"primitive":{"type":"Const","name":"flat","bound":[{"pos":0,"name":"value","kind":"F64","value":{"F64":0.0}}]}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":1,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0}],"source":"F64"}],"output":[{"node":1,"field":0,"name":"bias"}],"taps":[{"name":"flat_signal","from":{"node":0,"field":0}}]}}
@@ -0,0 +1,24 @@
{
"format_version": 1,
"kind": "campaign",
"name": "hv-ger40-cross-vol-vs-fixed",
"seed": 7,
"data": {
"instruments": ["GER40"],
"windows": [ { "from_ms": 1725148800000, "to_ms": 1727740800000 } ]
},
"risk": [
{ "vol": { "length": 3, "k": 2.0 } },
{ "fixed": { "distance": 10.0 } }
],
"strategies": [
{
"ref": { "content_id": "33af5e380d5e67d9b5464b4b9644419db1cdd2480104bd520592f6addcaeef34" },
"axes": {
"fast.length": { "kind": "I64", "values": [5, 10, 20] }
}
}
],
"process": { "ref": { "content_id": "c7fb729490770305d657e1e78d8daf12b1cd4dab990aea8cf4620c0b369a3c48" } },
"presentation": { "persist_taps": ["r_equity"], "emit": ["family_table", "selection_report"] }
}
@@ -0,0 +1,9 @@
{
"format_version": 1,
"kind": "process",
"name": "hv-sweep-sqn",
"description": "Single-stage sweep ranked by SQN — the minimum methodology for comparing two stop regimes.",
"pipeline": [
{ "block": "std::sweep", "metric": "sqn", "select": "argmax" }
]
}
@@ -0,0 +1,44 @@
{
"format_version": 1,
"kind": "campaign",
"name": "hv-ger40-flat-zero-trade",
"seed": 3,
"data": {
"instruments": [
"GER40"
],
"windows": [
{
"from_ms": 1725235200000,
"to_ms": 1725408000000
}
]
},
"strategies": [
{
"ref": {
"content_id": "6075193021f0226fdede891814401fc4abc51e19f4b7e2605113799fd781a6c7"
},
"axes": {
"bias.scale": {
"kind": "F64",
"values": [
1.0,
2.0
]
}
}
}
],
"process": {
"ref": {
"content_id": "c7fb729490770305d657e1e78d8daf12b1cd4dab990aea8cf4620c0b369a3c48"
}
},
"presentation": {
"persist_taps": [],
"emit": [
"family_table"
]
}
}
@@ -0,0 +1 @@
{"format_version":2,"blueprint":{"name":"ma-blend","doc":"weighted blend of an SMA crossover spread and a price-vs-slow momentum term","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":3}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":10}}]}},{"primitive":{"type":"Sub","name":"spread_node"}},{"primitive":{"type":"Sub","name":"mom"}},{"primitive":{"type":"LinComb","name":"combo","args":[{"name":"arity","value":"2"}],"bound":[{"pos":0,"name":"weights[0]","kind":"F64","value":{"F64":0.7}},{"pos":1,"name":"weights[1]","kind":"F64","value":{"F64":0.3}}]}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":2,"slot":0,"from_field":0},{"from":1,"to":2,"slot":1,"from_field":0},{"from":1,"to":3,"slot":1,"from_field":0},{"from":2,"to":4,"slot":0,"from_field":0},{"from":3,"to":4,"slot":1,"from_field":0},{"from":4,"to":5,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0},{"node":3,"slot":0}],"source":"F64"}],"output":[{"node":5,"field":0,"name":"bias"}],"taps":[{"name":"spread","from":{"node":2,"field":0}},{"name":"blend","from":{"node":4,"field":0}}]}}
@@ -0,0 +1 @@
{"format_version":2,"blueprint":{"name":"ma-blend-notaps","doc":"weighted blend of an SMA crossover spread and a price-vs-slow momentum term","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":3}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":10}}]}},{"primitive":{"type":"Sub","name":"spread_node"}},{"primitive":{"type":"Sub","name":"mom"}},{"primitive":{"type":"LinComb","name":"combo","args":[{"name":"arity","value":"2"}],"bound":[{"pos":0,"name":"weights[0]","kind":"F64","value":{"F64":0.7}},{"pos":1,"name":"weights[1]","kind":"F64","value":{"F64":0.3}}]}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":2,"slot":0,"from_field":0},{"from":1,"to":2,"slot":1,"from_field":0},{"from":1,"to":3,"slot":1,"from_field":0},{"from":2,"to":4,"slot":0,"from_field":0},{"from":3,"to":4,"slot":1,"from_field":0},{"from":4,"to":5,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0},{"node":3,"slot":0}],"source":"F64"}],"output":[{"node":5,"field":0,"name":"bias"}]}}
@@ -0,0 +1 @@
{"format_version":1,"blueprint":{"name":"lab_signal","doc":"fast/slow SMA difference clamped into a directional bias","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}}]}}],"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}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0}],"source":"F64"}],"output":[{"node":3,"field":0,"name":"bias"}]}}
@@ -0,0 +1 @@
{"format_version":2,"blueprint":{"name":"graph","doc":"weighted blend of an SMA crossover spread and a price-vs-slow momentum term","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":3}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":10}}]}},{"primitive":{"type":"Sub","name":"spread_node"}},{"primitive":{"type":"Sub","name":"mom"}},{"primitive":{"type":"LinComb","name":"combo","args":[{"name":"arity","value":"2"}],"bound":[{"pos":0,"name":"weights[0]","kind":"F64","value":{"F64":0.7}},{"pos":1,"name":"weights[1]","kind":"F64","value":{"F64":0.3}}]}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":2,"slot":0,"from_field":0},{"from":1,"to":2,"slot":1,"from_field":0},{"from":1,"to":3,"slot":1,"from_field":0},{"from":2,"to":4,"slot":0,"from_field":0},{"from":3,"to":4,"slot":1,"from_field":0},{"from":4,"to":5,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0},{"node":3,"slot":0}],"source":"F64"}],"output":[{"node":5,"field":0,"name":"bias"}],"taps":[{"name":"spread","from":{"node":2,"field":0}},{"name":"blend","from":{"node":4,"field":0}}]}}