21c1621bd0
"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.
497 lines
23 KiB
Markdown
497 lines
23 KiB
Markdown
# Node-instance naming — Implementation Plan
|
|
|
|
> **Parent spec:** `docs/specs/0031-node-instance-naming.md`
|
|
>
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: use the `implement` skill to run
|
|
> this plan. Steps use `- [ ]` checkboxes for tracking.
|
|
|
|
**Goal:** Give every blueprint node a name (default = its lowercased type label),
|
|
make `param_space()` uniformly `<node>.<param>`, re-key fan-in distinguishability
|
|
onto the node name, and remove the index-addressed `ParamAlias` overlay.
|
|
|
|
**Architecture:** `PrimitiveBuilder` (aura-core) gains an instance-name slot
|
|
(`name: Option<String>`, `.named()`, `node_name()`). `blueprint.rs` (aura-engine)
|
|
inserts the node-name segment in `collect_params`, re-keys `signature_of` and the
|
|
fan-in predicate onto the node name, and drops `ParamAlias` / `Composite.params` /
|
|
the `Composite::new` 5th argument / `aliases_on` / `check_alias_indices`. Removing
|
|
the argument is a compile-coupled change, so every in-workspace `Composite::new`
|
|
caller and `ParamAlias` reference migrates in the same task; the `cargo build
|
|
--workspace` gate enumerates completeness.
|
|
|
|
**Tech Stack:** Rust. `crates/aura-core/src/node.rs`,
|
|
`crates/aura-engine/src/{blueprint.rs, lib.rs, graph_model.rs, sweep.rs}`,
|
|
`crates/aura-cli/src/main.rs`, `crates/aura-cli/tests/cli_run.rs`,
|
|
`docs/design/INDEX.md`.
|
|
|
|
---
|
|
|
|
**Files this plan creates or modifies:**
|
|
|
|
- Modify: `crates/aura-core/src/node.rs:77-116` — `PrimitiveBuilder` instance-name mechanism
|
|
- Test: `crates/aura-core/src/node.rs` (mod tests, ~:190) — `node_name()` default + override
|
|
- Modify: `crates/aura-engine/src/blueprint.rs` — `collect_params` (:688-730), `signature_of` (:546-590), `leaf_has_unaliased_param`→`leaf_has_param` (:674-686), `check_composite_fan_in` (:635-672), `check_fan_in_distinguishability` (:616-628), `Composite` struct (:137-144) + `Composite::new` (:151-160) + `params()` (:180-184) + `param_space()` call (:197); REMOVE `ParamAlias` (:121-130), `aliases_on` (:592-598), `check_alias_indices` (:600-614)
|
|
- Test: `crates/aura-engine/src/blueprint.rs` (mod tests) — new path-shape / default-name / forcing-function / paramless tests; update the mirror + `top_level` + `signature_of` tests; remove the alias-semantics tests
|
|
- Modify: `crates/aura-engine/src/lib.rs:41-42` — drop the `ParamAlias` / `aliases_on` / `signature_of` re-export of the retired overlay
|
|
- Modify: `crates/aura-engine/src/graph_model.rs` — `ParamAlias` import (:235) + `Composite::new` fixtures (:274,:302,:326,:344) + alias literals (:287-288): structural migration only
|
|
- Modify: `crates/aura-engine/src/sweep.rs` — `ParamAlias` import (:173) + `Composite::new` fixtures (:276,:306) + alias literals (:289-290): structural migration only
|
|
- Modify: `crates/aura-cli/src/main.rs` — `sma_cross` sample (:137-155), root harness (:170), EMA/MACD composite (:338,:382), sweep goldens (:537-540), `.axis()` block (:229-231), single-run `.with()` (:516-518), MACD param assertion (:597-599), `ParamAlias` import (:14)
|
|
- Modify: `crates/aura-cli/tests/cli_run.rs:214` — the sweep-golden twin (lockstep with main.rs:537-540)
|
|
- Modify: `docs/design/INDEX.md` — amend C9 (:367-375) and C23 (:359-366, :813-851)
|
|
|
|
**Out of scope (do NOT touch):** `crates/aura-cli/tests/fixtures/sample-model.json`
|
|
and the `model_to_json` golden at `graph_model.rs:430` — `model_to_json` emits the
|
|
**type** label (`b.label()` → `"SMA"`) and factory param names (`"length"`), which
|
|
are alias-independent and node-name-independent; this cycle does not change the JSON
|
|
model surface, so those goldens stay byte-identical. The `fieldtests/` crates are
|
|
frozen non-workspace records — not built or gated by `cargo --workspace`.
|
|
|
|
---
|
|
|
|
## Task 1: `PrimitiveBuilder` instance-name mechanism (aura-core)
|
|
|
|
Additive — no existing call site breaks (`PrimitiveBuilder::new` keeps its
|
|
signature; the new field defaults internally).
|
|
|
|
**Files:**
|
|
- Modify: `crates/aura-core/src/node.rs:77-116`
|
|
- Test: `crates/aura-core/src/node.rs` (mod tests)
|
|
|
|
- [ ] **Step 1: Write the failing test**
|
|
|
|
Add to the `mod tests` block in `crates/aura-core/src/node.rs` (near the existing
|
|
`primitive_builder_label_is_the_bare_type` at ~:196):
|
|
|
|
```rust
|
|
#[test]
|
|
fn node_name_defaults_to_lowercased_type_label() {
|
|
// unnamed → the type label, ASCII-lowercased verbatim (no snake_case)
|
|
let unnamed = PrimitiveBuilder::new(
|
|
"SimBroker",
|
|
NodeSchema::default(),
|
|
|_| panic!("not built in this test"),
|
|
);
|
|
assert_eq!(unnamed.node_name(), "simbroker");
|
|
|
|
// explicit name overrides
|
|
let named = PrimitiveBuilder::new(
|
|
"SMA",
|
|
NodeSchema::default(),
|
|
|_| panic!("not built in this test"),
|
|
)
|
|
.named("fast");
|
|
assert_eq!(named.node_name(), "fast");
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: Run test to verify it fails**
|
|
|
|
Run: `cargo test -p aura-core node_name_defaults_to_lowercased_type_label`
|
|
Expected: compile error / FAIL — no method `node_name` / `named` on `PrimitiveBuilder`.
|
|
|
|
- [ ] **Step 3: Write minimal implementation**
|
|
|
|
In `crates/aura-core/src/node.rs`, add a `name: Option<String>` field to
|
|
`PrimitiveBuilder` (struct at :77-84), initialise it in `new` (:90-96), and add
|
|
the two methods. Concretely:
|
|
|
|
Struct — add the field:
|
|
```rust
|
|
pub struct PrimitiveBuilder {
|
|
name: &'static str, // existing: the type label
|
|
instance_name: Option<String>, // NEW: the optional instance name
|
|
schema: NodeSchema,
|
|
build: Box<dyn Fn(&[Scalar]) -> Box<dyn Node>>,
|
|
}
|
|
```
|
|
|
|
`new` — initialise the new field (`instance_name: None`):
|
|
```rust
|
|
pub fn new(
|
|
name: &'static str,
|
|
schema: NodeSchema,
|
|
build: impl Fn(&[Scalar]) -> Box<dyn Node> + 'static,
|
|
) -> Self {
|
|
Self { name, instance_name: None, schema, build: Box::new(build) }
|
|
}
|
|
```
|
|
|
|
Add the two methods (near `label()` at :113):
|
|
```rust
|
|
/// Set this node instance's name. Must be non-empty.
|
|
pub fn named(mut self, name: &str) -> Self {
|
|
debug_assert!(!name.is_empty(), "node name must be non-empty");
|
|
self.instance_name = Some(name.to_string());
|
|
self
|
|
}
|
|
|
|
/// The resolved node name: the explicit instance name if set, else the
|
|
/// type label ASCII-lowercased verbatim (e.g. "SimBroker" -> "simbroker").
|
|
pub fn node_name(&self) -> String {
|
|
self.instance_name
|
|
.clone()
|
|
.unwrap_or_else(|| self.name.to_ascii_lowercase())
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 4: Run test to verify it passes**
|
|
|
|
Run: `cargo test -p aura-core node_name_defaults_to_lowercased_type_label`
|
|
Expected: PASS.
|
|
|
|
- [ ] **Step 5: Build the crate (additive, no caller breakage)**
|
|
|
|
Run: `cargo build -p aura-core`
|
|
Expected: 0 errors (the new field is internal; `new` still takes 3 args).
|
|
|
|
---
|
|
|
|
## Task 2: Engine mechanism, overlay removal, and the full compile-coupled migration (aura-engine + aura-cli)
|
|
|
|
This is one task by necessity: dropping the `Composite::new` 5th argument and the
|
|
`ParamAlias` struct breaks every caller at once, so all callers + the struct
|
|
removal + the dependent test-string updates land together under one
|
|
`cargo build/test --workspace` gate (planner self-review #7).
|
|
|
|
**Files:** `crates/aura-engine/src/blueprint.rs`, `lib.rs`, `graph_model.rs`,
|
|
`sweep.rs`; `crates/aura-cli/src/main.rs`, `crates/aura-cli/tests/cli_run.rs`.
|
|
|
|
- [ ] **Step 1: Write/replace the executable-spec tests (the RED side)**
|
|
|
|
In `crates/aura-engine/src/blueprint.rs` `mod tests`, add the new behaviour tests.
|
|
These assert the post-change strings, so they fail (or do not compile) until the
|
|
logic + signature land in Steps 2-7. Use named SMAs and the **new** 5-arg
|
|
`Composite::new` (no `params` arg):
|
|
|
|
```rust
|
|
#[test]
|
|
fn named_siblings_path_qualify_with_node_segment() {
|
|
use aura_std::{Sma, Sub};
|
|
// two SMAs, named fast/slow, feeding a Sub, under composite "sma_cross"
|
|
let cross = Composite::new(
|
|
"sma_cross",
|
|
vec![
|
|
Sma::builder().named("fast").into(),
|
|
Sma::builder().named("slow").into(),
|
|
Sub::builder().into(),
|
|
],
|
|
vec![
|
|
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
|
|
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
|
|
],
|
|
vec![Role {
|
|
name: "price".into(),
|
|
targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }],
|
|
source: None,
|
|
}],
|
|
vec![OutField { node: 2, field: 0, name: "cross".into() }],
|
|
);
|
|
let names: Vec<String> = cross.param_space().into_iter().map(|p| p.name).collect();
|
|
assert_eq!(names, ["sma_cross.fast.length", "sma_cross.slow.length"]);
|
|
}
|
|
|
|
#[test]
|
|
fn unnamed_single_primitive_uses_lowercased_type_label_segment() {
|
|
use aura_std::Sma;
|
|
let bp = Composite::new(
|
|
"root",
|
|
vec![Sma::builder().into()],
|
|
vec![],
|
|
vec![],
|
|
vec![],
|
|
);
|
|
assert_eq!(bp.param_space()[0].name, "sma.length");
|
|
}
|
|
|
|
#[test]
|
|
fn unnamed_same_type_param_bearing_fan_in_is_rejected() {
|
|
use aura_std::{Sma, Sub};
|
|
let bp = Composite::new(
|
|
"sma_cross",
|
|
vec![Sma::builder().into(), Sma::builder().into(), Sub::builder().into()],
|
|
vec![
|
|
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
|
|
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
|
|
],
|
|
vec![Role {
|
|
name: "price".into(),
|
|
targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }],
|
|
source: None,
|
|
}],
|
|
vec![OutField { node: 2, field: 0, name: "cross".into() }],
|
|
);
|
|
// both SMAs default to "sma" → collide → fan-in indistinguishable
|
|
assert_eq!(bp.compile().err(), Some(CompileError::IndistinguishableFanIn { node: 2 }));
|
|
}
|
|
|
|
#[test]
|
|
fn named_param_bearing_fan_in_bootstraps() {
|
|
use aura_std::{Sma, Sub};
|
|
let bp = Composite::new(
|
|
"sma_cross",
|
|
vec![
|
|
Sma::builder().named("fast").into(),
|
|
Sma::builder().named("slow").into(),
|
|
Sub::builder().into(),
|
|
],
|
|
vec![
|
|
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
|
|
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
|
|
],
|
|
vec![Role {
|
|
name: "price".into(),
|
|
targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }],
|
|
source: None,
|
|
}],
|
|
vec![OutField { node: 2, field: 0, name: "cross".into() }],
|
|
);
|
|
// distinct node names → fan-in distinguishable → compiles
|
|
assert!(bp.compile().is_ok());
|
|
}
|
|
```
|
|
|
|
Keep `interchangeable_fan_in_allowed` (:1561) — two **paramless** same-type
|
|
siblings stay legal; after migration its fixture's `Composite::new` loses the
|
|
5th arg but the assertion (compiles OK) is unchanged.
|
|
|
|
- [ ] **Step 2: Run the new tests to verify they fail**
|
|
|
|
Run: `cargo test -p aura-engine named_siblings_path_qualify_with_node_segment`
|
|
Expected: FAIL — either a compile error (5-arg `Composite::new` not yet in
|
|
effect) or an assertion mismatch (`sma_cross.length` vs `sma_cross.fast.length`).
|
|
|
|
- [ ] **Step 3: Rewrite `collect_params` to insert the node segment uniformly**
|
|
|
|
Replace `collect_params` (:688-730) with the node-segment form (drop the
|
|
`aliases` parameter; a primitive contributes `<prefix>.<node-name>.<param>`):
|
|
|
|
```rust
|
|
fn collect_params(items: &[BlueprintNode], prefix: &str, out: &mut Vec<ParamSpec>) {
|
|
for item in items {
|
|
match item {
|
|
BlueprintNode::Primitive(b) => {
|
|
let node = if prefix.is_empty() {
|
|
b.node_name()
|
|
} else {
|
|
format!("{prefix}.{}", b.node_name())
|
|
};
|
|
for p in b.params() {
|
|
out.push(ParamSpec { name: format!("{node}.{}", p.name), kind: p.kind });
|
|
}
|
|
}
|
|
BlueprintNode::Composite(c) => {
|
|
let child = if prefix.is_empty() {
|
|
c.name().to_string()
|
|
} else {
|
|
format!("{prefix}.{}", c.name())
|
|
};
|
|
collect_params(c.nodes(), &child, out);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Update the `param_space()` call site (:197) to drop `&self.params`:
|
|
```rust
|
|
collect_params(&self.nodes, "", &mut out);
|
|
```
|
|
|
|
- [ ] **Step 4: Re-key `signature_of` and the fan-in predicate onto the node name**
|
|
|
|
`signature_of` (:546-590): drop the `aliases: &[ParamAlias]` parameter and the
|
|
`aliases_on` loop (:559-563); the per-node component becomes the full node name
|
|
(so two `"sma"` collide, `"fast"`/`"slow"` differ). Keep the `-> String` return.
|
|
Replace the primitive arm's initial-building with the node name:
|
|
|
|
```rust
|
|
pub fn signature_of(nodes: &[BlueprintNode], edges: &[Edge], roles: &[Role], node: usize) -> String {
|
|
let mut sig = match &nodes[node] {
|
|
BlueprintNode::Primitive(b) => b.node_name(), // was: type initial + alias initials
|
|
BlueprintNode::Composite(c) => c.name().to_string(),
|
|
};
|
|
// recurse over inputs exactly as today (edges feeding `node`), appending each
|
|
// input's signature_of(...) in slot order:
|
|
for e in inputs_of(edges, node) { // same input-gathering as today
|
|
sig.push_str(&signature_of(nodes, edges, roles, e.from));
|
|
}
|
|
sig
|
|
}
|
|
```
|
|
(Match the existing recursion shape at :559-590; only the per-node head and the
|
|
removed `aliases` param change.)
|
|
|
|
`leaf_has_unaliased_param` (:674-686) → `leaf_has_param`: drop the `aliases` arg
|
|
and the `aliased` subtraction (:681-682); it is now true iff the leaf node has ≥1
|
|
param:
|
|
```rust
|
|
fn leaf_has_param(nodes: &[BlueprintNode], node: usize) -> bool {
|
|
matches!(&nodes[node], BlueprintNode::Primitive(b) if !b.params().is_empty())
|
|
}
|
|
```
|
|
|
|
`check_composite_fan_in` (:635-672): drop the `param_aliases` parameter; remove
|
|
the `check_alias_indices` call (:644); update the two helper calls (:651-652):
|
|
```rust
|
|
signature_of(nodes, edges, input_roles, e.from),
|
|
leaf_has_param(nodes, e.from),
|
|
```
|
|
`check_fan_in_distinguishability` (:616-628): drop `c.params()` from the
|
|
`check_composite_fan_in(...)` call (:623).
|
|
|
|
The `IndistinguishableFanIn { node }` construction (:666) is unchanged.
|
|
|
|
- [ ] **Step 5: Remove the overlay (struct, field, arg, helpers, alias tests)**
|
|
|
|
- Delete `pub struct ParamAlias { … }` (:121-130).
|
|
- Delete the `params: Vec<ParamAlias>` field from `Composite` (:142) and the
|
|
`pub fn params(&self) -> &[ParamAlias]` accessor (:180-184).
|
|
- Change `Composite::new` (:151-160) to a 5-arg signature (drop `params`):
|
|
```rust
|
|
pub fn new(
|
|
name: impl Into<String>,
|
|
nodes: Vec<BlueprintNode>,
|
|
edges: Vec<Edge>,
|
|
input_roles: Vec<Role>,
|
|
output: Vec<OutField>,
|
|
) -> Self {
|
|
Self { name: name.into(), nodes, edges, input_roles, output }
|
|
}
|
|
```
|
|
- Delete `aliases_on` (:592-598) and `check_alias_indices` (:600-614). Keep the
|
|
`CompileError::BadInteriorIndex` variant (:458) — it is still used by the other
|
|
index checks (:498-515, :872-914); only the dangling-alias path that produced it
|
|
is gone.
|
|
- Delete the alias-semantics tests: `param_alias_relabels_param_space_name_in_place`
|
|
(:1991-2022), `partial_aliasing_relabels_only_the_named_slot` (:2087-2113),
|
|
`out_of_range_param_alias_rejected` (:2024-2057), `unaliased_params_keep_factory_names`
|
|
(:2059-…). Their behaviour no longer exists.
|
|
- Amend the alias-overlay comment at :803-810 to describe node-name qualification.
|
|
|
|
- [ ] **Step 6: Update the engine `lib.rs` re-export**
|
|
|
|
In `crates/aura-engine/src/lib.rs:41-42`, remove `ParamAlias` (and `aliases_on`
|
|
if re-exported) from the `pub use blueprint::{…}` list. Keep `signature_of`,
|
|
`Composite`, `Role`, `OutField`, `BindError`, etc. (Quote: drop exactly the
|
|
`ParamAlias`/`aliases_on` identifiers from the brace list.)
|
|
|
|
- [ ] **Step 7: Mechanically migrate every in-workspace `Composite::new` call site + `ParamAlias` reference**
|
|
|
|
Drop the 5th (`params`) argument from **every** `Composite::new(...)` call, and
|
|
remove every `ParamAlias { … }` literal / import, across the workspace. The
|
|
recon hand-list (advisory; the compile gate is authoritative):
|
|
- `crates/aura-engine/src/blueprint.rs` tests: the ~46 `Composite::new` call
|
|
sites enumerated by recon (e.g. :1273, :1301, …, :2363) lose their 5th arg;
|
|
the alias literals at :1312-1313, :1759-1760, :2006-2007, :2037, :2100,
|
|
:2192-2193, :2319-2321 are removed (or replaced with `.named(...)` on the
|
|
relevant builder where a same-type param-bearing fan-in fixture would otherwise
|
|
become `IndistinguishableFanIn`).
|
|
- `crates/aura-engine/src/graph_model.rs`: import (:235), `Composite::new`
|
|
fixtures (:274,:302,:326,:344), alias literals (:287-288) — drop the arg; where
|
|
a fixture fans in two same-type param-bearing leaves, add `.named("a")`/`.named("b")`
|
|
so it still compiles. **Do not** change the expected JSON golden at :430 (it
|
|
pins `"type":"SMA"` + `["length","i64"]`, which `model_to_json` still emits).
|
|
- `crates/aura-engine/src/sweep.rs`: import (:173), fixtures (:276,:306), alias
|
|
literals (:289-290) — same treatment.
|
|
- `crates/aura-cli/src/main.rs`: import (:14) removed; `sma_cross` (:137-155) —
|
|
the two `ParamAlias{name:"fast"/"slow"}` (:150-151) become `.named("fast")` /
|
|
`.named("slow")` on the two `Sma::builder()` (:140-ish) and the `params` arg is
|
|
dropped; root harness (:170) drops its `vec![]` params arg; EMA/MACD composite
|
|
(:338,:382) — its EMA-leg aliases (:363-365) become `.named(...)` on the EMA
|
|
builders, params arg dropped.
|
|
|
|
- [ ] **Step 8: Update the path-string assertions in the engine tests**
|
|
|
|
- `param_space_mirrors_compiled_flat_node_param_order` (:1958, assertion
|
|
:1981-1984): the fixture's two SMAs become `.named("fast")`/`.named("slow")`,
|
|
the Exposure node stays default-named; the expected vector changes from
|
|
`["sma_cross.fast", "sma_cross.slow", "scale"]` to
|
|
`["sma_cross.fast.length", "sma_cross.slow.length", "exposure.scale"]`. The
|
|
**kind-by-slot** part of the assertion (the load-bearing arity/order invariant)
|
|
is unchanged.
|
|
- `param_space_mirrors_compiled_flat_node_param_order_under_nesting` (:2177,
|
|
assertion :2236-2239): name the fixture's SMAs; the kind-only assertion stays;
|
|
any old alias literals (:2192-2193) are removed.
|
|
- `param_space_is_flat_path_qualified_and_slot_disambiguated` (:2116, assertion
|
|
:2152-2160): name the two SMAs; the expected strings gain the node segment
|
|
(e.g. `strategy.fast_slow.fast.length` / `…slow.length` per the chosen fixture
|
|
names).
|
|
- `top_level_leaf_params_are_unqualified` (:2243-2256): **invert** the pin — the
|
|
assertion at :2255 becomes `assert_eq!(space[0].name, "sma.length")` (root node
|
|
now carries its name segment). Rename the test to
|
|
`top_level_leaf_params_carry_the_node_segment` to reflect the inverted intent.
|
|
- `signature_of_is_type_initial_plus_aliases_plus_recursive_inputs` (:1289-1297)
|
|
+ `macd_like_signature_fixture` (:1299-1317): rename to
|
|
`signature_of_is_node_name_plus_recursive_inputs`; the fixture's EMA builders
|
|
are default-named (`"ema"`) or `.named(...)`; the expected signature strings
|
|
(:1294, :1296) are recomputed from the node-name head (no longer `"Efp"` /
|
|
`"SEfpEsp"`). Compute the new expected strings from the rewritten `signature_of`
|
|
and pin them exactly.
|
|
- `indistinguishable_fan_in_rejected` (:1531-1559): stays green
|
|
(`IndistinguishableFanIn { node: 2 }`); update the fixture comment (:1533-1534)
|
|
from "unaliased" to "both default to `sma`". (This test overlaps
|
|
`unnamed_same_type_param_bearing_fan_in_is_rejected` from Step 1 — keep both or
|
|
fold into one; do not leave a duplicate name.)
|
|
|
|
- [ ] **Step 9: Migrate the CLI sweep goldens (both files, lockstep)**
|
|
|
|
- `crates/aura-cli/src/main.rs`: the `.axis(...)` block (:229-231) →
|
|
`.axis("sma_cross.fast.length", …).axis("sma_cross.slow.length", …).axis("exposure.scale", …)`;
|
|
the single-run `.with(...)` block (:516-518) → the same three names; the sweep
|
|
golden assertions (:537-540) → `"params":{"sma_cross.fast.length":N,"sma_cross.slow.length":N,"exposure.scale":0.5}`;
|
|
the MACD param assertion (:597-599) gains the node segments for its EMA knobs +
|
|
`exposure.scale`.
|
|
- `crates/aura-cli/tests/cli_run.rs:214`: the **twin** golden — replace
|
|
`"params":{"sma_cross.fast":2,"sma_cross.slow":4,"scale":0.5}` with
|
|
`"params":{"sma_cross.fast.length":2,"sma_cross.slow.length":4,"exposure.scale":0.5}`.
|
|
Keep the substring contiguous on one line (self-review #6).
|
|
|
|
- [ ] **Step 10: Workspace build + test + clippy gate (the completeness enumerator)**
|
|
|
|
Run: `cargo build --workspace`
|
|
Expected: 0 errors. (Any remaining un-migrated `Composite::new` caller or
|
|
`ParamAlias` reference surfaces here — fix it, re-run, until 0 errors. This gate
|
|
is the authoritative completeness check for the compile-coupled migration.)
|
|
|
|
Run: `cargo test --workspace`
|
|
Expected: PASS — all new tests green, the mirror/top_level/signature tests green
|
|
with their updated strings, the CLI goldens green with the migrated names, the
|
|
`model_to_json` goldens green **unchanged**.
|
|
|
|
Run: `cargo clippy --workspace --all-targets -- -D warnings`
|
|
Expected: 0 warnings.
|
|
|
|
---
|
|
|
|
## Task 3: Amend the design ledger (C9, C23)
|
|
|
|
Doc-only; no compile coupling.
|
|
|
|
**Files:** `docs/design/INDEX.md`
|
|
|
|
- [ ] **Step 1: Amend C9 (fan-in distinguishability)**
|
|
|
|
In `docs/design/INDEX.md`, the C9 fan-in refinement paragraph (:367-375): replace
|
|
the rationale that keys distinguishability on "equal recursive signatures (type
|
|
initial + alias initials + …)" and fires "when at least one colliding source
|
|
carries an **unaliased param slot**" with the node-name keying: colliding sources
|
|
are those with equal recursive **node-name** signatures; the collision is
|
|
`IndistinguishableFanIn` when at least one carries a **param** (a param-bearing
|
|
same-name collision), resolved by giving the colliding nodes distinct names.
|
|
Paramless interchangeable same-name sources stay legal.
|
|
|
|
- [ ] **Step 2: Amend C23 (named boundary projections)**
|
|
|
|
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 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.
|
|
|
|
- [ ] **Step 3: Verify the ledger references no retired symbol**
|
|
|
|
Run: `grep -nE "ParamAlias|unaliased|aliases_on|check_alias_indices" docs/design/INDEX.md`
|
|
Expected: no remaining references to the retired overlay (or only historical
|
|
"was retired in cycle 0031" notes if added deliberately).
|