Repository navigation
The gate can load a module built outside its image — the seam that lets source leave core (#2276) - #2541
Merged
Conversation
…ts source leave core (#2276) A module's DELIVERY and its SOURCE location are independent, and only the first was solvable before now. The bake host (mw-plugin-test) judges a node repo's content, and that content may declare node types a MODULE provides — an Agent or Skill node needs the AI engine's types registered or the install is refused "not registered". While the module's source sits in core, the tester lands it from its own closure lane. The moment the source moves to a node repo, the platform image cannot build those bytes at all, and the only build of them is the one that repo's CI just produced. `--module <dll>` (repeatable) is how that build reaches the gate. Each path joins Modules:Assemblies AND Modules:Required, so an absent one fails RED before the mesh boots rather than booting a gate that then refuses every install needing the module and blames the CONTENT. Absolute paths pass through ResolveModulePath untouched, so a mounted module can never be silently substituted by a same-named copy in the image (the #2223 shadowing class). Every external module is echoed at startup — a run that loaded none must not look like a run that loaded them. This unblocks moving src/MeshWeaver.AI (and later MeshWeaver.Maps) out of core: the plugins gate mounts its own freshly built module instead of depending on the platform image to have built it. Docs: Modules.md gains the AI engine's inventory row and a "Deciding" section that states the model rather than the history — delivery vs source as independent properties, why the two activation lists are mutually exclusive for one name, why a host without a plugin catalog (Memex.LocalMesh) cannot use the registry lane, and the ordering rule the whole carve-out follows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tz1i2fFcJhvR1Eje8yFH5F
Contributor
There was a problem hiding this comment.
Pull request overview
Adds support for loading externally-built module entry assemblies into the mw-plugin-test gate run, enabling node-repo CI outputs to be used for type registration during gating even when module source moves out of the platform repo.
Changes:
- Add repeatable
--module <dll>CLI option and surface it throughGateOptionsinto gate mesh boot configuration. - Activate external modules by injecting them into both
Modules:AssembliesandModules:Required, and echo configured external modules at startup for traceability. - Add targeted tests for the external-module seam and expand module documentation to cover delivery vs source decisions.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tools/MeshWeaver.PluginTester/Program.cs | Parses --module, validates existence, and passes external module paths into gate options while logging them. |
| tools/MeshWeaver.PluginTester/PluginGateRunner.cs | Threads external module entries into gate mesh configuration and required-module validation. |
| test/MeshWeaver.PluginTester.Test/ExternalModuleGateTest.cs | Adds tests around module-path resolution and required-module missing detection. |
| src/MeshWeaver.Documentation/Data/Architecture/Modules.md | Documents AI module inventory entry and adds a “Deciding” section about delivery vs source location. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
…achable from this diff)
…t review) - ExternalModules_JoinBothActivationLists asserted only that GateOptions carries the paths. Renamed to say that, and it now checks the paths arrive VERBATIM and in order — rewriting one is how a mounted module gets silently replaced by a same-named copy in the image. The Required half is covered by MissingRequired_NamesAnAbsentExternalModule; the end-to-end fold by the gate suites that boot a mesh with the engine activated. - "NEVER under Modules:Assemblies" contradicted the very next paragraph (LocalMesh keeps the engine in its app closure) and the module's own guidance. Scoped to catalog-enabled deployments, with the LocalMesh case named: the rule is about not listing it in BOTH lanes, not about one lane being wrong. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tz1i2fFcJhvR1Eje8yFH5F
This was referenced Aug 28, 2026
Merged
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.
Why
A module's delivery (image vs registry) and its source location (platform repo vs node repo) are independent properties. We flipped AI's delivery today; its source could not follow, and neither can
MeshWeaver.Maps, for one reason:The gate judges a node repo's content, and that content declares node types a MODULE provides (an
Agent/Skillnode needs the AI engine's types registered, or the install is refused "not registered"). Once the source moves, the platform image cannot build those bytes, and the only build of them is the one the node repo's own CI just produced.What
--module <dll>, repeatable, onmw-plugin-test:Modules:Assemblies(activation) andModules:Required(the loud half), so an absent one fails RED before the mesh boots — never a gate that quietly ran without it and then blamed the content for every refused install;ResolveModulePathuntouched, so a mounted module can never be silently substituted by a same-named copy inside the image (the A view-pack fix can merge, build and deploy while the portal keeps loading an older copy of that pack #2223 shadowing class, one level down);Consumer side (next change, in MeshWeaver.Plugins): the gate job mounts the
modulesjob's freshly built bundle and passes--module. Thensrc/MeshWeaver.AIcan leave core.Tests
ExternalModuleGateTest(3): absolute paths resolve exactly as given (never probed); external modules carry throughGateOptions;MissingRequirednames an absent external module. Plus the existing 91MeshWeaver.PluginTester.Testcases still green.Docs
Modules.mdgains the AI engine's inventory row and a Deciding section written as mechanism, not history: delivery vs source as independent properties, the structural reasons some modules must stay image-shipped (storage bootstrap, middleware order), why the two activation lists are mutually exclusive for one name (ComputeEffectiveModuleEntriesdedupe + the landing 409), why a host with no plugin catalog (Memex.LocalMesh) cannot use the registry lane at all, and the ordering rule the carve-out follows.Doc link/embed integrity gates pass.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Tz1i2fFcJhvR1Eje8yFH5F