Skip to content

Wave 7: first-party modules move to MeshWeaver.Plugins as Store packages — the full chain #1664

Description

@rbuergi

Maintainer-directed target (2026-08-16): module code relocates to MeshWeaver.Plugins as bundle-built PACKAGES that appear properly in the Store (card, price, category), install through the standard Provision funnel, land in modules/ and load — with a curated PRE-INSTALL composition (export/import, platform menus/UI) as small per-module compile units under an Essentials META-package (dependency umbrella), not a monolith.

A full scoping pass mapped the chain across both repos. Headline: two disconnected compiled-code lanes exist today — the #1630 bundle lane ships NodeType assemblies into the assembly store (per-node ALC, no restart), while first-party modules are .csproj DLLs loaded by Assembly.LoadFrom at boot. No lane connects the Store to the module loader.

The 13 steps (BUILD vs EXISTS)

# Step Status
1 Package shape for a compiled module (payload pointer, framework-MVID pin, module discriminator, assembly entry name, TFM) BUILD — PluginContent/PluginManifest have none of it
2 Bundle build per framework in the Plugins repo (its CI never packs; the only producer is the platform's plugin-publish.yml, dispatch-only, NodeType-units-only) BUILD
3 Versioning (gen-manifests.py content-hash + derived SemVer, immutable <Module>/vX.Y.Z tags) EXISTS — reusable as-is
4 MVID gate (PrebuiltAssemblySeeder.DeclineReason — pure function) EXISTS — new call site needed at modules/ placement
5 Store card (Price/Currency/Poster/Body on PluginContent; name/icon/category on the node; category-keyed coupons) EXISTS — a module package renders with zero new card work
6 Provision/Install funnel — PackageInstaller only parses files→MeshNodes; needs a binary branch (fetch bundle → verify MVID → unpack) PARTIAL
7 Runtime writer into modules/ (today only the publish target writes there; no closure layout, no collision/cleanup/uninstall policy) BUILD
8 Load — InstallAssemblies is boot-only by construction; restart-as-activation is the realistic first step (a genuinely dynamic loader collides with the kernel snapshot — #1649 territory) BUILD
9 Activation — THE gap: no node/mesh-driven replacement for the static Modules:Assemblies appsettings list. Needs a persisted per-mesh activation list read at boot BEFORE InstallAssemblies, fed by install records; MapMeshModuleEndpoints (#1663) needs the same BUILD
10 Restart semantics — Store UI has no "restart required" state; drain/roll/verify orchestration absent BUILD
11 Fingerprint decisive — CompiledModulesHash recorded but not yet joined into the usable-build check (deliberate step-1 scope of #1653); flipping it is small and is a prerequisite for out-of-image modules HALF-BUILT
12 Pre-install composition — preInstalled + PluginCatalog:InstallByDefault + one-shot ledger + DependencyCheck/DependencyInstall leaves-first transitive install with the SoldSeparately carve-out. Essentials-as-umbrella needs manifest edits, not code EXISTS
13 Distribution coherence — plugin-publish.yml pushes nupkgs to GitHub Packages while PluginBundleClient fetches bundles from a registry portal's /api/plugins/bundles (served from that portal's own assembly store); nothing connects them. A module lane must pick ONE transport BUILD — quiet blocker

Phasing (critical path 9 → 7/8 → 1/2; 3/5/12 free; 4/11 cheap)

  1. Slice A — activation + landing (platform): persisted per-mesh module-activation list (fed by install records, read at boot before InstallAssemblies; restart-as-activation), the runtime modules/ writer with the MVID gate at placement, CompiledModulesHash flipped decisive, Store UI "restart required" state.
  2. Slice B — package + build (Plugins repo): module package shape (Add entire company to Open SMC Teams #1) + the bundle build lane in Plugins CI per framework MVID (Test #2), transport decision resolving Update release-packages.yml #13 (recommendation: the registry-portal bundle endpoint IS the transport; retire the GitHub-Packages push for first-party modules).
  3. Slice C — funnel: PackageInstaller's binary branch (moved canEdit and canRun permissions to props #6) + Provision→install→restart flow end-to-end.
  4. Slice D — composition + first mover: Markdown.Export relocates end-to-end as the pattern; Essentials becomes the meta-package over small per-module packages; pre-install verified on a fresh disposable mesh. Ordering constraint: splitting Essentials into module packages before Slice A lands yields packages that install and then do nothing.

Prereqs in flight: #1653 (modules/ layout — merged), #1663 (endpoint hook — riding), #52-task flip (pattern), #1660 (MVID determinism — makes bundle-per-framework sustainable; its CI-bake work shares Slice A's boot machinery).

Related: #1630, #1644, #1655, #1660. The Plugins repo's delta-gate (affected-modules.py) extends to compiled packages as ordinary module dirs — verified.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions