runtime: let a preset carry extensions and pre-built backends#444
Conversation
lgahdl
left a comment
There was a problem hiding this comment.
Checked whether this closes the preset-unreachability gap flagged on #442 (with_logs/with_chain/with_store unreachable through preset-based callers). It's only half-closed:
-
A preset author can now pre-load a
Prebuiltbackend inside their ownRuntime::components(self)impl (the newPrebuiltLogsPresettest demonstrates this well). But an external caller holding a stock preset (e.g.CoreRuntime) still has no hook to override that preset's chain/store/logs before.launch()—PresetBuilder::launch(builder.rs:109) still doesself.preset.components().build(...)inline with nothing exposed in between to intercept. The test harness still bypassesPresetBuilderentirely via the manualTypedBuilderchain, for exactly this reason, and this PR doesn't change that. Might be worth scoping the PR body to "preset-authored pre-built backends" so it doesn't read as fully closing #442's gap. -
builder.rs:98— the doc comment promises the preset's extensions are gathered with appended ones "after," but there's no test for the case where the preset and an appended extension register the same namespace (only distinct namespacesalpha/betaare tested). If a caller appends an extension meaning to override a preset's built-in one for the same namespace, the resulting behavior (silent double-link, last-wins, or error) is undefined and untested.
Everything else — ownership of self.preset.components()/extensions()/add_ons(), the runtime::<R>() sugar over with_runtime — looks clean, no bugs found there.
What
Widens the
Runtimepreset trait:components/add_onstakeself/&selfinstead of being static, and a newextensions()hook (default empty) lets a preset supply linker extensions.RuntimeBuilder::with_runtimebinds a preset by value;runtime::<R>()stays as sugar over it forR: Default.PresetBuilder::launchgathers the presets extensions ahead of any appended viawith_extensions, then builds components from the (now consuming) preset.Why
The preset trait could not express a domain preset that also needs a linker
Extension, or hand back an already-built instance (e.g. mock backends), so both paths bypassedruntime::<R>()and wired assembly by hand. This closes the trait-surface gap without a marker-vs-value split beyondruntime/with_runtime.Testing
preset_extensions_and_appended_extensions_both_link: a value-bound preset extension and an appended extension both reach the linker exactly once.preset_hands_over_a_prebuilt_backend:components(self)carries a pre-builtLogPipelinethrough unchanged.AI Assistance
Implemented with Claude Code assistance.
Closes #273