From d7874e256950587225cd62db5b5ab7b2f674d679 Mon Sep 17 00:00:00 2001 From: claude Date: Mon, 13 Jul 2026 04:50:36 +0200 Subject: [PATCH] =?UTF-8?q?fieldtest:=20bound-override=20cycle=20=E2=80=94?= =?UTF-8?q?=204=20examples,=206=20findings=20(4=20working,=201=20friction,?= =?UTF-8?q?=201=20bug)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per-cycle fieldtest over the #246 surface, consumer-perspective, public interface only: the scaffold quickstart end to end (aura new -> run -> --list-axes -> override sweep), --list-axes on a partially-open blueprint, an override family reproduced bit-identically (3/3 members), and the error surface (wrong axis name, kind-mismatched value — both exit 2). Corpus under fieldtests/cycle-246-bound-override/. Dispositions: the one bug (F6) is fixed in this commit — authoring-guide §1 still asserted a bound param 'never shows up in --list-axes' and 'no aura sweep --axis can reopen it', contradicting the shipped #246 semantics and the C12 amendment; the three-states paragraph now reads open = must-bind, bound = overridable default. The friction finding (F5, KindMismatch/MissingKnob printed as raw Debug structs beside polished prose) is filed as #247. refs #246 --- docs/authoring-guide.md | 16 ++-- .../bo_2_partial_open.json | 1 + .../bo_2_partial_open_opscript.json | 12 +++ .../bo_transcript.txt | 85 +++++++++++++++++++ .../signal-lab/.gitignore | 1 + .../signal-lab/Aura.toml | 4 + .../signal-lab/CLAUDE.md | 14 +++ .../signal-lab/blueprints/partial.json | 1 + .../signal-lab/blueprints/signal.json | 1 + 9 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 fieldtests/cycle-246-bound-override/bo_2_partial_open.json create mode 100644 fieldtests/cycle-246-bound-override/bo_2_partial_open_opscript.json create mode 100644 fieldtests/cycle-246-bound-override/bo_transcript.txt create mode 100644 fieldtests/cycle-246-bound-override/signal-lab/.gitignore create mode 100644 fieldtests/cycle-246-bound-override/signal-lab/Aura.toml create mode 100644 fieldtests/cycle-246-bound-override/signal-lab/CLAUDE.md create mode 100644 fieldtests/cycle-246-bound-override/signal-lab/blueprints/partial.json create mode 100644 fieldtests/cycle-246-bound-override/signal-lab/blueprints/signal.json diff --git a/docs/authoring-guide.md b/docs/authoring-guide.md index 97f6b97..158dfd4 100644 --- a/docs/authoring-guide.md +++ b/docs/authoring-guide.md @@ -259,14 +259,16 @@ purpose — three open campaign axes, see §3. This is the milestone fieldtest corpus's own example, verified below; byte-identical to the on-disk `fieldtests/milestone-research-artifacts/mra_1_strategy_smacross.json`.) -A `bind` in an `add` op pins that param to a fixed value and **removes it -from the sweepable param space**: a bound param is closed — it never shows -up in `--params`/`--list-axes`, and no campaign axis and no `aura sweep ---axis` can reopen it. `bind` is for a constant the strategy never varies; -leave a param unbound, as all three are here, to keep it open for sweeping. +A `bind` in an `add` op pins that param to a value and removes it from the +**open** param space (`--params`): a bound param is a **default** (#246) — a +run uses it as-is, while any campaign axis or `aura sweep --axis` naming it +re-opens it for that family and binds it per cell. `--list-axes` lists it +after the open knobs as `: default=`. `bind` is for a +value the strategy carries by default; leave a param unbound, as all three +are here, to make binding it mandatory for every sweep. -A param therefore has three states: **open** (a sweepable axis), **bound** -(closed by a `bind` — gone from the axis namespace), and **ganged** (open, but +A param therefore has three states: **open** (an axis every sweep MUST bind), +**bound** (a default any axis MAY override, #246), and **ganged** (open, but fused with its siblings under ONE public knob declared by a `gang` op; the member addresses are unbindable and only the gang's own single-segment name — wrapped like any knob, e.g. `graph.channel_length` — appears in `--list-axes`). diff --git a/fieldtests/cycle-246-bound-override/bo_2_partial_open.json b/fieldtests/cycle-246-bound-override/bo_2_partial_open.json new file mode 100644 index 0000000..5c39c03 --- /dev/null +++ b/fieldtests/cycle-246-bound-override/bo_2_partial_open.json @@ -0,0 +1 @@ +{"format_version":1,"blueprint":{"name":"graph","nodes":[{"primitive":{"type":"SMA","name":"fast"}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":4}}]}},{"primitive":{"type":"Sub","name":"sub"}},{"primitive":{"type":"Bias","name":"bias"}}],"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"}]}} \ No newline at end of file diff --git a/fieldtests/cycle-246-bound-override/bo_2_partial_open_opscript.json b/fieldtests/cycle-246-bound-override/bo_2_partial_open_opscript.json new file mode 100644 index 0000000..b851dab --- /dev/null +++ b/fieldtests/cycle-246-bound-override/bo_2_partial_open_opscript.json @@ -0,0 +1,12 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "SMA", "name": "fast"}, + {"op": "add", "type": "SMA", "name": "slow", "bind": {"length": {"I64": 4}}}, + {"op": "feed", "role": "price", "into": ["fast.series", "slow.series"]}, + {"op": "add", "type": "Sub", "name": "sub"}, + {"op": "connect", "from": "fast.value", "to": "sub.lhs"}, + {"op": "connect", "from": "slow.value", "to": "sub.rhs"}, + {"op": "add", "type": "Bias", "name": "bias"}, + {"op": "connect", "from": "sub.value", "to": "bias.signal"}, + {"op": "expose", "from": "bias.bias", "as": "bias"} +] diff --git a/fieldtests/cycle-246-bound-override/bo_transcript.txt b/fieldtests/cycle-246-bound-override/bo_transcript.txt new file mode 100644 index 0000000..845fada --- /dev/null +++ b/fieldtests/cycle-246-bound-override/bo_transcript.txt @@ -0,0 +1,85 @@ +Field test — cycle-246-bound-override — verbatim transcript +Binary: target/debug/aura (built from HEAD 9d4e4c7, `cargo build -p aura-cli`) +All runs synthetic (no --real). Project = the scaffolded signal-lab/. + +===================================================================== +EXAMPLE 1 — quickstart end to end (axis 1), exactly as scaffolded CLAUDE.md +===================================================================== + +$ aura new signal-lab +created project "signal-lab" (data-only; attach native nodes later with `aura nodes new`) + # scaffold ships ONE blueprint: signal-lab/blueprints/signal.json (all params bound) + +# CLAUDE.md quickstart advertises, verbatim: +# Run: aura run blueprints/signal.json +# Sweep: aura sweep blueprints/signal.json --axis signal_lab_signal.fast.length=2,4,8 +# (aura sweep --list-axes lists open + bound-overridable axes) + +$ aura run blueprints/signal.json # [exit 0] +{"manifest":{...,"params":[],...},"metrics":{"total_pips":0.3418...,"r":{"expectancy_r":1.271...,"n_trades":3,...}}} + +$ aura sweep blueprints/signal.json --list-axes # [exit 0] +signal_lab_signal.fast.length:I64 default=2 +signal_lab_signal.slow.length:I64 default=4 +signal_lab_signal.bias.scale:F64 default=0.5 + +$ aura sweep blueprints/signal.json --axis signal_lab_signal.fast.length=2,4,8 # [exit 0] +{"family_id":"sweep-0","report":{"manifest":{"params":[["signal_lab_signal.fast.length",{"I64":2}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],...}}} +{"family_id":"sweep-0","report":{"manifest":{"params":[["signal_lab_signal.fast.length",{"I64":4}],...]}}} +{"family_id":"sweep-0","report":{"manifest":{"params":[["signal_lab_signal.fast.length",{"I64":8}],...]}}} + # bound fast.length overridden per member; slow.length + bias.scale stay at their bound defaults. + +===================================================================== +EXAMPLE 2 — --list-axes on a partially-open blueprint (axis 2) +===================================================================== +# op-script bo_2_partial_open_opscript.json binds slow.length=4, leaves fast.length + bias.scale open. + +$ aura graph build < bo_2_partial_open_opscript.json > bo_2_partial_open.json # [exit 0] (name = "graph") + +$ aura graph introspect --params bo_2_partial_open.json # [exit 0] (raw namespace, OPEN only) +fast.length:I64 +bias.scale:F64 + +$ aura sweep bo_2_partial_open.json --list-axes # [exit 0] +graph.fast.length:I64 # open knobs first, NO default= +graph.bias.scale:F64 +graph.slow.length:I64 default=4 # bound param last, WITH default= + +# bound is optional (uses default); open is still required: +$ aura sweep blueprints/partial.json --axis graph.fast.length=2,4 --axis graph.bias.scale=0.5 --name bo2d # [exit 0] + # 2 members run; slow.length omitted -> stays at default 4 (absent from manifest params). +$ aura sweep blueprints/partial.json --axis graph.fast.length=2,4 # [exit 2] +aura: MissingKnob("graph.bias.scale") # <-- raw Debug enum print (see finding F5) + +===================================================================== +EXAMPLE 3 — override sweep + reproduce (axis 3) +===================================================================== +$ aura sweep blueprints/signal.json --axis signal_lab_signal.fast.length=2,4,8 --name bo3-override # [exit 0] +$ aura runs families # [exit 0] +{"family_id":"sweep-0","kind":"Sweep","members":3} +{"family_id":"bo2d-0","kind":"Sweep","members":2} +{"family_id":"bo3-override-0","kind":"Sweep","members":3} + +$ aura reproduce bo3-override-0 # [exit 0] (help says "content id"; the name works too) +bo3-override-0 member signal_lab_signal.fast.length=2, stop_length=3, stop_k=2 reproduced: bit-identical +bo3-override-0 member signal_lab_signal.fast.length=4, stop_length=3, stop_k=2 reproduced: bit-identical +bo3-override-0 member signal_lab_signal.fast.length=8, stop_length=3, stop_k=2 reproduced: bit-identical +reproduced 3/3 members bit-identically + +===================================================================== +EXAMPLE 4 — error surface (axis 4) +===================================================================== +$ aura sweep blueprints/signal.json --axis signal_lab_signal.nonexistent=1,2 # [exit 2] CLEAN +aura: axis signal_lab_signal.nonexistent: names no param of this blueprint (open or bound) — see `aura sweep --list-axes` + +$ aura sweep blueprints/signal.json --axis totally.bogus=1 # [exit 2] CLEAN (retired "nothing to sweep" gone) +aura: axis totally.bogus: names no param of this blueprint (open or bound) — see `aura sweep --list-axes` + +$ aura sweep blueprints/signal.json --axis signal_lab_signal.fast.length=1.5,2.5 # [exit 2] RAW DEBUG (finding F5) +aura: KindMismatch { knob: "signal_lab_signal.fast.length", expected: I64, got: F64 } + +# run/mc still refuse open blueprints: +$ aura run blueprints/partial.json # [exit 2] +aura: run requires a closed blueprint (no free parameters); 2 free knob(s) — bind them or use `aura sweep --axis` +$ aura mc blueprints/partial.json # [exit 2] (generic usage error, not the open-param prose) +$ aura run blueprints/signal.json # [exit 0] (all bound = closed) diff --git a/fieldtests/cycle-246-bound-override/signal-lab/.gitignore b/fieldtests/cycle-246-bound-override/signal-lab/.gitignore new file mode 100644 index 0000000..306cbf0 --- /dev/null +++ b/fieldtests/cycle-246-bound-override/signal-lab/.gitignore @@ -0,0 +1 @@ +/runs diff --git a/fieldtests/cycle-246-bound-override/signal-lab/Aura.toml b/fieldtests/cycle-246-bound-override/signal-lab/Aura.toml new file mode 100644 index 0000000..d45dade --- /dev/null +++ b/fieldtests/cycle-246-bound-override/signal-lab/Aura.toml @@ -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 diff --git a/fieldtests/cycle-246-bound-override/signal-lab/CLAUDE.md b/fieldtests/cycle-246-bound-override/signal-lab/CLAUDE.md new file mode 100644 index 0000000..062905b --- /dev/null +++ b/fieldtests/cycle-246-bound-override/signal-lab/CLAUDE.md @@ -0,0 +1,14 @@ +# signal-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 run blueprints/signal.json` (the starter is closed — all + params bound; bound values are defaults — any `--axis` may override them + (#246)) +- Sweep: `aura sweep blueprints/signal.json --axis signal_lab_signal.fast.length=2,4,8` + (`aura sweep --list-axes` lists the open + bound-overridable axes) +- Native nodes: when the project needs its first project-specific node, + `aura nodes new ` 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/`. diff --git a/fieldtests/cycle-246-bound-override/signal-lab/blueprints/partial.json b/fieldtests/cycle-246-bound-override/signal-lab/blueprints/partial.json new file mode 100644 index 0000000..5c39c03 --- /dev/null +++ b/fieldtests/cycle-246-bound-override/signal-lab/blueprints/partial.json @@ -0,0 +1 @@ +{"format_version":1,"blueprint":{"name":"graph","nodes":[{"primitive":{"type":"SMA","name":"fast"}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":4}}]}},{"primitive":{"type":"Sub","name":"sub"}},{"primitive":{"type":"Bias","name":"bias"}}],"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"}]}} \ No newline at end of file diff --git a/fieldtests/cycle-246-bound-override/signal-lab/blueprints/signal.json b/fieldtests/cycle-246-bound-override/signal-lab/blueprints/signal.json new file mode 100644 index 0000000..386a12d --- /dev/null +++ b/fieldtests/cycle-246-bound-override/signal-lab/blueprints/signal.json @@ -0,0 +1 @@ +{"format_version":1,"blueprint":{"name":"signal_lab_signal","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":2}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":4}}]}},{"primitive":{"type":"Sub"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":0.5}}]}}],"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"}]}} \ No newline at end of file