docs: ratify the milestone-fieldtest doc findings

- glossary "tap" + authoring-guide §3: the chart handle of a
  sweep/walkforward --trace family is the printed family handle
  (members keyed <cell>/<member>) — the campaign trace_name analog was
  documented, the sweep case was not (fieldtest spec_gap).
- authoring-guide §0: state the input window's financial-style ordering
  (index 0 = newest, index k = k cycles back) where the node pattern is
  taught — previously only in the design ledger's RingBuffer note.
- authoring-guide §3: the #234 cost block joins the open-slot list, the
  worked campaign example, and the prose (charge modes, net-vs-gross
  default, manifest stamping) — it was discoverable only via
  campaign introspect --unwired.

Fieldtest fixtures: 09da04f.
This commit is contained in:
2026-07-11 15:05:31 +02:00
parent 5616aa6c6a
commit f5911645f1
2 changed files with 25 additions and 3 deletions
+24 -2
View File
@@ -57,7 +57,12 @@ Every node type — std or project-local — is three things:
until every input the node needs has fired at least once; this warm-up
filter is what keeps a downstream consumer from ever observing a
fabricated value, C8), and `label()` (a short, human-readable debug
string — not the type id used for serialization, see below).
string — not the type id used for serialization, see below). The input
window `ctx.f64_in(i)` hands those past values back **financial-style:
index 0 is the newest cycle, index `k` is `k` cycles back** — so a
`lookbacks()` of `vec![n]` makes `w[0]..=w[n-1]` the last `n` values,
newest first, and a lookback-spanning node (momentum, ATR, RSI) reads its
span as `w[0]` vs `w[length]`, never the other way round.
2. **A `PrimitiveBuilder` recipe.** A `builder()` constructor that pairs a
`NodeSchema` (its input ports as `PortSpec`, its output fields as
`FieldSpec`, and its bindable params as `ParamSpec`) with a **build
@@ -453,6 +458,7 @@ open slot: kind (required, must be "campaign")
open slot: name (required, string)
open slot: data (required section: instruments + windows)
open slot: risk (optional, list of stop regimes { vol: { length, k } }; absent = one default regime)
open slot: cost (optional, list of cost models { constant: { cost_per_trade } } | { vol_slippage: { slip_vol_mult } } | { carry: { carry_per_cycle } }; absent = zero cost, net = gross)
open slot: strategies (required, non-empty list of { ref, axes })
open slot: process.ref (required, content id of a process document)
open slot: seed (required, non-negative integer)
@@ -475,6 +481,10 @@ open slot: presentation (required section: persist_taps (equity | exposure | r_e
{ "vol": { "length": 3, "k": 1.5 } },
{ "vol": { "length": 3, "k": 3.0 } }
],
"cost": [
{ "constant": { "cost_per_trade": 0.02 } },
{ "vol_slippage": { "slip_vol_mult": 0.1 } }
],
"strategies": [
{
"ref": { "content_id": "597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a" },
@@ -503,6 +513,15 @@ never by signal — the regime's stop defines the risk unit R. Absent or empty,
the matrix runs one implicit default regime (the same vol regime the
orchestration verbs bind when their stop flags are omitted).
The optional `cost` list is the campaign's cost model (#234): each entry
charges the trade stream in R — `constant` per closed trade, `vol_slippage`
proportional to local volatility per closed trade, `carry` per held cycle —
and the charges sum into the net curve, so every member reports net metrics
beside gross and the `net_r_equity` tap records the cost-dragged curve.
Absent or empty, the cost model is zero and net equals gross. The bound cost
knobs are stamped on each member's manifest (`cost[k].<knob>` params), so a
costed family reproduces bit-identically like any other.
### Validate — three tiers, honest degradation
```
@@ -566,4 +585,7 @@ time registers it implicitly. `aura campaign runs` lists stored
realizations; `aura campaign runs <id>` dumps the bare stored record(s) (not
the `{"campaign_run": …}` emit wrapper above). If `presentation.persist_taps`
is non-empty, the run also persists the named taps under
`runs/traces/<trace_name>/…`, chartable with `aura chart`.
`runs/traces/<trace_name>/…`, chartable with `aura chart`. The
`sweep`/`walkforward --trace` analog persists every member's taps as a
family charted the same way, by the handle the run prints (members keyed
`<cell>/<member>`).
+1 -1
View File
@@ -307,7 +307,7 @@ An orchestration axis varying tuning params (grid or random) within a fixed stru
### tap
**Avoid:** —
A named recorded stream produced by a recording `sink` — the addressable label (e.g. `equity`, `net_r_equity`) under which one sink's per-cycle output is persisted as a columnar (SoA) `ColumnarTrace` and selected for charting via `--tap`. Distinct from the `sink` node that emits it (a tap is the stream, the sink is the role) and from a whole recorded run (a bundle of taps); taps fire at their own cadences and are fused only by joining on the recorded timestamp, never by positional index. In a `campaign document`, `persist_taps` names taps from the CLOSED vocabulary `equity | exposure | r_equity | net_r_equity` (`tap_vocabulary`, 0109/#201) — a new observable is a new vocabulary entry or an authored blueprint sink, never an open node-path namespace.
A named recorded stream produced by a recording `sink` — the addressable label (e.g. `equity`, `net_r_equity`) under which one sink's per-cycle output is persisted as a columnar (SoA) `ColumnarTrace` and selected for charting via `--tap`. Distinct from the `sink` node that emits it (a tap is the stream, the sink is the role) and from a whole recorded run (a bundle of taps); taps fire at their own cadences and are fused only by joining on the recorded timestamp, never by positional index. In a `campaign document`, `persist_taps` names taps from the CLOSED vocabulary `equity | exposure | r_equity | net_r_equity` (`tap_vocabulary`, 0109/#201) — a new observable is a new vocabulary entry or an authored blueprint sink, never an open node-path namespace. Persisted taps are charted by the printed handle: a campaign run's via the record's `trace_name`, a `sweep`/`walkforward --trace` family's via the family handle the run prints (`aura chart <handle>`; its members are keyed `<cell>/<member>` in the chart).
### topology hash
**Avoid:** —