Skip to content

MeshWeaver.AI leaves the platform: carve out the three non-AI surfaces, then move the engine to MeshWeaver.Plugins #2276

Closed

Description

@rbuergi

Maintainer direction (2026-08-25): "all ai stuff deleted from core and all deployed and green."

MeshWeaver.AI and MeshWeaver.AI.Application are the last AI in the platform repo. This issue is the program: the verified inventory of every compiled edge, the three surfaces inside MeshWeaver.AI that are not AI and must be carved out first, and the phased move to MeshWeaver.Plugins.

What already left

0b3b4266f "Fourteen modules leave the platform" (2026-08-19) took the AI provider packs — MeshWeaver.AI.OpenAI, .AzureFoundry, .ClaudeCode, .Copilot, .WebSearch — to MeshWeaver.Plugins (Plugins#524). Memex.Portal.Shared.csproj:105 documents the flip. The directories still visible under src/MeshWeaver.AI.*/ in a dev tree are untracked bin/obj leftovers (git ls-files = 0 for all five); they are not in MeshWeaver.slnx.

Why the engine stayed

That commit states its own criterion: "Nothing in the platform's own src/ referenced them. That is what made this a deletion rather than an untangling." False for MeshWeaver.AI — it has 21 compiled consumers across 5 platform projects, using ~40 distinct public types:

Consumer Files Types used
memex/Memex.Portal.Shared 10 ModelProviderNodeType, MeshOperations, IChatClientFactory, Harness, ConnectSessionManager, IConnectStrategy/IConnectTokenSink/IMcpBackConnection, SkillNodeType/SkillDefinition/SkillInfo/SkillAction, AiContentSources, AiCatalogLayoutAreas, TokenUsage*, ModelPrice*, IProviderKeyProtector, LanguageModelCatalog*, ProviderCredentialSeed, ThreadComposer, Thread
src/MeshWeaver.GitSync 8 AiContentLocator, AgentFileParser, AgentConfiguration, BuiltInAgentProvider/BuiltInSkillProvider, SkillDefinition/SkillMarkdown/SkillNodeType, AgentChatClient, DescriptionGenerator, IProviderKeyProtector
src/MeshWeaver.Blazor.Portal 14 chat views (Chat/*), AddAITypes
memex/Memex.LocalMesh 1 MeshOperations
tools/MeshWeaver.PluginTester 1 AddAI(AiContentSources.ContentPartitions)

Plus 11 test projects referencing MeshWeaver.AI.csproj (AI.Test, Threading.Test, Content.Test, GitSync.Test, Autocomplete.Test, Documentation.Test, PathResolution.Test, Query.Test, Hosting.{Orleans,PostgreSql,Snowflake}.Test).

Verified NOT coupled (so these are not blockers): nothing in MeshWeaver.Mesh.Contract, Messaging.Hub, Hosting, Layout or Graph compiles against it — every StartThread/SubmitMessage hit in those assemblies is a comment. MeshWeaver.Layout's ThreadMessageBubbleControl and PromptCell are already contract-shaped.

Phase A — carve the non-AI OUT of MeshWeaver.AI (platform-only, no cross-repo ordering)

Three surfaces live in the AI assembly but are not AI. Each is a compiled edge that would otherwise force the platform to reference a module.

A1. MeshOperations → a platform assembly. src/MeshWeaver.AI/MeshOperations.cs is 4,385 lines of mesh get/search/create/update/patch/move/copy/delete/export — the facade behind the portal's REST API (Memex.Portal.Shared/Api/MeshApiEndpoints.cs) and Memex.LocalMesh/LocalMeshApiEndpoints.cs, as well as the MCP tools. Its only AI coupling is one member: ResolveContextPath(IAgentChat chat, string path) (line 158) — which stays behind in the AI assembly as an extension. Moves with it: NodeReadOutcome, NodeChangeEntry, MeshExportManifest/MeshExportFileEntry. New project (its dep set — ContentCollections, Indexing(.Graph), Kernel, Markdown, Layout, Graph — is wider than any existing platform assembly's, so folding it into MeshWeaver.Graph would bloat a core assembly).

A2. IProviderKeyProtector / IMasterKeyProvider / ConfigMasterKeyProvider → platform security. AES-256-GCM at-rest protection for stored credentials. Consumers are already mostly non-AI: GitSync/GitHubCredential + GitHubCredentialService (GitHub PATs) and Memex.Portal.Shared/Authentication/EaGraphAuth.cs (Entra), alongside AI's own ModelProviderConfiguration.ApiKey. Related: the plaintext-key rotation item.

A3. AiContentLocator / AiContentSources / the Agent+Skill parsing set — decision required. AgentFileParser, SkillNodeType, SkillDefinition, SkillMarkdown, AgentConfiguration, BuiltInAgentProvider/BuiltInSkillProvider. These are AI, so under "all AI deleted from core" they leave — which means their platform consumers (GitSync's five AI-content-sync files, Portal.Shared/Skills/AgentSkillSyncService, AiMenuContributions, PluginTester) leave with them (Phase B), rather than a MeshWeaver.AI.Contract staying behind. Recording the alternative explicitly so the choice is deliberate, not defaulted.

Phase B — the AI features leave the portal composition root

Each of these is an AI feature living in a platform assembly. A module can carry all of it: MeshNodeProviderAttribute.BuilderConfigurations hands a module the full MeshBuilder surface (incl. ConfigureServices, ConfigureDefaultNodeHub), MeshEndpointProviderAttribute carries routes, and menus/settings tabs go through the existing provider interfaces — the MeshWeaver.Social module is the worked precedent.

  • Memex.Portal.Shared: AiMenuContributions, Models/ModelProviderService, Models/ConnectTokenSink, Authentication/McpBackConnectionService, Settings/TokenUsageSettingsTab, Skills/AgentSkillSyncService, and the AI halves of MemexConfiguration + StaticRepoSyncExtensions.
  • MeshWeaver.GitSync: AiContentDiskWriter, AiContentSyncArea, AiContentSyncMenuProvider, HubAiContentSyncExtensions, PullRequestDraftService.
  • MeshWeaver.Blazor.Portal/Chat/* (14 files) — rides Extract the GUI implementations from the core repo: RN app + Blazor packs move to MeshWeaver.Plugins #2169 Phase B3 or moves to an AI view pack, whichever lands first.
  • tools/MeshWeaver.PluginTester — its .AddAI(...) in PluginGateRunner.

Phase C — the move

src/MeshWeaver.AI (156 files) + src/MeshWeaver.AI.Application (8 files, already a self-contained module: [assembly: AgentsApplication] : MeshNodeProviderAttribute, and Blazor.Portal's reference to it is ships-the-bits only — no code usage) + the AI-only test projects → MeshWeaver.Plugins. Delete here; declare under Modules:Required (not merely Assemblies) so a deployment that lost the bundle fails readiness instead of silently shipping a portal with no chat.

🚨 Ordering rule from Plugins#524: this merges only once the registry SERVES the bundles. Until then the image is where every consumer gets them and the deletion would take the capability with it.

Phase D — deployed and green

Registry serves the AI bundles → CD rolls memex / memex-cloud / client-i → verify a real chat round on a portal, not an API probe.

Risks to hold

  1. HubThreadExtensions is AGENTS.md's canonical thread-submission surface (hub.StartThread / SubmitMessage / MarkThreadDone / …) and it lives in src/MeshWeaver.AI. Moving it makes threads a module-provided capability; AGENTS.md and ThreadOperations.md must be updated in the same change set to name the new home.
  2. AiContentSources.ContentPartitions decides who SERVES the Agent/Provider/Harness/Skill partitions — a listed partition is served from Postgres and its in-memory StaticNodePartitionStorageProvider is not registered. Getting this wrong makes the in-memory provider shadow the DB nodes the Agent plugin installs.
  3. 11 test projects must each drop the dependency or travel with the module.
  4. A closure/app-root duplicate of a landed module is a 409 on every instance — the MeshModulesGuardPublishAppRoot refusal exists for exactly this and must stay armed.

🤖 Generated with Claude Code

Activity

  1. rbuergi commented on Aug 25, 2026

    @rbuergi
    ContributorAuthor

    Sharpened plan after building A1 + A2 — Phase B is intra-repo, and that reorders everything

    Building the first two steps changed the shape of the rest. Phase B does not need MeshWeaver.Plugins at all.

    The 14-module commit's criterion was "Nothing in the platform's own src/ referenced them — that is what made this a deletion rather than an untangling." The way to reach that state is not to move AI features to Plugins one at a time (each needing a served bundle before it can merge). It is to relocate every AI feature currently sitting in a platform assembly INTO MeshWeaver.AI itself, in this repo, with CI green at every step. When that is done the platform has zero AI files and zero AI references, and the engine moves out as ONE clean deletion — the same shape as the fourteen.

    B1 — Memex.Portal.Shared's AI features → MeshWeaver.AI

    AiMenuContributions, Models/ModelProviderService, Models/ConnectTokenSink, Authentication/McpBackConnectionService, Settings/TokenUsageSettingsTab, Skills/AgentSkillSyncService, and the AI halves of MemexConfiguration + StaticRepoSyncExtensions. Their registrations ride a module attribute — MeshNodeProviderAttribute.BuilderConfigurations hands a module the full MeshBuilder (ConfigureServices, ConfigureDefaultNodeHub, AddHostedService), which MeshWeaver.Social already proves in production.

    B2 — MeshWeaver.GitSync's AI-content sync → MeshWeaver.AI, inverting the dependency

    AiContentDiskWriter, AiContentSyncArea, AiContentSyncMenuProvider, HubAiContentSyncExtensions, PullRequestDraftService. GitSync currently points AT the AI engine; afterwards MeshWeaver.AI points at GitSync's git primitives, which is the right direction — a module may reference the platform, never the reverse. A2 already removed the other half of that edge (IProviderKeyProtector), so B2 takes GitSync's AI dependency to zero.

    🚨 This edge is load-bearing beyond GitSync: MeshWeaver.PluginCatalog → MeshWeaver.GitSync → MeshWeaver.AI is how the plugin catalog compiles against AI types today. It is a transitive reference, so it never appeared in any grep of direct ProjectReferences.

    B3 — Blazor.Portal/Chat/* and tools/MeshWeaver.PluginTester

    The chat views ride #2169 Phase B3 (the shell extraction) or move to an AI view pack, whichever lands first. PluginTester's .AddAI(AiContentSources.ContentPartitions) is real, not incidental — the plugin gate composes the in-mesh compile reference set, so it needs a decision, not a deletion.

    Then C — one deletion

    src/MeshWeaver.AI + src/MeshWeaver.AI.Application + the AI-only suites leave together, registry bundle first per Plugins#524.

    A trap found while cutting an edge, worth writing down

    Memex.LocalMesh's AI reference LOOKED dead the moment A1 moved MeshOperations — a stale using and nothing else. Removing it built clean. It was reverted anyway: dropping a ProjectReference drops the DLL from the app closure, and the closure is what CompileReferences composes the in-mesh compile reference set from. In-mesh source is invisible to dotnet build and to CI (AGENTS.md), so "it compiles" says nothing about whether a device-mesh NodeType still resolves using MeshWeaver.AI. Every edge cut in Phase B needs the node-JSON sweep, not just a green build.

    Status

  2. rbuergi commented on Aug 25, 2026

    @rbuergi
    ContributorAuthor

    The Store entry: ONE, and it does not need a source move

    Maintainer direction (2026-08-26): "build it including application … this must be all one entry in store."

    Checked how plugins are actually injected, and two facts change the plan:

    1. The CI matrix can build from the nested core checkout. MeshWeaver.Plugins/.github/workflows/ci.yml carries {package, module, project} rows, and two of them already point INTO a nested meshweaver/ checkout:

    {"package": "DefaultViews", "module": "MeshWeaver.Blazor.Views", "project": "meshweaver/src/MeshWeaver.Blazor.Views/MeshWeaver.Blazor.Views.csproj"}

    So MeshWeaver.AI can become a Store package before its source relocates — that is exactly the order DefaultViews/GraphViews took. The source move is a later tidy-up, not a prerequisite.

    2. The package is one content.module, so the app must be in the same assembly. OpenAI/index.json is a Store/Plugin node with "module": "MeshWeaver.AI.OpenAI" — singular. #2297 folds MeshWeaver.AI.Application into MeshWeaver.AI for that reason: one assembly, one module, one entry, and installing AI installs the app that maintains agents/models/skills/harnesses.

    Target entry:

    { "id": "AI", "nodeType": "Store/Plugin", "category": "AI",
      "content": { "module": "MeshWeaver.AI", "app": true,
                   "entryPoint": ".../area/AgentOverview", "minMeshVersion": "…" } }

    🚨 Installation is gated on the closure edge, not on the package. A closure DLL and a registry module of the same name are mutually exclusive — the landing service refuses with a 409 on every instance. So the entry may be defined, but must not be preInstalled until Memex.Portal.Shared stops referencing MeshWeaver.AI.

    Two findings from making the application live (#2297)

    The Agents application has been dead code since it was written. It carried [assembly: AgentsApplication], but a MeshNodeProviderAttribute is read in exactly ONE place — MeshBuilder.InstallAssemblies — and MeshWeaver.AI.Application was never listed under Modules:Assemblies. It rode the app closure via Blazor.Portal's ProjectReference and shipped in every image contributing nothing. ThreadChatView carries the scar: it constructs SkillAutocompleteProvider by hand because resolving it from DI "returned null and typing '/' showed nothing".

    Turning it on surfaced a platform hang — AutocompleteRequest could never be answered on a hub with a mesh-backed provider. DataExtensions.HandleAutocompleteRequest took LastAsync(), which emits only on COMPLETION, while SkillAutocompleteProvider composes ObserveSkillQueries → ObserveSnapshot → Switch — live subscriptions that never complete. Trace: HUB_HANDLE_END Result: Processed at +27 ms, then 30 s of silence and no response post. Fixed at the root — "settled" is now a quiet period (150 ms throttle / 2 s deadline / 2.5 s empty floor), never completion. Likely the same root cause as the open chat @-autocomplete report.

    Remaining edges before the entry can be installed

    Consumer Files State
    Memex.Portal.Shared 8 next — 5 of 6 checked have NO portal coupling; only AgentSkillSyncService needs PortalApplication.Hub
    Blazor.Portal/Chat/* 14 rides #2169 Phase B3
    tools/MeshWeaver.PluginTester 1 .AddAI(AiContentSources.ContentPartitions) — a real decision, the plugin gate composes the in-mesh compile reference set
    Memex.LocalMesh 0 ✅ cut (#2283)
    MeshWeaver.GitSync (+ PluginCatalog transitively) 0 ✅ cut (#2287 + #2292)
  3. rbuergi commented on Aug 25, 2026

    @rbuergi
    ContributorAuthor

    The last step has a real constraint: a module attribute cannot read configuration

    For the AI entry to carry the engine, AddAI must move from the portal's composition root onto the module's assembly attribute (BuilderConfigurations, the MeshWeaver.Social shape). That is blocked by one thing, and it is worth stating precisely rather than discovering it mid-PR:

    // MemexConfiguration.cs:794-802, 876
    var syncPartitions = features.StaticRepoSync.Partitions.ToHashSet(OrdinalIgnoreCase);
    if (syncPartitions.Overlaps(AiContentSources.ContentPartitions))
        syncPartitions.UnionWith(AiContentSources.ContentPartitions);   // serve AI content as a UNIT
    …
    .AddAI(serveFromPartition);

    AddAI takes a config-derived set, and decides at BUILDER time which partitions Postgres serves versus which get a read-only in-memory provider. A module attribute has no IConfiguration: MeshBuilder exposes none (checked), and MeshWeaver.Social documents the same limit — "there is no IConfiguration instance at install time", which is why it binds through the options pipeline instead.

    🚨 Defaulting the argument is not available as a shortcut. AiContentSources.ContentPartitions is load-bearing in the dangerous direction: membership decides who SERVES a partition, and dropping Agent re-registers the in-memory provider, which then shadows the DB nodes the Agent plugin installs — the agents silently revert to whatever the binary embeds. A module that guessed this set would fail exactly that way.

    Two ways out, both design calls rather than mechanics:

    1. Make the serve-from-DB decision resolve from bound options at runtime rather than at builder time, so AddAI() needs no argument and the attribute can carry it. Follows the LinkedInOptions precedent.
    2. Give MeshBuilder a configuration surface for install-time module contributions. Larger, and it changes the module contract for every pack.

    Until one lands, Modules:Assemblies carries the AI assembly (so the Agents application is contributed — #2297) while AddAI stays a compiled call, and the Store entry cannot be preInstalled because the closure DLL and a registry module of the same name are mutually exclusive (409).

    One rule worth extracting from today, across three independent findings

    Three separate mechanisms turned out to be built but not reachable, each found by a different session, each invisible from the definition side:

    finding looked wired because only visible from
    the Agents application (#2297) it had an assembly attribute and shipped in every image the only reader is MeshBuilder.InstallAssemblies, and it was listed under no Modules:Assemblies
    FrameworkReleaseBroadcaster (Plugins#686) the type existed and compiled in core the pack lane compiles plugin source against the RELEASED floor, where it does not exist
    the shared plugin-registry HTTP client its comment described its budget correctly the comment was true of one caller in three — the page-facing one inherited a downloader's 5-minute ceiling

    Check the call sites, not the declaration — and if there are none, that is the finding. Nothing in review catches these, because each diff is internally consistent; enumerating consumers is the only move that works.

  4. rbuergi commented on Aug 25, 2026

    @rbuergi
    ContributorAuthor

    Correction: the runtime-options route does not work, and the coupling is deeper than one argument

    I proposed resolving the serve-from-DB decision from bound options at runtime so the module attribute needs no configuration. That does not survive contact with the code, for a reason worth recording:

    var typeDefinition = CreateMeshNode();
    if (dbSynced)
        typeDefinition = typeDefinition with { IsDefinitionOnly = true };   // MeshNode.IsDefinitionOnly is `init`
    builder.AddMeshNodes(typeDefinition);

    dbSynced decides two things, not one: whether the in-memory partition provider is registered (deferrable), and whether the type-definition node is definition-only (not deferrable — it is an init property baked into the node at builder time). Leaving a DB-synced type's definition node servable is #902: the type-def node sits at the same path as the partition ROOT, so the durable root can be neither read, re-created, nor written — a permanently unrecoverable partition.

    So the decision has to be available at BUILDER time, which means the module attribute has to see configuration.

    The good news: the install path already holds it. MeshBuilderModuleActivation.InstallConfiguredModules(builder, configuration, …) takes IConfiguration, reads Modules:Assemblies from it, and then calls builder.InstallAssemblies(resolved) — dropping the configuration on the floor. Giving MeshBuilder a configuration surface set at that point is additive, backward-compatible, and fixes this for every pack rather than for AI. It is the general gap MeshWeaver.Social documents as "there is no IConfiguration instance at install time".

    A second coupling, found while scoping it

    Features:StaticRepoSync:Partitions is not only AI's gate. MemexConfiguration applies an AI-specific union to it —

    if (syncPartitions.Overlaps(AiContentSources.ContentPartitions))
        syncPartitions.UnionWith(AiContentSources.ContentPartitions);   // AI content is served as a UNIT

    — and then passes the SAME set to AddDocumentation(...) and AddStaticRepoSync(...). So the portal's static-repo IMPORT depends on knowing AI's partition names. Removing Memex.Portal.Shared's reference to MeshWeaver.AI means that union cannot stay where it is, and simply deleting it would drop Agent/Provider/Harness/Skill out of the import set — AI content silently stops being imported.

    That needs a contributor seam (a module declaring the partitions it wants imported), not a moved constant. It is the last real design question in this program, and it is bigger than the AddAI argument that surfaced it.

    Sequencing recommendation: land the four open edge-cuts first (they are independent and reviewable), then take this as its own change with the seam designed deliberately. Until then the AI assembly rides Modules:Assemblies for its application (#2297) while AddAI stays a compiled call, and the Store entry stays un-preInstalled.

  5. rbuergi commented on Aug 25, 2026

    @rbuergi
    ContributorAuthor

    Correcting myself again: the import "seam" is smaller than I said — no new interface needed

    I described the static-repo coupling as needing a contributor seam ("a module declaring the partitions it wants imported"). Reading AddStaticRepoSync rather than inferring from its signature, that is not so.

    serveFromPartition is used at builder time for exactly one thing: deciding which IStaticRepoSource registrations to add. The importer itself resolves them at RUNTIME —

    services.AddSingleton<IHostedService>(sp => new StaticRepoImportHostedService(
        …, sp.GetServices<IStaticRepoSource>(), …));

    So a module that registers its own sources is already a first-class contributor; the enumerable IS the seam. What the portal's copy does today is register AI's sources on AI's behalf:

    if (serveFromPartition.Overlaps(AiContentSources.ContentPartitions))
        services.AddBuiltInAiContentSources();
    …
    if (serveFromPartition.Contains(ModelProviderNodeType.RootNamespace))
        services.AddSingleton<IHostedService, ProviderCredentialSeedHostedService>();

    Both blocks are AI deciding AI's own business from a config key, in the composition root. With #2300 the module can read that key itself, so they move to the module and the portal stops naming AI partitions at all. No IPartitionGroup, no new contract — I was designing around a constraint that turned out not to exist.

    What that leaves, and why it is ONE atomic change rather than three

    It cannot be split, and the reason is worth writing down: if the module registers the AI content sources from configuration while MemexConfiguration still calls .AddAI(serveFromPartition) compiled-in, AddBuiltInAiContentSources() runs twice — duplicate IStaticRepoSource registrations, and the importer imports each source twice. So the module attribute and the removal of the compiled call have to land together, along with the rest of MemexConfiguration's AI wiring (~13 types: the Connect strategies, IChatClientFactory, Harness, ConnectSessionManager, the catalog options).

    Not starting it tonight, deliberately. Memex.Portal.Shared is being actively split by another workstream (~30 razor files out as Memex.Portal.Gui, ~79 staying), and a large refactor of MemexConfiguration — the one file that workstream says MOVES — against a tree that is mid-split is how two sessions build opposite things. It goes after that split lands, and after #2300 gives the module its configuration.

    Order from here: Plugins#685 → #2297 → #2283 / #2287 / #2292 / #2300 (independent) → the Portal.Shared split lands → the atomic AI-wiring move → the Store entry flips to preInstalled.

  6. added 5 commits that reference this issue on Aug 25, 2026
  7. rbuergi commented on Aug 26, 2026

    @rbuergi
    ContributorAuthor

    All five core PRs merged — where the program stands

    PR what state
    #2297 MeshWeaver.AI.Application folds into MeshWeaver.AI — one assembly, one module, one Store entry ✅ merged
    #2287 credential encryption → MeshWeaver.Mesh.Security; registration AddAI() → AddGraph() ✅ merged
    #2292 GitSync ↔ AI dependency inverted; PluginCatalog's transitive edge goes with it ✅ merged
    #2300 MeshBuilder.Configuration — a module can read deployment config at INSTALL time ✅ merged
    #2283 MeshOperations → MeshWeaver.Mesh.Operations assembly (namespace stays MeshWeaver.Mesh) ✅ merged
    Plugins#685 the plugins repo survives the series (namespace + the deleted project reference) ✅ merged
    Plugins#687 the AI Store entry — module: MeshWeaver.AI, app: true, entryPoint: Agent/AiAgents 📝 draft, 2 gates

    Platform consumers of the AI engine: 5 → 2. Memex.LocalMesh, MeshWeaver.GitSync and MeshWeaver.PluginCatalog are at zero. Memex.Portal.Shared (2 references) and tools/MeshWeaver.PluginTester remain.

    The one remaining change, and why it is atomic

    MemexConfiguration's AI wiring — the module attribute carrying AddAI, the removal of the compiled call, and ~13 types (Connect strategies, IChatClientFactory, Harness, ConnectSessionManager, the catalog options) — must land TOGETHER. Split it and AddBuiltInAiContentSources() runs twice: duplicate IStaticRepoSource registrations, and the importer imports every AI source twice.

    It is unblocked on mechanism now that #2300 is in. It is blocked on sequencing: MemexConfiguration is the one file the Portal.Shared split moves, and #2293 deletes 389 files including all of MeshWeaver.Blazor*.

    Then the entry ships

    Plugins#687 flips to preInstalled once (a) Memex.Portal.Shared stops referencing MeshWeaver.AI — otherwise the closure DLL and the registry module collide at 409 on every instance — and (b) minMeshVersion names a release that actually carries #2297. rc7 (2026-08-22) predates it, so that needs a release decision.

    What this program cost, and what it bought beyond the move

    Three defects found by building it rather than by looking for them:

    1. The Agents application was dead code its entire life. [assembly: AgentsApplication] shipped in every image while listed under no Modules:Assemblies — and MeshBuilder.InstallAssemblies is the only reader of that attribute. ThreadChatView carried the scar: it constructs SkillAutocompleteProvider by hand because DI "returned null and typing '/' showed nothing".
    2. AutocompleteRequest could never be answered on a hub with a mesh-backed provider. LastAsync() waits for COMPLETION; SkillAutocompleteProvider composes live subscriptions that never complete. The handler ran, returned Processed in 27 ms, and posted nothing. Fixed at the root — settled is now a quiet period, never completion.
    3. The credential protector rode AddAI(), while four unrelated subsystems resolve it optionally and store the secret verbatim on null. The day AI left, all four would have written plaintext silently.

    Two cross-repo breaks were caught before shipping — a new namespace that would have failed on the plugins TRUNK rather than on the PR, and a deleted project the plugins' own Blazor.Portal still referenced (MSB9008 — not a symbol, so no grep would have found it).

  8. rbuergi commented on Aug 26, 2026

    @rbuergi
    ContributorAuthor

    Directive sharpened: MeshWeaver.AI is removed entirely from core

    Not "stops being referenced" — the project gone from src/. Here is the full dependency order, measured rather than assumed, so the final deletion is mechanical.

    What holds the engine in core, after #2315

    holder kind resolution
    src/MeshWeaver.Blazor.Portal 14 files of real chat-view usage leaves wholesale in #2293 — nothing to un-reference
    tools/MeshWeaver.PluginTester a real .AddAI(AiContentSources.ContentPartitions) must obtain AI as an installed module, the way a portal does
    13 test projects mixed 2 dead (#2317), 2 travel with the engine, 9 need a call
    Memex.Portal.Shared the composition root ✅ zero, in #2315

    The PluginTester is not a reference to delete — it is a lane to switch

    It registers the AI node types because plugin packages ship Agent and Skill nodes, and without the types those installs are refused "not registered". That requirement does not go away when the engine leaves; it is the gate doing its job. The right shape is the one every deployment uses — install the module — which means the mw-plugin-test image must carry the AI bundle. So it cannot be done before the bundle ships, and the bundle cannot ship before the 409 clears (Plugins#687).

    The nine remaining test suites are a per-TEST question, not per-project

    They use threads and agents as the platform's canonical workload: Hosting.Orleans.Test names ThreadNodeType 49 times, Query.Test 10, Hosting.PostgreSql.Test 6. Two different things are mixed together:

    • tests genuinely about AI on that infrastructure (OrleansChatHistoryTest, OrleansCompileActivityAccessTest) — these travel with the engine;
    • tests about Orleans/PG/query behaviour that merely use thread nodes as a fixture — these stay, and need their workload re-pointed at a platform node type.

    Splitting them per-test is the work; moving whole projects would exile framework suites into a downstream repo, which is the same mistake the Portal.Shared split avoided.

    🚨 Guards that assert OVER the AI project — check these BEFORE deleting, not after

    Three times in one night a guard stayed behind while its subject moved (the #1814 surface-manifest pin, the overlay z-index test, the AI resolution-seam audit). Each time the destination looked complete because the code was there; only the check that verifies it was missing. The ones that would be orphaned here:

    test/MeshWeaver.AI.Test/AiContentPackDriftTest.cs        pins content/ai/** against the Plugins pack
    test/MeshWeaver.AI.Test/AiResolutionSeamAuditTest.cs     scans src/MeshWeaver.AI for query literals
    test/MeshWeaver.AI.Test/AiContentSection(.Test).cs       reads the repo's content/ai section
    test/MeshWeaver.AI.Test/BuiltInSkillCatalogTest.cs       the built-in skill catalog
    test/MeshWeaver.GitSync.Test/AiContentSyncBackTest.cs    writes the live Skill partition to disk
    test/MeshWeaver.Hosting.Orleans.Test/OrleansAutoExecuteTest.cs
    

    Plus one that is easy to miss because it names no AI type in its assertion: FrameworkBuildIdentityTest. FrameworkBuildIdentity.ContentSurfaceAssemblies lists MeshWeaver.AI as part of the surface in-mesh content compiles against, and the list is pinned to the PluginTester's closure. When the engine leaves that closure, the canonical list must drop it in the same change — the same gate that caught #2283 adding MeshWeaver.Mesh.Operations.

    Order

    1. ✅ Credential encryption is platform, not AI (#2276 step A2) #2287 / GitSync stops depending on the AI engine (#2276 step B2) #2292 / The AI application folds into the engine — one assembly, one module, one Store entry (#2276) #2297 / A module can read the deployment's configuration (#2276 enabler) #2300 / MeshOperations is not AI — it leaves the AI assembly (#2276 step A1) #2283 — merged
    2. The AI engine leaves the composition root — Memex.Portal.Shared no longer references it (#2276) #2315 — Memex.Portal.Shared to zero (in CI)
    3. Two test projects reference the AI engine and never use it (#2276) #2317 — two dead test references (in CI)
    4. Delete Blazor and the portal GUI from core #2293 — Blazor.Portal deleted from core (meshweaver-c0; unblocked, CI running)
    5. Plugins#687 flips to preInstalled — the 409 clears once 2 and 4 are in
    6. PluginTester switches to the module lane; ContentSurfaceAssemblies drops the entry
    7. The nine suites split per-test
    8. src/MeshWeaver.AI and src/MeshWeaver.AI.Application's remains leave core

    Steps 6–8 are gated on 5, which is gated on 4. Nothing in 6–8 can be done earlier without shipping a portal that cannot install the engine it needs.

  9. added 2 commits that reference this issue on Aug 26, 2026
  10. 19 remaining items

  11. rbuergi commented on Aug 27, 2026

    @rbuergi
    ContributorAuthor

    Correction to the 08-26 22:42 note — gate 1 (the 409) is NOT clear on the plugins side

    At MeshWeaver.Plugins main (7edad75a, 2026-08-27) src/Memex.Portal.Gui/Memex.Portal.Gui.csproj:111 carries a live <ProjectReference Include="$(MeshWeaverRoot)/src/MeshWeaver.AI/MeshWeaver.AI.csproj" /> (with using MeshWeaver.AI.Connect; in MemexPortalComposition.cs for IMcpBackConnection, which already lives in MeshWeaver.Mesh.Contract). So the portal image built from plugins DOES ship MeshWeaver.AI.dll in its app closure, and a registry module of that name would 409 on every instance.

    It cannot simply be dropped: FrameworkBuildIdentity.ContentSurfaceAssemblies lists MeshWeaver.AI, and the plugins hosts write their surface manifest from their compile closure — dropping the reference alone makes the portal hash AI as absent while mw-plugin-test (core) still hashes a real surface id: the #1814 identity split. So the Gui reference leaves in the same atomic change as the ContentSurfaceAssemblies entry (and the PluginTester's closure) — item 6 of the step list — not before.

    Context: the storage/transport carve-out landed today (core #2479, #2486, plugins #737, #738; core #2485 deleting the projects is the last piece). Two things from it matter here: (a) the module-pack lane now reads a node repo's src/platform-shipped.txt (projects that live in the node repo but ship in the image are treated as platform by the pack — the mechanism to reuse if AI ever needs an image-lane transition); (b) MeshWeaver.Hosting.Orleans.TestBase is now a shipped src project holding OrleansTestBase & co — the "surgery" for Hosting.Orleans.Test (the ~24 AI-specific classes coming out from under a base that seeds AddAITypes()) now happens in that project, which currently references MeshWeaver.AI for exactly that seeding.

  12. added 2 commits that reference this issue on Aug 27, 2026
  13. rbuergi commented on Aug 27, 2026

    @rbuergi
    ContributorAuthor

    The bake-host blocker is not AI-specific — it gates MeshWeaver.Maps too (measured 2026-08-27)

    Surveying what else can leave core turned up the same structural item from a second direction, worth stating once for the whole programme:

    A project can only leave core while the core bake host can still BUILD it. tools/MeshWeaver.PluginTester compiles core's gated sample content, and #2524's trick — replacing the ProjectReference with a tester-local MeshModuleClosure row — works precisely because src/MeshWeaver.AI is still in core's tree. The moment the source leaves, that row has nothing to build from.

    Maps hits this today. .github/scripts/stage-samples-gate.sh stages samples/Graph/Data/{ACME,Northwind,Cornerstone,…} through the gate, and Cornerstone/Pricing/Source/PricingLayoutAreas.cs makes real symbol use of MapControl / MapMarker. So moving src/MeshWeaver.Maps to plugins breaks the gated core sample — not the identity flip (that part is routine), the build source.

    Consequence for #2276's remaining step: the AI SOURCE move needs the same thing Maps needs — the bake host consuming a plugins-BUILT bundle (registry or CI artifact) rather than building from core source. That is the one genuine design item left in this programme; both moves unblock together, and neither should be attempted before it.

    Measured alongside: what can leave core with no such blocker is MeshWeaver.Speech.Contract, MeshWeaver.Observability.Contract and tools/MeshWeaver.LogWatcher — all outside ContentSurfaceAssemblies, so zero identity consequence. That move is in flight. ContentCollections.Indexing(+.Graph) remains blocked behind AI (AI is one of its four consumers; the residue is a tiny IImageDescriber + DocumentPaths contract). GitSync (6 consumers, takes PluginCatalog's registry half) is the large one after that. MeshWeaver.Cli is a shipped NuGet tool — zero project consumers is expected, it stays.

  14. added 4 commits that reference this issue on Aug 27, 2026
  15. rbuergi commented on Aug 28, 2026

    @rbuergi
    ContributorAuthor

    Status 2026-08-28: the core half is complete — #2588 merged (MeshWeaver.AI + the moved test suites leave core, combining #2568 + #2526 + #2586), on top of the seam PRs already recorded here (#2524 gate-lands-the-engine, #2541, #2547 Speech.Contract + log watcher, #2485/#2501 Orleans test-rig split).

    The remaining leg is MeshWeaver.Plugins#786 ("The AI engine moves in") — open with auto-merge armed at the time of writing. This issue closes when #786 lands; if #786 is merged and something still references the departed trees, that is a new finding, not this program.

  16. rbuergi commented on Aug 28, 2026

    @rbuergi
    ContributorAuthor

    Done. The AI engine has left the platform.

    The two halves, merged today:

    Also true as of today, beyond the letter of this issue:

    Remaining threads are tracked in their own issues: #2584 (fresh-install activation, interim
    cutting now), Systemorph/MeshWeaver.Plugins#977 (Blazor.Portal decoupling end-state), #2593 (voice-model pin eviction).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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