Commit Graph

49 Commits

Author SHA1 Message Date
claude 1baee774bb feat(aura-cli): --tap TAP=FOLD fold-subscription selector on aura run
Decide #310's data-authorability fork as (b), split by run-mode
authority: selecting a Named fold subscription is data-reachable on the
one-shot run path; adding a fold stays a Rust entry (role 2, C25).
`aura run` gains a repeatable --tap TAP=FOLD selector feeding the
existing TapPlan seam: no flag keeps the record-all default; any flag
replaces the plan entirely (unlisted taps stay unbound — C27 inert,
non-error). Validation stays in bind_tap_plan (roster-enumerating label
refusal, typed UndeclaredTap, both before store I/O); parse-level
refusals (malformed pair, duplicate tap) exit 2 via the verb's usage
convention.

Rejected alternatives (minuted on #310 with the skeptic-pass
rationale): an op-script/blueprint carrier (C27 forbids recording
policy in the serialized fragment); ratifying Rust-only (softens a
designed-in promise with effort as the only rationale). The
campaign/document carrier and the persist_taps/declared-tap namespace
reconciliation are deferred to the Measurement-reachable milestone
(#312/#327, minuted on #312).

Ledger: C27 Current state records the boundary; the superseded sentence
moved verbatim to the new c27-declared-taps.history.md sidecar; the
glossary tap-plan paragraph updated, fixing the pre-existing inaccuracy
that named `aura measure` a record-all-passing verb (it is the post-hoc
IC analysis and constructs no tap plan).

Verification: 5 new unit tests (parse branches), 5 new binary-level
selector tests incl. a byte-identity pin of an explicit all-record plan
vs the record-all default (C1), 1 measurement-arm test; full workspace
suite green; clippy -D warnings clean. Independent opus diff review:
approved, no Important/Minor findings (nits: inert-arm generic refusal,
a=b=c falling to the roster refusal — accepted as-is).

closes #310
2026-07-24 15:03:39 +02:00
claude 913d18755e docs(ledger, glossary): the stderr class-marker grammar joins C14
Iteration stderr-markers-2 close, task 5 of the stderr-class-markers
plan. C14's Current state gains the marker paragraph — note/warning
classes for continuing-run diagnostics, bare `aura: ` for exit-carrying
error lines and plain info lines, grep-stable grammar, single source in
aura-cli/src/diag.rs — and the glossary gains the `stderr class marker`
entry. No new C-number: C14 already owns the CLI stderr conventions and
the exit-code partition this grammar completes (derivation logged on
the #278 decision thread).

With this the milestone promise is shipped: the two diagnostic classes
are machine-separable on stderr (#278), and the all-zero-trade
walk-forward announces itself instead of completing silently (#313).
Exit-code semantics unchanged throughout.

closes #278
closes #313
2026-07-23 23:36:08 +02:00
claude bd0c557f16 docs(ledger, glossary): tap-subscribers cycle tidy — C8/C27/C28 lifts, tap subscription vocabulary
Cycle-close audit for the #283/#77 tap-subscribers cycle
(09994b8..6e3f394). Architect review: code contract-clean; what
holds — C1/C7/C8 (empty-output caller-built consumers, (Timestamp,
Cell) zero-heap payload, lifecycle hooks inside the sequential loop,
byte-identical twin-run and streamed-vs-legacy byte-equality pins),
C28 (assembly-crate placement of the writer-holding consumer,
c28_layering guard green), C25 (registry growth = new Rust entry,
data-expressible Named form, roster-enumerating refusals). All drift
items were doc lifts, resolved in this commit:

- C8: the lifecycle is now a symmetric pair — initialize() as
  finalize's start-of-stream mirror (infallible by signature;
  acquire-in-initialize, degrade-to-inert, surface-once-at-finalize);
  history sidecar records the refinement and the #77 resolution the
  old Deferred paragraph still carried as open.
- C27: Guarantee and Current state now describe the shipped model —
  tap plan (Named{label, params} | Live) over the layered fold
  registry, BOTH entry points (run_signal_r AND run_measurement) on
  the one shared wiring pair, record streaming at constant memory.
- C28: aura-runner now defines one graph node of its own (the
  in-graph record consumer — exactly the graph-meets-persistence
  assembly position); the #297 refusal-site count grows ~20 → ~24
  (the four tap-plan refusals, already typed before the exit).
- glossary §tap: the subscription/fold-registry sense added; Avoid
  line steers probe/monitor/scope away from the observation slot.

Bench (report-only, loadavg 5.8 > 2 on the box — read with care),
all fingerprints OK, no regression:
  engine_throughput    bars_per_s 14005262   wall_s 0.714s   Δ bars_per_s +3.0% wall_s -3.0%
  ingest_throughput    bars_per_s 12970670   wall_s 0.387s   Δ bars_per_s +0.5% wall_s -0.5%
  campaign_sweep       cpu_percent 2202.0   peak_rss_mb 92.2   wall_s 1.396s   Δ cpu_percent +1.5% peak_rss_mb -6.1% wall_s -1.5%
  campaign_heavy       cpu_percent 2155.0   peak_rss_mb 94.8   wall_s 5.585s   Δ cpu_percent +1.8% peak_rss_mb -3.5% wall_s -0.4%
  cli_fixed_cost       help_ms 1.5ms   run_ms 3.6ms   Δ help_ms -1.8% run_ms -2.6%
No baseline update (report-only surface; no ratify due).

Correction on 6e3f394's body: "no Probe symbol is introduced
anywhere" — introduced is the operative word; the pre-existing
aura-core test fixture `struct Probe` stays, as the cycle's design
record specified.

Follow-ups on the tracker: #308 (legacy Recorder surface migration),
#307 (binary trace format). Cycle spec/plan working files discarded.

refs #283 refs #77
2026-07-21 23:56:14 +02:00
claude a12617bb80 audit: document-first cycle close — doc verb rosters caught up
Architect review (cycle 757e3ac): core clean — show is pure shell
dispatch over Env::registry() (C28); both ledger amendments match the
F1-F8 decision log exactly; document schema untouched; the #164
no-framing pin is stricter than the spec snippet asked. Four peripheral
drift items, resolved:

- fix: docs/authoring-guide.md verb rosters now name show (process) and
  show|runs (campaign) — the guide teaches exactly the
  generate->retrieve->extend loop this cycle closed.
- fix: docs/glossary.md campaign/process document entries carry the
  settled verb sets (record-reality glossary write).
- fix: show_process's not-found refusal now sources its prose from
  ref_fault_prose(ProcessNotFound) instead of a hand-copied format!
  (byte-identical, test-pinned; the campaign-side prose has no RefFault
  sibling and stays the single campaign instance).
- ratify (log-only): the shipped show helpers use print! (no framing,
  #164) where the spec snippet sketched println! — the code is the
  stricter, correct form; recorded on the reference issue's decision
  log. The spec is a git-ignored working file swept at this close.

Regression: aura-bench report-only run, all fingerprints OK, deltas in
noise (host load 9.6 noted; engine/ingest/campaign/cli lanes all within
±5%). Full aura-cli gates re-run green after the tidy edits.

refs #300
2026-07-21 12:58:02 +02:00
claude a5e02ff541 docs: SessionFrankfurt output semantics + declared-tap authoring (#285)
Surfaced by the measurement-milestone fieldtest: a downstream author
reaching for session anchoring or declared taps had no public statement of
either — the semantics lived only in node source / the design ledger.

SessionFrankfurt / Session output semantics:
- glossary `session node`: corrected — it claimed three streams
  (`bars_since_open`, `in_session`, `session_open_ts`), but the shipped node
  emits ONE `i64` field `bars_since_open`. Now states the real contract: the
  count of completed bar-periods since the local (tz-aware, DST-correct)
  session open, close-instant indexed (09:15->1, 09:45->3; pre-open <=0), with
  the Frankfurt 09:00 Europe/Berlin open + `period_minutes` knob + the
  value-ignored `trigger`.
- authoring-guide: a "Session anchoring: the SessionFrankfurt preset"
  subsection — schema (trigger / period_minutes / bars_since_open), the
  close-instant multiples, the EqConst gating pattern, DST handling, and the
  add-snippet. Verified against `aura graph introspect --node SessionFrankfurt`.

Declared-tap authoring (C27 / the #284 tap op):
- authoring-guide: the `tap` op-table row (seven ops -> eight) + a worked
  "declaring a measurement tap" example. The example is verified: piping it
  through `aura graph build` emits
  `taps:[{"name":"spread","from":{"node":2,"field":0}}]`.
- design ledger op-list (INDEX.md): a `tap` bullet (seven verbs -> eight);
  also corrected the `expose` "only verb that keeps `as`" claim — `tap` keeps
  it too.
- README op-kind enumeration: adds `tap`.

Docs only; no code change. Both worked examples were run through the built
`aura` binary; the SessionFrankfurt schema was checked against introspect.

closes #285
2026-07-18 16:31:17 +02:00
claude 9005fd53a2 docs(glossary): record the C27 author-declared sense of 'tap' (#282)
The measurement milestone overloaded 'tap': beside the closed campaign
persist_taps vocabulary (equity | exposure | r_equity | net_r_equity), the
word now also names a declared tap — a Composite.taps entry a hand-authored
blueprint declares on an interior output wire (C27), the output-side twin of
an input_role, bound run-mode-aware. Record-reality glossary update
reconciling the two senses; a worked authoring example is owed at docwriter
(#285).
2026-07-18 00:48:43 +02:00
claude d1b3a3dd31 feat(research,composites,cli,docs): vol_tf — the timescale-matched stop regime
The second risk-regime variant vol_tf{period_minutes, length, k}
computes the vol estimator over completed time buckets: an H1 signal
gets an H1-matched stop in the research matrix instead of a hand-scaled
minute stop (the issue's k-inflation workaround retires). Additive
externally-tagged serde (stored Vol documents keep their content ids);
the executor arm wires the VolTfStop primitive via the builder+bind
chain; validate checks period_minutes/length/k positivity per regime.

The member-manifest round-trip holds for both variants (C1): vol_tf
members stamp stop_period_minutes/stop_length/stop_k and the reproduce
path re-derives the VolTf stop whenever stop_period_minutes is present
— never a silent default-Vol fallback. The Regimes slot label and the
unit notes name the new variant (period_minutes IS the stop's
timescale); glossary, authoring guide, and design ledger record the
second variant. Default regime and sugar paths byte-untouched.

Coverage: node units (rollover-only emission, bucket-delta math, the
constant-|delta| correspondence with the per-cycle regime), executor
fold, serde/validate units, the manifest round-trip unit, and a
hostless two-regime e2e (distinct ordinals; vol_tf members stamp their
timescale, vol members do not).

closes #262
2026-07-14 02:55:02 +02:00
claude e8b6878d3b feat(research,cli,docs): state cost and risk knob units in introspect and the glossary
campaign introspect --unwired now annotates the four silently
misreadable knobs with unit/semantics sub-lines: cost_per_trade is a
price-unit numerator charged as cost/|entry−stop| in R (not a cost in
R); slip_vol_mult multiplies the per-cycle vol estimate; vol.length
smooths the estimator and does not set the stop's timescale; vol.k
scales the stop distance (the risk-unit lever). Rendered additively
via a new OpenSlot.notes field, so the sibling tests pinning the slot
hint lines verbatim stay green byte-identically.

The glossary's cost-model and risk-regime entries mirror the same
semantics inline (two-sentence convention kept), the risk entry
pointing at #262 for the timescale-matched variant.

closes #265
2026-07-13 23:12:36 +02:00
claude e4fb64d7c6 docs: bound params are overridable defaults — C12 amendment, glossary, guide
Task 7 of the bound-override cycle: the design ledger's C12 records the
bound-as-default semantics (axis 1 may name a bound param; identity reads
the authored document; the retired axes-bind-only-open-knobs restriction
was an implementation consequence, not a recorded decision), the glossary's
blueprint entry carries the same sentence, and the authoring-guide's
data-only starter section explains the one-file run+sweep quickstart.

closes #246
2026-07-13 04:32:47 +02:00
claude 0170ec277f docs: two-tier project model — layout, guide, glossary, ledger, invariant 9 (#241 T7)
- CLAUDE.md invariant 9 amended end to end: a project is a directory
  anchored by a static Aura.toml, data-only by default; native node
  logic lives in attached node crates (the nodes/ antecedent removed —
  user decision 2026-07-12, re-opened by the role model's diagnosis).
- docs/project-layout.md reworked to the two tiers (data-only default
  tree + sibling node crate, workspace note under the crate half); the
  day-in-the-life walkthrough now attaches the project's node crate
  once and wires the namespace the shown command actually produces.
- docs/authoring-guide.md: data-only quickstart (closed run target,
  open sweep target) + `aura nodes new` as the native entry; section
  cross-reference updated.
- docs/glossary.md: new "data-only project" and "node crate" entries;
  Aura.toml and manifest entries carry the tier split.
- docs/design/INDEX.md: realization note (wiring-only tier, #241) in
  the project-environment section.
- rustdoc: `[nodes]` intra-doc-link escapes in project.rs/main.rs.

Full gates green: workspace suite (all binaries), clippy -D warnings,
doc build without new warnings.

closes #241
2026-07-12 17:45:59 +02:00
Brummel 43a427bfed audit: run-tail close — ledger and glossary reconciled to the shipped state
The tail audit over d1e01ef..62f6592 found no code drift against the
contracts (C18 name-resolution read-only, C23 doc identity-blind and
inline-dissolved, C1 fit deterministic) but four lagging records, fixed
here: the #106 real-roller amendment gains the #239 fit-to-window note
(fixed sizes are a ceiling on the sugar path); a #125 realization note
records the composite doc as a C23 debug symbol with its serde/identity/
viewer treatment; the glossary identity-id and composite entries name
the doc; GraphSession::finish states the deliberate absence of a
doc-carrying op-script surface (refs #125) instead of leaving the
authoring asymmetry silent.
2026-07-11 20:25:09 +02:00
Brummel 18f8e72946 feat(cli): chart resolves a --trace family by its chosen campaign name (#238)
The NotFound arm of emit_chart now queries the recorded campaign runs:
records with a persisted trace_name whose stored campaign document
carries name == ARG. A unique match re-dispatches the existing charting
path onto the resolved handle; several matches refuse listing the
candidate handles in append order (refuse-don't-guess — re-running a
named invocation legitimately yields {campaign8}-0, -1, ...); zero
matches keep the not-found message verbatim. The exact trace-store
handle always wins; the name never becomes a store key (C18 untouched).
Guide §3 and the glossary tap entry document the name alternative.

closes #238
2026-07-11 18:04:09 +02:00
Brummel f5911645f1 docs: ratify the milestone-fieldtest doc findings
- glossary "tap" + authoring-guide §3: the chart handle of a
  sweep/walkforward --trace family is the printed family handle
  (members keyed <cell>/<member>) — the campaign trace_name analog was
  documented, the sweep case was not (fieldtest spec_gap).
- authoring-guide §0: state the input window's financial-style ordering
  (index 0 = newest, index k = k cycles back) where the node pattern is
  taught — previously only in the design ledger's RingBuffer note.
- authoring-guide §3: the #234 cost block joins the open-slot list, the
  worked campaign example, and the prose (charge modes, net-vs-gross
  default, manifest stamping) — it was discoverable only via
  campaign introspect --unwired.

Fieldtest fixtures: 09da04f.
2026-07-11 15:05:31 +02:00
Brummel fc9cf23b87 feat(cli,docs): ship the ganged open examples + document the gang construct (#61 tasks 7-8)
The two open examples now expose their author-intended single knobs — the
closed builders always bound these pairs to one value by hand; the open forms
falsely offered them as independent axes:
- r_breakout_open: channel_hi.length + channel_lo.length -> channel_length
  (the Donchian channel is structurally ONE parameter)
- r_meanrev_open: mean_window.length + var_window.length -> window; the band
  factor stays an independent axis
Regenerated via the emitters (never hand-edited); the closed examples are
byte-unchanged. The carve builders gang in the open branch only.

Test migration: the two axis-namespace pins, five --real e2e invocations
(single gang axis, the 10,20 diagonal for the campaign pair — the mismatched
20,40/10,20 grid was exactly the configuration space the gang retires), and
the param_stability row counts (4 -> 3). The r-sma walkforward golden anchor
is untouched (it never swept a ganged pair).

Docs: authoring-guide gains the seventh op + the third param state
(open/bound/ganged) + the gang wrap note; README op list + Axis concept;
glossary gang entry; ledger C24 records the gang verb and the pre-ship
Tier-2 dormancy (no format-version bump while no out-of-repo reader exists).

Verified: full workspace suite 1104/0 (--real e2e included, local data
present), clippy -D warnings clean, cargo doc clean; live acceptance:
introspect --params prints channel_length:I64 alone / window:I64 +
band.factor:F64.

closes #61
2026-07-10 14:07:22 +02:00
Brummel 08b0f9c783 docs: #216 cycle-close audit — run-transcript regimes + glossary avoid reconcile
refs #216

Architect drift review over 68317ec..6e22c98 (two items, both fixed here;
code and ledger verified drift-clean):

- The authoring guide's 'Register and run' transcript still showed the
  pre-regime world (2 cells, regime-less family ids) directly under the
  worked example this cycle made two-regime / 4-cell. The transcript now
  shows the -r1 family-id suffix, per-cell regime fields (ordinal 0
  serialize-skipped, the established byte-stability pattern), the four
  cells, per-regime generalization entries, and a prose paragraph tying
  the 4 cells to the validate count (regimes compared, never pooled).
- The fresh glossary entry declared 'Avoid: stop regime' while this very
  cycle ships 'stop regimes' in its hint strings and guide prose — an
  Avoid line the codebase itself violates records intent, not reality.
  'stop regime' is dropped from Avoid ('risk section' stays: it wrongly
  suggests a section rather than an axis list).

What holds (architect): content-id parity untouched (probe is read-only,
canonical bytes unchanged); the validate cell product mirrors the exec
cross-product exactly; all six spec acceptance criteria shipped.

Regression: cargo test --workspace 62 result groups / 0 failures; clippy
-D warnings clean; cargo doc 0 warnings (all at 6e22c98; this commit is
docs-only).
2026-07-09 18:27:15 +02:00
Brummel 6e22c98e23 test(cli),docs: risk-axis introspection pins + guide/glossary coverage (#216 slice 2)
closes #216

The remaining introspection e2e pins: the bare-{} envelope probe (the
issue's exact reproduction) lists the optional risk slot; a bound
(non-empty) risk list closes it (no open slots); an EXPLICIT empty
'risk': [] still counts as open (pins the non-emptiness branch, which an
is_none()-based probe would get wrong); the --block std::risk assert is
sharpened to pin the optional rendering and the block doc line (the old
bare contains("risk") matched std::risk trivially).

Docs: the authoring guide's bare-{} transcript gains the risk line, the
§3 worked example gains a two-regime risk section (heading updated), a
prose paragraph explains the structural risk axis (stop defines R;
absent = the same default vol regime the verbs bind), and both validate
transcripts show the new matrix counts. The glossary gains the
'risk regime' entry (canonical term; avoid: stop regime, risk section).

Verified: cargo test --workspace 62 result groups / 0 failures; clippy
-D warnings clean; cargo doc 0 warnings; the guide's transcript strings
grep-match the shipped hint/summary bytes (1/2/1).
2026-07-09 18:19:01 +02:00
Brummel 4acea45519 chore(cli,docs): #220 cycle-close audit — doc reconcile + dispatch dedup
Cycle-close audit for the verb-axis-generalization cycle (a2294c7,
e7efe1f, b849bb7). Architect drift review: what holds — all four verbs
route through the one validate_and_register_axes seam into the campaign
executor; RGrid gone workspace-wide; zero too_many_arguments allows in
verb_sugar.rs; no r_sma_open embed at the verb dispatch sites (the
aura-graph default embed survives by design). Five drift items found,
all resolved fix-path in this commit:

- README (blueprint-verbs section + mc row), glossary (walk-forward
  entry), and ledger (verb-dissolution passage) reconciled to the
  shipped generic grammar; the ledger HISTORY note now separates the
  two supersessions correctly (#159 retired the built-in --strategy
  demo surface; #220 de-welded the verbs) instead of mis-attributing
  the weld removal to #159.
- Four stale characterization doc-comments in cli_run.rs reworded:
  the retired welded grammar is now named as the pinned grades'
  provenance, not the current spelling; one dangling reference to a
  deleted test repointed to the live anchor.
- The quadruplicated dispatch blocks extracted into two shared helpers
  beside validate_and_register_axes: exit_axis_register_error (the
  AxisRegisterError exit-map, byte-identical stderr + exit codes) and
  campaign_window_ms (from_choice -> full_window -> unix-ms clip);
  generalize's explicit unclipped (Some, Some) passthrough arm is
  untouched — only its fallback arm, which already ran the identical
  mechanics, calls the helper.

Regression gate green, no baseline moved (nothing to ratify):
cargo test --workspace exit 0, 62 test-result groups, 0 failures;
clippy --workspace --all-targets -D warnings clean; cargo doc
--workspace --no-deps 0 warnings. Spent cycle spec + plan working
files discarded per lifecycle.

refs #220
2026-07-09 15:35:47 +02:00
Brummel 07a73fb66e docs(cli,ledger): sweep #159 demo-retirement drift — stale comments + ledger notes
Cycle-close audit tidy for the #159 demo-retirement arc: behaviour-free
reword of prose/comments/docs left pointing at symbols the arc deleted.
Adversarially verified by the audit workflow; cargo build --workspace
--all-targets green.

- README: drop the removed `--harness` token; restrict the legacy built-in
  form claim to walkforward/mc/generalize (run/sweep no longer resolve one).
- glossary: the built-in `--strategy` sweep surface is retired (#159), not a
  live inline path.
- INDEX.md ledger: append [HISTORY] supersession markers (house style) to the
  dated realization notes advertising the retired `--harness` / built-in
  `--strategy` CLI forms (cost-flag #153, cycles 0065/0066/0067, name-res,
  #210 status); historical text preserved.
- aura-engine test-fixture docs: drop dead cross-crate refs to the deleted
  aura-cli fns sample_harness / build_sample and the deleted `macd` composite.
- cli_run.rs: reword the #159-cut-2 pin doc to the current clap generic-usage
  reality (no strategy_from / Strategy::RBreakout); r_sma_sweep_family ->
  blueprint_sweep_family.
- verb_sugar.rs: fix the pre-existing `E[R]` unresolved-doc-link warning.

Remaining tidy — the main.rs comment cluster plus its rustdoc link at :1546
(the second cargo-doc warning) — held for a follow-up issue. The dead
cost-graph branch is tracked in #221. refs #159
2026-07-08 11:12:22 +02:00
Brummel b761b3c9c2 docs: close the verb-dissolution milestone — ledger status 4/4 + glossary sugar note
The verb-dissolution STATUS paragraph read "cycle 0110 dissolved the first verb
… Remaining: generalize, walkforward, and mc's R-bootstrap path" — stale at HEAD,
where all four verbs are dissolved. The per-cycle audits were each scoped to
their own commit range, so the cumulative status line lagged; the milestone
close fieldtest (#210, 2026-07-07) surfaced the drift.

Refresh the paragraph to the completed state, and record the per-verb
dissolved-form asymmetry as intended scope (ratify): for sweep the dissolved
form is the blueprint file (`<bp.json> --real`) while `aura sweep --strategy
r-sma --real` stays the inline built-in path — the built-in `--strategy` demo
surface is #159's hard-wired-harness retirement target, not the dissolution's;
for generalize/walkforward/mc the dissolved form is `--strategy r-sma --real`.

Glossary: note in the sweep and walk-forward entries that the CLI verbs are now
thin sugar over the campaign path.

Milestone closed 2026-07-07 on a green end-to-end fieldtest (0 bugs). Forward
findings filed: #216 (risk-axis discoverability), #217 (verb knob asymmetry),
#218 (no-project store litter).

refs #210
2026-07-07 10:48:17 +02:00
Brummel f96796cd08 docs: close the cycle-0110 fieldtest doc-drift findings
Authoring guide §1: the inline SMA-crossover op-script no longer binds
fast/slow lengths — it is byte-identical to the corpus file it claims
to match (content id 597d719b… verified against the binary), and the
previously unwritten rule is stated: an op-script bind pins a param
OUT of the sweepable space (closed — no campaign axis or --axis can
reopen it). New passage + example distinguishing the raw param-space
namespace (--params, campaign-document axes) from the wrapped
--list-axes/--axis surface; glossary sweep entry carries the same
one-sentence distinction.

refs #210
2026-07-04 19:38:36 +02:00
Brummel 2c729965db audit: cycle 0110 tidy — verb-dissolution cycle 1 closed drift-clean
Architect review (scope e7c7bde..b7aaa0b) found three items; resolutions:

- fix: docs/authoring-guide.md + glossary aligned with the shipped
  vocabulary (std::sweep selection group optional/all-or-nothing,
  selection-free = terminal-only, worked example verified against the
  live binary).
- fix: the #203 wrapped/raw axis-name convention is now single-sourced
  in campaign_run.rs (wrapped_to_raw_axis + raw_matches_wrapped, a
  cross-documented inverse pair; dispatch_sweep and both bind sites
  call through it; inverse-property unit test). Ratify note: this
  unifies two previously different algorithms onto the documented
  first-segment semantics — the old loose ends_with suffix-match also
  accepted sub-segment shorthands (e.g. axis "length" against
  "sma_signal.fast.length") that no stored document or test used;
  such shorthands now refuse loudly (unbound/unknown axis) instead of
  matching, the refuse-don't-guess reading of #203.
- carry: run_blueprint_sweep/blueprint_sweep_family remain generically
  real-capable though the dispatch no longer routes real data to them;
  the residual capability is shared DataSource machinery, its removal
  falls out with the built-in/synthetic branch retirement (#159), and
  the synthetic-only status is documented at the fn.

What holds: C24 canonical form (flatten group leaves every stored
content id unchanged, golden pin untouched), C18 lineage (topology_hash
IS content_id_of, single store write resolves the strategy ref;
selection-free arm still persists the full family), C25 closed-
vocabulary discipline (all-or-nothing group, Blockly-clean), C3 (ms/ns
conversion through the ingest seam's own named fn).

Ledger: #109 open-thread status lifted to cycles 0107-0110 reality
(executor shipped, amendment package landed, verb dissolution running
as milestone #210 with sweep dissolved).

Regression gates: cargo test --workspace 1056/0; clippy -D warnings
clean; cargo doc clean. Cycle spec+plan removed at close per
convention.

refs #210
2026-07-04 19:16:06 +02:00
Brummel 6f2cf443c4 fieldtest: milestone-research-artifacts corpus (GREEN) + Aura.toml data-key doc fix (F7)
MILESTONE VERDICT: GREEN — the whole span (0106-0109) holds end to
end as one continuous consumer scenario: authored from a bare {} via
introspection alone, every ref resolved from the public surface, three
validation tiers, run by content id over two real instruments through
the full v2 pipeline, realization recorded (selection/survivors/
bootstrap/generalizations/trace_name), traces on disk and charted,
read back via campaign runs, byte-identical re-runs (C1), refusals
precise. 0 bugs, 0 frictions, 0 spec gaps; 2 doc-gaps.

F7 fixed in this commit (the docs claimed an archive-root path without
naming the key; a guessed [paths] archive silently no-ops): project-
layout and the glossary Aura.toml entry now name [paths] data, and the
aura new template advertises the commented-out key. F8 (op-script
grammar not CLI-discoverable) filed as #208, sibling of the #197 docs
half — one docwriter pass once desired.

The milestone-close gate evidence is this corpus; the formal milestone
close and the push remain user-reserved.

refs #189
2026-07-04 04:45:36 +02:00
Brummel 179c2f8bf0 audit: cycle 0109 tidy (drift resolved by ledger/glossary lift + tap-channel cross-pin)
Architect verdict: drift_found — the code holds (C1 honored not
assumed: the nominee re-run's metrics-equality hard refusal; C22/C14
clean: existing TraceStore + unchanged viewer, serde-default widening
round-trips, name composition single-sourced in derive_trace_name).
Resolved here:

- C18: the 0107 paragraph's 'persist_taps is deferred' points forward;
  new cycle-0109 realization paragraph records the closed tap
  vocabulary + UnknownTap tier, the nominee-only non-reduce re-run
  with the C1 metrics guard, the campaign trace family layout, the
  trace_name claim contract, the loud-skip lines, and the noted
  chart-over-family-root debt.
- Glossary: tap entry names the closed vocabulary + escalation rule;
  campaign document's presentation clause references it; campaign run
  gains the trace_name pointer.
- Debt fixed inline (architect med): tap_channel gains the
  emit_vocabulary-twin debug_assert cross-pin so a fifth vocabulary
  tap fails loudly instead of silently skipping.

The consumed 0108 fieldtest spec is removed with the cycle's spec+plan
(all its dispositions shipped: F6 #205, F8 #207, F11 #206, F7/F9/F10
doc-tightens).

Regression: cargo test --workspace 1041/0; clippy -D warnings clean;
cargo doc 0 warnings.

refs #201
2026-07-04 04:22:41 +02:00
Brummel 197936b27d docs: annotator-stage discoverability tightens (fieldtest 0108 F7/F9/F10)
The std::monte_carlo block doc now names the position-dependent
semantics (pooled OOS after wf / per-survivor otherwise) and the > 0
execution guard the generic u32 slot hint could not carry; the
std::generalize block doc names campaign scope, the >= 2-instrument
need, and the R-expectancy metric family. Glossary: new 'stage
bootstrap' entry defines the realization payload incl. prob_le_zero;
the campaign-run entry gains the generalizations schema and the
stdout-wrapper-vs-bare-store-line note. Introspection text and
glossary only — no document content id moves.

Gates: workspace green, clippy clean.

refs #200
2026-07-04 01:56:48 +02:00
Brummel ae2fac3212 audit: cycle 0108 tidy (drift resolved by ledger/glossary lift)
Architect verdict: drift_found — the expected pre-audit doc lag; the
code holds (C1: doc-seeded bootstrap + BTreeMap-ordered generalize;
C14/C23 sparse widening pinned by the pre-0108-line parse test;
terminal-annotator dataflow confirmed — nothing flows out, no new
emit kind, no content-id movement). All items resolved here:

- C18: 0107's 'refuse loudly at preflight' points forward; new
  cycle-0108 realization paragraph records the v2 shape, the
  dual-input stage bootstrap, campaign-scope generalize, the tier
  boundary (test-pinned on both sides), the record widenings, and
  the stringly wf-detection debt.
- Glossary: campaign document -> v2 shape; bootstrap and Monte-Carlo
  entries disambiguate the three senses (construction vs statistical
  r_bootstrap vs seed axis — the std::monte_carlo stage IS the
  trade-sequence bootstrap, named for r_bootstrap's arguments);
  generalize gains the campaign-scope realization.

Regression: cargo test --workspace 1025/0; clippy -D warnings clean;
cargo doc 0 warnings. Spec + plan removed at close per convention.

closes #200
2026-07-04 01:33:00 +02:00
Brummel 428f83c542 audit: cycle 0107 tidy (drift resolved by ledger/glossary lift)
Architect verdict: drift_found — the code holds its contracts (C1
determinism incl. lowest-index fault attribution and doc-seeded
deflation; C16 seam: aura-campaign excludes ingest/std/composites,
MemberRunner isolates the condemned CLI scaffolding; the walk_forward
lockstep set moved together), the docs lagged the tree. All six drift
items resolved in this commit:

- C18: 'no executor exists' retired (0106 text now points forward);
  new cycle-0107 realization records the executor, the aura-campaign
  home, ListSpace, the campaign_runs.jsonl sibling store, zero-survivor
  exit-0 semantics, emit/persist_taps split, the #196 on-ramp, and the
  machinery-true std::walk_forward correction.
- C16: aura-campaign added to the non-node crate enumeration
  (cycle-0107 realization; explicitly not C21's World).
- Glossary: campaign document entry corrected (run verb, execution
  prose); new 'campaign run' entry; blueprint entry gains the on-ramp
  verbs.

Carry-on debt (self-noted in code, tracked): metric-roster
triplication #190, deflation-constant duplication #199; cross-cell
fault orphans + nested-parallelism oversubscription noted in the
tasks-6-7 commit body. Follow-ups filed on the milestone: #200
(mc/generalize stage execution), #201 (persist_taps wiring).

Regression: cargo test --workspace 987/0; clippy -D warnings clean;
cargo doc 0 warnings. Spec + plan removed at close per convention
(durable rationale lives in the ledger; the canonical record is the
git history).

closes #198
2026-07-03 22:07:44 +02:00
Brummel e73aadae1e docs(ledger): #188 amendment package — C25 role model, C20/C22 refinements, invariant-10 clarification
C25 (new): the nine authoring roles cut by artifact + surface + iteration
cost, the recognizability test, the 6a/6b split on invariant 12's tier
boundary with the id machinery as interface, the text-first/headless-first
invariant (visual surfaces = stateless projections, viewers over editors),
and the Blockly litmus test as every vocabulary's acceptance criterion.

C20: the 'plain Rust loops, not a config schema' clause and the mini-DSL
forbid are scoped — they forbid an open logic-bearing language, not the
closed-vocabulary campaign document that now carries experiment intent
under the P1 construct tier; generators may stay Rust, what they yield is
data.

C22: stateless-projection refinement generalized to all artifact classes;
the shipped face recorded as the web-from-disk front. Glossary playground
entry aligned (the egui-native wording was stale against the 2026-06
revision).

CLAUDE.md invariant 10: clarified that closed-vocabulary data artifacts
(op-scripts, blueprints, process/campaign documents) are not the forbidden
DSL — RustAst failed as an open logic-bearing language; new logic
escalates to a Rust block, never a freetext hole.

All content ratified on #188 (body + addenda + resolution comments); this
commit is production of the durable record, no new design.

closes #192
2026-07-03 16:30:51 +02:00
Brummel ebe85683c9 audit: cycle 0106 tidy — ledger/glossary lift, unwired-hint fix, spec/plan retired
Architect drift review (holds: C14 headless authoring, C16/C17 no-DSL with
aura-research a true leaf, content-id move behaviour-preserving per the
untouched id goldens). Resolution per item:

- fix (docs): C18 gains the cycle-0106 realization note (processes/ +
  campaigns/ stores, document canonical form, the content-id primitive's
  library home, the referential tier, no-executor status); the #109
  analysis-meta-level open thread records the artifact half shipped v1 and
  what stays open (executor question, verb dissolution 'once it carries',
  the remaining #188 amendment package). Glossary: new campaign document +
  process document entries; content id generalized to all three artifact
  classes; experiment marked superseded by the campaign document (#188
  re-cut of the builder-API thread).
- fix (code): the --unwired guide advertised an identity_id process ref
  that validate_campaign refuses — the process.ref open-slot hint now says
  content-id-only (strategy refs keep both); lib + seam pins updated.
- filed forward: #190 (metric-vocabulary single-sourcing, the 0105 roster
  drift class), #191 (identity-ref store scan is O(store), performance
  only).
- carry-on: regression gates green by hand — cargo test --workspace 916/0,
  clippy -D warnings clean, cargo doc --no-deps 0 warnings; no baseline to
  ratify (project has no metric baseline scripts).

Cycle 0106 spec and plan retired per convention (git rm); durable record
is the ledger notes above plus #188/#189.

refs #189
2026-07-03 16:27:02 +02:00
Brummel 691562494b docs: fieldtest F3/F6 doc-gap fixes — manifest provenance in glossary, Aura.toml scaffold reality
Two doc-tightenings from the green milestone fieldtest (F3, F6 in
fieldtests/milestone-project-environment/FINDINGS.md): the glossary
manifest entry now names the topology hash and the project provenance
block {namespace, dylib_sha256, commit} a project-hosted run carries;
project-layout.md's Aura.toml annotation now matches what the scaffold
actually emits today ([paths] runs only — the data archive root joins
once real data enters).

refs #180
2026-07-02 22:24:02 +02:00
Brummel 7b429f931a audit: cycle 0104 tidy (drift-clean after three doc-mirror alignments)
Architect drift review (range d5c4361..45fb06d): drift_found, three items,
all doc-mirror — resolved inline as close-fixes:
- docs/design/INDEX.md — the two #171 deferral passages (C18 #158
  realization + C24 status) now record the shipped identity id (additive
  sibling; content id keeps the store/reproduce roles; introspection-only
  until a dedup consumer exists). Whole-harness / structural-axis
  content-addressing stays deferred.
- README.md — introspect table gains the --identity-id row incl. the
  combinable id-flag behaviour.
- docs/glossary.md — three record-reality entries: content id, identity id
  (Avoid: identity hash, topology-identity hash), topology hash; the
  README row aligned to the canonical term.

What holds (architect): additive-sibling discipline intact (no store code
touched, every content-id/topology_hash pin green); C23 honoured precisely
(each strip arm has a protecting property test; factoring byte-preserving
via the canonical golden); the two extra engine tests are genuinely
distinct coverage (recursion arm, role/output arms), no redundancy.

Regression gates (all green): cargo build clean; cargo test --workspace
884 passed / 0 failed (873 baseline + 11 new); clippy --all-targets
-D warnings clean; cargo doc --no-deps 0 warnings.

Ephemeral cycle artifacts removed per project convention (git rm):
docs/specs/0104-topology-identity-hash.md,
docs/plans/0104-topology-identity-hash.md.

refs #180
2026-07-02 21:29:38 +02:00
Brummel 4928e289f7 feat(project): the project-as-crate load boundary (cycle 0102)
A research project is now a loadable external cdylib crate. Inside a
directory whose ancestry holds an Aura.toml, aura discovers the project
root cargo-style, locates the compiled dylib via cargo metadata (debug
default, --release opt-in), loads it load-and-hold, and refuses
mismatches before trusting anything: the AURA_PROJECT descriptor
(aura-core::project, #[repr(C)]) carries a C-ABI stamp prefix (rustc +
aura-core version, baked per consuming build by the new aura-core
build.rs) validated before any Rust-ABI field is read. The vocabulary
charter gates the merged resolution: project type ids are ::-namespaced
(std stays bare), duplicates refuse, and the enumerable type-id list
must agree with the resolver, so introspection can never silently omit
a project type.

All blueprint verbs resolve through the merged project + std vocabulary
via a per-invocation Env threaded through the dispatch chains;
registry, trace-store, and data paths anchor at the project runs root
(Aura.toml [paths], paths-only by design — instrument geometry stays
the recorded sidecar, C15). RunManifest gains the Tier-1 project
provenance field (namespace + dylib sha256 + best-effort commit),
stamped beside topology_hash on the blueprint-run paths; pre-0102
registry lines load unchanged. Default node names strip the namespace,
so :: never reaches the param-path address space.

Proven by the demo-project fixture (built by the e2e via cargo,
path-dep on this workspace): run twice bit-identical, provenance
recorded, introspection lists demo::* beside std, registry anchors at
the discovered root from a subdirectory; the badcharter fixture proves
the charter refusal through the real libloading path; a never-built
project refuses with a cargo-build hint. Outside a project every path
collapses to the previous literals — goldens and manifest pins
byte-identical.

Verification: cargo build --workspace clean; cargo test --workspace 862
passed / 0 failed (incl. 7 project_load e2e); clippy -D warnings clean
(one precedent-matching allow(too_many_arguments) on run_oos_blueprint,
whose arity the Env threading raised to 8); doc build unchanged.
Docs/ledger aligned: Aura.toml field lists are paths-only in
project-layout.md, glossary, C16/C17; new C13 realization note records
the per-invocation-reload reading and the load-and-hold one-shot scope
boundary.

New deps, per-case review (aura-cli leaf binary only, never the frozen
artifact): libloading, toml.

refs #180
2026-07-02 18:13:37 +02:00
Brummel 4de6d5cbad rename: retire the stage1-* family for the r-family (r-sma / r-breakout / r-meanrev)
The stage1 ordinal has been dead vocabulary since the C10 reframe dropped
the two-stage research model: a 1 structurally implies a 2 that no longer
exists. The family is renamed by its live discriminator - the R yardstick -
with members named by their signal, uniform with their signal-named
siblings (sma, macd, momentum):

- selectors: stage1-r -> r-sma, stage1-breakout -> r-breakout,
  stage1-meanrev -> r-meanrev (old tokens are usage errors, exit 2 - no
  silent alias)
- identifiers: Strategy::RSma/RBreakout/RMeanRev, HarnessKind::RSma,
  r_sma_*/r_breakout_*/r_meanrev_*, wrap_r, run_signal_r, RGrid, R_SMA_*
- persisted identity: the sma_signal composite (param prefix
  sma_signal.fast.length / .slow.length; fixtures regenerated; content-ids
  shift - no test pins a literal hash, the registry parses no record names)
- e2e test files git-mv'd to r_sma_e2e / r_breakout_e2e / r_meanrev_e2e
- dead Stage-1/Stage-2 prose reworded to post-C10 vocabulary across
  rustdoc, Cargo.tomls, ledger live lines, and the glossary (historical
  entries stay; fieldtests corpus untouched)
- CLAUDE.md invariant 7 rewritten to record the ratified C10 reframe
  faithfully (the token-swap alone would have laundered the retired
  gated-currency/realistic-broker design into unmarked live prose); the
  unbacked account-mode clause dropped

Verification: cargo build/test --workspace green (51 targets), clippy
-D warnings clean, doc build clean, acceptance grep gate leaves exactly
the one resampling-stage false positive (harness.rs), smoke: --harness
r-sma runs, --harness stage1-r exits 2 with the new usage line.

Decision log: forks and rationale recorded on the issue (reconciliation
+ implementation-phase comments).

closes #174
2026-07-02 12:03:09 +02:00
Brummel 88e9c9a539 fix(cli): symmetric sweep/mc family-verb polish (closed error, mc seed label, mandatory-knob docs)
Three polish items surfaced by the World/C21 milestone fieldtest:

- A sweep of a fully-bound (closed) blueprint is refused up front with a clear
  "this blueprint is fully bound; nothing to sweep" message — the symmetric
  inverse of blueprint_mc_family's closed-blueprint guard — instead of leaking a
  misleading UnknownKnob for a knob that is not unknown but bound out.
  blueprint_sweep_family's error contract widens to String; the sweep terminal's
  BindError (a genuine unknown/kind-mismatch axis) still surfaces verbatim.
- mc reproduce lines now carry each member's seed=<N> label. Monte-Carlo members
  hold no tuning params, so the member label was blank; the seed is each draw's
  realization identity. Sweep / walk-forward labels (which echo params) unchanged.
- docs (design ledger + glossary): state that every open knob --list-axes prints
  is mandatory on sweep / walkforward — a subset is refused with the missing knob
  named (BindError::MissingKnob), there is no default; pin a knob you do not want
  to vary with a single-value axis.

RED-first for the two behaviour items. One existing unknown-axis E2E is re-pointed
from the closed fixture (which now hits the new "nothing to sweep" pre-check) to
the open fixture; it still exercises UnknownKnob("nope") specifically — resolve
raises UnknownKnob in phase 1 before MissingKnob in phase 2 — so the property is
preserved, not weakened.

closes #178
2026-07-02 09:41:54 +02:00
Brummel 8d04a845ee docs(glossary): align terminology with industry standard
Reconcile 68 terms against algotrading frameworks (LEAN, NautilusTrader,
backtrader, VectorBT, Zipline), quant-validation literature (Van Tharp,
Bailey & Lopez de Prado, White), and stream/dataflow vocabulary. Conservative
pass: extend Avoid lists with industry synonyms/homonyms and fold short
disambiguation notes into definitions; no canonical headings renamed.

Touched 18 entries. Avoid additions: overfit probability (PBO/CSCV), signal
(entry/exit signal, trade signal), position table (transactions, trade
blotter), conviction-based risk allocation (risk budgeting/parity/
contribution), run registry (model registry), session node (session window),
sign-agreement (market breadth). Disambiguation notes: broker vs fill/account
simulator, edge (wiring/trading/deploy senses), cycle (clock step vs DAG
loop), manifest vs Cargo.toml config, experiment vs MLflow container,
run-count (version counter), bias vs statistical bias, bootstrap vs
statistical bootstrap, deflated score anchored on the Deflated Sharpe Ratio,
Monte-Carlo (input not trade sequence), World vs Unreal UWorld.

Deferred (out of scope this pass): heading renames, a new `record` entry +
composite sense-split, the playground egui->web wording, the SoA Avoid line.
2026-06-29 10:55:37 +02:00
Brummel 39f9387c57 docs(glossary): add 'tap' — named recorded sink stream
Record-reality add: 'tap' is in consistent use across the code
(ColumnarTrace.tap, the --tap flag, the equity/exposure/net_r_equity/
r_equity taps) and the design ledger, but had no glossary entry. The
entry also draws the line the 'tap/sink' shorthand blurs: a sink is
the recording-role node, a tap is the named stream it records.
2026-06-28 22:24:42 +02:00
Brummel a517899297 docs: sync ledger cross-ref + glossary to the C10 rework (refs #116)
Follows the C10 rework (29cdc8c). C15: the deploy-grade geometry fields now defer
to the cost model's currency→R normalization / the live deploy edge, not the
retired Stage-2 realistic broker. Glossary: "realistic broker" and "Stage 1 /
Stage 2" marked superseded (kept as history); bias/broker/equity-stream/position-
table/R/R-metrics/R-evaluator/RiskExecutor/Sizer/sim-optimal-broker/veto reworked
to the cost-model-in-R model; added cost model, gross R, net R, net-R equity
curve, conviction-based risk allocation.
2026-06-28 12:00:29 +02:00
Brummel 3e8fd73f68 tidy: clear the milestone fieldtest findings (refusal reasons, --help, ledger + glossary)
Resolves the four non-bug findings from the inferential-validation milestone
fieldtest (the bug — the broken-pipe panic — is fixed in 1088320):
- [friction] generalize refusals now carry a reason instead of a bare usage dump:
  <2 instruments, a multi-value candidate flag, a missing knob, a duplicate
  symbol, and a non-stage1-r strategy each get a one-line why (mirroring the
  R-only metric refusal). Two parser tests strengthened to pin the message.
- [friction] --select <argmax|plateau:mean|plateau:worst> added to the
  walkforward branch of the global USAGE (aura --help) — the plateau objective
  was undiscoverable from the only help the CLI prints (the per-subcommand usage
  already carried it).
- [spec_gap] C1 gains a scope note: bit-identity is per-run; a derived metric
  recomputed by two different command paths may differ by floating-point
  reassociation (<=1 ULP), which is not a C1 violation — ratifies the
  fieldtester's reading of the sweep-vs-generalize sqn difference.
- [spec_gap] the milestone vocabulary is added to docs/glossary.md:
  cross-instrument generalization, deflated score, overfit probability,
  neighbourhood score, plateau selection, sign-agreement, worst-case floor.

The fieldtest triage spec (docs/specs/fieldtest-*) is removed now its findings
are resolved; the tracked fieldtests/ scenario corpus stays.

Verified: cargo test --workspace green (0 failed), clippy --workspace
--all-targets -D warnings clean; `aura --help` shows --select; the refusals
print their reason.

refs #146
2026-06-26 21:35:10 +02:00
Brummel 458b2ae74b audit(0067): cycle close — lift SQN100 / stage1-r-trace rationale to ledger, drop ephemera
Architect audit clean (no drift, no debt): raw sqn verified bit-identical,
C18 serde back-compat + C4 SoA seam + C1 determinism + Part-B symmetry all hold.

- Ledger C10: add a "Realization (cycle 0067, #130 + #135)" note — SQN100 as
  the turnover-robust opt-in rank key (raw sqn / default ranker byte-unchanged,
  serde(default) for back-compat), and per-member --trace now symmetric across
  all three sweep strategies via the shared persist_traces_r.
- Glossary: R-metrics list gains sqn_normalized; the SQN entry documents the
  SQN100 variant (was "deferred #130").
- Remove the ephemeral spec + plan (cycle closed; rationale lives in the ledger
  and git history).

refs #130, refs #135
2026-06-24 18:15:37 +02:00
Brummel 986a9fd5c7 audit(0066): cycle close — lift R-sweep/SQN rationale to ledger, drop ephemera
Cycle 0066 (#133) closed. The close audit (architect) found the family ratified against C12 axis-2 (rank-by-metric over the C18 family store) and the C10 R framing, with one [high] gap (swept-member manifest omitted the fixed R-defining params) fixed forward in 499121e.

- Ledger: a C10 realization note records the durable rationale -- SQN as the single-number sweep objective, the signal-only grid (the stop defines R, so varying it breaks cross-member SQN comparability -- the SQN100 #130 motivation), the R-metric rank vocabulary, and the manifest-completeness fix.
- Glossary: new 'R metrics' and 'SQN' entries.
- The ephemeral spec + plan are removed; the ledger + git history are the durable record.

Follow-ups filed: #135 (per-member --trace for the stage1-r sweep). refs #133
2026-06-24 16:24:25 +02:00
Brummel f040b66f30 design(c10): reframe to a bias stream + R-unit signal quality
Adopt the R-reframe ratified in #117: the strategy's native unit is risk
(R), not pips/dollars, and its primary output is a directional bias.

- exposure -> bias: the primary output is an UNSIZED direction + conviction
  `f64 in [-1,+1]`; sizing and the protective stop leave the strategy.
- Signal quality is measured in R (Stage 1): an R-evaluator integrates the
  per-trade R-outcomes of a flat-1R RiskExecutor into R-expectancy. R is
  defined by the stop, account-/instrument-agnostic; pips retired as the unit.
  Flat-1R needs no equity, so Stage 1 is feed-forward (no cycle).
- Risk-based execution is a decoupled layer: a RiskExecutor composite
  (stop-rule -> Sizer -> Veto -> position-management) per symbol, nested in a
  Broker/Account composite; account mode (netting/hedging) = composition
  constraint. "Sizer" is not "risk-manager" (that names the Veto layer).
- Currency P&L is Stage 2 (fixed-fractional, compounding). The only feedback
  (equity -> Sizer) is cut by a z^-1 register on the fill edge (mark-to-market
  stays a same-cycle price read), encapsulated in the executor; flat-1R vs
  compounding is a structural axis (the explicit register is mandatory because
  C23 reorders the flat graph).
- Position-event table stays the decoupled Stage-2 audit layer = first
  difference of the book (deal = target - book - in_flight); the flawed 0064
  exposure-integral derive is abandoned.

Touches: ledger C10 + CLAUDE.md domain invariant #7 + glossary (adds bias, R,
R-evaluator, RiskExecutor, Sizer, veto, Stage 1/2; revises broker, exposure
stream, position table, sim-optimal broker, strategy, ...). Also fixes
cross-file drift surfaced by adversarial review (C20 guarantee + front-matter
provenance still claimed "exposure stream"; cross-refs corrected to
C9/C19/C20/C23). Industry-grounded against LEAN / nautilus_trader / backtrader
/ QSTrader / vectorbt / zipline.

refs #117
2026-06-23 13:14:31 +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 8eff6398ca docs(glossary): add the cell entry 2026-06-16 12:20:36 +02:00
Brummel 0d7deb3a91 design(C10): reframe strategy output to intent/exposure stream; position table becomes a derived layer
The DAG expresses exactly one state at time t and a node emits at most one record
per eval (C8), so a *sequence* of position events — where one decision instant
(a stop-and-reverse) needs a close AND an open at the same event_ts — cannot be
the DAG's per-cycle output without violating C8. The state the DAG can express
faithfully is the desired exposure (one value per cycle); the buy/sell/close
events are its first difference, a derived consequence.

C10 is reframed accordingly: the strategy's primary, backtestable output is an
intent/exposure stream (one signed, bounded f64 in [-1,+1] per cycle). Signal
quality is measured by the sim-optimal broker integrating exposure*return into a
synthetic pip-equity curve. The broker-independent position-event table survives
as a decoupled, derivable, downstream position-management layer (computed table,
not a per-eval output) feeding realistic broker nodes for viability/deploy — no
longer the DAG output nor the signal-quality measure.

Touches the ledger contract (INDEX.md C10 + provenance/milestone/C20 ancillary),
the always-loaded summary (CLAUDE.md invariant #7), the glossary (broker, equity
stream, position table, realistic broker, signal, sim-optimal broker, strategy
reframed + new exposure-stream entry), and the north-star layout doc. Sealed
specs/plans (0001-0006) left as historical record.

refs #4 #5

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:02:33 +02:00
Brummel 3a02fbf383 audit: cycle 0006 tidy (clean) — glossary record-reality (sink is a role)
Architect drift review over 57310b8..HEAD: clean — no drift, no debt.
The C1/C7 boundary is correctly drawn (recorded values escape only via a
node-held mpsc::Sender with no out-edge; nothing recorded re-enters the
graph; the engine surface shrank). C2 holds (Ctx::now() is the present
cycle's ts). The C8/C22 cycle-0006 realization notes accurately describe
what shipped — no overclaim. Test fixtures stayed in #[cfg(test)] (C9).
Regression set is empty (profile) — architect is the sole gate; green.

Record-reality: the glossary 'sink' entry defined a sink as 'a pure
consumer node with no output', which the shipped TapForward node (records
AND forwards an output) now contradicts. Updated to reality: a sink is a
recording *role*, not a type — a node may be a pure consumer or record
and produce in the same eval (C8 'both'). No invention; the entry now
matches the substrate this cycle landed.
2026-06-04 14:41:38 +02:00
Brummel 57310b83c7 audit: cycle 0005 tidy — glossary record-reality (node-output-record)
Architect drift review over 9ff90b5..5228542 (node-output-record): drift_found,
all low-severity, NO contract violation. The load-bearing invariants hold:

- C7 forbids intact — the reused `scratch` buffer (cleared+extended, warm after
  cycle 1) and node-owned `[Scalar; K]` output buffers give zero per-cycle heap
  alloc on the inter-node forward path; no fifth scalar type, no dyn-Any, no
  heterogeneous buffer (the TwoField mixed-kind producer is rejected at bootstrap,
  never streamed). Purity grep clean. The sharpened C7 guarantee text matches the
  shipped per-field kind check + the Edge::from_field scatter.
- C8 revised text faithful — one output port (out_len), record of 1..K columns
  (Vec<FieldSpec>), field-wise binding only (N edges, no whole-record bind), scalar
  = degenerate K=1. No internal contradiction with C7/C9/C10.
- C6 untouched, verified against the run loop — one eval per node per cycle, every
  out-edge stamps SlotState { fresh_at: cycle_id, last_ts: ts } with the same ts,
  so the K fields of one record are co-fresh by construction. fires() unchanged.
- C3/C4/C5/C9 unperturbed (diff touches only node/edge plumbing); C2 lookback
  enforcement unperturbed (column.rs/ctx.rs/any.rs not in the diff).
- C10 coherence confirmed — a position event is a 5-field record
  (event_ts/action/position_id/instrument_id/volume), exactly the K-field
  base-column record C8/C7 now sanction; the decision/sizing node is an ordinary
  K=5 producer, the broker an N-edge field-wise consumer. No contract gap blocks
  the next consumer; C10 correctly out of scope this cycle.

Resolved [low] (the one confirmed drift) — glossary record-reality. The ledger
C7/C8 moved this cycle but the glossary lagged. Fixed three entries to the
post-0005 reality (this is audit's autonomous glossary write authority,
record-reality only): `node` ("at most one output" -> "at most one output port; a
producer's output is a record of 1..K base-scalar columns, scalar = degenerate
K=1"), `composite` (now connects the multi-column stream to the node-output model
— the record a producer's eval returns, bound field-wise), `edge` (forwards "one
field (from_field) of a producer's eval output record", per-field kind check).
The architect named `node` + `composite`; `edge` is an orchestrator-observed
addition in the same record-reality pass (post-from_field it read "forwards one
node's eval output", now imprecise for K>1).

Regression gate: profile regression list empty — architect is the sole gate, now
clean (36 tests: aura-core 19 + aura-std 3 + aura-engine 14; clippy -D warnings
clean; purity grep clean). Cycle 0005 is drift-clean.

Carry-on forward note (next-cycle owner, not a fix now):
- [low] cycle 0004's depth>1 join-lookback guard test remains merely OWED, not a
  fresh hole — the substrate enforces it via Window bounds (column.rs/ctx.rs
  untouched this cycle) and 0005 added no depth>1 join. Co-fresh borrowed-row
  routing does not interact with per-input lookback. A confirmation test is still
  owed when a depth>1 join lands.

NOT a milestone close: the walking-skeleton milestone still needs its end-to-end
fieldtest (ingest -> signal -> backtest -> position table -> broker -> pip-equity).
This cycle delivers the record-output substrate that the trading half (C10) now
builds on.

refs walking-skeleton

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:58:54 +02:00
Brummel 9ff90b5d80 audit: cycle 0004 tidy — diamond-barrier test + ledger/glossary record-reality
Architect drift review over 02fe891..f37b2a3 (firing-policies-and-merge):
drift_found, all medium/low, no contract violation. Invariants hold: C1 (the
merge is a deterministic linear scan, strict < on (timestamp, source-index) gives
C4 tie-break by declaration order; only per-call allocs), C3 (one merge at
ingestion), C5/C6 (both rails proven with worked vectors; sample-and-hold falls
out of the push model), C7 (type-erased edges, no dyn-Any/Rc/RefCell — purity grep
clean). Resolved the 0003 forward-note: cycle_id is now a real read field (the
freshness epoch, fresh_at == cycle_id), not write-only.

Resolved [med] (test gap): the barrier's timestamp token was proven only for the
multi-source same-timestamp case; C6's within-source diamond rejoin (one source,
two unequal-latency paths rejoining at a barrier) was claimed by the spec but
untested. Added `within_source_diamond_rejoin_barrier_fires`
(source -> {SMA(2), SMA(4)} -> BarrierSum): once SMA(4) warms at cycle 4, both
paths emit each cycle at the same timestamp and the barrier fires
(15+13, 17+15, 19+17). The code was already correct — every push in a cycle
stamps last_ts = that cycle's timestamp (source pushes and produced-edge forwards
alike) — so this closes the coverage gap, not a bug.

Resolved [med] (glossary record-reality): the run-count entry claimed it "drives
freshness-gated recompute", now false — the engine's firing gate reads the
per-wiring-slot cycle epoch (fresh_at), not Column::run_count. Sharpened the entry
to record reality: run-count is the node-visible per-column push counter;
fresh_at is the engine's per-slot freshness epoch. Not redundant (different
levels); both are maintained consistently on every push.

Resolved [low] (ledger silent on the barrier token): added a C6 "Realization
(cycle 0004)" note recording the load-bearing decision — barrier token is the
timestamp not cycle_id (forced by C4's same-timestamp-tie rule), firing tagged
per input with Firing::{Any, Barrier(u8)}, a mode-A input being its own trivial
group (so "per input group" and the per-input tag coincide).

Carry-on forward notes (next-cycle owners, not fixes now):
- [low] cycle_id is materialized internally (the freshness epoch) but not yet
  surfaced in run output (run returns Vec<Option<Scalar>>). Its first observable
  consumer is a sink / clock node (C18) or a timestamped trace — materialize the
  surfacing then.
- [low] all join fixtures declare lookback 1; a test guarding C8's "a node never
  reads beyond its declared lookback" for a depth>1 join is still owed (the
  substrate already enforces it via Window bounds, so this is confirmation, not a
  hole).

Regression gate: profile regression list empty — architect is the sole gate, now
clean (31 tests: aura-core 19 + aura-std 3 + aura-engine 9; clippy -D warnings
clean; purity grep clean). Cycle 0004 is drift-clean. NOT a milestone close: the
walking-skeleton milestone still needs its end-to-end fieldtest (ingest -> signal
-> backtest -> position table -> broker -> pip-equity), of which this cycle
delivers the firing/merge layer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 14:27:00 +02:00
Brummel 02fe89176f audit: cycle 0003 tidy — rename Sim -> Harness (glossary alignment)
Architect drift review over 71c8f6e..dd5c3fa (deterministic-sim-loop).
Invariants hold: C1 (single-threaded, bit-identical re-run, alloc-free per-cycle
ring path), C7 (AnyColumn type-erased edges, Box<dyn Node> is the node object not
a dyn-Any payload, kinds checked once at bootstrap), C8/C9 (DAG wired, Kahn
rejects cycles, None forwards nothing = sample-and-hold seed). Column::run_count
already exists, so the C5 freshness primitive lives at the substrate — the
deferral is honest, not a hole.

Resolved [high]: the runtime type was named `Sim`, colliding with the glossary's
load-bearing distinction — `sim` is the disjoint *executable unit / parallelism*
framing, whereas the thing built here (a closed root graph of source + nodes +
observe under a clock) is by C20 / the glossary a **harness**. Renamed
`Sim` -> `Harness`, `sim.rs` -> `harness.rs`, and the module/exports/doc to match,
before any other code takes a dependency on the wrong term. Gates re-run green
(26 tests, clippy -D warnings, purity grep).

Resolved [med] (glossary gap): added an `edge` entry anchoring the new wiring
vocabulary (Edge / source target) to the glossary — record-reality per the boss
glossary-write authority.

Carry-on with forward notes (next-cycle owners, not fixes now):
- [med] C4 monotonic cycle_id has no realization in the runtime type yet (the
  cycle clock is the record iteration; the explicit counter's first reader is
  freshness). Cycle 0004 owns materializing it together with C5.
- [low] Sub declares lookback 1; once depth>1 join nodes exist, add a test
  guarding C8's "a node never reads beyond its declared lookback".

Regression gate: profile regression list empty — architect is the sole gate,
now clean. Next direction: freshness-gated recompute + a second source (C5/C3).
2026-06-03 13:07:43 +02:00
Brummel d566fed92b docs: bootstrap the project glossary; wire paths.glossary
Build a 44-entry glossary from the prose surface (design ledger, project
layout, CLAUDE.md, crate doc-comments) in the convention's three-field
format, and set paths.glossary so it becomes standing reading for every
skill/agent role.

Contested clusters resolved with the user:
- bot vs frozen artifact kept as distinct entries (genus/species).
- backtest / sim / run pinned as three distinct framings, none banned.
- signal kept as its own concept (a score-producing node).
- sim-optimal broker distinguished from Aura.toml's "default broker".

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