Repository navigation
A surface says what it is, instead of borrowing a name that filtered right - #2137
Conversation
…right
The home screen listed the platform's own bookkeeping — every NodeType,
ModuleDefinition, Partition and Role registration — next to the viewer's actual
spaces. Those are in-memory declarations contributed by AddMeshNodes so the
platform knows a type exists. They are what a create menu offers. Nobody browses
them.
The cause was a borrowed name. Every browsing surface passed `context:search`:
the home catalog, the first-level union, a node's children list, the recent
lists. None of them are the search box. They said it because `search` was the one
context whose filtering withheld registrations — and each of them then STILL
carried its own patch on top (`-nodeType:NodeType`, `-nodeType:Store/Plugin`),
because a name you don't mean cannot say what you want.
So the surfaces now say what they are: `is:content`, alongside the existing
`is:main`. It withholds registrations, and it IMPLIES `context:content`, which is
what keeps the existing exclusion machinery working — per-node ExcludeFromContext
and, when the marked node is a NodeType definition, per-type, pushed into SQL by
the database providers. An explicit `context:` still wins.
Declaration belongs to whoever owns the thing, not to the surface: MeshNode
carries the mark, and MeshNodeVisibilityExtensions makes it one call —
`.HideFrom(...)`, `.HideFromContent()`, `.HideEverywhere()` — additive and
idempotent, so a module and a deployment can each contribute without silently
dropping the other's. That is the point: a home screen enumerating what to hide
is wrong the moment anyone installs something it has not heard of.
The 52 registration sites that declared {"search"} / {"search","create"} now also
declare "content". That is not new policy — it is the same nodes staying hidden
from the same surfaces, said in the surfaces' own terms. Without it, dropping the
borrowed `context:search` would have REVEALED them.
One list survives, and it is called out where it lives: `-nodeType:Store/Plugin
-nodeType:Store/Catalog` on the content scopes. Those are DYNAMIC node types
living in the Store partition, so marking them is a MeshWeaver.Plugins change
landing after this; deleting the terms first would put every installed plugin's
root back on the content list, duplicating its own app tile.
Content tabs, as asked: All, then Pinned, Mine, Shared. Pinned and Shared stay
conditional — a pin list with no pins and a path union with no paths both match
nothing, and an always-present tab would be an always-empty one. Mine is
unconditional: your own space is the one tab that is never empty for you.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
'let's just put Spaces for shared with me' — the tab answers 'what can I reach that I don't own', and Spaces names that better than describing how it got there. The key already existed in all four catalogs. Pinned and Spaces stay conditional (no pins / no grants ⇒ no tab); Mine is the viewer's own home path and is always there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces an explicit “content browsing” query intent (is:content) so UI browsing surfaces (home catalog, children lists, recent lists, etc.) stop pretending to be context:search just to inherit registration-node filtering. It also centralizes the context names (MeshContexts) and adds fluent helpers (MeshNodeVisibilityExtensions) so modules and deployments can declaratively hide nodes from specific surfaces.
Changes:
- Add
is:contentparsing toQueryParserand thread it throughParsedQuery, defaultingContexttoMeshContexts.Contentwhen appropriate. - Update static-node querying and Graph browsing/home queries to use
is:content(and adjust home tabs to include the new “Mine” tab). - Extend many registration/infrastructure node types’
ExcludeFromContextto include"content"and add localization keys for the new tab (server + React mirror).
Reviewed changes
Copilot reviewed 58 out of 58 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs | Adds coverage for is:content parsing + visibility helpers. |
| test/MeshWeaver.Graph.Test/PresentationSurfacesTest.cs | Updates expected content tab set to include “Mine”. |
| test/MeshWeaver.Graph.Test/HomeTabsTest.cs | Updates home tab expectations and asserts is:content is used. |
| test/MeshWeaver.Graph.Test/HomeCatalogTest.cs | Validates catalog queries use is:content instead of context:search. |
| src/MeshWeaver.PluginCatalog/PluginCatalogConfigurationExtensions.cs | Hides plugin catalog bookkeeping types from "content" context. |
| src/MeshWeaver.Messaging.Hub/Localization/strings.en.json | Adds home.mine (server catalog). |
| src/MeshWeaver.Messaging.Hub/Localization/strings.de.json | Adds home.mine (server catalog). |
| src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs | Parses is:content and implies context:content when not explicitly set. |
| src/MeshWeaver.Mesh.Contract/Query/ParsedQuery.cs | Adds IsContent to the parsed query contract. |
| src/MeshWeaver.Mesh.Contract/MeshNodeVisibilityExtensions.cs | Adds fluent APIs to mark nodes as hidden from contexts. |
| src/MeshWeaver.Mesh.Contract/MeshContexts.cs | Introduces named constants for query visibility contexts, including Content. |
| src/MeshWeaver.InstanceSync/InstanceSyncConfiguration.cs | Hides instance-sync config nodes from "content" context. |
| src/MeshWeaver.Hosting/Persistence/Query/StaticNodeQueryProvider.cs | Suppresses registration/config nodes when is:content is set. |
| src/MeshWeaver.Graph/UserActivityLayoutAreas.cs | Switches home/catalog queries to is:content and adds “Mine” scope. |
| src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs | Switches children catalog query to is:content. |
| src/MeshWeaver.Graph/Configuration/VUserNodeType.cs | Adds "content" exclusion for VUser. |
| src/MeshWeaver.Graph/Configuration/UserNodeType.cs | Adds "content" exclusion for User. |
| src/MeshWeaver.Graph/Configuration/UserActivityNodeType.cs | Adds "content" exclusion for UserActivity. |
| src/MeshWeaver.Graph/Configuration/TrackedChangeNodeType.cs | Adds "content" exclusion for TrackedChange. |
| src/MeshWeaver.Graph/Configuration/TeamsConversationNodeType.cs | Adds "content" exclusion for TeamsConversation. |
| src/MeshWeaver.Graph/Configuration/ScopeNodeType.cs | Adds "content" exclusion for Scope. |
| src/MeshWeaver.Graph/Configuration/ScheduledActionNodeType.cs | Adds "content" exclusion for ScheduledAction. |
| src/MeshWeaver.Graph/Configuration/RoleNodeType.cs | Adds "content" exclusion for Role. |
| src/MeshWeaver.Graph/Configuration/PartitionNodeType.cs | Adds "content" exclusion for Partition. |
| src/MeshWeaver.Graph/Configuration/PartitionAccessPolicyNodeType.cs | Adds "content" exclusion for PartitionAccessPolicy. |
| src/MeshWeaver.Graph/Configuration/NotificationSettingsNodeType.cs | Adds "content" exclusion for NotificationSettings. |
| src/MeshWeaver.Graph/Configuration/NotificationNodeType.cs | Adds "content" exclusion for Notification. |
| src/MeshWeaver.Graph/Configuration/NodeTypeNodeType.cs | Adds "content" exclusion for NodeType definitions. |
| src/MeshWeaver.Graph/Configuration/MeshWeaverInstanceNodeType.cs | Adds "content" exclusion for instance bookkeeping nodes. |
| src/MeshWeaver.Graph/Configuration/MeshDataSourceNodeType.cs | Adds "content" exclusion for MeshDataSource nodes. |
| src/MeshWeaver.Graph/Configuration/LicenseNodeType.cs | Adds "content" exclusion for LicenseAcceptance. |
| src/MeshWeaver.Graph/Configuration/KernelNodeType.cs | Adds "content" exclusion for KernelSession. |
| src/MeshWeaver.Graph/Configuration/InvitationNodeType.cs | Adds "content" exclusion for Invitation. |
| src/MeshWeaver.Graph/Configuration/HomeConfigNodeType.cs | Adds "content" exclusion for Home config nodes. |
| src/MeshWeaver.Graph/Configuration/GroupMembershipNodeType.cs | Adds "content" exclusion for GroupMembership. |
| src/MeshWeaver.Graph/Configuration/GraphSubscriptionNodeType.cs | Adds "content" exclusion for GraphSubscription. |
| src/MeshWeaver.Graph/Configuration/GlobalSettingsNodeType.cs | Adds "content" exclusion for Global settings nodes. |
| src/MeshWeaver.Graph/Configuration/EventSubscriptionNodeType.cs | Adds "content" exclusion for EventSubscription. |
| src/MeshWeaver.Graph/Configuration/EmailNodeType.cs | Adds "content" exclusion for Email. |
| src/MeshWeaver.Graph/Configuration/EaCredentialNodeType.cs | Adds "content" exclusion for EA Credential. |
| src/MeshWeaver.Graph/Configuration/CompletionMemoryNodeType.cs | Adds "content" exclusion for CompletionMemory. |
| src/MeshWeaver.Graph/Configuration/CodeNodeType.cs | Adds "content" exclusion for Code. |
| src/MeshWeaver.Graph/Configuration/AppNodeType.cs | Adds "content" exclusion for Installed App nodes. |
| src/MeshWeaver.Graph/Configuration/ApiTokenNodeType.cs | Adds "content" exclusion for ApiToken. |
| src/MeshWeaver.Graph/Configuration/ActivityNodeType.cs | Adds "content" exclusion for Activity. |
| src/MeshWeaver.Graph/Configuration/ActivityLogSegmentNodeType.cs | Adds "content" exclusion for ActivityLogSegment. |
| src/MeshWeaver.Graph/Configuration/AccessAssignmentNodeType.cs | Adds "content" exclusion for AccessAssignment. |
| src/MeshWeaver.Graph/CommentNodeType.cs | Adds "content" exclusion for Comment. |
| src/MeshWeaver.GitSync/GitHubSyncConfiguration.cs | Adds "content" exclusion for GitSync bookkeeping nodes. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-24-content-visibility.md | Adds a “What’s New” entry documenting the behavior change. |
| src/MeshWeaver.Blazor.Portal/PortalNodeType.cs | Adds "content" exclusion for PortalSession. |
| src/MeshWeaver.AI/TokenUsage.cs | Adds "content" exclusion for TokenUsage. |
| src/MeshWeaver.AI/ThreadComposerNodeType.cs | Adds "content" exclusion for ThreadComposer. |
| src/MeshWeaver.AI/ModelTierNodeType.cs | Adds "content" exclusion for ModelTierDefinition. |
| src/MeshWeaver.AI/ModelProviderNodeType.cs | Adds "content" exclusion for model provider nodes. |
| src/MeshWeaver.AI/AiSettingsNodeType.cs | Adds "content" exclusion for AI settings nodes. |
| clients/react/src/i18n/strings.en.json | Adds home.mine to React mirror catalog. |
| clients/react/src/i18n/strings.de.json | Adds home.mine to React mirror catalog. |
Suppressed comments (7)
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:35
- This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:42 - This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:52 - This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:60 - This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:74 - This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:85 - This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
test/MeshWeaver.Hosting.Test/ContentContextQueryTest.cs:92 - This test uses FluentAssertions (the
.Should()extension) butMeshWeaver.Hosting.Testdoes not reference FluentAssertions, so this will not compile. Use xUnitAssertAPIs instead.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
HideFromContent() takes no arguments — the example showed it taking node names, which is exactly the kind of snippet someone pastes and then has to debug. It now shows the real shape: one call, on the node. The other review point on this PR is wrong: MeshWeaver.Hosting.Test does have the .Should() assertions (global usings), and the file builds clean under -c Release -warnaserror with all 7 of its tests green. No change there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Test Results (shard 2)3 305 tests +7 3 305 ✅ +7 8m 17s ⏱️ +33s Results for commit 9d4d090. ± Comparison against base commit 10db821. This pull request removes 1 and adds 8 tests. Note that renamed tests count towards both. |
Test Results 55 files ± 0 55 suites ±0 54m 14s ⏱️ + 2m 53s Results for commit 9d4d090. ± Comparison against base commit 10db821. This pull request removes 1 and adds 22 tests. Note that renamed tests count towards both. |
The home screen listed the platform's own bookkeeping — every
NodeType,ModuleDefinition,PartitionandRoleregistration — next to the viewer's actual spaces. Those are in-memory declarationsAddMeshNodescontributes so the platform knows a type exists. They are what a create menu offers. Nobody browses them.The cause was a borrowed name
Every browsing surface passed
context:search: the home catalog, the first-level union, a node's children list, the recent lists. None of them are the search box. They said it becausesearchwas the one context whose filtering withheld registrations — and each of them then still carried its own patch on top (-nodeType:NodeType,-nodeType:Store/Plugin), because a name you don't mean cannot say what you want.What changed
Surfaces say what they are. New query term
is:content, alongside the existingis:main. It withholds registration nodes, and it impliescontext:content— which is what keeps the existing exclusion machinery working unchanged: per-nodeExcludeFromContext, and per-type when the marked node is a NodeType definition, pushed into SQL by the database providers. An explicitcontext:still wins.Declaration belongs to whoever owns the thing, not to the surface.
MeshNodecarries the mark;MeshNodeVisibilityExtensionsmakes it one call:.HideFrom(...)/.HideFromContent()/.HideEverywhere()are additive and idempotent, so a module and a deployment can each contribute without silently dropping the other's. That is the whole point: a home screen that enumerates what to hide is wrong the moment anyone installs something it has not heard of.The 52 sites that declared
{"search"}/{"search","create"}now also declare"content". This is not new policy — it is the same nodes staying hidden from the same surfaces, said in the surfaces' own terms. Without it, dropping the borrowedcontext:searchwould have revealed them. (NodeTypeNodeTypeis the one that proves the point: the children list carried-nodeType:NodeTypeprecisely because its{"search"}mark didn't cover that surface. That patch is now gone.)Sites declaring only
{"create"}(Release, Build) are deliberately untouched — they were always visible to browse and search, and still are.The one list that survives
-nodeType:Store/Plugin -nodeType:Store/Catalogon the content scopes, with a comment saying why it is still there: those are dynamic node types living in the Store partition, so marking them is aMeshWeaver.Pluginschange landing after this. Deleting the terms first would put every installed plugin's root back on the content list, duplicating its own app tile. Same forHosting, which is aStore/Plugininstance.Content tabs
All, then Pinned, Mine, Shared. Pinned and Shared stay conditional — a pin list with no pins and a path union with no paths both match nothing, so an always-present tab would be an always-empty one. Mine is unconditional: your own space is the one tab that is never empty for you. New
home.minekey in both server catalogs and theclients/reactmirror the drift guard checks.Tests
ContentContextQueryTest(7) —is:contentsets the flag and implies the context; an explicit context wins; a query that doesn't say it is untouched;HideFromis additive and idempotent across two declarers.HomeTabsTest/PresentationSurfacesTest/HomeCatalogTestupdated to the new tab set and the honest context name. FullMeshWeaver.Graph.Test: 1544 tests, green. Release-warnaserrorclean across Mesh.Contract, Hosting, Graph, AI.Follow-ups, not in this PR: marking
Store/Plugin,Store/Catalog,PostandEventin the repos/mesh that own them (one.HideFromContent()each).