feat(engine,cli): GraphBuilder gang cadence + render carrier (#61 tasks 5-6)
Builder: NodeHandle::param -> ParamRef, GraphBuilder::gang, build() resolves
the gang table (collect-then-reject, BuildError::{UnknownParam,AmbiguousParam,
BadGang}) and terminates in Composite::with_gangs — the same predicate the
op-script and serde boundaries use. C24 lockstep extended: an op-script gang
replay serializes byte-identically to the GraphBuilder twin (FlatGraph edges +
sources + canonical JSON).
Render: model_to_json emits a per-scope gangs fragment (name, kind, [node,pos,
"param"] members) for ganged scopes only — the gang-free model stays
byte-identical (model_golden untouched). graph-viewer.js annotates a ganged
open param with its public knob name; guarded by a viewer_gang_param.{mjs,rs}
pair RED-first per the established viewer_bound_param convention (a welcome
extra beyond the plan's file list).
Ratified deviation: the model's kind string uses the serde form ("I64") — the
plan's implementation snippet (kind_str -> "i64") contradicted its own test;
resolved toward the test + the blueprint_serde form. Two quality nits held as
principled plan-holds (inline resolution block; the unreachable unwrap_or
placeholder check_gangs refuses first).
Verified: aura-engine lib 264/0 (model_golden, lockstep, builder, carrier all
green), viewer_gang_param 1/0, workspace clippy -D warnings clean. Slice
resumed across a transient API failure via workflow resume (cached prefix).
refs #61
This commit is contained in:
@@ -810,6 +810,54 @@ fn graph_build_accepts_a_gang_op() {
|
||||
assert_eq!(params, "length:I64\n", "one fused public knob, not two members");
|
||||
}
|
||||
|
||||
/// Property (#61, Task 6 wiring): a blueprint built through the op-script `gang`
|
||||
/// op and then RENDERED via `aura graph <file>` — the real CLI round trip a
|
||||
/// consumer drives, not a hand-built `Composite` fed straight to `model_to_json`
|
||||
/// — embeds the fused gang table in the page's inlined `window.AURA_MODEL`. This
|
||||
/// is the seam that actually connects the construction-layer gang op to the
|
||||
/// viewer surface: `graph_model.rs`'s `model_carries_gangs_only_for_ganged_scopes`
|
||||
/// pins the JSON fragment in isolation, and `viewer_gang_param` pins the JS
|
||||
/// annotation against a hand-written model literal, but neither proves the gang
|
||||
/// table SURVIVES the build -> file -> render pipeline a consumer actually runs.
|
||||
#[test]
|
||||
fn graph_build_gang_op_survives_render_round_trip() {
|
||||
let dir = temp_cwd("graph-render-gang-round-trip");
|
||||
let ops = r#"[
|
||||
{"op":"source","role":"price","kind":"F64"},
|
||||
{"op":"add","type":"SMA","name":"a"},
|
||||
{"op":"add","type":"SMA","name":"b"},
|
||||
{"op":"gang","as":"length","into":["a.length","b.length"]},
|
||||
{"op":"add","type":"Sub"},
|
||||
{"op":"feed","role":"price","into":["a.series","b.series"]},
|
||||
{"op":"connect","from":"a.value","to":"sub.lhs"},
|
||||
{"op":"connect","from":"b.value","to":"sub.rhs"},
|
||||
{"op":"expose","from":"sub.value","as":"bias"}
|
||||
]"#;
|
||||
let (bp, stderr, ok) = run(&["graph", "build"], ops);
|
||||
assert!(ok, "graph build: stderr: {stderr}");
|
||||
let bp_path = dir.join("bp.json");
|
||||
std::fs::write(&bp_path, &bp).expect("write built blueprint");
|
||||
|
||||
let out = std::process::Command::new(BIN)
|
||||
.arg("graph")
|
||||
.arg(&bp_path)
|
||||
.current_dir(&dir)
|
||||
.output()
|
||||
.expect("spawn aura graph <blueprint>");
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(0),
|
||||
"`aura graph <blueprint.json>` exit: {:?}\nstderr: {}",
|
||||
out.status,
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
let html = String::from_utf8(out.stdout).expect("utf-8 stdout");
|
||||
assert!(
|
||||
html.contains(r#""gangs":[{"name":"length","kind":"I64","members":[["#),
|
||||
"rendered page does not embed the gang table: {html}"
|
||||
);
|
||||
}
|
||||
|
||||
/// The `gang` op's arity refusal (fewer than two members) reads as prose at the
|
||||
/// binary seam, attributed to its op index, never the raw `GangArity` Debug name.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user