Files
Aura/docs/design/contracts/c20-strategy-harness.md
T
claude 8688a60ded docs(ledger): split the design ledger into an INDEX map, per-contract live files, and history sidecars
The single-file ledger had grown to 2968 lines / ~42k tokens, mixing
current design law with accreted history: 59 cycle-stamped realization
blocks, 18 [HISTORY] passages, 22 supersession markers, and the C10 /
C22 / C24 reframe sagas layered several supersessions deep. A
code-grounding audit (31 agents, adversarially verified) confirmed 11
defects stated as current truth: stale crate homes from the C28 #288
roster split (cost nodes, PositionManagement, PositionEvent, Session),
the renamed InputSpec->PortSpec, the pre-#241 project model in C16 and
the open-threads section, a stale HarnessKind retirement deferral in
C24, and three C28-internal inconsistencies.

New shape, per the ailang precedent:

- INDEX.md stays the sole addressable entry point: foundation, external
  components, a C-id-keyed contract map (one line per contract), and
  only the genuinely open architectural threads.
- contracts/cNN-<slug>.md carries each contract's current truth only:
  Guarantee / Forbids / Why with ratified refinements integrated, plus
  a code-anchored Current state. All confirmed defects are fixed here;
  crate anchors were re-verified against the tree.
- contracts/cNN-<slug>.history.md (18 sidecars) and INDEX.history.md
  preserve every superseded block verbatim, stamps and issue refs
  intact, under a frozen-record banner. Nothing was deleted: superseded
  design intent remains an addressable working-tree artifact, off the
  per-cycle audit walk.
- Ledger discipline is now stated in INDEX.md: live files are edited in
  place at cycle close, superseded text moves verbatim to the sidecar,
  and a supersession marker in a live file is itself an audit finding.

Every contract file was verified against its old text by an independent
zero-loss pass (statement-by-statement) plus a code-accuracy spot check;
C-ids and contract titles are unchanged, so existing C-id citations in
code, tests, and issues resolve as before.
2026-07-21 16:40:36 +02:00

