Skip to content

refactor(views): the node-surface view layer leaves the platform for a module - #2678

Merged
rbuergi merged 13 commits into
mainfrom
feat/views-out
Aug 29, 2026
Merged

rbuergi merged 13 commits into
mainfrom
feat/views-out

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Follows the collaboration carve-out (#2660). 52 files, +105 / −8,713 — the node-surface layout areas move out of MeshWeaver.Graph into the MeshWeaver.Graph.Views module (Systemorph/MeshWeaver.Plugins, declared by the pre-installed DefaultViews package).

Paired with Systemorph/MeshWeaver.Plugins#904, which carries the moved code. Core merges first; Plugins main is briefly short the assembly between the two.

The rule this follows

Contract stays, logic leaves. The platform keeps every area-name constant, every NodeMenuItemDefinition the node menu is assembled from, the content deserializers other callers share, and the message handlers. Only rendering moves.

21 view files, ~10.6k lines: access assignments, API tokens, groups, group memberships, mesh data sources, notifications, releases, partition-sync admin, Space, StopSync, Copy, Move, Pin, AccessControl, Groups, Version, Code, Import, Activity, Delete.

Things the compiler found that reading would not have

  • VersionLayoutArea hid two message handlers. HandleRollbackNodeRequest / HandleUndoActivityRequest are registered platform-side and are not views; a line-cut would have relocated them silently.
  • Delete was registered in FOUR places — the default chain, MarkdownLayoutAreas, RedirectNodeType, and MeshWeaver.PluginCatalog. Only a whole-solution build surfaced the fourth. One node-wide registration now replaces all four.
  • WithDefaultArea forced keyed contributions. Every Add{X}Views() sets its type's default area, so a global registration would have made the last one applied the default for EVERY node type — each type opening on some other type's page, with nothing failing to compile.
  • Two private consts would have been left behind as unreachable privates; they belong with the views.

What opened up, and why

BuildAccessDenied, StripLeadingTitleHtml/Markdown, DeserializeAssignment, DeserializeMembership, ShowValidationError, PluginSurfaceProbe — each because both halves genuinely call them. ActivityLayoutAreas.StatusColor went public and then back to internal when its second caller followed it into the module, which is the shape you want.

SettingsLayoutArea no longer CALLS the AccessControl view — it embeds the area by name, so the settings tab knows an area name rather than an implementation.

Registration

Node-wide views use the pattern core already documents for the OgCard module ("registers on every per-node hub"); per-type view sets arrive as node-type-keyed contributions through NodeHubContributions, the seam #2660 introduced.

Verification

Full solution, Release, -warnaserror: 0 warnings, 0 errors, 88 projects, after every increment. Module suite 124 passed, 0 failed. Twelve suites travelled with their subject, including ones from MeshWeaver.Hosting.Monolith.Test and MeshWeaver.PluginCatalog.

🚨 Nothing here renders a page. Compilation and unit tests are the whole of the local signal; the in-mesh compile gates are the real check.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx

rbuergi and others added 10 commits August 29, 2026 11:03
Eight layout-area files (~4.4k lines) move out of MeshWeaver.Graph into the
MeshWeaver.Graph.Views module: access assignments, API tokens, groups, group
memberships, mesh data sources, notifications, releases and the partition-sync
admin tab. A view is the most-changed and least-load-bearing thing in the
platform, and it was pinned where only a platform release could ship a fix.

What stays is the CONTRACT, per the split you asked for: the node types, their
content records, the area-name consts and the NodeMenuItemDefinition
descriptors. Two content helpers — AccessControlLayoutArea.DeserializeAssignment
and GroupsLayoutArea.DeserializeMembership — become public rather than internal:
the deserialization is contract, the rendering that consumed it is not.

The seam is the one the collaboration carve-out introduced, now KEYED BY NODE
TYPE. That is not cosmetic. Every Add{X}Views() sets its type's default area
with WithDefaultArea, so contributing them globally would make the last
registration the default for EVERY node type — each type would open on some
other type's page. Each platform node type now calls
ApplyNodeHubContributions(NodeType); without the module that call is a no-op.

Seven files stay for the next increment because they need SPLITTING, not
moving: Pin/Copy/Move/StopSync/Version carry NodeMenuItemDefinition descriptors
the platform menu builds from, and AccessControl/Groups are called from
MeshNodeLayoutAreas' forwarders.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects emitted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
First of the seven files that need SPLITTING rather than moving. The platform
keeps StopSyncLayoutArea: the area name and the NodeMenuItemDefinition the node
menu is assembled from platform-side. Only the render method and its private
helper move to StopSyncViews in the module.

The registration follows the pattern core already documents two lines above it —
the OgCard module 'registers on every per-node hub' — so no new seam was needed
for a node-wide view.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
…g moves

Same cut as StopSync: the platform keeps each area's name consts and the
NodeMenuItemDefinition the node menu is assembled from; the render methods and
their private helpers move to Copy/Move/PinViews in the module, registered on
every per-node hub the way OgCard already is.

Four of the seven split-needing files are done. The remaining three are not
mechanical: VersionLayoutArea interleaves two views with
HandleRollbackNodeRequest / HandleUndoActivityRequest and stream helpers that
are NOT views, and AccessControl / Groups keep their deserializers plus
ShowAddAssignmentDialog, which UserNodeType calls.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects emitted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
…ndering moves

Six of the seven split-needing files done. These two were not a line cut: their
base members sit BETWEEN the view and its helpers, so the extraction was by
member rather than by offset.

Core keeps, and three of them had to open up because both halves call them:
  - AccessControlLayoutArea: DeserializeAssignment, DeleteAssignment,
    ShowAddAssignmentDialog (UserNodeType calls it) and ShowValidationError,
    which the kept dialog AND the moved views both use;
  - GroupsLayoutArea: DeserializeMembership.

Two forwarders in MeshNodeLayoutAreas are gone with them, and SettingsLayoutArea
no longer CALLS the AccessControl view — it embeds the area by name, the same
shape the inline comments section uses. That is the whole point: the settings
tab knows an area name, not a view implementation.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects emitted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
Both views (Versions, VersionDiff) and their thirteen render helpers move.
The platform keeps what is NOT a view: the menu descriptor, the compare-stream
ids, the content helpers, and — the reason this file needed care — the
RollbackNodeRequest / UndoActivityRequest MESSAGE HANDLERS, which are registered
here and would have been silently relocated by a naive line cut.

PluginSurfaceProbe becomes public: the view modules probe for an installed
package the same way MarkdownOverviewLayoutArea's approvals section does, and a
probe only the platform can call forces every module to hand-roll its own.

All seven split-needing files are now done; the view layer in the module is 15
files. Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects emitted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
CodeLayoutAreas keeps its seventeen area-name constants — NodeTypeLayoutAreas
links them — and every view moves. Two private data-ids moved WITH the views
rather than staying behind as unreachable privates, and ActivityLayoutAreas.
StatusColor became public because the code cell's toolbar chip renders the same
chip and must not fork the palette.

CodeNodeType and ScopeNodeType now admit the code views as a keyed contribution
instead of calling AddCodeViews() directly.

Five suites move with their subject (ActivityProgressView, CodeCellEditor,
CodeCellOwnRun, CodeCellStaleness, ImportLayoutArea). They drive internal view
helpers, so the module grants InternalsVisibleTo to its test project — the same
grant MeshWeaver.Graph.Test had.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects; module suite 64 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
… moves

ActivityLayoutAreas had exactly ONE core consumer (NodeTypeLayoutAreas reads
ProgressArea), so the platform keeps the five area-name constants and all
fifteen members — the four views plus the header/log/status building blocks —
move to ActivityViews.

Measuring that took care: grepping 'ActivityLayoutAreas.' also matches
'UserActivityLayoutAreas.', which made the coupling look 8-consumers deep when
it is one. The precise count is what made this a clean cut instead of a
member-by-member sort.

CodeViews already rendered the same status chip, so its calls follow the helpers
into the module — which also retires the StatusColor I made public last commit;
it is an internal detail of the view layer again, on the right side of the line.

ActivityNodeType admits the views as a keyed contribution. Two more suites
travel with their subject.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects emitted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
…tions

SpaceLayoutAreas (779 loc) had exactly two real code references, both .WithView
registrations in SpaceNodeType; the other three matches were doc prose. So the
whole file moves and SpaceNodeType admits the views as a keyed contribution,
carrying the rule that editing a Space edits its markdown body rather than a
property form.

Three shared view helpers open up because the module renders through them:
MeshNodeLayoutAreas.BuildAccessDenied and OverviewLayoutArea's two
StripLeadingTitle overloads. Three Space suites travel with their subject.

Re-measuring first is what made this a wholesale move rather than a split — the
same lesson as Activity, where a sloppy grep had reported eight consumers for a
file that has one.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects; module suite 104 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
…hree

DeleteLayoutArea keeps its menu descriptor and the QueriesParam const; the view
and its twenty-six helpers move. MaxListedPaths travels with them — it is a
rendering detail, and leaving it behind would have made it an unreachable
private.

The platform registered this same view in FOUR places: the default chain,
MarkdownLayoutAreas, RedirectNodeType and — found only by building the whole
solution — MeshWeaver.PluginCatalog's CatalogLayoutAreas. One node-wide
registration in the module replaces all of them, which is a small
simplification the move surfaced rather than caused.

Three suites travel with their subject, including one from
MeshWeaver.Hosting.Monolith.Test that drove Delete's ancestor-resolution
helpers.

Verified: full solution, Release, -warnaserror — 0 warnings, 0 errors,
88 projects; module suite 124 passed, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
Copilot AI lite review requested due to automatic review settings August 29, 2026 12: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.

Pull request overview

This PR refactors the MeshWeaver.Graph “node-surface” view layer to leave the core platform and be provided by the MeshWeaver.Graph.Views module, keeping platform-side contracts (area-name constants, menu definitions, shared content helpers, and handlers) while removing the rendering implementations and per-type view registrations.

Changes:

  • Removed numerous layout-area view implementations from MeshWeaver.Graph and adjusted hub/layout registration to rely on module-provided registrations via NodeHubContributions.
  • Promoted a small set of shared helpers (e.g., deserializers, string-strippers, probes) to public so the out-of-tree views can reuse them without duplicating logic.
  • Deleted/relocated view-specific unit/integration tests from core (expected to live with the moved view module).

Reviewed changes

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

Show a summary per file
File Description
test/MeshWeaver.Hosting.Monolith.Test/DeleteRedirectToExistingParentTest.cs Removes e2e coverage tied to Delete view implementation now expected to live in the views module.
test/MeshWeaver.Graph.Test/SpaceResolveSpaceTest.cs Removes Space view-specific unit tests that move with the view implementation.
test/MeshWeaver.Graph.Test/SpaceLayoutAreasLogoTest.cs Removes Space logo rendering tests (view behavior moved to module).
test/MeshWeaver.Graph.Test/SpaceDefaultCatalogTest.cs Removes Space default-catalog behavior tests (view behavior moved to module).
test/MeshWeaver.Graph.Test/ImportLayoutAreaTest.cs Removes Import layout-area view tests as Import view leaves core.
test/MeshWeaver.Graph.Test/DeleteQuerySetTest.cs Removes Delete view URL/pure helper coverage that is now module-owned.
test/MeshWeaver.Graph.Test/CodeCellStalenessTest.cs Removes Code view behavior tests moving with module-provided Code views.
test/MeshWeaver.Graph.Test/CodeCellOwnRunTest.cs Removes Code view behavior tests moving with module-provided Code views.
test/MeshWeaver.Graph.Test/CodeCellEditorTest.cs Removes Code editor view tests moving with module-provided Code views.
test/MeshWeaver.Graph.Test/ActivityProgressViewTest.cs Removes Activity view rendering tests moving with module-provided views.
test/MeshWeaver.Graph.Test/ActivityCancelVisibilityTest.cs Removes Activity cancel-visibility view tests moving with module-provided views.
test/MeshWeaver.Graph.Test/AccessAssignmentLayoutAreasTest.cs Removes AccessAssignment view tests moving with module-provided views.
src/MeshWeaver.PluginCatalog/CatalogLayoutAreas.cs Stops re-registering Create/Delete views here; relies on module registrations instead.
src/MeshWeaver.Graph/StopSyncLayoutArea.cs Leaves platform-side contract/menu descriptor; removes the StopSync rendering implementation.
src/MeshWeaver.Graph/SettingsLayoutArea.cs Embeds AccessControl by area name (module-provided implementation) instead of calling a platform view method.
src/MeshWeaver.Graph/ReleaseLayoutAreas.cs Removes Release rendering implementation from core.
src/MeshWeaver.Graph/PluginSurfaceProbe.cs Promotes probe API to public for reuse by view modules.
src/MeshWeaver.Graph/PinLayoutArea.cs Removes Pin/Unpin/PinnedThumbnail view implementations from core, leaving menu descriptors/constants.
src/MeshWeaver.Graph/OverviewLayoutArea.cs Promotes title-stripping helpers to public for reuse by module views.
src/MeshWeaver.Graph/NotificationLayoutAreas.cs Removes Notification view implementations from core.
src/MeshWeaver.Graph/MoveLayoutArea.cs Removes Move rendering implementation from core, leaving menu descriptor/constants.
src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs Removes platform registrations for views that now come from the module; promotes BuildAccessDenied to public for module reuse.
src/MeshWeaver.Graph/MeshDataSourceLayoutAreas.cs Removes MeshDataSource view implementations from core.
src/MeshWeaver.Graph/MarkdownLayoutAreas.cs Stops re-registering Delete in Markdown views; relies on module registrations.
src/MeshWeaver.Graph/IPartitionSyncSourceProvider.cs Updates doc comment to reference module-provided GUI surface.
src/MeshWeaver.Graph/ImportLayoutArea.cs Removes Import view implementation from core, leaving the menu descriptor.
src/MeshWeaver.Graph/GroupsLayoutArea.cs Keeps only the platform-side content helper (membership deserialization) for module views.
src/MeshWeaver.Graph/GroupMembershipLayoutAreas.cs Removes GroupMembership view implementations from core.
src/MeshWeaver.Graph/GroupLayoutAreas.cs Removes Group view implementations from core.
src/MeshWeaver.Graph/CopyLayoutArea.cs Removes Copy rendering implementation from core, leaving menu descriptor/constants.
src/MeshWeaver.Graph/Configuration/UserNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) to pick up module-provided views.
src/MeshWeaver.Graph/Configuration/SpaceNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Space views.
src/MeshWeaver.Graph/Configuration/ScopeNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Code/Scope views.
src/MeshWeaver.Graph/Configuration/ReleaseNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Release views.
src/MeshWeaver.Graph/Configuration/RedirectNodeType.cs Removes Delete registration; relies on module-provided Delete view.
src/MeshWeaver.Graph/Configuration/NotificationNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Notification views.
src/MeshWeaver.Graph/Configuration/MeshDataSourceNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for MeshDataSource views.
src/MeshWeaver.Graph/Configuration/GroupNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Group views.
src/MeshWeaver.Graph/Configuration/GroupMembershipNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for GroupMembership views.
src/MeshWeaver.Graph/Configuration/CodeNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Code views.
src/MeshWeaver.Graph/Configuration/ApiTokenNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for ApiToken views.
src/MeshWeaver.Graph/Configuration/ActivityNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for Activity views.
src/MeshWeaver.Graph/Configuration/AccessAssignmentNodeType.cs Switches to .ApplyNodeHubContributions(NodeType) for AccessAssignment views.
src/MeshWeaver.Graph/ApiTokenLayoutAreas.cs Removes ApiToken view implementations from core.
src/MeshWeaver.Graph/ActivityLayoutAreas.cs Removes Activity view implementations from core, leaving constants expected by module views.
src/MeshWeaver.Graph/AccessControlLayoutArea.cs Keeps platform-side helpers (deserialization, delete, add-assignment dialog) for module views and adjusts visibility.
src/MeshWeaver.Graph/AccessAssignmentLayoutAreas.cs Removes AccessAssignment view implementations from core.
Suppressed comments (2)

