Commit Graph

4 Commits

Author SHA1 Message Date
Brummel 77a1d26017 feat(core): the node contract — Node, schema/eval, Ctx, and a worked SMA
Cycle 0002, the second walking-skeleton slice on top of the 0001 substrate:
the interface every node forever implements (C8), proven end-to-end by a real
node with no engine present.

- `Node` (aura-core) — `schema() -> NodeSchema` declares inputs (kind +
  lookback) and the single output kind; `eval(&mut self, Ctx) -> Option<Scalar>`
  computes one cycle's output (`None` = filter / not-yet-warmed-up). `&mut self`
  so a node may keep its own derived state.
- `Ctx<'a>` (aura-core) — a `Copy` borrow-wrapper handing `eval` zero-copy,
  financial-indexed `Window`s per input (`ctx.f64_in(i)[k]`, index 0 = newest).
  A kind mismatch panics ("engine bug") — wiring guarantees the kind, so a
  mismatch can only mean the wiring layer is broken; this keeps node-author code
  clean (`w[k]`, not `w?[k]`).
- `AnyColumn::as_f64/as_i64/as_bool/as_ts` (aura-core) — the read-side mirror of
  the existing `as_*_mut`, the mechanism `Ctx` uses to get a typed window from a
  type-erased edge. Closes the read-side gap the cycle-0001 audit recorded.
- `Sma` (aura-std) — the skeleton's first real block: a producer node computing
  the moving mean of one f64 input, emitting `None` until warmed up. Authored in
  a downstream crate (proving aura-core's contract is usable across the crate
  boundary) and driven by a hand-written test that mimics exactly what the sim
  loop will later generalize: push fresh input, eval, collect.

Deliberately deferred (spec 0002 "Out of scope", recorded as decisions): the
firing policies (C6 — InputSpec carries no firing field yet), the sim loop (C4)
and freshness gating (C5), schema-level tunable params (C12/C19), and the
no-output sink refinement (C8 consumer side).

Gates green: cargo build/test (20: 18 aura-core + 2 aura-std)/clippy -D warnings
all clean; surface-purity grep (no dyn-Any / Rc / RefCell) clean.

refs walking-skeleton
2026-06-03 12:17:33 +02:00
Brummel a4760497ec feat(core): the streaming substrate — scalars, columns, type-erased edges
Cycle 0001 of the walking-skeleton milestone: the aura-core data substrate
everything streams through.

- scalar.rs: the closed four-type set — Scalar (Copy POD carrier), ScalarKind
  (the kind tag), Timestamp (i64 epoch-ns newtype). No boxed Value, no dyn Any,
  no heap (C7).
- column.rs: Column<T>, a fixed-capacity bounded-lookback ring pre-sized at
  construction (no hot-loop realloc, C8), financial-indexed (index 0 = newest),
  carrying a monotonic run_count freshness primitive (C5). Window<'_,T> is its
  zero-copy read view with newest-at-0 Index. No RefCell/Rc — a sim is
  single-threaded (C1), so push is &mut and read is &.
- any.rs: AnyColumn, the type-erased edge over the four Column kinds. push()
  kind-checks at the edge (wiring time) and rejects a wrong-kind value with
  KindMismatch, leaving the column untouched; the hot path bypasses the check
  via the monomorphic as_*_mut accessors (C7).
- error.rs: KindMismatch { expected, got }, the guard error.

Sharpens the RustAst rtl/ reference (VecDeque + RefCell + boxed Value) into a
fixed ring of Copy scalars with direct dispatch. Node trait, Ctx, firing
policies, and the sim loop are deferred to subsequent cycles.

Verified independently: cargo build --workspace (0 warnings), cargo test
--workspace (14 aura-core tests green incl. ring-wrap, run_count monotonicity,
zero-copy window, and the wrong_kind_push_is_rejected guard), cargo clippy
--workspace --all-targets -D warnings (clean), and a surface-purity grep
confirming no RefCell/Rc/dyn Any on the substrate.

refs #0001-core-streaming-substrate

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:42:21 +02:00
Brummel 9eae43d308 docs: C19/C20 — bootstrap + strategy/harness; a project is a Rust program
Anchor the implementation-design branch: C19 (construction is a bootstrap phase — param-generic blueprint -> frozen instance; recursive up to the harness; params size/configure but never change topology). C20 (strategy = reusable context-free composite blueprint with role inputs + position-event output; harness = the root sim graph and C1's disjoint unit, with structural axes = experiment matrix vs tuning params = sweep; both strategy AND experiment authored in Rust via builder APIs, not a config DSL). Extend C8 (schema declares tunable params+ranges), C16 (a project is a Rust crate: cdylib of node/strategy/experiment blueprints + static Aura.toml; hosted by aura during research, frozen to a binary for deploy), C17 (all logic is Rust — nodes/strategies/experiments; Aura.toml = static context only), C12 (frozen topology = a harness instance; structural matrix is the outer axis). Add CLAUDE.md invariant 11; refresh project-layout.md (experiments/ dir, Rust experiments, day-in-the-life).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 09:54:44 +02:00
Brummel 744c2f31a8 chore: scaffold aura workspace and wire the skills dev-cycle
Cargo workspace aura-core -> aura-engine -> aura-cli (bin `aura`) plus nodes/ for hot-reloadable cdylib node crates. Crate bodies are intentionally API-free; types arrive from the first spec. Adds the skills profile (.claude/dev-cycle-profile.yml), the project CLAUDE.md with the eight domain invariants, and the design-ledger skeleton.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 01:31:14 +02:00