96 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# C20 — Strategy ↔ harness; the harness is the root sim graph
**Guarantee.** A **strategy** is a reusable composite-node blueprint (C9): broker-,
data-, and viz-independent, with inputs declared as named **roles** (symbol-agnostic
where possible) and the **bias** stream (C10) as output. A **harness** (the
experimental setup) is the **root sim graph** — sources bound to the strategy's
input roles + the strategy + attached broker node(s) + sinks — and is itself
produced by the bootstrap (C19). A harness *instance* is C1's disjoint unit (the
root scope). The harness has **two kinds of parameterization**: **structural axes**
(which strategy, which instrument(s), which broker(s), which window, which **risk
regime**) whose variation selects *different* instances — the **experiment matrix**
(the risk regime is the fourth axis, #210, carried as `CampaignDoc.risk`;
kept-separate, compared-not-selected, see C10) — and **tuning params** (the
strategy's numeric params) swept *within* a fixed structure (Fork A). The same
strategy blueprint is reused across backtest, sweep, visual workspaces, and the
frozen live bot — each a different harness. **Both strategy and harness/experiment
are authored in Rust** via builder APIs (C17); the experiment matrix is ordinary
Rust control flow (loops/conditionals), not a config schema. Ontologically, a node
(incl. a strategy composite) is an **open** fragment — free input roles + ≤1 output
(C8/C9) — that does not run alone; a **harness is the closed root graph**: a
strategy with its input roles bound to sources and its output terminated in
broker/sink nodes, under a clock. A harness is therefore **not a node** (no free
inputs, no output; it does not fit `eval`) — it is the *closure that runs*, C1's
disjoint unit / the root scope. Harnesses do not nest as nodes; the World (C21)
orchestrates them as objects.
**Forbids.** Embedding data sources / brokers / sinks inside a strategy; a
declarative experiment mini-DSL (logic is Rust — C17); modelling the harness as a
node (it is the closed root scope, not an open composable node). The mini-DSL
prohibition is scoped by the #188 role-model pass: it forbids an **open,
logic-bearing** experiment language (the RustAst trap), **not** the closed-vocabulary
**campaign document** (C25/C18) that carries persisted experiment intent — data
windows × strategy ids × param axes × process ref, under the total, declarative P1
construct tier (bounded axes, gates, ladders; no variables, no general recursion, no
unbounded iteration — invariant 5's no-free-feedback move applied one level up;
#188/#189). A *generator* that enumerates structural variants may still be
plain Rust; what it yields, and what a campaign declares, is data. Genuinely new
logic (metrics, analysis blocks) escalates to a new Rust block, never to a freetext
hole in the artifact.
**Why.** Reusability needs the strategy to be a context-free blueprint that many
harnesses embed. Modelling the harness as a root graph keeps it within the one
Node/graph abstraction (C9) and makes "10 strategies in one environment" and "one
strategy × N instruments" plain nested loops over the structural axes. Rust
authoring (not config) preserves full programmatic power — conditional/adaptive
matrices, generated axes, custom wiring — and avoids re-introducing the DSL trap
C17 rejects.
## Current state
**The shippable form is the `Composite` blueprint.** A **hand-wired `FlatGraph` is
not a shippable strategy** — it carries no `param_space()`, so the World families
(sweep / walk_forward / compare, C21) cannot consume it without a hand re-author.
The **canonical shippable form is the `Composite` blueprint** (the authoring source
level, C9/C19); the `FlatGraph` is only its compiled substrate (C23). This is
concrete in the GER40 session-breakout example (`ger40_breakout_blueprint`,
`crates/aura-ingest/examples/shared/breakout_real.rs`), whose `param_space()` is
exactly its tuning knobs and whose **bar period is a construction argument** binding
Resample + Session together — a structural matrix axis (C12: a different period is a
*different strategy*, not a sweep point), never a `param_space` entry, so a sweep
cannot desync the two clocks. Structural constants (e.g. a `delay.lag`, C8) are
bound out of the space.
**Experiment-matrix members are topology-data.** The "ordinary Rust control flow"
clause holds for the **generator** — the loop / conditional that *enumerates*
structural variants may stay Rust (C17). But each **member** it yields is a
**topology-data value** (C24), not a hand-coded blueprint nor engine-baked source: a
structural axis selects among *data* blueprints the World constructs, mutates, and
serializes, which is what makes structural variation first-class and searchable
rather than a hand-enumerated menu. Persisted experiment *intent* is the campaign
document (C25/C18).
**Pre-C24 scaffolding retired.** The pre-C24 scaffolding — `HarnessKind` and the
per-strategy `*_sweep_family` functions — is **gone**. The family builders are now
generic and blueprint-driven: `blueprint_sweep_family`, `blueprint_walkforward_family`,
`blueprint_mc_family` (and `blueprint_sweep_over`) in
`crates/aura-runner/src/family.rs`. The R-evaluator scaffold `wrap_r`
(defined in `crates/aura-runner/src/member.rs`; imported and called from
`runner.rs`) survives; its last hard data weld — the
hard-wired `price`←close role and the `M1Field::Close`-only open sites — is retired
(a strategy's input roles now bind archive columns by name, C26), and `wrap_r`'s
remaining R-scaffolding retirement is tracked at #159.
## See also
- [C9](c09-fractal-composition.md) — the strategy as a composite blueprint.
- [C10](c10-bias-r-cost.md) — the bias output and the risk-regime axis.
- [C17](c17-authoring-surface.md) — Rust authoring and the DSL prohibition.
- [C19](c19-bootstrap.md) — the bootstrap that produces the harness.
- [C21](c21-world.md) — the World orchestrates harnesses as objects.
- [C23](c23-graph-compilation.md) — the `FlatGraph` compiled substrate.
- [C24](c24-blueprint-data.md) — experiment-matrix members as topology data.
- [C25](c25-role-model.md), [C18](c18-registry.md) — the campaign document / run registry.
- [C26](c26-input-binding.md) — roles bind archive columns by name.
> History: [c20-strategy-harness.history.md](c20-strategy-harness.history.md)