fieldtest: trace-handle cycle — 5 examples, 3 bugs / 4 friction / 2 spec-gaps / 4 working

Source-blind field test of the handle echo and the rewritten chart refusal
(range 9636b00..9f87e5a), driven from the public interface only: the built
binary's help and refusals, the authoring guide, the glossary, the ledger.
Replayable via c309_0_run_all.sh, which rebuilds its lab from scratch and
captures stdout/stderr per step.

The chain the cycle promised holds: take trace_name off a run's stdout, feed
it to chart and to measure ic, never once list the trace directory. Both legs
report the handle identically — including the measurement leg the audit
caught shipping without a pin — and a tap-free run emits no key at all,
consistently across stdout and the stored record. The family-id arm proved
its worth: the intuitive cut of a family id yields a REAL but wrong handle
(another run's data), and the arm refuses to make it.

Findings routed: the three bugs fixed in-cycle RED-first (51ac155 and its
successor); the friction and spec-gap items filed as a collective issue.

refs #309
This commit is contained in:
2026-07-26 23:43:39 +02:00
parent ede26bb231
commit a09aaadcbd
97 changed files with 700 additions and 0 deletions
@@ -0,0 +1,204 @@
# cycle-309 (trace handle) — field-test transcript
Source-blind run against the public interface only: the built binary's help
and refusals, `docs/authoring-guide.md`, `docs/glossary.md`, `docs/design/`,
and `git log`. Nothing under `crates/` was opened.
Binary: `target/debug/aura`, built from this working tree with `cargo build`
(HEAD `9f87e5a`, manifests stamp `9f87e5a…-dirty` — the untracked corpus).
Replay: `./c309_0_run_all.sh` (rebuilds the lab from scratch; every step's
stdout/stderr lands beside it as `c309_*.out` / `c309_*.err`).
Project: `c309lab/`, scaffolded by `aura new`. Its `runs/` is git-ignored by
the scaffold's own `.gitignore`, so the ~15 MB of recorded traces stay out of
the commit; the authored fixtures (op-scripts, process + campaign documents)
and the captured outputs are the corpus.
---
## Axis 1 — the echo, on both legs
### Strategy leg — `c309_1_spread_strategy.ops.json`
An SMA-crossover bias with two declared taps (`spread` on `sub.value`,
`signal` on `bias.bias`) and a `name` op (`c309_spread`).
```
$ aura graph introspect --taps ../c309_1_spread_strategy.bp.json
spread sub.value F64
signal bias.bias F64
$ aura exec ../c309_1_spread_strategy.bp.json
{"manifest":{…},"metrics":{…},"trace_name":"c309_spread"} # exit 0, stderr empty
$ find runs/traces/c309_spread
runs/traces/c309_spread/{index.json,spread.json,signal.json}
```
The handle is the last key of the same stdout object as the report; nothing
is printed on stderr, and the report keys are unchanged.
### Measurement leg — `c309_3_measurement.ops.json`
No `expose`, no bias output: a `Scale(1.0)` price passthrough tapped as
`price` and the fastslow spread tapped as `signal`.
```
$ aura exec ../c309_3_measurement.bp.json
{"manifest":{…,"broker":"measurement",…},"taps":["price","signal"],"trace_name":"c309_measure"}
```
Same field, same position. (First attempt failed at build time on a port
name I guessed — `aura: op 4 (feed): node "px" has no input port "input"`;
`graph introspect --node Scale` names it `signal`. Clean diagnostic, one
retry.)
## Axis 2 — the chain, without knowing the name beforehand
```
$ H=$(jq -r '.trace_name' < ../c309_1_run.out) # -> c309_spread
$ aura chart "$H" # exit 0, HTML on stdout
series: c309_spread, spread, signal
$ aura chart "$H" --tap spread # exit 0, series: c309_spread, spread
$ M=$(jq -r '.trace_name' < ../c309_3_run.out) # -> c309_measure
$ aura measure ic "$M" --signal signal --price price
{"run":"c309_measure","signal_tap":"signal","price_tap":"price","horizon":1,
"permutations":1000,"seed":0,"n_pairs":13,"information_coefficient":0.148…,
"overfit_probability":0.300…}
```
Both destinations accept the printed value verbatim. No `ls runs/traces/`
anywhere in the loop.
Fold-only variant (`--tap spread=mean`) still reports `trace_name`; the
one-row trace charts, and the previous run's leftover `signal.json` in the
same directory is *not* resurrected — the rerun rewrites `index.json`
(`"taps":["spread"]`) and the chart shows `spread` alone.
Unnamed blueprint (`name` op stripped): handle `graph`, `aura chart graph`
exits 0.
## Axis 3 — the two refusal arms
### Arm A — not a family id
```
$ aura chart no_such_run # exit 1
aura: no recorded run or family 'no_such_run' under runs/traces (a single run
prints its handle as `trace_name` on stdout; a campaign run prints it as
`campaign_run.trace_name`, one per run — check that value for a typo. A trace
is produced by `aura exec --tap <NODE.FIELD>=<FOLD>` on a blueprint or a
campaign's `presentation.persist_taps` section, not by naming a handle here)
```
Claim-by-claim:
| claim | verdict |
|---|---|
| a single run prints `trace_name` on stdout | TRUE (both legs, above) |
| a campaign run prints `campaign_run.trace_name`, one per run | TRUE (two runs → `c364e8c3-0`, `c364e8c3-1`) |
| a campaign's `presentation.persist_taps` produces a trace | TRUE |
| `aura exec --tap <NODE.FIELD>=<FOLD>` produces a trace | **FALSE** (see below) |
```
$ aura exec ../c309_1_spread_strategy.bp.json --tap sub.value=record # exit 2
aura: the tap plan names 'sub.value', but the blueprint declares no such tap — declared taps: spread, signal
$ aura exec ../c309_1_spread_strategy.bp.json --tap spread=mean # exit 0
```
The flag takes the declared tap NAME, as `exec --help` says
(`--tap <TAP=FOLD>`); and it is not needed at all — the two runs at the top
of this transcript recorded their traces with no flag.
### Arm B — a family id out of the families listing
```
$ aura runs families
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","kind":"Sweep","members":4}
$ aura chart c364e8c3-0-GER40-w0-r0-s0-0 # exit 1
aura: no recorded run or family 'c364e8c3-0-GER40-w0-r0-s0-0' under runs/traces — that
looks like a family id, not a trace handle. Recorded trace handles for campaign
'c364e8c3': c364e8c3-0.
aura: Did you mean: aura chart c364e8c3-0
$ aura chart c364e8c3-0 # exit 0
series: c364e8c3-0, 88a221aa-GER40-w0/fast.length_2__slow.length_8__… (4 members)
```
After a second run of the same campaign, the same arm lists both handles and
suggests nothing:
```
$ aura chart c364e8c3-0-GER40-w0-r0-s0-1 # exit 1
… Recorded trace handles for campaign 'c364e8c3': c364e8c3-0, c364e8c3-1.
```
That second case is the trap the arm exists for: the family id's *trailing*
segment is the run (`-s0-1` → run 1), so the naive cut to the leading pair
gives `c364e8c3-0` — a real, chartable handle holding a **different run's**
data. The arm refuses instead of guessing.
Zero-handle sub-case (a campaign run with `persist_taps: []`, and a
campaign head never recorded at all) — identical prose for both:
```
$ aura chart 94355db6-0-GER40-w0-r0-s0-0 # this campaign recorded nothing
$ aura chart deadbeef-0-GER40-w0-r0-s0-0 # no such campaign at all
aura: no recorded run or family '…' under runs/traces — that looks like a family id,
not a trace handle. The handle is the `trace_name` the campaign run printed; this id's
second segment counts strategies while the handle's counts runs, so cutting the id
down is not a way to derive it.
```
Following that advice: the run in question printed
`campaign_run` **without** a `trace_name` key (`has("trace_name") == false`).
The pointer is true but empty — the arm knows the campaign recorded nothing
and does not say so.
## Axis 4 — the tap-free case
```
$ aura exec blueprints/signal.json # the scaffold's own signal
{"manifest":{…},"metrics":{…}} # exit 0
$ jq 'has("trace_name")' < … false
```
No key, no note, no stderr. Same for the campaign leg with
`persist_taps: []` (`campaign_run` has no `trace_name` key) and for the
stored `campaign_runs.jsonl` record. Absent-when-nothing is consistent
across all three surfaces.
```
$ aura exec blueprints/signal.json --tap spread=record # exit 2
aura: the tap plan names 'spread', but the blueprint declares no such tap — declared taps:
$ aura graph introspect --taps blueprints/signal.json # exit 0
aura: note: blueprints/signal.json declares no taps
```
The refusal's roster runs dry mid-sentence where the introspect verb says it
plainly.
## Beyond the arms — `measure ic` on a handle it will not take
```
$ aura measure ic c364e8c3-0 --signal equity --price r_equity # exit 1
aura: reading run 'c364e8c3-0' traces failed: no recorded run 'c364e8c3-0' under runs/traces
```
`runs/traces/c364e8c3-0/` exists — `aura chart c364e8c3-0` renders it, and
the member path underneath is accepted:
```
$ aura measure ic 'c364e8c3-0/88a221aa-GER40-w0/fast.length_2__slow.length_8__stop_length_3__stop_k_2' \
--signal equity --price r_equity # exit 0
{"run":"c364e8c3-0/88a221aa-…","n_pairs":24455,"information_coefficient":0.00796…,…}
```
And `measure ic`'s own not-found refusal carries no route back to where a
handle comes from, unlike `chart`'s:
```
$ aura measure ic no_such_run --signal signal --price price # exit 1
aura: reading run 'no_such_run' traces failed: no recorded run 'no_such_run' under runs/traces
```
(Its wrong-tap refusal, by contrast, is exemplary:
`aura: run 'c309_measure' has no tap 'close' (taps: ["price", "signal"])`.)
@@ -0,0 +1,8 @@
count — number of warm rows (any kind; i64 row); one row at the last warm ts
first — first warm value, at its own timestamp (any kind; kind-preserving row)
last — last warm value, at its own timestamp (any kind; kind-preserving row)
max — maximum of the series (f64 taps; f64 row); one row at the last warm ts
mean — arithmetic mean of the series (f64 taps; f64 row); one row at the last warm ts
min — minimum of the series (f64 taps; f64 row); one row at the last warm ts
record — persist the full series, lossless, at constant memory (any kind)
sum — sum of the series (f64 taps; f64 row); one row at the last warm ts
@@ -0,0 +1 @@
created project "c309lab" (data-only; attach native nodes later with `aura nodes new`)
@@ -0,0 +1,39 @@
[c309_0_vocabulary] exit=0 -- aura graph introspect --vocabulary
[c309_0_folds] exit=0 -- aura graph introspect --folds
[c309_6_data_ger40] exit=0 -- aura data info GER40
[c309_4_tapfree] exit=0 -- aura exec blueprints/signal.json
[c309_12_tapfree_flag] exit=2 -- aura exec blueprints/signal.json --tap spread=record
[c309_12_tapfree_introspect] exit=0 -- aura graph introspect --taps blueprints/signal.json
[c309_1_taps] exit=0 -- aura graph introspect --taps ../c309_1_spread_strategy.bp.json
[c309_1_run] exit=0 -- aura exec ../c309_1_spread_strategy.bp.json
[chain] single-run handle from stdout: c309_spread
[c309_10b_chart_taponly] exit=0 -- aura chart c309_spread --tap spread
[c309_3_run] exit=0 -- aura exec ../c309_3_measurement.bp.json
[chain] measurement-leg handle from stdout: c309_measure
[c309_3_ic] exit=0 -- aura measure ic c309_measure --signal signal --price price
[c309_5c_tap_name] exit=0 -- aura exec ../c309_1_spread_strategy.bp.json --tap spread=mean
[c309_11_run] exit=0 -- aura exec ../c309_11_unnamed.bp.json
[c309_11_chart] exit=0 -- aura chart graph
[c309_5a_notfound] exit=1 -- aura chart no_such_run
[c309_5b_tap_nodefield] exit=2 -- aura exec ../c309_1_spread_strategy.bp.json --tap sub.value=record
[c309_10a_chart_tapname] exit=1 -- aura chart spread
[c309_6_process_register] exit=0 -- aura process register ../c309_6_process_sweep.json
[c309_6_strategy_register] exit=0 -- aura graph register ../c309_1_spread_strategy.bp.json
[c309_6_campaign_validate] exit=0 -- aura campaign validate ../c309_6_campaign.json
[c309_6_campaign_run] exit=0 -- aura exec ../c309_6_campaign.json
[c309_7_families] exit=0 -- aura runs families
[chain] family id from the listing: c364e8c3-0-GER40-w0-r0-s0-0
[c309_7_chart_familyid] exit=1 -- aura chart c364e8c3-0-GER40-w0-r0-s0-0
[c309_7_chart_suggested] exit=0 -- aura chart c364e8c3-0
[c309_8_campaign_run1] exit=0 -- aura exec ../c309_6_campaign.json
[c309_8_families] exit=0 -- aura runs families
[c309_8_chart_two_handles] exit=1 -- aura chart c364e8c3-0-GER40-w0-r0-s0-1
[c309_9_run] exit=0 -- aura exec ../c309_9_campaign_notaps.json
[c309_9_stored_record] exit=0 -- aura campaign runs 94355db6a5063d6765e04e9cd8ac9d3dc268c915962b6900ef0c9f1d3d420fd4
[c309_9_chart_notaps] exit=1 -- aura chart 94355db6-0-GER40-w0-r0-s0-0
[c309_9_chart_unknown] exit=1 -- aura chart deadbeef-0-GER40-w0-r0-s0-0
[c309_10c_measure_notfound] exit=1 -- aura measure ic no_such_run --signal signal --price price
[c309_13a_measure_badtap] exit=1 -- aura measure ic c309_measure --signal signal --price close
[c309_13b_measure_campaign] exit=1 -- aura measure ic c364e8c3-0 --signal equity --price r_equity
[c309_13c_measure_member] exit=0 -- aura measure ic c364e8c3-0/88a221aa-GER40-w0/fast.length_2__slow.length_8__stop_length_3__stop_k_2 --signal equity --price r_equity
done — outputs in /home/brummel/dev/aura/.claude/worktrees/issue-309-trace-handle/fieldtests/cycle-309-trace-handle
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# Replay of the cycle-309 (trace handle) field test.
#
# Drives the `aura` binary as a downstream consumer: scaffolds a project,
# authors op-scripts, runs them, chains the printed handle into `chart` and
# `measure ic`, and provokes both arms of the chart not-found refusal.
#
# cd fieldtests/cycle-309-trace-handle && ./c309_0_run_all.sh
#
# Every command's stdout/stderr lands beside this script as c309_*.out /
# c309_*.err. Nothing here asserts; the transcript records what happened.
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$HERE/../.." && pwd)"
AURA="$ROOT/target/debug/aura"
[ -x "$AURA" ] || { echo "build first: (cd $ROOT && cargo build)" >&2; exit 1; }
cd "$HERE"
rm -rf c309lab
"$AURA" new c309lab > c309_0_new.out 2>&1
cd c309lab
run() { # run <slug> <args...>
local slug="$1"; shift
"$AURA" "$@" > "../${slug}.out" 2> "../${slug}.err"
echo "[$slug] exit=$? -- aura $*"
}
# --- discovery -------------------------------------------------------------
run c309_0_vocabulary graph introspect --vocabulary
run c309_0_folds graph introspect --folds
run c309_6_data_ger40 data info GER40
# --- axis 4: the tap-free single run --------------------------------------
run c309_4_tapfree exec blueprints/signal.json
run c309_12_tapfree_flag exec blueprints/signal.json --tap spread=record
run c309_12_tapfree_introspect graph introspect --taps blueprints/signal.json
# --- axis 1a: the echo on the strategy leg --------------------------------
"$AURA" graph build < ../c309_1_spread_strategy.ops.json \
> ../c309_1_spread_strategy.bp.json 2> ../c309_1_build.err
run c309_1_taps graph introspect --taps ../c309_1_spread_strategy.bp.json
run c309_1_run exec ../c309_1_spread_strategy.bp.json
# --- axis 2a: chain the printed handle into chart -------------------------
H=$(jq -r '.trace_name' < ../c309_1_run.out)
echo "[chain] single-run handle from stdout: $H"
"$AURA" chart "$H" > /tmp/c309_chart.html 2> ../c309_2_chart.err
echo "[c309_2_chart] exit=$? series: $(grep -o 'name":"[^"]*"' /tmp/c309_chart.html | sort -u | tr '\n' ' ')" \
> ../c309_2_chart.summary.txt
run c309_10b_chart_taponly chart "$H" --tap spread
# --- axis 1b/2b: the measurement leg and `measure ic` ---------------------
"$AURA" graph build < ../c309_3_measurement.ops.json \
> ../c309_3_measurement.bp.json 2> ../c309_3_build.err
run c309_3_run exec ../c309_3_measurement.bp.json
M=$(jq -r '.trace_name' < ../c309_3_run.out)
echo "[chain] measurement-leg handle from stdout: $M"
run c309_3_ic measure ic "$M" --signal signal --price price
# --- the fold-only variant (a handle without a full series) ---------------
run c309_5c_tap_name exec ../c309_1_spread_strategy.bp.json --tap spread=mean
"$AURA" chart "$H" > /tmp/c309_chart2.html 2> ../c309_5d_chart_after_fold.err
echo "[c309_5d] exit=$? series: $(grep -o 'name":"[^"]*"' /tmp/c309_chart2.html | sort -u | tr '\n' ' ')" \
> ../c309_5d_chart_after_fold.summary.txt
# --- the default (unnamed) blueprint --------------------------------------
jq 'map(select(.op != "name"))' ../c309_1_spread_strategy.ops.json > ../c309_11_unnamed.ops.json
"$AURA" graph build < ../c309_11_unnamed.ops.json > ../c309_11_unnamed.bp.json 2>&1
run c309_11_run exec ../c309_11_unnamed.bp.json
run c309_11_chart chart "$(jq -r '.trace_name' < ../c309_11_run.out)"
# --- axis 3a: the not-found arm, and its advice taken literally -----------
run c309_5a_notfound chart no_such_run
run c309_5b_tap_nodefield exec ../c309_1_spread_strategy.bp.json --tap sub.value=record
run c309_10a_chart_tapname chart spread
# --- axis 3b: the family-id arm -------------------------------------------
run c309_6_process_register process register ../c309_6_process_sweep.json
run c309_6_strategy_register graph register ../c309_1_spread_strategy.bp.json
run c309_6_campaign_validate campaign validate ../c309_6_campaign.json
run c309_6_campaign_run exec ../c309_6_campaign.json
run c309_7_families runs families
FID=$(jq -r '.family_id' < ../c309_7_families.out | head -1)
echo "[chain] family id from the listing: $FID"
run c309_7_chart_familyid chart "$FID"
run c309_7_chart_suggested chart "$(tail -1 ../c309_6_campaign_run.out | jq -r '.campaign_run.trace_name')"
run c309_8_campaign_run1 exec ../c309_6_campaign.json # second run: two handles
run c309_8_families runs families
run c309_8_chart_two_handles chart "$(jq -r '.family_id' < ../c309_8_families.out | tail -1)"
jq '.name = "c309-spread-ger40-sweep-notaps" | .presentation.persist_taps = []' \
../c309_6_campaign.json > ../c309_9_campaign_notaps.json
run c309_9_run exec ../c309_9_campaign_notaps.json
CID=$(tail -1 ../c309_9_run.out | jq -r '.campaign_run.campaign')
run c309_9_stored_record campaign runs "$CID"
run c309_9_chart_notaps chart "${CID:0:8}-0-GER40-w0-r0-s0-0"
run c309_9_chart_unknown chart deadbeef-0-GER40-w0-r0-s0-0
# --- measure ic refusals and the campaign handle --------------------------
run c309_10c_measure_notfound measure ic no_such_run --signal signal --price price
run c309_13a_measure_badtap measure ic "$M" --signal signal --price close
CH=$(tail -1 ../c309_6_campaign_run.out | jq -r '.campaign_run.trace_name')
run c309_13b_measure_campaign measure ic "$CH" --signal equity --price r_equity
MEMBER=$(cd runs/traces/"$CH" && find . -mindepth 2 -maxdepth 2 -type d | head -1 | sed 's|^\./||')
run c309_13c_measure_member measure ic "$CH/$MEMBER" --signal equity --price r_equity
# --- trim: chart stdout is a self-contained HTML page (~70 KB each); keep a
# --- one-line series summary in the corpus instead of the regenerable blob.
cd "$HERE"
for f in c309_*.out; do
head -c 15 "$f" | grep -q '<!doctype html>' || continue
{ echo "# $(basename "$f" .out): HTML chart page, $(wc -c < "$f") bytes"
echo "# series: $(grep -o 'name":"[^"]*"' "$f" | sed 's/name":"//;s/"//' | sort -u | tr '\n' ' ')"
} > "${f%.out}.summary.txt"
: > "$f"
done
echo "done — outputs in $HERE"
@@ -0,0 +1,36 @@
Abs absolute value of the input series
Add elementwise sum of two input series
And logical AND of two boolean series
Bias clamps the strategy signal into the bias contract [-1,+1]
CarryCost cost-model node: cost accrued per held cycle (param carry_per_cycle)
Const constant-valued stream from a single param
ConstantCost cost-model node: fixed cost per trade (param cost_per_trade), charged at close
CostSum sums cost-model contributions into one cost-in-R stream
CumSum running cumulative sum of the input series
Delay emits the input from `lag` cycles ago — the explicit delay register (C9)
Div elementwise quotient of two input series
EMA exponential moving average over the input series
EqConst true where the input equals a constant param
FixedStop derives the protective stop that defines the risk unit R
Gt true where the first input exceeds the second
Latch level-sensitive set/reset register holding 1.0 when latched, 0.0 when reset
LinComb linear combination of its inputs with constant weights
LongOnly when enabled, clamps negative exposure to flat (long-only); otherwise passes exposure through
Max elementwise maximum of two input series
Min elementwise minimum of two input series
Mul elementwise product of two input series
PositionManagement turns bias plus protective stop into a managed position in R
Resample emits a completed bar once per resample boundary, never mid-bar
RollingMax rolling maximum over a fixed lookback window
RollingMin rolling minimum over a fixed lookback window
Scale input multiplied by a constant factor param
Select chooses between two inputs by a boolean selector
Session bars elapsed since the session open, from the configured open time and timezone
SessionFrankfurt bars elapsed since the Frankfurt session open (09:00 Europe/Berlin)
Sign sign of the input: -1, 0 or +1
Sizer size = risk_budget / stop_distance at the deploy edge; bias only gates firing, research runs flat-1R
SMA simple moving average over the input series
Sqrt square root of the input series
Sub elementwise difference of two input series
VolSlippageCost cost-model node: slippage proportional to volatility (slip_vol_mult × volatility input), charged at close
When emits the input only on cycles where the condition input is true
@@ -0,0 +1 @@
aura: no recorded run or family 'spread' under runs/traces (a single run prints its handle as `trace_name` on stdout; a campaign run prints it as `campaign_run.trace_name`, one per run — check that value for a typo. A trace is produced by `aura exec --tap <NODE.FIELD>=<FOLD>` on a blueprint or a campaign's `presentation.persist_taps` section, not by naming a handle here)
@@ -0,0 +1,2 @@
# c309_10b_chart_taponly: HTML chart page, 71949 bytes
# series: c309_spread spread
@@ -0,0 +1 @@
aura: reading run 'no_such_run' traces failed: no recorded run 'no_such_run' under runs/traces
@@ -0,0 +1,2 @@
# c309_11_chart: HTML chart page, 72305 bytes
# series: graph signal spread
@@ -0,0 +1 @@
{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[],"defaults":[["fast.length",{"I64":2}],["slow.length",{"I64":5}],["bias.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=0.0001)","topology_hash":"d7d3f844ed7a4daaf388e418c8e75098e10fe8777be887eede600de2a2642ae4","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":0.2146800000000105,"max_drawdown":0.19279999999999503,"bias_sign_flips":2,"r":{"expectancy_r":0.515750880540302,"n_trades":3,"win_rate":0.6666666666666666,"avg_win_r":1.1439327691362082,"avg_loss_r":-0.7406128966515102,"profit_factor":3.089151631866538,"max_r_drawdown":0.0,"n_open_at_end":1,"sqn":0.6231985130629969,"sqn_normalized":0.6231985130629969,"net_expectancy_r":0.515750880540302,"conviction_terciles_r":[2.0771328641652427,0.21073267410717364,-0.7406128966515102]}},"trace_name":"graph"}
@@ -0,0 +1 @@
{"format_version":1,"blueprint":{"name":"graph","doc":"SMA crossover bias with the raw fast-slow spread tapped for inspection","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":5}}]}},{"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"}],"taps":[{"name":"spread","from":{"node":2,"field":0}},{"name":"signal","from":{"node":3,"field":0}}]}}
@@ -0,0 +1,84 @@
[
{
"op": "doc",
"text": "SMA crossover bias with the raw fast-slow spread tapped for inspection"
},
{
"op": "source",
"role": "price",
"kind": "F64"
},
{
"op": "add",
"type": "SMA",
"name": "fast",
"bind": {
"length": {
"I64": 2
}
}
},
{
"op": "add",
"type": "SMA",
"name": "slow",
"bind": {
"length": {
"I64": 5
}
}
},
{
"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": "tap",
"from": "sub.value",
"as": "spread"
},
{
"op": "tap",
"from": "bias.bias",
"as": "signal"
},
{
"op": "expose",
"from": "bias.bias",
"as": "bias"
}
]
@@ -0,0 +1 @@
aura: the tap plan names 'spread', but the blueprint declares no such tap — declared taps:
@@ -0,0 +1 @@
aura: note: blueprints/signal.json declares no taps
@@ -0,0 +1 @@
aura: run 'c309_measure' has no tap 'close' (taps: ["price", "signal"])
@@ -0,0 +1 @@
aura: reading run 'c364e8c3-0' traces failed: no recorded run 'c364e8c3-0' under runs/traces
@@ -0,0 +1 @@
{"run":"c364e8c3-0/88a221aa-GER40-w0/fast.length_2__slow.length_8__stop_length_3__stop_k_2","signal_tap":"equity","price_tap":"r_equity","horizon":1,"permutations":1000,"seed":0,"n_pairs":24455,"information_coefficient":0.00796145701775343,"overfit_probability":0.14285714285714285}
@@ -0,0 +1 @@
{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[],"defaults":[["fast.length",{"I64":2}],["slow.length",{"I64":5}],["bias.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=0.0001)","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":0.2146800000000105,"max_drawdown":0.19279999999999503,"bias_sign_flips":2,"r":{"expectancy_r":0.515750880540302,"n_trades":3,"win_rate":0.6666666666666666,"avg_win_r":1.1439327691362082,"avg_loss_r":-0.7406128966515102,"profit_factor":3.089151631866538,"max_r_drawdown":0.0,"n_open_at_end":1,"sqn":0.6231985130629969,"sqn_normalized":0.6231985130629969,"net_expectancy_r":0.515750880540302,"conviction_terciles_r":[2.0771328641652427,0.21073267410717364,-0.7406128966515102]}},"trace_name":"c309_spread"}
@@ -0,0 +1 @@
{"format_version":1,"blueprint":{"name":"c309_spread","doc":"SMA crossover bias with the raw fast-slow spread tapped for inspection","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":5}}]}},{"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"}],"taps":[{"name":"spread","from":{"node":2,"field":0}},{"name":"signal","from":{"node":3,"field":0}}]}}
@@ -0,0 +1,16 @@
[
{"op": "name", "name": "c309_spread"},
{"op": "doc", "text": "SMA crossover bias with the raw fast-slow spread tapped for inspection"},
{"op": "source", "role": "price", "kind": "F64"},
{"op": "add", "type": "SMA", "name": "fast", "bind": {"length": {"I64": 2}}},
{"op": "add", "type": "SMA", "name": "slow", "bind": {"length": {"I64": 5}}},
{"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": "tap", "from": "sub.value", "as": "spread"},
{"op": "tap", "from": "bias.bias", "as": "signal"},
{"op": "expose", "from": "bias.bias", "as": "bias"}
]
@@ -0,0 +1,2 @@
spread sub.value F64
signal bias.bias F64
@@ -0,0 +1 @@
[c309_2_chart] exit=0 series: name":"c309_spread" name":"signal" name":"spread"
@@ -0,0 +1 @@
{"run":"c309_measure","signal_tap":"signal","price_tap":"price","horizon":1,"permutations":1000,"seed":0,"n_pairs":13,"information_coefficient":0.14840672180898593,"overfit_probability":0.3006993006993007}
@@ -0,0 +1 @@
{"format_version":1,"blueprint":{"name":"c309_measure","doc":"measurement-only graph: the momentum spread and the price it is measured against","nodes":[{"primitive":{"type":"Scale","name":"px","bound":[{"pos":0,"name":"factor","kind":"F64","value":{"F64":1.0}}]}},{"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":5}}]}},{"primitive":{"type":"Sub","name":"sub"}}],"edges":[{"from":1,"to":3,"slot":0,"from_field":0},{"from":2,"to":3,"slot":1,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0},{"node":2,"slot":0}],"source":"F64"}],"taps":[{"name":"price","from":{"node":0,"field":0}},{"name":"signal","from":{"node":3,"field":0}}]}}
@@ -0,0 +1,15 @@
[
{"op": "name", "name": "c309_measure"},
{"op": "doc", "text": "measurement-only graph: the momentum spread and the price it is measured against"},
{"op": "source", "role": "price", "kind": "F64"},
{"op": "add", "type": "Scale", "name": "px", "bind": {"factor": {"F64": 1.0}}},
{"op": "feed", "role": "price", "into": ["px.signal"]},
{"op": "add", "type": "SMA", "name": "fast", "bind": {"length": {"I64": 2}}},
{"op": "add", "type": "SMA", "name": "slow", "bind": {"length": {"I64": 5}}},
{"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": "tap", "from": "px.value", "as": "price"},
{"op": "tap", "from": "sub.value", "as": "signal"}
]
@@ -0,0 +1 @@
{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[],"defaults":[["px.factor",{"F64":1.0}],["fast.length",{"I64":2}],["slow.length",{"I64":5}]],"window":[1,18],"seed":0,"broker":"measurement","topology_hash":"82dc9784c3b3fc3aba405df0ef7b298264dc982c00ac4fd5990b18d590c7c49c","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"taps":["price","signal"],"trace_name":"c309_measure"}
@@ -0,0 +1 @@
{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[],"defaults":[["fast.length",{"I64":2}],["slow.length",{"I64":4}],["bias.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=0.0001)","topology_hash":"00c04d95f78f9c92100d4de638ccae40f9b08f212c353c467882ff836826a689","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":0.34185000000002036,"max_drawdown":0.11139999999998655,"bias_sign_flips":2,"r":{"expectancy_r":1.2710005136982836,"n_trades":3,"win_rate":1.0,"avg_win_r":1.2710005136982836,"avg_loss_r":0.0,"profit_factor":0.0,"max_r_drawdown":0.0,"n_open_at_end":1,"sqn":3.141496526818299,"sqn_normalized":3.141496526818299,"net_expectancy_r":1.2710005136982836,"conviction_terciles_r":[0.9285858482198718,2.0771328641652427,0.8072828287097363]}}}
@@ -0,0 +1 @@
aura: no recorded run or family 'no_such_run' under runs/traces (a single run prints its handle as `trace_name` on stdout; a campaign run prints it as `campaign_run.trace_name`, one per run — check that value for a typo. A trace is produced by `aura exec --tap <NODE.FIELD>=<FOLD>` on a blueprint or a campaign's `presentation.persist_taps` section, not by naming a handle here)
@@ -0,0 +1 @@
aura: the tap plan names 'sub.value', but the blueprint declares no such tap — declared taps: spread, signal
@@ -0,0 +1 @@
aura: note: declared tap "signal" unbound this run
@@ -0,0 +1 @@
{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[],"defaults":[["fast.length",{"I64":2}],["slow.length",{"I64":5}],["bias.scale",{"F64":0.5}]],"window":[1,18],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=0.0001)","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":0.2146800000000105,"max_drawdown":0.19279999999999503,"bias_sign_flips":2,"r":{"expectancy_r":0.515750880540302,"n_trades":3,"win_rate":0.6666666666666666,"avg_win_r":1.1439327691362082,"avg_loss_r":-0.7406128966515102,"profit_factor":3.089151631866538,"max_r_drawdown":0.0,"n_open_at_end":1,"sqn":0.6231985130629969,"sqn_normalized":0.6231985130629969,"net_expectancy_r":0.515750880540302,"conviction_terciles_r":[2.0771328641652427,0.21073267410717364,-0.7406128966515102]}},"trace_name":"c309_spread"}
@@ -0,0 +1 @@
[c309_5d] exit=0 series: name":"c309_spread" name":"spread"
@@ -0,0 +1,21 @@
{
"format_version": 1,
"kind": "campaign",
"name": "c309-spread-ger40-sweep",
"seed": 7,
"data": {
"instruments": ["GER40"],
"windows": [ { "from_ms": 1725148800000, "to_ms": 1727740800000 } ]
},
"strategies": [
{
"ref": { "content_id": "88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6" },
"axes": {
"fast.length": { "kind": "I64", "values": [2, 4] },
"slow.length": { "kind": "I64", "values": [8, 16] }
}
}
],
"process": { "ref": { "content_id": "3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0" } },
"presentation": { "persist_taps": ["equity", "r_equity"], "emit": ["family_table"] }
}
@@ -0,0 +1,2 @@
aura: campaign run 0 recorded: 1 cells
aura: traces persisted: c364e8c3-0 (2 tap(s) x 1 cell(s))
@@ -0,0 +1,5 @@
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":2}],["slow.length",{"I64":8}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":1311.7250000000104,"max_drawdown":615.6000000000058,"bias_sign_flips":3977,"r":{"expectancy_r":0.028321444460569407,"n_trades":3903,"win_rate":0.33692031770433,"avg_win_r":1.5089377461851683,"avg_loss_r":-0.7240009808747663,"profit_factor":1.0589943641136834,"max_r_drawdown":78.64539272099334,"n_open_at_end":1,"sqn":1.0540214890316064,"sqn_normalized":0.16871363772287948,"net_expectancy_r":0.028321444460569407,"conviction_terciles_r":[-0.05124882989934285,0.06705254021274346,0.0691606230683076]}}}}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":2}],["slow.length",{"I64":16}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":35.86250000013888,"max_drawdown":657.0250000000078,"bias_sign_flips":2550,"r":{"expectancy_r":0.001942726488289421,"n_trades":2581,"win_rate":0.2909724912824487,"avg_win_r":1.9096186007126963,"avg_loss_r":-0.7809340940267545,"profit_factor":1.0035086026962674,"max_r_drawdown":72.50403168697483,"n_open_at_end":1,"sqn":0.05152717930726507,"sqn_normalized":0.010142438121122548,"net_expectancy_r":0.001942726488289421,"conviction_terciles_r":[0.003799692660105443,-0.03634478563974999,0.0383309605444476]}}}}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":4}],["slow.length",{"I64":8}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":742.7500000001023,"max_drawdown":422.36250000000837,"bias_sign_flips":3570,"r":{"expectancy_r":0.025765945651374078,"n_trades":3811,"win_rate":0.358960902650223,"avg_win_r":1.508960221588393,"avg_loss_r":-0.8047742792695608,"profit_factor":1.0499444782267588,"max_r_drawdown":90.38863380823058,"n_open_at_end":1,"sqn":0.8490217221109733,"sqn_normalized":0.1375305967356901,"net_expectancy_r":0.025765945651374078,"conviction_terciles_r":[0.016131381474867954,-0.0014331659738562395,0.06257064137773533]}}}}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":4}],["slow.length",{"I64":16}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":-70.01874999997267,"max_drawdown":914.4874999999981,"bias_sign_flips":1965,"r":{"expectancy_r":-0.021911292659493667,"n_trades":2388,"win_rate":0.3274706867671692,"avg_win_r":1.76727288256566,"avg_loss_r":-0.8931080703843195,"profit_factor":0.9635201732345389,"max_r_drawdown":132.7156533736896,"n_open_at_end":1,"sqn":-0.5448524993019401,"sqn_normalized":-0.11149664160230002,"net_expectancy_r":-0.021911292659493667,"conviction_terciles_r":[-0.0043670430492390765,-0.0543615931213561,-0.007005241807885511]}}}}
{"campaign_run":{"campaign":"c364e8c309e9f585b29850864258425654abb0bc9ba50c8fc87fd67fbe04f96e","process":"3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0","run":0,"seed":7,"cells":[{"strategy":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","instrument":"GER40","window_ms":[1725148800000,1727740800000],"stages":[{"block":"std::sweep","family_id":"c364e8c3-0-GER40-w0-r0-s0-0"}],"coverage":{"effective_from_ms":1725236099999,"effective_to_ms":1727726220000}}],"trace_name":"c364e8c3-0"}}
@@ -0,0 +1,3 @@
campaign document valid (intrinsic): 1 strategy(ies), 2 axes (4 points), 1 instrument(s), 1 window(s), 1 regime(s) (default) — 1 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
@@ -0,0 +1 @@
{"symbol":"GER40","digits":1,"pipSize":1.0,"tickSize":0.1,"lotSize":1.0,"baseAsset":"DE40","quoteAsset":"EUR"}
@@ -0,0 +1 @@
registered process 3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0 (/home/brummel/dev/aura/.claude/worktrees/issue-309-trace-handle/fieldtests/cycle-309-trace-handle/c309lab/runs/processes/3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0.json)
@@ -0,0 +1,7 @@
{
"format_version": 1,
"kind": "process",
"name": "c309-explore-only-sweep",
"description": "Selection-free sweep: the family itself is the result.",
"pipeline": [ { "block": "std::sweep" } ]
}
@@ -0,0 +1 @@
registered blueprint 88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6 (/home/brummel/dev/aura/.claude/worktrees/issue-309-trace-handle/fieldtests/cycle-309-trace-handle/c309lab/runs/blueprints/88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6.json)
@@ -0,0 +1,2 @@
aura: no recorded run or family 'c364e8c3-0-GER40-w0-r0-s0-0' under runs/traces — that looks like a family id, not a trace handle. Recorded trace handles for campaign 'c364e8c3': c364e8c3-0.
aura: Did you mean: aura chart c364e8c3-0
@@ -0,0 +1,2 @@
# c309_7_chart_suggested: HTML chart page, 443485 bytes
# series: 88a221aa-GER40-w0/fast.length_2__slow.length_16__stop_length_3__stop_k_2 88a221aa-GER40-w0/fast.length_2__slow.length_8__stop_length_3__stop_k_2 88a221aa-GER40-w0/fast.length_4__slow.length_16__stop_length_3__stop_k_2 88a221aa-GER40-w0/fast.length_4__slow.length_8__stop_length_3__stop_k_2 c364e8c3-0
@@ -0,0 +1 @@
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","kind":"Sweep","members":4}
@@ -0,0 +1,2 @@
aura: campaign run 1 recorded: 1 cells
aura: traces persisted: c364e8c3-1 (2 tap(s) x 1 cell(s))
@@ -0,0 +1,5 @@
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-1","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":2}],["slow.length",{"I64":8}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":1311.7250000000104,"max_drawdown":615.6000000000058,"bias_sign_flips":3977,"r":{"expectancy_r":0.028321444460569407,"n_trades":3903,"win_rate":0.33692031770433,"avg_win_r":1.5089377461851683,"avg_loss_r":-0.7240009808747663,"profit_factor":1.0589943641136834,"max_r_drawdown":78.64539272099334,"n_open_at_end":1,"sqn":1.0540214890316064,"sqn_normalized":0.16871363772287948,"net_expectancy_r":0.028321444460569407,"conviction_terciles_r":[-0.05124882989934285,0.06705254021274346,0.0691606230683076]}}}}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-1","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":2}],["slow.length",{"I64":16}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":35.86250000013888,"max_drawdown":657.0250000000078,"bias_sign_flips":2550,"r":{"expectancy_r":0.001942726488289421,"n_trades":2581,"win_rate":0.2909724912824487,"avg_win_r":1.9096186007126963,"avg_loss_r":-0.7809340940267545,"profit_factor":1.0035086026962674,"max_r_drawdown":72.50403168697483,"n_open_at_end":1,"sqn":0.05152717930726507,"sqn_normalized":0.010142438121122548,"net_expectancy_r":0.001942726488289421,"conviction_terciles_r":[0.003799692660105443,-0.03634478563974999,0.0383309605444476]}}}}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-1","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":4}],["slow.length",{"I64":8}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":742.7500000001023,"max_drawdown":422.36250000000837,"bias_sign_flips":3570,"r":{"expectancy_r":0.025765945651374078,"n_trades":3811,"win_rate":0.358960902650223,"avg_win_r":1.508960221588393,"avg_loss_r":-0.8047742792695608,"profit_factor":1.0499444782267588,"max_r_drawdown":90.38863380823058,"n_open_at_end":1,"sqn":0.8490217221109733,"sqn_normalized":0.1375305967356901,"net_expectancy_r":0.025765945651374078,"conviction_terciles_r":[0.016131381474867954,-0.0014331659738562395,0.06257064137773533]}}}}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-1","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":4}],["slow.length",{"I64":16}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":-70.01874999997267,"max_drawdown":914.4874999999981,"bias_sign_flips":1965,"r":{"expectancy_r":-0.021911292659493667,"n_trades":2388,"win_rate":0.3274706867671692,"avg_win_r":1.76727288256566,"avg_loss_r":-0.8931080703843195,"profit_factor":0.9635201732345389,"max_r_drawdown":132.7156533736896,"n_open_at_end":1,"sqn":-0.5448524993019401,"sqn_normalized":-0.11149664160230002,"net_expectancy_r":-0.021911292659493667,"conviction_terciles_r":[-0.0043670430492390765,-0.0543615931213561,-0.007005241807885511]}}}}
{"campaign_run":{"campaign":"c364e8c309e9f585b29850864258425654abb0bc9ba50c8fc87fd67fbe04f96e","process":"3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0","run":1,"seed":7,"cells":[{"strategy":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","instrument":"GER40","window_ms":[1725148800000,1727740800000],"stages":[{"block":"std::sweep","family_id":"c364e8c3-0-GER40-w0-r0-s0-1"}],"coverage":{"effective_from_ms":1725236099999,"effective_to_ms":1727726220000}}],"trace_name":"c364e8c3-1"}}
@@ -0,0 +1 @@
aura: no recorded run or family 'c364e8c3-0-GER40-w0-r0-s0-1' under runs/traces — that looks like a family id, not a trace handle. Recorded trace handles for campaign 'c364e8c3': c364e8c3-0, c364e8c3-1.
@@ -0,0 +1,2 @@
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","kind":"Sweep","members":4}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-1","kind":"Sweep","members":4}
@@ -0,0 +1,2 @@
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-0","kind":"Sweep","members":4}
{"family_id":"c364e8c3-0-GER40-w0-r0-s0-1","kind":"Sweep","members":4}
@@ -0,0 +1,51 @@
{
"format_version": 1,
"kind": "campaign",
"name": "c309-spread-ger40-sweep-notaps",
"seed": 7,
"data": {
"instruments": [
"GER40"
],
"windows": [
{
"from_ms": 1725148800000,
"to_ms": 1727740800000
}
]
},
"strategies": [
{
"ref": {
"content_id": "88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6"
},
"axes": {
"fast.length": {
"kind": "I64",
"values": [
2,
4
]
},
"slow.length": {
"kind": "I64",
"values": [
8,
16
]
}
}
}
],
"process": {
"ref": {
"content_id": "3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0"
}
},
"presentation": {
"persist_taps": [],
"emit": [
"family_table"
]
}
}
@@ -0,0 +1 @@
aura: no recorded run or family '94355db6-0-GER40-w0-r0-s0-0' under runs/traces — that looks like a family id, not a trace handle. The handle is the `trace_name` the campaign run printed; this id's second segment counts strategies while the handle's counts runs, so cutting the id down is not a way to derive it.
@@ -0,0 +1 @@
aura: no recorded run or family 'deadbeef-0-GER40-w0-r0-s0-0' under runs/traces — that looks like a family id, not a trace handle. The handle is the `trace_name` the campaign run printed; this id's second segment counts strategies while the handle's counts runs, so cutting the id down is not a way to derive it.
@@ -0,0 +1 @@
aura: campaign run 0 recorded: 1 cells
@@ -0,0 +1,5 @@
{"family_id":"94355db6-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":2}],["slow.length",{"I64":8}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":1311.7250000000104,"max_drawdown":615.6000000000058,"bias_sign_flips":3977,"r":{"expectancy_r":0.028321444460569407,"n_trades":3903,"win_rate":0.33692031770433,"avg_win_r":1.5089377461851683,"avg_loss_r":-0.7240009808747663,"profit_factor":1.0589943641136834,"max_r_drawdown":78.64539272099334,"n_open_at_end":1,"sqn":1.0540214890316064,"sqn_normalized":0.16871363772287948,"net_expectancy_r":0.028321444460569407,"conviction_terciles_r":[-0.05124882989934285,0.06705254021274346,0.0691606230683076]}}}}
{"family_id":"94355db6-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":2}],["slow.length",{"I64":16}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":35.86250000013888,"max_drawdown":657.0250000000078,"bias_sign_flips":2550,"r":{"expectancy_r":0.001942726488289421,"n_trades":2581,"win_rate":0.2909724912824487,"avg_win_r":1.9096186007126963,"avg_loss_r":-0.7809340940267545,"profit_factor":1.0035086026962674,"max_r_drawdown":72.50403168697483,"n_open_at_end":1,"sqn":0.05152717930726507,"sqn_normalized":0.010142438121122548,"net_expectancy_r":0.001942726488289421,"conviction_terciles_r":[0.003799692660105443,-0.03634478563974999,0.0383309605444476]}}}}
{"family_id":"94355db6-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":4}],["slow.length",{"I64":8}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":742.7500000001023,"max_drawdown":422.36250000000837,"bias_sign_flips":3570,"r":{"expectancy_r":0.025765945651374078,"n_trades":3811,"win_rate":0.358960902650223,"avg_win_r":1.508960221588393,"avg_loss_r":-0.8047742792695608,"profit_factor":1.0499444782267588,"max_r_drawdown":90.38863380823058,"n_open_at_end":1,"sqn":0.8490217221109733,"sqn_normalized":0.1375305967356901,"net_expectancy_r":0.025765945651374078,"conviction_terciles_r":[0.016131381474867954,-0.0014331659738562395,0.06257064137773533]}}}}
{"family_id":"94355db6-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8","params":[["fast.length",{"I64":4}],["slow.length",{"I64":16}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["bias.scale",{"F64":0.5}]],"window":[1725148800000000000,1727740800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","project":{"commit":"9f87e5a58321ec945c98d86b006d7a0ea84173f8-dirty"}},"metrics":{"total_pips":-70.01874999997267,"max_drawdown":914.4874999999981,"bias_sign_flips":1965,"r":{"expectancy_r":-0.021911292659493667,"n_trades":2388,"win_rate":0.3274706867671692,"avg_win_r":1.76727288256566,"avg_loss_r":-0.8931080703843195,"profit_factor":0.9635201732345389,"max_r_drawdown":132.7156533736896,"n_open_at_end":1,"sqn":-0.5448524993019401,"sqn_normalized":-0.11149664160230002,"net_expectancy_r":-0.021911292659493667,"conviction_terciles_r":[-0.0043670430492390765,-0.0543615931213561,-0.007005241807885511]}}}}
{"campaign_run":{"campaign":"94355db6a5063d6765e04e9cd8ac9d3dc268c915962b6900ef0c9f1d3d420fd4","process":"3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0","run":0,"seed":7,"cells":[{"strategy":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","instrument":"GER40","window_ms":[1725148800000,1727740800000],"stages":[{"block":"std::sweep","family_id":"94355db6-0-GER40-w0-r0-s0-0"}],"coverage":{"effective_from_ms":1725236099999,"effective_to_ms":1727726220000}}]}}
@@ -0,0 +1 @@
{"campaign":"94355db6a5063d6765e04e9cd8ac9d3dc268c915962b6900ef0c9f1d3d420fd4","process":"3c340a4b8dff56aab2440c2b53e4a1b7e78b09068c8111e9941511e618a86fe0","run":0,"seed":7,"cells":[{"strategy":"88a221aa5110cd583bcb084f72239fd575d58ee0cbe0d61ec50effa6dc1c33b6","instrument":"GER40","window_ms":[1725148800000,1727740800000],"stages":[{"block":"std::sweep","family_id":"94355db6-0-GER40-w0-r0-s0-0"}],"coverage":{"effective_from_ms":1725236099999,"effective_to_ms":1727726220000}}]}
@@ -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 @@
# c309lab — 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":"c309lab_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"}]}}