feat(aura-cli): composite definition renders as a typed signature
Refines #41's blueprint-definition render. The [param:<name>] marker nodes #41 added bloated the ASCII MACD graph (three extra nodes + fan-in edges); this moves the interface into the title line and folds names into the leaf labels that already exist: - title is the composite's typed signature, e.g. macd(fast:i64, slow:i64, signal:i64) -> (macd, signal, histogram) (param kinds from the aliased leaf's factory params via a new ScalarKind->lowercase kind_str; output NAMES only — output kinds need a pre-build factory interface, deferred to #43) - leaf labels fold aliased param names: [EMA] -> [EMA(fast)] - unnamed interior input slots render as ordered stubs: [Sub] -> [Sub(#A,#B)] (count/order derived render-side from c.edges() + c.input_roles(), no engine schema needed; arity-1 nodes get no stub) - outputs de-prefixed: [out:macd] -> [macd]; the [param:*] marker nodes are gone - two stale doc comments corrected: render_definition's [param:] prose and node.rs LeafFactory::label (the renderer went flat in 0017, so the cited ascii-dag cluster-garble rationale no longer applies — wide labels are safe; the factory label stays bare because alias names are composite-level) Render-only: no engine/ParamAlias/param_space change. compiled_view_golden byte-identical (C23 guard — verified untouched in the diff); aura run --macd deterministic and unchanged (total_pips 0.1637945563898923, 3 sign flips). The title format change repinned five .matches("name:")->.matches("name(") definition-count asserts (sma_cross/outer/inner/dup/macd); the stub separator is "," (no space) to match the [Sub(#A,#B)] surface. Verification (orchestrator-run): cargo build/test/clippy --workspace -D warnings all green; the redesigned MACD render confirmed by eye. refs #41 #43
This commit is contained in:
+19
-13
@@ -390,8 +390,8 @@ mod tests {
|
||||
fn blueprint_view_defines_each_composite_once() {
|
||||
let out = graph::render_blueprint(&sample_blueprint());
|
||||
// the sma_cross body is defined exactly once, with its interior + ports
|
||||
assert_eq!(out.matches("sma_cross:").count(), 1, "definition not rendered once:\n{out}");
|
||||
for needle in ["[SMA]", "[Sub]", "[in:price]", "[out:cross]"] {
|
||||
assert_eq!(out.matches("sma_cross(").count(), 1, "definition not rendered once:\n{out}");
|
||||
for needle in ["[SMA]", "[Sub(#A,#B)]", "[in:price]", "[cross]"] {
|
||||
assert!(out.contains(needle), "missing {needle} in definition:\n{out}");
|
||||
}
|
||||
}
|
||||
@@ -425,8 +425,8 @@ mod tests {
|
||||
// outer shows the inner composite as an opaque node, and both get a definition
|
||||
assert!(out.contains("[outer]"), "missing opaque outer node:\n{out}");
|
||||
assert!(out.contains("[inner]"), "inner must be opaque inside outer's definition:\n{out}");
|
||||
assert_eq!(out.matches("outer:").count(), 1, "outer defined once:\n{out}");
|
||||
assert_eq!(out.matches("inner:").count(), 1, "inner defined once:\n{out}");
|
||||
assert_eq!(out.matches("outer(").count(), 1, "outer defined once:\n{out}");
|
||||
assert_eq!(out.matches("inner(").count(), 1, "inner defined once:\n{out}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -449,7 +449,7 @@ mod tests {
|
||||
);
|
||||
let out = graph::render_blueprint(&bp);
|
||||
assert_eq!(out.matches("[dup]").count(), 2, "two opaque uses expected:\n{out}");
|
||||
assert_eq!(out.matches("dup:").count(), 1, "body defined once:\n{out}");
|
||||
assert_eq!(out.matches("dup(").count(), 1, "body defined once:\n{out}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -503,17 +503,17 @@ mod tests {
|
||||
|
||||
where:
|
||||
|
||||
sma_cross:
|
||||
sma_cross() -> (cross):
|
||||
[in:price]
|
||||
┌───└───┐
|
||||
↓ ↓
|
||||
[SMA] [SMA]
|
||||
└───┌───┘
|
||||
↓
|
||||
[Sub]
|
||||
[Sub(#A,#B)]
|
||||
│
|
||||
↓
|
||||
[out:cross]
|
||||
[cross]
|
||||
|
||||
|
||||
"#;
|
||||
@@ -578,12 +578,18 @@ sma_cross:
|
||||
// defines its EMA-of-EMA interior once under `where:`.
|
||||
let out = graph::render_blueprint(&macd_blueprint());
|
||||
assert!(out.contains("[macd]"), "missing opaque macd node:\n{out}");
|
||||
assert_eq!(out.matches("macd:").count(), 1, "macd defined once:\n{out}");
|
||||
assert!(out.contains("[EMA]"), "macd interior must show EMA leaves:\n{out}");
|
||||
assert_eq!(out.matches("macd(").count(), 1, "macd defined once:\n{out}");
|
||||
assert!(
|
||||
out.contains("macd(fast:i64, slow:i64, signal:i64) -> (macd, signal, histogram)"),
|
||||
"typed signature line: {out}"
|
||||
);
|
||||
assert!(out.contains("[EMA(fast)]"), "fast EMA folds its param: {out}");
|
||||
assert!(out.contains("[EMA(slow)]"), "slow EMA folds its param: {out}");
|
||||
assert!(out.contains("[EMA(signal)]"), "signal EMA folds its param: {out}");
|
||||
assert!(out.contains("[Sub(#A,#B)]"), "Sub shows its two ordered inputs: {out}");
|
||||
assert!(out.contains("[in:price]"), "named MACD input role: {out}");
|
||||
assert!(out.contains("[param:fast]"), "aliased fast length: {out}");
|
||||
assert!(out.contains("[param:slow]"), "aliased slow length: {out}");
|
||||
assert!(out.contains("[param:signal]"), "aliased signal length: {out}");
|
||||
assert!(!out.contains("[param:"), "param marker nodes removed: {out}");
|
||||
assert!(!out.contains("[out:"), "output prefix dropped: {out}");
|
||||
}
|
||||
|
||||
/// E2E acceptance (#41 / spec 0019, the worked example): the real MACD strategy
|
||||
|
||||
Reference in New Issue
Block a user