docs(ledger), fix(aura-cli): override-hash ratified, exec exit partition pinned, cost-wiring example

Harvest sweep, batch 6 of 6.

- #343 ratified (per the decision minuted on the issue): an override IS
  a topology-parameter variation — the executed run's topology_hash is
  the reopened topology's own, deliberately not required to resolve in
  the store; the manifest's params map plus the base document
  reconstruct the variant. C24 carries the full clause, C12/C18
  cross-reference it; pinned by a bare-vs-noop-override hash test
  (distinct, and stable across runs).
- #342 item 5: C14 pins exec's unresolved-target exit partition on the
  existing usage/runtime line — file-content faults (not-JSON,
  op-script, wrong-kind) exit 2, missing-state faults (unreadable
  non-id target, unregistered content id) exit 1. One sanctioned
  realignment: the wrong-kind refusal moves 1 → 2 to join its
  file-content siblings (RED-first on the updated pin); the
  unregistered-id row gains its missing sibling pin.
- #341 item 4: the authoring guide gains a worked cost-wiring op-script
  (ConstantCost → CostSum via PositionManagement geometry, built and
  verified), honest about being a wiring reference — production cost
  models still come from a campaign document's cost block (C10).

closes #341
closes #342
closes #343
This commit is contained in:
2026-07-26 13:05:36 +02:00
parent 74281842b8
commit 2e532bce00
7 changed files with 194 additions and 11 deletions
+54
View File
@@ -361,6 +361,60 @@ at all — the same closed-args-then-bind order every arg-bearing type follows
introspect --params` as `combo.weights[1]:F64` (alongside
`combo.weights[0]:F64 default=0.7`).
### Worked example: wiring a cost model (`ConstantCost` → `CostSum`)
`CostSum`'s `cost[k].<field>` inputs (C10) are meaningless fed from a bare
source: they read the co-temporal record a real `PositionManagement` node
emits (`closed`, `open`, `entry_price`, `stop_price`). Every node in that
chain — `Bias`, `FixedStop`, `Sizer`, `PositionManagement`, `ConstantCost`,
`CostSum` — sits in the closed vocabulary, so the whole cost-model wiring is
honestly expressible by hand, one `add`/`connect` pair at a time, mirroring
the Rust `risk_executor` + `cost_graph` composite-builders (`aura-composites`)
field-for-field:
```json
[
{"op": "source", "role": "price", "kind": "F64"},
{"op": "source", "role": "signal", "kind": "F64"},
{"op": "add", "type": "Bias", "name": "bias", "bind": {"scale": {"F64": 1.0}}},
{"op": "feed", "role": "signal", "into": ["bias.signal"]},
{"op": "add", "type": "FixedStop", "name": "stop", "bind": {"distance": {"F64": 0.01}}},
{"op": "add", "type": "PositionManagement", "name": "pm"},
{"op": "feed", "role": "price", "into": ["stop.price", "pm.price"]},
{"op": "add", "type": "Sizer", "name": "sizer", "bind": {"risk_budget": {"F64": 1.0}}},
{"op": "connect", "from": "bias.bias", "to": "sizer.bias"},
{"op": "connect", "from": "stop.stop_distance", "to": "sizer.stop_distance"},
{"op": "connect", "from": "bias.bias", "to": "pm.bias"},
{"op": "connect", "from": "stop.stop_distance", "to": "pm.stop_distance"},
{"op": "connect", "from": "sizer.size", "to": "pm.size"},
{"op": "add", "type": "ConstantCost", "name": "cc", "bind": {"cost_per_trade": {"F64": 0.5}}},
{"op": "connect", "from": "pm.closed_this_cycle", "to": "cc.closed"},
{"op": "connect", "from": "pm.open", "to": "cc.open"},
{"op": "connect", "from": "pm.entry_price", "to": "cc.entry_price"},
{"op": "connect", "from": "pm.stop_price", "to": "cc.stop_price"},
{"op": "add", "type": "CostSum", "name": "costsum", "args": {"n_costs": "1"}},
{"op": "connect", "from": "cc.cost_in_r", "to": "costsum.cost[0].cost_in_r"},
{"op": "connect", "from": "cc.cum_cost_in_r", "to": "costsum.cost[0].cum_cost_in_r"},
{"op": "connect", "from": "cc.open_cost_in_r", "to": "costsum.cost[0].open_cost_in_r"},
{"op": "expose", "from": "pm.realized_r", "as": "realized_r"},
{"op": "expose", "from": "costsum.cost_in_r", "as": "cost_in_r"}
]
```
`CostSum`'s port names ARE the `cost[k].<field>` shape already
(`cost[0].cost_in_r`, …) — `cost_port` is baked into `CostSum::make`'s schema
itself (#271), no composite-level renaming needed; a second factor is
`args: {"n_costs": "2"}` plus a second cost-node block wired into
`cost[1].*`, and `CostSum` per-field-sums whatever arity it was given (#341
item 4). This closes the "CostSum reachable but pathless" gap: the ports
genuinely connect at the op-script level, using only closed-vocabulary
nodes. It is a standalone wiring reference, though, not the production
attachment path — a campaign strategy's real cost model still comes from
the campaign document's `cost:` block (C10, `cost_nodes_for`), wrapped
around the user's bias-only blueprint entirely in Rust at run time; a
user's op-script-authored blueprint never embeds `PositionManagement` /
cost nodes itself.
### Session anchoring: the `SessionFrankfurt` preset
To anchor logic to the trading session, the closed vocabulary ships a
+5 -2
View File
@@ -10,8 +10,11 @@ param — the family boundary re-opens it on the probe and on every member
reload, and the axis binds it per cell; `exec`'s blueprint leg still requires
every param resolved (a truly open param refuses), and its own `--override
NODE.PARAM=VALUE` (#246 residue, #319) reopens exactly the named bound param
for that one execution — the single-member analogue of a campaign axis.
Identity is untouched: `content_id_of` (`crates/aura-research/src/lib.rs`) is
for that one execution — the single-member analogue of a campaign axis. The
reopened execution's `topology_hash` is therefore the reopened topology's own,
not the pre-override document's — ratified as the deliberate reading, not a
defect (#343; full ratification in [C24](c24-blueprint-data.md)'s
"Reproduction identity"). Identity is untouched: `content_id_of` (`crates/aura-research/src/lib.rs`) is
the one hashing primitive, read directly off the authored document by
`aura_runner::member`'s `run_signal_r`/`run_blueprint_member` — where the
manifest's `topology_hash` is computed inline (#319 Task 9 retired the
@@ -75,6 +75,28 @@ The machine-first help surface (JSON/manifest help, stdin op-scripts) is
deferred to the #157 / [C21](c21-world.md) track, distinct from this
human/GNU-convention compliance.
**`exec`'s unresolved-target exit partition is pinned (#342 item 5).** A
target fault splits along the same usage/runtime line the exit-code partition
above already draws, keyed on whether a *real, existing document's content*
is being judged (usage, exit 2 — the content of an argv-named file is itself
part of the argument) or the target simply fails to resolve to any recorded
state at all (runtime, exit 1 — the needed environment/recorded state is
missing). Missing-state faults (exit 1): a target naming no readable file and
no plausible content id (`'{target}' is neither a readable .json file nor a
64-hex content id`), and a well-formed-but-unregistered 64-hex content id
(`no campaign {id} in the project store`) — no file or store entry exists to
have content in either case. File-content faults (exit 2): a file that does
not parse as JSON at all, a valid-JSON op-script array (not a document exec
can execute at all — it names the `graph build` escalation instead), and a
kind-bearing document whose `"kind"` is not `"campaign"` (e.g. a process
document handed to `exec`) — all three are a real, readable file whose
content is the fault. The wrong-kind case is the one realignment this pin
made (#342 item 5): it shipped at exit 1 (mirroring the campaign leg's own
missing-state refusals) until this pass, despite being a file-content fault
like its op-script and not-valid-JSON siblings, not a missing-state fault
like the file-vs-id cases — realigned to exit 2 to match its true class, the
one sanctioned behaviour change of this pin.
**Two artifact classes, two redundancy budgets** (#249, ratified 2026-07-13).
The data layer the programmatic face emits is a public interface read raw (by
humans and LLMs), and its records split into two classes with opposite
+7 -1
View File
@@ -147,7 +147,13 @@ entry); name coincidence against one of the two namespaces IS the mechanism, and
the referenced blueprint is the single source of truth for which namespace a name
falls in. Pinned by
`referential_tier_accepts_a_kind_correct_axis_over_a_bound_param`
(`aura-registry/src/lib.rs`).
(`aura-registry/src/lib.rs`). The single-run analogue — `exec`'s own
`--override NODE.PARAM=VALUE` reopening a bound param for one execution — has
the identical hash consequence, ratified rather than fixed (#343): the
executed topology's `topology_hash` is the reopened topology's own, not the
referenced document's, exactly as a reopened campaign member's has always
been ([C24](c24-blueprint-data.md)'s "Reproduction identity" carries the full
ratification).
**The campaign executor.** `aura exec <file|content-id>` (#319) executes a
campaign (a file is register-then-run sugar; the content id is canonical): a
@@ -119,6 +119,25 @@ itself blueprint-data. The **identity id** (#171) is an additive sibling:
--identity-id`. The byte-exact content id keeps the store/reproduce roles; the
identity id is introspection-only until a dedup consumer exists.
**The override-reopened hash is ratified, not a defect (#343).** `exec`'s
`--override NODE.PARAM=VALUE` (above) reopens a bound param before bootstrap, so
the executed signal's canonical bytes — and therefore its `topology_hash` — are
the **reopened topology's own**, which may correspond to no blueprint ever
`put_blueprint`-stored, even for a "no-op" override that re-binds a param to its
existing bound value (the bound value still moves from `defaults` to `params`,
#249, changing the canonical bytes `topology_hash` covers). This is deliberate,
not accidental: an override **is** a topology-parameter variation, exactly as
the campaign leg's #246 axis-over-bound-param path has always minted the
reopened member's hash, never the referenced document's ([C18](c18-registry.md)'s
bound-override coincidence) — stamping the pre-override document's stored hash
on the single-run leg instead would make the two reopen mechanisms disagree
about what identity means for the same mechanism. Reproduction identity survives
regardless: the manifest's `params` map plus the base document deterministically
reconstruct the executed variant, byte-identically. An unresolved
`topology_hash` is the honest name of a real, reconstructible topology, not a
dangling reference — store-resolution (`get_blueprint`) is a lookup
convenience, never an identity guarantee.
### Axis discovery
`aura graph introspect --params <blueprint.json|id>` (#328) is the one