Skip to content

Lift the non-visual portal infrastructure out of MeshWeaver.Blazor - #2285

Merged
rbuergi merged 12 commits into
mainfrom
refactor/lift-nonvisual-infrastructure-out-of-blazor
Aug 26, 2026
Merged

rbuergi merged 12 commits into
mainfrom
refactor/lift-nonvisual-infrastructure-out-of-blazor

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Unblocks removing GUI from core. The blocker turned out to be a mislabelled layer, not volume.

What was in the way

MeshWeaver.Blazor/Infrastructure/ holds eight files that are not views:

ArticleExtensions   CircuitContextAccessor   MeshUserProjection   NonfileRouteConstraint
PortalApplication   PortalErrorSink          UserContextMiddleware  UserIdentityCache

Not one of them imports MeshWeaver.Blazor or Microsoft.AspNetCore.Components — they were
already Blazor-free and merely lived in the UI project. Meanwhile 12 core files and 12 core test
projects
import that namespace, so deleting the Blazor project would take core's own middleware
and caches with it.

The move

They go to MeshWeaver.Hosting.AspNetCore/Portal/, where ASP.NET middleware belongs, with
namespaces that stop claiming to be Blazor. Because the files were already Blazor-free the move is
pure — no code changes — and it costs exactly three project references:

reference needed by
ContentCollections ArticleExtensions
Layout PortalErrorSink
Markdown.Export.Contract PortalApplication

PortalApplication stays in src/ with the middleware that consumes it. My first attempt put it in
memex/Memex.Portal.Shared and the compiler rejected it: UserContextMiddleware uses it, and
src/ cannot reference memex/.

MeshWeaver.Blazor now references MeshWeaver.Hosting.AspNetCore rather than owning this code —
UI depends on hosting, never the reverse.

Verification

CI's flags (-c Release -warnaserror), all 0 warnings / 0 errors:

Hosting.AspNetCore · Blazor · Blazor.Portal · Hosting.Blazor · Memex.Portal.Shared
Hosting.Blazor.Test · Hosting.PostgreSql.Test · Hosting.Monolith.Test · Memex.Portal.Shared.Test

The InternalsVisibleTo hazard was checked rather than hoped: MeshWeaver.Blazor grants IVT to
three assemblies and the new home to one — which is exactly how MeshWeaver.OgCard.Test silently
lost CS1729 when it moved out. Only PortalErrorSink declares anything internal, and every
consumer compiles.

No What's New entry: internal restructuring, no user-visible change.

Removing GUI from core is blocked by a mislabelled layer, not by volume.
MeshWeaver.Blazor/Infrastructure holds eight files that are NOT views:
ArticleExtensions, CircuitContextAccessor, MeshUserProjection,
NonfileRouteConstraint, PortalApplication, PortalErrorSink,
UserContextMiddleware, UserIdentityCache.

Not one of them imports MeshWeaver.Blazor or Microsoft.AspNetCore.Components —
they were already Blazor-free and merely LIVED in the UI project. Meanwhile 12
core files and 12 core test projects import that namespace, so deleting the
Blazor project would take core's own middleware and caches with it.

They move to MeshWeaver.Hosting.AspNetCore/Portal/, which is where ASP.NET
middleware belongs, with namespaces that stop claiming to be Blazor. Because
the files were already Blazor-free the move is pure: no code changes, and it
costs exactly three project references — ContentCollections (ArticleExtensions),
Layout (PortalErrorSink) and Markdown.Export.Contract (PortalApplication).

PortalApplication stays in src/ with the middleware that uses it. The first
attempt put it in memex/Memex.Portal.Shared and the compiler rejected it:
UserContextMiddleware consumes it, and src/ cannot reference memex/.

MeshWeaver.Blazor now references MeshWeaver.Hosting.AspNetCore rather than
owning this code — UI depends on hosting, never the reverse.

Verified with CI's flags (-c Release -warnaserror), all 0/0:
  Hosting.AspNetCore · Blazor · Blazor.Portal · Hosting.Blazor · Portal.Shared
  Hosting.Blazor.Test · Hosting.PostgreSql.Test · Hosting.Monolith.Test
  Memex.Portal.Shared.Test

