# Fieldtest transcript — cycle #271 (typed construction args) Verbatim command/output capture for the `fieldtests/construction-args/` fixtures. Binary: `target/debug/aura` built from HEAD `6ca359a` via `cargo build --workspace` (debug profile). Runs used a scratch project `aura new ca_lab` (in `/tmp/ca_lab`); real data resolved from the built-in archive (`/mnt/tickdata/Pepperstone`). All op-scripts authored from the public interface only (README, authoring guide, glossary, design ledger C24, `aura graph introspect`). Public interface only — no crate source read. --- ## Discovery loop (axis 3) — is the args grammar learnable from the binary? ``` $ aura graph introspect --vocabulary | wc -l 36 $ aura graph introspect --node Session Session — bars elapsed since the session open, from the configured open time and timezone arg tz: Tz (IANA timezone name, e.g. Europe/Berlin) arg open: TimeOfDay (local wall-clock HH:MM) note ports and params form at construction; args are required $ aura graph introspect --node LinComb LinComb — linear combination of its inputs with constant weights arg arity: Count (positive integer count) note ports and params form at construction; args are required $ aura graph introspect --node CostSum CostSum — sums cost-model contributions into one cost-in-R stream arg n_costs: Count (positive integer count) note ports and params form at construction; args are required ``` The arg *grammar* (name, kind, hint) is fully self-describing. But `--node ` stops at the note — it does NOT reveal the post-construction ports/params. To learn the port names you must author a partial op-list carrying the args and pipe it through `--unwired`; to learn the param names you must build and `--list-axes`. Nothing on the `--node` surface names those follow-up steps. First naive guess at LinComb's input port was `lc.in0` — wrong: ``` $ echo '[{"op":"add","type":"LinComb","name":"lc","args":{"arity":"3"}}]' \ | aura graph introspect --unwired lc.term[0]:F64 lc.term[1]:F64 lc.term[2]:F64 $ echo '[{"op":"add","type":"CostSum","name":"cs","args":{"n_costs":"3"}}]' \ | aura graph introspect --unwired cs.cost[0].cost_in_r:F64 cs.cost[0].cum_cost_in_r:F64 cs.cost[0].open_cost_in_r:F64 cs.cost[1].cost_in_r:F64 (… ×3 slots, 3 fields each) ``` Weight param names, discovered only after a build: ``` $ aura graph build < lc_probe.ops.json > lc_probe.bp.json $ aura sweep lc_probe.bp.json --list-axes graph.lc.weights[0]:F64 # open by default → sweepable (C24) graph.lc.weights[1]:F64 ... ``` --- ## Example 1 — `ca_1_ny_session` (axis 1: non-Frankfurt Session as data) ``` $ aura graph build < ca_1_ny_session.ops.json > ca_1_ny_session.bp.json $ head -c 25 ca_1_ny_session.bp.json {"format_version":2,"blue # arg-bearing → v2 $ aura graph introspect --content-id --identity-id < ca_1_ny_session.ops.json 5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37 # content id 4bf0513a4d2e852ab580fd8846737f57c1825b944ff9df1a48040a07fe92446b # identity id # --- inside ca_lab/ --- $ aura run ca_1_ny_session.bp.json --real US500 --from 1725148800000 --to 1725580800000 {"manifest":{... "topology_hash":"5b085a5b...b40d95cf"? -> 5b085a5b... (== content id) ...}, "metrics":{... "expectancy_r":0.7853745294474523,"n_trades":18 ...}} (exit 0) # synthetic refuses cleanly (OHLC strategy, close-only synthetic stream): $ aura run ca_1_ny_session.bp.json aura: strategy "graph" consumes columns beyond close (open, high, low) — synthetic data generates a close series only; run with --real ``` Full report captured in `ca_1_ny_session.run.json`. --- ## Example 2 — `ca_2_lincomb_blend` (axis 2: LinComb arity + weights + swept period) Three SMA spreads blended through `LinComb(arity 3)` with bound `weights[i]`, NY-session-gated, `Session.period_minutes` left OPEN (sweepable). ``` $ aura graph build < ca_2_lincomb_blend.ops.json > ca_2_lincomb_blend.bp.json $ head -c 25 ca_2_lincomb_blend.bp.json {"format_version":2,"blue $ aura sweep ca_2_lincomb_blend.bp.json --list-axes graph.sess.period_minutes:I64 # open graph.lc.weights[0]:F64 default=0.5 # bound (re-openable by --axis) graph.lc.weights[1]:F64 default=0.3 graph.lc.weights[2]:F64 default=0.2 ... # --- inside ca_lab/ --- sweep the arity-unlocked weight AND the period param: $ aura sweep ca_2_lincomb_blend.bp.json --real US500 --from 1725148800000 --to 1725580800000 \ --axis graph.sess.period_minutes=15,30 --axis 'graph.lc.weights[0]=0.3,0.5' --name ca2_blend {"family_id":"caa3508a-0-US500-w0-r0-s0-0", ... 4 members ...} (exit 0) $ aura reproduce caa3508a-0-US500-w0-r0-s0-0 ... member graph.lc.weights[0]=0.3, graph.sess.period_minutes=15 ... reproduced: bit-identical ... (×4) reproduced 4/4 members bit-identically ``` Sweep output in `ca_2_lincomb_blend.sweep.jsonl`. NB: at this gating, the two `weights[0]` values yield identical member metrics (the gated blend's sign is weight-insensitive here) — a semantic property of the strategy, not the arg channel; the params bound and swept correctly. CostSum arity probe: `ca_2b_costsum_arity.ops.json` → `--unwired` shows `cost[i].{cost_in_r,cum_cost_in_r,open_cost_in_r}` (3 slots × 3 fields). Wiring CostSum end to end needs the RiskExecutor context (cost nodes take `closed/open/entry_price/stop_price`) — no op-script path for that exists in the public corpus (see finding SG2). --- ## Example 3 — refusal battery (axis 4: strict-form refusal prose) Every case: `aura graph build < FIXTURE`, stderr + exit code. ``` ca_3a_bad_tz aura: op 1 (add): node sess arg "tz" expects Tz (IANA timezone name, e.g. Europe/Berlin) — got "berlin" exit 1 ca_3b_unpadded_time aura: op 1 (add): node sess arg "open" expects TimeOfDay (local wall-clock HH:MM) — got "9:30" exit 1 ca_3c_zero_count aura: op 2 (add): node lc arg "arity" expects Count (positive integer count) — got "0" exit 1 ca_3d_garbage_count aura: op 1 (add): node lc arg "arity" expects Count (positive integer count) — got "three" exit 1 ca_3e_missing_arg aura: op 1 (add): node sess is missing required arg "tz" exit 1 ca_3f_args_on_argless aura: op 1 (add): node a takes no construction args exit 1 ca_3g_unknown_arg_key aura: op 1 (add): node sess has no construction arg "region" exit 1 ca_3h_partial_args aura: op 1 (add): node sess is missing required arg "open" exit 1 ``` Edge-form strictness (ad-hoc, `--unwired`): ``` Count arity: "3"→ok "03"→refuse "+3"→refuse "3.0"→refuse "1e1"→refuse "-2"→refuse " 3"→refuse "0x3"→refuse Time open: "09:30"→ok "00:00"→ok "23:59"→ok "24:00"→refuse "09:60"→refuse "9:05"→refuse "09:5"→refuse "09:30:00"→refuse "0930"→refuse ``` Note the padding asymmetry: `open` REQUIRES a zero-padded hour (`09:05`), but `arity` REFUSES a leading zero (`03`). See finding SG1. --- ## Example 4 — `ca_4` register → use (axis 5: #317 interplay) ``` $ aura graph build < ca_4_ny_anchor_pattern.ops.json > ca_4_ny_anchor_pattern.bp.json $ head -c 25 ca_4_ny_anchor_pattern.bp.json {"format_version":2,"blue $ aura graph introspect --content-id --identity-id < ca_4_ny_anchor_pattern.ops.json d51132463b2d1780b3ed9b83dc9f9a229a9d6b93fce3e15c7c0572970e2e4564 863c89ddeaa2dfe7d79c7e55944263145399c67397a27c0955bdd768cc6ed72e # --- inside ca_lab/ --- $ aura graph register .../ca_4_ny_anchor_pattern.bp.json --name ny_anchor registered blueprint d51132463b2d... (.../runs/blueprints/d51132463b2d....json) label "ny_anchor" -> d51132463b2d... $ aura graph introspect --registered ny_anchor d51132463b2d NY cash-open session anchor: bars elapsed since the 09:30 America/New_York open $ aura graph build < ca_4_consumer.ops.json > consumer.bp.json # stderr: aura: note: use "anchor": ny_anchor -> d51132463b2d... $ head -c 25 consumer.bp.json {"format_version":2,"blue # v2 propagates THROUGH the splice $ aura graph introspect --content-id --identity-id < ca_4_consumer.ops.json 985991f62cc6b92895018312c5ea86e493ef1c09dd53cf6e0813551baa97b671 bbe7060f4136255e594e1b01242ae80c3f5decfc543f23198d66adff6ce52a7b $ aura run consumer.bp.json --real US500 --from 1725148800000 --to 1725580800000 {"manifest":{... "topology_hash":"985991f6..." (== content id), "defaults":[["graph.anchor.sess.period_minutes",{"I64":15}], ...] ...}, "metrics":{... "n_trades":8 ...}} (exit 0) # doc gate on the args-bearing composite (doc stripped): $ aura graph register ca4_docless.bp.json --name ny_docless aura: blueprint: composite `graph` carries no doc — a registered composite describes itself (C29); add a doc line (...) before register exit 1 ``` Consumer report captured in `ca_4_consumer.run.json`. --- ## Cross-cutting confirmations ``` # args-free document stays format_version 1 (byte-stability invariant, C18): $ echo '[{"op":"source",...},{"op":"add","type":"SMA",...},...]' | aura graph build | head -c 25 {"format_version":1,"blue # content id deterministic across builds: $ aura graph introspect --content-id < ca_1_ny_session.ops.json (×2) -> identical 5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37 5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37 ```