feat(runtime): per-component Builder traits and BuilderContext#190
Open
mfw78 wants to merge 1 commit into
Open
feat(runtime): per-component Builder traits and BuilderContext#190mfw78 wants to merge 1 commit into
mfw78 wants to merge 1 commit into
Conversation
Backends were opened by scattered from_config and open calls in the composition roots. Introduce a ComponentBuilder trait taking a shared BuilderContext (loaded config plus resolved data directory) and wrap the provider pool, LocalStore, and the cow orderbook pool as builders. A ComponentsBuilder assembles the core seams plus the lattice Ext payload into a Components bundle, sizing the log pipeline from limits.logs. The cow builder lives in shepherd-cow-host because the cow cone belongs to that extension crate, not the core runtime. The CLI launch path and the embed example now drive the ComponentsBuilder rather than opening each backend by hand.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #90.
Introduces a per-component
ComponentBuildertrait and aBuilderContext, plus concrete builders for the provider pool, local store, and (in the cow extension crate) the reference order book, assembled by aComponentsBuilderthat composition roots call instead of the previous four scattered open calls.This is part of the epic #79 train and merges in stack order, on top of the injectable
TaskExecutorfrom #89.Changes
BuilderContext<'a> { config: &EngineConfig, data_dir: &Path }andtrait ComponentBuilder { type Output; fn build(self, ctx) -> impl Future<Output = anyhow::Result<Output>> + Send }incrates/nexum-runtime/src/host/component/builder.rs.ProviderPoolBuilder(wrapsProviderPool::from_config) andLocalStoreBuilder(createsdata_dirand opensdata_dir/local-store.redb), plus a no-opimpl ComponentBuilder for ()for the empty-extension lattice.ComponentsBuilder<C, S, E>whosebuild::<T: RuntimeTypes>drives the three builders against the Chain/Store/Ext lattice and sizes a freshLogPipelinefromlimits.logs().ReferenceExtBuilderincrates/shepherd-cow-host/src/ext_cow.rs, wrappingOrderBookPool::from_config. This stays in the cow extension crate, not core, matching the existing crate boundary (OrderBookPoolis owned byshepherd-cow-host; the core runtime carries no cow dependency).crates/nexum-cli/src/launch.rsto build components viaComponentsBuilder::new(ProviderPoolBuilder, LocalStoreBuilder, ReferenceExtBuilder).build::<ReferenceTypes>(&ctx).crates/nexum-runtime/examples/embed.rsto use the core-only lattice,ComponentsBuilder::new(ProviderPoolBuilder, LocalStoreBuilder, ()), retaining the embedder's log read handle viacomponents.logs.clone().Test plan
cargo fmt --all --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-features --no-fail-fast(all green, zero failed, zero skipped)e2e_supervisor_boots_example_module,e2e_balance_tracker_block_dispatch,e2e_ethflow_watcher_log_dispatch,e2e_stop_loss_block_dispatch,e2e_twap_monitor_block_dispatch,twap_monitor_without_cow_extension_fails_to_boot, and thecow_bootsuiteembed.rsexample builds against the core-only (cow-free) latticeNotes for reviewer
buildisimpl Future<Output = ...> + Sendrather than a bare synchronous function, becauseProviderPool::from_configgenuinely dials WS transports and needs to be async. This follows the existingChainProvideridiom elsewhere in the codebase and keeps builders usable from a spawned task; the synchronous builders (LocalStore, cow) simply have await-free bodies.One ordering change worth flagging explicitly: previously
create_dir_all(data_dir)ran before the provider pool was opened; now the provider pool builder runs first andLocalStoreBuildercreates the data directory as part of opening the store. Neither the provider pool nor the cow extension touchesdata_dir, and the directory is still created before the cow extension opens its own state, so this reordering is benign, but it is a real behavioural change from a pure move and is called out here rather than left implicit.Follow-ups intentionally left out of scope for this PR:
ComponentsBuilderinto the epic's declarative type-stateRuntimeBuilder, so the builder assembly and the executor choice from supervisor: introduce TaskExecutor, thread it through stream openers #89 meet in one place rather than at the imperative composition roots.TaskExecutorfrom the launcher rather than havingbootstrap::runhard-pickTokioExecutor.BuildErrorenum (thiserror) at theComponentBuilderseam instead ofanyhow, for structured boot-failure classification.ComponentsBuilderoptionally accept a pre-builtLogPipelineso an embedder can inject a custom sink instead of always getting the in-memory default.AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.