Commit Graph

212 Commits

Author SHA1 Message Date
Brummel da5068e10a plan: 0061 families-comparison view
Three tasks: (1) aura-registry — NameKind/FamilyMember/WriteKind, name_kind,
read_family, ensure_name_free + a NameTaken error variant; (2) aura-cli — the
comparison ChartData builder (shared y-scale, union-ts spine), filter_to_tap,
parse_chart_args, the emit_chart name-kind branch, the --tap flag, USAGE; (3)
aura-cli — the write-guard calls in the six tracing fns + collision tests. Each
task RED-first with per-crate gates; workspace test + clippy at the close.

refs #107
2026-06-21 17:49:42 +02:00
Brummel 5f31eccc7c spec: 0061 families-comparison view (boss-signed)
A read-side cycle: `aura chart <family>` overlays one tap (default equity) of all
members of a sweep / MC / walk-forward family in one self-contained uPlot page,
consistent across kinds via the existing union-ts spine. The view consumes a
"set of runs to compare" (a family is its first producer) — the first step toward
the programmable analysis meta-level (C21), without rebuilding the orchestration
axes. aura-registry gains name_kind / read_family / ensure_name_free (a write-guard
making name resolution a total function); aura-cli gains the comparison ChartData
builder + emit_chart branch + --tap. aura-engine untouched (C9/C14).

Brainstorm-ratified, grounding-check PASS (11/11 current-behaviour assumptions
ratified by green tests). Signed under /boss on the grounding PASS.

refs #107
2026-06-21 17:39:20 +02:00
Brummel 99fd32b1f9 feat(real-family): realistic strategy lengths over real data
The built-in family grid was calibrated for the synthetic demo streams (18/60
bars), where trend SMA 2-5 / MACD 2-4-3 are the only lengths that warm. Over real
M1 data those are noise — ~9000 exposure sign-flips per month, a strategy trading
the bid-ask wiggle, not a trend.

DataSource::strategy_lengths() makes the grid data-kind-dependent (like
wf_window_sizes): synthetic keeps {2,3}x{4,5} + MACD 2/4/3 (byte-unchanged); real
uses {50,100}x{200,400} trend SMAs + standard 12/26/9 MACD. Threaded through
sweep_family + sweep_over (the walk-forward in-sample sweep). Over real EURUSD the
monthly flip count drops from ~9000 to ~130-310 — a genuine trend cross.

This is a demo-strategy calibration patch (ledger C22 amendment notes it as such);
the real answer is project-authored strategies owning their own grid (C9), deferred
to the project-env work.

Verified: cargo test -p aura-cli (all green, synthetic byte-unchanged),
clippy -D warnings clean; real sweep probe shows ~130-310 flips/month.

refs #106
2026-06-21 16:06:28 +02:00
Brummel 607e5487e9 audit(real-family): cycle close 0060 — ledger records the real-data family axis
Architect drift review (b92aab7..HEAD): the cycle is contract-clean — C9 (engine
untouched, whole change CLI-side), C6/C1 (real bars streamed from the pre-recorded
archive, real sweep byte-deterministic), C10 (refuse-don't-guess shared by run
--real and the family path), C12 (MC-exclusion fenced: mc --real exits 2). One
medium ledger-gap, now closed; one low item ratified as carry-on.

