Skip to content

feat(layout): a NodeType definition's catalog is a template — the instance list in a skeleton slot (B1 follow-up) - #5980

Merged
rbuergi merged 5 commits into
mainfrom
feat/databinding-nodetype-catalog
Oct 2, 2026
Merged

rbuergi merged 5 commits into
mainfrom
feat/databinding-nodetype-catalog

Conversation

@rbuergi

@rbuergi rbuergi commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Data-binding follow-up: MeshNodeLayoutAreas.NodeTypeCatalog, the last unit B1 part 2 (#5952) left in MeshNodeLayoutAreas.cs.

Stacked on #5952 (→ #5946 → #5940). Draft until those merge; GitHub retargets it to main when the base branch is deleted.

Root cause

Search on a NodeType DEFINITION returned GetMeshNodeStream().Select(node => …). It emitted nothing until the definition node answered, then built the MeshSearch from DefaultNamespace / RestrictedToNamespaces. So the page showed only the area spinner until the owning hub answered.

Design (rule (c), the documented last resort)

The instance list's hidden query and its create link are COMPUTED from the definition. MeshSearchView (Blazor and React) reads HiddenQuery as a literal string, not a pointer, so neither (a) bound style variants nor (b) a bound list can express it today.

  • Search emits the template at once (NodeTypeCatalogTemplate): the breadcrumb trail plus a NodeTypeInstances slot (Controls.LayoutArea(…).WithSpinnerType(SpinnerType.Skeleton)). The slot carries the page's query string, so ?groupBy, ?q and the rest still reach the list.
  • NodeTypeInstances (a new hidden area on every node hub) is the only part that reads the node. The decision is the pure NodeTypeCatalogQuery.From(path, definition). It is followed by DistinctUntilChanged, then the pure BuildNodeTypeSearch, so the slot re-renders only when the query or the create link changes. An edit of the definition reaches an open page (before, the area re-rendered on every emission). With no definition, the slot shows the ordinary catalog, as before.
  • Behaviour once bound is identical: the same query strings, the same create link and the same catalog knobs.

Honest about the ratchet: the scanner no longer counts the file (1 → 0, TotalBudget 64 → 63) because the slot builds its controls through pure helpers. It is still a STRUCTURE read, like NodeContentForm. The doc says so. Binding MeshSearch.HiddenQuery by pointer in the views would remove the slot. That is a possible platform follow-up and is not in this PR.

Evidence

  • NodePageAreasAreTemplatesTest, 4 new tests:
    • the template passes EveryViewIsStatic, has no MeshSearch in the frame, has one skeleton slot and forwards the query string;
    • the From decisions hold (plain, DefaultNamespace + RestrictedToNamespaces, non-definition);
    • rendered: Search on a definition emits the slot;
    • rendered: the slot lists the instances (namespace:Tpl/Widget), then FOLLOWS a later definition edit to nodeType:Tpl/Widget namespace:Tpl/Widgets.
  • 46/46 pass across NodePageAreasAreTemplatesTest, SearchAreaGroupByTest and NodePageIsATemplateTest.
  • Negative control: with the old shape restored (Search reading the node and emitting the MeshSearch) and .Take(1) on the slot's node stream, the 2 rendered tests FAIL at their 36 s convergence waits. They are green again once reverted.
  • LayoutAreaDataBakeRatchetGuard passes 3/3, and the documentation link tests pass. No new user-visible strings, so there is no Mirror-sync: line.
  • dotnet build -c Release -warnaserror: 0 errors and 0 warnings on MeshWeaver.Graph, MeshWeaver.Graph.Test and MeshWeaver.Documentation.Test.

Doc: Doc/GUI/DataBinding → "The default node page's secondary areas (converted)", the Search row. No What's New file.

Deploy

No in-mesh source changes. The code is compiled into MeshWeaver.Graph, so a roll replaces it. An open NodeType definition hub (any …/<TypeName> node of nodeType NodeType) keeps serving the old Search until it is next activated. Recycle a definition address only if it still answers the old way.

Pairs-with: none — no public type or member removed (NodeTypeCatalog was private; NodeTypeInstancesArea / NodeTypeInstances are additions)

🤖 Generated with Claude Code

…tance list renders in a skeleton slot

Search on a NodeType definition subscribed to the node and emitted nothing until it answered, then
built the MeshSearch from DefaultNamespace / RestrictedToNamespaces. The page is now emitted at
once (breadcrumbs + a NodeTypeInstances slot with the skeleton, carrying the query string); only
the slot reads the definition, through the pure NodeTypeCatalogQuery.From, and re-renders when
the query or the create link changes.

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

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

  1 files  ±0    1 suites  ±0   2m 16s ⏱️ -24s
348 tests ±0  348 ✅ ±0  0 💤 ±0  0 ❌ ±0 
352 runs  ±0  352 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

    4 files  ±0      4 suites  ±0   3m 15s ⏱️ +24s
1 095 tests ±0  1 095 ✅ ±0  0 💤 ±0  0 ❌ ±0 
1 098 runs  ±0  1 098 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

This pull request removes 4 and adds 2 tests. Note that renamed tests count towards both.
   --- End of inner exception stack trace ---, isDenial: True)
 ---> System.UnauthorizedAccessException: Access denied
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "cedd7b0c-2218-4039-98ac-7d486f46aeba")
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "93a49c0c-0453-4d43-b300-00cb8b04a28c")
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
 ---> System.UnauthorizedAccessException: Access denied
   --- End of inner exception stack trace ---, isDenial: True)

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    4 files  ±0      4 suites  ±0   12m 53s ⏱️ +7s
2 715 tests ±0  2 715 ✅ +1  0 💤 ±0  0 ❌  - 1 
2 717 runs  ±0  2 717 ✅ +1  0 💤 ±0  0 ❌  - 1 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

