venue: install-time body-version handshake#448
Conversation
lgahdl
left a comment
There was a problem hiding this comment.
Solid, well-tested handshake — verified the core correctness questions: admit_worker always sees the complete adapter set (providers load before modules, no partial-view ordering hazard), version-set membership is a real .contains() check (not emptiness), the export-vs-manifest divergence test uses a genuine mismatch, and enforce_extension_sections refuses any unclaimed section rather than silently dropping it. Three things worth a look:
| /// `[venue] body_versions` set contains that version. Every installed | ||
| /// venue is a legal runtime submit target, so one non-decoding adapter | ||
| /// refuses the keeper. | ||
| pub(crate) fn admit_worker( |
There was a problem hiding this comment.
Neither this function's doc nor admit_provider's mentions the vacuous-pass case: a keeper whose manifest omits the [venue] section entirely is admitted unconditionally, regardless of what adapters are installed — the check only fires when a keeper opts in by declaring the section. That's a reasonable default (backward-compat for non-venue keepers) but reads, from the doc alone, as if every keeper is checked. Worth stating the precondition explicitly and why silent opt-out is intentional.
There was a problem hiding this comment.
Confirmed still valid at HEAD - admit_worker (handshake.rs:94) and admit_provider (:47) still carry no note on the vacuous opt-out. Tracked as a doc note in #519.
| /// opaquely. The runtime ascribes them no meaning; it routes them | ||
| /// to the wired extensions' install predicates, and a section no | ||
| /// extension claims is refused at boot. | ||
| #[serde(flatten)] |
There was a problem hiding this comment.
#[serde(flatten)] into a BTreeMap<String, toml::Value> has no uniqueness check across wired extensions' claimed section names — enforce_extension_sections only verifies a section is claimed by at least one extension, not by at most one. If a second extension later picks the same section name (e.g. another one also wants "venue" for something unrelated), nothing detects the collision; whichever extension's parser runs first silently wins. Worth asserting uniqueness of manifest_sections() across the wired extension set at boot.
There was a problem hiding this comment.
Confirmed still valid at HEAD. enforce_extension_sections (supervisor.rs:358) is still .any(|ext| ext.manifest_sections().contains(...)) - at-least-one, never at-most-one. Same collision class as the event-seam dup-kind gap, so I folded it into #517: one boot-time uniqueness pass covers subscription kinds and manifest section names, mirroring the service-namespace bail HostServices::from_extensions already does.
| .await | ||
| .map_err(anyhow::Error::from) | ||
| .context("read adapter body-versions")?; | ||
| crate::handshake::verify_exported_versions(venue_id.as_str(), &declared, exported)?; |
There was a problem hiding this comment.
This divergence check runs after bindings.instantiate (line 701), not before compile/instantiation like admit_provider/admit_worker in supervisor.rs. That's unavoidable (you can't call a guest export before instantiating), but it means a malicious/buggy adapter component still fully instantiates — and any instantiation-time side effects run — before this specific check catches the export/manifest mismatch. Worth a doc note clarifying that only the manifest-section predicates are pre-compile; this export check is necessarily post-instantiation, pre-init.
There was a problem hiding this comment.
Confirmed still valid at HEAD - the divergence check still runs after VenueAdapter::instantiate_async (registry.rs:716) with no note on the ordering. Agreed it is unavoidable (no guest export before instantiation); tracked as a doc note in #519 alongside the vacuous opt-out.
1b9074a to
a4e316f
Compare
d0ec1e9 to
bcccf1b
Compare
Closes #382
What
Adds
videre:venue/adapter.body-versions() -> list<u32>to the venue WIT surface and an install-time handshake: a keeper module declares the one body-schema version it encodes, a venue adapter declares the set it decodes, both via a new opaqueExtensionSectionsmanifest carrier (#[serde(flatten)]onManifest).Supervisor::installnow runs each wiredExtension'sadmit_provider/admit_workerpredicate before compiling, refusing an undeclared manifest section or a version-mismatched pair fail-fast.videre-hostimplements the predicate in a newhandshake.rs, asserting a keeper's version is decoded by every installed adapter.Why
Bodies are opaque
list<u8>with a guest-side borsh version tag, so schema agreement between a keeper and its adapter was never a checked property; a mismatch failed obscurely at runtime instead of at boot. This wires the handshake through the generalizedExtensionseam rather than freezing the WIT surface.Closes #382
Testing
cargo nextest run --workspace --all-features: new supervisor unit tests for undeclared-section refusal, and newvidere-hoste2e tests (e2e_mismatched_body_versions_refuse_the_pair_at_boot,e2e_manifest_export_divergence_refuses_the_adapter_at_boot).AI Assistance
Implemented with Claude Code.