Deploying a plugin change β€” merging is not shipping

A merged pull request changes nothing on any mesh. The plugin repos have no image: an instance runs what its Space has GitSynced and last compiled. Until you pull it and recompile, main and the mesh disagree β€” and the mesh keeps serving the old behaviour while looking perfectly healthy.

This is the tail of every plugin change (MeshWeaver.Plugins, MeshWeaver.Reinsurance, MeshWeaver.SocialMedia, Systemorph/MeshWeaver.Education). The repo-side procedure is the /pullrequest skill in each of those repos; this page is the mesh-side half.

The three steps

git_hub_sync op=check  space=Store     # what is the delta? (read-only, asks GitHub live)
git_hub_sync op=update space=Store     # pull main β†’ import into the Space
compile @Store/Catalog                 # 🚨 the step everyone forgets

Each op runs as an Activity β€” it returns a path immediately and finishes later: get @Store/_Activity/{id} and wait for content.status: Succeeded.

1. check first, always

update pulls the branch HEAD, so if main advanced past the Space's _GitSync.lastSyncCommitSha you are also shipping everyone else's commits in that subdirectory. Know what is in the delta before you pull it.

The Space's _GitSync.subdirectory is the blast radius: Store syncs only Store/, so a change spanning two plugins needs two syncs.

2. update β€” and read what it actually says

3. Recompile β€” the assembly is the deliverable, not the commit

A NodeType serves its last successfully compiled assembly. A recompile happens on a release request, not automatically on every import, and a failed recompile keeps the last-good assembly β€” so the mesh runs your old code with no error anywhere.

Verify on the NodeType node itself (get @Store/Catalog):

Force it with compile @Store/Catalog (returns Ok, or Error with the Roslyn diagnostics inline). Compile every type whose Source/ your change touched β€” including types that merely share it (sources: ["shared=@Store/Plugin/Source"]), because a shared file changes every consumer.

4. Verify the behaviour, not the sync

"Activity Succeeded" only means the import ran. Open the surface you changed and use it.

Worked example β€” 2026-08-03

Provisioning failed on memex with Access denied: Create permission required for node 'AgenticPrimerDe/_Activity/…'. The fix β€” a system-identity install engine β€” had been merged for hours and was already synced onto the mesh, and git_hub_sync update answered Skipped (0 node(s)), correctly: the nodes matched.

The button still ran the old code, because Store/Catalog sat at lastCompiledVersion 1012 against node version 1019 β€” currentSourceVersions listed sources the compiled assembly had never seen. One compile @Store/Catalog (new assembly v1022, compiledSources now equal to currentSourceVersions) and provisioning worked.

The failed provision had also left a husk: a partition root with _GitSync and _Policy but no content. The catalog refuses to re-provision it, because it only offers Provision when the real root is confirmed absent. It was completed in place β€” git_hub_sync op=update on that Space plus a compile of its NodeType β€” rather than deleted and started over.

Core is the opposite case

Systemorph/MeshWeaver does have an image, so merging to main is the deploy: main-cd.yml publishes the image set to ACR and the portals self-update.

Two things to know before calling it deployed:

Never fix it live

A GitSynced space is rewritten from main on every sync, so an edit_content / patch fix survives only until the next sync and then silently reverts. Change the repo, PR it, sync it. A live edit is a stopgap to stop bleeding, and it must land in the repo the same session.

See also: Doc/Architecture/GitHubSync, Doc/Architecture/PluginRegistry, Doc/Architecture/NodeTypeCompilation.

Reconnecting…
The server was updated. Reloading the page to pick up the latest version.