feat(cli,docs): ship the ganged open examples + document the gang construct (#61 tasks 7-8)
The two open examples now expose their author-intended single knobs — the closed builders always bound these pairs to one value by hand; the open forms falsely offered them as independent axes: - r_breakout_open: channel_hi.length + channel_lo.length -> channel_length (the Donchian channel is structurally ONE parameter) - r_meanrev_open: mean_window.length + var_window.length -> window; the band factor stays an independent axis Regenerated via the emitters (never hand-edited); the closed examples are byte-unchanged. The carve builders gang in the open branch only. Test migration: the two axis-namespace pins, five --real e2e invocations (single gang axis, the 10,20 diagonal for the campaign pair — the mismatched 20,40/10,20 grid was exactly the configuration space the gang retires), and the param_stability row counts (4 -> 3). The r-sma walkforward golden anchor is untouched (it never swept a ganged pair). Docs: authoring-guide gains the seventh op + the third param state (open/bound/ganged) + the gang wrap note; README op list + Axis concept; glossary gang entry; ledger C24 records the gang verb and the pre-ship Tier-2 dormancy (no format-version bump while no out-of-repo reader exists). Verified: full workspace suite 1104/0 (--real e2e included, local data present), clippy -D warnings clean, cargo doc clean; live acceptance: introspect --params prints channel_length:I64 alone / window:I64 + band.factor:F64. closes #61
This commit is contained in:
+12
-1
@@ -31,7 +31,7 @@ $ aura graph build < smacross.json > blueprint.json
|
||||
Nodes are referenced by an **identifier** (given by `add`, see below); ports
|
||||
are dotted `<identifier>.<port>` on both sides of a wire.
|
||||
|
||||
### The six ops
|
||||
### The seven ops
|
||||
|
||||
| op | JSON shape | does |
|
||||
|---|---|---|
|
||||
@@ -41,6 +41,7 @@ are dotted `<identifier>.<port>` on both sides of a wire.
|
||||
| `feed` | `{"op":"feed","role":<str>,"into":[<port>, …]}` | fan a previously-declared role into one or more interior input slots, all-or-nothing (a failing target leaves none of the batch wired). |
|
||||
| `connect` | `{"op":"connect","from":<port>,"to":<port>}` | wire one interior output field to one interior input slot. A `connect` that would close a dataflow cycle is rejected immediately — the only legal feedback path is an explicit delay/state node (domain invariant 5). |
|
||||
| `expose` | `{"op":"expose","from":<port>,"as":<str>}` | promote an interior output field to a boundary output under the alias `as` — the only op whose name key is a real *alias* (contrast `add`'s `name`, which is an identifier, not a rename). |
|
||||
| `gang` | `{"op":"gang","as":"channel_length","into":["channel_hi.length","channel_lo.length"]}` | Fuse two or more sibling params into ONE public knob: the member addresses leave the sweepable param space and `as` replaces them; the bound or swept value fans out to every member at bootstrap. Members must share one scalar kind and stay open (un-bound). |
|
||||
|
||||
Value forms are the typed-tag representations used everywhere in this
|
||||
family of artifacts:
|
||||
@@ -78,6 +79,12 @@ 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 param therefore has three states: **open** (a sweepable axis), **bound**
|
||||
(closed by a `bind` — gone from the axis namespace), 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`).
|
||||
|
||||
### Commands
|
||||
|
||||
```
|
||||
@@ -125,6 +132,10 @@ raw (--params, campaign axes): fast.length
|
||||
wrapped (--list-axes, --axis): graph.fast.length
|
||||
```
|
||||
|
||||
A ganged knob's raw address has one path segment less than a member address
|
||||
would — it sits at the composite's own level, like a role name (e.g.
|
||||
`channel_length`, not `channel_hi.length`) — and wraps identically (`graph.channel_length`).
|
||||
|
||||
`--content-id`, `--identity-id`, `--params`, and `graph register` all accept
|
||||
**either** shape: the raw op-script array or an already-built `#155`
|
||||
blueprint envelope (object) — shape-discriminated automatically, so you
|
||||
|
||||
+11
-1
@@ -2093,6 +2093,11 @@ node type, edge semantics, or structural-axis kind) bumps `format_version` so an
|
||||
old reader refuses cleanly (`LoadError::UnsupportedVersion` / `UnknownNodeType`,
|
||||
already green). The per-section required-flag scheme is deferred (no current
|
||||
Tier-2 section to validate it; recorded on #156).
|
||||
Pre-ship dormancy (#61, 2026-07-10): until the first external ship there are
|
||||
no out-of-repo readers — reader and writer change atomically in one commit —
|
||||
so the Tier-2 bump discipline is dormant and structurally-semantic additions
|
||||
(the `gangs` section) land as additive-optional fields of v1; the first ship
|
||||
consciously freezes v1, gangs included, and activates the bump discipline.
|
||||
**Milestone delivered — 2026-06-30, cycle 0090 — the serializable format + loader + construction service.** A green end-to-end milestone fieldtest (`fieldtests/milestone-topology-as-data/`) proves the full author → serialize → load → construct → introspect → reproduce story from the public surface alone, 0 behavioural bugs; the round-trippable format (#155), the construction service (#157), and the forward-compat two-tier discipline (#156) all shipped. Polish filed forward: op-script grammar docs + a stale example (#163), the canonical trailing-newline / `Composite` value ergonomics (#164), CLI discoverability of `build`/`introspect` (#159).
|
||||
**Realization (2026-06-30, cycle 0092 — runs are built FROM blueprint-data, #165).**
|
||||
`aura run <blueprint.json>` now loads a serialized **signal** blueprint
|
||||
@@ -2195,7 +2200,7 @@ fixture from the scaffolder.
|
||||
**Op-script grammar (`aura graph build`, the #157 wire surface).** The construction
|
||||
op-script is a JSON **array of ops**, each object internally tagged by `"op"`,
|
||||
replayed in order; nodes are referenced **by identifier**, ports as dotted
|
||||
`<identifier>.<port>`. The six verbs:
|
||||
`<identifier>.<port>`. The seven verbs:
|
||||
- `source` — `{"op":"source","role":<str>,"kind":<ScalarKind>}` — declare a root
|
||||
source role producing a base column of `kind`.
|
||||
- `input` — `{"op":"input","role":<str>}` — declare a root input role (kind inferred
|
||||
@@ -2212,6 +2217,11 @@ replayed in order; nodes are referenced **by identifier**, ports as dotted
|
||||
- `expose` — `{"op":"expose","from":<port>,"as":<str>}` — promote an interior output
|
||||
field to a boundary output, aliased by `as` — **the only verb that keeps `as`**
|
||||
(a real alias, not a naming; contrast `add`'s `name`).
|
||||
- `gang` — `{"op":"gang","as":"channel_length","into":["channel_hi.length","channel_lo.length"]}`
|
||||
— fuse two or more sibling params into ONE public knob: the member addresses
|
||||
leave the sweepable param space and `as` replaces them; the bound or swept
|
||||
value fans out to every member at bootstrap. Members must share one scalar
|
||||
kind and stay open (un-bound).
|
||||
|
||||
Value forms are the #155 representations: a `Scalar` bind value is the typed tag form
|
||||
`{"I64":2}` / `{"F64":0.5}` / `{"Bool":true}` / `{"Timestamp":<i64>}`, and `kind` is
|
||||
|
||||
+11
-1
@@ -119,6 +119,16 @@ A node re-evaluates only when ≥1 of its own inputs is fresh this cycle; otherw
|
||||
**Avoid:** deploy artifact, standalone binary
|
||||
A statically-linked, versioned, frozen build, never hot-swapped (audit trail: this artifact = this commit). The general category; a `bot` is the specific case of a deployed strategy + broker.
|
||||
|
||||
### gang
|
||||
**Avoid:** —
|
||||
A blueprint-level declaration that two or more sibling nodes' open params are
|
||||
semantically one knob. The member addresses leave the blueprint's parameter
|
||||
space; one gang address (a single path segment at the composite's level)
|
||||
replaces them, and its value fans out to every member at bootstrap. Binding is
|
||||
structural, not advisory — no consumer can bind a member independently. The
|
||||
gang's name is a debug/axis symbol (identity-blind); its member coordinates
|
||||
are identity-bearing. Declared by the `gang` op / `GraphBuilder::gang`.
|
||||
|
||||
### gross R
|
||||
**Avoid:** —
|
||||
The R-multiple outcome of the **signal alone** — per-trade R integrated by the R-evaluator with **no `cost model`** attached (the zero-cost baseline). `net R = gross R − cost-in-R` once a cost model is composed on.
|
||||
@@ -293,7 +303,7 @@ The harness's structural parameterization — which strategy, instrument(s), bro
|
||||
|
||||
### sweep
|
||||
**Avoid:** param-sweep, parameter sweep
|
||||
An orchestration axis varying tuning params (grid or random) within a fixed structure. The inner, param-tuning loop, distinct from the structural experiment matrix. On a loaded blueprint every open knob (`--list-axes`) is **required** — a subset is refused with the missing knob named; pin an unwanted knob with a single-value axis (`--axis name=<one-value>`), there is no default. `aura sweep --axis` takes the `--list-axes`-printed, root-composite-wrapped name (e.g. `graph.fast.length`) — not the raw `param_space` name (`fast.length`) that `graph introspect --params` and a campaign document's axes use; the CLI strips exactly one leading wrapper segment (#210). The `aura sweep` CLI verb is now thin sugar over the `campaign document` path — its blueprint form (`<bp.json> --real`) translates to a generated, content-addressed campaign run through the one executor (#210); the built-in `--strategy` sweep surface was retired by #159 (its hard-wired harnesses removed) — sweep now runs from a blueprint + `--axis`, and a retired `--strategy` token falls to the generic usage error.
|
||||
An orchestration axis varying tuning params (grid or random) within a fixed structure. The inner, param-tuning loop, distinct from the structural experiment matrix. On a loaded blueprint every open knob (`--list-axes`) is **required** — a subset is refused with the missing knob named; pin an unwanted knob with a single-value axis (`--axis name=<one-value>`), there is no default. `aura sweep --axis` takes the `--list-axes`-printed, root-composite-wrapped name (e.g. `graph.fast.length`) — not the raw `param_space` name (`fast.length`) that `graph introspect --params` and a campaign document's axes use; the CLI strips exactly one leading wrapper segment (#210). The `aura sweep` CLI verb is now thin sugar over the `campaign document` path — its blueprint form (`<bp.json> --real`) translates to a generated, content-addressed campaign run through the one executor (#210); the built-in `--strategy` sweep surface was retired by #159 (its hard-wired harnesses removed) — sweep now runs from a blueprint + `--axis`, and a retired `--strategy` token falls to the generic usage error. A ganged pair contributes ONE axis.
|
||||
|
||||
### tap
|
||||
**Avoid:** —
|
||||
|
||||
Reference in New Issue
Block a user