ed1d22bbfa2d38d1dbf1b4ca278357631b776a78
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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
|
||
|
|
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 |
||
|
|
931109df58 |
feat(aura-core,aura-std,aura-engine): declare node tunable params (#30)
Cycle A of milestone 'The World — parameter-space & sweep'. A node now declares its tunable parameters in its C8 schema, and a blueprint aggregates them into one flat, inspectable param-space — the root that unlocks the C12 orchestration axes (#31 bind, #32 sweep), filling the gap C8/C23 name 'deliberately not in the schema yet'. - aura-core: ParamSpec { name: String, kind: ScalarKind } as a third schema- declaration type; NodeSchema gains a third field 'params'. name is String (not &'static like FieldSpec) because a vector knob carries a runtime index and aggregation prefixes the composite path. - aura-std: Sma declares [length:I64], Exposure [scale:F64], LinComb expands to N flat [weights[i]:F64] (N = its input arity, topology-fixed per C19); Sub/Add/ SimBroker/Recorder declare none (pip_size is metadata, C10/C15; Recorder is wiring). - aura-engine: Blueprint::param_space() walks the graph-as-data depth-first in lower_items order, path-qualifying via the already-public Composite::name() — a read-only projection (C9). compile/inline_composite/lower_items are untouched, so the compilat stays bit-identical (composite_sma_cross_runs_bit_identical_to_hand_wired and the golden render tests stay green). Design: param identity is positional (slot after the deterministic inline order, C23 'by index not name'); the path-qualified name is a non-load-bearing debug symbol — same-type siblings in one composite share a name, uniqueness is at the slot. Flat over a structured arity-bearing ParamSpec because flattening is unavoidable (a sweep enumerates a flat point-space) and structure-in-the-runtime is the nested-composite reading C23 rejects (see spec 0015 for the full rationale). Scope is declaration + aggregation + inspection only; binding (#31), sweep enumeration (#32), search-range, validity-constraint, and default-range/slider are deferred. An E2E test pins the load-bearing C23/#31 invariant: param_space() slot order mirrors compile()'s flat-node param order, kind-by-slot, on the SMA-cross harness. fieldtests/ (excluded crates) left as frozen snapshots. Verified: cargo build/test --workspace green (64 tests), clippy --all-targets -D warnings clean; compile/inline diff empty. closes #30 |
||
|
|
0a855c3943 |
feat(aura-cli): aura graph renders a wired graph as an ASCII DAG (#13)
Make a wired graph introspectable so a mis-wiring becomes visible. Two
selectable views, both authored from one built-in sample blueprint:
aura graph clustered blueprint view — composites drawn as named
ascii-dag cluster boxes (pre-inline, C9)
aura graph --compiled flat compilat view — composite boundaries dissolved
(C23); the graph the run loop actually runs
The payoff is intrinsic, param-carrying node labels: two SMAs read SMA(2) /
SMA(4), so a swapped fast/slow input reads back differently. This is realized
by a `label()` default method on the core Node trait — a non-load-bearing
render symbol the run loop never reads (wiring is by index), the symbol C23
already reserves citing #13. Recorded as a C8 refinement in the ledger.
Rejected the alternatives in brainstorm: a separate Describe trait (forces a
combined trait-object dance for a label the ledger calls non-load-bearing) and
extrinsic parallel labels (decoupled from the node, so an author can label the
slow SMA "fast" and mask the very bug the render exists to surface).
Mechanism:
- aura-core: Node::label() default method (additive, object-safe, single-line).
- aura-std: per-node overrides — SMA(n)/Exposure(s)/SimBroker(p) carry params;
Sub/Add/LinComb/Recorder are bare (their identity is not a mis-wiring axis).
- aura-engine: Composite gains an authored `name` (cluster title; dissolves at
inline) + read-only graph-as-data accessors on Blueprint/Composite. No
external dependency — the engine stays dependency-pure (C16); ascii-dag lives
only in aura-cli. The label-free index-wired compilat (C23) is unchanged.
- aura-cli: ascii-dag v0.9.1 + a graph.rs adapter (Vertical mode; labels
materialized into an owned Vec<String> that outlives the borrow-based Graph).
`aura run` is untouched (the sample duplication is dedup idea #14).
Tests: a concern-defining test (swapped sample renders != correct), structure
pins (cluster present in blueprint view, absent in compiled view), per-node
label disambiguation, and two frozen byte-goldens of the deterministic render.
The cycle-0012 bit-identical and run-sample non-regression tests stay green.
Verified by the orchestrator (not the agent report): cargo build --workspace
clean; cargo test --workspace all green; cargo clippy --workspace --all-targets
-D warnings clean; both views run live and render as expected.
closes #13
|
||
|
|
521a16e56f |
docs(aura-std): document Add/LinComb firing policy + multi-row-per-ts shape
Resolves the two spec_gaps from the cycle-0008 fieldtest
(docs/specs/fieldtest-0008-sum-combinators.md), the same class the 0007 fieldtest
raised for SimBroker (and which
|
||
|
|
84130c2cab |
feat(aura-std): Add + LinComb sum combinators
aura-std shipped Sma, Sub, Exposure, SimBroker but no sum, so the north-star
"combine one signal with another" research move (C10) could not be expressed
from shipped blocks — the cycle-0007 fieldtest had to hand-author a project-local
Add2. This adds the missing combinator(s):
- Add — two-input f64 sum (a + b), the parameterless companion to Sub. Mirrors
sub.rs modulo the operator.
- LinComb { weights } — N-input weighted sum (Σ wᵢ·xᵢ). The weights are the
node's tunable parameters (C8/C12) and fix its arity (weights.len() inputs);
this is the form the north-star "combine A and B *with weights*" reaches for.
LinComb([1,1]) is Add; LinComb([1,-1]) is Sub.
Both withhold output (None) until *all* inputs are present — consistent with Sub,
and causally clean: a cold input leg is never silently folded in as 0.0.
LinComb::new panics on empty weights (build-time param error, like Sma::new).
Both ship because each is independently reached-for: Add for readability symmetry
with Sub, LinComb for the weighted/tunable combination — mirroring the project's
already-shipped choice to keep Sub as a named node beside a general form.
Hand-driven unit tests in the established aura-std style (5 new): Add sum, the
Add == LinComb([1,1]) identity, the N>2 warm-up, and the empty-weights panic.
Verified: cargo test -p aura-std (14 passed), clippy --all-targets -D warnings
clean, RUSTDOCFLAGS="-D warnings" cargo doc -p aura-std --no-deps clean.
closes #11
|