cdb6313ee8be0b6f0ed36d1342ac7ea6b9d18179
147 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cdb6313ee8 |
spec: 0026 graph render redesign
Replace the ascii-dag aura graph view with a homogeneous pin-graph: aura emits a deterministic JSON model (hand-rolled, RunReport::to_json house style, no serde); a vendored viewer JS (genDot, ported from the prototype) turns it into DOT; Graphviz-WASM lays out + draws it in the browser. aura stays a read-only serializer (C9), ships no layout engine. The golden-tested contract is the JSON model. Iteration 1: the model serializer + golden/determinism/read-only tests. Iteration 2: viewer + WASM vendoring + self-contained HTML, retire ascii-dag. Grounding-check PASS; design ratified interactively against the 0026 prototype. |
||
|
|
7f485bbe72 |
docs(design): graph-render redesign prototype
Interactive, throwaway prototype of the aura graph render redesign — the visual language ratified for cycle 0026, replacing the ascii-dag text view. Homogeneous pin-nodes (body + n input pins + m output pins) rendered via Graphviz-WASM in the browser; pin-to-pin edges, type-as-colour, drill-down + inline-expand of composites, per-element styled tooltips, source/sink colouring, top-rank input ordering. index.html is the artifact; the ~1.4 MB WASM dep is git-ignored and restored by fetch-deps.sh. Visual companion to docs/specs/0026. |
||
|
|
63af2d1095 |
audit: cycle 0025 (#49) — drift-clean; root renders like any composite
Architect drift review (d6f59d7..12b1bce): NO code drift, no contract weakened,
no ledger edit needed.
- C9 (read-only render): the change touches only label/entry assembly
(render_blueprint, leaf_label, render_graph signature); no eval, no run-path
code. 150 tests green (same count), clippy clean, build green.
- C12 ("mis-wiring visible before a run"): realized at the root, not overstated —
a top-level fan-in's wiring was invisible (bare [SimBroker]); it now surfaces
which producer feeds which slot ([SimBroker(#E,#price)]). The C8 label-render
refinement (INDEX.md:250, "label() surfaces a mis-wiring") is extended to the
root, not contradicted.
- C23 (names dissolve post-inline): render_compilat byte-untouched (still emits
source:{kind} from SourceSpec.kind); the [price] pre-inline / [source:F64]
post-inline split now renders C23's boundary-dissolution visibly, with
compiled_view_golden as the negative control.
- C3 (sources bind at ingestion only): root entries filtered to source.is_some()
bound roles — the one semantic root-vs-interior distinction, correctly retained.
- #49 acceptance: the Option<&Composite> drop unifies both render_graph callers
onto one stub path; no dead arm, no second/root-only stub function, no scope
creep beyond graph.rs (production) + main.rs (test-only goldens/assertions).
No ledger prose names the root source:{kind} marker as canonical; the C9
cycle-0017 realization (where: definitions render) is not stale. No new invariant
introduced — the cycle realizes existing contracts more fully, so no realization
note is manufactured.
Regression: none configured in the profile (no-op) — the architect review is the
gate. Resolution: carry-on (drift-clean). NOT a milestone close.
Tracker reconciliation done this cycle (no code, orchestrator-applied):
- #36 closed — 0024 resolved it (params declared once on the recipe; the 8
lockstep tests deleted), but Gitea's `closes #43 #36` only auto-closed #43.
- #25 closed — 0024 removed the dyn Node::schema() re-call + bootstrap-derivation
duplication this issue named (signatures gathered once into FlatGraph).
- #24 retitled to derive_signature()/signature() — the panic-vs-typed-error
divergence persists under 0024's renamed symbols; still open, low-priority.
|
||
|
|
12b1bcec22 |
feat(aura-cli): render the root composite like any other composite
Close #49 and remove the last two render special-cases the blueprint root still carried, both pre-0024 vestiges. Since cycle 0024 the root is an ordinary Composite with input_roles, so the render no longer needs to treat it apart: (A) Fan-in slot stubs at the root. A composite-interior multi-input leaf already renders its wired slots as #… stubs; a top-level leaf did not, because render_blueprint threaded stub_ctx: None. It now passes the root composite (it IS a &Composite, carrying roles + edges), and stub_ctx drops its Option — both render_graph callers pass &Composite. The existing slot_source/ fan_in_identifiers/signature_of serve a top-level leaf verbatim; no second stub path (#49 acceptance). SimBroker now renders [SimBroker(#E,#price)] (#E = the Exposure producer's sibling-unique signature prefix, #price = the price source role name). (B) Role-named root entries. render_blueprint built entry markers from format!("source:{kind}") while render_definition uses role.name — the marker/stub asymmetry. The root now builds entries from role.name (filtered to bound roles, source.is_some()), identical to the interior, so the source marker reads [price] and matches the #price slot stub it feeds. render_compilat is deliberately untouched: post-inline the role name has dissolved (C23), so the compiled view keeps [source:F64] from the flat SourceSpec.kind — [price] pre-inline / [source:F64] post-inline is C23 made visible, and compiled_view_golden is the byte-unchanged negative control. Design call (orchestrator, with the user): the marker/stub asymmetry was fixed at its source (the entry naming) rather than by special-casing the stub to match the kind-named marker — the latter would have been a root-only stub behaviour, violating the "no second stub path" acceptance. The user chose full symmetry ([price], dropping the kind annotation) over a name+kind marker, prioritising structural cleanliness; the only remaining root-vs-interior distinction is the bound-role filter (C3), which is semantic, not cosmetic. Scope: crates/aura-cli/src/graph.rs only; read-only render (C9), behaviour-preserving for the run path (C1), no engine change. blueprint_view_golden re-captured from the live `aura graph` output (the where: section stays byte-identical — only the main graph re-flows); the SimBroker needle, a root-SimBroker-stub assertion on the macd view, and a [src] role-name-passthrough assertion are added. Verification (orchestrator-run, not agent-reported): cargo build --workspace green; cargo test --workspace 150 passed / 0 failed (same count, no run-path test moved); cargo clippy --workspace --all-targets -D warnings clean. compiled_view_golden and render_compilat byte-untouched. closes #49 |
||
|
|
cd569aa6d0 |
plan: 0025 render root like any composite
Two-task plan for spec 0025 (#49). Task 1 is one compile unit in crates/aura-cli/src/graph.rs: thread the root composite as stub_ctx (drop the Option, update both render_graph callers) and name root entries by role.name instead of source:{kind}; gate is `cargo build -p aura-cli` (goldens stay red until Task 2 — the golden-recapture exception). Task 2 re-captures blueprint_view_golden from the live `aura graph` output, updates the SimBroker needle, adds a root-SimBroker-stub assertion to the macd test and a [src] role-name-passthrough assertion to reused_composite_defined_once; gate is `cargo test --workspace` + clippy. compiled_view_golden is the byte-unchanged negative control (render_compilat path, C23). plan-recon mapped exact line numbers and flagged the source:{kind} golden twin (blueprint changes / compiled must not) and the stale, out-of-scope render_clustered.txt fixture. |
||
|
|
ed1d22bbfa |
spec: 0025 render root like any composite (slot stubs + role-name entries)
Settled source: issue #49, enabled by cycle 0024 (
|
||
|
|
d6f59d7a52 |
audit: cycle 0024 (#43, #36) — drift-clean; ledger reconciled to the pre-build signature
Architect drift review (862882b..1b39093): NO code drift, no contract weakened. C1 (behaviour-preserving: 150 tests green, render goldens byte-identical, no behavioural assertion altered), C8 (sink output: vec![] preserved), C9/C23 (read-only render touches no eval/build; derive_signature's Box::leak is cold-path-only, leaked names non-load-bearing) all hold. Regression scripts: none configured (no-op) — the architect review is the gate. The only drift was design-ledger prose, anticipated and deferred to this audit by the plan. Resolved here (fix path, orchestrator-applied — docwriter is barred from the design ledger): - docs/design/INDEX.md C8 Guarantee: rewritten — a node's signature (NodeSchema) is declared pre-build on the value-empty recipe; the built node implements lookbacks() (the one param-dependent sizing quantity) + eval(); schema() is gone. - INDEX.md C8 cycle-0015 note: Blueprint::param_space -> Composite::param_space; the #36 lockstep-debt clause marked closed by 0024. - INDEX.md: added a C8 cycle-0024 realization (signature lives once on the recipe, the signature/sizing split, #43/#36 closed) and a C19 cycle-0024 realization (struct Blueprint collapsed into the root Composite; Role.source/runnable-iff- bound/UnboundRootRole; FlatGraph as the named compilat). Stale symbol names in the dated 0016/0017 notes annotated in place with their 0024 renames. - aura-std/src/lincomb.rs module doc: Blueprint::param_space -> Composite::param_space. Ledger-gap (four new load-bearing invariants previously unrecorded) closed by the two new realization notes. Green baseline re-confirmed after the edits: cargo test --workspace 150 passed / 0 failed; cargo clippy --all-targets -D warnings clean. refs #43 #36 |
||
|
|
1b3909316e |
feat(aura): node signature lives in the blueprint; collapse Blueprint into Composite
Consolidate the node data structure so every node's signature (NodeSchema:
inputs/output/params) is declared once and exists in the blueprint pre-build,
and dissolve the special "root graph" type. Behaviour-preserving (C1).
Signature vs sizing
- NodeSchema is now the static signature only: InputSpec -> PortSpec{kind,firing},
with lookback removed. The signature is fully static per blueprint (input
kinds/firing, output fields, params); LinComb's variable arity is a builder arg,
not an injected param.
- The one param-dependent quantity, an input's buffer lookback (e.g. Sma's window =
its injected length), moves out of the signature to Node::lookbacks() -> Vec<usize>,
read only by bootstrap for sizing. Node::schema() is removed.
- LeafFactory -> PrimitiveBuilder, which carries the full NodeSchema. The built node
no longer re-declares it: closes the params-declared-twice drift (#36, the 8
per-node factory_params_match_built_node_schema lockstep tests are deleted — their
subject is now structurally impossible) and a value-empty recipe exposes its full
I/O interface pre-build (#43).
Root is just a bound composite
- struct Blueprint is deleted; its compile/bootstrap/param_space methods move onto
Composite. Role gains source: Option<ScalarKind> (None = open interior port,
Some = bound ingestion feed). A composite is runnable iff every root role is bound;
the "main graph" is no longer a category, only the fully-source-bound composite.
New error CompileError::UnboundRootRole for an open root role.
- BlueprintNode::signature() answers uniformly for both arms: Primitive returns the
builder's declared schema, Composite derives it from the interior (role kinds in,
OutField kinds out, aggregated params), pre-build, no build.
compile -> FlatGraph -> bootstrap
- compile validates structure pre-build via signature() (validate_wiring: range +
kind, returning the same variants as before, so an edge kind fault is now caught
before any build closure fires) and emits FlatGraph{nodes,signatures,sources,edges}.
- bootstrap consumes the FlatGraph: kinds/firing/output from the carried signatures,
buffer depth from node.lookbacks(). SourceSpec survives as the flat descriptor.
Renames: BlueprintNode::Leaf -> Primitive, LeafFactory -> PrimitiveBuilder.
Render (aura-cli/src/graph.rs) is migrated compile-only: it takes &Composite, maps
bound roles to the same source-entry shape, so both render goldens reproduce
byte-identical output (no re-capture needed). Render-fidelity tuning is the next cycle.
Verification (orchestrator-run, not agent-reported): cargo build --workspace green;
cargo test --workspace 150 passed / 0 failed; cargo clippy --workspace --all-targets
-D warnings clean. All pinned determinism/run-output tests pass with values unchanged;
no behavioural assertion was altered to go green. 5 new tests assert the signature is
pre-build and uniform, that compile rejects a kind mismatch without building (via a
panicking builder), UnboundRootRole, and lookbacks()/signature arity agreement.
Deferred to cycle-close audit (per plan): docs/design/INDEX.md and some aura-std
module docs still name the old Node::schema()/LeafFactory/BlueprintNode::Leaf/
Blueprint::param_space contracts; prose reconciliation is the architect's at audit.
closes #43 #36
|
||
|
|
c7fc2f6a37 |
plan: 0024 node signature in blueprint
Five-task, compile-gate-sequenced plan for the behaviour-preserving refactor: aura-core types (PortSpec/PrimitiveBuilder/NodeSchema/lookbacks) -> aura-std 8 nodes -> aura-engine lib (Composite absorbs Blueprint, signature/derive_ signature, FlatGraph, pre-build validate_wiring, bootstrap reshape) -> engine tests -> aura-cli/ingest + compile-only render. Per-crate partial build gates; workspace gate only in the final task. One working-tree unit (committed once after Task 5 green). refs #43 #36 |
||
|
|
78d68fa8ad |
spec: 0024 node signature in blueprint
Consolidate the node data structure so every node's signature (NodeSchema: inputs/output/params) exists in the blueprint pre-build, declared once. - Signature vs sizing split: NodeSchema becomes the static signature (InputSpec -> PortSpec, lookback removed); the one param-dependent quantity (input buffer lookback) moves to a build-time Node::lookbacks() query. Node::schema() is removed. - PrimitiveBuilder (ex-LeafFactory) carries the schema; the built node no longer re-declares it -> closes the params-declared-twice drift. - Blueprint collapses into Composite: Role gains source: Option<ScalarKind>; the root is the fully-bound composite (no "main graph"); new error UnboundRootRole. - compile -> FlatGraph -> bootstrap: FlatGraph carries node + signature in parallel; bootstrap sizes from lookbacks(), kind-checks from the signatures. - Renames: BlueprintNode::Leaf -> Primitive, LeafFactory -> PrimitiveBuilder. Behaviour-preserving (C1). Render is out of scope beyond compiling (next cycle). refs #43 #36 |
||
|
|
862882bc04 |
audit: cycle 0023 (#48) — drift reconciled; render paths unified
Architect drift review (bb90c42..481172a): no contract drift. C9 (render reads structure + label()/params()/output() only, never eval), C8 (sink = zero-output leaf, no special case), C12 (blueprint = root composite is render-structural only; types stay distinct), C23 (consumer-prefix mirrors the := binding), #38 (composites stay opaque) — all hold. Three fidelity items, resolved: - [high, fixed] spec acceptance over-claimed: the SimBroker slot-stub box read as in-scope though the work is deferred. Spec amended — the stub acceptance is annotated against #49, the met boxes checked. - [medium, recorded] no docs/plans/0023: this cycle ran spike→refactor under user steering instead of planner→implement, because the edge-label-vs- consumer-side fork needed an empirical probe (ascii-dag silently drops edge labels on collision) before a placeholder-free plan was possible. A plan RECORD (not a task plan) now holds the 0023 slot so the counter pairing stays intact and the next cycle takes 0024. - [low, carry-on] multi_output_field_name's leaf-producer fallback is latent and untested (no multi-output leaf in the corpus). Carried as debt. Regression scripts: none configured (no-op). Build/test/clippy green. Deferred stub work is tracked in #49 (user-signed). closes #48 |
||
|
|
481172ae2e |
feat(aura-cli): unify blueprint main-graph render through one shared core
render_blueprint and render_definition were two divergent paths: the main graph drew bare factory.label() leaves and bare edges, the composite interior drew enriched leaves (params, slot stubs, output bindings). They now delegate to one shared render_graph over borrowed slices — the blueprint is the root composite, differing only at the borders (ParamNames::Factory vs Aliases, Entry unifying SourceSpec and Role, empty OutField list = no bindings). LeafFactory holds a Box<dyn Fn>, so it is not Clone — an owned root-composite adapter is impossible; the shared core takes borrowed slices instead. The main graph now shows what the strategy does: a multi-output producer's selected field surfaces as a consumer-side prefix ([histogram -> Exposure(scale)]), mirroring the := output-binding form. Edge labels are deliberately avoided — ascii-dag 0.9.1 silently drops an edge label it cannot place without collision (arena_render.rs can_place_label), unreliable in a dense graph. Deferred: top-level blueprint multi-input leaves render without #-slot stubs (stub_ctx None) — fan_in_identifiers is still composite-coupled via signature_of. refs #48 |
||
|
|
5dd9503e40 |
spec: 0023 unify blueprint main-graph render
The CLI blueprint main-graph render is a separate, poorer path than the composite-definition render: bare leaves, bare edges, dropped from_field. Unify both through the composite machinery — the blueprint is the root composite, differing only at the borders (sources, factory params, sinks as zero-output terminal leaves). Harness signature header deferred. refs #48 |
||
|
|
bb90c42028 |
audit: cycle 0022 (#46) — drift reconciled; output bindings shipped
Architect drift review (range 69d2094..HEAD), regression gate empty (no scripts configured). Status: drift_found, all resolved here or queued. What holds: C8/C23 intact — output_binding folds OutField.name onto the producer label as a pure render symbol; compiled_view_golden byte-identical, no name reaches the compilat; the drawn where: graph is now exactly the computation DAG (false terminals + node-count inflation gone). Resolved (doc reconciliation, this commit): - docs/design/INDEX.md: two stale render descriptions brought current — the C9/0018 realization said output names render as `[out:<name>]` markers; the C19/0017 realization said `[in:k]`/`[out]` port markers. Both superseded by the `name := producer` binding form (the `[out]` staleness is cycle-0022's; the adjacent `[in:k]` was pre-existing drift from 0019/0020 and is reconciled in the same clause while here). - docs/specs/0022: post-ship note added — its Components/Testing strategy under-counted the blast radius, missing the full-render golden blueprint_view_golden (forced re-capture, caught at implement). Queued (not fixed): output_binding's tuple arm `(a, b) := …` is spec'd + shipped but unexercised (no fixture re-exports >1 field from one node) — filed as #47 (idea). cycle 0022 drift-clean after this reconciliation (not a milestone close). |
||
|
|
3b496883e6 |
feat(aura): render composite output re-exports as producer bindings
In the blueprint view's `where:` section, a composite's output re-exports now fold onto their producing node's label as a binding (`[macd := Sub(#Ef,#Es)]`) instead of each becoming a standalone terminal node wired from its producer. An OutField re-exports an existing interior node's value — it is never a new node — so the old form drew false terminals (MACD's macd line feeds the signal EMA and histogram internally yet rendered as a dead-end leaf) and inflated the node count by the output arity (MACD where: 8 -> 6 nodes; sma_cross drops its [cross] stub + edge). The drawn graph is now exactly the computation DAG; the `:=` prefix is the visual signal that a node's value escapes the boundary. Input roles stay standalone entry nodes (no producer to annotate) — the asymmetry is deliberate. render_definition drops its per-OutField node+edge loop; a new output_binding helper yields the `name := ` / tuple `(a, b) := ` prefix. Pure render layer: C8/C23 untouched, OutField.name never reaches the compilat, compiled_view_golden byte-identical, MACD run deterministic and unchanged in metrics. Test blast radius was wider than spec 0022 §Components / the plan's Scope note counted: besides the MACD pinning test, four more sites assert a producer that carries an OutField and so gain the `:=` prefix — blueprint_view_defines_each_composite_once, the two fan-in identifier tests, the cli_run integration test, and (missed by the plan, caught at implement) the full-render blueprint_view_golden. All re-pins are forced by the design, zero judgement. The output_binding tuple arm is unexercised by current fixtures (no composite re-exports >1 field from one node). Verified: cargo test --workspace 0 failed; clippy --all-targets -D warnings clean. closes #46 |
||
|
|
b2f27f8590 |
plan: 0022 composite output binding render
RED-first: re-pin all five render assertions whose producer carries an OutField (macd, sma_cross cross, two fan-in `o` outputs — across main.rs + cli_run.rs) to the `:= ` binding form, then fold output_binding onto the producer label in render_definition. Blast radius wider than spec §Components named (flagged for audit). refs #46 |
||
|
|
7d4740e8b2 |
spec: 0022 composite output binding render
Render composite output re-exports as producer-label bindings (`name := <producer-label>`) instead of standalone terminal nodes: folds the output name onto its producing node, dropping the false terminals and the node-count inflation (MACD where: 8 -> 6). Pure render layer; C8/C23 untouched, compiled view byte-identical. refs #46 |
||
|
|
69d20949c0 |
tidy(aura-engine): single-own alias-validity + shared alias-count anchor
Collapse the two correctness-neutral debt items the 0021 fan-in pre-pass left behind (architect drift review at cycle close). Alias-validity: the `BadInteriorIndex` check was raised in two places — the structural pre-pass `check_composite_fan_in` and `inline_composite`. Since `compile_with_params` runs the pre-pass over every composite before any lowering, `inline_composite`'s copy was dead for that error path. The check now lives in one helper `check_alias_indices`, called solely by the pre-pass; `inline_composite` drops its copy (and the now-unused `param_aliases` binding — the overlay is a pure naming layer, unused in lowering, which is driven by the injected scalar vector). Alias-count: the per-node `a.node == node` predicate was re-derived in three spots (signature base, the unaliased-param test, the CLI render base-length). All three now route through one exported anchor `aliases_on`, so an alias-semantics change touches one site. Behaviour-preserving: the full workspace suite is the guard (15+6 cli, 25 core, 69 engine, 6+1+1 ingest/misc, 29 std — 0 failed), `out_of_range_param_alias_rejected` still green (now raised by the pre-pass), clippy -D warnings clean. No ledger change (the C9 refinement landed in 0021). closes #45 |
||
|
|
04c2280dd8 |
audit: cycle 0021 (#44) — drift-noted; fan-in distinguishability shipped
Architect drift review over efbe0f4..3f4d756 (the two un-audited interim render commits 32ac8a3/b73d707 plus the 0021 fan-in cycle). Holds: - C23 intact — the IndistinguishableFanIn check is a construction-phase pre-pass; the compilat stays name-free (compiled_view_golden byte-stable). - C9 boundary clean — signature distinguishability lives at the blueprint layer and dissolves at inline; the C9 ledger refinement is accurate and in-format. - Pre-pass placement (before the arity gate, not inside inline_composite) is the spec-aligned home, not drift: a no-param compile() of a param-bearing composite would hit ParamArity first. Regression: commands.regression is empty (no gate) — architect is the sole gate; clean of contradictions. Debt (correctness-neutral, not blocking) tracked in #45 for a focused tidy iteration rather than rushed at cycle tail: - inline_composite's alias-validity loop is now dead for BadInteriorIndex (the pre-pass raises it first for every composite). - per-node alias count is re-derived in three sites (signature_of base, leaf_has_unaliased_param, signature_base_len). refs #45 |
||
|
|
3f4d756ed2 |
feat(aura): fan-in input distinguishability — construction constraint + source-derived render
A fan-in node (>1 input) whose colliding sources hide an unnamed configuration axis is now illegal at construction, and the definition view renders each fan-in input as a source-derived recursive-signature identifier instead of the positional, meaningless #A/#B. The root defect was sma_cross: two Sma into a Sub with unaliased length params, rendering sma_cross() -> (cross) with two indistinguishable [SMA] and [Sub(#A,#B)] — the author meant fast vs slow but the identity hid it. Now it renders sma_cross(fast:i64, slow:i64) with [SMA(fast)]/[SMA(slow)] and [Sub(#Sf,#Ss)]. Shape (single source of truth for "signature" shared by engine + CLI): - aura-engine signature_of(): a node's recursive authoring identity — type initial + alias initials + each wired input's signature (recursing into interior leaves, stopping at named roles/composites at their initial). - aura-cli leaf_label/fan_in_identifiers: shortest sibling-unique prefix of a source's signature, never below its base (type + alias initials); a role-fed slot renders its name verbatim (#price); equal-signature interchangeable inputs keep the positional letter. - aura-engine IndistinguishableFanIn: a signature collision is a fault only when a colliding source carries an unaliased param (the unnamed axis); param-less interchangeable sources (fan_composite's Pass/Pass) stay legal. Param-aware criterion (refined during design): keeps the blast radius to the param-bearing alias-less fixtures (sma_cross CLI + engine, the nested fast_slow); fan_composite and the hand-wired flat fixtures stay green. Placement decision (deviates from the plan): the constraint runs as a structural pre-pass (check_fan_in_distinguishability) at the head of compile_with_params, BEFORE the param-arity gate — not inside inline_composite as the plan drafted. Reason: the no-param compile() of a param-bearing composite would hit ParamArity first and preempt the fault; the spec mandates a structural check needing no param values, so the pre-pass is the spec-aligned home. Alias-validity ordering (BadInteriorIndex before the fan-in fault) is preserved at the pre-pass head. C23 untouched: the check is construction-phase; the compilat stays name-free (compiled_view_golden byte-stable). Ledger C9 carries the refinement. Known debt (non-gating): the alias-index validity check now exists in both inline_composite and the pre-pass (the pre-pass reaches every composite first, making inline_composite's copy effectively dead). Left for a separate tidy — a 5-line, correctness-neutral removal with its own test surface. closes #44 |
||
|
|
3aa124f815 |
plan: 0021 fan-in distinguishability
Four tasks: shared recursive signature_of helper (aura-engine); CLI source-derived fan-in identifiers + sma_cross aliases + render goldens (aura-cli); the IndistinguishableFanIn construction constraint + engine fixture aliases (aura-engine); the C9 ledger refinement. Ordered so the workspace test suite stays green at every task boundary. Refs #44 |
||
|
|
22a690361a |
spec: 0021 refine fan-in constraint to a param-aware criterion
A signature collision is a fault only when at least one colliding source carries an unaliased param slot — the configuration axis the author left unnamed (sma_cross's length). Equal-signature sources with no param are genuinely interchangeable (fan_composite's Pass/Pass, add(price,price)) and stay legal; the render uses the positional letter for them. Keeps the construction blast radius to the param-bearing alias-less fixtures. Refs #44 |
||
|
|
14d91035ec |
spec: 0021 fan-in distinguishability
A construction-phase constraint (CompileError::IndistinguishableFanIn, raised in inline_composite) makes a fan-in node whose sources have identical recursive signatures illegal; the definition view then renders each fan-in input as the shortest unique prefix of its source's signature (replacing positional #A/#B); and the sma_cross fixture gains its missing fast/slow aliases. Refs #44 — scope extended from render-only to a construction-phase invariant during design (the positional #A was a symptom of unnamed, indistinguishable fan-in sources, which is the actual fault to forbid). |
||
|
|
b73d7076c3 |
feat(aura-cli): TTY-gated ANSI edge colouring + blank line after composite signature
Two presentation refinements to the `aura graph` views, render-only (no
engine change, C8/C9/C23 untouched).
Edge colouring: thread a `Color { Plain, Ansi }` through render_flat /
render_definition / render_blueprint / render_compilat. `Ansi` uses
ascii-dag's colored scanline pass (per-edge palette colours) so crossing
edges stay traceable; `Plain` is the existing monochrome `g.render()`.
The CLI selects `Ansi` only when stdout is a TTY (`IsTerminal`), so a
redirect to a file or pipe stays byte-clean — `aura graph | …` carries no
escape codes. ascii-dag colours only edges; node-label text is unaffected.
Tests render `Color::Plain` explicitly, so both goldens stay byte-stable
(compiled_view_golden remains the C23 guard); a new test pins that `Ansi`
emits escapes and `Plain` does not, and that labels survive colouring.
Blank line: render_definition now separates the typed signature title from
the graph body with an empty line. blueprint_view_golden re-captured.
Considered but rejected this round: per-node role highlighting of the
signature identifiers — needs either an ascii-dag fork (node colouring is
hard-disabled upstream) or a per-graph string-surgery pass that does not
generalise beyond hand-known labels. Only edge colouring survives here.
|
||
|
|
32ac8a30ea |
feat(aura-cli): de-prefix input-role markers ([in:price] -> [price])
Symmetric with the output de-prefix shipped in
|
||
|
|
efbe0f4a66 |
audit: cycle 0020 tidy (clean) — typed-signature render, render-only
Architect drift review over ebe2e71..HEAD (spec |
||
|
|
2f4916596d |
feat(aura-cli): composite definition renders as a typed signature
Refines #41's blueprint-definition render. The [param:<name>] marker nodes #41 added bloated the ASCII MACD graph (three extra nodes + fan-in edges); this moves the interface into the title line and folds names into the leaf labels that already exist: - title is the composite's typed signature, e.g. macd(fast:i64, slow:i64, signal:i64) -> (macd, signal, histogram) (param kinds from the aliased leaf's factory params via a new ScalarKind->lowercase kind_str; output NAMES only — output kinds need a pre-build factory interface, deferred to #43) - leaf labels fold aliased param names: [EMA] -> [EMA(fast)] - unnamed interior input slots render as ordered stubs: [Sub] -> [Sub(#A,#B)] (count/order derived render-side from c.edges() + c.input_roles(), no engine schema needed; arity-1 nodes get no stub) - outputs de-prefixed: [out:macd] -> [macd]; the [param:*] marker nodes are gone - two stale doc comments corrected: render_definition's [param:] prose and node.rs LeafFactory::label (the renderer went flat in 0017, so the cited ascii-dag cluster-garble rationale no longer applies — wide labels are safe; the factory label stays bare because alias names are composite-level) Render-only: no engine/ParamAlias/param_space change. compiled_view_golden byte-identical (C23 guard — verified untouched in the diff); aura run --macd deterministic and unchanged (total_pips 0.1637945563898923, 3 sign flips). The title format change repinned five .matches("name:")->.matches("name(") definition-count asserts (sma_cross/outer/inner/dup/macd); the stub separator is "," (no space) to match the [Sub(#A,#B)] surface. Verification (orchestrator-run): cargo build/test/clippy --workspace -D warnings all green; the redesigned MACD render confirmed by eye. refs #41 #43 |
||
|
|
71f50330db |
plan: 0020 composite signature render
Two-task render-only plan executing spec 0020:
- T1 (graph.rs + node.rs): add `signature` (typed title line, with a new
ScalarKind->lowercase `kind_str` match — none exists today, {:?} gives
PascalCase) and `leaf_label` (fold aliased param names + ordered
input-slot stubs); edit render_definition (title->signature,
leaf->leaf_label, drop [param:*] loop, de-prefix outputs); fix two stale
doc comments (the render_definition [param:] description + the
node.rs:93-101 cluster rationale). Gate: cargo build -p aura-cli (the
goldens go red until T2 re-captures; cargo test is NOT a T1 gate).
- T2 (main.rs): repin the FIVE title asserts name:->name( (the blast
radius: sma_cross/outer/inner/dup/macd, four beyond the spec's named
one); update the definition needle ([Sub]->[Sub(#A,#B)], [out:cross]->
[cross]); rewrite the MACD render assertions (drop [param:*], add the
signature + [EMA(fast)] + [Sub(#A,#B)] + [macd] + [param:/[out: absence);
re-capture blueprint_view_golden wholesale; confirm compiled_view_golden
byte-identical (C23); full --workspace triple -D warnings.
Render-only: no engine/ParamAlias/param_space change; compiled_view_golden
byte-identical; aura run --macd unchanged. Output kinds deferred to #43.
refs #41 #43
|
||
|
|
42eb62771d |
spec: 0020 composite signature render
Render-only refinement of #41's composite blueprint-definition view. The [param:<name>] marker nodes #41 added bloat the ASCII graph; this moves the interface into a typed signature title line and folds names into the node labels that already exist: - title: macd(fast:i64, slow:i64, signal:i64) -> (macd, signal, histogram) (param kinds from factory().params()[slot].kind; OUTPUT NAMES ONLY) - leaf labels fold aliased param names: [EMA] -> [EMA(fast)] - unnamed interior input slots as positional stubs: [Sub] -> [Sub(#A,#B)] (count/order derived render-side from c.edges() + c.input_roles()) - outputs de-prefixed: [out:macd] -> [macd]; [param:*] marker nodes removed - fix stale node.rs:93-101 cluster rationale (renderer went flat in 0017) Output KINDS are deferred: a value-empty LeafFactory exposes no output schema pre-build (the mc_4/#42 finding), so the typed arrow (-> macd:f64) waits on #43. Render-only: no engine/ParamAlias/param_space change; compiled_view_golden byte-identical (C23); aura run --macd unchanged. Gates green: feature-acceptance (the worked MACD before->after is the evidence), placeholder scan clean, parse-every-block no-op (no spec_validation parser), grounding-check PASS (10 assumptions ratified; both load-bearing premises — no pre-build factory output schema, flat renderer — confirmed). refs #41 #43 |
||
|
|
ebe2e71349 |
audit: cycle 0019 (#41) — drift-clean; C9 boundary-uniform realization note
Architect drift review over 8bc429f..HEAD (spec |
||
|
|
41cbb5506f |
feat(aura-engine): name the composite boundary — input roles + param aliases
Brings the other two composite-boundary edge-kinds to the named-projection shape #40 gave outputs. input_roles changes from a bare Vec<Vec<Target>> to Vec<Role { name, targets }> (rendered [in:<name>]); a composite gains params: Vec<ParamAlias { name, node, slot }> that relabels an interior leaf param slot's surface name in param_space() (rendered [param:<name>]). Param aliasing is a PURE NAMING OVERLAY, not curation (the load-bearing decision, per spec 0019): every interior param slot stays in param_space() and sweepable; the alias only relabels in place, never reorders or hides. Proven empirically — the MACD run is byte-identical (total_pips 0.1637945563898923, 3 sign flips), only the param labels improved: param_space() now surfaces [macd.fast, macd.slow, macd.signal] instead of three indistinguishable macd.length, and the manifest reads ema_fast/ ema_slow/ema_signal. C23 honoured: role/param/output names are non-load-bearing debug symbols dropped at lowering; identity is positional (role index, param slot, output field). compiled_view_golden is byte-identical (verified: the golden region is untouched in the diff). An out-of-range alias (missing/ non-leaf node or slot past the leaf's param count) is rejected at compile_with_params as BadInteriorIndex, mirroring the output range-check (no new variant). Orthogonal to #36 — purely additive at the composite level. Aliasing is demonstrated on the CLI MACD site only (the spec's worked example + a new E2E test macd_param_space_surfaces_the_three_named_aliases); sma_cross, the engine test fixtures, and the construction-layer fieldtests get the forced role-name + empty params, so the param_space C23 anchor goldens (param_space_mirrors_compiled_flat_node_param_order + siblings) stay byte-identical. Verification (orchestrator-run, not trusted from the agent report): cargo build/test/clippy --workspace -D warnings all green (engine 66, cli 12); the separate-workspace construction-layer fieldtest crate builds (guards the #42 latent-drift recurrence); compiled_view_golden + MACD determinism unchanged. Two faithful repairs to the plan's literal test/code bodies, no semantic change: the out-of-range test uses .err()/Some(BadInteriorIndex) (the Ok arm Vec<Box<dyn Node>> is not Debug, so .unwrap_err() would not compile), and the inline_composite destructure binds params as `param_aliases` to avoid shadowing the injected `params: &[Scalar]` arg. closes #41 |
||
|
|
c9115e3e0f |
plan: 0019 name composite boundary
Four-task plan executing spec 0019, sequenced like cycle 0018 (type-shape change rippling engine -> CLI): - T1 engine type migration, behaviour-preserving: Role/ParamAlias types, Composite struct/new/accessors, inline_composite role-walk, lib.rs re-export, all engine test Composite::new sites. Gate per-crate (cargo test -p aura-engine, NOT --workspace; aura-cli compiles in T3). The new params field is dormant -> param_space byte-identical, C23 anchor goldens green. - T2 param aliasing RED-first: collect_params alias relabel + inline_composite alias range-validation (-> BadInteriorIndex, reusing the variant), with 4 new unit tests (relabel, out-of-range, unaliased regression, partial). - T3 CLI: render_definition [in:name]/[param:name] markers; MACD author site (named role + fast/slow/signal aliases, the worked example); sma_cross named role only; blueprint_view_golden re-capture; compiled_view_golden stays byte-identical (C23 guard). - T4 fieldtests sweep (separate workspace root -> explicit cargo build gate, guarding the #42 latent-drift recurrence) + full --workspace triple (-D warnings). Aliasing demonstrated on the CLI MACD site only (the spec's evidence); every other composite site gets the forced role-name + empty params, so the param_space C23 anchor goldens stay byte-identical. refs #41 |
||
|
|
03f2dc4c51 |
spec: 0019 name composite boundary
Sibling of #40 (composite output as a named multi-field record). Brings the other two composite-boundary edge-kinds to the same named-projection shape: input roles (Vec<Role { name, targets }>, rendered [in:<name>]) and a param-alias overlay (Vec<ParamAlias { name, node, slot }>) that relabels an interior leaf param slot's surface name in param_space(). Load-bearing decision recorded in the spec: param aliasing is a pure naming overlay, NOT curation — every interior slot stays in param_space() and sweepable; the alias only relabels in place, never reorders/hides (forced by the issue's "legibility not capability" framing + C23). The injected point vector is unchanged; MACD surfaces macd.fast/slow/signal instead of three indistinguishable macd.length. Gates green: feature-acceptance (worked MACD before->after is the evidence), placeholder scan clean, parse-every-block no-op (profile declares no spec_validation), grounding-check PASS (7 load-bearing assumptions each ratified by a named currently-green test; compiled_view + param_space slot-order goldens stand as the C23 regression anchors). refs #41 |
||
|
|
241bb626e6 |
fix(fieldtests): port construction-layer fixtures to current authoring API
The four standalone construction-layer fieldtest bins (mc_1..mc_4) no longer compiled: they are their own workspace root, so the engine's `cargo build --workspace` never touched them and two waves of API drift went latent. Two breakage classes, both confined to the fixture files (no engine change): - Stale cycle-0016 authoring. `BlueprintNode::from(<Node>::new(..))` relied on the `From<NodeType>` impls retired in the value-empty migration; only `From<LeafFactory>` survives. Ported to `<Node>::factory().into()` — nodes are value-empty blueprint items, params bound at compile. Knock-on in mc_4 `describe_node`: a blueprint leaf is now a `&LeafFactory` with no pre-build schema, so leaf introspection reports the render label + declared param count (inputs / outputs exist only on the compiled flat node, post-build). - Cycle-0018 (#40) OutPort -> OutField slice drift. `Composite::output()` now returns `&[OutField]`; the mc_4 read sites were still treating it as a single port. Ported to index the record; the walk assertion now also pins the arity (one re-exported field), which is the #40 shape. Faithful ports, not assertion-gutting: each fixture still exercises its axis (composite build+run / miswire render / nested composite / graph introspection), verified by running all four bins to their `OK:` line. One genuine semantic drift flagged in mc_2: the blueprint-view label is now the bare value-empty type ("SMA"), so two same-type leaves share a label and are disambiguated by the slot/edge table; the valued SMA(2)/SMA(4) label lives on the compiled view. The fixture asserts what the blueprint view actually exposes and keeps the load-bearing edge-table observability check untouched. closes #42 |
||
|
|
8bc429f367 |
audit: cycle 0018 (#40) — drift-clean; C9 multi-output realization note
Architect drift review over a4cfe5c..HEAD (covers the previously-unaudited EMA node and MACD PoC plus the #40 composite multi-output cycle): status clean. C8/C7/C4 preserved (one port, one row per eval, K co-fresh base columns — structurally identical to OHLCV); C23 honoured (ItemLowering:: Composite.output is Vec<(usize,usize)>, no name in the compilat; the compiled-view render stayed bit-identical). EMA and MACD PoC carry no ledger drift. Resolution of the three minors: - Ledger lagged the new behaviour: added a "Realization (cycle 0018)" note under C9 recording that a composite's output is now a named K-field record (Vec<OutField>), the same arity C8 already grants a leaf, names dropped at lowering (C23). Amended here (ledger amendment is the audit's job). - blueprint.rs module-doc / Composite struct-doc / new-doc still said "one output port" singular — updated to "output record". - Non-workspace fieldtest From<Sma> debt is pre-existing (cycle-0016) and already tracked as #42; not re-filed. No regression scripts configured (profile regression: []), so the architect review is the sole gate. Carry-on: the next natural iteration is the #41 legibility sibling (input-role + param naming at the composite boundary). |
||
|
|
784e6c917a |
feat(aura-engine): composite output is a named multi-field record
Replace a composite's single output port (OutPort { node, field }) with
an ordered, named record (Vec<OutField { node, field, name }>). A
composite can now re-export K interior fields as one output; a consumer
selects one via the existing Edge::from_field — the same field-wise
selector that already works for multi-output leaf producers (OHLCV).
Why: multi-line indicators (MACD, Bollinger, Stochastic, Ichimoku) could
not be authored as a composition and re-exported as a unit — only one
line escaped the boundary. The MACD PoC was forced to expose only the
histogram. This lifts the three `field == 0` / `from_field == 0` caps at
the composite boundary (inline_composite nested arm, rewrite_edge
composite arm), range-checking the index instead.
Boundary completion, not an invariant change:
- C8/C7/C4 untouched — one port, one row per eval, K base columns (a
3-line MACD is identical in kind to OHLCV).
- C23 honoured — re-export names live at the blueprint boundary only and
are dropped in the compilat (raw index wiring). compiled_view_golden
stayed byte-identical (the regression guard): no name leaked into the
flat graph.
The MACD PoC now re-exports macd / signal / histogram as a record; the
strategy still trades the histogram, selected via from_field: 2. The
render shows K [out:<name>] markers per multi-output composite (input
roles stay [in:<index>] — naming them is the dependent #41).
Output naming ships with the capability (OutField is born name-ready) so
#41 — composite param aliasing + input-role naming — does not reopen the
type.
Verification: cargo build/test/clippy --workspace -- -D warnings all
green; aura-engine 62 tests (+3 capability, +1 through-run E2E), aura-cli
unchanged-count green; compiled_view_golden byte-identical.
Known debt (out of scope, pre-existing): the non-workspace construction-
layer fieldtests (fieldtests/milestone-construction-layer/mc_1..mc_4)
carry their OutField sweep but still do not compile standalone — they use
the Sma::new / BlueprintNode::from(Sma) API retired in the cycle-0016
value-empty migration, never propagated to these fixtures. Tracked as a
follow-up.
closes #40
|
||
|
|
2c33a8d74f |
plan: 0018 composite multi-output record
Four tasks: engine type migration (behaviour-preserving, caps kept) → cap-lift with RED-first capability tests → CLI render + author sites + golden re-capture → non-workspace fieldtest sweep + workspace gate. refs #40 |
||
|
|
9ddeab8b7e |
spec: 0018 composite multi-output record
Composite::output: OutPort -> Vec<OutField { node, field, name }> so
multi-line indicators (MACD/Bollinger/Stochastic/Ichimoku) can be
authored as a composition and re-exported as a named record. Output
half only; param/input-role naming is the dependent sibling.
refs #40
|
||
|
|
d8b2a2880d |
feat(aura-cli): MACD strategy PoC over the EMA node
Author MACD as a nested composite -- price -> fast/slow EMA -> Sub (MACD line) -> signal EMA -> Sub (histogram), the histogram exposed as the single output the strategy trades. A richer fixture than sma_cross: an EMA-of-EMA chain with interior fan-out (the MACD line feeds both the signal EMA and the histogram), exercising the nested-composite render shipped in cycle 0017. It runs over the real path: the composite blueprint is compiled to a flat harness via compile_with_params + Harness::bootstrap (the same machinery as the SMA compiled view), not hand-flattened. New surfaces: aura run --macd (runs the strategy, prints metrics) and aura graph --macd [--compiled]. main's arg parsing is rewritten to a whole-argv match, preserving the #16 strict contract (trailing token / unknown subcommand -> usage, exit 2). MACD gets its own longer synthetic stream because the SMA-seeded EMAs warm up; the SMA sample's stream and goldens are untouched. This PoC makes two parameter-space gaps concrete for the milestone: the strategy's param_space is [macd.length, macd.length, macd.length, scale] -- three identical names distinguishable only by slot (the named-param case, blueprint #30) -- and a composite exposes only one output port, so the MACD/signal/histogram tuple cannot all be tapped for display (the tuple-output case). The compiled view's valued labels (EMA(2)/EMA(4)/EMA(3)) are what currently disambiguate the three EMAs. Tested: MACD compiles from the nested composite and runs deterministically (C1), the trace is non-trivial (>=1 exposure sign flip), and the blueprint view renders the composite definition once. |
||
|
|
ae1d4564f5 |
feat(aura-std): EMA node (SMA-seeded, O(1) per cycle)
Add Ema, the std-lib's first recursive/stateful producer: exponential moving average with alpha = 2/(length+1). The building block MACD (and DEMA, MACD-histogram, etc.) needs, and a worked example of a node whose param sizes its math, not its input window. Seeding is ratified as SMA-seeded (ta-lib convention): the EMA stays silent until it has seen length samples, seeds with their SMA, then runs the recurrence. Chosen over a first-value seed for three substantive reasons -- warm-up consistency with Sma (both emit None until length samples), parity with the EMA traders expect (ta-lib MACD seeds this way), and statistical honesty (no average claimed from a single observation). A first-value seed was the proof-of-concept convenience; rejected. Performance: recursive state means lookback = 1 (length sizes alpha, not the window); eval is O(1) time and state via ema += alpha*(x - ema), with no hot-path allocation (the output buffer is reused). Tested: warm-up-then-smooth (a step input separates it from a plain SMA), length-1 identity, label, and factory/schema agreement. |
||
|
|
a4cfe5c53f |
audit: cycle 0017 (#38) — render_flat dedup + ledger #38 realization note
Architect drift review of the #38 cycle (a70c5fa..cd31447) against the design ledger. No ledger-contract drift: C23 holds (render_compilat byte-identical, compiled_view_golden green), C9/C12 honoured (the new main-graph + where:- definitions view renders a composite as an opaque authoring-level node with its body defined once — a faithful blueprint/source view vs. the inlined compiled form), the nested-composite unimplemented! is genuinely removed and tested, and no orphaned references to the removed ItemDisplay/producer_id/consumer_ids remain in crates/ (only frozen historical plan docs mention them). Two debt items, both fixed here (not carried): - [medium] crates/aura-cli/src/graph.rs — render_compilat open-coded the same Graph::with_mode/add_node/add_edge/render idiom the new render_flat helper wraps. Fixed: render_compilat now builds its edge-pairs (its Edge structs + source targets) and delegates to render_flat, so render_flat is the single flat-build point shared by all three render functions. Behaviour-preserving — same node and edge insertion order — verified by compiled_view_golden staying byte-identical. - [low] the retired cluster-box blueprint-render model and its substantive cause (ascii-dag 0.9.1's subgraph /2 centering bug; flat-only being the fix) lived only in the superseded spec 0013, not in the durable contract layer. Fixed: added a "Realization (cycle 0017 — blueprint render = main graph + definitions)" note to the ledger (INDEX.md, under the C22 blueprint-view detail) recording the opaque-node + where:-definitions model, the authoring-vs-compiled split, the ascii-dag-bug rationale, the scale/render-once/nested benefits, and the #37 playground (enter/focus) counterpart vs. #38 static CLI form. regression: profile declares no regression scripts and no architect_sweeps — the architect review is the sole gate. No baseline to update. Cycle 0017 is drift-clean after these fixes. NOT a milestone close — that needs the end-to-end milestone fieldtest, still deferred until the sweep root (#32-#33) lands. |
||
|
|
cd31447d98 |
feat(aura-cli): blueprint view = main graph + composite definitions (#38)
Rewrite the `aura graph` blueprint view from ascii-dag subgraph cluster boxes to
a "program with subroutines" model: a flat main graph that wires the harness with
each composite shown 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` (flat, fully-inlined, C23) is byte-for-byte unchanged.
Why (not effort):
- Correctness under width. ascii-dag 0.9.1's subgraph level-centering rounds
sibling x-positions with `/2`, overlapping wide sibling labels (a
width/parity-sensitive bug with no config/padding dodge that survives
unequal-width siblings; verified by reproduction). The flat layout is
collision-free; this view renders only flat graphs, so the bug cannot arise.
- Scale. A composite is one opaque node in the main graph, so blueprint size
tracks top-level wiring, not inlined node count — real strategies stay
displayable.
- Render-once. A composite reused N times has its body rendered once
(collect_distinct_composites dedups by name(), recursively).
- Removes the nested-composite `unimplemented!` — the definitions pass recurses,
so nested composites render as opaque nodes with their own definitions.
Mechanics: ItemDisplay/producer_id/consumer_ids are gone (a composite is now one
display node, so boundary fan-resolution collapses); new render_flat (the same
no-subgraph idiom render_compilat uses), collect_distinct_composites, and
render_definition. The now-unused `Target` import is dropped.
Divergence from the plan's literal text: the plan's `collect_distinct_composites`
used a nested `if let { if .. }`; this toolchain's clippy (collapsible_if, rust
1.94) rejects it under -D warnings, so it is the behaviour-identical let-chain form
`if let BlueprintNode::Composite(c) = item && !seen.contains(&c.name())`.
Tests: the two cluster-asserting blueprint tests are replaced by four behavioural
tests (opaque-node main graph; defines-each-composite-once; nested-renders-without-
panic; reused-composite-defined-once) plus a recaptured blueprint_view_golden
(captured verbatim from `aura graph`, not hand-authored). The four must-stay-green
tests pass; compiled_view_golden is byte-identical (render_compilat untouched).
Verified: `cargo test --workspace` all green, `cargo clippy --workspace
--all-targets -D warnings` clean.
The interactive enter/focus navigation counterpart is the playground's, tracked
separately as #37.
closes #38
|
||
|
|
870dfcec5b |
plan: 0017 blueprint view as main graph + composite definitions
Two tasks, CLI-render-only (graph.rs + main.rs tests): - Task 1: rewrite render_blueprint to the main-graph + where:-definitions model (composite = opaque node; collect_distinct_composites recursive/deduped by name; render_definition with [in:k]/[out] port markers); drop ItemDisplay/producer_id/ consumer_ids and the nested-composite unimplemented!; behavioural tests RED->GREEN (opaque-node, defines-once, nested-no-panic, reuse-defined-once). - Task 2: recapture the blueprint golden from `aura graph` stdout; full-workspace test + clippy gate. render_compilat untouched (its golden stays byte-identical). refs #38 |
||
|
|
2d3792e45f |
spec: 0017 blueprint view as main graph + composite definitions
Redesign the `aura graph` blueprint view (render_blueprint) from ascii-dag subgraph cluster boxes to a "program with subroutines" model: a small main graph that wires the harness with each composite shown as a single opaque node, plus a `where:` section rendering each distinct composite type's interior once. render_compilat (flat, fully-inlined, C23) is unchanged. Design ratified in-session. The 3a-vs-3b fork was resolved by medium: the interactive enter/focus model (3a) is the playground's, parked as #37; the static main+definitions model (3b) is the CLI's, this cycle. Substance: - Correctness under width: ascii-dag 0.9.1's subgraph level-centering rounds sibling x-positions with `/2`, overlapping wide sibling labels (a width/parity-sensitive bug with no config/padding dodge that survives unequal-width siblings). The flat layout is collision-free; the new model renders only flat graphs, so the bug cannot arise. - Scale: a composite is one opaque node in the main graph, so blueprint size tracks top-level wiring, not inlined node count — real strategies stay displayable. - Render-once: a composite reused N times has its body rendered once. - Removes the nested-composite `unimplemented!` at graph.rs:74-77 (the definitions pass is recursive). Defaults baked (not forks): composite-type dedup key = name() (assumes same name => same structure, the authoring convention); opaque-node ports shown as [in:k] / [out] markers in a definition. grounding-check PASS — all nine load-bearing assumptions ratified by green tests (Composite/Blueprint API, the flat render_compilat path, the unimplemented! site, the two replaced cluster tests, the four must-stay-green tests). spec_validation parse gate is a confirmed no-op (none configured). refs #38 |
||
|
|
a70c5faab7 |
audit: cycle B (0016) — ledger 0016 realization note (C8/C19), debt #36 filed
Architect drift review of the #31 cycle (2a9a141..4b64409) against the design ledger. The feature is clean: C19/C23 realized literally (LeafFactory recipe; compile_with_params builds-then-wires slot-by-slot in the same walk param_space() projects — #34's dual-traversal hazard genuinely subsumed, one traversal, both mirror tests green incl. nesting); C12 "no recompile per param-set" holds (value-empty blueprint, vector-bound, bit-identity green); the removed Composite::schema/BlueprintNode::schema confirmed caller-free. ledger (fixed here): - C8: the 0015 note's "binding a value to a slot (#31) ... deferred" line was stale (shipped). Updated to record #31 landed in 0016, and that the param declaration's authoring home moved to LeafFactory.params() (read pre-build) alongside the built node's schema().params (the duplication is debt #36). - C19: added a "Realization (cycle 0016 — param-set injection)" note (the per-cycle pattern C8/C10 already carry for 0005/0006/0007/0015): the value-empty leaf, build-then-wire bootstrap_with_params/compile_with_params, the typed kind/arity errors, the bit-identical compilat, and the C22 blueprint-view bare-type label (value-bearing SMA(2) now only in the compiled view). debt (filed, carry-on): - Every param-bearing node declares its ParamSpecs twice (factory() and schema()), kept in lockstep only by a per-node test; drift compiles. Filed as #36 (sibling of #34's traversal-duplication concern). Not active drift — the agreement holds and is tested per node. regression: profile declares no regression scripts and no architect_sweeps — the architect review is the sole gate. No baseline to update. Cycle B is drift-clean after these amendments. NOT a milestone close — that needs the end-to-end milestone fieldtest, deferred until the sweep root (#32-#33) lands. |
||
|
|
4b64409036 |
feat(aura-core,aura-std,aura-engine,aura-cli): inject a param-set vector at bootstrap (#31)
Cycle B of milestone "The World — parameter-space & sweep". A blueprint is now value-empty: a leaf holds a param-generic recipe, not a built node, and a positional Scalar vector is bound slot-by-slot at bootstrap — so one blueprint bootstraps into many distinct instances under different vectors, with no cdylib rebuild (C12/C19). This is the binding primitive a sweep (#32) drives. Ratified design (brainstorm): value-empty reconstruct-through-new() over mutate-in-place and over a default-bearing variant. The value lives only in the injected vector (no baked default), keeping the blueprint a pure param-generic recipe (C19); every injected value flows through the node's own constructor (the single sizing/validation gate). - aura-core: LeafFactory { name, params, build } — the recipe (params -> sized node through `new`); Scalar::as_i64/as_f64 value accessors. Node trait unchanged. - aura-std: each of the 7 nodes exposes factory() (SMA length:I64, Exposure scale:F64, LinComb arity x weights[i]:F64; Sub/Add/SimBroker/Recorder paramless, capturing their non-param construction args — pip_size, the Recorder channel). - aura-engine: BlueprintNode::Leaf(LeafFactory), From<LeafFactory>; param_space() reads factory.params() pre-build; compile_with_params/bootstrap_with_params build each leaf from its kind-checked slice while lowering (build-then-wire), arity checked up front via param_space().len(); CompileError::{ParamKindMismatch, ParamArity}. compile/inline/edge-rewrite are structurally unchanged, so the compilat stays bit-identical for a given point (the bit-identity and both param_space mirror tests stay green). The vestigial pre-build Composite::schema / BlueprintNode::schema (no live caller — interface resolution is structural on the built flat nodes) are removed. - aura-cli: the blueprint view labels leaves by bare type via LeafFactory::label() (`[SMA]`) — the ascii-dag renderer cannot render wide cluster-sibling labels (see spec); the compiled view still labels valued (`SMA(2)`). The sample supplies its point as a vector; the mis-wiring swap moved to the compiled view. The #34 dual-traversal drift hazard is subsumed: compile_with_params consumes the vector in the same recipe walk param_space() reports, so the two share one traversal. Verified: cargo build/test --workspace green (127 tests, incl. bit-identity, both mirror tests, and 4 new injection tests — different-vector-different-run, kind mismatch, arity, determinism); clippy --workspace --all-targets -D warnings clean; `aura graph` blueprint view renders cleanly. Scope: one vector -> one instance. Deferred: sweep enumeration (#32), domain validation (#32/C20), single-run authoring convenience (#35). closes #31 |
||
|
|
b02f31cdd4 |
spec: 0016 — blueprint-view label is the bare type (ascii-dag wide-label limit) (#31)
The amend chose `SMA(length)` (type + knob names) for the param-generic blueprint view. Implementation surfaced that the ascii-dag 0.9.1 renderer writes a label verbatim on one line (no multi-line — `render/ascii.rs::write_node` brackets the raw string) and its Sugiyama subgraph layout overlaps two wide sibling boxes inside a cluster (`[SMA(length[SMA(length)]`). Width is auto-computed but the cluster packing does not honor it; the only spacing knob (`node_spacing`) is on the deprecated config path, global, and width-independent — no robust option, and domain labels grow unboundedly wide (`LinComb(weights[0], weights[1])`, deep path-qualified names). Horizontal mode is already rejected (collapses fan-outs). So `LeafFactory::label()` renders the bare node type (`SMA`). The tunable knobs are surfaced by `param_space()`, not in the graph; the compiled view still labels built nodes valued (`SMA(2)`) via `Node::label`. Correct C22 reading either way — structure (now: type-only) before, values after. refs #31 |
||
|
|
bf5ff22371 |
plan: 0016 param-set injection (#31)
Four crate-gated tasks for spec 0016: aura-core (LeafFactory + Scalar accessors), aura-std (factory() on the 7 nodes), aura-engine (value-empty Leaf, build-then-wire compile_with_params/bootstrap_with_params, kind+arity errors, vestigial schema removal, fixtures + injection tests re-expressed), aura-cli (param-generic render, sample + goldens, swap moved to the compiled view). Compile gates are crate-scoped so each task's gate is satisfiable with all its callers threaded in-task. refs #31 |
||
|
|
e9eea1ada3 |
spec: 0016 amend — value-empty render surface + vestigial schema removal (#31)
Plan-recon surfaced two surfaces the first draft under-scoped; resolved here after a user design decision on the render form. - Blueprint rendering (C22): a value-empty blueprint has no bound values, so the `aura graph` blueprint view can no longer label a leaf `SMA(2)`. LeafFactory gains `name` + `label()`, and the blueprint view renders the param-generic form `SMA(length)` (type + tunable knob names, no values), chosen over a bare `SMA` to surface the knobs the milestone is about. The compiled view (post-build flat nodes) is unchanged — it still labels valued. Correct C22 reading: structure before, values after. - Vestigial pre-build interface removed: `Composite::schema` / `BlueprintNode::schema` derive an item interface from built interior leaves; a value-empty leaf has none, and both methods have no live caller (compile resolves every interface structurally on the built flat nodes). Removed with their unit test. This is why the factory carries no io skeleton — the build-then-wire decision stands, no schema duplication. - OQ3: the swapped-sample mis-wiring moves from the builder args to the injected vector; its observability moves to the compiled view (the blueprint view is param-generic and identical for both orderings). Grounding-check re-run: PASS (LeafFactory::label internally consistent; the no-live-caller claim for the removed methods verified; blueprint-view vs compiled-view goldens correctly partitioned). refs #31 |
||
|
|
b9edeaf2db |
spec: 0016 param-set injection — value-empty blueprints bound by a vector (#31)
Cycle B of milestone "The World — parameter-space & sweep". A blueprint's tunable values are injected at bootstrap rather than baked into the builder: a leaf becomes a param-generic recipe (LeafFactory: params -> sized node), and a new build-then- wire compile path binds a positional Scalar vector slot-by-slot against param_space(), building each node through its own constructor. Ratified design (brainstorm): value-empty B over mutate-in-place and over the default-bearing variant. The value lives only in the injected vector (no baked default), so the blueprint stays a pure param-generic recipe (C19); injected values flow through the single new() sizing/validation gate; and because compile_with_params consumes the vector in the same depth-first order param_space() reports, the two share one traversal — subsuming #34's dual-traversal drift hazard. Scope: one vector -> one instance; LeafFactory in aura-core; bootstrap_with_params/ compile_with_params; CompileError::{ParamKindMismatch, ParamArity}; Scalar::as_i64/ as_f64 accessors; fixtures/CLI/bit-identity re-expressed against the vector. Deferred: sweep enumeration (#32), domain validation (#32/C20), single-run authoring convenience (#35). Gates: grounding-check PASS (8 current-behaviour assumptions ratified against green tests; the sole BLOCK — a missing Scalar value accessor — resolved by adding it as in-scope surface). Parse gate a no-op (profile declares no spec_validation). refs #31 |