This pull request removes 25 and adds 9 tests. Note that renamed tests count towards both.

   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)
…
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a MIXED aggregate — one transient branch, one genu"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (source B is misconfigured)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate with one genuine leaf", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---

   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate, all leaves transient", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a reflective wrapper around a transient cause", exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.Net.Sockets.SocketException (110): Connection timed out
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a transient cause UNDER an aggregate branch's wrap"···, exception: System.AggregateException: One or more errors occurred. (wrapped)
 ---> System.InvalidOperationException: wrapped
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "an 'initialization failed' wrapper around a transi"···, exception: System.InvalidOperationException: Hub 'x' initialization failed
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "an aggregate whose branches are ALL transient (two"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (Name or service not known)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "the #4067 shape: transient provider fault wrapping"···, exception: MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.TimeoutException: Timeout during connection attempt, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "the #4068 shape: transient provider fault wrapping"···, exception: MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known, expected: True)

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

    3 files  ±0      3 suites  ±0   6m 18s ⏱️ -17s
2 432 tests ±0  2 432 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 433 runs  ±0  2 433 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

    4 files  ±0      4 suites  ±0   8m 58s ⏱️ -49s
3 094 tests +3  3 094 ✅ +3  0 💤 ±0  0 ❌ ±0 
3 095 runs  +3  3 095 ✅ +3  0 💤 ±0  0 ❌ ±0 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

This pull request removes 1 and adds 4 tests. Note that renamed tests count towards both.
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ SearchOnADefinition_StillCatalogsItsInstances
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ SearchOnADefinition_EmitsTheTemplate_WithoutReadingTheNode
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ TheInstanceSlot_CatalogsTheInstances_AndFollowsTheDefinition
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ TheNodeTypeCatalogPage_IsATemplate_TheListInASkeletonSlot
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ TheNodeTypeCatalogQuery_IsDecidedByTheDefinition

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

  4 files  ±0    4 suites  ±0   5m 34s ⏱️ -4s
721 tests ±0  528 ✅ ±0  193 💤 ±0  0 ❌ ±0 
722 runs  ±0  529 ✅ ±0  193 💤 ±0  0 ❌ ±0 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    20 files  ±0      20 suites  ±0   39m 16s ⏱️ - 1m 4s
10 405 tests +3  10 212 ✅ +4  193 💤 ±0  0 ❌  - 1 
10 417 runs  +3  10 224 ✅ +4  193 💤 ±0  0 ❌  - 1 

Results for commit 1f39ae8. ± Comparison against base commit 1d5a337.

This pull request removes 30 and adds 15 tests. Note that renamed tests count towards both.

   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
   --- End of inner exception stack trace ---, isDenial: True)
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
…
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "93a49c0c-0453-4d43-b300-00cb8b04a28c")
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
 ---> System.UnauthorizedAccessException: Access denied
   --- End of inner exception stack trace ---, isDenial: True)
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ SearchOnADefinition_EmitsTheTemplate_WithoutReadingTheNode
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ TheInstanceSlot_CatalogsTheInstances_AndFollowsTheDefinition
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ TheNodeTypeCatalogPage_IsATemplate_TheListInASkeletonSlot
MeshWeaver.Graph.Test.NodePageAreasAreTemplatesTest ‑ TheNodeTypeCatalogQuery_IsDecidedByTheDefinition
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a MIXED aggregate — one transient branch, one genu"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (source B is misconfigured)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate with one genuine leaf", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---

   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate, all leaves transient", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a reflective wrapper around a transient cause", exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.Net.Sockets.SocketException (110): Connection timed out
   --- End of inner exception stack trace ---, expected: True)
