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
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
//! weights are construction parameters that configure the node and fix its
|
||||
//! arity (`weights.len()` inputs); they are also the combination's tunable
|
||||
//! params, declared in the schema (cycle 0015) as `weights[0..N]` — N flat
|
||||
//! indexed `F64` knobs that `Blueprint::param_space` aggregates (C8/C12/C19).
|
||||
//! indexed `F64` knobs that `Composite::param_space` aggregates (C8/C12/C19).
|
||||
|
||||
use aura_core::{
|
||||
Ctx, FieldSpec, Firing, Node, NodeSchema, ParamSpec, PortSpec, PrimitiveBuilder, Scalar,
|
||||
|
||||
+61
-11
@@ -192,10 +192,15 @@ set and SoA. The open set is composites (schemas of columns), not scalar types.
|
||||
Type-erasure at the edge is also forced by the cdylib boundary (C13).
|
||||
|
||||
### C8 — The node contract
|
||||
**Guarantee.** A node implements `schema()` (declares each input's scalar type,
|
||||
required lookback depth, and firing group, **and the node's own tunable
|
||||
parameters — typed, with ranges**, which aggregate into the blueprint's
|
||||
param-space the optimizer sweeps, C12/C19/C20) + `eval(ctx) -> Option<&[Scalar]>`. The
|
||||
**Guarantee.** A node has a **signature** — its `NodeSchema`: each input's scalar
|
||||
type and firing group, its output record, **and the node's own tunable parameters —
|
||||
typed, with ranges**, which aggregate into the blueprint's param-space the optimizer
|
||||
sweeps (C12/C19/C20). The signature is **declared pre-build on the value-empty
|
||||
recipe** (C19), so the whole interface is legible without building (cycle 0024).
|
||||
The built node implements `lookbacks()` — the per-input buffer depth, the one
|
||||
quantity that may depend on an injected param (e.g. an `Sma`'s window = its
|
||||
`length`), read once at bootstrap to size the windows — and `eval(ctx) ->
|
||||
Option<&[Scalar]>`. The
|
||||
engine provides read-only, zero-copy windows into each input's SoA ring buffer
|
||||
(`ctx.f64_in(x)[k]`, sized at wiring); a node may *additionally* keep its own
|
||||
mutable series for derived/intermediate state. `None`/Void return = filter /
|
||||
@@ -248,7 +253,8 @@ not part of the C8 dataflow contract — adding it changes no run behaviour.
|
||||
**Realization (cycle 0015 — param declaration).** The tunable-parameter half of
|
||||
this contract is now realized: a node declares its knobs in `schema()` as
|
||||
`params: Vec<ParamSpec>` (`ParamSpec { name: String, kind: ScalarKind }`), and
|
||||
`Blueprint::param_space()` aggregates them into one flat, path-qualified list — a
|
||||
`Composite::param_space()` (cycle 0024; was `Blueprint::param_space()`) aggregates
|
||||
them into one flat, path-qualified list — a
|
||||
read-only projection of the graph-as-data (C9), mirroring the inline order
|
||||
(C19/C23) so a param's slot matches the later flat-node order. Two refinements to
|
||||
the guarantee's "typed, with ranges": (1) the declaration carries `name` + `kind`
|
||||
@@ -262,10 +268,31 @@ uniqueness is at the slot. A vector knob (`LinComb.weights`) expands to `N` flat
|
||||
`bool` (a `timestamp` knob is a structural axis, C20, never a numeric sweep param).
|
||||
Binding a value to a slot landed in cycle 0016 (#31, see C19/C23); enumerating a
|
||||
sweep (#32) is the deferred next layer. The 0016 binding also moved the param
|
||||
declaration's *authoring* home: a value-empty blueprint leaf is a `LeafFactory`
|
||||
recipe whose `params()` is read pre-build, while the built node's `schema().params`
|
||||
still reports the same slots — the two are kept in lockstep by a per-node test
|
||||
(a duplication filed as debt, #36).
|
||||
declaration's *authoring* home into the value-empty recipe, whose `params()` is read
|
||||
pre-build. In 0016–0023 the built node's `schema().params` still reported the same
|
||||
slots, kept in lockstep by a per-node test (a duplication filed as debt, #36); **cycle
|
||||
0024 dissolved this** — the signature is declared *once* on the recipe and the built
|
||||
node no longer carries `schema()` (#36 closed). See the C8 cycle-0024 realization.
|
||||
|
||||
**Realization (cycle 0024 — the signature lives in the blueprint, #43/#36).** The
|
||||
node's whole declared interface — its `NodeSchema` (input scalar types + firing,
|
||||
output record, params) — now lives **once**, on the value-empty recipe
|
||||
`PrimitiveBuilder` (ex-`LeafFactory`), read pre-build by `param_space()`, the
|
||||
compile-time structural validation, and the render. This closes two debts: **#43**
|
||||
(a value-empty recipe used to declare *no* input/output interface pre-build — only
|
||||
params) and **#36** (params declared twice, recipe vs built node, kept in lockstep
|
||||
by a per-node test — those 8 tests are deleted, the duplication structurally gone).
|
||||
The split that makes this work: a node's signature is **fully static** per blueprint
|
||||
(input kinds/firing, output fields, params — verified across the roster; a variable-
|
||||
arity node like `LinComb` takes its arity as a *recipe argument*, not an injected
|
||||
param), so it can be declared without building; the **one** param-dependent quantity,
|
||||
an input's buffer **lookback** depth, is no longer in the signature but answered by
|
||||
`Node::lookbacks() -> Vec<usize>`, read only by bootstrap to size the windows.
|
||||
`Node::schema()` is therefore **removed** — the signature is pre-build data, not a
|
||||
built-node method. `BlueprintNode::signature()` answers uniformly for both arms (a
|
||||
primitive returns its recipe's schema; a composite *derives* it from the interior:
|
||||
role kinds in, re-exported field kinds out, aggregated params), so "every node has a
|
||||
signature in the blueprint" holds for composites too.
|
||||
|
||||
### C9 — Fractal, acyclic composition
|
||||
**Guarantee.** A composite is itself a `Node` that wires a sub-graph and exposes
|
||||
@@ -594,7 +621,11 @@ sees a generic vector of typed ranges)" and C19's "factory `params → sized nod
|
||||
*literally*: a blueprint leaf is **value-empty** — `BlueprintNode::Leaf` holds a
|
||||
`LeafFactory { name, params, build }` recipe, not a built node — and the value lives
|
||||
only in the injected vector (no baked default), so the blueprint stays a pure
|
||||
param-generic recipe. `Blueprint::bootstrap_with_params(Vec<Scalar>)` /
|
||||
param-generic recipe. (Renamed in cycle 0024: `BlueprintNode::Primitive` holds a
|
||||
`PrimitiveBuilder { name, schema, build }` — the recipe now carries the full
|
||||
signature, see the C8 0024 realization; `bootstrap_with_params`/`compile_with_params`
|
||||
moved onto `Composite` when `struct Blueprint` collapsed into it, see the C19 0024
|
||||
realization.) `bootstrap_with_params(Vec<Scalar>)` /
|
||||
`compile_with_params` **build each leaf through its own constructor** (the single
|
||||
sizing/validation gate) from its kind-checked slice **while lowering** (build-then-
|
||||
wire), consuming the vector slot-by-slot in the *same* depth-first walk
|
||||
@@ -607,7 +638,8 @@ the **compilat stays bit-identical** for a given point (C23, the correctness
|
||||
invariant). The value *domain* (e.g. `length ≥ 1`) stays the constructor's own
|
||||
`assert`; the search-range is still the run's (#32/C20). One value-empty leaf
|
||||
detail for C22: the blueprint view (pre-run, param-generic) labels a leaf by **bare
|
||||
type** (`LeafFactory::label` → `[SMA]`) — the value-bearing `SMA(2)` of C8's render-
|
||||
type** (`PrimitiveBuilder::label`, was `LeafFactory::label`, → `[SMA]`) — the
|
||||
value-bearing `SMA(2)` of C8's render-
|
||||
label refinement now appears only in the *compiled* view (built nodes, `Node::label`).
|
||||
**Realization (cycle 0017 — blueprint render = main graph + definitions).** The
|
||||
`aura graph` blueprint view (C9 graph-as-data, #13) renders the **authored
|
||||
@@ -631,6 +663,24 @@ definitions pass recurses). The interactive *enter/focus* counterpart (a composi
|
||||
collapsed to a navigable node) is the playground's, parked as a separate concern
|
||||
(#37); the static CLI keeps the all-at-once definitions form (#38).
|
||||
|
||||
**Realization (cycle 0024 — the root is the fully-bound composite; the compilat is
|
||||
a named type).** `struct Blueprint` is **deleted**: the root graph IS a `Composite`,
|
||||
and `compile_with_params`/`bootstrap_with_params`/`param_space` are its methods.
|
||||
What distinguished the root — its bound data sources — is now a property of its input
|
||||
roles: `Role` carries `source: Option<ScalarKind>` (`None` = an open interior port,
|
||||
wired by the enclosing graph; `Some(kind)` = a bound ingestion feed). A composite is
|
||||
**runnable iff every root role is bound** (C3: sources bind at ingestion only); an
|
||||
open root role is a compile-time `CompileError::UnboundRootRole`. So the "main graph"
|
||||
is no longer a separate kind — only the composite all of whose roles are
|
||||
source-bound, governed by the same conditions as any other node. Compilation now
|
||||
targets a **named type**: `compile` validates structurally **pre-build** (via
|
||||
`signature()`, no node constructed — an ill-typed wiring is caught before any build
|
||||
closure fires) and emits `FlatGraph { nodes, signatures, sources, edges }` — the
|
||||
C23 compilat, now first-class — which `Harness::bootstrap` consumes (kinds/firing
|
||||
from the carried signatures, buffer depth from `lookbacks()`). The per-flat-node
|
||||
signature travels beside the node, so `bootstrap` reads it without a built-node
|
||||
`schema()` call (which no longer exists, see the C8 0024 realization).
|
||||
|
||||
### C20 — Strategy ↔ harness; the harness is the root sim graph
|
||||
**Guarantee.** A **strategy** is a reusable composite-node blueprint (C9):
|
||||
broker-, data-, and viz-independent, with inputs declared as named **roles**
|
||||
|
||||
Reference in New Issue
Block a user