design: ratify C28 — internal stratification (ladder, process column, shell)

Codify the layer model settled with the user: an inner-to-outer ladder
engine -> market -> {measurement | strategy} -> backtest -> execution,
the research-process column beside the ladder, the shell outside. States
the import rule (inner never imports outer; measurement/strategy
siblings; column imported by no ladder crate; shell imports all;
dev-deps exempt), the six seams (five already ratified contracts —
C8/C24/C27/C18/C10-C13 — only the metric interface new), and an honest
Status recording the one hard production violation (engine -> analysis
via report.rs re-exports + the R-typed mc.rs fields) and its coupling to
the deferred #147.

Also restore the "### C19" header, deleted as collateral of ebe8568
(2026-07-03 cycle-0106 tidy); its body survived orphaned under C18. C28
cites C19, so the header must resolve.

refs #286
This commit is contained in:
2026-07-19 15:14:50 +02:00
parent 592750b122
commit 1c49d5dce2
+112
View File
@@ -1680,6 +1680,8 @@ and both callers are untouched; maintenance is lazy-only — put-time indexing
was rejected because it would need a roster-free doc-level identity function was rejected because it would need a roster-free doc-level identity function
whose equivalence to the loaded-composite path no green test ratifies (decision whose equivalence to the loaded-composite path no green test ratifies (decision
log: #191 comments). log: #191 comments).
### C19 — Bootstrap: blueprint → instance (recursive)
**Guarantee.** Construction is a distinct phase, recursive at every level. Each **Guarantee.** Construction is a distinct phase, recursive at every level. Each
node type has a **factory** `params → sized concrete node` (e.g. `SMA(length)` node type has a **factory** `params → sized concrete node` (e.g. `SMA(length)`
sizes its ring buffer). A **blueprint** is the param-generic, input-role-generic sizes its ring buffer). A **blueprint** is the param-generic, input-role-generic
@@ -2590,6 +2592,116 @@ benefit — a sweep paying zero for the study wires behind an unbound tap — is
**deferred to the future DCE cycle** (C23); the mechanism ships now, verified **deferred to the future DCE cycle** (C23); the mechanism ships now, verified
sound. (#282, 2026-07-18.) sound. (#282, 2026-07-18.)
### C28 — Internal stratification: the trading ladder, the process column, the shell
**Guarantee.** The aura workspace's crates realize a layered responsibility
model along two axes. A **ladder**, ordered by domain specificity from inner to
outer:
1. **engine** — the domain-free deterministic streaming runtime and vocabulary
(cells/kinds/freshness/firing, graph build, compile, run, taps/trace — C1C9,
C19, C23, C24), the domain-free node roster (arithmetic/logic/rolling nodes
plus the generic `Recorder`/`GatedRecorder`/`SeriesReducer` sinks), and
generic statistics (the Monte-Carlo and moving-block-bootstrap kernels). The
layer name is wider than the crate `aura-engine`: it spans `aura-core`,
`aura-engine`, the domain-free part of `aura-std`, and the generic-statistics
surface.
2. **market** — what a market *is*, carrying no analysis or strategy intent:
instruments and pip/point geometry (C15), session anchoring, bar resampling,
market-data ingestion (`aura-ingest`).
3. **measurement** — descriptive statistics over market streams (session
statistics, conditional rates, distributions). Sibling of **strategy**: both
consume *market*, neither imports the other.
4. **strategy** — the *definition* of trading signals: bias, stop rules, sizing,
cost-model nodes.
5. **backtest** — the *evaluation* of strategies: simulated execution without
money (the `SimBroker`, position-management), the R-metric reductions and the
position-event table, and the per-run scaffold. Backtest mirrors *execution*
on the research side — execution semantics in R units, money exiled.
6. **execution** — money, account-term sizing, the live broker; already exiled to
the deploy edge by C10/C13, existing today only as that ratified boundary.
Beside the ladder stands the **process column** — the research-process machinery
(the run registry C18, the process/campaign document types, campaign execution).
It consumes run *artifacts*, not market streams, and orchestrates runs of any
ladder layer; it stands beside the ladder, not on a rung. The **shell** (the
`aura` CLI) imports everything and is imported by nothing.
**Import rule.** An outer ladder layer may import inner layers, never the
reverse; *measurement* and *strategy* are siblings (no import either way);
*backtest* may import *strategy*. The process column imports the engine layer
plus the run-artifact and metric interfaces, and is imported by no ladder crate;
column-internal edges are free. The shell imports all; nothing imports the
shell. **`dev-dependencies` are exempt** — tests may cross layers (the existing
`engine`/`ingest`/`registry``std` edges are dev-only and stay). The rule
binds **crate structure, not graph composition**: a blueprint may feed a
measurement statistic into a bias input — data flow inside a graph is free (C24);
layers govern imports, graphs compose freely.
**Forbids.** An inner layer importing an outer one — most sharply the engine
layer importing backtest reductions, or market importing strategy. A ladder crate
importing the process column. Money (currency P&L, account sizing) inside the
strategy or backtest layers (C10/C13 — it lives only at the execution/deploy
edge). Once a second consumer warrants the split, keeping multiple layers welded
in one crate's roster.
**Why.** The stack is a framework specialized for traders: the inner engine is a
domain-free analysis substrate (the same machinery would measure robot telemetry
or any timestamped process), the outer rungs the trading specialization, and the
two together are the "game engine for traders" (C16's game/engine split applied
*inside* the workspace, from the engine|project boundary to the intra-stack
layering). Separable responsibilities behind narrow, contract-defined seams let a
contributor focus on one rung without absorbing the rest, and make each boundary
auditable. Enforcement is the crate graph itself: once crates are cut along these
cells, a layer violation is a compile error and every new edge a visible
`Cargo.toml` diff — no linter, no discipline appeals. Five of the six seams are
already ratified contracts and this model only *names* them as layer boundaries:
the node contract (C8, engine ↔ any vocabulary), blueprint-as-data (C24,
topology ↔ engine — its shape selecting the run scaffold is the additive #286
refinement, phase 3 below), declared taps (C27, run ↔ analysis — the only way
values leave a run), the run registry (C18, run ↔ process column), and the
deploy edge (C10/C13, everything ↔ money). Only the
process column ↔ metric interface is new (a named metric vocabulary *supplied* by
measurement and backtest instead of baked in R-only — this is #147).
**Status (2026-07-19, milestone "Stratification — ladder, process column,
shell", #286).** This contract states the *target*. At HEAD the crates cut by
mechanical role (vocabulary / reductions / documents / orchestration / CLI), not
cleanly by layer, so the layering is realized only partially:
- The dependency *direction* already nearly obeys the rule. The one hard
production violation is `aura-engine → aura-analysis`: `report.rs:20`
re-exports the R-metrics, the position-event table, the hurdle math, and the
selection-provenance types (`RMetrics`/`RunMetrics`/`summarize_r`/
`r_metrics_from_rs`, `PositionEvent`/`PositionAction`/`derive_position_events`,
`inv_norm_cdf`/`expected_max_of_normals`, `FamilySelection`/`SelectionMode`),
and the generic-statistics kernel in `mc.rs` carries R/bias-typed fields
(`McAggregate.bias_sign_flips`, `RBootstrap.e_r`) inside otherwise domain-free
structs.
- **That violation is the exact surface of the deliberately-deferred #147.**
Cutting it cleanly needs the metric genericity (`RunReport<M>` plus abstracting
the registry deflation vocabulary) that #136 ratified *deferring* (user-ratified
2026-06-27: the registry `Metric`/`metric_cmp`/deflation vocabulary "stays in
the registry by design … forcing genericity would be a one-implementor
abstraction", deferred to the World/C21 layer — see the C16 realization note).
The stratification supplies the *second* metric consumer (measurement) that the
deferral was waiting on, so retiring #147 and cutting this edge are one coupled
decision — reserved to the user, since it reverses a ratified deferral.
- The interweaving is mostly *inside* crates. `aura-std` holds four layers in one
roster: engine (arithmetic/logic/rolling + the generic sinks), market
(`session.rs`, `resample.rs`), strategy (`bias.rs`/`stop_rule.rs`/`sizer.rs` +
the cost nodes) and backtest (`sim_broker.rs`, `position_management.rs`);
`aura-analysis` holds backtest reductions and generic hurdle math together. No
crate exists yet for *measurement* (its run verb is the additive shape dispatch,
#286) or *execution* (unbuilt — the C10/C13 edge only). Under this model the
`aura-registry → aura-research` edge is column-internal and legal.
- Phased realization (each independently shippable; behaviour byte-identical
except the purely additive shape dispatch): (1) this contract; (2) cut the
`engine → analysis` edge — coupled to the #147 decision above; (3) the #286
shape dispatch plus the per-run scaffold as a library (seeds an `aura-backtest`
crate, gives *measurement* its run verb, removes the measured O(cycles) run-time
retention); (4) split the `aura-std` roster along engine / market /
strategy+backtest; (5) split `aura-analysis` into generic statistics and
backtest metrics; (6) generify the column's metric interface (demand-driven —
this is #147). Crate names provisional; full evidence on #286 and the milestone.
--- ---
## Open architectural threads not yet resolved ## Open architectural threads not yet resolved