Composite output is a single port — multi-line indicators (MACD, Bollinger…) can't re-export a record #40
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A composite exposes exactly one output field (
Composite::output: OutPort). Multi-line indicators — MACD (macd / signal / histogram), Bollinger (upper / mid / lower), Stochastic (%K / %D), Ichimoku (5 lines) — cannot be authored as a composition and re-exported as a unit; only one line escapes the boundary. The MACD PoC (commitd8b2a28) could expose only the histogram for this reason.Diagnosis (grounded in the code)
The substrate is already multi-field everywhere except the composite boundary:
Node::schema().outputisVec<FieldSpec>— a K-column record (OHLCV = 5 columns through one port), supported today.Edge.from_fieldselects which output field a consumer reads.from_fieldfor leaf producers — a multi-output leaf works today (blueprint.rsrewrite_edge, theLeafarm).The only cap is the composite boundary, in three spots in
crates/aura-engine/src/blueprint.rs:struct Composite { output: OutPort }(~line 48) — one(node, field).rewrite_edge(~line 377): a composite consumer assertsfrom_field != 0 → error.inline_composite(~line 326): samefield != 0guard for nested composites.Invariant-consistent (does NOT touch C8 / C7 / C4)
This is a boundary completion, not an invariant change.
Fix shape
Composite::output: OutPort → Vec<OutPort>(the output record = ordered re-exported interior fields).rewrite_edge/inline_composite: index thatVecbyfrom_field+ range-check — exactly the shape theLeafarm already has — instead of asserting== 0.[out:k]markers (analogous to[in:k]) and K fan-out edges at the opaque composite node.Composite::new(… output: vec![…]).Relationship to the "composite-edge signature" theme
This is the output half of giving a composite a typed, named boundary signature. The closed #30 gave leaf params their typed names;
FieldSpec.namealready carries output-field names (macd/signal/hist) — they just aren't surfaced at the boundary. The still-open sibling gap is composite-level param aliasing: two SMAs in one composite both surface aslength(["sma_cross.length", "sma_cross.length"]) with no way to alias them toshortLen/longLen. Inputs (roles), outputs (this issue), and params (aliasing) together form the "composite boundary gets a named typed signature" movement — the form behindmacd(fast, slow, signal) -> (macd, signal, hist).Decision (boundary-signature correlation analysis): params, inputs, and outputs are the same named-positional-interior-projection pattern and converge at the renderer (the legible
macd(fast, slow, signal) -> (macd, signal, hist)signature needs all three names at once). Two consequences for THIS issue:Vec<OutField { node, field, name }>, not bareVec<OutPort>— so it is not reopened later just to add names. Output-field naming ships with the multi-output capability here.Co-designed in one brainstorm ("composite boundary signature"), implemented in sequence: #40 capability + output names first, #41 legibility second.