diff --git a/crates/aura-engine/src/blueprint.rs b/crates/aura-engine/src/blueprint.rs index f9cafda..7e39bb9 100644 --- a/crates/aura-engine/src/blueprint.rs +++ b/crates/aura-engine/src/blueprint.rs @@ -1,8 +1,9 @@ //! The construction layer (C9/C19/C23): a named, param-generic graph-as-data //! (`Blueprint`) that **compiles** to the flat, type-erased instance the run loop //! already runs (the *compilat*). The unit of reuse is the [`Composite`]: a -//! nestable sub-graph fragment exposing one output port (C8) and named input -//! roles, which `compile` **inlines** into the flat `(nodes, sources, edges)` the +//! nestable sub-graph fragment exposing an output record (one port, K re-exported +//! fields; C8) and named input roles, which `compile` **inlines** into the flat +//! `(nodes, sources, edges)` the //! unchanged [`crate::Harness::bootstrap`] consumes. //! //! The compilat is wired by raw index, **not by name** (C23): a composite's @@ -43,7 +44,8 @@ impl From for BlueprintNode { /// A reusable sub-graph fragment compiled away by inlining (C9/C23). It is **not** /// a [`Node`]: it is never `eval`'d. It holds interior items (local indices), /// interior edges (local indices), input roles (role `r` fans into the interior -/// targets `input_roles[r]`), and the one exposed output port. +/// targets `input_roles[r]`), and the exposed output record (each entry +/// re-exports one interior `(node, field)` under a boundary name). pub struct Composite { name: String, nodes: Vec, @@ -54,7 +56,7 @@ pub struct Composite { impl Composite { /// Build a composite from its authored name, interior items, interior edges - /// (local indices), input roles, and output port. The `name` is a + /// (local indices), input roles, and output record. The `name` is a /// non-load-bearing render symbol (the cluster title for #13); it does not /// reach the compilat (the boundary dissolves at inline, C23). pub fn new( diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index 5395b4c..190fa24 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -292,6 +292,23 @@ is). So "nestable arbitrarily" and "graph-as-data" hold at the **blueprint driving a nested sub-engine* — is **explicitly rejected**: it would keep the interior opaque to the cross-graph optimiser (C23) and add a runtime sub-loop the flat model does not need. Inlining is what makes the composite boundary free. +**Realization (cycle 0018 — composite multi-output record, #40).** "Exposes one +output" is one output **port** carrying a **record of 1..K re-exported fields**, not +one field: `Composite.output` is a `Vec` (was a +single `OutPort`). Each entry is a **named projection** of one interior +`(node, output-field)`; a consumer selects which re-exported field it reads via the +same `Edge::from_field` that already binds leaf record columns (C8 realization, +cycle 0005). This is the **same arity** C8 already grants a leaf (OHLCV = one port, +5 columns): a multi-line indicator (MACD = macd/signal/histogram) is **one** record +of K fields, **one** port, **one** row per `eval` — C8/C7/C4 untouched, a boundary +completion, not a contract change. A strategy composite is simply the K=1 case +(one exposure field, C10). The re-export **names** are **non-load-bearing** (C23): +they live at the blueprint boundary and in render (`[out:]` markers, #13) +but are dropped at lowering — `ItemLowering::Composite.output` is `Vec<(usize, +usize)>`, raw index pairs only, so the compilat is name-free (verified: the +compiled-view render stayed bit-identical across this change). Input-role and +param **names** at the same boundary remain index-only pending #41 (the legibility +sibling that depends on this cycle). ### C10 — Strategy output is an intent/exposure stream; position management is a decoupled derived layer; brokers are downstream nodes **Guarantee.** A strategy's primary, backtestable output is **not** an equity