Skip to content

fix(install): the default install lands every module first, and a declared set installs only itself - #6737

Merged
rbuergi merged 26 commits into
mainfrom
fix/bootstrap-module-phase-first
Oct 14, 2026
Merged

rbuergi merged 26 commits into
mainfrom
fix/bootstrap-module-phase-first

Conversation

@rbuergi

@rbuergi rbuergi commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What

The platform bootstrap: a FRESH instance whose image does not ship the store-delivered modules (a control image, Mesh:ClosedTypeSet=true) can now install the store from the registry.

1. Phase 1 — modules; phase 2 — nodes. InstanceAutoRegistrationService.LandModulesFirst lands the compiled module of every selected package that has no install record yet, BEFORE any package's nodes are written. Phase 2 (the node install, in dependency order) is subscribed only after every module of the selection has been decided.

  • Same gates the install funnel applies before a file travels: entitlement (with the deployment-config principal), the licence-acceptance gate, and declared parameters; the platform floor is the adoption's own floorHold. Each adoption is bounded by PerPackageAdoptBudget; the module set is proposed after every wave that decided a fresh carrier.
  • Fresh installs only: an installed package keeps its module on the funnel (after content, inside the floor and update-policy holds), so this never lands drift those holds gate. An unreadable install record is not treated as fresh.
  • Never fails the pass: the adoption absorbs its failures; a fault of the phase is logged at Error and the content phase runs as before.
  • The landing raises the pending-restart marker (restart-as-activation — a brand-new module is NotHeld); the pass after that restart finds Skill/Agent registered and installs Store first, then everything rooted on Store/Plugin. The "NodeType must be registered" validation is untouched — the first pass's content failures are FAILED with their cause and retried by the next pass.
  • DefaultInstallSummary.ModulesLanded + a MODULES LANDED ahead of content (load at the next restart): […] clause on the summary line.