src/MeshWeaver.Graph/AccessControlLayoutArea.cs:75

  • ShowAddAssignmentDialog can currently be invoked with an empty/root nodePath, which allows minting a root-scoped AccessAssignment (the interactive UI should not offer this per AccessAssignmentGuard.CanGrantAt) and also produces an invalid access namespace ("/_Access"). Add an explicit guard up front to block the root context before building the form.
    public static void ShowAddAssignmentDialog(UiActionContext ctx, string nodePath)
    {
        var formId = $"add_assignment_{Guid.NewGuid().AsString()}";
        ctx.Host.UpdateData(formId, new Dictionary<string, object?>
        {
            ["accessObject"] = "",
            ["role"] = ""
        });

src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs:315

  • BuildAccessDenied includes several user-visible hard-coded English strings (the explanatory paragraph and the confirmation dialog title/body). These should be localized via keys in strings.{en,de}.json to avoid rendering English for German viewers.
    public static UiControl BuildAccessDenied(string nodePath, string? locale = null)
    {
        var nodeName = nodePath.Split('/').LastOrDefault() ?? nodePath;
        return Controls.Stack.WithWidth("100%").WithStyle("padding: 48px 24px; align-items: center; text-align: center;")
            .WithView(Controls.Icon(FluentIcons.ShieldKeyhole())
                .WithStyle("font-size: 64px; color: var(--neutral-foreground-hint); margin-bottom: 16px;"))
            .WithView(Controls.H2(LocalizationCatalog.Get("error.accessDenied", locale)).WithStyle("margin: 0;"))
            .WithView(Controls.Html(
                $"<p style=\"color: var(--neutral-foreground-hint); max-width: 480px;\">" +
                $"You do not have permission to view <strong>{System.Web.HttpUtility.HtmlEncode(nodeName)}</strong>. " +
                $"Contact the owner to request access.</p>"))
            .WithView(Controls.Button(LocalizationCatalog.Get("ui.requestAccess", locale))
                .WithAppearance(Appearance.Accent)
                .WithIconStart(FluentIcons.PersonAdd())
                .WithClickAction(ctx =>
                {
                    // Show a confirmation that the request was noted
                    var dialog = Controls.Dialog(
                        Controls.Markdown(
                            $"Access request for **{nodeName}** has been noted.\n\n" +
                            "The node owner will be notified."),
                        "Access Requested"
                    ).WithSize("S").WithClosable(true);

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

Comment on lines +182 to 187
public static void ShowValidationError(UiActionContext ctx, string message)
{
var errorDialog = Controls.Dialog(
Controls.Markdown(message),
"Validation Error"
).WithSize("S").WithClosable(true);
@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

689 tests   497 ✅  4m 56s ⏱️
  5 suites  192 💤
  5 files      0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

941 tests   941 ✅  5m 11s ⏱️
  6 suites    0 💤
  6 files      0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

913 tests   913 ✅  5m 29s ⏱️
  6 suites    0 💤
  6 files      0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

   10 files     10 suites   4m 59s ⏱️
3 444 tests 3 444 ✅ 0 💤 0 ❌
4 078 runs  4 078 ✅ 0 💤 0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

1 528 tests   1 528 ✅  6m 18s ⏱️
    8 suites      0 💤
    8 files        0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

788 tests   784 ✅  7m 37s ⏱️
  6 suites    4 💤
  6 files      0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

   41 files     41 suites   34m 34s ⏱️
8 303 tests 8 107 ✅ 196 💤 0 ❌
8 937 runs  8 741 ✅ 196 💤 0 ❌

Results for commit 5c3169a.

♻️ This comment has been updated with latest results.

rbuergi and others added 3 commits August 29, 2026 14:30
CI caught what my local verification structurally could not. These suites render
areas by NAME, not by type reference, so they compiled cleanly against a core
that no longer serves them and failed only at RUNTIME — fifteen tests across
three projects (Hosting.Monolith.Test, AccessControl.Test, Content.Test).

A full solution build plus the module's unit tests can never see this. Only
running core's own suite would have, and I did not — the lesson from the
collaboration half that I failed to carry over.

Moved to the module's test project, where the mesh composes AddGraphViews().

Verified: full solution Release -warnaserror 0/0; module suite 145 passed,
0 failed (was 138/7).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HGrR8eBykEAKSBgtFJo3Hx
…travels too

Shard 5 went red on MeshWeaver.Security.Test with 5 failures, all in
AccessControlLayoutAreaTest. The suite renders MeshNodeLayoutAreas.AccessControlArea
by NAME, so it compiled clean against core and only failed at runtime once
AccessControlViews.AccessControl moved to the MeshWeaver.Graph.Views module.

Same class as the five suites already moved, and the sixth of its kind: a
name-addressed render is invisible to the compiler, so only a run catches it.
Sweeping every core test for the module's full area set (constants AND string
literals) turns up no further renderer -- the other 21 matches reference the
menu DESCRIPTORS, which stay in core, which is why only this shard reddened.

Moves to MeshWeaver.Graph.Views.Test composing .AddGraphViews().
…o moves nothing binds

The only red left on this PR is 'Public surface (binary compatibility)', which Consolidate
folds in ('Fail if the binary-compatibility gate failed'); every test shard is green.

Run with --sibling MeshWeaver.Plugins, the gate itself classifies all nine as PROVEN
CROSS-REPO MOVES into src/MeshWeaver.Graph.Views and states that a forwarder is impossible
here (it would have to live in src/MeshWeaver.Graph and reference an assembly this repo does
not build). Its documented resolution for that case is an allow entry carrying the claim that
no shipped module holds the TypeRef. The evidence for that claim is in the file, gathered
today: org-wide code search, the plugins repo outside the module, four sibling checkouts, and
the fact that in-mesh source addresses areas by NAME — which is exactly why this move compiled
clean and surfaced only in runtime render tests.

Ratchet honoured: these lines are to be DELETED once #2678 ships; a stale entry fails the gate.
rbuergi added a commit that referenced this pull request Aug 30, 2026
 merged (#2783)

`scripts/type-forwards.allow` still lists

    MeshWeaver.Fixture:MeshWeaver.Fixture.ObservableAwait

but #2771 has merged, so that move is IN main. The gate compares against the
MERGE BASE, so relative to any branch cut after #2771 nothing of that name
moves — and the entry is reported as STALE:

    STALE ALLOW ENTRY: scripts/type-forwards.allow lists
    `MeshWeaver.Fixture:MeshWeaver.Fixture.ObservableAwait`,
    but nothing of that name moved in this diff

🚨 That reddens EVERY subsequent PR, not one. Measured: both currently open PRs
fail `Public surface (binary compatibility)` on it — #2782 (a test guard plus an
allow file) and #2781 (a documentation-only Homebrew change). Neither can reach
a public type; both are blocked by main.

This is the failure mode the allow file's own rule names and that #2678 -> #2688
already paid for once: an allow entry goes stale FLEET-WIDE the instant its move
merges, so it must be deleted in the VERY NEXT change. It was flagged on #2771
before that merge and landed with it anyway, which is exactly how the previous
seven stale entries accumulated.

The file now carries no live entries — header only, which is the correct state:
nothing is currently exempt.

Verified:
  scripts/check-type-forwards.py --self-test  -> All 28 self-tests passed
  scripts/check-type-forwards.py --base <merge-base>
                                             -> OK, no unguarded public-type move

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rbuergi
rbuergi deleted the feat/views-out branch October 10, 2026 13:10
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