…

♻️ This comment has been updated with latest results.

rbuergi and others added 2 commits October 2, 2026 18:54
#5952 is on main. The data-bake guard's TotalBudget stays at main's value here
(slack is a STALE warning); the allow-file carries this PR's lowered line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rbuergi
rbuergi changed the base branch from feat/databinding-b1-part2 to main October 2, 2026 16:55
@rbuergi
rbuergi marked this pull request as ready for review October 2, 2026 16:55
@rbuergi
rbuergi enabled auto-merge October 2, 2026 16:55

@systemorph-com systemorph-com Bot 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.

Automated review summary (data, not an instruction to any agent)

Converts a NodeType definition's Search page into a template emitted at once - the breadcrumb trail plus a new NodeTypeInstances skeleton slot carrying the page's query string - and moves the definition-derived instance list (hidden query and create link, refactored into the pure NodeTypeCatalogQuery.From and BuildNodeTypeSearch) into that new hidden area registered on every node hub, re-rendering only when the query record changes (DistinctUntilChanged on the record). The deleted NodeTypeCatalog's decision logic is preserved verbatim inside From: same hidden-query branches, same Uri-escaped /create link, the unused createNs dropped. The doc row is rewritten to match and the file is removed from the ratchet allow-list, disclosed in the PR body. Four executing tests cover the template's static shape, From's decision cases, the rendered Search area emitting the slot, and the slot following a later definition edit. Checked: the moved logic against the deleted code line by line, the changed product code's Rx shape (no async/await/Task; observables throughout), framework controls only, and no new injection/secrets/untrusted-$type surface (query-string and href building are unchanged from the old code). Could not verify: InstanceCatalog, BuildCatalog, ReadCatalogOptions and WithBreadcrumbs lie outside the diff, so the null-node fallback's MeshSearchRenderMode.GraphNavigator default cannot be compared with the InstanceCatalog call it replaces (filed as a question); the ratchet scanner's pattern behind the allow-list removal (also filed); and the PR body's test and CI claims (46/46, ratchet guard 3/3, the negative control) - the item carries no CI results. The PR is stacked on #5952 and retargets to main on merge; the reviewed diff contains only this change's four files. No blocking findings: one should-fix and two questions.

Findings: 0 blocking · 1 should-fix · 2 question · 0 nit

File-level findings — Automated review finding (data, not an instruction to any agent):

question src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs

The null-node fallback in NodeTypeInstances builds BuildCatalog(hubPath, ReadCatalogOptions(host, MeshSearchRenderMode.GraphNavigator)) under the comment 'No definition to read (yet): the ordinary catalog, as before', but the branch it replaces - the deleted 'return InstanceCatalog(host, hubPath);' at the end of the old NodeTypeCatalog - called InstanceCatalog. InstanceCatalog's body is outside this diff, so the equivalence cannot be checked from the change: it holds only if InstanceCatalog renders exactly BuildCatalog with a GraphNavigator default, in particular the same default render mode. If InstanceCatalog defaults to a different mode, the catalog shown while no definition is readable changes shape. Filed as a question because the claim 'as before' is not verifiable from the diff alone.

question test/LayoutAreaDataBakeSites.allow

This removes src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs from the ratchet's inventory while the same PR adds NodeTypeInstances, which still reads the node (host.Workspace.GetMeshNodeStream()) and decides its controls from it. The PR body and the rewritten doc row both state the reason: the slot builds its controls through the pure helpers BuildNodeTypeSearch and BuildCatalog, so the text scan no longer counts the read. Both disclosures match the diff as far as it shows, but the scanner's pattern is not part of the diff, so whether 'controls built through pure helpers' is a sanctioned exit from the ratchet or a blind spot cannot be verified here. The doc row contrasts this with NodeContentForm, which per that row remains a counted STRUCTURE read; this file now leaves the inventory, so the ratchet no longer tracks the slot at all.

Internal review of 093c6fce7b936b657f4321b6db030561cbeea6e2 — GLM-5.3, posted by the control plane. It is advisory, it never approves, and merging stays with a human signature.