- Ledger: docs/design/INDEX.md C22 gains a "real-data family source" amendment
  (#106) recording the opt-in real-data axis on sweep/walkforward families, the
  DataSource provider, the MC exclusion (Fork A), and the oos{ns} key widening.
  This was the only drift — a documentation gap, not code drift.
- Ratified carry-on [low]: the real walk-forward member key oos{from.0} is now an
  epoch-ns integer; portable and collision-free, covered in practice by the
  walkforward_real test (>=2 distinct oos<ns> dirs) and the 9-window E2E probe.
  No explicit ns-uniqueness assertion beyond starts_with("oos") — acceptable; a
  dedicated pin is not worth an iteration.
- Retire ephemeral spec/plan 0060 (git rm) per the cycle-artifact lifecycle; the
  durable record is this ledger amendment + the git history.

No regression scripts configured (architect is the gate). Full workspace test +
clippy -D warnings green at close.

refs #106
2026-06-21 15:33:02 +02:00
Brummel bd5a08d71f plan: 0060 real-data source path for family runs
Five compile-gated tasks for spec 0060: (1) additive DataSource/DataChoice
provider + ns roller constants, (2) pip-parametrize the two blueprints + thread
all callers, (3) thread &DataSource into the five family builders + run_sweep/
run_walkforward (dispatch passes Synthetic), (4) --real parser grammar +
build-or-refuse dispatch + USAGE, (5) gated real-path integration tests + full
suite + clippy. Each task threads its signature change with all callers so
`cargo build -p aura-cli --all-targets` is green per task; the byte-unchanged
synthetic path is the regression guard.

refs #106
2026-06-21 14:17:49 +02:00
Brummel 9637730520 spec: 0060 real-data source path for family runs (boss-signed)
Opt-in `--real <SYMBOL> [--from <ms>] [--to <ms>]` for `aura sweep` and
`aura walkforward`, mirroring `aura run --real`: each family member streams real
M1 close bars from the local data-server archive instead of the synthetic stream.
MC is excluded — its seed varies a synthetic price-walk realization, undefined
over real data (one realization -> identical members; a real MC needs a
bootstrap-resampling axis, its own cycle).

Engine, ingest, and registry untouched: a CLI-side `DataSource` provider replaces
the hardcoded `VecSource`. `M1FieldSource` already impls `Source`; `WindowRoller`
already rolls over epoch-unit timestamps.

Boss-signed: Step-5 grounding-check PASS — all 8 load-bearing current-behaviour
assumptions ratified by named, currently-green tests.

refs #106
2026-06-21 14:05:34 +02:00
Brummel b92aab713c audit(sweep-key): cycle close 0059 — drift-clean, retire spec/plan
Cycle-close tidy for the generic portable sweep member-key + bool-param demo
strategy (spec/plan 0059, reference issue #105, implementations 27f850d + 0b73a75).

Architect drift review (range 1d6fafb..HEAD): clean — no drift, no debt.
- C1 (determinism): varying_axes + member_key are pure functions of the grid
  point, no schedule state; the engine carries no trace state (consistent with
  the #104 design + the C22/#101 ledger note).
- C7/C8/C9: LongOnly is a clean one-in/one-out f64 node, None until warmed (C8
  filter), the first bool *param* through the already-ratified Cell::bool()
  path; momentum is an ordinary composite of existing nodes; brokers stay
  downstream (C10). C18/C21/C22 upheld.
- The engine accessor exposes the binder's OWN axis-cardinality knowledge (it
  holds the value-lists), not a presentation concern — formatting stays in the
  CLI. The hand-rolled fnv1a64 mirrors the ledger-blessed SplitMix64 precedent
  (harness.rs): tiny, dependency-free, bit-stable-on-purpose (std DefaultHasher
  is unstable across releases; on-disk-name stability is the per-case C16
  reason). LongOnly is a genuine universal aura-std block (long-only is
  asset-agnostic). The ledger amendment matches the code.

Regression: the project declares no dedicated regression command; the gate is
the architect review plus the full suite, verified green at 0b73a75 (cargo test
--workspace, clippy --all-targets -D warnings).

Spec docs/specs/0059 and plan docs/plans/0059 retired (git rm) per the ephemeral
active-cycle artefact lifecycle; the durable rationale (the portable member-key
convention) lives in the ledger amendment (docs/design/INDEX.md C22/#101 note)
landed in 0b73a75.

closes #105
2026-06-21 11:35:59 +02:00
Brummel 0b73a75d4b feat(momentum): bool-param demo strategy + aura sweep --strategy selector
Proves the #105 generic portable member key end-to-end: a demo strategy whose
params have nothing in common with the SMA-cross demo, swept by the same
machinery, with a bool axis surfacing — conformant — in the member dir names.

- momentum strategy: price -> Ema(length:i64) -> Sub(price-ema) ->
  Exposure(scale:f64) -> LongOnly(enabled:bool) -> SimBroker. Three swept params
  of three kinds incl. a bool; the exposure sink taps the post-gate exposure so
  the bool's effect is in the trace.
- aura sweep gains --strategy <sma|momentum> via a pure, unit-tested
  parse_sweep_args (mirroring parse_real_args); default = SMA-cross, so the
  existing bare / --name / --trace forms are unchanged.
- `aura sweep --strategy momentum --trace mom` persists 8 member dirs named e.g.
  ema.length-5_exposure.scale-0.5_longonly.enabled-true — the bool in the dir
  name, every name matching [A-Za-z0-9._-], each chartable.
- ledger (docs/design/INDEX.md): the C22/#101 member-key note's sweep clause
  amended to the generalised portable form (MC seed{N} / walk-forward oos{ns}
  unchanged).

Self-verified: cargo build --workspace, cargo test --workspace (all green incl.
momentum_param_space_is_ema_exposure_longonly, the 8-point determinism test,
the parse_sweep_args grammar test, and the momentum_sweep_trace integration test
asserting 8 portable bool-bearing dirs + a chartable member), cargo clippy
--workspace --all-targets -D warnings.

refs #105
2026-06-21 11:32:46 +02:00
Brummel 44e3a1a678 plan: 0059 generic portable sweep key + bool-param demo strategy
Decomposes spec 0059 into 5 tasks: (1) engine SweepBinder::varying_axes
accessor; (2) aura-std LongOnly bool-param node; (3) the portable member_key
renderer replacing sweep_member_key (+ sweep_family refactor + the SMA
sweep-trace assertion update); (4) the momentum strategy + --strategy selector
(+ the momentum integration test); (5) ledger amendment + full-suite/lint gate.
Each task is RED-first and builds green per task.

refs #105
2026-06-21 10:55:20 +02:00
Brummel a8ba019d4d spec: 0059 generic portable sweep key + bool-param demo strategy (boss-signed)
Generalises the family-member trace key (#105 foot-gun): derive it from the
axes that actually vary (not two hardcoded axis names), and render it as a
filesystem-conformant directory name on every major OS — charset [A-Za-z0-9._-],
case-less values (no case-insensitive-FS collision), length-bounded with an
FNV-1a fallback for the unbounded-grid edge.

Adds the first bool *param* node (LongOnly) and a momentum demo strategy
(Ema -> Sub -> Exposure -> LongOnly -> SimBroker) swept via a new
`aura sweep --strategy <sma|momentum>` selector — the empirical proof the
generic key works for a strategy whose params (incl. a bool) differ entirely
from the SMA-cross demo.

Boss-signed on the Step-5 grounding-check PASS (an independent fresh-context
agent): all 9 load-bearing current-behaviour assumptions ratified by green
tests; the end-to-end bool-param sweep path is correctly scoped as new
behaviour proven by new tests, not assumed. Workspace type-checks clean.

refs #105
2026-06-21 10:41:31 +02:00
Brummel 1d6fafbc39 audit(family-traces): cycle close 0058 — drift-clean, retire spec/plan
Cycle-close tidy for family-member trace persistence (spec/plan 0058,
reference issue #104, implementation d3cb5f8).

Architect drift review (range 06fdafa..d3cb5f8): drift_found, low-grade
only — no contract violated. C1 (determinism), C7 (SoA), C8 (sinks),
C18/C21 (registry/families) all upheld; the opt-in --trace path is
genuinely byte-neutral. Two items, both resolved here:

- [high] Ledger gap: the C22/#101 disk-trace note recorded only the
  single-run runs/traces/<name>/ layout. This cycle establishes a new,
  load-bearing on-disk convention (per-member nested standalone run-dirs
  runs/traces/<name>/<member_key>/) that the deferred family-comparison
  view will build on. FIXED: amended the C22/#101 realization note in
  docs/design/INDEX.md to record the layout, the content-derived
  deterministic member keys, and the parallel-safe lock-free write.

- [medium] sweep_member_key hard-codes two grid axes; collision-free only
  over today's built-in grid, a latent foot-gun if the grid varies an
  unlisted axis. Not a current defect (one grid, covered, fail-loud on a
  missing listed axis). CARRY-ON: filed #105 (idea) for generalised key
  derivation when the grid generalises.

Regression: the project declares no dedicated regression command; the
gate is the architect review plus the full suite, verified green at
d3cb5f8 (cargo test --workspace, clippy --all-targets -D warnings).

Spec docs/specs/0058 and plan docs/plans/0058 retired (git rm) per the
ephemeral active-cycle artefact lifecycle; durable rationale lifted to
the ledger amendment above.

refs #104
2026-06-20 20:01:13 +02:00
Brummel f33b427883 plan: 0058 family-trace-persistence
Three tasks (MC, sweep, walk-forward) wiring per-member trace persistence
into the family closures + a full-suite/lint gate. Each task threads its
builder signature and every caller together so the workspace compiles
green per task.

refs #104
2026-06-20 18:51:32 +02:00
Brummel 04f13af88a spec: 0058 family-trace-persistence (boss-signed)
Persist each family member's equity/exposure streams to disk (opt-in
--trace on sweep|mc|walkforward), mirroring the single-run trace path, so
the C21 family-comparison view has per-member data and any single member
is chartable today. Write side only; the comparison view, decimation,
and a binary trace container are deferred.

Autonomously signed under /boss on the Step-5 grounding-check PASS.
refs #104
2026-06-20 18:40:41 +02:00
Brummel 87e6e8992d audit(viewer-tier1): cycle close — drift-clean, retire spec/plan 0057
Architect drift review over 5bff7e0..HEAD: clean, no drift, no debt. C14/C7
firewall intact (main.rs byte-unchanged → build_chart_data still returns
ChartData{xs,series}, the injected window.AURA_TRACES payload shape untouched;
the ordinal index spine is derived client-side). C22 holds — the
ordinal/continuous toggle + wheel-zoom/drag-pan/dblclick-reset are view
affordances over a recorded trace (read-only setScale on the x range), not a
scene editor. The #102 manifest-header gap is neither closed nor regressed,
still tracked.

Regression gate: cargo test --workspace green (incl. the four chart guards +
render inline tests), clippy --all-targets -D warnings clean; aura has no
separate regression script, so the suite + architect are the gates. cycle
clean.

Spec/plan 0057 retired per the ephemeral-artifact lifecycle (durable record:
the feature commit 45cc1c4, the #103 decision-log comments, and git history).

refs #103
2026-06-19 19:03:16 +02:00
Brummel bb8045ea59 plan: trace-chart viewer Tier-1 — ordinal x-axis + zoom/pan/cursor-sync
Five tasks: RED x-mode guard; buildCharts gains xMode (ordinal default) +
wheelZoomPlugin + panel cursor-sync, with the two twin guards re-pointed in
lockstep; mount render(xMode)+toggle; render.rs CHART_HEAD toggle + chart-only
style + chrome tests; full-suite/clippy/e2e gate.

refs #103
2026-06-19 18:23:42 +02:00
Brummel be71f0a55c spec: trace-chart viewer Tier-1 — ordinal x-axis + zoom/pan/cursor-sync (boss-signed)
Tier-1 comfort pass for the served trace chart (#103): an ordinal x-axis
default (collapses non-trading gaps) with a one-click continuous toggle, plus
wheel-zoom / drag-pan / dblclick-reset, a value-readout legend, and panel
cursor-sync. Confined to the read/render side (chart-viewer.js + render.rs
CHART_HEAD); the Rust serve contract is unchanged.

Boss-signed: grounding-check PASS (five current-behaviour assumptions ratified
by green node guards + render.rs inline tests). Derived-fork decision log in
the #103 comments.

refs #103
2026-06-19 18:16:03 +02:00
Brummel 5bff7e0fb9 audit(trace-charts): cycle close — C22 realization note, retire ephemera
Cycle-close audit for the trace-charts visual face (#101, shipped across
8bb5256 persist + 15ee6d5 serve). Architect drift review (13941a2..HEAD)
+ the regression gate (cargo build/test/clippy --workspace, all exit 0,
orchestrator-verified).

What holds (carry-on): C14 clean — aura-engine/aura-core carry zero
UI/HTML/uPlot knowledge; ColumnarTrace does struct->encoding only, file
I/O in aura-registry, rendering in aura-cli. C1/C3 clean — persistence
and serve-time alignment are post-run pure reductions (join_on_ts at
serve time only, never in-graph). C7 clean — on-disk f64 columns +
kinds-tagged base types, the documented coercion honest, no 5th scalar.

Resolutions:
- [fix] Added the C22 realization note now that the web-from-disk seam
  shipped (the amendment 3b56efb had deferred it to "when the seam
  ships").
- [ratify] The served page injects the chart SERIES but drops the run
  manifest (no run-context header) — a deliberate, defensible naive-viewer
  scope call (the manifest is on disk in index.json; a header matters most
  for the deferred families/comparison work, C21). The deviation from spec
  0056 §1/§4 landed unflagged in 15ee6d5; it is now flagged here and
  tracked as a follow-up. refs #102
- [tidy] Retired this cycle's ephemera (spec 0056, plans 0055/0056) and
  the stale debris from the prior Runway close (spec 0055-fieldtest) per
  the ephemeral-artifact convention; the durable record is the ledger +
  git history.

Cycle drift-clean (modulo the ratified, tracked manifest-header gap).

refs #101
2026-06-19 00:59:54 +02:00
Brummel 709a68a2ae plan: trace charts iter 2 (serve) — render_chart_html, chart-viewer.js, aura chart verb
Iteration-2 (serve half) plan for spec 0056: a first-party chart-viewer.js (pure buildCharts + browser mount) with a node .mjs DOM guard; render_chart_html + ChartMode/ChartData/Series mirroring render_html; emit_chart + the spec-§6 union-spine join_on_ts alignment + the `aura chart <name> [--panels]` arms. uPlot already vendored (d534f10). RED-first; no existing-signature changes (no caller blast radius).

refs #101
2026-06-19 00:25:06 +02:00
Brummel 99a18ff00c plan: trace charts iter 1 (persist) — ColumnarTrace, TraceStore, --trace wiring
Iteration-1 (persist half) plan for spec 0056: ColumnarTrace (aura-engine), TraceStore (aura-registry), and the shared persist_traces helper threaded into all three run forms. RED-first; Task 3 folds all nine signature-change callers in before the build gate (per plan-recon's compile-gate warning). Serve/chart half deferred to iteration 2.

refs #101
2026-06-18 23:41:42 +02:00
Brummel bcf48f3f86 spec: trace charts — persist taps + serve web charts (auto-signed)
First cut of aura's visual face (issue #101; the web-from-disk pivot
ratified into C14/C22 this session, commit 3b56efb): tap arbitrary
recorder streams from a run, persist them to disk as columnar (SoA)
JSON, and serve them as a self-contained uPlot HTML chart — feeds
overlaid on a shared timestamp axis, or timestamp-aligned in stacked
panels. `aura run [--macd] [--trace <name>]` and `aura run --real <SYM>
... [--trace <name>]` persist; `aura chart <name> [--panels]` serves.
Both modes share one synthetic-union-spine join_on_ts alignment.

Signed via the specify auto-sign gate: the user is away under an
explicit "work fully autonomously, document decisions" mandate, so no
manual signature was available. All objective gates green (precondition
clean, self-review clean, grounding-check PASS), and a unanimous 5-lens
adversarial spec-skeptic panel (criterion / grounding / scope-fork /
ambiguity / plan-readiness all SOUND).

The panel earned its keep — two self-correction rounds to unanimity:
- Round 0 caught (a) panels shipped NOT timestamp-aligned, contradicting
  the user's verbatim "aligned nach Timestamps in Panels" — corrected to
  conform to issue #101 Fork A; (b) the USAGE advertised `--macd --trace`
  with no dispatch arm — corrected to an orthogonal `--trace` composing
  with every run form via a shared persist helper.
- Round 1 caught the union-spine -> join_on_ts mapping under-specified
  (which tap is the spine?) — corrected with an explicit 3-step
  synthetic-empty-spine mechanism (no privileged tap, no points dropped),
  plus a to_rows uniformly-f64 clarification.

The two delegated naive-viewer decisions (per-series y-scale, union
spine) are documented with provenance on issue #101.

refs #101
2026-06-18 23:28:58 +02:00
Brummel 3b56efbdb4 docs(design): amend C22/C14 visual face — web-from-disk, not egui
The visual face pivots from the ledger's egui-native, in-process
zero-copy direction to a web frontend served from disk-persisted
recorder traces: the engine writes recorded traces to disk, a browser
charts them. Settled in an in-context design discussion (provenance in
issue #101): raw per-tap trace persistence + serve-time join_on_ts
alignment + a static self-contained HTML chart (uPlot). The engine
stays headless (C14) — arguably more strictly, since a browser reading
a serialized file is further from the hot path than egui reaching into
the live SoA columns. Amends the C14 visual-face note and the open
"Playground & World UI surface" thread; the C22 realization note lands
when the seam ships.

refs #101
2026-06-18 21:45:03 +02:00
Brummel 13941a24d5 fieldtest: milestone runway — real-data seam, 4 examples, 6 findings (gate green)
Milestone-close fieldtest for "Runway — real-data ergonomics & honesty
hardening". Four curated end-to-end scenarios derived top-down from the
milestone promise, run as a downstream consumer against real GER40/EURUSD M1
bars (public interface only; no crates/*/src read):

  1. per-instrument pip honesty (#22) — GER40 index pip 1.0 AND EURUSD forex
     pip 0.0001 both honest end-to-end; AAPL.US/FOOBAR un-vetted refused
     exit 2, no stdout leak
  2. real GER40 M1 open via open_ohlc from aura-ingest ALONE (#80/#81/#92) —
     no data-server dep, 53173 real bars, C4 O/H/L/C order, ts-window inverse
  3. multi-tap ts-join (#93) — two taps at different cadences, 27744 rows,
     0 by-ts mismatches; warm-up None rows where a positional zip would corrupt
  4. run-registry coherence (#73/#82) — list/rank retired exit 2, families/
     family live, two-store Registry read-back + rustdoc

Findings: 4 working, 1 friction, 1 spec_gap.
  - friction: Cell exposes only from_i64/from_f64/... while the side-by-side
    Scalar is a tagged enum with public I64(..)/F64(..) variants. The natural
    param-authoring entry point is Scalar (Cell is the hot-path buffer carrier),
    so the wrong reach is a self-correcting compile snag — ergonomic only.
    Filed as a follow-up idea.
  - spec_gap: unknown family id exits 0 empty — ratified into the C18 note in
    the preceding commit (treat-as-empty contract).

Gate verdict: GREEN. All seven axes mapped to a covering scenario and exercised
on real bars; both finding classifications and the one material coverage gap
were adversarially re-verified. That gap — #22's FX-vetted pip face, untested by
the original scenario set — was probed (EURUSD -> sim-optimal(pip_size=0.0001),
FX-scaled, not index-mis-scaled) and folded into scenario 1, so the pip promise
is demonstrated on both positive faces. Every scenario re-run independently on
HEAD before commit.
2026-06-18 21:13:56 +02:00
Brummel 5a14d9cc44 docs(design): ratify C18 unknown-family-id contract (treat-as-empty, exit 0)
The Runway milestone fieldtest surfaced a spec_gap: `aura runs family <id>`
with an unknown-but-well-formed id exits 0 with empty output, and neither the
ledger nor the glossary constrained that case. The behaviour is already the
documented, tested CLI contract (treat-as-empty, mirroring Registry::load's
missing-store = Ok(empty)); this lifts that contract to the durable C18 note
so a consumer reasoning from the spec can derive it, and records that tightening
to a non-zero "no such family" exit (typo-safety) stays an available future UX
choice rather than a current contract.

Ratifies the spec_gap from docs/specs/0055-fieldtest-runway-real-data-seam.md.
2026-06-18 21:13:17 +02:00
Brummel 0d185fb4c3 chore(audit): tighten C18 note — append/load are public-API-only after the runs retire
The milestone-close architect flagged that the runs-retire note over-claimed
"retained because used": after dropping runs list/rank, Registry::append/load (the
flat-store half) have no in-tree caller — only rank_by/optimize keep live
consumers. Note now distinguishes the live half from the public-but-uncalled half
(a latent dead-code surface for a later sweep). Doc-only.
2026-06-18 19:56:25 +02:00
Brummel 3dac2c0c99 refactor(aura-cli): retire the dead-end runs list/rank CLI surface
Since cycle 0045 the flat runs.jsonl store has had no producer (sweep/mc/
walkforward persist to the family store; `aura run` does not persist), so
`aura runs list` / `runs rank` read a store nothing populates — a live dead-end
surface, the honesty gap the Runway milestone closes.

Resolve the C18 deferred fork (INDEX.md) as (b) RETIRE: drop the two CLI commands
+ their dispatch arms, usage fragments, and the now-unused load_runs_or_exit.
Families (sweep/mc/walkforward, C21) subsume standalone over-time comparison. The
aura-registry flat lib API (append/load/rank_by/optimize) is RETAINED — optimize
backs walk-forward's in-sample step, rank_by backs `runs family ... rank`.
`runs families` / `runs family` are untouched.

Decision recorded on #73 (user-directed (b), 2026-06-18). Cosmetic sub-item
(json! family-wrapper -> to_json() stdout key-order unification) deferred to a
follow-up: json! routes the embedded report through serde_json::Value, which
re-alphabetizes keys, so it needs manual JSON construction, not a trivial swap.

RED-first: the retire test asserted `runs list`/`rank` now exit 2 (was exit 0).
Verified: cargo build --workspace, clippy --all-targets -D warnings, and
cargo test --workspace all green.

closes #73
2026-06-18 19:53:26 +02:00
Brummel 77358d2240 chore: cycle 0054 close — per-instrument pip; C10/C15 realization note, retire spec+plan
Audit (architect drift review + cargo test --workspace) clean: code matches the
spec, the engine stayed domain-free (no instrument identity in Ctx / the hot
path), InstrumentSpec sits beside the hot path per C7/C15. No regression scripts
configured (no-op gate); the full suite is green.

Ratify: the architect flagged one ledger-realization gap — C10/C15 described
per-instrument pip as standing design intent but carried no realization note for
the now-shipped channel. Added dated realization notes to C10 (the per-instrument
pip channel + the refuse-don't-guess honesty rule) and C15 (instrument specs as
metadata, first realized by InstrumentSpec/instrument_spec).

Retire the ephemeral cycle artefacts (spec 0054, plan 0054) per the active-cycle
lifecycle. Deferred follow-up: #98 (route the runnable GER40 examples through the
lookup).

refs #22
2026-06-18 19:40:57 +02:00
Brummel 47bcb29899 plan: 0054 per-instrument pip metadata channel
refs #22
2026-06-18 19:06:10 +02:00
Brummel 2844ace2ce spec: 0054 per-instrument pip metadata channel
refs #22
2026-06-18 18:58:56 +02:00
Brummel 7deb38edd8 chore: cycle 0053 close — audit clean, retire spec + plan
Cycle 0053 (multi-tap trace join on timestamp, #93) closes drift-clean.

Audit (architect drift review over 066638e..HEAD against docs/design + the
CLAUDE.md domain invariants):
- C8/C18 honoured: join_on_ts is a post-run reduction over recorded
  (Timestamp, Vec<Scalar>) sink streams, a true sibling of summarize/f64_field
  in the report layer — correct architectural home.
- C3 not violated: the join runs post-run over already-recorded output, not
  in-graph; no as-of join smuggled into the DAG. C1 ts-uniqueness is a
  documented precondition, not a runtime check — consistent with how the
  engine leaves wiring-time invariants to contract.
- Option-per-side keeps the engine honest (reports presence; the consumer owns
  the 0.0/-1/false defaults). The hand-rolled *_by_ts HashMaps are fully gone;
  the two RED unit tests pin the #93 cardinality-misalignment + spine-drop.
- No drift, no debt, no ledger entry needs updating. Recommendation: carry on.

Regression gate: no dedicated regression scripts configured (optional per the
conventions); build/test/clippy --workspace --all-targets is the gate and ran
green — the gated GER40 byte-identity tests executed against the local archive
(not skipped), proving drain_trace's trace is byte-preserved across the
refactor.

Per the artifact lifecycle (committed while the cycle is live, git rm at cycle
close), the ephemeral spec and plan are retired here; their durable rationale
lives in the implementation commits 74324d1 / 35c5adc and the git history.
2026-06-18 15:04:42 +02:00
Brummel a162585981 plan: 0053 multi-tap ts-join
Bite-sized execution plan for spec 0053: Task 1 the join_on_ts helper +
JoinedRow + two RED unit tests in aura-engine report.rs (re-exported from
lib.rs); Task 2 the behaviour-preserving drain_trace refactor onto the helper;
Task 3 the Recorder prose cadence/join note. Final gate is workspace
build/test/clippy.

refs #93
2026-06-18 14:47:11 +02:00
Brummel 24fa3fe155 spec: 0053 multi-tap ts-join
Ratified design for a reusable, spine-anchored join_on_ts helper in
aura-engine that fuses multi-tap Recorder traces on the recorded timestamp
(Option-per-side: the engine reports presence, the consumer interprets
absence). Refactors drain_trace onto it and documents the cadence rule on
the Recorder API. Resolves the #93 zip-by-index panic.

refs #93
2026-06-18 14:41:19 +02:00
Brummel 066638ec25 chore: cycle 0052 close — audit clean, retire spec + plan
Cycle 0052 (real-data source-open seam, Runway-1) closes drift-clean.

Audit (architect drift review over aedaa5d..HEAD against docs/design + the
CLAUDE.md domain invariants):
- C3 (one ms<->ns crossing) strengthened — the inverse is seam-private and the
  only consumer-side divide left; every consumer ns_to_ms / unix_ms_to_epoch_ns
  wrap is gone.
- C4 (O/H/L/C merge tie-break order) now in exactly one vetted home (open_ohlc);
  the hand-spelled four-field loops are gone.
- C12 (one shared Arc<DataServer>/cache) preserved; C7 surface additive.
- No drift, no debt, no ledger entry needs updating. Recommendation: carry on.

Regression gate: no dedicated regression scripts configured (optional per the
conventions); build/test/clippy --workspace is the gate and ran green — the gated
open_ohlc_seam behaviour-preservation test executed against the local archive
(not skipped), proving byte-identity vs the ms-path.

Per the artifact lifecycle (committed while the cycle is live, git rm at cycle
close), the ephemeral spec and plan are retired here; their durable rationale
lives in the implementation commit 8c9a1b4 and the git history.
2026-06-18 13:03:03 +02:00
Brummel 2ffcd9f03d plan: real-data source-open seam — execution plan
Bite-sized, placeholder-free projection of spec 0052 for the implement skill:
Task 1 the additive aura-ingest surface + hermetic round-trip test; Task 2 a
gated behaviour-preservation test (open_ohlc Timestamp path == ms-path open);
Task 3 the atomic compile-driven consumer migration (shared retype + 6 GER40
consumers); Task 4 the compiler-invisible compare.rs + acceptance grep gates.

refs #80, #81, #92
2026-06-18 12:26:18 +02:00
Brummel fa9dac35aa spec: real-data source-open seam (Runway-1)
Consolidate aura-ingest's OHLC source-open surface onto the engine-native
epoch-ns Timestamp currency: a private seam-owned inverse, a Timestamp-window
opener, a canonical OHLC bundle opener (fixed C4 O/H/L/C order), and a
DataServer/DEFAULT_DATA_PATH re-export + default_data_server convenience — so a
real-data source builds from aura-ingest alone, with the one ms<->ns crossing
owned by the seam. Behaviour-preserving (byte-identical RunReports).

Grounded against the tree via the ground-spec-0052 workflow (25/28 assertions
confirmed; compare.rs compiler-invisible site + AC1 scope fix applied).

refs #80, #81, #92
2026-06-18 12:26:11 +02:00
Brummel 28958f2110 chore: retire docs/specs and docs/plans as committed artifacts
Per-cycle specs/plans are step-scoped: every file maps to already-shipped
code, their snippets drift hard against current APIs (InputSpec->PortSpec,
Sim->Harness, schema() removed, C16 zero-dep reversed, ascii-dag retired),
and a stale spec read as an API reference misleads agents into non-compiling
code. No durable knowledge lost — rationale lives in the ledger + code
rustdoc, history in git + the tracker.

- gitignore docs/specs/ and docs/plans/
- delete all 117 existing specs/plans (recoverable via git history)
- CLAUDE.md: specs/plans are local-only ephemeral artifacts
2026-06-18 11:06:37 +02:00
Brummel 0d7c2c16f4 docs: narrow streaming residency claim from whole-process RSS to the source ring
The C12 realization and the 0041 spec claimed streaming residency is O(one chunk) at the process level ("a 20-year window streams in the same memory as a one-day one"). That holds only for the aura source ring (M1FieldSource::resident_records(), bounded by one chunk and correctly tested); whole-process RSS grows O(records-touched) because data-server's FileCache retains each window's parsed chunks (~56 B/record) read-only for the pass. Reproduced: 6 MiB @ 1mo -> 173 MiB @ ~10y, linear.

That retention is the replay-many optimization (load-once; close+volume share one parse via the field-agnostic FileKey), not a leak, and no always-on eviction can bound a single forward pass without regressing it. This narrows the docs/comments to the true per-source-ring property and names the FileCache per-window retention as the real, replay-amortized process cost. The streaming_seam assert is unchanged (it was always the ring bound; only its labelling confused ring vs process). The deferred opt-in non-retaining streaming read path is parked as Brummel/data-server#2.

closes #95
2026-06-17 22:09:32 +02:00
Brummel dcd550788d docs(design): canonical shippable strategy form is a Composite blueprint (C20)
Add a C20 realization recording the resolution of the GER40 deep-dive's #94
finding: a hand-wired FlatGraph is not a shippable strategy (no param_space, so
World-opaque); the canonical form is the Composite blueprint, the FlatGraph its
compiled substrate (C23). Pins the bar-period-as-structural-construction-arg
decision (spec 0051) to the structural-axis-vs-tuning-param split.

refs #94
2026-06-17 19:31:24 +02:00
Brummel 98be64ebdf spec(0051): strategy as a World-consumable Composite blueprint
Milestone spec: ship the GER40 session-breakout as a Composite blueprint so the
same strategy runs across backtest / sweep / walk_forward / compare without
re-authoring (the #94 fieldtest friction). Records the design decision that the
bar period is a structural axis (a construction arg binding both Resample and
Session, so a sweep cannot desync them — #96) and that the canonical shippable
strategy form is a Composite (FlatGraph is its compiled substrate). Authoring-
side; no engine-core change (the existing bind() + GraphBuilder + param_space()
layer already suffices).

refs #94, #96, #97
2026-06-17 19:06:11 +02:00
Brummel 90c1de841d fieldtest: GER40 session-breakout research deep-dive — 7 bins, 8 findings
Public-API research deep-dive driving the just-shipped GER40 real-data
session-breakout demo (5b5f034) through the escalating sequence a serious
researcher attempts next: scale to multi-year, walk-forward, structural-param
sweep, multi-instrument compare. Standalone consumer crate (path-deps only;
public interface = ledger + glossary + example corpus + cargo doc; no
crates/*/src read). All runs against the real /mnt/tickdata/Pepperstone archive.

Findings: 3 bugs, 1 friction, 3 spec_gap, 1 working. Triaged to the tracker:
- spec_gap: the flagship breakout ships as a raw FlatGraph the World API cannot
  consume (sweep / walk_forward / compare all forced a hand re-author to a
  Composite, which reproduced the FlatGraph numbers EXACTLY) — refs #94.
- bug: process residency is O(window) (6->173 MiB across 1mo->10y) despite the
  documented O(one-chunk) claim; the aura ring stays <=1024 but data-server
  retention scales, and streaming_seam.rs only measures the ring — refs #95.
- bug: the bar-period is one knob split across Resample (tunable param) and
  Session (baked) and desyncs silently to 0.0 pips; Delay.lag leaks into the
  default param_space (the C34 deform-vs-tune discriminator) — refs #96.
- spec_gap: the walk_forward empty-space idiom for param-free strategies is
  undefined — refs #97.
- spec_gap (no per-instrument pip registry) and friction (one-directional
  ns->ms conversion) re-confirm the known #22 and #80.
- working: C1 determinism over 7y / 148k bars, the lazy streaming source, and
  the sweep/WFO cores held under real multi-year load; the Composite re-author
  was behaviour-preserving (C23).

Scratch consumer crate + run transcripts committed under fieldtests/ per the
fieldtest convention (matching cycle-0049). The crate path-deps the engine and
reads the real archive; its bins are the repros cited in the issues above.
2026-06-17 18:55:04 +02:00
Brummel 16adb2b949 docs(specs): 0050 — session-breakout node vocabulary (milestone spec)
Milestone 'Strategy node vocabulary I — temporal, logic, resample & session':
the 7 aura-std nodes (EqConst, Gt, And, Delay, Latch, Resample, Session) plus a
synthetic e2e fixture, driven by the GER40 15m session-breakout. Records the
design pass's cross-cutting decisions: close-instant timestamp convention,
Latch emits f64 (Exposure dropped from the DAG), the EqConst i64->bool gate,
the Resample-only Barrier(0) firing regime, and the build order. refs #84-#91.
2026-06-17 16:41:31 +02:00
Brummel 562791e613 fieldtest: milestone the-world-orchestration-families — 4 examples, 4 findings
Milestone-close gate for "The World, part II — orchestration families".
Four end-to-end scenarios derived top-down from the milestone promise,
each built from HEAD and run as a downstream consumer through the public
API + CLI only (no crates/*/src read):

- mw_3 (headline): real EURUSD-M1 walk-forward composing all four axes
  (grid sweep + optimize in-sample, OOS stitch) over the M1FieldSource
  seam + lineage — 5 windows, 145 200-pt stitched curve, C2 held.
- mw_2: monte_carlo over 128 seeds, reproducible McFamily (C1) + aggregate.
- mw_1: random sweep -> optimize -> 64-member lineage round-trip.
- mw_4: family-lineage CLI transcript.

Findings: 4 working (promise empirically delivered), 1 bug, 3 friction.
- bug F5: `aura runs list`/`rank` cannot read a pre-0047 runs.jsonl — the
  cycle-0047 typed-Scalar params migration (86746e3) left the persisted
  flat store unmigrated; load() fails at the first bare float (+ exits 0).
- friction F6: no epoch_ns_to_unix_ms inverse for real-data walk-forward.
- friction F7: DataServer/DEFAULT_DATA_PATH not re-exported by aura-ingest.
- friction F8: family store is directory-keyed, undocumented on Registry::open.

Spec: docs/specs/fieldtest-milestone-the-world-orchestration-families.md
2026-06-17 15:46:18 +02:00
Brummel af0191884d fieldtest: cycle-0049 — 4 examples, 7 findings
Public-API field test of the random param-sweep surface, from a standalone
downstream-consumer crate (path-deps only; the public interface = ledger +
glossary + spec 0049 + cargo doc rustdoc; no crates/*/src read). Four bins,
each built from HEAD and run: continuous tuning (200-point random tune ranked
by total_pips), the typed validation gate (all five reachable SweepError
variants pre-run), reproducibility + seed-sensitivity + the full i64::MIN..=MAX
sampler edge, and Space-trait interchangeability (one tune_and_rank<S: Space>
over both GridSpace and RandomSpace).

Findings: 0 bugs, 4 working, 2 spec_gap, 1 friction. The four working findings
confirm the cycle's acceptance criterion empirically — the headline tune reads
as the code a researcher would write, the gate is precise and fires before any
run, the C1 reproducibility promise is checkable in one line, and the Space
trait delivers one-consumer/both-enumerations.

Triage of the actionable findings:
- friction (no named-axis builder for RandomSpace — positional Vec<ParamRange>
  must align with param_space() by hand, and a same-kind transposition passes
  validation silently): filed as a feature for a future cycle, refs #79
  (a RandomBinder sibling to the grid's SweepBinder).
- spec_gap (SweepError rustdoc summary named only GridSpace): fixed inline in a
  follow-up doc commit.
- spec_gap (NonNumericRange / Bool-slot ranges unreachable with the shipped
  aura-std node roster — no node declares a Bool/Timestamp knob): RATIFIED as
  intentional. The variant is a forward-looking structural guard for the C16
  "author your own node" path (a Bool/Timestamp param-slot a custom node may
  declare); its current untriggerability with the standard roster is expected,
  not drift.

refs #79
2026-06-17 13:42:39 +02:00
Brummel 3fca7810d0 audit: cycle 0049 — drift-clean (random param-sweep)
Architect drift review over 3de00e2..HEAD (the 0049 spec/plan/feat plus the
two intervening refactors that had not been audited: aura-ingest M1 transpose
6390093, aura-std SMA perf 67c1f51). Verdict: feature clean — C1 determinism
preserved (RandomSpace points seed-determined before any run; grid path
behaviour-preserving via trait-forwards-to-inherent), the #52/#71 source-seam
firewall honoured in code (sweep stays &S: Space + Fn(&[Cell]) -> RunReport, no
Source type enters the sweep layer; SplitMix64 a code-path-disjoint instance),
and both intervening refactors behaviour-preserving (pinned by
incremental_matches_full_resum_within_tolerance and
chunked_accumulation_equals_single_transpose).

Two low-grade doc-debt items found and fixed inline (doc-only, behaviour-
preserving):
- sweep.rs module doc named only the grid axis; refreshed to name RandomSpace
  + the Space trait the module now also owns.
- C12 ledger had no realization note for axis-1 (param-sweep); added one
  recording the grid (0028) + random (0049) landing and the Space-trait
  unification.

Regression gate: the project configures no regression scripts, so the test
suite + lint are the gate. Independently verified: cargo test --workspace green
(incl. the 17 new engine tests + 6 public-API E2E), cargo clippy --workspace
--all-targets -- -D warnings clean.

Drift-clean, not a milestone close (no milestone fieldtest run this cycle).
2026-06-17 13:28:07 +02:00
Brummel b99f52443d plan: 0049 random param-sweep
Five bite-sized tasks for the RandomSpace cut: (1) the Space trait +
behaviour-preserving generalization of sweep/sweep_with_threads, (2) typed
ParamRange, (3) RandomSpace::new validation + three SweepError variants,
(4) SplitMix64 -> pub(crate) + the seeded sampler, (5) public exports +
random-sweep integration. Each task is RED-first with single-substring test
filters; the grid suite is the C1 behaviour-preservation regression guard.

refs #52
2026-06-17 12:46:45 +02:00
Brummel 5b3d133529 spec: 0049 random param-sweep (boss-signed)
RandomSpace + a Space trait + typed ParamRange: the random half of the
C12.1 param-sweep axis (grid shipped in 0028). N seeded uniform draws over
declared continuous ranges, fed to the same enumeration-agnostic sweep core.
Param-only sweep signature and a code-path-disjoint SplitMix64 instance keep
the World-II source-seam firewall (refs #71) intact.

Auto-signed under /boss spec auto-sign: fresh grounding-check PASS and a
unanimous five-lens spec-skeptic panel (criterion, grounding, scope-fork,
ambiguity, plan-readiness all SOUND).

refs #52
2026-06-17 12:36:39 +02:00
Brummel 6ce00ee053 plan: 0048 walk-forward param plane
Two-task execution plan for spec 0048: Task 1 lands the whole aura-engine/walkforward.rs cut atomically (struct shapes, walk_forward seam, param_stability rewrite, scalar_as_f64 deletion, fixture migration, new Bool-slot test) gated on a crate-only `cargo test -p aura-engine`; Task 2 threads the aura-cli caller and runs the workspace gates. Keeps a windows.is_empty() guard in param_stability to preserve the documented empty-on-no-windows contract (C1).

refs #75
2026-06-16 18:52:32 +02:00
Brummel 791b809413 spec: 0048 walk-forward param plane
Settled-design spec for the walk-forward param-plane cut: WalkForwardResult gains space: Vec<ParamSpec>, WindowRun.chosen_params Vec<Scalar> -> Vec<Cell>, walk_forward takes the space by value (Fn-closure generic untouched), and param_stability schema-checks a per-slot coercer (Bool -> 0/1, Timestamp unreachable per C20) before a type-blind reduction, deleting scalar_as_f64 + its per-value unreachable.

Behaviour-preserving (C1): param_stability yields identical MetricStats over the existing fixtures. Overturns 0047's Fork A (chosen_params stays Vec<Scalar>) — the WF structs carry no serde derives, so the serializability defense is moot; the substantive case is C7 purity + SweepFamily symmetry. grounding-check PASS.

refs #75
2026-06-16 18:42:20 +02:00
Brummel 86746e3d5d refactor(aura-core): Scalar as a native tagged enum, disjoint from Cell; typed RunManifest.params
Scalar was `struct { kind: ScalarKind, cell: Cell }` — "a Cell wearing a kind hat." The recorded reason for that shape was migration ease, which is not a design rationale (CLAUDE.md: rationale != effort), so the struct had no substantive defense. Redefine it as the native tagged union it conceptually is:

    enum Scalar { I64(i64), F64(f64), Bool(bool), Timestamp(Timestamp) }

This is substantively better on four axes: kind/bits skew becomes unrepresentable (illegal states gone); accessors panic loudly on the wrong variant instead of a release-mode silent bit reinterpret; PartialEq derives the documented IEEE-754 / cross-kind value semantics (the hand-roll, needed only because the struct inherited Cell's bitwise compare, is gone); and serde is a plain derive emitting the externally-tagged wire form ({"I64":10}/{"F64":2.5}) — the private ScalarRepr shadow enum that motivated this was never needed. It is also C7-honest: erased-on-the-hot-path (Cell) and self-describing-at-the-edge (Scalar) are two disjoint types bridged by explicit conversion.

The whole public API is preserved (Scalar's fields were private), so call sites do not churn: the enum change is contained to scalar.rs, where cell() now encodes and from_cell() decodes per kind. Cell and ScalarKind are untouched.

With Scalar serializable, lift RunManifest.params from Vec<(String, f64)> to Vec<(String, Scalar)>: the param's kind (an i64 length vs an f64 scale) now survives into the C18 record (runs.jsonl) and the CLI JSON instead of collapsing to f64. scalar_as_param_f64 is deleted; sim_optimal_manifest passes typed params through. This is a deliberate wire-shape change — params now render as tagged scalars; the JSON-asserting tests are updated to the new shape on purpose.

Hand-authored manifest params across the CLI's single-run/mc/macd sites use honest kinds (lengths -> i64, scales -> f64) so they match the sweep path (which already derives correct kinds via zip_params); their in-binary JSON assertions are re-tagged accordingly.

Walk-forward fork resolves with no code change: WindowRun.chosen_params stays Vec<Scalar> (the serializable record carrier), reduced to f64 only at the param_stability statistic boundary (scalar_as_f64 retained). Glossary 'cell' entry updated to describe Scalar as the disjoint tagged union, not 'a cell plus its kind tag'.

Gates: build --all-targets, test --workspace (incl. new scalar_serde_round_trips), clippy -D warnings, doc --no-deps — all clean.
2026-06-16 17:11:25 +02:00
Brummel 3598cb9dde audit: cycle 0047 — drift-clean (cell hot-path carrier)
cycle 0047 tidy. Architect drift review (b188773..82635fa, against the
design ledger C7/C8/C1) found the carrier swap drift-clean:
- Node::eval -> Option<&[Cell]>, all 8 aura-std out-buffers [Cell; N], the
  inter-node forward via the branch-free push_cell (harness.rs:426); Scalar
  survives only on the three keep-set boundaries (param plane,
  AnyColumn::get, source ingestion at harness.rs:402). The convert/keep
  partition and the three-role test rule are honoured site-for-site.
- The dual API is coherent: fallible push (ingestion + kind-guard tests)
  vs infallible push_cell (bootstrap-verified inter-node forward) are each
  load-bearing and tested. No dead code, no C7 violation (no tag on the hot
  path; scratch: Vec<Cell> reused via clear(), no per-cycle alloc).
- Both C7 realization notes + the C8 prose accurately describe the landed
  state. 285 tests green; build/clippy/test/doc clean.

Tidy fix (pre-existing, surfaced by the review):
- docs/glossary.md `node` entry said a node implements `schema()`, but
  Node::schema() was removed in cycle 0024 (the signature is declared
  pre-build on PrimitiveBuilder). Corrected to `lookbacks()` + `eval(ctx)`,
  the methods the Node trait actually carries. Record-reality.
2026-06-16 13:22:55 +02:00
Brummel 82635fa259 refactor: Cell becomes the hot-path value carrier (C7/C8 realization)
Motivation
----------
The C7 realization note (cd3d1ca / 049f22a) deferred this step: with
Scalar split into { kind, cell }, the tag-free Cell could become the
hot-path carrier, but eval and the edges still flowed the fatter
self-describing Scalar. This lands the swap.

Change
------
- Node::eval now returns Option<&[Cell]>; every node out-buffer is
  [Cell; N]. The inter-node forward copies the row into a Vec<Cell> and
  pushes each field via a new branch-free, infallible AnyColumn::push_cell
  — the edge from_field->slot kind match is verified once at bootstrap
  (C7), so the runtime push needs no per-value kind check. It only removes
  a Result the forward path already .expect()ed.
- Scalar stays on the self-describing dynamic boundaries: the param plane
  (build / bind / compile_with_params / sweep points / RunManifest),
  AnyColumn::get (the type-erased read for sinks / serde), and source
  ingestion (Source::next, the heterogeneous C3 merge). The fallible
  AnyColumn::push is retained for ingestion + the kind-guard tests.

Trade
-----
The per-value runtime kind check on node OUTPUT is removed: a node that
builds a wrong-kind cell pushes raw bits with no panic. This is the same
authoring-bug class C8 already leaves to a debug_assert (output width);
node-output-kind correctness is the node's declared FieldSpec contract,
caught by each node's own eval test. Cross-node kind agreement still rests
on the bootstrap kind-check (bootstrap_rejects_*_kind_mismatch, green).

Tests
-----
Behaviour-preserving (C1): 285 green, 0 red. The only test-expectation
edits are carrier re-spellings (Scalar::f64(x) -> Cell::from_f64(x)) of
identical values; test column writes and out-of-graph channel rows stay
Scalar (the spec's three-role rule). Adds an AnyColumn::push_cell
round-trip test plus a cross-kind end-to-end forward test (a mixed
f64/i64 record whose bit patterns diverge across kinds — pins the i64
forward path the f64-only tests cannot catch). Ledger C7/C8 notes updated.

Gates: cargo build / test / clippy --all-targets -D warnings / doc
--workspace all clean.

closes #74
2026-06-16 13:17:49 +02:00