The InternalsVisibleTo hazard was checked rather than hoped: MeshWeaver.Blazor
grants IVT to three assemblies and the new home to one, which is how
MeshWeaver.OgCard.Test silently lost CS1729 when it moved. Only PortalErrorSink
declares anything internal and every consumer compiles.

No What's New entry: internal restructuring, no user-visible change.
Copilot AI lite review requested due to automatic review settings August 25, 2026 21:27

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.

Pull request overview

This PR relocates non-visual “portal infrastructure” types (middleware, caches, accessors, routing constraint) out of MeshWeaver.Blazor into MeshWeaver.Hosting.AspNetCore/Portal, so core/hosting can depend on them without taking a UI/Blazor assembly dependency.

Changes:

  • Moved portal infrastructure types to MeshWeaver.Hosting.AspNetCore.Portal and updated namespaces/usings across src/, memex/, and tests.
  • Updated MeshWeaver.Hosting.AspNetCore and MeshWeaver.Blazor project references to reflect the new ownership direction (UI → hosting).
  • Updated doc comments and fully-qualified type references where they mentioned the old namespace.

Reviewed changes

Copilot reviewed 51 out of 51 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/MeshWeaver.Security.Test/AuthBootstrapIdentityLatchTest.cs Update using from MeshWeaver.Blazor.Infrastructure to MeshWeaver.Hosting.AspNetCore.Portal.
test/MeshWeaver.Hosting.PostgreSql.Test/UserDirectoryCompletenessTests.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Monolith.Test/UserDirectoryContentShapeTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Monolith.Test/NodeTypeDeclarationSelfTypingTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/UserIdentityLookupClassifierTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/UserContextMiddlewareExclusionTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/ResolveHttpCallerTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/PortalErrorPopupTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/NonfileRouteConstraintTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/NavigationServiceTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/NavigationProgressTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/DegradedCircuitIdentityRecoveryTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/CatchAllPageRoutingTest.cs Update using to the new portal namespace.
test/MeshWeaver.Hosting.Blazor.Test/AnonymousCircuitLocaleSeedTest.cs Update using to the new portal namespace.
test/Memex.Portal.Shared.Test/EaConnectRouteTest.cs Update using to the new portal namespace.
src/MeshWeaver.Hosting.Blazor/NavigationService.cs Update using to the new portal namespace.
src/MeshWeaver.Hosting.Blazor/CircuitAccessHandler.cs Update namespace references in XML docs and type/service references to the new portal namespace.
src/MeshWeaver.Hosting.Blazor/BlazorHostingExtensions.cs Update using to the new portal namespace.
src/MeshWeaver.Hosting.AspNetCore/Portal/UserIdentityCache.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/UserContextMiddleware.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/PortalErrorSink.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/PortalApplication.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/NonfileRouteConstraint.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/MeshUserProjection.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/CircuitContextAccessor.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/Portal/ArticleExtensions.cs Change namespace to MeshWeaver.Hosting.AspNetCore.Portal.
src/MeshWeaver.Hosting.AspNetCore/MeshWeaver.Hosting.AspNetCore.csproj Add project references needed by moved portal infrastructure.
src/MeshWeaver.Blazor/Services/BlazorAutocompleteService.cs Update using to the new portal namespace.
src/MeshWeaver.Blazor/Pages/ContentPage.razor.cs Update using to the new portal namespace.
src/MeshWeaver.Blazor/Pages/ArticlesCatalogPage.razor Update @using to the new portal namespace.
src/MeshWeaver.Blazor/Pages/ArticlePage.razor Update @using to the new portal namespace.
src/MeshWeaver.Blazor/MeshWeaver.Blazor.csproj Add reference to MeshWeaver.Hosting.AspNetCore so UI consumes hosting-owned portal infrastructure.
src/MeshWeaver.Blazor/BlazorView.razor.cs Update using to the new portal namespace.
src/MeshWeaver.Blazor.Portal/Layout/PortalLayoutBase.razor.cs Update using to the new portal namespace.
src/MeshWeaver.Blazor.Portal/Infrastructure/VUserHelper.cs Update using to the new portal namespace.
src/MeshWeaver.Blazor.Portal/Components/UserProfile.razor.cs Update using to the new portal namespace.
src/MeshWeaver.Blazor.Portal/Components/PortalErrorModal.razor Update injected PortalErrorSink type to the new namespace.
src/MeshWeaver.Blazor.Portal/Chat/ThreadChatView.razor.cs Update service resolve of PortalErrorSink to the new namespace.
memex/Memex.Portal.Shared/Social/GitHubConnectEndpoints.cs Update using comment/import for PortalApplication to new namespace.
memex/Memex.Portal.Shared/Skills/AgentSkillSyncService.cs Update using to the new portal namespace.
memex/Memex.Portal.Shared/Pages/Onboarding.razor Update @using to the new portal namespace.
memex/Memex.Portal.Shared/MemexConfiguration.cs Update using to the new portal namespace.
memex/Memex.Portal.Shared/Layout/MemexMobileMenu.razor Update @using to the new portal namespace.
memex/Memex.Portal.Shared/Email/OutboundEmailSender.cs Update using to the new portal namespace.
memex/Memex.Portal.Shared/Email/InvitationEmailSender.cs Update using to the new portal namespace.
memex/Memex.Portal.Shared/Authentication/VirtualUserMiddleware.cs Update using to the new portal namespace.
memex/Memex.Portal.Shared/Authentication/OnboardingMiddleware.cs Update using to the new portal namespace.
memex/Memex.Portal.Shared/Authentication/OAuthConnectController.cs Update using comment/import for PortalApplication to new namespace.
memex/Memex.Portal.Shared/Authentication/EaGraphAuth.cs Update using comment/import for PortalApplication to new namespace.
memex/Memex.Portal.Shared/Authentication/ApiTokenController.cs Update using comment/import for PortalApplication to new namespace.
memex/Memex.Portal.Shared/Api/MeshApiEndpoints.cs Update using comment/import for PortalApplication to new namespace.

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

