Ratify a five-layer model and dispatch aura run on blueprint shape #286
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
All file references are at engine commit
592750b.The layer model (proposed as a ledger contract)
The stack's de-facto layering, made explicit, inside out:
aura-coreplus the graph/compile/harness half ofaura-engine(the determinism/causality/composition contracts C1–C9, construction C19, compilation C23, blueprint-as-data C24 indocs/design/INDEX.md). Verified free of trading vocabulary in production code: trading identifiers incrates/aura-engine/src/builder.rsoccur only inside its test module (#[cfg(test)]opens at line 341).aura-ingest). This layer exists but is unnamed: theaura-stdroster mixes it with layer-1 arithmetic (SMA,Sub,CumSum, …) and layer-3b strategy nodes in one vocabulary.b — trading-strategy — bias signals, stops, R-evaluation:
Bias/stop rules/PositionManagementinaura-std, the R-metric roster inaura-analysis, the process/campaign machinery. 3a and 3b are siblings: both consume layer 2, neither needs the other.The rule worth ratifying: an inner layer never imports an outer one, and 3a/3b are siblings — neither routes through the other. It is the same cut C10/C13 already made at the 3b|4 boundary, applied to the inner boundaries.
Verified violations at HEAD
The only run verb mandates layer 3b.
dispatch_runrefuses any blueprint without abiasoutput ("aura run expects a strategy with a bias output",crates/aura-cli/src/main.rs:3589-3603) and routes every run throughrun_signal_r→wrap_rwith thereduceflag hardcodedfalse(main.rs:1721,main.rs:1750).wrap_r(main.rs:1489-1667) welds onSimBroker, the risk executor, and four to five per-cycleRecordersinks — equity, exposure, the dense 14-column PM record ("Emits ONE dense record per cycle",crates/aura-std/src/position_management.rs:3), plus ther_equitytap — whose mpsc channels are drained only after the run completes (main.rs:1783-1785).Measured consequence (single
aura run, UK100 M1, warm page cache, peak RSS via/bin/time -f %M): a measurement-shaped blueprint — 33 closed-roster std nodes computing a session-anchored conditional statistic (5-minute candles at the 09:00 Europe/Berlin open viaSessionFrankfurt+Resample, cross-candle values held viaWhenplus the engine's sample-and-hold, group-keyed rates via value-gatedCumSum, read out through declared taps) — runs only by exposing its statistic under the namebias, and then pays the full strategy scaffold: peak RSS 172 MB over 1y, 911 MB over 5y, 2013 MB over 12y — linear in cycles. With all six declared taps removed the 12y run still peaks at 2011 MB, so the retention is the mandatory wrap, not the tap drain (#283 targets the declared-tap drain path; at one tap firing per day that component is negligible here). The statistic itself is fully expressible in the closed std vocabulary: the data-only graph matched a standalone Rust reference implementation of the same statistic (a directaura-ingestconsumer) to under 0.1 percentage points over 12 years (conditional continuation rates 51.19% vs 51.23% and 47.42% vs 47.35%). The layer-3a computation exists; only its run path does not.Layer 3a has no first-class surface. The metric vocabulary is R-only (
aura process introspect --metrics: every rankable/gate metric is a strategy-run reduction), in-graph order statistics are excluded by design (the declared-taps contract C27 forbids them in-graph — "they stay sink/analysis-side"), and the only extraction seam is declared taps on a single run followed by offline reduction of the trace.Layer 1 imports layer 3b.
crates/aura-engine/Cargo.tomldepends onaura-analysis, self-described in that file's comment as holding "the pure trading-domain reductions (R-metrics, the position-event table, the multiple-comparison hurdle math)", re-exported viareport::(#136 lifted these out of the engine'sreportmodule intoaura-analysis; the engine still consumes and re-exports them). R-shaped production types sit inside the engine crate:bias_sign_flips(crates/aura-engine/src/mc.rs:41,mc.rs:89), resampledE[R]statistics (mc.rs:182-183). The ledger's description of the engine as domain-free (C10's phrase "the domain-freeaura-engine") is aspiration, not fact, at HEAD.Direction
biasgate indispatch_runbecomes a shape dispatch. A blueprint exposingbiastakes the current strategy path unchanged (byte-identical). A blueprint declaring only taps runs bare: bootstrap, run, drain the declared taps — nowrap_r, no broker/executor compute, no O(cycles) recording. Nothing that runs today changes behaviour, since a taps-only blueprint is currently refused outright; the bare path is new surface only. This gives 3a its run verb and removes the measured 2 GB retention for measurement runs at the root.report::R re-exports out ofaura-engine(completing the #136 direction), and stratify theaura-stdroster into layer-1 arithmetic / layer-2 session-and-geometry / layer-3b strategy nodes when a consumer warrants it.Phase 1 landed — C28 ratified; the
engine → analysisedge is coupled to the deferred #147.The stratification layer model is now a ledger contract: C28 — Internal stratification: the trading ladder, the process column, the shell (
docs/design/INDEX.md). It states the inner-to-outer ladder (engine → market → {measurement | strategy} → backtest → execution), the process column beside the ladder, the shell outside, the import rule, and the six seams (five already-ratified contracts — C8/C24/C27/C18/C10-C13 — only the process-column ↔ metric interface new). Committed on branchworktree-issue-286-stratify(the commit also restores the### C19ledger header, accidentally deleted as collateral ofebe8568; its body had survived orphaned under C18).The one hard production violation, verified:
aura-engine → aura-analysis.crates/aura-engine/src/report.rs:20re-exports the R-metrics, the position-event table, the hurdle math and the selection-provenance types; the generic-statistics kernel carries R/bias-typed fields (McAggregate.bias_sign_flipsatcrates/aura-engine/src/mc.rs:41,RBootstrap.e_ratmc.rs:182). Every other production edge points inward or is column-internal (independently re-checked).Cutting this edge needs #147 — making
RunReport/RunManifestgeneric over a metric type and abstracting the registry'soptimize_deflatednull-model, so domain metrics leave the engine crate. #147 was ratified deferred twice (2026-06-27 in the #136 thread; 2026-07-02, "leave it deferred"), on the grounds that it is a one-implementor abstraction until a genuine second metric consumer or cross-domain need appears, and that building it in anticipation is a strategic bet no source in the tree settles.Scope of the block (the load-bearing nuance): #147 blocks only the engine-domain-freedom capstone — the edge cut. It does not block the measured win: measurement's bare run verb plus the ~2 GB peak-RSS reduction is the additive shape dispatch (phase 3), which touches no metric genericity; nor does it block the
aura-stdroster split (phase 4). So the "second consumer" condition the deferral waited on is only partially met — measurement gains its run verb without #147; only the ideal of a truly domain-free innermost layer requires it. Un-deferring #147 therefore remains the same build-in-anticipation bet, now weighed against the stratification goal rather than a forced concrete need.Open decision: the order in which #147 (and the coupled edge cut +
aura-analysissplit) is sequenced against the #147-free wins (phase 3, phase 4).Sequencing decided (2026-07-19): the #147-free wins first.
Order: phase 3 (measurement's bare run verb + the ~2 GB peak-RSS reduction) and the
aura-stdroster split first — additive and #147-free — then #147 (theRunReport<M>genericity) together with the coupledengine → analysisedge cut and theaura-analysissplit as one block.#147 stays open as that block's prerequisite; its twice-ratified deferral is lifted for this milestone (it will be solved when the coupled block is reached, not kept indefinitely deferred). The alternative of leaving
engine → analysisas a permanent documented violation was declined.Phase-3 design decisions (specify) — the measurement run verb.
Recording the derived decisions for the shape-dispatch work — the third of the six phases enumerated in the Status block of ledger contract C28 (
docs/design/INDEX.md; the tracker milestone carries the same list, but a comment cannot link a milestone, so the ledger Status is the reachable anchor). Spec:measurement-run-verb(git-ignored working file, not committed).aura runshape-dispatches on the loaded blueprint's output: abiasport → the currentrun_signal_rpath, byte-identical; nobias+ ≥1 declared tap → a new barerun_measurement; neither → refuse (inert). Basis: #286's proposal; thebiasrefusal atcrates/aura-cli/src/main.rs:3595becomes the branch point; the closed-blueprint guard stays on both paths.run_measurement=run_signal_r(crates/aura-cli/src/main.rs:1721) minuswrap_rand the eq/ex/r R-evaluation, keeping the C27 tap bind → drain → persist verbatim. No broker, no risk executor, no O(cycles) recorders — this is where the measured ~2 GB retention is removed.RunReport/summarizedo not apply. A newMeasurementReport { manifest, taps: [names] }mirrors the persistedindex.jsonshape;RunManifest.broker(a requiredString,report.rs:52) carries an interim"measurement"sentinel. Basis: consistency with the existingRunReportserde +trace_storepersistence, weighed against risk — the honestbroker: Option<String>model is deferred to the #147 metric-genericity block so this phase stays #147-free and the strategy-path C18 goldens byte-identical.None of the three is a pure-preference fork — each is derivable from the sources, the existing serde, or relative risk — so decided here rather than bounced.
Spec auto-signed (specify Step 6,
/boss) — the measurement run verb.The
measurement-run-verbspec — phase 3 of the plan in C28's Status block (measurement's bare run verb viaaura runshape-dispatch) — was signed autonomously. Under/bossthe signature is the Step-5grounding-checkPASS, an independent fresh-context agent's verdict against currently-green tests, not the orchestrator's own confidence; no human signed at this gate.All load-bearing assumptions are ratified by named, currently-green tests: a tap-only / no-
biasgraph compiles + bootstraps + runs (crates/aura-engine/tests/bind_tap_e2e.rs,flat_taps_e2e.rs, andharness::tests::flat_graph_taps_are_inert_scaffolding_at_bootstrap); the pre-compile tap predicate;RunManifest.brokeras a requiredString(report.rs:52); today's no-biasrefusal (run_refuses_a_non_bias_output_blueprint); and the declared-tap persist round-trip (tap_recording.rs).Two corrections the check surfaced — mechanism ratified, only names differ: the pre-compile predicate is
Composite::taps() -> &[Tap](crates/aura-engine/src/blueprint.rs:242), not the spec's provisionaldeclared_taps()(!signal.taps().is_empty()); and declared taps persist underruns/traces/<name>/<tap>.json, notruns/<name>/….The spec is a git-ignored working file (never committed); the design's durable record is contract C28 in the ledger.
Phase 3 landed on the branch (commit
34ff539, unmerged).aura runnow shape-dispatches on the loaded blueprint: abiasoutput → the existing strategy path (byte-identical); nobias+ ≥1 declared tap → a barerun_measurement(bootstrap → run → drain taps, nowrap_r, no broker/executor/eq-ex-r recorders); neither → refuse. A newMeasurementReport { manifest, taps }is the stdout/record shape (no R metrics — a bare run has no broker);brokercarries the interim"measurement"sentinel.Verified (orchestrator-run, not agent-reported):
cargo test --workspacegreen — thebiaspath byte-identical, C18 goldens untouched, the regression testrun_refuses_a_non_bias_output_blueprintstill green (its blueprint has a non-biasoutput but no tap → still refused, now via the three-wayelse);cargo clippy --workspace --all-targets -- -D warningsclean; the RED E2Emeasurement_blueprint_runs_bare_and_emits_its_tapgreen.run_signal_ris byte-identical (the tap machinery is duplicated intorun_measurement, not extracted).The measurement arm's closed-blueprint guard uses
signal.param_space(), notblueprint_axis_probe— the latter weldswrap_rby thebiasport and would panic on a no-biassignal (the exact reason the oldbias-refusal existed).Both of this issue's deliverables are shipped on
main(origin/mainatb39fd63):(
docs/design/INDEX.md), commit1c49d5d.aura runshape-dispatch giving the measurement layer its bare runverb (no strategy scaffold on a taps-only blueprint), commit
34ff539.Closing as complete. The rest of the Stratification milestone lives elsewhere: the
aura-stdlayer-crate split in #288 (done), the follow-up windowed-fold factoringin #289, and the #147-coupled block (phases 2/5/6 — cut the
aura-engine→aura-analysisedge + generify the metric interface), which reverses a ratifieddeferral and is reserved to the user.