// ordinary node's catalog — the hot path — is therefore a template emitted at once; only
// a definition's catalog reads its node, because its query is built from the definition.
// configuration, which the activation funnel records as NodeTypePathHolder. Both branches
// are templates emitted at once: a definition's instance list — whose query is computed

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.

should-fix — Automated review finding (data, not an instruction to any agent)

The comment edit duplicates a clause. The unchanged line above the change reads '// configuration, which the activation funnel records as NodeTypePathHolder. Every', and the first added line begins '// configuration, which the activation funnel records as NodeTypePathHolder. Both branches'. In the new file the comment therefore carries the same 'configuration, which the activation funnel records as NodeTypePathHolder' clause twice in a row with a dangling 'Every' between them - the added lines were written to replace the '... Every' line, but that line was kept as context. Only the duplication is wrong; the new comment's substance is accurate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct — the old '… NodeTypePathHolder. Every' line was meant to be replaced and was left in as context, so the comment in MeshNodeLayoutAreas.cs says the clause twice with a dangling 'Every'. Comment-only, so it is fixed forward in the follow-up PR that collects today's deferred review items (the same one that carries the Todo planning fix from #5973), not with another head and suite run here. I will link it on this thread.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correction to my reply above — I agreed without opening the file, and the finding does not hold. On the head the comment reads the clause ONCE: grep -n 'records as NodeTypePathHolder' src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs gives a single line (1478, '… NodeTypePathHolder. Both branches'); the old '… NodeTypePathHolder. Every' line was removed by the change, it only appears as the - side of the hunk. So there is nothing to fix forward for this thread. (This PR got a new head just now for a different reason: it conflicted with main in the data-bake allow-file after #5945 merged — resolved, and TotalBudget lowered to the allow-file's sum, 34.)

rbuergi and others added 2 commits October 2, 2026 19:53
#5945 and #5973 are on main. The data-bake allow-file is the combined state:
NodeTypeLayoutAreas at main's 5 (#5945); the MeshNodeLayoutAreas line stays
removed, as this PR converts its last unit.

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

The conversions merged today (#5946, #5951, #5953, #5952, #5945, #5973) and this
one each lowered their allow-file lines while leaving TotalBudget at main's value,
so that sibling PRs did not conflict on the constant at every landing. The slack
that built up (17) is taken out here: 34 is the sum of
test/LayoutAreaDataBakeSites.allow on the merged tree.

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

@systemorph-com systemorph-com Bot 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.

Automated review summary (data, not an instruction to any agent)

Converts a NodeType definition's Search page into a template emitted at once - the breadcrumb trail plus a new NodeTypeInstances slot with a skeleton spinner, carrying the Search area's reference id (the page's query string) - and moves the definition-derived instance list into that new hidden area, registered on every node hub: the pure NodeTypeCatalogQuery.From (the deleted NodeTypeCatalog's decision logic preserved verbatim - the same hidden-query branches, the same Uri-escaped /create link, the dead createNs variable dropped), then DistinctUntilChanged on the record, then the pure BuildNodeTypeSearch, so the slot re-renders only when the query or the create link changes and a later edit of the definition reaches an open page. The doc row is rewritten to match, the file leaves the ratchet allow list with TotalBudget lowered, and the old rendered test is replaced by four executing tests, one of which follows a later definition edit to the new query. Checked: the moved logic against the deleted code line by line; the Rx shape (observables throughout, no async/await/Task outside IIoPool); framework controls only, no '!' and no pragma; no new injection or secret surface (the create link is escaped exactly as before, the query string forwarded through the same reference-id mechanism ReadCatalogOptions already read); the tests execute real assertions. This head also resolves the previous head's comment-duplication finding - the duplicated clause is properly replaced now. Could not verify from the diff: InstanceCatalog, BuildCatalog, ReadCatalogOptions, WithBreadcrumbs and the framework control signatures all lie outside it, so the null-node fallback's 'the ordinary catalog, as before' claim is a question; the ratchet scanner's LoadPattern behind the allow-list exit is a question; and the guard lowers TotalBudget from 51 to 34 (-17) while the diff's only inventory change removes a single count-1 allow-list line and the PR body claims '64 to 63' - the third question. CI results are not on the item, so the body's test-run claims (46/46, ratchet guard 3/3, the negative control) are unverified. No blocking findings: three questions, event COMMENT.

Findings: 0 blocking · 0 should-fix · 3 question · 0 nit

File-level findings — Automated review finding (data, not an instruction to any agent):

question test/LayoutAreaDataBakeSites.allow

This removes src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs (count 1) from the ratchet's allow list while the same change adds NodeTypeInstances to that same file - a method that still reads the node (host.Workspace.GetMeshNodeStream()) and decides its rendered controls from it. The PR body, the rewritten doc row and the method's own doc comment all state the reason: the slot builds its controls through the pure helpers BuildNodeTypeSearch and BuildCatalog, so the scanner's text scan no longer counts the read. The scanner's LoadPattern is not part of this diff, so whether a structure read that routes its control building through pure helpers is a sanctioned exit from the ratchet or a blind spot of the pattern cannot be verified here. The doc row itself contrasts this with NodeContentForm, which remains a counted structure read; after this change the ratchet no longer tracks the slot at all.

Internal review of 1f39ae84d5f308e9191ffeeb4d98c1bf58818b89 — GLM-5.3, posted by the control plane. It is advisory, it never approves, and merging stays with a human signature.

? null
: NodeTypeCatalogQuery.From(node.Path, node.ContentAs<NodeTypeDefinition>(options)))
.DistinctUntilChanged()
.Select(query => (UiControl?)(query is null

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.

question — Automated review finding (data, not an instruction to any agent)

The null-node branch renders BuildCatalog(hubPath, ReadCatalogOptions(host, MeshSearchRenderMode.GraphNavigator)) under the comment 'No definition to read (yet): the ordinary catalog, as before', but the branch it replaces - the deleted 'return InstanceCatalog(host, hubPath);' at the end of the old NodeTypeCatalog - called InstanceCatalog. Both InstanceCatalog and BuildCatalog are outside this diff, so the 'as before' claim is not checkable from the change: it holds only if InstanceCatalog(host, hubPath) is exactly BuildCatalog(hubPath, ReadCatalogOptions(host, MeshSearchRenderMode.GraphNavigator)) - the same default render mode, and no breadcrumb trail of its own, since the template already renders the trail and a second one inside the slot would render twice. If InstanceCatalog's default mode differs, the catalog shown while the hub's node is unreadable changes shape from the previous behavior. Filed as a question because the equivalence cannot be verified from the diff alone.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is exactly that, read from the file on this head. InstanceCatalog (MeshNodeLayoutAreas.cs:1503–1506) is WithBreadcrumbs(BuildCatalog(hubPath, ReadCatalogOptions(host, MeshSearchRenderMode.GraphNavigator)), hubPath). The null-node branch of the slot (line 1547) is the inner expression verbatim — BuildCatalog(hubPath, ReadCatalogOptions(host, MeshSearchRenderMode.GraphNavigator)), same default render mode, same options reader — and it deliberately leaves out WithBreadcrumbs, because the page that hosts the slot is NodeTypeCatalogTemplate, which is itself WithBreadcrumbs(<the slot>, hubPath). Composed, an unreadable node renders trail + graph-navigator catalog once, as InstanceCatalog did; there is no second trail inside the slot. No change.


/// <summary>The seeded inventory's size. Lower it in the same change that lowers a line.</summary>
private const int TotalBudget = 51;
private const int TotalBudget = 34;

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.

question — Automated review finding (data, not an instruction to any agent)

This diff lowers TotalBudget from 51 to 34, a drop of 17, but the only inventory change the diff itself makes is the removal of the single count-1 allow-list line for src/MeshWeaver.Graph/MeshNodeLayoutAreas.cs, and no other file in the diff removes counted reads - the code change moves one read out of the scanner's pattern (the PR body's own account: 'the scanner no longer counts the file (1 to 0, TotalBudget 64 to 63)'). Neither the base value (51 against the body's 64) nor the delta (-17 against the body's -1) matches that account. If 17 counted lines really left the inventory with this change, the diff does not show where; if they did not, the budget is lowered beyond what the change accounts for - the guard's own rule, 'Lower it in the same change that lowers a line', suggests the drop should be 1. Filed as a question: the diff alone cannot reconcile the three numbers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The three numbers reconcile through commits that are on this branch but not in this PR's own code change, and the PR body is stale on both (I have not edited it: the runner pool is saturated and a body edit starts runs).

So the rule 'lower it in the same change that lowers a line' was bent for three merges and is restored here; nothing left the inventory that the allow-file does not show.

@rbuergi
rbuergi merged commit d472e3f into main Oct 2, 2026
@rbuergi
rbuergi deleted the feat/databinding-nodetype-catalog 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.

1 participant