Comment thread src/MeshWeaver.Hosting.AspNetCore/MeshWeaver.Hosting.AspNetCore.csproj Outdated
MeshWeaver.Blazor.Portal carries the same mislabelling MeshWeaver.Blazor did:
an Authentication/ and Infrastructure/ of plain services, none of which import
any Blazor view type. Core code depends on two of them:

  AuthenticationOptions  <- Memex.Portal.Shared/Authentication/ExternalAuthController
  VUserHelper            <- Memex.Portal.Shared/Authentication/VirtualUserMiddleware
                            AND src/MeshWeaver.Hosting/Persistence/PersistenceExtensions

I first lifted seven, then checked each file's real consumers and put five back.
AuthenticationBuilderExtensions, AuthenticationNavigation{Service,Extensions},
IAuthenticationNavigationService and StylesConfiguration are consumed only by
MemexConfiguration and by views — all of which move out — so lifting them would
have dragged AspNet.Security.OAuth.Apple (and transitively OpenIdConnect and
IdentityModel) into the ASP.NET hosting layer to serve nobody who stays.

That is the discipline this whole refactor turns on: lift what the platform
needs, not what happens to sit in the same folder.

Verified with CI's flags, 0/0: Hosting.AspNetCore, Blazor.Portal, Hosting.
The blanket namespace rewrite was too eager in three places:

  VirtualUserMiddleware  duplicated a using (CS0105)
  Login.razor            lost the VIEW namespace when IAuthenticationNavigationService
                         went back to Blazor.Portal
  MemexConfiguration     same, for AuthenticationBuilderExtensions and
                         AddAuthenticationNavigation

All three need BOTH namespaces now: the two services that stayed lifted
(AuthenticationOptions, VUserHelper) and the five that went back to the views.

🚨 Caught only because the build's exit code was checked. An earlier run of the
#2245 ratchet reported "Passed! 2 tests" while the build had exited 1 — the test
ran against a stale DLL and proved nothing. Re-verified properly:
build exit=0 / 0 Error(s), THEN NodeTypeDeclarationSelfTypingTest 2/2 passed.

