fieldtest: m1-self-description — 5 examples, 1 bug / 3 friction / 3 spec-gap
Binary-only milestone fieldtest for milestone 36 (self-description): a
fieldtester agent bootstrapped from the release binary (d26f0c8) alone —
no engine sources, no repo docs, no bootstrap card — and drove five
end-to-end scenarios: cold bootstrap -> author -> validate (green,
synthetic + real EURUSD, 3944 trades), execution semantics +
latch/edge-pulse idiom (green), vocabulary breadth (33 nodes / 7 folds /
17 metrics / 6+6 blocks, every entry with a meaning), document ramp from
a bare {} (green, 3 members), trace/measurement path (dead-ends,
tracked).
Verdict: the bootstrap card (#267, closed as superseded) is empirically
redundant for the bootstrap->author->validate spine. Two seams keep the
promise short of end-to-end, both tracked outside M1: the declared-tap
drop on the registration path (#327, the missing mechanism of #312/M6)
and the sugar<->document axis namespace (#328, prerequisite of the #319
retirement). Friction routed: #329 #330 #331; evidence comments on #312
and #324. Milestone 36 closed with this adjudication; the fieldtest spec
remains the usual git-ignored working file.
refs #267, refs #312, refs #319
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# Milestone 36 fieldtest — "Self-description: every surface explains itself"
|
||||
|
||||
Empirical, binary-only check of the milestone promise: that a deployment-posture
|
||||
agent with **only** the `aura` binary (no engine sources, no repo docs, no
|
||||
hand-written bootstrap card) can bootstrap from the surfaces alone.
|
||||
|
||||
Every artefact here was produced touching nothing but the release binary
|
||||
(`d26f0c8`) and what it emits (help text, `aura new` scaffold, introspection
|
||||
output, error messages). One child dir per scenario; each README states the
|
||||
property it protects. Full findings + verdict: `docs/specs/fieldtest-m1-self-description.md`.
|
||||
|
||||
| dir | axis | outcome |
|
||||
|-----|------|---------|
|
||||
| s1_bootstrap_author_validate | cold bootstrap → author → validate | green |
|
||||
| s2_execution_pulse_idiom | execution semantics + pulse idiom | green (1 friction) |
|
||||
| s3_vocabulary_breadth | vocabulary self-description breadth| pass (1 friction) |
|
||||
| s4_document_ramp | document-first ramp from `{}` | green (2 gaps) |
|
||||
| s5_trace_measurement | trace / measurement path | dead-end (1 bug, 1 gap) |
|
||||
@@ -0,0 +1,33 @@
|
||||
# s1 — cold bootstrap → author → validate
|
||||
|
||||
**Protected property:** starting from `aura --help` alone (no repo, no docs), a
|
||||
downstream agent can scaffold a project, author a new strategy over the
|
||||
discovered op-grammar vocabulary, and drive it to a green backtest — using only
|
||||
what the binary emits.
|
||||
|
||||
## Trail (binary-only)
|
||||
1. `aura --help` — states what aura is, the two-layer model, and the execution
|
||||
model (bias in [-1,+1], held as target position, stop = R).
|
||||
2. `aura new demo-strat` — scaffolds `Aura.toml`, `blueprints/signal.json`, and a
|
||||
machine-written `CLAUDE.md` bootstrap card.
|
||||
3. `aura graph build --help` — the op-list authoring grammar (one line of meaning
|
||||
per op).
|
||||
4. `aura graph introspect --vocabulary` / `--node <T>` — node types and port
|
||||
schemas.
|
||||
5. Author `ema_cross.oplist.json` (this dir); build it:
|
||||
`aura graph build < ema_cross.oplist.json > blueprints/ema_cross.json`
|
||||
6. Validate green:
|
||||
- synthetic: `aura run blueprints/ema_cross.json` → exit 0 (18-cycle synthetic
|
||||
stream → 0 trades; all-zero metrics, no note that the stream is tiny).
|
||||
- real: `aura run blueprints/ema_cross.json --real EURUSD --from 1577836800000
|
||||
--to 1583020800000` → 3944 trades, valid metrics JSON, exit 0.
|
||||
|
||||
`ema_cross.blueprint.json` is the built artefact `graph build` emitted.
|
||||
|
||||
## Notes
|
||||
- The harness auto-wraps the bias with `sim-optimal+risk-executor` and reports R
|
||||
metrics even though the blueprint emits only a bias — confirming the documented
|
||||
execution model without any extra authoring.
|
||||
- Minor friction: `graph build` has no op to set the blueprint name; it defaults
|
||||
to `graph`, and that name leaks into the sweep axis namespace
|
||||
(`graph.fast.length`).
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"blueprint":{"name":"graph","doc":"EMA(5)/EMA(20) spread clamped to a directional bias","nodes":[{"primitive":{"type":"EMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":5}}]}},{"primitive":{"type":"EMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":20}}]}},{"primitive":{"type":"Sub","name":"spread"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":0.25}}]}}],"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,13 @@
|
||||
[
|
||||
{"op":"source","role":"price","kind":"F64"},
|
||||
{"op":"add","type":"EMA","name":"fast","bind":{"length":{"I64":5}}},
|
||||
{"op":"add","type":"EMA","name":"slow","bind":{"length":{"I64":20}}},
|
||||
{"op":"feed","role":"price","into":["fast.series","slow.series"]},
|
||||
{"op":"add","type":"Sub","name":"spread"},
|
||||
{"op":"connect","from":"fast.value","to":"spread.lhs"},
|
||||
{"op":"connect","from":"slow.value","to":"spread.rhs"},
|
||||
{"op":"add","type":"Bias","name":"bias","bind":{"scale":{"F64":0.25}}},
|
||||
{"op":"connect","from":"spread.value","to":"bias.signal"},
|
||||
{"op":"expose","from":"bias.bias","as":"bias"},
|
||||
{"op":"doc","text":"EMA(5)/EMA(20) spread clamped to a directional bias"}
|
||||
]
|
||||
@@ -0,0 +1,32 @@
|
||||
# s2 — execution semantics + one-shot/pulse idiom
|
||||
|
||||
**Protected property:** from the surfaces alone a consumer can learn (a) what the
|
||||
strategy's output stream means, (b) how it is executed against a protective stop,
|
||||
and (c) the signal-side idiom the surfaces recommend when a held one-shot / pulse
|
||||
behaviour is wanted — and can author that idiom to a green run.
|
||||
|
||||
## What the surfaces say
|
||||
- `aura --help`: "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 signal quality is measured in R."
|
||||
- Node schemas make the execution layer concrete: `Bias` (clamp to [-1,+1]),
|
||||
`FixedStop` (`price → stop_distance`, defines R), `PositionManagement`
|
||||
(`bias + price + stop_distance + size → managed position in R`). The built-in
|
||||
`run`/`sweep` harness supplies this risk executor automatically.
|
||||
- The scaffolded `CLAUDE.md`: "Entry signals become held state via the signal-side
|
||||
latch/edge-pulse idiom (see `aura graph introspect --vocabulary`)."
|
||||
|
||||
## Authored idioms (both build + validate green)
|
||||
- `latch_hold.oplist.json` — momentary crossover events → held state via `Latch`
|
||||
(`set = fast>slow`, `reset = slow>fast`), held level → `Bias`. Runs green
|
||||
(2543 trades over EURUSD 2020-01..03).
|
||||
- `edge_pulse.oplist.json` — the complementary one-shot pulse, built as the
|
||||
first-difference of the latched level (`Delay(lag=1)` + `Sub`) fed to `Bias`
|
||||
(+1 on entry edge, −1 on exit edge, 0 held). Builds + validates green.
|
||||
|
||||
## Friction recorded
|
||||
The `CLAUDE.md` names the "latch/edge-pulse idiom" and points to
|
||||
`graph introspect --vocabulary`, but that surface only lists node one-liners —
|
||||
it lists `Latch` but no `edge`/`pulse` primitive and no composition recipe. The
|
||||
pulse *is* constructible (Latch→Delay→Sub→Bias), but the consumer must infer the
|
||||
first-difference recipe; the pointer resolves to a list, not a recipe.
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"blueprint":{"name":"graph","doc":"edge-pulse: first-difference of the latched level, +1 on entry edge -1 on exit edge","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":5}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":20}}]}},{"primitive":{"type":"Gt","name":"cross_up"}},{"primitive":{"type":"Gt","name":"cross_dn"}},{"primitive":{"type":"Latch","name":"hold"}},{"primitive":{"type":"Delay","name":"prev","bound":[{"pos":0,"name":"lag","kind":"I64","value":{"I64":1}}]}},{"primitive":{"type":"Sub","name":"edge"}},{"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":0,"from_field":0},{"from":0,"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},{"from":4,"to":6,"slot":0,"from_field":0},{"from":5,"to":6,"slot":1,"from_field":0},{"from":6,"to":7,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0}],"source":"F64"}],"output":[{"node":7,"field":0,"name":"bias"}]}}
|
||||
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{"op":"source","role":"price","kind":"F64"},
|
||||
{"op":"add","type":"SMA","name":"fast","bind":{"length":{"I64":5}}},
|
||||
{"op":"add","type":"SMA","name":"slow","bind":{"length":{"I64":20}}},
|
||||
{"op":"feed","role":"price","into":["fast.series","slow.series"]},
|
||||
{"op":"add","type":"Gt","name":"cross_up"},
|
||||
{"op":"connect","from":"fast.value","to":"cross_up.a"},
|
||||
{"op":"connect","from":"slow.value","to":"cross_up.b"},
|
||||
{"op":"add","type":"Gt","name":"cross_dn"},
|
||||
{"op":"connect","from":"slow.value","to":"cross_dn.a"},
|
||||
{"op":"connect","from":"fast.value","to":"cross_dn.b"},
|
||||
{"op":"add","type":"Latch","name":"hold"},
|
||||
{"op":"connect","from":"cross_up.value","to":"hold.set"},
|
||||
{"op":"connect","from":"cross_dn.value","to":"hold.reset"},
|
||||
{"op":"add","type":"Delay","name":"prev","bind":{"lag":{"I64":1}}},
|
||||
{"op":"connect","from":"hold.value","to":"prev.series"},
|
||||
{"op":"add","type":"Sub","name":"edge"},
|
||||
{"op":"connect","from":"hold.value","to":"edge.lhs"},
|
||||
{"op":"connect","from":"prev.value","to":"edge.rhs"},
|
||||
{"op":"add","type":"Bias","name":"bias","bind":{"scale":{"F64":1.0}}},
|
||||
{"op":"connect","from":"edge.value","to":"bias.signal"},
|
||||
{"op":"expose","from":"bias.bias","as":"bias"},
|
||||
{"op":"doc","text":"edge-pulse: first-difference of the latched level, +1 on entry edge -1 on exit edge"}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"blueprint":{"name":"graph","doc":"latched long: set on fast>slow, reset on slow>fast, held as bias","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":5}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":20}}]}},{"primitive":{"type":"Gt","name":"cross_up"}},{"primitive":{"type":"Gt","name":"cross_dn"}},{"primitive":{"type":"Latch","name":"hold"}},{"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":0,"from_field":0},{"from":0,"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}],"source":"F64"}],"output":[{"node":5,"field":0,"name":"bias"}]}}
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{"op":"source","role":"price","kind":"F64"},
|
||||
{"op":"add","type":"SMA","name":"fast","bind":{"length":{"I64":5}}},
|
||||
{"op":"add","type":"SMA","name":"slow","bind":{"length":{"I64":20}}},
|
||||
{"op":"feed","role":"price","into":["fast.series","slow.series"]},
|
||||
{"op":"add","type":"Gt","name":"cross_up"},
|
||||
{"op":"connect","from":"fast.value","to":"cross_up.a"},
|
||||
{"op":"connect","from":"slow.value","to":"cross_up.b"},
|
||||
{"op":"add","type":"Gt","name":"cross_dn"},
|
||||
{"op":"connect","from":"slow.value","to":"cross_dn.a"},
|
||||
{"op":"connect","from":"fast.value","to":"cross_dn.b"},
|
||||
{"op":"add","type":"Latch","name":"hold"},
|
||||
{"op":"connect","from":"cross_up.value","to":"hold.set"},
|
||||
{"op":"connect","from":"cross_dn.value","to":"hold.reset"},
|
||||
{"op":"add","type":"Bias","name":"bias","bind":{"scale":{"F64":1.0}}},
|
||||
{"op":"connect","from":"hold.value","to":"bias.signal"},
|
||||
{"op":"expose","from":"bias.bias","as":"bias"},
|
||||
{"op":"doc","text":"latched long: set on fast>slow, reset on slow>fast, held as bias"}
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
# s3 — vocabulary self-description breadth
|
||||
|
||||
**Protected property:** every closed-vocabulary entry class the binary exposes is
|
||||
reachable and carries a non-empty one-line meaning, and no entry's meaning is a
|
||||
byte-identical (non-discriminating) duplicate of a sibling in the same class.
|
||||
|
||||
`breadth_probe.sh` drives only `aura` introspection output; `breadth_probe.out`
|
||||
is its captured result. Run with `AURA=<path-to-release-aura> bash breadth_probe.sh`.
|
||||
|
||||
## Result (see breadth_probe.out)
|
||||
- 33/33 node types resolve via `graph introspect --node <T>` with a
|
||||
`"<Name> — <meaning>"` schema. PASS.
|
||||
- 7/7 folds, 6/6 process blocks, 6/6 campaign blocks, 17/17 metrics reachable and
|
||||
carry a meaning (metrics also carry applicability tags). PASS.
|
||||
- **One blemish:** three distinct node types — `CarryCost`, `ConstantCost`,
|
||||
`VolSlippageCost` — share the byte-identical one-liner
|
||||
*"cost-model node: charges its cost in R from position geometry, at close or
|
||||
accrued per held cycle"*. From `--vocabulary` (the primary discovery surface)
|
||||
a consumer cannot tell them apart; the distinguishing detail (the param
|
||||
`carry_per_cycle` vs `cost_per_trade` vs `slip_vol_mult`, and the extra
|
||||
`volatility` input) lives only in `--node` and in the campaign `cost` slot
|
||||
prose. The one-liner exists (C29 satisfied) but is not entry-specific.
|
||||
@@ -0,0 +1,45 @@
|
||||
== node vocabulary: every node resolves via --node with a meaning ==
|
||||
nodes probed: 33
|
||||
== duplicate node one-liners (non-discriminating meanings) ==
|
||||
x3 identical: cost-model node: charges its cost in R from position geometry, at close or accrued per held cycle
|
||||
== folds carry a meaning ==
|
||||
ok: Count
|
||||
ok: Sum
|
||||
ok: Mean
|
||||
ok: Min
|
||||
ok: Max
|
||||
ok: First
|
||||
ok: Last
|
||||
== process blocks resolve via --block ==
|
||||
ok: std::sweep
|
||||
ok: std::gate
|
||||
ok: std::walk_forward
|
||||
ok: std::monte_carlo
|
||||
ok: std::generalize
|
||||
ok: std::grid
|
||||
== campaign blocks resolve via --block ==
|
||||
ok: std::data
|
||||
ok: std::risk
|
||||
ok: std::cost
|
||||
ok: std::strategy
|
||||
ok: std::process_ref
|
||||
ok: std::presentation
|
||||
== metrics carry an applicability tag + meaning ==
|
||||
ok: expectancy_r
|
||||
ok: win_rate
|
||||
ok: avg_win_r
|
||||
ok: avg_loss_r
|
||||
ok: profit_factor
|
||||
ok: max_r_drawdown
|
||||
ok: sqn
|
||||
ok: sqn_normalized
|
||||
ok: net_expectancy_r
|
||||
ok: n_trades
|
||||
ok: n_open_at_end
|
||||
ok: total_pips
|
||||
ok: max_drawdown
|
||||
ok: bias_sign_flips
|
||||
ok: deflated_score
|
||||
ok: overfit_probability
|
||||
ok: neighbourhood_score
|
||||
RESULT: fail=0
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
# Scenario 3 — vocabulary self-description breadth probe.
|
||||
# Protected property: every closed-vocabulary entry class the binary exposes is
|
||||
# REACHABLE and carries a non-empty one-line meaning; no entry's meaning is a
|
||||
# byte-for-byte duplicate of another entry in the SAME class (a duplicate is a
|
||||
# non-discriminating meaning).
|
||||
# Binary-only: uses nothing but `aura` introspection output.
|
||||
set -u
|
||||
AURA="${AURA:?set AURA to the release binary path}"
|
||||
|
||||
fail=0
|
||||
|
||||
echo "== node vocabulary: every node resolves via --node with a meaning =="
|
||||
nodes=$("$AURA" graph introspect --vocabulary | awk '{print $1}')
|
||||
for n in $nodes; do
|
||||
line=$("$AURA" graph introspect --node "$n" 2>&1 | head -1)
|
||||
case "$line" in
|
||||
"$n — "*) : ;; # "<Name> — <meaning>"
|
||||
*) echo " MISSING/BAD meaning for node $n: [$line]"; fail=1 ;;
|
||||
esac
|
||||
done
|
||||
echo " nodes probed: $(echo "$nodes" | wc -w)"
|
||||
|
||||
echo "== duplicate node one-liners (non-discriminating meanings) =="
|
||||
"$AURA" graph introspect --vocabulary \
|
||||
| sed -E 's/^[A-Za-z0-9_]+ +//' \
|
||||
| sort | uniq -c | sort -rn \
|
||||
| awk '$1 > 1 { print " x"$1" identical: "substr($0, index($0,$2)) }'
|
||||
|
||||
echo "== folds carry a meaning =="
|
||||
"$AURA" graph introspect --folds | awk 'NF==0{next} {print " ok: "$1}'
|
||||
|
||||
echo "== process blocks resolve via --block =="
|
||||
for b in $("$AURA" process introspect --vocabulary | awk '{print $1}'); do
|
||||
"$AURA" process introspect --block "$b" >/dev/null 2>&1 && echo " ok: $b" || { echo " BAD: $b"; fail=1; }
|
||||
done
|
||||
|
||||
echo "== campaign blocks resolve via --block =="
|
||||
for b in $("$AURA" campaign introspect --vocabulary | awk '{print $1}'); do
|
||||
"$AURA" campaign introspect --block "$b" >/dev/null 2>&1 && echo " ok: $b" || { echo " BAD: $b"; fail=1; }
|
||||
done
|
||||
|
||||
echo "== metrics carry an applicability tag + meaning =="
|
||||
"$AURA" process introspect --metrics | awk '{print " ok: "$1}'
|
||||
|
||||
echo "RESULT: fail=$fail"
|
||||
@@ -0,0 +1,38 @@
|
||||
# s4 — document-first ramp (grow from `{}` to a runnable campaign)
|
||||
|
||||
**Protected property:** using only `--unwired` introspection and validation
|
||||
diagnostics, a consumer can grow a process document and a campaign document from a
|
||||
bare `{}` to a registered, runnable state, and run the campaign green.
|
||||
|
||||
## Trail (binary-only)
|
||||
1. `echo '{}' > x.json; aura process introspect --unwired x.json` — lists the
|
||||
whole envelope (`format_version`, `kind`, `name`, `pipeline`).
|
||||
2. Grow `process.json`: `--unwired` on a doc with `pipeline:[]` says "a process
|
||||
needs at least one stage"; a stage `{}` is told `pipeline[0].block (required,
|
||||
block id)` → correct shape is `{"block":"std::sweep"}`.
|
||||
`aura process validate` → valid; `aura process register` → content id.
|
||||
3. Grow `campaign.json` similarly (`aura campaign introspect --unwired`,
|
||||
`--block std::*`). `aura campaign validate` passes all three tiers
|
||||
(intrinsic / referential / executable); `register` → content id;
|
||||
`campaign run <id>` → 3 members, green.
|
||||
|
||||
`process.json` and `campaign.json` in this dir are the final registered forms;
|
||||
`ema_open.oplist.json` is the strategy authored with an **open** `fast.length`
|
||||
param (see friction 2).
|
||||
|
||||
## Frictions recorded
|
||||
1. **`process.ref` shape under-documented.** `campaign introspect --block
|
||||
std::process_ref` and `--unwired` both describe it as *"content id of a process
|
||||
document"* (reads as a bare string), but the validator rejects the bare string:
|
||||
`unknown variant '<id>', expected 'content_id' or 'identity_id'` — the tagged
|
||||
`{"content_id": "<id>"}` form is required and appears nowhere in the
|
||||
introspection. Recoverable only via the validate error.
|
||||
2. **Two-layer axis-namespace seam.** `aura sweep <bp> --list-axes` presents
|
||||
`graph.fast.length` as sweepable (overriding the *bound* default, #246), and
|
||||
the sugar `aura sweep --axis graph.fast.length=…` accepts it. But the canonical
|
||||
**document** form rejects that same name: `axis "graph.fast.length" is not in
|
||||
the param space` — a campaign axis must be an **open** param, named **without**
|
||||
the `graph.` prefix (`fast.length`, per `graph introspect --params`, which
|
||||
prints *nothing* for a fully-bound blueprint). The name a consumer learns from
|
||||
the sugar (`graph.fast.length`) is not the name the document layer wants
|
||||
(`fast.length`), and no surface reconciles the two.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"format_version":1,
|
||||
"kind":"campaign",
|
||||
"name":"ema_axis_sweep",
|
||||
"data":{"instruments":["EURUSD"],"windows":[{"from_ms":1577836800000,"to_ms":1583020800000}]},
|
||||
"strategies":[{"ref":{"content_id":"2c94edd4e3a3253fa446f2700f5ada1cb4cb9ceafcd99494d8d8e5244e3148a6"},"axes":{"fast.length":{"kind":"I64","values":[3,5,8]}}}],
|
||||
"process":{"ref":{"content_id":"b3c0f7548731f4078ac6f0ba4444781ff51b067b4dd25567a12c49423b5d63ef"}},
|
||||
"seed":0,
|
||||
"presentation":{"persist_taps":["r_equity"],"emit":["family_table"]}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[
|
||||
{"op":"source","role":"price","kind":"F64"},
|
||||
{"op":"add","type":"EMA","name":"fast"},
|
||||
{"op":"add","type":"EMA","name":"slow","bind":{"length":{"I64":20}}},
|
||||
{"op":"feed","role":"price","into":["fast.series","slow.series"]},
|
||||
{"op":"add","type":"Sub","name":"spread"},
|
||||
{"op":"connect","from":"fast.value","to":"spread.lhs"},
|
||||
{"op":"connect","from":"slow.value","to":"spread.rhs"},
|
||||
{"op":"add","type":"Bias","name":"bias","bind":{"scale":{"F64":0.25}}},
|
||||
{"op":"connect","from":"spread.value","to":"bias.signal"},
|
||||
{"op":"expose","from":"bias.bias","as":"bias"},
|
||||
{"op":"doc","text":"EMA(open fast)/EMA(20) spread bias, fast.length swept by campaign"}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"kind":"process","name":"minimal_sweep","pipeline":[{"block":"std::sweep"}]}
|
||||
@@ -0,0 +1,39 @@
|
||||
# s5 — trace / measurement path
|
||||
|
||||
**Protected property:** from the surfaces a consumer can discover which verbs
|
||||
persist per-cycle traces and reach a signal-quality measurement — the milestone's
|
||||
own headline being "signal quality is measured in R".
|
||||
|
||||
## What the surfaces say
|
||||
`aura --help`: "Traces: `sweep --real --trace` / `walkforward --real --trace`
|
||||
record per-cycle taps under runs/, consumed by `aura chart` and `aura measure`."
|
||||
`aura measure ic --help`: "Information Coefficient of a **signal** tap against
|
||||
forward returns of a **price** tap" — requires `--signal <SIGNAL>` and
|
||||
`--price <PRICE>`.
|
||||
|
||||
## What actually happens
|
||||
- Discovery works: `runs families` lists the traced families; `measure ic`'s
|
||||
`<RUN>` is the member path **relative to** `runs/traces/`
|
||||
(`<family>/<instr-window>/<param-combo>`); the missing-tap error is clear and
|
||||
lists available taps. `measure ic` runs green on the persisted taps.
|
||||
- **Dead-end for the intended inputs.** The only taps any surface-reachable verb
|
||||
persists are the closed presentation set `equity` / `exposure` / `r_equity`
|
||||
(`net_r_equity`) — execution-side R/pip curves, **not** the strategy's bias
|
||||
signal nor the instrument price. So `measure ic` can only be fed, e.g.,
|
||||
`--signal exposure --price equity`, which is not a signal-vs-price IC at all
|
||||
(result ≈ noise, 0.0019).
|
||||
- **Declared taps are silently dropped.** `graph build --help` documents the op
|
||||
`tap` as *"declare a **recordable** tap on a wire"*. `tapped.oplist.json` (this
|
||||
dir) declares `tap bias.bias as signal` and `tap fast.value as price`, yet after
|
||||
`sweep --real --trace` the persisted set is still `["equity","exposure",
|
||||
"r_equity"]`; both `measure ic --signal signal` and `chart --tap signal` report
|
||||
the tap does not exist. There is no surface-documented path to persist a genuine
|
||||
signal or price tap, so `measure ic`'s stated contract is unreachable end-to-end.
|
||||
|
||||
## Evidence (verbatim)
|
||||
```
|
||||
$ aura measure ic --signal signal --price price <tapped-run>
|
||||
aura: run '…' has no tap 'signal' (taps: ["equity", "exposure", "r_equity"])
|
||||
$ aura chart 010f8afa-0 --tap signal
|
||||
aura: no family member has a tap named 'signal' (exit 0)
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
[
|
||||
{"op":"source","role":"price","kind":"F64"},
|
||||
{"op":"add","type":"SMA","name":"fast","bind":{"length":{"I64":5}}},
|
||||
{"op":"add","type":"SMA","name":"slow","bind":{"length":{"I64":20}}},
|
||||
{"op":"feed","role":"price","into":["fast.series","slow.series"]},
|
||||
{"op":"add","type":"Sub","name":"spread"},
|
||||
{"op":"connect","from":"fast.value","to":"spread.lhs"},
|
||||
{"op":"connect","from":"slow.value","to":"spread.rhs"},
|
||||
{"op":"add","type":"Bias","name":"bias","bind":{"scale":{"F64":0.25}}},
|
||||
{"op":"connect","from":"spread.value","to":"bias.signal"},
|
||||
{"op":"tap","from":"bias.bias","as":"signal"},
|
||||
{"op":"tap","from":"fast.value","as":"price"},
|
||||
{"op":"expose","from":"bias.bias","as":"bias"},
|
||||
{"op":"doc","text":"tapped: bias exposed and tapped as signal, fast tapped as price"}
|
||||
]
|
||||
Reference in New Issue
Block a user