Files
Aura/docs/specs/fieldtest-milestone-walking-skeleton.md
T
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

11 KiB
Raw Blame History

Fieldtest — milestone "Walking skeleton" — 2026-06-04

Status: Draft — awaiting orchestrator triage Author: fieldtester (dispatched by fieldtest skill, milestone-scope variant) Scope mode: MILESTONE (closing functional gate), not per-cycle.

Scope

The "Walking skeleton" milestone (Gitea Brummel/Aura issues #4#8) promises a runnable end-to-end thread (design ledger INDEX.md ~line 20): ingest → one signal (SMA-cross) → exposure/intent stream → sim-optimal broker → synthetic pip-equity signal-quality metric, foldable into a structured RunReport (manifest + metrics, C18/C14), deterministic (C1), reachable via the aura run CLI (#8), and — per C22 — populated enough that "a newcomer sees a populated trace immediately."

This fieldtest derives three end-to-end scenarios top-down from that promise and drives them from the public interface only (the aura binary's observable behaviour, rustdoc, INDEX.md, public re-exports, data-server's public rustdoc). No crates/*/src was read. The artefact under test was built from HEAD (cargo build -p aura-cli; the consumer crate compiled against the current path-dep'd engine crates).

Examples

fieldtests/milestone-walking-skeleton/ms_1_newcomer_cli.sh — the newcomer CLI path

  • Invokes the real target/debug/aura binary (built from HEAD) as a downstream user with nothing but the rustdoc module blurb. Checks: single-line JSON RunReport with the documented {manifest, metrics} shape; exit 0; byte-identical across two runs (C1); a NON-degenerate trace (≥1 exposure sign flip, C22); and the bad-args / usage contract.
  • Fits the promise: this is the one-command surface the milestone says makes the whole thread runnable, and the C22 "populated trace" demonstrator.
  • Outcome: built? yes. ran? yes. matched expected? yes — single-line {manifest,metrics}, exit 0, byte-identical, metrics total_pips=-0.13, max_drawdown=0.17, exposure_sign_flips=1 (populated). Bad/empty subcommand → exit 2, aura: usage: aura run on stderr, empty stdout.

fieldtests/milestone-walking-skeleton/ms_2_real_data_thread.rs — the real-data thread

  • A standalone consumer crate (own [workspace], path-deps on aura-core/std/engine/ingest + git dep on data-server — the shape a C16 project takes) wires the WHOLE thread over real recorded M1 bars: load_m1_window(AAPL.US, 2006-08) → close_stream → SMA(2)/SMA(4) → Sub → Exposure(0.5) → SimBroker(1e-4) → 2×Recorder → f64_field → summarize → RunReport, then folds the report twice and asserts determinism.
  • Fits the promise: this is the literal ingest→…→metric thread over REAL bars, the substance #7 + the milestone claim.
  • Outcome: built? yes, first try. ran? yes (21 M1 bars ingested). matched expected? yes, and better than the carrier predicted — the run is deterministic (cross-process byte-identical RunReport, C1) AND non-degenerate: total_pips=-1.5, max_drawdown=65.5, exposure_sign_flips=6. Window timestamps are canonical epoch-ns. See finding [spec_gap] on the #19 premise.

fieldtests/milestone-walking-skeleton/ms_3_epoch_ns_coherence.rs — epoch-ns coherence

  • Hand-builds 4 M1Parsed bars (data-server's public AoS record) with known time_ms, runs transpose_m1 → close_stream → SMA(2) → Recorder, and asserts the recorded sink-trace timestamps equal unix_ms_to_epoch_ns(time_ms) (= ms·1e6) — the C3 normalization carried intact from ingest through the run loop into the recorded metric stream. No external data needed.
  • Fits the promise: closes the loop on C3 ("normalize at the one boundary") — proves the metric stream a newcomer reads is in aura's canonical time unit.
  • Outcome: built? yes. ran? yes. matched expected? yes — ingest stamps […400e9, …460e9, …520e9, …580e9]; sink trace is the warmed suffix in the same epoch-ns stamps.

Findings

[working] The full real-data thread is authorable from the public interface and is deterministic + populated

  • Example: ms_2_real_data_thread.rs.
  • What happened: the entire ingest→signal→exposure→broker→metrics→RunReport thread compiled on the first attempt from rustdoc signatures alone (Harness::bootstrap, Edge/Target/SourceSpec field layout, summarize/f64_field, the aura-std node ctors, load_m1_window/close_stream). Two in-process folds and two separate processes produced byte-identical RunReports.
  • Why working: the milestone's headline promise — a real ingest→metric thread, deterministic (C1) — is delivered, and the public surface is self-sufficient for a downstream author to wire it. This is the milestone's central win.
  • Recommended action: carry-on.

[working] aura run delivers the C22 populated-trace newcomer path

  • Example: ms_1_newcomer_cli.sh.
  • What happened: one command, single-line {manifest,metrics} JSON, exit 0, byte-identical twice, non-degenerate (1 sign flip, real drawdown). Bad/missing subcommand → exit 2 + usage on stderr + empty stdout.
  • Why working: C22 ("a newcomer sees a populated trace immediately") and C14 (structured face from a binary) are both satisfied by the shipped binary.
  • Recommended action: carry-on.

[working] C3 epoch-ns normalization is coherent end to end

  • Example: ms_3_epoch_ns_coherence.rs.
  • What happened: close_stream timestamps equal unix_ms_to_epoch_ns(time_ms), and the recorded sink trace carries exactly those epoch-ns stamps (warmed suffix). ms·1e6 holds.
  • Why working: C3's "one boundary normalizes, nowhere else" is observably true through ingest → run → sink; the metric stream is in canonical time.
  • Recommended action: carry-on.

[spec_gap] The #19 "AAPL.US too sparse → degenerate metrics" premise does NOT hold for the SMA(2)/SMA(4) demo config

  • Example: ms_2_real_data_thread.rs.
  • What happened: the carrier (and issue #19, from the cycle-0011 per-cycle fieldtest) asserts AAPL.US 2006 is too sparse (~21 M1 bars/month) to warm an SMA-cross, so the real-data run yields all-zero degenerate metrics. Empirically this is false for the SMA(2)/SMA(4) cross (the same fast/slow pair the shipped aura run sample uses): 21 bars warm SMA(4) after 4 bars, the cross produces 6 exposure sign flips, total_pips=-1.5, max_drawdown=65.5 — a populated, non-degenerate trace over REAL bars. The degeneracy #19 observed is window/param-dependent (a deeper SMA, e.g. the longer lengths a realistic daily cross would use, would not warm on 21 bars), not intrinsic to the symbol.
  • Why spec_gap: the milestone never pins the "real-data demo" SMA lengths or window, so two equally-plausible readings diverge on whether the real-data path is degenerate. I picked the shipped aura run config (SMA 2/4); under it the real-data thread is populated, not degenerate. The honest milestone roll-up therefore differs from the carrier's pre-stated assumption: the real-data thread is also a populated-trace demonstrator at the shipped param config, not merely "correct but degenerate." #19's concern remains valid for deeper SMAs / the C22 "name a denser demo symbol" recommendation, but it is not a blocker and the milestone promise is met on real bars at the demo config.
  • Recommended action: ratify (record that the walking-skeleton real-data demo is pinned to SMA 2/4 over 2006-08 and is populated there) AND re-scope #19 to "denser demo data for deep/daily crosses" rather than "real path is degenerate" — the latter is no longer accurate.

[spec_gap] aura run <trailing junk> → exit 0, trailing args silently ignored

  • Example: ms_1_newcomer_cli.sh (aura run extra junk → exit 0, full report).
  • What happened: the arg parser keys only on the first token being run and ignores everything after. aura run garbage runs the sample harness and exits 0.
  • Why spec_gap: re-confirmation at the milestone gate of the cycle-0010 finding (already filed). The milestone's CLI contract does not unambiguously cover run <extra>; the binary chose the lenient reading. Not a regression — same behaviour as cycle-0010.
  • Recommended action: ratify-or-tighten (decide whether trailing args reject with exit 2 or are deliberately ignored). Low priority; carried from #?/cycle-0010.

[friction] aura --help lands on the error path (exit 2, bare usage line)

  • Example: ms_1_newcomer_cli.sh (aura --help → exit 2, aura: usage: aura run on stderr, empty stdout).
  • What happened: a newcomer's reflex first command (--help) is treated as an unknown subcommand: exit 2, no help text, just the one-line usage on stderr.
  • Why friction: the task (discover how to run) completes — the usage line does name aura run — but the conventional discovery affordance returns a nonzero error path rather than help on stdout. For a "newcomer sees a populated trace" milestone (C22), the first-contact ergonomics are slightly off.
  • Recommended action: plan (tidy) — make --help/-h print the usage to stdout with exit 0; keep unknown subcommands at exit 2. Trivial, optional.

[friction] SimBroker slot order is load-bearing, both f64, unchecked at bootstrap

  • Example: ms_2_real_data_thread.rs (had to consult rustdoc to wire slot 0 = exposure, slot 1 = price correctly).
  • What happened: SimBroker's two inputs are both f64, so a swapped wiring is not caught at bootstrap (the rustdoc explicitly warns it "would silently produce a wrong equity curve"). The downstream author must read prose to get it right; there is no typed guard.
  • Why friction: the thread is wireable correctly only by reading the rustdoc carefully — a known, documented footgun, but a footgun. Not a bug (it is documented and the wiring API offers no kind to distinguish the two f64 slots).
  • Recommended action: plan (consider a named-role or distinct-newtype wiring for broker inputs in a later cycle); or carry-on if deemed acceptable given the rustdoc warning. Documented, so low urgency.

Recommendation summary

Finding Class Action
Real-data thread authorable, deterministic, populated working carry-on
aura run C22 populated-trace newcomer path working carry-on
C3 epoch-ns coherence ingest→run→sink working carry-on
#19 "real path degenerate" false at SMA 2/4 demo config spec_gap ratify + re-scope #19
aura run <junk> → exit 0 (lenient) spec_gap ratify-or-tighten
aura --help → exit 2, no help text friction plan (tidy)
SimBroker slot order load-bearing, unchecked friction plan / carry-on

Milestone roll-up

The "Walking skeleton" milestone DELIVERS its promise end to end. The full thread — ingest → SMA-cross → exposure → sim-optimal broker → pip-equity metric → structured RunReport — runs deterministically (C1, cross-process byte-identical), in canonical epoch-ns time (C3), reachable via aura run (#8/C14), and produces a populated trace (C22) on both the synthetic sample harness AND the real AAPL.US 2006-08 bars at the shipped SMA(2)/SMA(4) config. The carrier's pre-stated worry — that the real-data path is correct-but- degenerate — did not reproduce at the demo configuration; #19's degeneracy is a deep-SMA / dense-data concern, not a milestone failure. No bugs found. Two spec_gaps and two friction items, none blocking.