That ratchet guards a defect measured at 3.2 failures/second on every serving
pod (a NodeType declaration filed under the type it declares, so it matched every
nodeType:User query). It stays in core and still runs; the lift only rewrote its
using.
@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    55 files  ±0      55 suites  ±0   56m 19s ⏱️ -58s
11 722 tests ±0  11 417 ✅ ±0  305 💤 ±0  0 ❌ ±0 
12 267 runs  ±0  11 962 ✅ ±0  305 💤 ±0  0 ❌ ±0 

Results for commit 22f92cf. ± Comparison against base commit 3b39c4f.

♻️ This comment has been updated with latest results.

Review caught it: the note claimed 'these two references are the only ones the
move adds' while the project adds three. Markdown.Export.Contract went in later,
for PortalApplication, and I did not update the sentence above it.

A dependency note that undercounts is worse than none — it is exactly what a
future audit would trust instead of reading the list.
The over-lift correction put AuthenticationBuilderExtensions back into
MeshWeaver.Blazor.Portal.Authentication, but the blanket namespace rewrite had
already repointed this consumer at the lifted namespace — so it referenced a
type that is no longer there.

Caught by CI's clean build, not locally: this project was not in the set I
rebuilt after the correction. Swept the other four returned types the same way
and this was the only consumer left stale.

Verified: Memex.Portal.Shared.Test builds 0 errors under -warnaserror.
@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

2 122 tests  ±0   1 822 ✅ ±0   12m 10s ⏱️ + 1m 40s
    9 suites ±0     300 💤 ±0 
    9 files   ±0       0 ❌ ±0 

Results for commit 22f92cf. ± Comparison against base commit 3b39c4f.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

   10 files  ±0     10 suites  ±0   7m 11s ⏱️ +21s
1 310 tests ±0  1 309 ✅ ±0  1 💤 ±0  0 ❌ ±0 
1 311 runs  ±0  1 310 ✅ ±0  1 💤 ±0  0 ❌ ±0 

Results for commit 22f92cf. ± Comparison against base commit 3b39c4f.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

1 206 tests   1 206 ✅  12m 22s ⏱️
    9 suites      0 💤
    9 files        0 ❌

Results for commit 22f92cf.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

    9 files  ±0      9 suites  ±0   5m 32s ⏱️ -53s
1 827 tests ±0  1 823 ✅ ±0  4 💤 ±0  0 ❌ ±0 
2 371 runs  ±0  2 367 ✅ ±0  4 💤 ±0  0 ❌ ±0 

Results for commit 22f92cf. ± Comparison against base commit 3b39c4f.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 819 tests  ±0   1 819 ✅ ±0   9m 22s ⏱️ ±0s
   10 suites ±0       0 💤 ±0 
   10 files   ±0       0 ❌ ±0 

Results for commit 22f92cf. ± Comparison against base commit 3b39c4f.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

3 438 tests  ±0   3 438 ✅ ±0   9m 39s ⏱️ -4s
    8 suites ±0       0 💤 ±0 
    8 files   ±0       0 ❌ ±0 

Results for commit 22f92cf. ± Comparison against base commit 3b39c4f.

♻️ This comment has been updated with latest results.

The gate builds MeshWeaver.Plugins' src against this PR, and twelve of its
modules referenced the PLATFORM's MeshWeaver.Blazor through $(MeshWeaverRoot) —
so this lift removed Infrastructure/ out from under them and they lost even the
transitive types (MeshNodeProviderAttribute, MessageHubConfiguration,
MeshWeaver.Layout, MeshWeaver.Messaging).

Plugins#688 points them at that repo's OWN copy, which it has carried all along.
Empty commit purely to re-run the gate against it.

Worth noting the gate did exactly its job: a platform change breaking the
plugins repo failed the PLATFORM's PR, before merge, instead of surfacing there
hours later. That is the property #2277 just widened from two packages to all 53.
…al-infrastructure-out-of-blazor

# Conflicts:
#	memex/Memex.Portal.Shared/Authentication/EaGraphAuth.cs
@rbuergi
rbuergi merged commit dbdbebc into main Aug 26, 2026
27 checks passed
@rbuergi
rbuergi deleted the refactor/lift-nonvisual-infrastructure-out-of-blazor branch August 28, 2026 08:56
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