Commit Graph

19 Commits

Author SHA1 Message Date
Brummel 4fac529de0 fieldtest: milestone walking-skeleton — 3 e2e scenarios, delivers end-to-end
Milestone-scope fieldtest (the functional leg of the Walking-skeleton
milestone-close gate), from the public interface only. Three end-to-end
scenarios, all green:
- the newcomer CLI path: `aura run` -> single-line {manifest,metrics} JSON,
  exit 0, byte-identical twice (C1), non-degenerate trace (C22), bad-args ->
  exit 2;
- the real-data thread: real AAPL.US 2006-08 M1 bars -> load_m1_window ->
  close_stream -> SMA-cross -> Exposure -> SimBroker -> summarize -> RunReport,
  deterministic AND populated;
- epoch-ns coherence: C3 normalization holds ingest -> run -> sink.

Roll-up: the milestone DELIVERS its promise end to end (ingest -> one signal ->
exposure -> sim-optimal broker -> pip-equity metric -> structured RunReport,
deterministic, populated) on BOTH the synthetic and real-data paths. 0 bugs.

Headline concern (verified by the orchestrator): issue #19's premise is WRONG at
the shipped SMA(2)/SMA(4) demo config — 21 AAPL.US bars warm the cross and
produce a populated trace (total_pips=-1.5, max_drawdown=65.5, 6 sign flips),
not all-zero. The degeneracy #19 saw was deep-SMA/param-dependent, not intrinsic
to the symbol. #19 to be re-scoped. Other findings: `aura run <junk>` exit 0
(already #16), `aura --help` lands on the exit-2 error path (friction), SimBroker
two-f64-slot order unchecked at bootstrap (documented footgun) — both filed.
2026-06-04 22:25:01 +02:00
Brummel 77ad977623 fieldtest: cycle-0011 — 3 examples, 5 findings
Per-cycle fieldtest of the aura-ingest ingestion boundary (issue #7), from the
public interface only. 3 examples (transpose/normalize core; close_stream ->
deterministic harness run with epoch-ns end-to-end; load_m1_window over real
AAPL.US 2006-08 bars + None paths), all green. 0 bugs, 0 friction.

Two spec_gaps named for follow-up (neither a code defect; both filed to the
tracker):
- load_m1_window returns Some(empty M1Columns) — not None — for an in-coverage
  but bar-empty window. The rustdoc's "None if no data in [from_ms,to_ms]" reads
  bar-level but the realized boundary is file-level (it inherits data-server's
  file-skip None). A consumer matching None == "no bars" is wrong for the
  in-coverage-empty case. -> tighten the load_m1_window rustdoc (one line).
- AAPL.US (the carrier/integration-test symbol) has only ~21 M1 bars/month, so
  the SMA-cross never warms and the end-to-end run yields all-zero (degenerate
  but valid) metrics. The boundary is correct (C2 warm-up); the milestone's
  shipped demo data is too thin to show a non-degenerate trace. -> weigh against
  C22's "newcomer sees a populated trace" before the Walking-skeleton close
  (document expected density or name a denser demo symbol/window).
2026-06-04 22:04:48 +02:00
Brummel df0574a75d spec: 0011 data-server M1 ingestion at the one merge boundary
First real data source (refs #7, Walking-skeleton milestone). A new
`aura-ingest` crate pulls data-server as a cargo git dependency, transposes
its AoS M1Parsed records into SoA base columns (C7), normalizes Unix-ms to
canonical epoch-ns at the one ingestion boundary (C3), and feeds the existing
k-way merge a real close-price stream so a backtest runs over real bars (C1).

Decisions captured:
- Eager materialization (not a lazy/shared Source abstraction): C12's cross-sim
  Arc<[T]> sharing has no consumer until the multi-sim orchestration cycle, so
  building it now would be speculative infra; deferred, transpose logic carries
  over.
- aura-ingest is the external-dependency firewall: data-server transitively
  pulls chrono+regex+zip; isolating it in its own crate keeps core/std/engine
  zero-external-dep. cargo test --workspace now needs a populated cargo cache.
- Scope: boundary + tests only, no aura run CLI arg surface (would force the
  unsettled #16 arg-parse decision); M1 first, tick deferred.

grounding-check returned BLOCK on the single load-bearing external assumption
(the data-server public API) — structurally unratifiable by an aura-side test
because data-server is brand-new this cycle; all 9 aura-internal assumptions
were ratified by named green tests. Overridden after verifying data-server's
API against its actual source (lib.rs DataServer::new/has_symbol/
stream_m1_windowed/next_chunk/DEFAULT_DATA_PATH; records.rs M1Parsed fields,
types, Copy), per the agent's documented override path. User-approved.
2026-06-04 21:41:58 +02:00
Brummel f68258b044 fieldtest: cycle-0010 — 3 examples, 6 findings
Public-interface-only field test of the walking-skeleton closing seam (#8):
the `aura run` CLI and the reusable aura-std::Recorder sink. A standalone
consumer crate (path-deps on the three engine crates, as a C16 project would)
drives the real binary as a subprocess and wires Recorder via the raw
Harness::bootstrap API.

Examples (all built from HEAD and ran green):
- c0010_1: drive `aura run` as a downstream CLI/jq consumer — single-line JSON
  report, byte-identical across two runs (C1), bad-args → exit 2 + exact usage on
  stderr with empty stdout.
- c0010_2: wire Recorder onto Sma(3) via raw bootstrap, drain the mpsc::Receiver
  — rows match the rustdoc warm-up model exactly.
- c0010_3: Recorder over [I64, Bool, Timestamp] — the four-kind claim (never
  exercised by the CLI's f64-only path) holds, verified from rustdoc alone.

Findings: 0 bugs, 4 working, 1 spec_gap, 1 friction.
- [spec_gap] `aura run <trailing-arg>` is accepted (exit 0), not rejected — the
  arg parse keys only on the first token being `run` and ignores the rest. The
  cycle_scope's "any other or missing subcommand -> exit 2" does not unambiguously
  cover `run <junk>`; the binary chose the lenient reading. Tracked for a
  ratify-or-tighten decision.
- [friction] verifying the documented {manifest, metrics} JSON nesting needs a
  hand-rolled string walker — the zero-dep consumer has only to_json() and no
  typed read-path. Low-priority tidy.

Both non-bug findings filed to the forward queue; neither blocks the cycle.
2026-06-04 20:55:28 +02:00
Brummel 4a78170dfb spec: 0010 aura run CLI
Cycle 0010, the Walking-skeleton milestone's closing seam: an `aura run`
subcommand that bootstraps a built-in sample harness (synthetic source →
SMA-cross → Exposure → SimBroker → recording sinks), runs it
deterministically, and prints the cycle-0009 metrics+manifest report as
canonical JSON to stdout.

The crux the cycle resolves: no recording sink node ships today (recording
lives only as #[cfg(test)] fixtures), and Harness::run returns () with a sink
as the only data-out path. So this cycle first ships a reusable
aura-std::Recorder (a pure consumer holding an mpsc::Sender, purity-preserving
per C7), then wires the CLI on top.

Load-bearing decisions, user-approved at the brainstorm gate:
- Recorder ships in aura-std (universal block, C16), not engine or CLI-local.
- Sample harness is authored as a plain Rust constructor over the raw
  Harness::bootstrap API (C17/C20) — the open experiment-builder DSL thread is
  deliberately NOT committed this cycle.
- Zero-dependency CLI: hand-parsed args (no clap); manifest commit from
  option_env!("AURA_COMMIT") defaulting to "unknown" (build.rs git capture
  deferred).

Grounding-check PASS (all load-bearing codebase assumptions ratified by green
tests). Non-goals: experiment-builder DSL, aura new, Aura.toml schema, the
data-server source (#7), build.rs git capture.

refs #8
2026-06-04 20:29:29 +02:00
Brummel a982b96ecc fieldtest: cycle-0009 — 4 examples, 6 findings
First fieldtest of the run-metrics + manifest report surface. A standalone
downstream-consumer crate (fieldtests/cycle-0009-run-metrics/) path-depends on
the engine crates and exercises the post-0009 surface from the public interface
only (rustdoc + ledger + glossary + project layout, never crates/*/src).

Primary axis empirically met: the north-star "a run emits metrics + manifest"
move is reachable from rustdoc alone — drain two recording sinks -> f64_field ->
summarize -> RunManifest -> to_json, metrics matching the hand model on the first
run, deterministic across reruns.

Findings: 0 bugs, 1 friction, 1 spec_gap, 4 working.
  - working x4: north-star reachable from rustdoc; SimBroker firing/slot docs (a
    resolved 0007 gap) now carry the example; summarize metric definitions exact
    on six degenerate inputs (incl. negative-curve drawdown + flat-as-sign-0);
    f64_field panics precise and well-located.
  - spec_gap: to_json's JSON key names + {manifest,metrics} nesting are not on
    the public surface — a consumer parsing the JSON (C18 registry, the deferred
    aura run printer) cannot author against it from rustdoc alone.
  - friction: to_json renders whole-valued f64 without a decimal point (3.0 ->
    "3"), so one f64 field appears as integer or decimal token within one schema.

Both doc-level findings are the same doc pass and matter mainly for the deferred
aura run (#8) and the C18 registry that will parse this JSON. Spec feeds the next
plan as reference.

refs #6
2026-06-04 19:06:13 +02:00
Brummel bf72924db7 spec: 0009 run metrics + manifest
Cycle 0009 (Walking skeleton milestone, issue #6): a post-run pure-function
reduction over the recorded pip-equity + exposure streams into summary metrics
(total pips, peak-to-trough drawdown, exposure sign-flip count) plus a
caller-supplied RunManifest (commit, params, data-window, seed, broker), paired
as RunReport with canonical hand-rolled zero-dep JSON (C14). Lives in a new
aura-engine report module; no engine/Harness/node-contract change.

The reduction is post-run, not a node (C8 caps a node at one record per eval
with no end-of-run eval); matches C18's manifest+metrics-per-run-from-day-one.
The `aura run` subcommand that prints the report is deferred to #8.

Grounding-check PASS (all load-bearing assumptions ratified by green tests /
authoritative sources). Spec-validation parse pass is a documented no-op (no
parser configured for the profile).

refs #6
2026-06-04 18:42:55 +02:00
Brummel 90e298d3b4 fieldtest: cycle-0008 — 5 examples, 6 findings
First fieldtest of the sum combinators. A standalone downstream-consumer crate
(fieldtests/cycle-0008-sum-combinators/) path-depends on the engine crates and
exercises the post-0008 surface from the public interface only (rustdoc + ledger
+ glossary + project-layout, never crates/*/src).

Primary axis empirically met: the north-star two-signal combine move now uses the
shipped Add (Add::new() dropped in exactly where the 0007 fixture hand-authored
an Add2) — the 0007 boilerplate is retired, end to end through SimBroker to a
deterministic recorded pip curve.

Findings: 0 bugs, 1 friction, 2 spec_gaps, 3 working.
  - working ×3: Add2 retired; LinComb weighted/variadic sums exact (<1e-12);
    warm-up barrier + empty-weights panic as documented.
  - spec_gap: Add/LinComb per-input firing policy (Firing::Any / mode-A as-of
    join) absent from the public surface — same class as the 0007 SimBroker gap.
  - spec_gap: a fired combinator emits one row per *cycle*, so a heterogeneous
    same-timestamp multi-source trace can carry >1 row per timestamp (correct per
    C4/C5, undocumented at this surface).
  - friction: nested consumer crate still needs the empty [workspace] table
    (carried from 0006/0007; #9 closed the docs half; folds into aura new).

Spec feeds the next plan as reference.
2026-06-04 18:21:57 +02:00
Brummel 288e75e7fd spec: 0008 sum combinators (Add + LinComb)
Ships the missing sum combinator(s) in aura-std so the north-star combine move
(C10) is expressible from shipped blocks. Two nodes: Add (parameterless two-input
f64 sum, companion to Sub) and LinComb { weights } (N-input weighted sum, weights
as tunable params + arity, C8/C12). Both withhold output until all inputs are
present (no implicit cold-leg 0.0).

Resolves the cycle-0007 fieldtest [friction]: the consumer had to hand-author a
project-local Add2 to combine two signals.

refs #11
2026-06-04 18:01:09 +02:00
Brummel f3cd2e1320 fieldtest: cycle-0007 — 4 examples, 7 findings
First fieldtest of the signal-quality loop. A standalone downstream-consumer crate
(fieldtests/cycle-0007-signal-quality/) path-depends on the engine crates and
exercises the post-0007 surface from the public interface only (rustdoc + specs +
ledger + glossary, never crates/*/src):

  1 single-signal quality backtest, end to end (SMA-cross -> Exposure -> SimBroker
    -> Recorder pip curve)
  2 Exposure clamp + sizing (hard ±1 saturation, sign preserved)
  3 sim-optimal integration: short-on-falling pays positive pips; pip_size=2 curve
    exactly halves pip_size=1
  4 north-star combine-two-signals (two MA-cross spreads summed into one exposure)

Findings: 3 working (carry-on), 2 spec_gap, 2 friction.
  - spec_gap: SimBroker firing policy + cold-exposure->0.0 warm-up emission shape
    not on the public surface (only in the feat commit body).
  - spec_gap: SimBroker input slot order (0=exposure, 1=price) only in C10 prose /
    commit body; a swapped wiring is not caught at bootstrap (both f64).
  - friction: the north-star "combine two signals" move needs a sum/LinComb
    combinator aura-std does not ship (hand-authored Add2 in the fixture).
  - friction: standalone consumer crate still needs the empty [workspace] table
    (carried from cycle-0006; tracked as #9).

Spec at docs/specs/fieldtest-0007-signal-quality.md feeds the next plan.

refs #4 #5

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:30:13 +02:00
Brummel fe77b13e73 spec: 0007 signal-quality loop (exposure stream + sim-optimal broker)
Cycle 0007 bundles Gitea #4 (exposure node) and #5 (sim-optimal broker) — the two
halves of the signal-quality loop, the realization of the C10 reframe. Ships two
aura-std nodes: Exposure { scale } (clamp(signal/scale, -1, +1)) and
SimBroker { pip_size } (causal prev_exposure * dprice / pip_size integration, no
look-ahead). Engine unchanged — pure node authoring on the frozen substrate.

grounding-check: PASS (all substrate assumptions ratified by green tests).

refs #4 #5

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:02:33 +02:00
Brummel 0bf15cb069 fieldtest: cycle-0006 sink recording — 5 examples, 6 findings
First fieldtest of the project. A standalone downstream-consumer crate
(fieldtests/cycle-0006-substrate/) path-depends on the engine crates and
exercises the post-0006 substrate from the public interface only (rustdoc +
specs + ledger, never crates/ source):

  1 custom recording node via the Node contract + Ctx::now()
  2 fan-out/fan-in DAG, 3-arg bootstrap, run() -> ()
  3 two interior streams recorded from one run (the cycle headline)
  4 byte-identical recorded output across two runs (C1 determinism)
  5 mis-wired recording edge rejected (KindMismatch) at bootstrap

Findings: 3 working (carry-on), 2 friction, 1 spec_gap.
  - friction: a nested standalone consumer crate fights the workspace
    resolver (needs an empty [workspace] table — Cargo's own hint).
  - friction: recorder boilerplate is hand-rewritten per author (C9
    deliberately ships no library sink).
  - spec_gap: the public surface never states output: vec![] is THE sink
    declaration, nor defines a Some return paired with empty output.

Spec at docs/specs/fieldtest-0006-substrate.md feeds the 0007 plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 15:36:50 +02:00
Brummel 22ee99abcd spec: 0006 sink recording
A sink is a role, not a type: recording is an out-of-graph side effect a
node performs in eval, pushing to a destination it holds as a field. No
Sink type, no trait, no engine sink-awareness. The engine stays the
router for in-graph routing (edge table = graph-as-data); the node-side
push is the only out-of-graph escape, and that boundary is the
determinism boundary. A node may be producer and sink at once (C8 both).

Engine surface shrinks: Ctx gains now(); the observe index (field,
bounds check, per-cycle collection) is removed; bootstrap drops its 4th
param; run returns (). Recording streams are sparse and timestamped
(only fired cycles), replacing the dense Vec<Option<row>>.

Realization notes land on C8 and C22; no new contract.

refs #2
2026-06-04 14:11:00 +02:00
Brummel e9b4d51c30 spec: 0005 node output record
Cycle 0005 (BLOCKER, milestone walking-skeleton): generalize a node's output
from a single scalar to a record of base-scalar columns (K >= 1), with a scalar
being the degenerate K = 1 case. A node keeps exactly one output port; that
port's payload becomes an ordered list of named, typed base columns (a composite
stream, C7). This unblocks every multi-column producer the engine needs next --
OHLCV bars and, later, the C10 position-event table -- none of which can exist
while a node emits at most one column. This revises C8 and sharpens C7.

The load-bearing design call, made with the user: the eval output representation
under C7's "no per-event heap allocation". eval becomes
`-> Option<&[Scalar]>` -- the node fills a buffer it owns (sized once at
construction) and returns a borrowed K-field row; the engine copies it into one
reused scratch row (resolving the borrow, zero per-cycle alloc once warm) and
scatters each field to its out-edges. `None` still means filter/not-warmed.
Rejected alternatives, on substance: returning `Option<Vec<Scalar>>` allocates
per fire (violates C7's forbids); an inline fixed `[Scalar; N]` record bakes a
magic width cap; engine-owned output columns invert the eval model (write-into-out
+ a fired flag) and split "fired" from "produced" for an output-lookback benefit
we do not need (history is bound as an input, not read from a node's own past).
The borrowed row is the minimal faithful generalization of today's
`Some(Scalar)` push route, K-wide.

Binding stays field-wise only: `Edge` gains `from_field`; consuming a whole
record is N edges; no "bind whole record" mechanism. The K fields of one record
are co-fresh by construction (one eval, one timestamp), so C6 is untouched. The
record is structural bundling over the four base types (C7 intact) -- no fifth
scalar type, no dyn Any, no heterogeneous buffer.

Scope is the substrate only: the contract change, the Sma/Sub degenerate
migration, the engine from_field wiring, and a neutral OHLCV proof (a 5-field
bundler fed by five timestamp-aligned barrier sources + a downstream Sub binding
high - low field-wise, plus must-fail cases: from_field out of range -> BadIndex,
per-field kind mismatch -> KindMismatch). The C10 position table and broker nodes
are out of scope -- later cycles that consume this capability.

Self-review clean; grounding-check PASS (14 load-bearing "before"-state
assumptions ratified by named green tests; C6/C7/C8 match the ledger as written;
parse-every-block a documented no-op -- profile declares no spec_validation).

refs #1
refs walking-skeleton

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:35:31 +02:00
Brummel 4cbb7795ef spec: cycle 0004 firing policies and merge
Fourth walking-skeleton cycle: the reactive-semantics layer — both firing
policies (C6), the k-way ingestion merge (C3), the monotonic cycle_id clock
(C4), and freshness-gated recompute / sample-and-hold (C5). This is the first
point where the engine departs from RustAst rather than sharpening it.

Both rails ship together (user directive: "must sit right from the start"):
- A = fire-on-any-fresh + hold (as-of join);
- B = all-fresh barrier (synchronizing join), accumulating across cycles.
Per-input-group, mixable on one node. Encoded as Firing::{Any, Barrier(u8)} on
InputSpec (where C8 places firing); default Any keeps Sma/Sub unchanged.

Key design resolution (studied against RustAst src/ast/rtl/streams/): the
barrier token is the data *timestamp*, not cycle_id. RustAst's
last_cycle_per_input.all(== cycle_id) synchronizes one source's fan-out but
cannot synchronize independent sources — under C4 four same-timestamp sources
are four different cycle_ids, so the cycle_id barrier never fires for C6's own
OHLC example. Substituting timestamp is the minimal faithful generalization
(fires both the diamond rejoin and the multi-source bar). Mode A and the k-way
merge are both new (RustAst had neither).

Two read clocks, both load-bearing (resolves the 0003 audit's "0004 owns
cycle_id" with no write-only field): cycle_id is the freshness epoch (C5 reads
it via per-slot fresh_at == cycle_id); timestamp is the barrier token (C6 reads
it via last_ts == T). Sample-and-hold falls out of the existing push model — a
non-firing node pushes nothing, so consumers see the held value via window[0].

Scope (user-chosen): reactive semantics only — in-memory (timestamp, value)
sources; the merge is the permanent ingestion core, the Source trait (C11) +
data-server IO are a later orthogonal cycle. bootstrap/run/InputSpec signatures
change (the 0003 tests re-express on the multi-source API).

Headline test pair (identical sources, firing-only difference): A emits
[None,None,120,130,140,240] (holds); B emits [None,None,120,None,None,240]
(waits for timestamp coincidence). Plus determinism (C1), mixed A+B, the 0003
fan-out/join compat baseline, and the bootstrap rejections.

Grounding-check PASS: 10 load-bearing substrate assumptions ratified by green
tests; the spec's "before" shapes match disk exactly.

refs walking-skeleton

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:00:06 +02:00
Brummel aaaf463102 spec: cycle 0003 deterministic single-source sim loop
Third walking-skeleton cycle: aura-engine's first real content — a Sim that
runs a wired DAG of nodes deterministically, cycle by cycle. First point where
authored nodes execute against data, not just under a hand-fed Ctx.

Engine shape (contract-forced): a flat Vec<NodeBox> + an index edge table,
topologically ordered (Kahn), owned &mut by the loop — the flat, monomorphized
sharpening of RustAst's Rc<RefCell<dyn Observer>> push graph (C1/C7). Each node
owns its input columns (cycle-0002 shape), so Ctx is unchanged and the per-cycle
path allocates nothing. Wiring is by forwarding: a producer's eval output is
pushed into its consumers' input columns; a None forwards nothing (the seed of
sample-and-hold).

Bootstrap generalizes C7's "type check paid once at wiring" to the whole
topology: size input columns from each node's schema, kind-check every edge,
reject directed cycles (BootstrapError). A worked 2-input Sub node lands in
aura-std so the loop is proven on a real fan-out+join DAG
(source -> {SMA(2), SMA(4)} -> Sub -> observe), with a determinism assertion (C1).

Deliberately deferred (recorded as decisions): freshness gating / sample-and-hold
(C5 -> cycle 0004, only testable once a second source at a different rate exists);
the Source trait + data-server ingestion + k-way merge (C3/C11); the ergonomic
builder API (C19); the real sink + run registry (C18/C22); cross-sim parallelism.

Grounding-check PASS: all assumptions about the 0001 substrate and 0002 node
contract ratified by green tests; no phantom methods.

refs walking-skeleton
2026-06-03 12:50:17 +02:00
Brummel 4f72701e3b spec: cycle 0002 node contract and ctx
The second walking-skeleton cycle, on top of the 0001 streaming substrate:
the Node contract (C8) and its evaluation context.

Scope (one iteration):
- `Node` trait — `schema() -> NodeSchema` (inputs: kind + lookback; output
  kind) + `eval(&mut self, Ctx) -> Option<Scalar>` (None = filter / not warmed).
- `Ctx` — a Copy borrow-wrapper handing eval zero-copy, financial-indexed
  Windows per input (`ctx.f64_in(i)[k]`, index 0 = newest).
- Read-side `AnyColumn::as_f64/as_i64/as_bool/as_ts` — mirrors the existing
  write-side `as_*_mut` and closes the cycle-0001 audit gap.
- `Sma` in aura-std — the worked producer node (the skeleton's first block),
  driven by a hand-written test that mimics the future sim loop.

Deliberate deferrals (recorded as decisions, not gaps): the sim loop (C4),
freshness gating (C5), firing policies (C6, so InputSpec carries no firing
field yet), schema-level tunable params (C12/C19), and sinks / no-output
nodes (C8 consumer side). The hand-driven test stands in for the loop.

Grounding-check PASS: all load-bearing assumptions about the 0001 substrate
(Column/Window/AnyColumn/Scalar, financial indexing) ratified by green tests.

refs walking-skeleton
2026-06-03 12:05:38 +02:00
Brummel b622a74571 spec: cycle 0001 core streaming substrate
The first walking-skeleton cycle: the aura-core data substrate everything
streams through — the four scalar base types (Scalar/ScalarKind/Timestamp,
C7), the fixed-capacity financial-indexed SoA Column with its zero-copy
Window (C8), the type-erased AnyColumn edge with an edge-time kind check
(C7), and the per-column run_count freshness primitive (C5). Sharpens the
RustAst reference: no boxed Value, no VecDeque, no RefCell/Rc, no per-event
allocation. Node trait, Ctx, firing policies, and the sim loop are deferred
to subsequent cycles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:30:01 +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