docs,engine: drop coined "compilat", use FlatGraph / "flat graph"
"Compilat" (German "Kompilat") was a coined noun for the product of the
bootstrap compilation — neither English nor a natural fit. The runtime
artifact already has a code identifier for exactly this thing: the
`FlatGraph` struct (harness.rs). Replace the coinage with that identifier:
- prose mentions -> "flat graph" (mirrors the type, reads plainly)
- definitional anchors -> `FlatGraph` (C11, C23, the running-graph line)
- `render_compilat` -> `render_flat_graph` (historical render symbol;
keeps the `render_blueprint` / `render_flat_graph`
source-vs-product pairing)
- `intra-compilat` -> `intra-graph`
- `from_compilat` (test) -> `from_flat`
"compilation" / "re-compilation" / "bootstrap-as-compilation" (the process,
ordinary English) are deliberately left untouched. Behaviour-preserving:
only comments, design ledger, specs/plans, one test-local variable and its
assert messages change. Full workspace test suite green; clippy clean.
This commit is contained in:
@@ -114,10 +114,10 @@ design decision, not a refactor, and belongs in the ledger.
|
||||
blueprint). The harness — sources + strategy + broker node(s) + sinks — is
|
||||
the root sim graph, itself bootstrapped, and is C1's disjoint unit; its
|
||||
structural axes form the experiment matrix, its tuning params the sweep.
|
||||
**The bootstrap is a compilation** to a flat, type-erased *compilat*, wired
|
||||
**The bootstrap is a compilation** to a flat, type-erased `FlatGraph`, wired
|
||||
by raw index (composites inline — a composite is an authoring-level node, not
|
||||
a runtime object; names survive only as non-load-bearing debug symbols, as
|
||||
today). The compilat is the target of **behaviour-preserving** optimisation,
|
||||
today). The flat graph is the target of **behaviour-preserving** optimisation,
|
||||
C1 the correctness invariant — intra-graph (CSE/DCE) and across a sweep family
|
||||
(sweep-invariant sub-graph computed once, shared via C11/C12). See C9/C19/C23.
|
||||
12. **The World is the product; the playground is a trace explorer.** Three
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! The construction layer (C9/C19/C23): a named, param-generic graph-as-data
|
||||
//! ([`Composite`]) that **compiles** to the flat, type-erased instance the run loop
|
||||
//! already runs (the *compilat*, a [`crate::FlatGraph`]). The unit of reuse is the
|
||||
//! already runs (a [`crate::FlatGraph`]). The unit of reuse is the
|
||||
//! [`Composite`]: a nestable sub-graph fragment exposing an output record (one port,
|
||||
//! K re-exported fields; C8) and input roles (each open, or — at the root —
|
||||
//! source-bound). `compile` **inlines** the nesting into the flat `FlatGraph` the
|
||||
@@ -8,7 +8,7 @@
|
||||
//! blueprint (there is no separate `Blueprint` type — a fully source-bound composite
|
||||
//! is the runnable root).
|
||||
//!
|
||||
//! The compilat is wired by raw index, **not by name** (C23): a composite's
|
||||
//! The flat graph is wired by raw index, **not by name** (C23): a composite's
|
||||
//! boundary dissolves at compile time; field/role names, where kept, are
|
||||
//! non-load-bearing debug symbols (as `FieldSpec.name` already is). This module
|
||||
//! adds no optimisation pass (CSE/DCE, sweep-invariant hoisting are deferred,
|
||||
@@ -25,7 +25,7 @@ use crate::{GridSpace, RunReport, SweepFamily};
|
||||
/// One re-exported field of a composite's output record: an interior
|
||||
/// `(node, output-field)` surfaced at the boundary under `name`. `name` is a
|
||||
/// non-load-bearing render/debug symbol (C23) — like `FieldSpec.name` and
|
||||
/// `Composite.name`, it does not reach the compilat.
|
||||
/// `Composite.name`, it does not reach the flat graph.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OutField {
|
||||
pub node: usize,
|
||||
@@ -157,7 +157,7 @@ impl Composite {
|
||||
/// Build a composite from its authored name, interior items, interior edges
|
||||
/// (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).
|
||||
/// reach the flat graph (the boundary dissolves at inline, C23).
|
||||
pub fn new(
|
||||
name: impl Into<String>,
|
||||
nodes: Vec<BlueprintNode>,
|
||||
@@ -473,7 +473,7 @@ fn resolve(space: &[ParamSpec], bound: &[(String, Scalar)]) -> Result<Vec<Scalar
|
||||
Ok(point)
|
||||
}
|
||||
|
||||
/// A construction-phase fault, caught before the flat compilat reaches
|
||||
/// A construction-phase fault, caught before the flat graph reaches
|
||||
/// `Harness::bootstrap`.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CompileError {
|
||||
@@ -483,7 +483,7 @@ pub enum CompileError {
|
||||
RoleKindMismatch { role: usize },
|
||||
/// The output port names a missing interior node or output field.
|
||||
OutputPortOutOfRange,
|
||||
/// The lowered flat compilat failed `Harness::bootstrap`'s checks (kind
|
||||
/// The lowered flat graph failed `Harness::bootstrap`'s checks (kind
|
||||
/// mismatch, bad index, or directed cycle).
|
||||
Bootstrap(BootstrapError),
|
||||
/// An injected param value's scalar kind does not match the slot's declared
|
||||
@@ -631,7 +631,7 @@ fn collect_params(items: &[BlueprintNode], prefix: &str, out: &mut Vec<ParamSpec
|
||||
}
|
||||
}
|
||||
|
||||
/// How one blueprint item resolved into the flat compilat. Edges and source
|
||||
/// How one blueprint item resolved into the flat graph. Edges and source
|
||||
/// targets to/from an item are resolved through this.
|
||||
enum ItemLowering {
|
||||
/// A leaf lowered to exactly one flat node at this index.
|
||||
@@ -701,10 +701,10 @@ fn inline_composite(
|
||||
flat_edges: &mut Vec<Edge>,
|
||||
) -> Result<ItemLowering, CompileError> {
|
||||
// `name` is the non-load-bearing render symbol (#13); it dissolves at inline
|
||||
// (C23 — the boundary does not reach the compilat), so it is not destructured.
|
||||
// (C23 — the boundary does not reach the flat graph), so it is not destructured.
|
||||
// Node names join the same non-load-bearing debug-symbol class: they qualify the
|
||||
// param-space path at construction but are dropped at lowering — the injected
|
||||
// scalar `params: &[Scalar]` arg drives `lower_items` below; the compilat stays
|
||||
// scalar `params: &[Scalar]` arg drives `lower_items` below; the flat graph stays
|
||||
// wired by raw index.
|
||||
let Composite { name: _, nodes, edges, input_roles, output } = c;
|
||||
let item_count = nodes.len();
|
||||
@@ -1901,16 +1901,16 @@ mod tests {
|
||||
// the same blueprint, actually compiled to its flat node array; each flat
|
||||
// node's own declared params, concatenated in flat-node order
|
||||
let flat = bp.compile_with_params(&[Scalar::I64(2), Scalar::I64(4), Scalar::F64(0.5)]).expect("harness compiles");
|
||||
let from_compilat: Vec<ParamSpec> =
|
||||
let from_flat: Vec<ParamSpec> =
|
||||
flat.signatures.iter().flat_map(|s| s.params.clone()).collect();
|
||||
|
||||
// same count, same per-slot kind, same order — the projection mirrors the
|
||||
// compilation (names differ: param_space path-qualifies, the raw node does
|
||||
// not, so compare on the load-bearing axis, kind-by-slot)
|
||||
assert_eq!(space.len(), from_compilat.len(), "param count must match the compilat");
|
||||
assert_eq!(space.len(), from_flat.len(), "param count must match the flat graph");
|
||||
assert_eq!(
|
||||
space.iter().map(|p| p.kind).collect::<Vec<_>>(),
|
||||
from_compilat.iter().map(|p| p.kind).collect::<Vec<_>>(),
|
||||
from_flat.iter().map(|p| p.kind).collect::<Vec<_>>(),
|
||||
"per-slot param kinds must line up with the compiled flat-node order",
|
||||
);
|
||||
// the realistic harness's concrete space: two SMA lengths (I64) + Exposure
|
||||
@@ -2060,16 +2060,16 @@ mod tests {
|
||||
// the same blueprint, compiled to its flat node array; each flat node's
|
||||
// own declared params, concatenated in flat-node order
|
||||
let flat = bp.compile_with_params(&[Scalar::I64(2), Scalar::I64(4), Scalar::F64(1.0), Scalar::F64(-1.0)]).expect("nested composite compiles");
|
||||
let from_compilat: Vec<ParamSpec> =
|
||||
let from_flat: Vec<ParamSpec> =
|
||||
flat.signatures.iter().flat_map(|s| s.params.clone()).collect();
|
||||
|
||||
// same count, same per-slot kind, same order — the nested projection
|
||||
// mirrors the compilation (names differ: param_space path-qualifies, the
|
||||
// raw node does not, so compare on the load-bearing axis, kind-by-slot)
|
||||
assert_eq!(space.len(), from_compilat.len(), "param count must match the compilat");
|
||||
assert_eq!(space.len(), from_flat.len(), "param count must match the flat graph");
|
||||
assert_eq!(
|
||||
space.iter().map(|p| p.kind).collect::<Vec<_>>(),
|
||||
from_compilat.iter().map(|p| p.kind).collect::<Vec<_>>(),
|
||||
from_flat.iter().map(|p| p.kind).collect::<Vec<_>>(),
|
||||
"per-slot param kinds must line up with the compiled flat-node order, under nesting",
|
||||
);
|
||||
// pin the concrete shape: two Sma lengths (I64), Sub none, two LinComb
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! A fluent, additive authoring surface that wires a blueprint by typed node
|
||||
//! handles and port/field *names*, resolving them to the raw-index `Composite`
|
||||
//! at a single fallible `build()`. The compilat stays index-wired (C23): names
|
||||
//! at a single fallible `build()`. The flat graph stays index-wired (C23): names
|
||||
//! are resolved at the authoring boundary and never reach `FlatGraph` — the same
|
||||
//! posture param-name resolution already has (`Binder`, blueprint.rs). Resolution
|
||||
//! mirrors `PrimitiveBuilder::bind`'s collect-then-reject (node.rs), but returns
|
||||
|
||||
@@ -52,7 +52,7 @@ pub struct SourceSpec {
|
||||
}
|
||||
|
||||
/// The flat, type-erased, index-wired output of `Composite::compile` — the target
|
||||
/// `Harness::bootstrap` consumes (C23's "compilat", now a named type). `signatures[i]`
|
||||
/// `Harness::bootstrap` consumes (C23's "flat graph", now a named type). `signatures[i]`
|
||||
/// is the static signature of `nodes[i]` (gathered from each primitive's builder at
|
||||
/// lowering); `bootstrap` reads kinds/output from it and `nodes[i].lookbacks()` for
|
||||
/// buffer depth. `sources` are the lowered bound roles, in role-declaration order.
|
||||
|
||||
+27
-27
@@ -12,7 +12,7 @@ C10 was later reframed in cycle 0007 — the intent/exposure stream is the prima
|
||||
output, the position table a derived layer — see C10). C19–C22 were added as the
|
||||
construction / World / playground layer; C23 and the C9/C19 compilation
|
||||
refinements were settled 2026-06-05 for the **Construction-layer** milestone (the
|
||||
blueprint→compilat reading of composites and graph optimisation).
|
||||
blueprint→flat-graph reading of composites and graph optimisation).
|
||||
The `CLAUDE.md` **Domain invariants** section is the compressed, always-loaded
|
||||
summary of the
|
||||
subset that agents must never violate; this file is the fuller form with
|
||||
@@ -265,11 +265,11 @@ sweep covers is an experiment axis, #32/C20; the node declares the knob's existe
|
||||
and type, never its search interval). (2) Identity is **positional** (the slot,
|
||||
C23 "by index, not name"); the path-qualified `name` is a non-load-bearing debug
|
||||
symbol (like `FieldSpec.name`) — uniqueness is at the slot. **Refinement (cycle
|
||||
0032):** identity in the **compilat** stays positional (C23, unchanged), but the
|
||||
0032):** identity in the **flat graph** stays positional (C23, unchanged), but the
|
||||
`param_space()` **name projection** — the authoring / by-name address space (the
|
||||
surface a sweep axis or single-run binding addresses) — must be **injective** for a
|
||||
blueprint to compile (a duplicated path is unaddressable; see C9). Two layers:
|
||||
positional wiring below (the compilat), an injective name address space above (the
|
||||
positional wiring below (the flat graph), an injective name address space above (the
|
||||
authoring boundary). So same-type siblings in one composite no longer silently
|
||||
share a name — they must be `.named(...)` apart, which is also what disambiguates a
|
||||
same-type fan-in (C9). A vector knob (`LinComb.weights`) expands to `N` flat
|
||||
@@ -332,7 +332,7 @@ never consumers, so only interior input slots are subject to the rule. There is
|
||||
optional-input concept**: every declared input port is required (no shipped node runs
|
||||
meaningfully without one; an unwarmed mode-A input is *wired-but-not-yet-valued*, not
|
||||
unwired). The check is **index-based and name-free** — it touches no name machinery
|
||||
and emits nothing into the compilat, so C23 is untouched (it proves the existing
|
||||
and emits nothing into the flat graph, so C23 is untouched (it proves the existing
|
||||
raw-index wiring is total and single-valued). Inherited identically by the raw
|
||||
`Composite::new` path and the `GraphBuilder::build()` path (both compile via
|
||||
`compile_with_params`).
|
||||
@@ -358,7 +358,7 @@ sub-graph into the one flat instance (C19/C23): the composite *boundary* dissolv
|
||||
into the raw index wiring the run loop already consumes, and names stay
|
||||
**non-load-bearing** (informative debug symbols only, as `FieldSpec.name` already
|
||||
is). So "nestable arbitrarily" and "graph-as-data" hold at the **blueprint
|
||||
(source)** level; the running graph is the flat, index-wired **compilat**. The earlier reading — *a composite survives as a `Box<dyn Node>`
|
||||
(source)** level; the running graph is the flat, index-wired **`FlatGraph`**. The earlier reading — *a composite survives as a `Box<dyn Node>`
|
||||
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.
|
||||
@@ -376,7 +376,7 @@ completion, not a contract change. A strategy composite is simply the K=1 case
|
||||
they live at the blueprint boundary and in render (cycle 0022/#46 folds each onto
|
||||
its producing node as a `name := …` binding; originally `[out:<name>]` 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
|
||||
usize)>`, raw index pairs only, so the flat graph is name-free (verified: the
|
||||
compiled-view render stayed bit-identical across this change).
|
||||
**Realization (cycle 0019 — name the composite boundary, #41; param-overlay retired,
|
||||
cycle 0031).** The named-projection shape covers the surviving boundary edge-kinds:
|
||||
@@ -390,9 +390,9 @@ carries a name (default = its lowercased type label, override via `.named()`), a
|
||||
same-type fan-in is distinguished by naming the colliding legs, the same single act
|
||||
that qualifies their param paths. Like the output and role names, **node names are
|
||||
non-load-bearing** (C23): they live at the blueprint boundary and in render but are
|
||||
dropped at lowering — the compilat is wired by raw index. The full composite
|
||||
dropped at lowering — the flat graph is wired by raw index. The full composite
|
||||
boundary signature (named inputs, multi-outputs) and the per-node param path are
|
||||
legible without changing the compilat.
|
||||
legible without changing the flat graph.
|
||||
**Refinement (param-namespace injectivity, cycle 0032; supersedes the fan-in
|
||||
distinguishability check).** A blueprint compiles only if its `param_space()` name
|
||||
projection is **injective** — every path-qualified knob name is unique. A duplicated
|
||||
@@ -416,7 +416,7 @@ That breadth guarded **render identity**, dead since the renderer was retired in
|
||||
0026; both extra rejections are **intentionally dropped**. A future node-/wiring-name
|
||||
distinguishability check, if ever wanted (e.g. for the WASM graph view's #21
|
||||
thread), is decoupled from param-space injectivity. Construction-phase only; the
|
||||
compilat stays name-free (C23).
|
||||
flat graph stays name-free (C23).
|
||||
|
||||
### 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
|
||||
@@ -670,13 +670,13 @@ of rewriting code. Naming the build phase makes the implicit "wiring" of C7/C12
|
||||
explicit.
|
||||
**Refinement (Construction-layer milestone, 2026-06-05).** This binding is a
|
||||
**compilation**: the param-generic, named blueprint (source) is lowered to a flat,
|
||||
type-erased **compilat** (C7) **wired by raw index, not by name**
|
||||
type-erased **flat graph** (C7) **wired by raw index, not by name**
|
||||
(`Edge { from, to, slot, from_field }`): composite boundaries dissolve entirely,
|
||||
and field / role names are demoted to **non-load-bearing** debug symbols (as
|
||||
`FieldSpec.name` already is). "No recompile" above means no **Rust /
|
||||
cdylib** rebuild (C12/C13: the cdylib loads once); re-deriving an instance per
|
||||
param-set is a cheap **graph re-compilation**, not a code recompile. Naming the
|
||||
build phase a compilation makes its successor explicit: the compilat is the target
|
||||
build phase a compilation makes its successor explicit: the flat graph is the target
|
||||
of behaviour-preserving optimisation (C23).
|
||||
**Realization (cycle 0016 — param-set injection).** The bootstrap now binds an
|
||||
injected param-set, realizing C12's "params injected at graph build (the optimizer
|
||||
@@ -697,7 +697,7 @@ traversal hazard) and the value reaches the node at the slot the sweep enumerate
|
||||
Arity is checked up front (`param_space().len()`); a wrong-kind or wrong-length
|
||||
vector is a typed `CompileError::{ParamKindMismatch, ParamArity}` (the typed-value
|
||||
check C8 deferred). The lowering/edge/source rewrite is structurally unchanged, so
|
||||
the **compilat stays bit-identical** for a given point (C23, the correctness
|
||||
the **flat graph stays bit-identical** for a given point (C23, the correctness
|
||||
invariant). The value *domain* (e.g. `length ≥ 1`) stays the constructor's own
|
||||
`assert`; the search-range is still the run's (#32/C20). One value-empty leaf
|
||||
detail for C22: the blueprint view (pre-run, param-generic) labels a leaf by **bare
|
||||
@@ -726,7 +726,7 @@ definitions pass recurses). The interactive *enter/focus* counterpart (a composi
|
||||
collapsed to a navigable node) is the playground's, parked as a separate concern
|
||||
(#37); the static CLI keeps the all-at-once definitions form (#38).
|
||||
|
||||
**Realization (cycle 0024 — the root is the fully-bound composite; the compilat is
|
||||
**Realization (cycle 0024 — the root is the fully-bound composite; the flat graph is
|
||||
a named type).** `struct Blueprint` is **deleted**: the root graph IS a `Composite`,
|
||||
and `compile_with_params`/`bootstrap_with_params`/`param_space` are its methods.
|
||||
What distinguished the root — its bound data sources — is now a property of its input
|
||||
@@ -739,7 +739,7 @@ source-bound, governed by the same conditions as any other node. Compilation now
|
||||
targets a **named type**: `compile` validates structurally **pre-build** (via
|
||||
`signature()`, no node constructed — an ill-typed wiring is caught before any build
|
||||
closure fires) and emits `FlatGraph { nodes, signatures, sources, edges }` — the
|
||||
C23 compilat, now first-class — which `Harness::bootstrap` consumes (kinds/firing
|
||||
C23 flat graph, now first-class — which `Harness::bootstrap` consumes (kinds/firing
|
||||
from the carried signatures, buffer depth from `lookbacks()`). The per-flat-node
|
||||
signature travels beside the node, so `bootstrap` reads it without a built-node
|
||||
`schema()` call (which no longer exists, see the C8 0024 realization).
|
||||
@@ -785,7 +785,7 @@ shrink propagates for free, and chained binds reconstruct the correct positional
|
||||
vector because each layer computes its slot index relative to the param list it
|
||||
sees. C23 is unaffected: `bind` resolves the param **name** to a position at
|
||||
**authoring** time (the by-name authoring address space, the 0032 amendment) and
|
||||
the compilat stays wired by raw index — the name never reaches it. The
|
||||
the flat graph stays wired by raw index — the name never reaches it. The
|
||||
complementary question — exporting a **named frozen** strategy (all/most knobs
|
||||
bound) as a reusable blueprint *value* — is deferred (#60); `bind` ships only the
|
||||
per-knob overlay, no registry (C9/C10 intact).
|
||||
@@ -884,23 +884,23 @@ Recorded streams are sparse and timestamped (a record per fired cycle, tagged
|
||||
### C23 — Graph compilation and behaviour-preserving optimisation
|
||||
**Guarantee.** The bootstrap (C19) is a **compilation**: it lowers a param-generic,
|
||||
named **blueprint** (the authoring source — nodes, composites, strategy, harness;
|
||||
C8/C9/C20) into a flat, type-erased **compilat** — the frozen runnable
|
||||
C8/C9/C20) into a flat, type-erased **`FlatGraph`** — the frozen runnable
|
||||
instance (C7) — **wired by raw index, not by name** (`Edge { from, to, slot,
|
||||
from_field }`). Composites are **inlined** at this step (C9): the composite
|
||||
*boundary* dissolves entirely (there is no composite in the compilat). The
|
||||
*boundary* dissolves entirely (there is no composite in the flat graph). The
|
||||
blueprint's field / input-role *names* are **non-load-bearing** — the wiring
|
||||
resolves by index, and names survive at most as **informative debug symbols**
|
||||
(exactly as `FieldSpec.name` already is, C8), kept for tracing / rendering (C9
|
||||
graph-as-data, #13) but carrying no run semantics. The compilat is then the target of **behaviour-preserving
|
||||
graph-as-data, #13) but carrying no run semantics. The flat graph is then the target of **behaviour-preserving
|
||||
optimisation** — any transform that leaves every observable sink trace
|
||||
bit-identical (C1 is the correctness invariant) — on two levels:
|
||||
- **intra-compilat** (within one graph): **common-subexpression elimination** —
|
||||
- **intra-graph** (within one graph): **common-subexpression elimination** —
|
||||
two identical nodes (same type, same bound params, same input source) merge to
|
||||
one with output fan-out, so fractal composition (C9) costs no redundant compute —
|
||||
and **dead-node elimination** — a node on no path to a sink is dropped.
|
||||
Pure-consumer sinks (C8, no output) are never CSE candidates, so their
|
||||
out-of-graph side effects are preserved by construction.
|
||||
- **across the sweep family** (over the family of compilats one blueprint yields
|
||||
- **across the sweep family** (over the family of flat graphs one blueprint yields
|
||||
under a param sweep, C12): the sub-graph whose nodes carry **no swept param** and
|
||||
whose inputs are **all sweep-invariant** (transitively from the sources — same
|
||||
data window) is **loop-invariant** w.r.t. the sweep and is computed **once**; its
|
||||
@@ -915,16 +915,16 @@ analysed or rewritten across its boundary, so it forecloses both levels.
|
||||
for these rewrites — a behaviour-preserving transform is only meaningful because
|
||||
"same input → bit-identical run" makes "same result" decidable, and a
|
||||
sweep-invariant sub-graph is reproducible enough to compute once and share. The
|
||||
compilat representation (C19) is the necessary condition: only a flat, inspectable
|
||||
flat graph representation (C19) is the necessary condition: only a flat, inspectable
|
||||
graph-as-data — with each node's declared param-ranges (C8) — lets the compiler
|
||||
identify identical sub-expressions, dead nodes, and the sweep-invariant frontier.
|
||||
This is precisely why a composite is an inlining (C9) and not a runtime
|
||||
sub-engine: the flat compilat is what makes the whole graph optimisable.
|
||||
**Status (Construction-layer milestone).** The compilat *representation* —
|
||||
sub-engine: the flat graph is what makes the whole graph optimisable.
|
||||
**Status (Construction-layer milestone).** The flat graph *representation* —
|
||||
blueprint → inline / compile → flat instance — is the load-bearing substrate built
|
||||
**first**; the optimisation passes (intra-compilat CSE/DCE, sweep-invariant
|
||||
**first**; the optimisation passes (intra-graph CSE/DCE, sweep-invariant
|
||||
hoisting) are **deferred**, behaviour-preserving follow-on work, each gated by a
|
||||
"compilat with pass ≡ compilat without pass, bit-identical run" test (C1). The
|
||||
"flat graph with pass ≡ flat graph without pass, bit-identical run" test (C1). The
|
||||
sweep-level pass further presupposes per-node param declarations (C8 — landed in
|
||||
cycle 0015 as `name`+`kind`; the swept *range* still pending #32/C20) and the sweep
|
||||
orchestration itself (C12/C21).
|
||||
@@ -934,9 +934,9 @@ The bootstrap-as-compilation now includes one structural gate:
|
||||
C12-C19), run before name resolution. It reads the **boundary** name projection — the
|
||||
authoring address space — and rejects a duplicated path (`DuplicateParamPath`). Node
|
||||
names stay **non-load-bearing**: they qualify the param path at construction and are
|
||||
dropped at lowering (the compilat is wired by raw index, unchanged). The check makes
|
||||
dropped at lowering (the flat graph is wired by raw index, unchanged). The check makes
|
||||
the by-name *authoring address space* injective; it does **not** make names
|
||||
load-bearing in the compilat.
|
||||
load-bearing in the flat graph.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Blueprint → compilat: composite inlining — Implementation Plan
|
||||
# Blueprint → flat graph: composite inlining — Implementation Plan
|
||||
|
||||
> **Parent spec:** `docs/specs/0012-blueprint-compile-composites.md`
|
||||
>
|
||||
@@ -13,10 +13,10 @@ prove an SMA-cross composite runs bit-identically to today's hand-wired graph (C
|
||||
**Architecture:** A new module `crates/aura-engine/src/blueprint.rs` sits *above*
|
||||
`Harness::bootstrap`. `Blueprint::compile()` recursively inlines every `Composite`
|
||||
(append interior nodes at an offset, rewrite interior edges, fan input roles out,
|
||||
resolve the one output port), producing the same flat compilat a hand-wiring would.
|
||||
resolve the one output port), producing the same flat graph a hand-wiring would.
|
||||
The run loop, `bootstrap`'s signature, and `Edge`/`Target`/`SourceSpec`/`Node` are
|
||||
untouched; bootstrap's existing kind- and Kahn-cycle-check validate the lowered
|
||||
compilat. Optimisation passes (C23) are explicitly out of scope.
|
||||
flat graph. Optimisation passes (C23) are explicitly out of scope.
|
||||
|
||||
**Tech Stack:** Rust, `aura-engine` (depends on `aura-core`; `aura-std` is a
|
||||
dev-dependency reachable from tests). No new external dependencies (C16).
|
||||
@@ -57,12 +57,12 @@ Create `crates/aura-engine/src/blueprint.rs` with exactly this content:
|
||||
```rust
|
||||
//! 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
|
||||
//! already runs (the *flat graph*). 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
|
||||
//! unchanged [`crate::Harness::bootstrap`] consumes.
|
||||
//!
|
||||
//! The compilat is wired by raw index, **not by name** (C23): a composite's
|
||||
//! The flat graph is wired by raw index, **not by name** (C23): a composite's
|
||||
//! boundary dissolves at compile time; field/role names, where kept, are
|
||||
//! non-load-bearing debug symbols (as `FieldSpec.name` already is). This module
|
||||
//! adds no optimisation pass (CSE/DCE, sweep-invariant hoisting are deferred,
|
||||
@@ -479,7 +479,7 @@ In `crates/aura-engine/src/blueprint.rs`, add the `CompileError` enum immediatel
|
||||
after the `Composite` impl block (before `pub struct Blueprint`):
|
||||
|
||||
```rust
|
||||
/// A construction-phase fault, caught before the flat compilat reaches
|
||||
/// A construction-phase fault, caught before the flat graph reaches
|
||||
/// `Harness::bootstrap`.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CompileError {
|
||||
@@ -489,7 +489,7 @@ pub enum CompileError {
|
||||
RoleKindMismatch { role: usize },
|
||||
/// The output port names a missing interior node or output field.
|
||||
OutputPortOutOfRange,
|
||||
/// The lowered flat compilat failed `Harness::bootstrap`'s checks (kind
|
||||
/// The lowered flat graph failed `Harness::bootstrap`'s checks (kind
|
||||
/// mismatch, bad index, or directed cycle).
|
||||
Bootstrap(BootstrapError),
|
||||
}
|
||||
@@ -499,9 +499,9 @@ Then add the `compile` and `bootstrap` methods inside `impl Blueprint` (after
|
||||
`new`):
|
||||
|
||||
```rust
|
||||
/// Lower to the flat compilat: inline every composite (recursive), offset
|
||||
/// Lower to the flat graph: inline every composite (recursive), offset
|
||||
/// interior indices, rewrite edges, and fan input roles out. The run loop and
|
||||
/// `bootstrap`'s data model are unchanged; the lowered compilat is wired by raw
|
||||
/// `bootstrap`'s data model are unchanged; the lowered flat graph is wired by raw
|
||||
/// index (C23).
|
||||
// The flat triple is exactly `Harness::bootstrap`'s argument list; naming it
|
||||
// would be a speculative type alias this cycle (same call as the CLI's sample).
|
||||
@@ -533,7 +533,7 @@ Then add the `compile` and `bootstrap` methods inside `impl Blueprint` (after
|
||||
Ok((flat_nodes, flat_sources, flat_edges))
|
||||
}
|
||||
|
||||
/// Compile, then hand the flat compilat to the unchanged `Harness::bootstrap`.
|
||||
/// Compile, then hand the flat graph to the unchanged `Harness::bootstrap`.
|
||||
pub fn bootstrap(self) -> Result<Harness, CompileError> {
|
||||
let (nodes, sources, edges) = self.compile()?;
|
||||
Harness::bootstrap(nodes, sources, edges).map_err(CompileError::Bootstrap)
|
||||
@@ -544,7 +544,7 @@ Finally add the free lowering helpers and the `ItemLowering` enum at the end of
|
||||
file (after the `impl Blueprint` block, before `#[cfg(test)] mod tests`):
|
||||
|
||||
```rust
|
||||
/// How one blueprint item resolved into the flat compilat. Edges and source
|
||||
/// How one blueprint item resolved into the flat graph. Edges and source
|
||||
/// targets to/from an item are resolved through this.
|
||||
enum ItemLowering {
|
||||
/// A leaf lowered to exactly one flat node at this index.
|
||||
|
||||
@@ -29,7 +29,7 @@ v0.9.1, new `graph.rs`), `docs/design/INDEX.md` (C8 refinement note).
|
||||
- Modify: `crates/aura-std/src/sma.rs:22-46`, `sub.rs:27-47`, `exposure.rs:23-39`, `sim_broker.rs:59-85`, `add.rs:36-56`, `lincomb.rs:42-66`, `recorder.rs:31-58` — `label()` overrides.
|
||||
- Test: `crates/aura-std/src/sma.rs:48` (tests module) — disambiguation test.
|
||||
- Modify: `crates/aura-engine/src/blueprint.rs` — `Composite.name` field (54-59), widened `Composite::new` (64-71), accessors on `Composite` (61-90) and `Blueprint` (115-161), and the 7 `Composite::new` call sites (356, 433, 481, 513, 527, 541, 631).
|
||||
- Create: `crates/aura-cli/src/graph.rs` — the ascii-dag adapter (`render_blueprint`, `render_compilat`).
|
||||
- Create: `crates/aura-cli/src/graph.rs` — the ascii-dag adapter (`render_blueprint`, `render_flat_graph`).
|
||||
- Modify: `crates/aura-cli/Cargo.toml:12-15` — add `ascii-dag = "0.9.1"`.
|
||||
- Modify: `crates/aura-cli/src/main.rs` — imports (9-14), `mod graph;`, sample builders, `graph` dispatch arm + usage strings (114-126). `sample_harness` (42-78) and `run_sample` (83-112) are NOT touched.
|
||||
- Test: `crates/aura-cli/src/main.rs:128-168` (tests module) — render tests.
|
||||
@@ -274,7 +274,7 @@ to:
|
||||
/// Build a composite from its authored name, interior items, interior edges
|
||||
/// (local indices), input roles, and output port. 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).
|
||||
/// reach the flat graph (the boundary dissolves at inline, C23).
|
||||
pub fn new(
|
||||
name: impl Into<String>,
|
||||
nodes: Vec<BlueprintNode>,
|
||||
@@ -409,7 +409,7 @@ ascii-dag = "0.9.1"
|
||||
//! The `aura graph` ASCII-DAG adapter (#13): turns the engine's graph-as-data
|
||||
//! (C9) into an `ascii_dag::Graph` rendered to a `String`. Two views:
|
||||
//! `render_blueprint` draws composites as named cluster boxes (pre-inline);
|
||||
//! `render_compilat` draws the flat post-inline graph (boundaries dissolved,
|
||||
//! `render_flat_graph` draws the flat post-inline graph (boundaries dissolved,
|
||||
//! C23). Rendering reads structure + node `label()`s only — never `eval`.
|
||||
//!
|
||||
//! ascii-dag borrows its node/subgraph labels as `&'a str`, so each function
|
||||
@@ -541,7 +541,7 @@ pub fn render_blueprint(bp: &Blueprint) -> String {
|
||||
|
||||
/// Compiled view: the flat post-inline graph (no clusters; boundaries dissolved,
|
||||
/// C23). Each `Box<dyn Node>` labels itself; node display id = node index.
|
||||
pub fn render_compilat(nodes: &[Box<dyn Node>], sources: &[SourceSpec], edges: &[Edge]) -> String {
|
||||
pub fn render_flat_graph(nodes: &[Box<dyn Node>], sources: &[SourceSpec], edges: &[Edge]) -> String {
|
||||
let mut labels: Vec<String> = nodes.iter().map(|n| n.label()).collect();
|
||||
let source_base = labels.len();
|
||||
for src in sources {
|
||||
@@ -669,7 +669,7 @@ to:
|
||||
let bp = sample_blueprint();
|
||||
let out = if compiled {
|
||||
let (nodes, sources, edges) = bp.compile().expect("valid sample blueprint");
|
||||
graph::render_compilat(&nodes, &sources, &edges)
|
||||
graph::render_flat_graph(&nodes, &sources, &edges)
|
||||
} else {
|
||||
graph::render_blueprint(&bp)
|
||||
};
|
||||
@@ -729,7 +729,7 @@ In `crates/aura-cli/src/main.rs`, inside the existing `#[cfg(test)] mod tests` (
|
||||
fn compiled_view_dissolves_the_composite_boundary() {
|
||||
let bp = sample_blueprint();
|
||||
let (nodes, sources, edges) = bp.compile().expect("valid sample");
|
||||
let out = graph::render_compilat(&nodes, &sources, &edges);
|
||||
let out = graph::render_flat_graph(&nodes, &sources, &edges);
|
||||
// node labels survive inlining...
|
||||
assert!(out.contains("SMA(2)") && out.contains("SMA(4)"), "labels lost:\n{out}");
|
||||
// ...but the composite cluster name does NOT (boundary dissolved, C23)
|
||||
@@ -748,7 +748,7 @@ In `crates/aura-cli/src/main.rs`, inside the existing `#[cfg(test)] mod tests` (
|
||||
- [ ] **Step 2: Run the tests to verify they pass**
|
||||
|
||||
Run: `cargo test -p aura-cli blueprint_view_shows_cluster_and_param_labels compiled_view_dissolves_the_composite_boundary swapped_sma_inputs_render_differently`
|
||||
Expected: PASS (all three). (`render_blueprint`/`render_compilat`/`sample_blueprint` already exist from Task 4; this task only adds tests + the test-only swapped builder.)
|
||||
Expected: PASS (all three). (`render_blueprint`/`render_flat_graph`/`sample_blueprint` already exist from Task 4; this task only adds tests + the test-only swapped builder.)
|
||||
|
||||
- [ ] **Step 3: Freeze the full-byte golden snapshots**
|
||||
|
||||
@@ -773,7 +773,7 @@ Then run: `cargo run -q -p aura-cli -- graph --compiled`, and add the twin:
|
||||
fn compiled_view_golden() {
|
||||
let bp = sample_blueprint();
|
||||
let (nodes, sources, edges) = bp.compile().expect("valid sample");
|
||||
let out = graph::render_compilat(&nodes, &sources, &edges);
|
||||
let out = graph::render_flat_graph(&nodes, &sources, &edges);
|
||||
let expected = "<<paste the exact captured `aura graph --compiled` stdout here>>";
|
||||
assert_eq!(out, expected, "compiled render drifted; re-capture if intended");
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ params into one flat, path-qualified, inspectable param-space.
|
||||
declare their tunable knobs. `aura-engine` gains a read-only `Blueprint::param_space()`
|
||||
that walks the graph-as-data (using the already-public `Composite::name()` as path
|
||||
prefix) in the same deterministic depth-first order `lower_items` uses — a parallel
|
||||
projection that leaves `compile`/`inline_composite` (and the compilat) untouched.
|
||||
projection that leaves `compile`/`inline_composite` (and the flat graph) untouched.
|
||||
|
||||
**Tech Stack:** Rust workspace — `aura-core` (node contract), `aura-std` (7 nodes),
|
||||
`aura-engine` (blueprint/compile). Param identity is positional (slot), name a
|
||||
@@ -320,7 +320,7 @@ the build names any remaining `NodeSchema` literal missing `params`, add
|
||||
Run: `cargo test -p aura-engine`
|
||||
Expected: PASS — all pre-existing tests (incl. the bit-identical
|
||||
`composite_sma_cross_runs_bit_identical_to_hand_wired` and the golden render tests)
|
||||
stay green: the compilat is unchanged, only schema literals gained an empty field.
|
||||
stay green: the flat graph is unchanged, only schema literals gained an empty field.
|
||||
|
||||
---
|
||||
|
||||
@@ -515,7 +515,7 @@ and `LinComb::schema` are clippy-clean).
|
||||
- **Do not touch** `compile`, `inline_composite`, `lower_items`, or any edge/wiring
|
||||
logic. `param_space()` is a *parallel* read-only projection that mirrors the
|
||||
inliner's traversal order; it must not share or alter it. The spec's correctness
|
||||
rests on the compilat staying bit-identical (every existing golden / bit-identical
|
||||
rests on the flat graph staying bit-identical (every existing golden / bit-identical
|
||||
test stays green by construction).
|
||||
- **fieldtests/ are out of scope** — they are excluded crates (own `Cargo.toml`),
|
||||
not in `--workspace`, and are frozen cycle-archive snapshots. They construct the
|
||||
|
||||
@@ -467,7 +467,7 @@ param-driven path plus no-param wrappers. The arity is checked up front via
|
||||
self.compile_with_params(&[])
|
||||
}
|
||||
|
||||
/// Compile under an injected vector, then hand the flat compilat to the
|
||||
/// Compile under an injected vector, then hand the flat graph to the
|
||||
/// unchanged `Harness::bootstrap`.
|
||||
pub fn bootstrap_with_params(self, params: Vec<Scalar>) -> Result<Harness, CompileError> {
|
||||
let (nodes, sources, edges) = self.compile_with_params(¶ms)?;
|
||||
@@ -640,7 +640,7 @@ and inside the composite loop:
|
||||
}
|
||||
```
|
||||
|
||||
(`render_compilat` / the compiled-view renderer operates on built flat nodes via
|
||||
(`render_flat_graph` / the compiled-view renderer operates on built flat nodes via
|
||||
`Node::label()` and is unchanged.)
|
||||
|
||||
- [ ] **Step 2: Sample blueprint → factories (`main.rs`)**
|
||||
@@ -665,7 +665,7 @@ and inside the composite loop:
|
||||
(`main.rs:230`): the blueprint view is now param-generic and identical for both
|
||||
orderings, so the swap is not observable there. Re-express the swap as a different
|
||||
injected vector (`vec![Scalar::I64(4), Scalar::I64(2), Scalar::F64(0.5)]`) and
|
||||
assert the **compiled** view differs (`render_compilat` of the compiled flat nodes
|
||||
assert the **compiled** view differs (`render_flat_graph` of the compiled flat nodes
|
||||
shows `SMA(4)`/`SMA(2)` swapped), not the blueprint view. Rename the test to its
|
||||
new premise (e.g. `swapped_param_vector_changes_the_compiled_render`).
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ top-level item — a composite labelled by `name()`, opaque) plus a definitions
|
||||
block where each distinct composite type (deduped by `name()`, collected
|
||||
recursively) renders its interior once with `[in:k]`/`[out]` port markers. The
|
||||
old `ItemDisplay`/`producer_id`/`consumer_ids`/subgraph machinery and the
|
||||
nested-composite `unimplemented!` are removed. `render_compilat` is untouched.
|
||||
nested-composite `unimplemented!` are removed. `render_flat_graph` is untouched.
|
||||
|
||||
**Tech Stack:** `crates/aura-cli/src/graph.rs` (render), `crates/aura-cli/src/main.rs`
|
||||
(tests), `ascii-dag` flat `RenderMode::Vertical`, the `aura_engine`
|
||||
@@ -161,7 +161,7 @@ imports (lines 12-14) with:
|
||||
//! views. `render_blueprint` shows the authored structure — a flat main graph
|
||||
//! wiring the harness with each composite as a single opaque node, plus a
|
||||
//! `where:` section that defines each distinct composite type once (its interior
|
||||
//! with `[in:k]`/`[out]` port markers). `render_compilat` shows the flat
|
||||
//! with `[in:k]`/`[out]` port markers). `render_flat_graph` shows the flat
|
||||
//! post-inline graph (boundaries dissolved, C23). Rendering reads structure +
|
||||
//! node `label()`s only — never `eval`.
|
||||
//!
|
||||
@@ -178,7 +178,7 @@ use aura_engine::{Blueprint, BlueprintNode, Composite, Edge, SourceSpec};
|
||||
|
||||
(`Composite` is added — named by the new helpers; `Target` is dropped — no longer
|
||||
named after the `ItemDisplay` collapse. `Edge`/`SourceSpec`/`Node` remain: they are
|
||||
`render_compilat`'s parameter types.)
|
||||
`render_flat_graph`'s parameter types.)
|
||||
|
||||
- [ ] **Step 4: Rewrite `graph.rs` — replace `ItemDisplay`/`producer_id`/`consumer_ids`/`render_blueprint` (old lines 16-132)**
|
||||
|
||||
@@ -233,7 +233,7 @@ pub fn render_blueprint(bp: &Blueprint) -> String {
|
||||
}
|
||||
|
||||
/// Build and render a flat (no-subgraph) ascii-dag graph from owned labels and
|
||||
/// edge pairs — the same idiom `render_compilat` uses.
|
||||
/// edge pairs — the same idiom `render_flat_graph` uses.
|
||||
fn render_flat(labels: &[String], edges: &[(usize, usize)]) -> String {
|
||||
let mut g = Graph::with_mode(RenderMode::Vertical);
|
||||
for (id, l) in labels.iter().enumerate() {
|
||||
@@ -376,7 +376,7 @@ Run: `cargo test --workspace`
|
||||
Expected: PASS, 0 failed. In particular the four must-stay-green tests
|
||||
(`compiled_view_dissolves_the_composite_boundary`, `compiled_view_golden`,
|
||||
`swapped_param_vector_changes_the_compiled_render`,
|
||||
`run_sample_is_deterministic_and_non_trivial`) remain green — `render_compilat` is
|
||||
`run_sample_is_deterministic_and_non_trivial`) remain green — `render_flat_graph` is
|
||||
untouched, so `compiled_view_golden` is byte-identical.
|
||||
|
||||
Run: `cargo clippy --workspace --all-targets -- -D warnings`
|
||||
|
||||
@@ -15,7 +15,7 @@ composite boundary (`NodeSchema.output: Vec<FieldSpec>`, `Edge::from_field`
|
||||
selects a column, leaf multi-output already works). This cycle replaces the
|
||||
single `OutPort` with a `Vec<OutField>` and lifts the three `field == 0` caps at
|
||||
the boundary (`inline_composite` nested arm, `rewrite_edge` composite arm). Names
|
||||
live at the blueprint boundary only and are dropped in the compilat (C23); C8/C7/C4
|
||||
live at the blueprint boundary only and are dropped in the flat graph (C23); C8/C7/C4
|
||||
are untouched — one port, one row, K columns.
|
||||
|
||||
**Tech Stack:** `crates/aura-engine/src/blueprint.rs` (type + compile logic),
|
||||
@@ -72,7 +72,7 @@ with:
|
||||
/// One re-exported field of a composite's output record: an interior
|
||||
/// `(node, output-field)` surfaced at the boundary under `name`. `name` is a
|
||||
/// non-load-bearing render/debug symbol (C23) — like `FieldSpec.name` and
|
||||
/// `Composite.name`, it does not reach the compilat.
|
||||
/// `Composite.name`, it does not reach the flat graph.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct OutField {
|
||||
pub node: usize,
|
||||
@@ -547,14 +547,14 @@ Run: `cargo test -p aura-cli blueprint_view_golden`
|
||||
Expected: FAIL first (golden drift: `[out]` → `[out:cross]`), then PASS after the
|
||||
literal is re-captured.
|
||||
|
||||
- [ ] **Step 9: Confirm the compilat golden is byte-identical (main.rs:505–530)**
|
||||
- [ ] **Step 9: Confirm the flat graph golden is byte-identical (main.rs:505–530)**
|
||||
|
||||
`compiled_view_golden` pins the flat compilat render; per C23 names are dropped at
|
||||
`compiled_view_golden` pins the flat graph render; per C23 names are dropped at
|
||||
inline, so it must **not** change (acceptance criterion 6 — the regression guard).
|
||||
|
||||
Run: `cargo test -p aura-cli compiled_view_golden`
|
||||
Expected: PASS with **no** edit to the golden literal. If it drifts, a name leaked
|
||||
into the compilat — a bug to fix, not a golden to re-capture.
|
||||
into the flat graph — a bug to fix, not a golden to re-capture.
|
||||
|
||||
- [ ] **Step 10: Full CLI test + clippy**
|
||||
|
||||
@@ -617,7 +617,7 @@ Expected: PASS — zero warnings.
|
||||
- [ ] `cargo test --workspace` green (incl. the four new engine capability tests and the re-captured `blueprint_view_golden`).
|
||||
- [ ] `cargo clippy --workspace --all-targets -- -D warnings` green.
|
||||
- [ ] `rg "OutPort" --type rust` returns nothing (type fully retired).
|
||||
- [ ] `compiled_view_golden` unchanged (compilat byte-identical — C23 / acceptance criterion 6).
|
||||
- [ ] `compiled_view_golden` unchanged (flat graph byte-identical — C23 / acceptance criterion 6).
|
||||
- [ ] The MACD PoC re-exports `macd`/`signal`/`histogram`; the run still trades the histogram (via `from_field: 2`).
|
||||
|
||||
The implementation commit closes #40.
|
||||
|
||||
@@ -668,7 +668,7 @@ literal (do not hand-edit field-by-field). Re-run: PASS.
|
||||
|
||||
Run: `cargo test -p aura-cli compiled_view_golden`
|
||||
Expected: PASS with NO edit to the golden (`main.rs:510-535`). The boundary names
|
||||
never reach the compilat (C23); if this golden drifts, STOP — that is a bug, not a
|
||||
never reach the flat graph (C23); if this golden drifts, STOP — that is a bug, not a
|
||||
golden to re-capture.
|
||||
|
||||
- [ ] **Step 9: Confirm MACD run determinism is unchanged**
|
||||
|
||||
@@ -419,7 +419,7 @@ fallback path is the unchanged positional branch.)
|
||||
- [ ] **Step 7: Confirm `compiled_view_golden` is byte-stable**
|
||||
|
||||
Run: `cargo test -p aura-cli compiled_view_golden`
|
||||
Expected: PASS unchanged — the compilat carries no aliases / `#` identifiers
|
||||
Expected: PASS unchanged — the flat graph carries no aliases / `#` identifiers
|
||||
(C23 guard). If it fails, the render change leaked into the compiled view — stop
|
||||
and inspect; do not re-capture this golden.
|
||||
|
||||
@@ -636,7 +636,7 @@ signatures (type initial + alias initials + recursive input signatures) — do n
|
||||
hide an unnamed configuration axis: a collision is a `CompileError`
|
||||
(`IndistinguishableFanIn`) when at least one colliding source carries an
|
||||
unaliased param slot. Genuinely-interchangeable sources (equal signatures, no
|
||||
param) stay legal. Construction-phase only; the compilat stays name-free (C23).
|
||||
param) stay legal. Construction-phase only; the flat graph stays name-free (C23).
|
||||
The graph view renders each fan-in input as the shortest sibling-unique prefix
|
||||
of its source signature.
|
||||
```
|
||||
|
||||
@@ -482,7 +482,7 @@ In `crates/aura-engine/src/harness.rs`, next to `SourceSpec` (≈49), add:
|
||||
|
||||
```rust
|
||||
/// The flat, type-erased, index-wired output of `Composite::compile` — the target
|
||||
/// `Harness::bootstrap` consumes (C23's "compilat", now a named type). `signatures[i]`
|
||||
/// `Harness::bootstrap` consumes (C23's "flat graph", now a named type). `signatures[i]`
|
||||
/// is the static signature of `nodes[i]` (gathered from each primitive's builder at
|
||||
/// lowering); `bootstrap` reads kinds/output from it and `nodes[i].lookbacks()` for
|
||||
/// buffer depth. `sources` are the lowered bound roles, in role-declaration order.
|
||||
@@ -1093,7 +1093,7 @@ is preserved). `macd_blueprint` (264-) return type → `Composite`.
|
||||
and `Harness::bootstrap(nodes, sources, edges)` → `Harness::bootstrap(flat)`.
|
||||
|
||||
`render_compiled` (336-337): signature `bp: Blueprint` → `bp: Composite`; body
|
||||
`let flat = bp.compile_with_params(point).expect("valid blueprint"); graph::render_compilat(&flat.nodes, &flat.sources, &flat.edges, color)`.
|
||||
`let flat = bp.compile_with_params(point).expect("valid blueprint"); graph::render_flat_graph(&flat.nodes, &flat.sources, &flat.edges, color)`.
|
||||
|
||||
`run_sample`/`sample_harness` (the bootstrap at main.rs:53): same `FlatGraph`
|
||||
threading as `run_macd`.
|
||||
@@ -1114,7 +1114,7 @@ In `crates/aura-cli/src/graph.rs`:
|
||||
- Match arms `BlueprintNode::Leaf` → `Primitive` at **118, 212-213, 325, 337, 399-400**.
|
||||
- `factory: &LeafFactory` param at **250** → `&PrimitiveBuilder` (its `.params()`/
|
||||
`.label()` calls are unchanged).
|
||||
- The `sources: &[SourceSpec]` param at 482 (render_compilat) is unchanged
|
||||
- The `sources: &[SourceSpec]` param at 482 (render_flat_graph) is unchanged
|
||||
(`FlatGraph.sources` is still `Vec<SourceSpec>`).
|
||||
|
||||
- [ ] **Step 5: Migrate aura-cli's `#[cfg(test)]` module**
|
||||
|
||||
@@ -15,7 +15,7 @@ the CLI render layer: (A) thread the root composite as the fan-in stub context
|
||||
(`stub_ctx` drops its `Option`; both `render_graph` callers pass `&Composite`),
|
||||
and (B) build root entries from `role.name` instead of `format!("source:{kind}")`.
|
||||
The existing `slot_source`/`fan_in_identifiers`/`signature_of` are reused verbatim
|
||||
(no new stub path). `render_compilat` is untouched (the compiled view keeps
|
||||
(no new stub path). `render_flat_graph` is untouched (the compiled view keeps
|
||||
`[source:F64]` — names dissolve post-inline, C23). Behaviour-preserving for the
|
||||
run path (C1); read-only render (C9); no engine change.
|
||||
|
||||
@@ -50,7 +50,7 @@ captured from the live `aura graph` / `aura graph --macd` output.
|
||||
add a `[src]` role-name-passthrough assertion.
|
||||
|
||||
**Explicitly OUT of scope (do not touch):**
|
||||
- `crates/aura-cli/src/graph.rs:486-505` (`render_compilat`) — the negative-control
|
||||
- `crates/aura-cli/src/graph.rs:486-505` (`render_flat_graph`) — the negative-control
|
||||
path; must stay byte-identical so `compiled_view_golden` does not move.
|
||||
- `crates/aura-cli/src/main.rs:564-589` (`compiled_view_golden`) — its expected
|
||||
block (`[source:F64]`, `[SimBroker(0.0001)]`) must NOT be edited.
|
||||
|
||||
@@ -572,7 +572,7 @@ And delete the `render_compiled` helper (lines 358-363):
|
||||
/// (C23) view — the shared body of the `--compiled` paths.
|
||||
fn render_compiled(bp: Composite, point: &[Scalar], color: graph::Color) -> String {
|
||||
let flat = bp.compile_with_params(point).expect("valid blueprint");
|
||||
graph::render_compilat(&flat.nodes, &flat.sources, &flat.edges, color)
|
||||
graph::render_flat_graph(&flat.nodes, &flat.sources, &flat.edges, color)
|
||||
}
|
||||
```
|
||||
If `is_terminal`/`IsTerminal` was imported only for the `color` binding, its `use`
|
||||
@@ -605,7 +605,7 @@ which dies with the file).
|
||||
|
||||
In `crates/aura-cli/src/main.rs`'s `#[cfg(test)] mod tests`, delete these test
|
||||
functions in full (each asserts retired ascii-dag output and references
|
||||
`graph::render_blueprint` / `graph::render_compilat` / `graph::Color`):
|
||||
`graph::render_blueprint` / `graph::render_flat_graph` / `graph::Color`):
|
||||
```text
|
||||
blueprint_view_main_graph_shows_composite_as_opaque_node (~409-425)
|
||||
blueprint_view_defines_each_composite_once (~427-435)
|
||||
|
||||
@@ -485,7 +485,7 @@ In the C23-related prose at :359-366 and :813-851: strike the `ParamAlias`
|
||||
param-overlay from the named-projection set (the param projection is retired;
|
||||
`Role.name` input roles and `OutField.name` outputs remain). Note that node names
|
||||
join the same non-load-bearing debug-symbol class (construction-time identity,
|
||||
dropped at lowering; the compilat stays wired by raw index). Remove the sentence
|
||||
dropped at lowering; the flat graph stays wired by raw index). Remove the sentence
|
||||
referencing the dangling-alias `BadInteriorIndex` compile check (:362-364) — that
|
||||
path is gone with the overlay.
|
||||
|
||||
|
||||
@@ -469,7 +469,7 @@ distinguishability check, if ever wanted, is decoupled from param-space injectiv
|
||||
|
||||
At the sentence "Identity is **positional** (the slot, C23 'by index, not name');
|
||||
… same-type siblings in one composite share a name, uniqueness is at the slot",
|
||||
add the refinement: identity in the **compilat** stays positional (C23, unchanged),
|
||||
add the refinement: identity in the **flat graph** stays positional (C23, unchanged),
|
||||
but the `param_space()` **name projection** — the authoring / by-name address space
|
||||
— must be **injective** for a blueprint to compile (cycle 0032). Two layers:
|
||||
positional wiring below, injective name address space above.
|
||||
@@ -477,9 +477,9 @@ positional wiring below, injective name address space above.
|
||||
- [ ] **Step 3: Note the C23 amendment**
|
||||
|
||||
Record that the injectivity check is part of bootstrap-as-compilation; node names
|
||||
stay non-load-bearing (dropped at lowering, compilat wired by raw index). The check
|
||||
stay non-load-bearing (dropped at lowering, flat graph wired by raw index). The check
|
||||
reads the boundary name projection; it does not make names load-bearing in the
|
||||
compilat.
|
||||
flat graph.
|
||||
|
||||
- [ ] **Step 4: Verify the ledger still builds as docs (sanity)**
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ resolves every name against each node's cached `NodeSchema` by exactly-one-match
|
||||
(the `PrimitiveBuilder::bind` posture, but fallible) and hands the resolved
|
||||
`Vec<Edge>`/`Vec<Role>`/`Vec<OutField>` to the unchanged `Composite::new`. A new
|
||||
`impl From<Composite> for BlueprintNode` lets `add` accept nested composites.
|
||||
Names never reach the compilat (C23 holds by construction).
|
||||
Names never reach the flat graph (C23 holds by construction).
|
||||
|
||||
**Tech Stack:** Rust, `aura-engine` (blueprint/harness), `aura-core` (NodeSchema/
|
||||
PortSpec/FieldSpec/ScalarKind), `aura-std` nodes for tests.
|
||||
@@ -105,7 +105,7 @@ Create `crates/aura-engine/src/builder.rs` with:
|
||||
//!
|
||||
//! A fluent, additive authoring surface that wires a blueprint by typed node
|
||||
//! handles and port/field *names*, resolving them to the raw-index `Composite`
|
||||
//! at a single fallible `build()`. The compilat stays index-wired (C23): names
|
||||
//! at a single fallible `build()`. The flat graph stays index-wired (C23): names
|
||||
//! are resolved at the authoring boundary and never reach `FlatGraph` — the same
|
||||
//! posture param-name resolution already has (`Binder`, blueprint.rs). Resolution
|
||||
//! mirrors `PrimitiveBuilder::bind`'s collect-then-reject (node.rs), but returns
|
||||
|
||||
@@ -324,7 +324,7 @@ Expected: PASS (`1 passed`).
|
||||
deliberately under-wired `strategy` (LinComb's two `term` inputs never fed) only to
|
||||
read its flat param order. Fully wire it: fan `fast_slow`'s output into both LinComb
|
||||
terms, and add a covering root role for `strategy`'s `price` input. Wiring changes no
|
||||
node and no param, so the asserted `space == from_compilat` equality is unchanged.
|
||||
node and no param, so the asserted `space == from_flat` equality is unchanged.
|
||||
|
||||
**Files:**
|
||||
- Modify: `crates/aura-engine/src/blueprint.rs:1877`
|
||||
@@ -611,7 +611,7 @@ never consumers, so only interior input slots are subject to the rule. There is
|
||||
optional-input concept**: every declared input port is required (no shipped node runs
|
||||
meaningfully without one; an unwarmed mode-A input is *wired-but-not-yet-valued*, not
|
||||
unwired). The check is **index-based and name-free** — it touches no name machinery
|
||||
and emits nothing into the compilat, so C23 is untouched (it proves the existing
|
||||
and emits nothing into the flat graph, so C23 is untouched (it proves the existing
|
||||
raw-index wiring is total and single-valued). Inherited identically by the raw
|
||||
`Composite::new` path and the `GraphBuilder::build()` path (both compile via
|
||||
`compile_with_params`).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Blueprint → compilat: composite inlining — Design Spec
|
||||
# Blueprint → flat graph: composite inlining — Design Spec
|
||||
|
||||
**Date:** 2026-06-05
|
||||
**Status:** Draft — awaiting user spec review
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
Introduce the **construction layer** that turns a hand-written, raw-index graph
|
||||
into named **graph-as-data** (a `Blueprint`) that **compiles** to the flat,
|
||||
type-erased instance the run loop already runs (the **compilat**). The unit of
|
||||
type-erased instance the run loop already runs (the **flat graph**). The unit of
|
||||
reuse is the **composite**: a nestable sub-graph fragment that exposes one output
|
||||
port and named input roles, and that the compile step **inlines** into the flat
|
||||
`(nodes, sources, edges)` the unchanged `Harness::bootstrap` consumes.
|
||||
|
||||
This realizes C9 (fractal composition), C19 (bootstrap = compilation), and C23
|
||||
(blueprint → flat compilat, wired by raw index; names non-load-bearing). It is the
|
||||
(blueprint → flat graph, wired by raw index; names non-load-bearing). It is the
|
||||
anchor of the *Construction layer* milestone (Gitea #12).
|
||||
|
||||
**What ships:** a `Blueprint` / `Composite` representation in `aura-engine`, a
|
||||
@@ -51,9 +51,9 @@ edges *into* a composite are resolved through its input roles (a fan-out: one
|
||||
blueprint edge may become several flat edges), and edges *out of* a composite are
|
||||
resolved to its interior output port. Nesting is handled by compiling
|
||||
inside-out / recursively. After lowering, `bootstrap`'s existing kind-check and
|
||||
Kahn cycle-check cover the flat compilat for free (C7/C8).
|
||||
Kahn cycle-check cover the flat graph for free (C7/C8).
|
||||
|
||||
The compilat is **wired by raw index, not by name** (C23): the composite boundary
|
||||
The flat graph is **wired by raw index, not by name** (C23): the composite boundary
|
||||
dissolves entirely; field/input-role names, where kept, are non-load-bearing debug
|
||||
symbols (as `FieldSpec.name` already is, `crates/aura-core/src/node.rs:37`).
|
||||
|
||||
@@ -198,20 +198,20 @@ pub struct Blueprint {
|
||||
impl Blueprint {
|
||||
pub fn new(nodes: Vec<BlueprintNode>, sources: Vec<SourceSpec>,
|
||||
edges: Vec<Edge>) -> Self;
|
||||
/// Lower to the flat compilat: inline every composite (recursive), offset
|
||||
/// Lower to the flat graph: inline every composite (recursive), offset
|
||||
/// interior indices, rewrite edges, fan input roles out. Run loop unchanged.
|
||||
pub fn compile(self) -> Result<(Vec<Box<dyn Node>>, Vec<SourceSpec>, Vec<Edge>), CompileError>;
|
||||
/// Compile, then hand the flat compilat to the unchanged Harness::bootstrap.
|
||||
/// Compile, then hand the flat graph to the unchanged Harness::bootstrap.
|
||||
pub fn bootstrap(self) -> Result<Harness, CompileError>;
|
||||
}
|
||||
|
||||
/// A construction-phase fault, caught before the flat compilat reaches bootstrap.
|
||||
/// A construction-phase fault, caught before the flat graph reaches bootstrap.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CompileError {
|
||||
BadInteriorIndex, // an interior edge/role/output index is out of range
|
||||
RoleKindMismatch { role: usize }, // a role fans into interior slots of differing kinds
|
||||
OutputPortOutOfRange, // the output port names a missing interior node/field
|
||||
Bootstrap(BootstrapError), // the lowered flat compilat failed bootstrap's checks
|
||||
Bootstrap(BootstrapError), // the lowered flat graph failed bootstrap's checks
|
||||
}
|
||||
```
|
||||
|
||||
@@ -232,7 +232,7 @@ trait are **unchanged**.
|
||||
items at an offset, rewrite interior edges, resolve edges into a composite via
|
||||
its input roles (fan-out), resolve edges out of a composite to its output port.
|
||||
- **`CompileError`** — construction-phase faults, with `Bootstrap(BootstrapError)`
|
||||
for the lowered-compilat failure.
|
||||
for the lowered flat-graph failure.
|
||||
|
||||
## Data flow
|
||||
|
||||
@@ -251,10 +251,10 @@ Authoring → `Blueprint` (graph-as-data, blueprint indices) → `compile()`:
|
||||
`from: base_c + output.node`, `from_field: output.field`.
|
||||
4. Result: flat `(nodes, sources, edges)` with no composites, wired by raw index.
|
||||
`Blueprint::bootstrap` hands these to the unchanged `Harness::bootstrap`, whose
|
||||
kind-check + Kahn cycle-check (`harness.rs:142-192`) validate the compilat.
|
||||
kind-check + Kahn cycle-check (`harness.rs:142-192`) validate the flat graph.
|
||||
|
||||
Then `Harness::run` drives the flat compilat exactly as today (C1 determinism
|
||||
preserved — the compilat is the same flat topology the hand-wiring produced).
|
||||
Then `Harness::run` drives the flat graph exactly as today (C1 determinism
|
||||
preserved — the flat graph is the same flat topology the hand-wiring produced).
|
||||
|
||||
## Error handling
|
||||
|
||||
@@ -263,10 +263,10 @@ preserved — the compilat is the same flat topology the hand-wiring produced).
|
||||
(`BadInteriorIndex`), a role fanning into interior slots of differing scalar
|
||||
kinds (`RoleKindMismatch`), an output port naming a missing interior node/field
|
||||
(`OutputPortOutOfRange`).
|
||||
- The lowered flat compilat is validated by `bootstrap`'s **existing** checks; any
|
||||
- The lowered flat graph is validated by `bootstrap`'s **existing** checks; any
|
||||
`BootstrapError` (kind mismatch, bad index, cycle) is wrapped as
|
||||
`CompileError::Bootstrap(..)`. No duplication of bootstrap's validation in the
|
||||
inliner — the compilat is checked once, where it always was (C7/C8).
|
||||
inliner — the flat graph is checked once, where it always was (C7/C8).
|
||||
- A composite's *derived* `schema()` is what the enclosing graph kind-checks
|
||||
against; a same-name role fanning to mismatched kinds is caught at compile, not
|
||||
hidden until run.
|
||||
@@ -278,7 +278,7 @@ preserved — the compilat is the same flat topology the hand-wiring produced).
|
||||
an edge out of a composite resolves to its output port; a **nested** composite
|
||||
(composite-in-composite) inlines correctly.
|
||||
- **Unit (errors):** `BadInteriorIndex`, `RoleKindMismatch`, `OutputPortOutOfRange`
|
||||
each provoked by a malformed composite; a lowered compilat with a kind mismatch
|
||||
each provoked by a malformed composite; a lowered flat graph with a kind mismatch
|
||||
or cycle surfaces as `CompileError::Bootstrap(..)`.
|
||||
- **Integration (headline, C1):** the SMA-cross composite, compiled and run,
|
||||
produces equity + exposure sink traces **bit-identical** to the hand-wired flat
|
||||
@@ -307,7 +307,7 @@ possible once params and the sweep orchestration land (C12/C21).
|
||||
4. The SMA-cross composite produces a run **bit-identical** to the hand-wired
|
||||
graph (C1) — the headline test passes.
|
||||
5. `compile()` rejects malformed wiring with a typed `CompileError`; the lowered
|
||||
flat compilat is validated by `bootstrap`'s existing kind/cycle checks (no
|
||||
flat graph is validated by `bootstrap`'s existing kind/cycle checks (no
|
||||
re-implementation).
|
||||
6. `Harness::bootstrap`, `Harness::run`, `Edge`, `Target`, `SourceSpec`, and the
|
||||
`Node` trait are **unchanged**; the run loop is untouched.
|
||||
|
||||
@@ -22,7 +22,7 @@ Two views are rendered, selectable:
|
||||
- `aura graph` — the **blueprint** view: the authored graph *before* inlining,
|
||||
with each composite drawn as a labelled cluster box (C9 fractal structure as
|
||||
written).
|
||||
- `aura graph --compiled` — the **compilat** view: the flat, post-inline
|
||||
- `aura graph --compiled` — the **flat graph** view: the flat, post-inline
|
||||
`(nodes, sources, edges)` that actually runs; composite boundaries are
|
||||
dissolved (C23). This is the same graph the run loop and the deferred C23
|
||||
optimiser see.
|
||||
@@ -54,7 +54,7 @@ reason the work is split across crates rather than landing in one:
|
||||
*with its parameters*, so two `Sma` nodes read `SMA(2)` and `SMA(4)` and a
|
||||
swap is visible. The method is additive, non-load-bearing, and never read by
|
||||
the run loop — a C8 refinement aligned with C23, not a behavioural change. It
|
||||
must live on `Node` (not a side table) because the compilat view holds
|
||||
must live on `Node` (not a side table) because the flat graph view holds
|
||||
`Vec<Box<dyn Node>>` and labels each node by asking the trait object directly.
|
||||
|
||||
## Concrete code shapes
|
||||
@@ -151,7 +151,7 @@ pub trait Node {
|
||||
The default takes `&self` and returns an owned `String`, so `Node` stays
|
||||
object-safe and `Box<dyn Node>::label()` dispatches (a `type_name::<Self>()`
|
||||
default would require `Self: Sized` and is therefore rejected — it would not be
|
||||
callable on the `dyn Node` the compilat holds).
|
||||
callable on the `dyn Node` the flat graph holds).
|
||||
|
||||
**2. aura-std overrides — one shown, the rest analogous (aura-std/src/sma.rs).**
|
||||
|
||||
@@ -221,7 +221,7 @@ use ascii_dag::graph::{Graph, RenderMode};
|
||||
|
||||
// Compiled view: trivial — compile(), then one display node per flat node, one
|
||||
// edge per flat edge, each label from the boxed node itself.
|
||||
pub fn render_compilat(nodes: &[Box<dyn Node>], sources: &[SourceSpec],
|
||||
pub fn render_flat_graph(nodes: &[Box<dyn Node>], sources: &[SourceSpec],
|
||||
edges: &[Edge]) -> String {
|
||||
let labels: Vec<String> = /* source labels ++ nodes.iter().map(|n| n.label()) */;
|
||||
let mut g = Graph::with_mode(RenderMode::Vertical);
|
||||
@@ -236,7 +236,7 @@ pub fn render_compilat(nodes: &[Box<dyn Node>], sources: &[SourceSpec],
|
||||
// leaves render inside it; blueprint-level edges/source-targets resolve through
|
||||
// composite input-roles (fan) and output ports to interior display ids — the
|
||||
// same boundary resolution compile() performs, but emitting cluster-grouped
|
||||
// display nodes instead of a flat compilat.
|
||||
// display nodes instead of a flat graph.
|
||||
pub fn render_blueprint(bp: &Blueprint) -> String { /* … */ }
|
||||
```
|
||||
|
||||
@@ -252,7 +252,7 @@ match args.next().as_deref() {
|
||||
let bp = sample_blueprint();
|
||||
let out = if compiled {
|
||||
let (nodes, sources, edges) = bp.compile().expect("valid sample blueprint");
|
||||
graph::render_compilat(&nodes, &sources, &edges)
|
||||
graph::render_flat_graph(&nodes, &sources, &edges)
|
||||
} else {
|
||||
graph::render_blueprint(&bp)
|
||||
};
|
||||
@@ -296,7 +296,7 @@ fn swapped_sma_inputs_render_differently() {
|
||||
internal test call sites. No dependency added.
|
||||
- **aura-cli** (`Cargo.toml`, `src/main.rs`, new `src/graph.rs`): the
|
||||
`ascii-dag` dependency; `sample_blueprint()` (+ a swapped variant for the
|
||||
test); the `graph` module with `render_blueprint` / `render_compilat`; the
|
||||
test); the `graph` module with `render_blueprint` / `render_flat_graph`; the
|
||||
`graph` dispatch arm; the rendering tests.
|
||||
|
||||
## Data flow
|
||||
@@ -308,7 +308,7 @@ edges/source-targets through composite roles/output to interior display ids,
|
||||
labels each leaf via `node.label()` → `Graph::render()` → `println!` to stdout.
|
||||
|
||||
`aura graph --compiled` → `sample_blueprint()` → `bp.compile()` yields the flat
|
||||
`(nodes, sources, edges)` → `render_compilat(...)` assigns one display id per
|
||||
`(nodes, sources, edges)` → `render_flat_graph(...)` assigns one display id per
|
||||
source and per flat node, draws the flat edges, labels each `Box<dyn Node>` via
|
||||
`.label()` → `Graph::render()` → stdout. Composite boundaries are gone (C23):
|
||||
the cluster boxes of the blueprint view are absent, by design.
|
||||
@@ -365,7 +365,7 @@ commitment* — and is met:
|
||||
C1 determinism are untouched (`label()` is never read during a run); the C8
|
||||
node contract is *refined*, not broken (the addition is the non-load-bearing
|
||||
render symbol C23 already reserves and cites #13 for); composites still inline
|
||||
to a name-free index-wired compilat (C23 — the compiled view demonstrates it).
|
||||
to a name-free index-wired flat graph (C23 — the compiled view demonstrates it).
|
||||
|
||||
Issue #13's own acceptance checklist is satisfied: `ascii-dag` added as the
|
||||
rendering crate's dependency; a `graph → ascii_dag::Graph` adapter in Vertical
|
||||
|
||||
@@ -44,10 +44,10 @@ Two layers, both resting on machinery that already exists:
|
||||
the deterministic depth-first item order that `lower_items` (the inliner)
|
||||
already uses. **`compile`/`inline_composite` are not touched**: the param-space
|
||||
is a separate read-only projection of the blueprint (a further C9
|
||||
introspection, like `nodes()`), not a change to the flat compilat.
|
||||
introspection, like `nodes()`), not a change to the flat graph.
|
||||
|
||||
The **identity** of a param is **positional** — its slot index in the flat
|
||||
param-space — exactly as the compilat wires by raw index, not by name (C23). The
|
||||
param-space — exactly as the flat graph wires by raw index, not by name (C23). The
|
||||
name is a **non-load-bearing debug symbol**, path-qualified at aggregation time
|
||||
(`strategy.combine.weights[0]`) so a reader can trace a knob back to its node.
|
||||
|
||||
@@ -270,7 +270,7 @@ whose kind could mismatch (that check lands with the bind in #31).
|
||||
param-space; an empty blueprint yields an empty space.
|
||||
|
||||
Build/test/clippy green across the workspace; existing compile/bootstrap/run and
|
||||
render tests stay green (the compilat is unchanged — `compile`/`inline_composite`
|
||||
render tests stay green (the flat graph is unchanged — `compile`/`inline_composite`
|
||||
are not touched, so every existing bit-identical and golden-snapshot test is
|
||||
unaffected by construction).
|
||||
|
||||
@@ -292,7 +292,7 @@ applies, read against aura's domain invariants:
|
||||
Determinism (C1) holds — aggregation order is a pure structural function.
|
||||
Topology-invariance (C19) holds — a vector knob's arity `N` is topology-fixed
|
||||
(it equals the node's input arity), declared as `N` fixed entries, never a
|
||||
sweep param. The compilat is untouched (C23) — params are a read-only
|
||||
sweep param. The flat graph is untouched (C23) — params are a read-only
|
||||
projection, not a change to the wired graph; every existing bit-identical test
|
||||
stays green by construction.
|
||||
|
||||
@@ -300,7 +300,7 @@ applies, read against aura's domain invariants:
|
||||
|
||||
- **Param-set binding / injection (#31)** — binding an injected typed value-vector
|
||||
to the param-space slot-by-slot, with the kind-check that declaration defers.
|
||||
- **Sweep enumeration (#32)** — building a family of compilats over the
|
||||
- **Sweep enumeration (#32)** — building a family of flat graphs over the
|
||||
param-space.
|
||||
- **The run-supplied search-range (#32 / C20)** — which subset/grid a run sweeps
|
||||
lives in the experiment-builder, not in the node (the param declaration carries
|
||||
|
||||
@@ -302,7 +302,7 @@ not the node (C20, established at #30's close), and full domain validation is
|
||||
- **Bit-identity (the central proof).** `bootstrap_with_params(vec![I64(2),
|
||||
I64(4), F64(0.5)])` on the SMA-cross harness produces equity + exposure traces
|
||||
bit-identical to the hand-wired `sma_cross(2, 4)` graph — build-then-wire does
|
||||
not change the compilat for a given point. (Re-expresses
|
||||
not change the flat graph for a given point. (Re-expresses
|
||||
`composite_sma_cross_runs_bit_identical_to_hand_wired`.)
|
||||
- **Injection is observable.** A different vector (`[I64(5), I64(20), F64(1.0)]`)
|
||||
yields a different, populated trace from the same blueprint — distinct instances,
|
||||
|
||||
@@ -20,7 +20,7 @@ reused composite's body once, removes the current nested-composite `unimplemente
|
||||
and renders on ascii-dag's **flat** layout only — sidestepping the cluster-layout
|
||||
bug at the root.
|
||||
|
||||
The **compiled view** (`render_compilat`, flat fully-inlined, C23) is unchanged,
|
||||
The **compiled view** (`render_flat_graph`, flat fully-inlined, C23) is unchanged,
|
||||
byte-for-byte.
|
||||
|
||||
## Architecture
|
||||
@@ -30,10 +30,10 @@ Two ontological tiers map onto two render shapes:
|
||||
| View | What it shows | Mechanism |
|
||||
|------|---------------|-----------|
|
||||
| Blueprint (`render_blueprint`) | authored source: harness wiring + composites as named subroutines, each body rendered once | main flat graph (composite = opaque node) + a `where:` block of per-type definitions |
|
||||
| Compiled (`render_compilat`) | inlined machine form, boundaries dissolved (C23) | one flat graph (unchanged) |
|
||||
| Compiled (`render_flat_graph`) | inlined machine form, boundaries dissolved (C23) | one flat graph (unchanged) |
|
||||
|
||||
The redesign is **CLI-render-only**. No change to the engine, the Node/Blueprint
|
||||
data model, or `render_compilat`. The blueprint data model already carries
|
||||
data model, or `render_flat_graph`. The blueprint data model already carries
|
||||
everything needed (`Composite::name/nodes/edges/input_roles/output`,
|
||||
`Blueprint::nodes/sources/edges`).
|
||||
|
||||
@@ -47,7 +47,7 @@ everything needed (`Composite::name/nodes/edges/input_roles/output`,
|
||||
`Barycentric`/`BrandesKopf` are unimplemented stubs; `render()` takes no config).
|
||||
The **flat** layout reserves `width + 3` per node and is collision-free at all
|
||||
widths. The new model renders only flat graphs, so the bug cannot arise.
|
||||
2. **Scale.** The blueprint is authored structure, not the compilat. A composite
|
||||
2. **Scale.** The blueprint is authored structure, not the flat graph. A composite
|
||||
with 50 interior nodes is **one** node in the main graph; blueprint size tracks
|
||||
top-level wiring, not inlined node count. Real strategies stay displayable.
|
||||
3. **Render-once.** A composite reused N times appears N times as an opaque node in
|
||||
@@ -182,7 +182,7 @@ fn render_definition(c: &Composite) -> String {
|
||||
`where:` block. Uses only flat ascii-dag graphs.
|
||||
- **`render_flat(labels, edges) -> String`** (new internal helper, or inline). A
|
||||
thin wrapper over the existing flat-graph build (`Graph::with_mode(Vertical)`,
|
||||
`add_node`, `add_edge`, `render`) — exactly what `render_compilat` already does,
|
||||
`add_node`, `add_edge`, `render`) — exactly what `render_flat_graph` already does,
|
||||
with **no** `add_subgraph` / `put_nodes`.
|
||||
- **`collect_distinct_composites(bp) -> Vec<&Composite>`** (new). Walks top-level
|
||||
items and, recursively, composite interiors; returns distinct composites in
|
||||
@@ -191,7 +191,7 @@ fn render_definition(c: &Composite) -> String {
|
||||
- **`render_definition(c) -> String`** (new). One composite interior → flat graph
|
||||
with `[in:k]` / `[out]` port markers, prefixed `"<name>:\n"`.
|
||||
- **`ItemDisplay`**, **`producer_id`**, **`consumer_ids`** (simplified as above).
|
||||
- **`render_compilat`** — untouched.
|
||||
- **`render_flat_graph`** — untouched.
|
||||
|
||||
## Data flow
|
||||
|
||||
@@ -264,7 +264,7 @@ Unchanged and must stay green: `compiled_view_dissolves_the_composite_boundary`,
|
||||
- `aura graph` (no flag) prints the sample as a small main graph with `[sma_cross]`
|
||||
opaque, followed by a `where:` block defining `sma_cross` once, on a flat layout
|
||||
(no `╔═╗` subgraph boxes).
|
||||
- `aura graph --compiled` output is byte-identical to before (`render_compilat`
|
||||
- `aura graph --compiled` output is byte-identical to before (`render_flat_graph`
|
||||
untouched; its golden unchanged).
|
||||
- The `unimplemented!("nested-composite cluster rendering")` at `graph.rs:75` is
|
||||
gone; a one-level-nested composite renders.
|
||||
|
||||
@@ -50,9 +50,9 @@ boundary; it does not widen the node contract.
|
||||
base column; the record is a bundle of base columns, as today.
|
||||
- **C4** (one record per cycle) — unchanged. One `eval`, one row, K columns,
|
||||
co-fresh by construction.
|
||||
- **C23** (compilat wired by raw index; names are non-load-bearing debug
|
||||
- **C23** (flat graph wired by raw index; names are non-load-bearing debug
|
||||
symbols) — **honoured**: the re-export *names* live at the blueprint boundary
|
||||
only. The compilat lowering drops them and carries raw `(node, field)` indices,
|
||||
only. The flat graph lowering drops them and carries raw `(node, field)` indices,
|
||||
exactly as `FieldSpec.name` and `Composite.name` are dropped at inline today.
|
||||
|
||||
A strategy composite still outputs **one** exposure (C10/C7): it is simply a
|
||||
@@ -144,7 +144,7 @@ pub struct OutPort {
|
||||
/// One re-exported field of a composite's output record: an interior
|
||||
/// `(node, output-field)` surfaced at the boundary under `name`. `name` is a
|
||||
/// non-load-bearing render/debug symbol (C23) — like `FieldSpec.name` and
|
||||
/// `Composite.name`, it does not reach the compilat.
|
||||
/// `Composite.name`, it does not reach the flat graph.
|
||||
pub struct OutField {
|
||||
pub node: usize,
|
||||
pub field: usize,
|
||||
@@ -322,7 +322,7 @@ Authoring → compile → run is unchanged in shape; only the boundary arity wid
|
||||
3. **Edge rewrite (`rewrite_edge`):** a consumer edge reading the composite with
|
||||
`from_field = k` resolves to `output[k]` — the k-th re-exported flat
|
||||
`(node, field)`. Out-of-range `k` → `BadInteriorIndex`.
|
||||
4. **Bootstrap:** the flat compilat is unchanged in kind — ordinary
|
||||
4. **Bootstrap:** the flat graph is unchanged in kind — ordinary
|
||||
`(from_node, from_field) → (to_node, slot)` edges. Existing per-field
|
||||
kind-checks at bootstrap (`slot_kind`) apply to each re-exported field as they
|
||||
already do for any producer field. No new kind rule.
|
||||
@@ -349,7 +349,7 @@ Unit tests in `blueprint.rs` (alongside the existing compile tests):
|
||||
|
||||
1. **Multi-output happy path:** a composite re-exporting 2 interior fields; two
|
||||
downstream consumers read `from_field: 0` and `from_field: 1`; assert the
|
||||
compilat wires each consumer to the correct distinct flat `(node, field)`.
|
||||
flat graph wires each consumer to the correct distinct flat `(node, field)`.
|
||||
2. **Nested multi-output:** an outer composite re-exporting two fields of an
|
||||
**inner** multi-output composite (exercises the nested arm's
|
||||
`nested.get(field)`); assert correct flat resolution.
|
||||
@@ -383,7 +383,7 @@ preserving).
|
||||
record; the histogram remains reachable as one selected field.
|
||||
5. `aura graph` renders K `[out:<name>]` markers per multi-output composite.
|
||||
6. Single-field output records (every strategy composite, `sma_cross`) compile
|
||||
and run identically to today — C8 / C7 / C4 untouched; the compilat for an
|
||||
and run identically to today — C8 / C7 / C4 untouched; the flat graph for an
|
||||
unchanged blueprint is byte-identical.
|
||||
7. `cargo build --workspace`, `cargo test --workspace`, and
|
||||
`cargo clippy --workspace --all-targets -- -D warnings` are green.
|
||||
|
||||
@@ -56,13 +56,13 @@ Consequence, made explicit so the implementation cannot drift: a param's identit
|
||||
in `param_space()` stays its **slot** (position), never its name. Aliases relabel
|
||||
in place; they never reorder, add, or remove a slot. The existing invariant test
|
||||
`param_space_mirrors_compiled_flat_node_param_order` (slot order mirrors the flat
|
||||
compilat) therefore stays green unchanged — it is the C23 anchor for this cycle.
|
||||
flat graph) therefore stays green unchanged — it is the C23 anchor for this cycle.
|
||||
|
||||
### Invariant-neutrality
|
||||
|
||||
- **C23 honoured.** Names are non-load-bearing debug symbols dropped at lowering;
|
||||
identity is positional everywhere (param slot, role index, output field index).
|
||||
The compilat is byte-identical — `compiled_view_golden` is the regression guard,
|
||||
The flat graph is byte-identical — `compiled_view_golden` is the regression guard,
|
||||
exactly as #40 honoured it. The role/param/output *names* never reach a
|
||||
`Box<dyn Node>`.
|
||||
- **C8 / C7 / C4 untouched.** This is authoring-surface legibility only: no change
|
||||
@@ -369,7 +369,7 @@ Engine unit tests (`crates/aura-engine/src/blueprint.rs`):
|
||||
→ `param_space()` identical to today's path-qualified factory names.
|
||||
3. **Slot order invariant (C23 anchor).** `param_space_mirrors_compiled_flat_node_param_order`
|
||||
stays green unchanged — aliases relabel, never reorder; the slot still mirrors
|
||||
the flat compilat. (No new test; the existing one is the guard.)
|
||||
the flat graph. (No new test; the existing one is the guard.)
|
||||
4. **Out-of-range alias → `BadInteriorIndex`** at `compile_with_params`
|
||||
(alias `node`/`slot` past the interior leaf's params).
|
||||
5. **Partial aliasing.** A composite aliasing one of two slots → the aliased slot
|
||||
|
||||
@@ -55,7 +55,7 @@ labels — stale prose this cycle corrects.
|
||||
compile path, and the run are untouched. Files: `graph.rs` (`render_definition`),
|
||||
`main.rs` (render tests/goldens), `node.rs` (doc comment only).
|
||||
- **C23.** `compiled_view_golden` is byte-identical — only the blueprint-definition
|
||||
render changes; the compiled/flat view and the compilat are unaffected. Boundary
|
||||
render changes; the compiled/flat view and the flat graph are unaffected. Boundary
|
||||
names still never reach a `Box<dyn Node>`.
|
||||
- **C8/C7/C4 untouched** — authoring-surface legibility only. `aura run --macd`
|
||||
is deterministic and unchanged (render-only).
|
||||
|
||||
@@ -98,7 +98,7 @@ one composite share a name — uniqueness is at the slot". That stays true for
|
||||
(C12/C19/C23 untouched). This cycle adds a *separate* authoring well-formedness
|
||||
rule that bites only at fan-in nodes whose colliding sources have an unnamed
|
||||
configuration axis. C23 is not violated — the check runs during construction,
|
||||
before the type-erased compilat; runtime names stay non-load-bearing debug
|
||||
before the type-erased flat graph; runtime names stay non-load-bearing debug
|
||||
symbols. What changes is that a composite which was silently accepted (then
|
||||
rendered ambiguously) is now rejected at compile. This is a deliberate contract
|
||||
refinement, recorded in the ledger.
|
||||
@@ -341,7 +341,7 @@ Render (aura-cli):
|
||||
- **New focused render test**: per-node-call uniqueness, role-name passthrough
|
||||
(`#price`), the recursive descent (`[Sub(#SEf,#SEu)]`), and the interchangeable
|
||||
positional fallback (`[Join(#A,#B)]`-style).
|
||||
- **`compiled_view_golden`** (`main.rs:533`): byte-stable — compilat labels via
|
||||
- **`compiled_view_golden`** (`main.rs:533`): byte-stable — flat graph labels via
|
||||
`Box<dyn Node>::label()`, no fan-in stubs, no `#` identifier. C23 guard.
|
||||
|
||||
Fixture knock-on (the constraint-driven set):
|
||||
@@ -364,7 +364,7 @@ Per aura's feature-acceptance: a strategy author cannot accidentally ship a
|
||||
fan-in whose inputs differ in configuration but share a rendered identity — the
|
||||
engine rejects it at construction, where aura makes invariants structural;
|
||||
genuinely-interchangeable inputs stay legal; the graph view communicates input
|
||||
provenance correctly; no runtime/compilat behaviour changes (C1/C12/C19/C23
|
||||
provenance correctly; no runtime/flat graph behaviour changes (C1/C12/C19/C23
|
||||
intact).
|
||||
|
||||
- [ ] A composite with a fan-in node whose two sources have equal signatures and
|
||||
|
||||
@@ -33,7 +33,7 @@ interior nodes — histogram included. There is no case where an `OutField` warr
|
||||
a real extra node, so the fix is uniform: fold the name into the producer.
|
||||
|
||||
This is **pure render-layer legibility**, not a capability. `OutField.name` is a
|
||||
non-load-bearing render/debug symbol (C23) that never reaches the compilat; the
|
||||
non-load-bearing render/debug symbol (C23) that never reaches the flat graph; the
|
||||
engine, blueprint data model, and bootstrap are untouched. The implementation
|
||||
commit closes #46.
|
||||
|
||||
@@ -80,7 +80,7 @@ test asserts it verbatim.
|
||||
- **C23 honoured.** `OutField.name` stays a non-load-bearing render symbol dropped
|
||||
at lowering; output identity is the `(node, field)` position, which survives.
|
||||
The `:=` form changes only where the name is *printed*, never what it *is*. The
|
||||
compiled view (`render_compilat`) is name-free and byte-identical —
|
||||
compiled view (`render_flat_graph`) is name-free and byte-identical —
|
||||
`compiled_view_golden` is the regression guard, unchanged.
|
||||
- **C8 / C7 untouched.** No change to the runtime record shape, the four base
|
||||
scalars, or one-record-per-cycle. This is authoring-surface legibility only.
|
||||
@@ -244,7 +244,7 @@ The MACD author site (`fn macd` in `main.rs`) and every engine type are
|
||||
3. **Blueprint render** (`render_definition`): for each interior node, the output
|
||||
names re-exporting it are folded onto its label as a `:=` binding; no standalone
|
||||
output node is emitted. Input roles still render as entry nodes.
|
||||
4. **Compiled render** (`render_compilat`) is name-free and byte-identical
|
||||
4. **Compiled render** (`render_flat_graph`) is name-free and byte-identical
|
||||
(`compiled_view_golden`).
|
||||
|
||||
## Error handling
|
||||
|
||||
@@ -242,7 +242,7 @@ fn field_label(producer_outputs: usize, from_field: usize, name: Option<&str>) -
|
||||
label. Composite-opaque rendering retained.
|
||||
- `render_flat` / the `add_edge` call (`graph.rs:81-94`) — gains an optional
|
||||
per-edge label argument; used by `render_blueprint`, `render_definition`,
|
||||
and `render_compilat` alike (shared, so the label mechanism is single-owned).
|
||||
and `render_flat_graph` alike (shared, so the label mechanism is single-owned).
|
||||
- `leaf_label` — generalised (or paralleled by a top-level variant) to source
|
||||
param names from `LeafFactory::params()` when there is no `ParamAlias` list.
|
||||
- a `from_field` → name resolver using `Composite::output()` with an
|
||||
|
||||
@@ -63,10 +63,10 @@ a root role is a bound ingestion feed (C3). That filter is semantic, not
|
||||
cosmetic, and is the sole remaining distinction; the *rendering* of a role is now
|
||||
identical across levels.
|
||||
|
||||
**The compiled view is deliberately left as `[source:F64]`.** `render_compilat`
|
||||
**The compiled view is deliberately left as `[source:F64]`.** `render_flat_graph`
|
||||
(graph.rs:495) builds source labels from the flat `SourceSpec.kind` — post-inline
|
||||
the role *name* has dissolved (C23, names are non-load-bearing debug symbols that
|
||||
do not reach the compilat), so only the kind survives there. Thus `[price]`
|
||||
do not reach the flat graph), so only the kind survives there. Thus `[price]`
|
||||
pre-inline (name alive) and `[source:F64]` post-inline (name gone) is not an
|
||||
inconsistency — it is C23 made visible, and it is the negative control proving the
|
||||
change is confined to the structural blueprint view.
|
||||
@@ -165,7 +165,7 @@ slot stubs in both views (the "root has no context" carve-out is removed).
|
||||
- **`render_graph` / `leaf_label`** (graph.rs): `stub_ctx` becomes `&Composite`;
|
||||
the fan-in gate keys on `slots.len() > 1` alone.
|
||||
- **`render_definition`** (graph.rs): passes `c` instead of `Some(c)` (mechanical).
|
||||
- **`render_compilat`** (graph.rs): **unchanged** — keeps `source:{kind}` from the
|
||||
- **`render_flat_graph`** (graph.rs): **unchanged** — keeps `source:{kind}` from the
|
||||
flat `SourceSpec` (C23).
|
||||
- **`slot_source` / `fan_in_identifiers` / `signature_of`**: unchanged, reused
|
||||
verbatim.
|
||||
@@ -180,7 +180,7 @@ an edge-fed slot resolves through `signature_of(bp.nodes(), bp.edges(),
|
||||
bp.input_roles(), bp.params(), e.from)`; a role-fed slot returns the role name.
|
||||
The `where:` definitions still flow through `render_definition(c)` →
|
||||
`render_graph(…, stub_ctx = c)`, untouched and byte-stable. The compiled view
|
||||
flows through the independent `render_compilat`, untouched.
|
||||
flows through the independent `render_flat_graph`, untouched.
|
||||
|
||||
## Error handling
|
||||
|
||||
@@ -217,7 +217,7 @@ All affected tests live in `crates/aura-cli/src/main.rs`:
|
||||
(acceptance #1 for `--macd` + acceptance #2).
|
||||
|
||||
4. **`compiled_view_golden`** (~line 569): asserted **unchanged** — renders
|
||||
through `render_compilat`, a separate path that keeps `[source:F64]` (C23:
|
||||
through `render_flat_graph`, a separate path that keeps `[source:F64]` (C23:
|
||||
name dissolved post-inline) and `[SimBroker(0.0001)]`. The negative control.
|
||||
|
||||
5. **`nested_composite_renders_without_panic`** (~437) and
|
||||
|
||||
@@ -177,13 +177,13 @@ leaf `#45475a`, composite `#5b4b8a`, source `#2e5a3a`, sink `#5a2e3e`.
|
||||
### Implementation shape — before → after (secondary)
|
||||
|
||||
`crates/aura-cli/src/graph.rs` (the ascii-dag adapter, ~505 lines) is **retired**. Its
|
||||
public entry points (`render_blueprint`, `render_compilat`) and the `ascii-dag`
|
||||
public entry points (`render_blueprint`, `render_flat_graph`) and the `ascii-dag`
|
||||
dependency in `crates/aura-cli/Cargo.toml` are removed.
|
||||
|
||||
```rust
|
||||
// BEFORE — ascii-dag adapter (graph.rs), point-nodes + invented label notation:
|
||||
pub fn render_blueprint(bp: &Composite, color: Color) -> String { /* ascii_dag::Graph … */ }
|
||||
pub fn render_compilat(nodes: &[Box<dyn Node>], …) -> String { /* ascii_dag::Graph … */ }
|
||||
pub fn render_flat_graph(nodes: &[Box<dyn Node>], …) -> String { /* ascii_dag::Graph … */ }
|
||||
|
||||
// AFTER — a read-only model serializer (new module, e.g. graph_model.rs),
|
||||
// hand-rolled deterministic JSON in the RunReport::to_json house style (no serde):
|
||||
|
||||
@@ -258,7 +258,7 @@ contributes one `ParamSpec` per param slot, named
|
||||
prefix by its own name and recurses. Slot order and arity are **unchanged** from
|
||||
today (the mirror test against the compiled flat-node order stays green); only
|
||||
the per-knob *string* changes (it gains the node segment and, where a
|
||||
`ParamAlias` used to relabel, reverts to `<node>.<factory-param>`). The compilat
|
||||
`ParamAlias` used to relabel, reverts to `<node>.<factory-param>`). The flat graph
|
||||
remains name-free and wired by raw index (C23): node names are construction-time
|
||||
identity and debug symbols, dropped at lowering, exactly as alias names were.
|
||||
|
||||
|
||||
@@ -344,14 +344,14 @@ existing resolve → lower → bootstrap flow is unchanged.
|
||||
injectivity.
|
||||
- **C12/C19 (255–270).** The 0015-era line "same-type siblings in one composite
|
||||
share a name, uniqueness is at the slot" is now refined: identity in the
|
||||
**compilat** stays positional (C23, unchanged), but the `param_space()` **name
|
||||
**flat graph** stays positional (C23, unchanged), but the `param_space()` **name
|
||||
projection** — the authoring/by-name address space — must be **injective** for a
|
||||
blueprint to compile. The two layers are distinct: positional wiring below,
|
||||
injective name address space above.
|
||||
- **C23.** The injectivity check is part of bootstrap-as-compilation; node names
|
||||
stay non-load-bearing (dropped at lowering, compilat wired by raw index). The
|
||||
stay non-load-bearing (dropped at lowering, flat graph wired by raw index). The
|
||||
check reads the boundary name projection; it does not make names load-bearing in
|
||||
the compilat.
|
||||
the flat graph.
|
||||
|
||||
## Testing strategy
|
||||
|
||||
|
||||
@@ -59,10 +59,10 @@ closure-wrapping.
|
||||
against the node's declared `ParamSpec.name`. This follows the C23
|
||||
authoring-address-space convention as amended in cycle 0032
|
||||
(`check_param_namespace_injective`): the by-name *authoring* address space is
|
||||
injective, while the *compilat* stays wired by raw index (C23 unchanged). Name at
|
||||
the authoring surface, index in the compilat; `.bind()` sits on the authoring
|
||||
injective, while the *flat graph* stays wired by raw index (C23 unchanged). Name at
|
||||
the authoring surface, index in the flat graph; `.bind()` sits on the authoring
|
||||
side and resolves the name to a position immediately — the name is not persisted
|
||||
into the compilat, so C23's "names are non-load-bearing in the compilat" holds.
|
||||
into the flat graph, so C23's "names are non-load-bearing in the flat graph" holds.
|
||||
|
||||
`.bind()` is **not** the `builder_const(2)` per-node constructor the issue rejects
|
||||
(which "explodes combinatorially — which subset is constant?"): it is one method,
|
||||
@@ -227,7 +227,7 @@ Construction (unchanged): `Composite::param_space()` → `collect_params` iterat
|
||||
bound knob. `compile_with_params(params)` checks arity against the (shrunk)
|
||||
`param_space`, then `lower_items` slices `n = builder.params().len()` open values
|
||||
and calls `builder.build(open_slice)`; the wrapped closure reconstructs the full
|
||||
positional vector and delegates to the node constructor. The compilat is wired by
|
||||
positional vector and delegates to the node constructor. The flat graph is wired by
|
||||
raw index exactly as before (C23).
|
||||
|
||||
## Error handling
|
||||
@@ -307,6 +307,6 @@ currently-green test):
|
||||
`PrimitiveBuilder::bind`.
|
||||
- Chained and single binds reconstruct the correct positional argument vector for
|
||||
multi-param nodes (invariant test 3 green).
|
||||
- C23 holds: the compilat is still wired by raw index; bound param names are
|
||||
resolved to positions at authoring time and never reach the compilat.
|
||||
- C23 holds: the flat graph is still wired by raw index; bound param names are
|
||||
resolved to positions at authoring time and never reach the flat graph.
|
||||
- No new dependency (C16); no node registry or by-name runtime lookup (C9/C10).
|
||||
|
||||
@@ -59,7 +59,7 @@ the standalone HTML):
|
||||
`name: ` declaration prefix to the box head when a name is present.
|
||||
|
||||
**Invariant check.** The name is a render/debug symbol on the model surface
|
||||
only; it is **not** carried into the compilat (lowering drops it, exactly as
|
||||
only; it is **not** carried into the flat graph (lowering drops it, exactly as
|
||||
today — C23). The model gains a deterministic field sourced from an
|
||||
author-controlled identifier (C14: same input → same model bytes). No hot-path,
|
||||
determinism, or causality surface is touched. This is the same render/model-only
|
||||
@@ -294,7 +294,7 @@ cellLabel ── o.name present ⇒ prefix "fast: " + head "SMA" + sig "[lengt
|
||||
⇒ fast: SMA[length]
|
||||
```
|
||||
|
||||
The name is dropped at lowering (compilat wiring is by raw index, C23); it never
|
||||
The name is dropped at lowering (flat graph wiring is by raw index, C23); it never
|
||||
re-enters the engine — there is no runtime path here, only the render/model
|
||||
surface.
|
||||
|
||||
@@ -351,7 +351,7 @@ exported and headlessly drivable), the `named()`/`node_name()` tests above.
|
||||
- `cargo build --workspace`, `cargo test --workspace`, and
|
||||
`cargo clippy --workspace --all-targets -- -D warnings` are green; the
|
||||
`viewer_dot.rs`/`.mjs` guard passes.
|
||||
- C23 (name dropped at lowering, not in the compilat) and C14 (deterministic
|
||||
- C23 (name dropped at lowering, not in the flat graph) and C14 (deterministic
|
||||
model bytes) hold — verified by the unchanged lowering path and the
|
||||
re-captured goldens.
|
||||
- Out-of-scope items (collapsed-composite visibility, composite-box prefix, INFO
|
||||
|
||||
@@ -67,7 +67,7 @@ param-space")` is exactly that check). Every *unbound* param therefore forces a
|
||||
sweep axis. Binding `blend.weights[2]` removes it from the param-space, so it
|
||||
needs no axis — a bound param is a structural constant that drops out of the
|
||||
tuning surface (C23: `bind` resolves the param *name* to a fixed position; the
|
||||
compilat is unchanged).
|
||||
flat graph is unchanged).
|
||||
|
||||
**Blast radius.**
|
||||
|
||||
|
||||
@@ -475,7 +475,7 @@ render/debug surface only, never read by bootstrap or the run loop (C23).
|
||||
deterministic (C14). Unbound nodes' model bytes are unchanged.
|
||||
3. The bound slot remains absent from the tunable surface (`params()` /
|
||||
`param_space` / sweep axes) — `bind`'s tuning-side behaviour is unchanged
|
||||
(C12/C19), and the compilat is unchanged (C23: render/debug symbol only).
|
||||
(C12/C19), and the flat graph is unchanged (C23: render/debug symbol only).
|
||||
4. New unit tests pin the recorded original position and the conditional model
|
||||
field; a headless guard pins the dimmed `name=value` render and slot-order
|
||||
faithfulness (including a non-trailing bind). All existing goldens, viewer
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
Add an additive, fluent `GraphBuilder` that authors a blueprint's topology by
|
||||
**typed node handles** and **port names** instead of raw positional indices, and
|
||||
resolves them to the existing index-wired `Composite` at a single fallible
|
||||
terminal `build()`. The compilat stays wired by raw index (C23): name resolution
|
||||
terminal `build()`. The flat graph stays wired by raw index (C23): name resolution
|
||||
happens at the authoring boundary, the same posture param-name resolution already
|
||||
has (`Binder`/`with` → `bootstrap`, `crates/aura-engine/src/blueprint.rs:259,413`).
|
||||
|
||||
@@ -66,7 +66,7 @@ mistyped; only port/field names are strings, and they are resolved at `build()`.
|
||||
|
||||
From `build()` onward the pipeline is byte-for-byte today's: `validate_wiring` →
|
||||
`lower_items`/`inline_composite` → `rewrite_edge`/`resolve_target` → `FlatGraph`.
|
||||
The compilat never sees a name; the run loop (C1/C2) is untouched. Kind checks
|
||||
The flat graph never sees a name; the run loop (C1/C2) is untouched. Kind checks
|
||||
are **not** duplicated in the builder — a resolved edge that connects mismatched
|
||||
kinds still surfaces through the existing `validate_wiring` / bootstrap kind-check
|
||||
(name resolution is necessary, not sufficient; kinds remain the structural gate).
|
||||
@@ -270,7 +270,7 @@ representation is byte-identical to a hand-written `Composite::new`.
|
||||
BlueprintNode`, addressed by derived role/output names.
|
||||
- [ ] The raw-index `Composite::new` stays public and unchanged; all existing call
|
||||
sites compile and pass; both authoring forms interoperate.
|
||||
- [ ] The compilat is unchanged: no name reaches `FlatGraph`; `compile_with_params`
|
||||
- [ ] The flat graph is unchanged: no name reaches `FlatGraph`; `compile_with_params`
|
||||
/ `inline_composite` / `rewrite_edge` / `Harness::bootstrap` / the run loop
|
||||
are untouched. Determinism (C1) and no-look-ahead (C2) hold by construction.
|
||||
- [ ] `cargo build --workspace`, `cargo test --workspace`, and
|
||||
|
||||
@@ -23,7 +23,7 @@ run. Today an unwired input slot is bootstrapped with an empty column
|
||||
forgotten connection runs a deterministic but wrong backtest, and two producers
|
||||
into one slot is ill-formed (a slot holds exactly one column) yet uncompiled-
|
||||
against. A single new structural check at the existing compile boundary closes
|
||||
both, for both authoring surfaces, without touching the compilat (C23).
|
||||
both, for both authoring surfaces, without touching the flat graph (C23).
|
||||
|
||||
Non-goal (explicitly out of scope, dropped this cycle): promoting port/field/node
|
||||
names to load-bearing wiring keys; node-name or port/field-name uniqueness;
|
||||
@@ -216,7 +216,7 @@ pub enum CompileError {
|
||||
> concept**: every declared input port is required (no shipped node runs
|
||||
> meaningfully without one; an unwarmed mode-A input is *wired-but-not-yet-valued*,
|
||||
> not unwired). The check is **index-based and name-free** — it touches no name
|
||||
> machinery and emits nothing into the compilat, so C23 is untouched (it proves the
|
||||
> machinery and emits nothing into the flat graph, so C23 is untouched (it proves the
|
||||
> existing raw-index wiring is total and single-valued). Inherited identically by
|
||||
> the raw `Composite::new` path and the `GraphBuilder::build()` path (both compile
|
||||
> via `compile_with_params`).
|
||||
@@ -227,7 +227,7 @@ pub enum CompileError {
|
||||
→ [existing index/kind checks] → `check_ports_connected(nodes, edges, roles)` →
|
||||
[recurse per nested composite] → (on Ok) `UnboundRootRole` check → `lower_items`
|
||||
→ `FlatGraph`. The new check is a pure read over the same three slices
|
||||
`validate_wiring` already holds; it adds no data to the compilat and no work to the
|
||||
`validate_wiring` already holds; it adds no data to the flat graph and no work to the
|
||||
run loop.
|
||||
|
||||
## Error handling
|
||||
@@ -260,7 +260,7 @@ need all faults are out of scope (the existing variants are first-fault too).
|
||||
(`crates/aura-engine/src/test_fixtures.rs`) and the builder harness
|
||||
(`builder_harness_compiles_identically_to_hand_wired`) still compile green; the
|
||||
aura-cli sample / sweep / param_space / render tests stay green.
|
||||
6. **C23 regression — compilat byte-identical.** For any graph that still compiles,
|
||||
6. **C23 regression — flat graph byte-identical.** For any graph that still compiles,
|
||||
the lowered `FlatGraph` is unchanged (the existing identity test covers this; the
|
||||
check adds nothing to lowering).
|
||||
|
||||
@@ -329,7 +329,7 @@ slot is covered by its role target, and `UnboundRootRole` is checked after
|
||||
asserting their original deep-fault variant; and the param-order test
|
||||
(`param_space_mirrors_compiled_flat_node_param_order_under_nesting`) fully wired and
|
||||
still asserting its `param_space == compiled-flat-param-order` equality.
|
||||
- The full existing suite stays green (regression 5) and the compilat is
|
||||
- The full existing suite stays green (regression 5) and the flat graph is
|
||||
byte-identical for graphs that still compile (regression 6).
|
||||
- The C8 ledger realization note is landed.
|
||||
- `cargo test --workspace` green; `cargo clippy --workspace --all-targets -D
|
||||
|
||||
Reference in New Issue
Block a user