From 965c5f402e14555dd7f61763e63ee7a68b094d2e Mon Sep 17 00:00:00 2001 From: mfw78 Date: Tue, 21 Jul 2026 23:28:37 +0000 Subject: [PATCH 1/2] test(videre-host): pin unknown-venue on a registry-less client boot --- crates/videre-host/tests/platform.rs | 132 ++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/crates/videre-host/tests/platform.rs b/crates/videre-host/tests/platform.rs index ff3506f2..8e56da58 100644 --- a/crates/videre-host/tests/platform.rs +++ b/crates/videre-host/tests/platform.rs @@ -15,9 +15,9 @@ use nexum_runtime::engine_config::{ AdapterEntry, EngineConfig, ModuleEntry, ModuleLimits, PoisonLimitsSection, }; use nexum_runtime::host::component::ChainMethod; -use nexum_runtime::host::extension::{EventSources, Extension, ExtensionEvent}; +use nexum_runtime::host::extension::{EventSources, Extension, ExtensionEvent, ProviderManifest}; use nexum_runtime::host::state::HostState; -use nexum_runtime::manifest::CapabilityRegistry; +use nexum_runtime::manifest::{CapabilityRegistry, ExtensionSections, NamespaceCaps}; use nexum_runtime::supervisor::{Supervisor, build_linker, build_provider_linker}; use nexum_runtime::test_utils::{MockChainProvider, MockStateStore, MockTypes, mock_components}; use videre_host::bindings::{ @@ -1081,3 +1081,131 @@ async fn e2e_crash_looping_adapter_is_poisoned() { Err(VenueError::Unavailable(_)) )); } + +// ── service-missing unknown-venue ───────────────────────────────────── + +/// The videre platform stripped of its registry service: it links +/// `videre:venue/client` and admits the keeper manifest, but publishes +/// no service, so `HostServices::from_extensions` seeds no venue +/// registry. The one variance from [`Videre`] is `service` returning +/// `None`. +struct ClientWithoutRegistry(Videre); + +impl Extension for ClientWithoutRegistry { + fn namespace(&self) -> &'static str { + Extension::::namespace(&self.0) + } + + fn capabilities(&self) -> NamespaceCaps { + Extension::::capabilities(&self.0) + } + + fn link(&self, linker: &mut Linker>) -> anyhow::Result<()> { + Extension::::link(&self.0, linker) + } + + fn manifest_sections(&self) -> &'static [&'static str] { + Extension::::manifest_sections(&self.0) + } + + fn subscriptions(&self) -> &'static [&'static str] { + Extension::::subscriptions(&self.0) + } + + fn admit_worker( + &self, + worker: &str, + sections: &ExtensionSections, + providers: &[ProviderManifest], + ) -> anyhow::Result<()> { + Extension::::admit_worker(&self.0, worker, sections, providers) + } +} + +/// The service-lookup miss, end to end: a keeper importing +/// `videre:venue/client` boots through `boot_single` with no registry +/// service seeded, so `client.rs` resolves every venue call to +/// `unknown-venue` before any adapter is consulted. Distinct from the +/// adapter-map miss, where the registry is present and the venue id is +/// merely unlisted. +#[tokio::test] +async fn client_without_registry_service_resolves_every_venue_to_unknown() { + let Some(wasm) = module_wasm_or_skip("echo-client") else { + return; + }; + + // A [venue]-free manifest: no adapter boots under `boot_single`, so a + // keeper declaring `[venue] body_version` would be refused before it + // could reach the client face at all. + let dir = tempfile::tempdir().expect("tempdir"); + let manifest = dir.path().join("echo-client.toml"); + std::fs::write( + &manifest, + r#" +[module] +name = "echo-client" + +[capabilities] +required = ["client", "logging"] + +[[subscription]] +kind = "block" +chain_id = 1 +"#, + ) + .expect("write manifest"); + + let engine = make_wasmtime_engine(); + let extensions: Vec>> = vec![Arc::new(ClientWithoutRegistry( + platform(&EngineConfig::default()), + ))]; + let linker = make_linker(&engine, &extensions); + let components = mock_components(); + let logs = components.logs.clone(); + let limits = ModuleLimits::default(); + + let mut supervisor = Supervisor::boot_single( + &engine, + &linker, + &wasm, + Some(&manifest), + &components, + &limits, + &extensions, + None, + ) + .await + .expect("boot_single"); + + // The precondition of the client.rs unknown-venue branch: the booted + // service map holds no venue registry. + assert!( + supervisor + .services() + .get::(VenueRegistry::NAMESPACE) + .is_none(), + "boot_single must seed no registry service", + ); + + // One chain-1 block drives the keeper's quote then submit; with no + // registry both resolve to unknown-venue, which the keeper absorbs. + assert_eq!(supervisor.dispatch_block(block(1)).await, 1); + assert_eq!(supervisor.alive_count(), 1, "the keeper stays alive"); + + let runs = logs.list_runs("echo-client"); + assert_eq!(runs.len(), 1, "one run recorded for echo-client"); + let page = logs.read(&runs[0].run, 0); + let messages: Vec<&str> = page.records.iter().map(|r| r.message.as_str()).collect(); + assert!( + messages + .iter() + .any(|m| m.contains("quote at echo-venue was refused")), + "quote resolved to unknown-venue; records were: {messages:?}", + ); + assert!( + messages + .iter() + .any(|m| m.contains("submit to echo-venue was refused")), + "submit resolved to unknown-venue; records were: {messages:?}", + ); +} From a89301198ffcdcbdd9564eb5c4b541b3f1988383 Mon Sep 17 00:00:00 2001 From: mfw78 Date: Thu, 23 Jul 2026 14:52:50 +0000 Subject: [PATCH 2/2] docs(videre-host): correct the registry-less wrapper variance note --- crates/videre-host/tests/platform.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/videre-host/tests/platform.rs b/crates/videre-host/tests/platform.rs index 8e56da58..55053ff6 100644 --- a/crates/videre-host/tests/platform.rs +++ b/crates/videre-host/tests/platform.rs @@ -1084,11 +1084,11 @@ async fn e2e_crash_looping_adapter_is_poisoned() { // ── service-missing unknown-venue ───────────────────────────────────── -/// The videre platform stripped of its registry service: it links -/// `videre:venue/client` and admits the keeper manifest, but publishes -/// no service, so `HostServices::from_extensions` seeds no venue -/// registry. The one variance from [`Videre`] is `service` returning -/// `None`. +/// The videre platform with its registry service withheld: forwards +/// every face `boot_single` consults to [`Videre`] save `service`, which +/// returns `None`, so `HostServices::from_extensions` seeds no venue +/// registry. The provider and event faces default (unused under +/// `boot_single`). struct ClientWithoutRegistry(Videre); impl Extension for ClientWithoutRegistry {