feat(runtime)!: cut guest-to-guest calling and restore the single-store model - #274
Merged
Conversation
mfw78
force-pushed
the
chore/spdx-resolver-msrv
branch
from
August 17, 2026 04:44
8e315c0 to
84ad7c5
Compare
…re model Remove [component].provides and the engine.toml [implements] table with their verification, authorization and prepass machinery: enforce_provides, enforce_implements, the interface claim ledger, and the six refusals they raised. The six labels leave the pinned error_kind set, a deliberate operator-contract change the closed-set test now enforces in reduced form. Keep InterfaceId and InterfaceTrack for the plugin registry, less matches_export, and record why in the module rustdoc. Move the operator artifact pin from the [implements] row to [[modules]].digest, verified on the exact bytes handed to the compiler beside the author's [component].digest. DigestPin::Operator now names [[modules]].digest in engine.toml, and its wording test changes with it. Supersede ADR-0021 with ADR-0022, which re-grounds one-component-one-Store on store-scoped enforcement. Amend ADR-0017, ADR-0020 and ADR-0016 in place, and repoint the operator handbook and the packaging guide at [[modules]].digest. BREAKING CHANGE: a manifest carrying [component].provides or an engine.toml carrying [implements] now refuses at parse as an unknown key. Closes #253 Closes #254 Closes #255 Closes #256 Closes #257 AI Assistance: Claude Fable 5 used for the implementation.
mfw78
force-pushed
the
feat/cut-guest-to-guest
branch
from
August 17, 2026 04:58
40243f7 to
0132a85
Compare
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.
Stacked on #273. Base is
chore/spdx-resolver-msrv, not main. Merge #273 first; GitHub retargets this to main when it does.Why the feature goes
No component the toolchain builds can satisfy a
providesclaim.synthesizeincrates/nexum-world/src/lib.rsemits one world carrying func exports only,export initandexport on-event, and never an interface instance.enforce_providesaccepted onlyComponentItem::ComponentInstance.The test fixture stated the contradiction in its own header: it "exports an interface instance, which no in-tree guest can".
Zero in-tree manifests declared
providesand zero configs declared[implements], so what shipped was a complete admission-control system for a capability that could not be produced or consumed.Neither product the runtime serves needs the edge.
A daemon module is host-triggered.
A wallet plugin is host-called and returns a verdict.
A decoder plugin feeding a risk plugin is cascading host-to-guest over a host-defined interchange type, which also keeps user consent non-transitive: a user approves a set of plugins, never a call graph among them.
Operator impact
This is a config-key, refusal-wording and metric-label contract change.
The
engine.toml[implements]table is removed.EngineConfigcarriesdeny_unknown_fields, so a stale table refuses at parse as a TOML error an operator cannot distinguish from a typo. No shim was added because no config ever declared one.[component].providesis removed from the manifest and refuses the same way.Six labels leave the closed
error_kindset:invalid_interface_id,interface_claimed,provides_not_exported,implementer_unbound,implementer_unpinned,implementer_not_claiming. The closed-set test enforces the reduced set.DigestPin::Operator's wording changed, and its pin test changed with it.What got stronger
The operator artifact pin moves from an
[implements]row to[[modules]].digest, so it is available for every module rather than only for aprovidesclaimant that could not exist.ModuleEntry.digestis validated at parse with a typedEngineConfigError::InvalidModuleDigest. The operator pin and the author's[component].digeststay independent, both verified against the exact bytes handed to the compiler, operator checked first. A mismatch names which pin failed.A review finding added tests pinning that a matching operator digest does not satisfy
require_component_digest: the author pin is still required when the operator demands one.What was kept, and why it is written down
InterfaceIdandInterfaceTracksurvive, lessmatches_export, whose only caller wasenforce_provides.The module rustdoc now records why, so the next reader does not delete them as orphans: a plugin registry must select candidates for a slot before reading bytes, and
InterfaceTrack's leading-zero rule decides whether a registry update is auto-installable or needs fresh user consent.The records
New ADR-0022 supersedes ADR-0021 in full, since ADR-0021's whole Decision was the pair.
ADR-0022 re-grounds one component, one
Storeon store-scoped enforcement rather than the old imports-become-the-union claim, which is true ofwacbut no longer inherent to the Component Model sinceimplementsandexternal-idmerged.ResourceLimiteris store-level andmemory_growingcarries no instance identity, fuel and epoch deadlines areStoremethods, andLinkerInstance::func_newclosures carry no caller identity. None of that is fixable by any composition mode.It concedes that WASI Virt's attenuation is structural and holds against a malicious guest, while covering import-shaped capabilities only, and it explicitly rejects same-
Storeseparate instantiation for the same fuel, memory and poison reason.ADR-0017 is amended where it matters most. #233 deleted the extension-installed component path partly on the stated grounds that a service edge would replace it. Cutting that edge would have left #233 standing on nothing, so the record now re-grounds it on its independent merits, an unused parallel admission path, a second registry and the shadowing defect #204 itself reported, and says plainly that a host-calls-guest seam is expected to return for the plugin engine without re-litigating #233.
ADR-0016, ADR-0018 and ADR-0020 carry in-place marks, with two-way supersession metadata restored.
Review
Seven findings, all fixed, none rejected.
Two were the same defect:
production.mdclaimed only[[modules]].digestholds against a compromised artifact store, inconsistent withREADME.mdanddocs/02.ModuleEntrylost its publicDeserializeand regained it through#[serde(try_from)]so digest validation still runs on the public path, pinned by a new test.ADR-0017's
wacalternative still rested on the union-of-imports ground and now points at ADR-0022's re-grounding.ADR-0022's Consequences claimed no shim variant existed; the true reason is that no config ever declared the table.
ADR-0018 needed its own marks, and ADR-0022 needed
supersedes: 0016to restore two-way metadata.The last added the
require_component_digesttests described above.Verification
just cigreen: 778 tests, content lint, zero-leak, fmt, clippy, rustdoc, guest wasms, doctests../scripts/msrv-lint.shok.Closes #253
Closes #254
Closes #255
Closes #256
Closes #257
AI Assistance: Claude Fable 5 and Claude Opus 5 used for the implementation, review, and this description.