The single-file ledger had grown to 2968 lines / ~42k tokens, mixing current design law with accreted history: 59 cycle-stamped realization blocks, 18 [HISTORY] passages, 22 supersession markers, and the C10 / C22 / C24 reframe sagas layered several supersessions deep. A code-grounding audit (31 agents, adversarially verified) confirmed 11 defects stated as current truth: stale crate homes from the C28 #288 roster split (cost nodes, PositionManagement, PositionEvent, Session), the renamed InputSpec->PortSpec, the pre-#241 project model in C16 and the open-threads section, a stale HarnessKind retirement deferral in C24, and three C28-internal inconsistencies. New shape, per the ailang precedent: - INDEX.md stays the sole addressable entry point: foundation, external components, a C-id-keyed contract map (one line per contract), and only the genuinely open architectural threads. - contracts/cNN-<slug>.md carries each contract's current truth only: Guarantee / Forbids / Why with ratified refinements integrated, plus a code-anchored Current state. All confirmed defects are fixed here; crate anchors were re-verified against the tree. - contracts/cNN-<slug>.history.md (18 sidecars) and INDEX.history.md preserve every superseded block verbatim, stamps and issue refs intact, under a frozen-record banner. Nothing was deleted: superseded design intent remains an addressable working-tree artifact, off the per-cycle audit walk. - Ledger discipline is now stated in INDEX.md: live files are edited in place at cycle close, superseded text moves verbatim to the sidecar, and a supersession marker in a live file is itself an audit finding. Every contract file was verified against its old text by an independent zero-loss pass (statement-by-statement) plus a code-accuracy spot check; C-ids and contract titles are unchanged, so existing C-id citations in code, tests, and issues resolve as before.
6.0 KiB
C16 — Engine / project separation; three-tier node reuse
Guarantee. aura is the reusable engine; each research project is a
separate external repo that depends on aura via cargo (the game-engine / game
split). Node reuse is cargo-native, in three tiers: aura-std (universal
blocks, shipped with the engine) / shared node crates (cross-project-reusable,
their own repos, pulled as cargo git deps) / project-local node crates
(experimental, project-specific). A reusable node is an rlib dependency; the
hot-reload unit is the project-side cdylib that composes it (C13).
A project is a directory anchored by a static Aura.toml (project context,
paths only: data archive root, runs dir), in two tiers (#241, ratified
2026-07-12):
- Data-only — the default, smallest project:
Aura.toml+blueprints/+runs/, blueprints and research documents over the std vocabulary, no crate, no build step. - Native — node logic lives in node crates: separate
cdylibcrates referenced viaAura.toml [nodes], scaffolded and attached by a dedicated verb (the visible role-2 switch, C25).
The load boundary tier-selects: a [nodes] pointer list → load that crate;
a root Cargo.toml → the pre-#241 native project, unchanged; neither →
std-vocabulary-only. aura new scaffolds the data-only tier; aura nodes new
scaffolds a node crate beside the project and attaches it. During research the
aura host loads and runs the project (C13 hot-reload); for deploy the chosen
strategy + broker freeze into a standalone binary.
Dependency policy (amended 2026-06-10). Dependencies are admitted by
deliberate, per-case review — what a crate pulls in weighed against what it
buys — with particular scrutiny for anything that enters the frozen deploy
artifact (C13: this bot = this commit). Well-established standard crates
(serde, rayon, …) pass that review and are used wherever they do the job,
including in the bot. There is no blanket zero-dependency commitment and
no blanket admission; hand-rolling what a vetted standard crate already does
is the anti-pattern, not the dependency. aura-ingest is the data-source
ingestion edge, not a dependency firewall.
Forbids. Project-specific signals in the aura repo (it keeps at most
example/fixture nodes under examples/ for its own tests); a multi-project
manager inside aura; a bespoke node registry/marketplace (cargo + Gitea is the
package mechanism). Dependency admission is governed by the per-case policy
above, not a blanket ban.
Why. The engine/game split keeps the engine sharp and reusable while each project versions its own research with its own forward-queue. Promotion (local → shared → std) is the ordinary Rust reuse gradient, no new mechanism. The original "a project is always a Rust crate" invariant was deliberately amended (#241) once the role model diagnosed that the smallest project carries no native logic at all.
Current state
The engine workspace carries the non-node crates beyond aura-std; the full
roster and its layering are C28's ladder — this contract does not re-enumerate
it. aura-ingest is the data-source ingestion edge, where the data-server
external tree enters.
Engine ↔ domain seam — the metric-generic engine (decision log:
#136 → #147/#290/#291/#292). aura-engine is the domain-free, metric-generic
run loop: RunReport<M> (crates/aura-engine/src/report.rs) is parametrized
over a metric type. The concrete trading instantiation M = RunMetrics and the
backtest metric reductions (RunMetrics, RMetrics, summarize_r,
PositionEvent / PositionAction / derive_position_events) live in the
outer-rung crate aura-backtest (crates/aura-backtest/src/metrics.rs).
The domain-neutral statistics substrate and selection provenance — the
multiple-comparison hurdle math (inv_norm_cdf, expected_max_of_normals), the
bootstrap/permutation kit (MetricStats, resample_block, permute), the
MetricVocabulary trait, and FamilySelection / SelectionMode — live in
aura-analysis (crates/aura-analysis/src/lib.rs). aura-registry's
selection vocabulary and aura-measurement's IC (IcMetrics) are the trait's
two production implementors. This is the realized form of the once-deferred
"make RunReport generic / turn the orchestration layer into a domain-agnostic
substrate" work.
Campaign-execution leaf. aura-campaign owns campaign-execution
semantics — cell enumeration, preflight, gate evaluation, winner selection,
walk-forward rolling, realization assembly (C18) — as a leaf library whose deps
deliberately exclude aura-ingest / aura-std / aura-composites; harness
construction and data binding enter only through the one-method MemberRunner
seam (&dyn MemberRunner), so each consumer binds its own runner while the
semantics live here once. It is explicitly not C21's World: it realizes one
campaign document and owns no topology, data sources, or UI.
Two-tier scaffolding. aura new emits the data-only project
(crates/aura-cli/src/scaffold.rs: Aura.toml + blueprints/*.json + runs/,
no crate); aura nodes new emits a node crate beside the project and appends
the [nodes] pointer (crates/aura-cli/src/main.rs; the load-boundary tier
hints live in graph_construct.rs::tier_hint_for_type_id). Provenance widened
additively: a data-only run stamps commit-only
(crates/aura-runner/src/project.rs::Env::provenance).
See also
- C1 — the behaviour-preserving invariant the crate extractions kept
- C13 — hot-reload authoring loop / frozen deploy artifact
- C18 — the run registry and campaign realization assembly
- C21 — the World the campaign leaf is deliberately not
- C25 — the role-2 switch
aura nodes newmakes visible - C28 — the full crate roster and the layer ladder
History: c16-engine-project-split.history.md