2. A declared set installs only itself. PluginCatalogOptions.InstallPreInstalledPackages keeps its bool surface (reads true while unset); the new InstallPreInstalledPackagesConfigured (bool?) tells unset from true. Unset, the preInstalled baseline applies unless InstallByDefault declares an EXPLICIT set (every entry Source/Package, none Source/*); then exactly the named packages and their declared requires are selected. An explicit true/false still wins. A whole-source pattern (the chart default Plugins/*) or no patterns keeps the baseline exactly as before.

3. Docs: PluginAuthoring, the chart's installPreInstalledPackages comments, Doc/Architecture/PluginRegistry — new section The bootstrap: modules first, then nodes, and the InstallPreInstalledPackages bullet; EnvironmentComposition lane table; DeploymentContent.PreInstall summary.

Why (measured on a fresh control instance, 2026-10-13)

[DefaultInstall] installing package Store failed … NodeType(s) not registered: Skill
[DefaultInstall] installing package AI failed … NodeType 'Store/Plugin' is not registered
[DefaultInstall] reconciled with FAILURES: 0 installed, 0 up to date, 48 failed [Store, AI, Acp, …]

/data/modules empty. Store's nodes need Skill (the MeshWeaver.AI module, delivered by AI); AI's root and every other root are Store/Plugin (declared by Store); a module landed only after its own package's content validated (CatalogLayoutAreas.InstallOrUpdateCore → WithModule runs on the content's success). No entry point. The instance named five packages and the pass selected 48: every preInstalled package of the registry plus Store.

Tests

test/Memex.Portal.Shared.Test/StoreBootstrapLandsModulesFirstTest.cs, against an in-process registry serving the REAL wire shapes (listing, /files, bundle index, a module bundle with real assembly bytes) to the real RegistryPackageSource / PluginBundleClient:

  • StoreBootstrapLandsModulesFirstTest.AFreshImage_LandsEveryModuleFirst_AndSelectsOnlyTheDeclaredSet — reproduces the production errors verbatim (Install of 'AI' failed: NodeType 'Store/Plugin' is not registered, Store on Skill), and asserts all three modules landed with the pending-restart marker, and the selection is {Store, AI, EntityViews, Chat} without the unnamed preInstalled Games.
  • StoreBootstrapCompletesAfterTheRestartTest.OnceTheModulesLoad_OnePassInstallsTheStoreThenEverythingRootedOnIt — with Skill registered (the loaded module's stand-in), one pass delivers all four, Store before AI before Chat.
  • PreInstalledBaselineSelectionTest — the selection rule's truth table.

Negative controls (run locally, each reverted alone):

  • Module phase removed → Expected collection {} to equal {"Bootstrap.Test.AI", "Bootstrap.Test.Chat", "Bootstrap.Test.EntityViews"} (the sidecar stays empty — the production state).
  • Selection reverted to ?? true → Expected collection {"AI", "Chat", "EntityViews", "Games", "Store"} to equal {"AI", "Chat", "EntityViews", "Store"}.

Restored: 231/231 across every default-install / module-landing / floor-hold / install-record class in Memex.Portal.Shared.Test (48 classes); 830/830 MeshWeaver.Documentation.Test. Built -c Release -warnaserror: MeshWeaver.PluginCatalog, Memex.Portal.Shared.Test, MeshWeaver.Documentation.Test, MeshWeaver.Deployment.Contract.Test — 0 Error(s), 0 Warning(s).

Deploy notes

  • Behaviour change on the next boot of any instance whose InstallByDefault names packages exactly and does not set InstallPreInstalledPackages: the preInstalled baseline is no longer selected there. Nothing installed is removed; installed packages keep updating through the registry reconciler. Instances with a whole-source pattern (the chart default Plugins/*) are unchanged.
  • A fresh instance needs ONE restart after its first boot for the landed modules to load (the self-updater takes the pending-restart marker; where it cannot roll, any restart does).
  • Not established here: a cross-package root (Store/Plugin) on a closed type set once installer-side NodeType rows are withheld (Closed type set: package installer holds no NodeType rows; #6349 retry skips the closed-set refusal (#6627) #6670, open) — phase 1 lands the modules either way, which is what /health required_modules reads.

Implementers: none — no interface member added.
Pairs-with: none — additive only: PluginCatalogOptions.InstallPreInstalledPackagesConfigured, DefaultInstallSummary.ModulesLanded (init); CatalogLayoutAreas.ProposeMeshModuleSet private → internal.

🤖 Generated with Claude Code

…lared set installs only itself

A fresh instance whose image ships none of the store-delivered modules could not install the store:
Store's nodes need Skill (registered by the MeshWeaver.AI module that AI delivers), AI's root is typed
Store/Plugin (declared by Store), and a mixed package's module landed only after its own content had
validated. Every install failed validation, no module ever reached the volume, and no restart could
register the types (measured on a fresh control instance: 0 installed, 48 failed, /data/modules empty).

Phase 1 of the default install now lands the module of every selected, not-yet-installed package
BEFORE any package's nodes are written (entitlement and parameter gates applied first; the floor is
the adoption's own hold). The landing raises the pending-restart marker; the pass after that restart
finds Skill/Agent registered and installs Store first, then everything rooted on Store/Plugin, in the
order the declared requires already derive. The "NodeType must be registered" validation is unchanged.

Selection: PluginCatalog:InstallPreInstalledPackages is now nullable. Unset, the preInstalled
baseline applies unless InstallByDefault declares an explicit set (Source/Package entries only) — a
deployment that names its packages gets those and their requires, not every preInstalled package of
the registry on top. An explicit true/false still wins.

Pinned by StoreBootstrapLandsModulesFirstTest / StoreBootstrapCompletesAfterTheRestartTest /
PreInstalledBaselineSelectionTest against an in-process registry serving the real wire shapes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The module phase bypasses license consent, can stall indefinitely, and may permanently skip module-set proposal recovery.

7 open findings
What changed in this PR

Adds two-phase plugin bootstrap so modules land before package content, while explicit package sets exclude the baseline unless configured otherwise.

Changes:

  • Adds modules-first bootstrap and restart reporting.
  • Introduces context-dependent preinstalled-package selection.
  • Adds integration tests and updates deployment documentation.
File Description
InstanceAutoRegistrationService.cs Implements selection and modules-first installation.
PluginCatalogOptions.cs Makes baseline configuration nullable.
CatalogLayoutAreas.cs Exposes module-set proposal internally.
DeploymentContent.cs Documents explicit preinstall sets.
PluginRegistry.md Documents bootstrap sequencing.
EnvironmentComposition.md Updates composition semantics.
StoreBootstrapLandsModulesFirstTest.cs Tests bootstrap, restart, and selection behavior.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/PluginCatalogOptions.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/PluginCatalogOptions.cs
Comment on lines +149 to +156
/// <para>🚨 <b>Unset (null, the default) it follows <see cref="InstallByDefault"/></b> (the
/// platform bootstrap, 2026-10-14): the baseline applies unless <see cref="InstallByDefault"/>
/// declares an EXPLICIT set — every entry naming a package (<c>Source/Package</c>), none a whole
/// source (<c>Source/*</c>). A deployment that names its packages gets exactly those plus their
/// declared <c>requires</c>; until this, the baseline added every <c>preInstalled</c> package of
/// every source on top (a fresh control instance naming five packages selected 48). Set it
/// <c>true</c> to keep the baseline beside a declared set, <c>false</c> to suppress it
/// everywhere — an explicit value always wins.</para>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3e0f65f: PluginAuthoring.md, the chart's config.yaml comment and values.yaml comment now describe the unset rule (applies unless installByDefault names an explicit Source/Package set; true/false always wins).

Comment thread test/Memex.Portal.Shared.Test/StoreBootstrapLandsModulesFirstTest.cs Outdated
rbuergi and others added 2 commits October 14, 2026 07:46
…ys propose after a fresh wave; keep InstallPreInstalledPackages bool (Configured reads unset); docs + chart comments; immutable fixture data

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 05:46
@meshweaver-cloud
meshweaver-cloud Bot disabled auto-merge October 14, 2026 05:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.Deployment.Contract/DeploymentContent.cs Outdated
Comment thread src/MeshWeaver.Documentation/Data/Architecture/PluginRegistry.md Outdated
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs
Comment thread src/MeshWeaver.PluginCatalog/PluginCatalogOptions.cs Outdated
rbuergi and others added 2 commits October 14, 2026 07:58
…fault entry keeps the baseline; assert modules download before any content; decisions cited by policy id (default-install-modules-first, declared-package-set-is-exact)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 05:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/MeshWeaver.Documentation/Data/Architecture/PluginRegistry.md Outdated
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs
…gates are listed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 06:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Fresh module proposals omit dependency constraints from not-yet-written install records, and an unbounded record read can block the entire bootstrap.

2 open findings
2 resolved since last review
Previously missed (3)

In code that hasn't changed since last review

Medium severity Apply read timeout before install-record adoption pass

src/​MeshWeaver.PluginCatalog/​InstanceAutoRegistrationService.cs:2268

The adoption timeout does not cover this preceding install-record read. If storage never emits, the sequential Concat cannot advance and phase 2 is never subscribed, so one wedged record read blocks every module and all package content instead of being isolated as an unreadable record. Apply the established install-record read budget before the catch so the pass can continue.

Low severity Clarify baseline suppression when InstallPreInstalledPackages is false

src/​MeshWeaver.Deployment.Contract/​DeploymentContent.cs:211

The final sentence is unconditional, but an explicit PluginCatalog:InstallPreInstalledPackages=false suppresses the baseline even when PreInstall is empty or contains a whole-source pattern. Qualify this as the unset-key behavior so the public contract does not contradict the explicit override.

Low severity Document InstallByDefault relationship for unset behavior

src/​MeshWeaver.Documentation/​Data/​Architecture/​PluginRegistry.md:90

The introduction at line 90 still says these two keys are independent, but the new unset behavior here explicitly derives the baseline from InstallByDefault. That contradiction can make operators assume an explicit package set still retains the baseline; update the introduction to acknowledge the relationship.

🧠 Review effort: Balanced

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
…s AND the selection's declared floors

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 06:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Mixed module waves can activate a refused carrier, and case-insensitive record matching can skip required floor validation.

3 open findings
1 resolved since last review

🧠 Review effort: Balanced

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/ModuleDependencyFloor.cs Outdated
…s compared ordinally

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 06:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Module activation can bypass current authorization and ownership holds, and dependency-floor matching remains case-inconsistent.

4 open findings
2 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Modules adopted before partition ownership holds are enforced

src/​MeshWeaver.PluginCatalog/​InstanceAutoRegistrationService.cs:2252

Modules are adopted before Install() evaluates the partition-ownership holds. An unproven registry ref or a proven source targeting another repository can therefore land and propose its module here even though lines 2451-2478 later return HoldForThePartitionsOwnWriter without fetching content; that hold's existing contract explicitly says “no module is adopted” (line 2529). Apply the ownership verdict before admitting a carrier so code cannot load without its matching held content.

🧠 Review effort: Balanced

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/ModuleDependencyFloor.cs Outdated
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
…y no longer promises a restart activation the proposal may not have written

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Module proposals can still publish unvalidated or incomplete module sets, and malformed patterns can suppress the baseline.

3 open findings
1 resolved since last review

🧠 Review effort: Balanced

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs
Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
…e that could not be cleared withholds the set even when it never landed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 08:00
@meshweaver-cloud
meshweaver-cloud Bot disabled auto-merge October 14, 2026 08:00
@rbuergi
rbuergi enabled auto-merge October 14, 2026 08:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A previously landed module can still be activated after its package becomes terminally refused.

2 open findings
2 resolved since last review

🧠 Review effort: Balanced

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
rbuergi and others added 2 commits October 14, 2026 10:07
…modules from the pass's proposal too

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 08:08
@meshweaver-cloud
meshweaver-cloud Bot disabled auto-merge October 14, 2026 08:08
@rbuergi
rbuergi enabled auto-merge October 14, 2026 08:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A terminally skipped dependency can still allow a dependent-only module set to be proposed.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

rbuergi and others added 2 commits October 14, 2026 10:34
…tInstallSummary.ModuleSetVerdict), not a store the reconciler's own wave close also writes

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 08:35
@meshweaver-cloud
meshweaver-cloud Bot disabled auto-merge October 14, 2026 08:35
@rbuergi
rbuergi enabled auto-merge October 14, 2026 08:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Module-set proposal can still activate uncleared or incomplete carrier combinations, and malformed patterns can suppress the baseline.

2 open findings

🧠 Review effort: Balanced

Comment thread src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Outdated
rbuergi and others added 2 commits October 14, 2026 10:43
…nless phase 1 cleared it as a fresh carrier

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 08:43
@meshweaver-cloud
meshweaver-cloud Bot disabled auto-merge October 14, 2026 08:43
@rbuergi
rbuergi enabled auto-merge October 14, 2026 08:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes central bootstrap and module-activation sequencing across multiple authorization, dependency, and recovery paths.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

@rbuergi
rbuergi merged commit 4701ca7 into main Oct 14, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants