Skip to content

feat(samples): Northwind, Article and PythonDemo views are templates (data-binding B4, part 1) - #5951

Merged
rbuergi merged 3 commits into
mainfrom
feat/databinding-b4-samples
Oct 2, 2026
Merged

rbuergi merged 3 commits into
mainfrom
feat/databinding-b4-samples

Conversation

@rbuergi

@rbuergi rbuergi commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Data-binding batch B4, part 1: the in-mesh authoring samples NodeType authors copy. Refs #5940 (based on its branch; retargets to main when it merges).

What was wrong

Sixteen sample layout areas loaded their node on the hub (host.Workspace.GetStream<MeshNode>().Select(nodes => …FirstOrDefault(n => n.Path == hubPath))) and baked the values into hand-built Controls.Html markup. The page waited for the read, then showed a snapshot, and authors copied both habits.

What changed

  • Northwind Customer / Supplier (4 areas): each area is (host, _) => OverviewTemplate(path). Every value is a JsonPointerReference into the content with DataContext = GetMeshNodeDataContext(path), composed from Stack / LayoutGrid / Label. The hub reads nothing.
  • Northwind Employee / Product (4): the same for stored fields. Values only the hub can compute (dates in the viewer's culture, years of service, the listing and stock statuses) come from a feed: a function that builds no control, logs and shows its failures, and is bound with Template.Bind into a control declared up front.
  • Article, Northwind + ACME (4): the title and body are pointers into the node, and the metadata line is a feed. Thumbnail is new MeshNodeThumbnailControl(path, path), the path-only shape from B0 (Plugins#2632).
  • ReportsCatalog (Thumbnail, plus Overview, which the scanner missed): the title is a pointer, and the report cards are a Controls.MeshSearch that the GUI runs.
  • PythonDemo PrimeReport (1): one markdown control bound to /data/primeReport, fed by the IIoPool-backed Python run.
  • Platform: LayoutTemplate.Descendants / DeferredViews (MeshWeaver.Layout) reads a control tree as a template. It is public because in-mesh C# can't see a container's protected view list. It sits on a new internal IDeclaresViews on ContainerControl<T>, so no public interface changes.
  • Ratchet: 8 allow lines removed, TotalBudget 73 → 59.
  • Docs: GUI/DataBinding gets a table of the samples, GUI/LayoutAreas drops its bake-shaped "reactive view" and "own content" examples for template + feed, and DataMesh/CallingPython now shows the template + feed.

Values are displayed as stored. Lost from the old views: the "—" placeholder for an empty field, the $-formatted price, and the coloured status badges. The joined location line is now separate City / Region / Country fields. Captions are still the samples' authored English.

Evidence

  • In-mesh tests, run by the samples gate: each converted NodeType has a Test/ folder (8 suites, 17 cases). Every case builds the template from a path, with a feed that never emits, and asserts DeferredViews is empty, there's no HtmlControl, and the expected pointers are bound against the expected context. Pure functions (employment markdown in en/de, stock thresholds, the article header) are tested too. Local bake-then-gate.sh on samples/Graph/Data: 27/27 compiled, both warning ratchets ENFORCED with 0 NEW, ALL GREEN, and check-tests-area-verdicts.py passed with 8 suites executed and counted. The doc gate is also green.
  • Negative control: I added one deferred view (WithView((h, c) => h.Workspace.GetMeshNodeStream().Select(…))) to CustomerNodeLayoutAreas.OverviewTemplate. The gate then went RED: ❌ CustomerOverview defers 1 view(s) until data arrives: StackControl[3]: ViewStream1`. Reverted afterwards.
  • LayoutTemplateTest (2 cases, both directions) passes. LayoutAreaDataBakeRatchetGuard 3/3 passes with no stale lines for these files.
  • dotnet build -c Release -warnaserror: 0 warnings, 0 errors for MeshWeaver.Layout, MeshWeaver.Layout.Test, MeshWeaver.Documentation.Test and MeshWeaver.PluginTester.

Not in this PR

  • ACME/Project (5 catalog areas) and the SocialMedia doc samples (2) are part 2. The ACME areas need a paired change because MeshWeaver.Plugins/src/MeshWeaver.Acme.Test/ProjectTodoViewsTest asserts a CatalogControl shape.
  • samples/Todo (7) is deferred. Every area has per-row action buttons, and a bound row can't carry its click yet (the platform gap noted in GUI/DataBinding). Plugins' MeshWeaver.Todo.Test also asserts the baked LayoutGridControl.

Deploy

These are seeded sample nodes. After the roll, recycle the NodeTypes Northwind/{Customer,Supplier,Employee,Product,Article,ReportsCatalog}, ACME/Article and PythonDemo/PrimeReport on any portal that serves the samples. The cascade covers their instances.

Pairs-with: none — no public surface removed; LayoutTemplate is additive and IDeclaresViews is internal.
Implementers: none — no member added to a public interface (IDeclaresViews is internal).
Mirror-sync: none — no i18n catalog key added or changed.

🤖 Generated with Claude Code

…(data-binding B4, part 1)

Sixteen in-mesh sample areas loaded their node on the hub and baked the values into
hand-built HTML. They are now TEMPLATES: built from the node's path, emitted whole on the
first render, every stored value a JsonPointerReference the GUI resolves through the node
stream; values only the hub can compute (employment dates, stock status, an article's
metadata line, the Python report) come from a FEED that builds no control, bound with
Template.Bind. Thumbnails are path-only. ReportsCatalog's cards are a MeshSearch.

Each converted NodeType gains a Test/ folder whose cases build the template from a path
(with a silent feed) and assert LayoutTemplate.DeferredViews is empty plus the bound
pointers; LayoutTemplate is a new public reader in MeshWeaver.Layout so in-mesh C# can
make that assertion. Ratchet: 8 lines removed, TotalBudget 73 -> 59.

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

Copy link
Copy Markdown
Contributor

Auto-merge was not armed. This pull request targets feat/databinding-scan-guard, not the default branch main — a non-default base has no branch protection and therefore no required contexts, so arming it would merge it immediately, before its own CI runs. Merge it by hand when you are ready, or retarget it at main to have it armed normally.

@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 41s ⏱️ -29s
348 tests ±0  348 ✅ ±0  0 💤 ±0  0 ❌ ±0 
352 runs  ±0  352 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

♻️ 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   5m 44s ⏱️ +6s
2 368 tests +2  2 368 ✅ +2  0 💤 ±0  0 ❌ ±0 
2 372 runs  +2  2 372 ✅ +2  0 💤 ±0  0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

This pull request removes 1 and adds 3 tests. Note that renamed tests count towards both.
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "4af85333-65da-441e-8b5e-b10bad24d4f5")
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "a0acb438-9f8f-4733-8267-0b078d148000")
MeshWeaver.Layout.Test.LayoutTemplateTest ‑ ADeferredView_IsNamed_WhereverItSits
MeshWeaver.Layout.Test.LayoutTemplateTest ‑ ATreeOfControls_IsATemplate_AndEveryControlIsVisited

♻️ 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)

1 110 tests  ±0   1 110 ✅ ±0   3m 44s ⏱️ +5s
    4 suites ±0       0 💤 ±0 
    4 files   ±0       0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

This pull request removes 3 and adds 1 tests. Note that renamed tests count towards both.
   --- End of inner exception stack trace ---, isDenial: True)
 ---> System.UnauthorizedAccessException: Access denied
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.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)

2 672 tests  ±0   2 672 ✅ ±0   12m 52s ⏱️ +23s
    4 suites ±0       0 💤 ±0 
    4 files   ±0       0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

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 4)

767 tests  ±0   574 ✅ ±0   1m 49s ⏱️ -10s
  4 suites ±0   193 💤 ±0 
  4 files   ±0     0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

♻️ 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   12m 58s ⏱️ -42s
2 977 tests ±0  2 977 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 978 runs  ±0  2 978 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

♻️ 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 51s ⏱️ -45s
10 242 tests +2  10 049 ✅ +2  193 💤 ±0  0 ❌ ±0 
10 251 runs  +2  10 058 ✅ +2  193 💤 ±0  0 ❌ ±0 

Results for commit 2d2ecb0. ± Comparison against base commit 7b097dd.

This pull request removes 29 and adds 13 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: "a0acb438-9f8f-4733-8267-0b078d148000")
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.Layout.Test.LayoutTemplateTest ‑ ADeferredView_IsNamed_WhereverItSits
MeshWeaver.Layout.Test.LayoutTemplateTest ‑ ATreeOfControls_IsATemplate_AndEveryControlIsVisited
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)
…

♻️ This comment has been updated with latest results.

@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)

Data-binding batch B4, part 1: the Northwind Customer, Supplier, Employee, Product, Article and ReportsCatalog sample views, the ACME Article views and the PythonDemo PrimeReport view are converted from hub-side node reads (GetStream<MeshNode>() plus FirstOrDefault on the hub path) with hand-built Controls.Html markup into templates built from the node's path alone. Stored fields are JsonPointerReferences into the node that the GUI resolves; values only the hub can compute (employment dates and years of service, stock and listing statuses, the article header line, the Python prime report) come from feeds — observables that build no control and Catch their failures into a log line plus visible fallback text — bound into controls declared up front; the catalog's report cards become a Controls.MeshSearch with a hidden namespace/sort query. Every converted NodeType registers an in-mesh Tests view in its JSON configuration. The PR description additionally states a platform addition (public LayoutTemplate.Descendants/DeferredViews over a new internal IDeclaresViews on ContainerControl<T>), documentation updates, and a warning-ratchet reduction (8 allow lines removed, TotalBudget 73 to 59).

Checked from the readable part of the diff: template and feed construction (DistinctUntilChanged, Catch with logging), pointer and data-context binding, the new in-mesh test suites (they execute their cases and render verdict rows), the NodeType JSON registrations, and the visible docs excerpt. The diff carried by the review item is incomplete: src/MeshWeaver.Documentation/Data/DataMesh/CallingPython.md is truncated, and 7 patches are omitted — src/MeshWeaver.Documentation/Data/GUI/DataBinding.md, src/MeshWeaver.Documentation/Data/GUI/LayoutAreas.md, the new src/MeshWeaver.Layout/LayoutTemplate.cs, the ContainerControl.cs change (its project is masked in the review copy), test/LayoutAreaDataBakeSites.allow, test/MeshWeaver.Documentation.Test/LayoutAreaDataBakeRatchetGuard.cs, and the new test/MeshWeaver.Layout.Test/LayoutTemplateTest.cs. Nothing is asserted about the platform API's behavior, the ratchet-budget change, or the unread documentation. The review copy of the diff also masks some identifiers, so the findings quote readable fragments verbatim and carry no line anchors.

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

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

blocking samples/Graph/Data/Northwind/Employee/Test/EmployeeViewTests.cs

The null-forgiving operator is banned as a way to silence warnings. In Employment_IsATemplate_EvenWhileItsFeedIsSilent, Expect(body is not null, …) cannot teach the compiler that body is non-null — Expect is not annotated [DoesNotReturnIf(false)] — so the following dereference body!.DataContext uses ! precisely to suppress the resulting CS8602 in this #nullable enable file. The assertion can carry the proof instead, e.g. Expect(body is { DataContext: var dc } && dc == LayoutAreaReference.GetDataPointer(EmployeeNodeLayoutAreas.EmploymentDataId), …), which needs no operator. The same operator appears in ReportsCatalogViewTests.cs (search!.HiddenQuery), reported as its own finding.

blocking samples/Graph/Data/Northwind/ReportsCatalog/Test/ReportsCatalogViewTests.cs

search!.HiddenQuery uses the null-forgiving operator to suppress the CS8602 that #nullable enable emits for the MeshSearchControl? returned by SingleOrDefault(); the repository bans ! used to silence a warning. As the diff shows it, the same statement is also internally inconsistent: its failure-message interpolation dereferences search.HiddenQuery without the operator, which leaves that dereference a new CS8602 in a new file — at odds with the PR's stated 0-new-warning result for the samples build. A single non-null pattern match over search, or a [DoesNotReturnIf(false)] annotation on Expect, makes both dereferences safe with no operator.

question samples/Graph/Data/Northwind/Article/Source/ArticleLayoutAreas.cs

HeaderFeed resolves CultureInfo.GetCultureInfo(host.ViewerLocale()) while the view is being constructed — before the observable pipeline, and therefore outside the Catch<string, Exception>(…) that guards every other failure in the feed. GetCultureInfo throws CultureNotFoundException for an unrecognized name; whether ViewerLocale() can ever return one is not visible in this diff. If it can, the Overview construction throws for the whole area instead of degrading to the logged-and-shown fallback the feed otherwise promises. The same construction-time culture lookup is in EmploymentFeed (samples/Graph/Data/Northwind/Employee/Source/EmployeeNodeLayoutAreas.cs) and in the ACME twin (samples/Graph/Data/ACME/Article/Source/ArticleLayoutAreas.cs); resolving the culture inside the Select, where the Catch applies, would keep the feed's error contract intact.

nit samples/Graph/Data/Northwind/Employee/Source/EmployeeNodeLayoutAreas.cs

The overview card binds City and Country but not Region, and nothing else on the Employee page binds it — the view this change replaces rendered employee.Region in its joined Location line (new[] { employee.City, employee.Region, employee.Country }), so EmployeeContent.Region is now displayed nowhere on the page. The Supplier overview card drops Region the same way (it survives only on the Supplier contact page), while the Customer overview keeps it via its AddressCard.

⚠️ 🚨 The diff is INCOMPLETE: 1 patch(es) truncated and 7 omitted (budget 150000 characters, 20000 per file) — say so in the review summary and do not assert anything about what you could not read.


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

…erviews bind Region again

Review findings on #5951:
- EmployeeViewTests / ReportsCatalogViewTests dereferenced a SingleOrDefault() result
  through `!` after an Expect(x is not null) the compiler cannot see through. Each now
  pattern-matches `is not { } x` and throws the same message, so no operator is needed.
  The same `!` in LayoutTemplate.DeferredViews (src) goes the same way: one pattern
  match inside the Select, then OfType<string>().
- The Employee overview no longer showed Region anywhere on the page, and the Supplier
  overview dropped it. Both overview cards bind it again, and their tests assert the binding.

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

rbuergi commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Disposition of the file-level findings in review 5376210163, which reviewed head 98dcfe14e8. They have no inline threads, so this comment is the record. The fixes are in 059897e.

  1. blocking, Northwind/Employee/Test/EmployeeViewTests.cs (body!.DataContext): fixed. Expect(body is not null) followed by body! became if (… .SingleOrDefault() is not { } body) throw new InvalidOperationException("…"). The message is unchanged and the operator is gone. The same ! also sat in a file the review could not read, src/MeshWeaver.Layout/LayoutTemplate.cs DeferredViews (x.View!.GetType()). It is restructured the same way: one view is { } deferred and not UiControl pattern inside the Select, then .OfType<string>().
  2. blocking, Northwind/ReportsCatalog/Test/ReportsCatalogViewTests.cs (search!.HiddenQuery, plus the un-banged search.HiddenQuery in the message): fixed with the same is not { } search pattern. Both dereferences are now on a definitely-assigned non-null local.
  3. question, CultureInfo.GetCultureInfo(host.ViewerLocale()) resolved outside the feed's Catch: answered, not changed. LayoutAreaHost.ViewerLocale() returns AccessService.ViewerLocale(), which is Locales.Resolve(…). Locales.Resolve is documented to never throw and never return null, and it only ever returns a member of Locales.Supported (["en", "de"]), falling back to "en". GetCultureInfo("en") and GetCultureInfo("de") are predefined cultures. No project or Dockerfile sets InvariantGlobalization or PredefinedCulturesOnly, and the area's own test case resolves "de" without error. So the lookup cannot throw for any input, and moving it inside the Select would only redo the lookup on every emission. This applies to all three sites: Northwind Article, ACME Article and the Employee EmploymentFeed.
  4. nit, Region shown nowhere on the Employee page and dropped from the Supplier overview: fixed. Both overview cards bind Region again, between City and Country, as the replaced Location line did. EmployeeViewTests.Overview_IsATemplateBoundByPath and SupplierViewTests now assert the region binding, along with city and country.

Verification on 059897e:

  • dotnet build -c Release -warnaserror (one project per invocation) gave 0 Warning(s) and 0 Error(s) for MeshWeaver.Layout, MeshWeaver.Layout.Test and MeshWeaver.PluginTester.
  • LayoutTemplateTest passed 2/2.
  • The samples content gate, reproduced locally the way CI runs it (stage-samples-gate.sh then bake-then-gate.sh with .github/samples-gate.allow and .github/samples-gate-warnings.allow), reported ALL GREEN with exit 0 and 27/27 baked assemblies adopted. Every touched type reports compile=Ok render=ok tests=ok: Employee 3/3, ReportsCatalog 1/1, Supplier 2/2. Both warning ratchets are ENFORCED with 0 NEW.

@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)

Data-binding batch B4, part 1: the sample layout areas of Northwind Customer, Supplier, Employee, Product, Article and ReportsCatalog, of ACME Article and of PythonDemo PrimeReport are converted from hub-side node reads ([PERSON_NAME]<MeshNode>() plus FirstOrDefault on the hub path, values baked into hand-built Controls.Html markup) into templates built from the node's path alone. Stored fields become JsonPointerReference bindings the GUI resolves; values only the hub can compute (employment dates and years of service, the listing and stock statuses, the article header line, the Python prime report) come from feeds — observables that build no control and log and show their failures — bound into controls declared up front; the catalog's report cards become a Controls.MeshSearch over a hidden namespace/sort query; and every converted NodeType registers an in-mesh Tests view in its [ADDRESS] configuration, the eight new Test folders each contributing a suite whose listed cases execute at render and report verdict rows.

Checked from the readable part of the diff: the template and feed construction in all eight converted sources (DistinctUntilChanged, [PERSON_NAME] with logging, the IIoPool.InvokeBlocking Python run), the pointer and data-context bindings the new suites assert, the Tests-view registrations in the NodeType [ADDRESS] files, and the pure functions (Header, EmploymentMarkdown, ListingStatus, StockStatus) with their en/de culture and threshold cases. The new test helpers check nulls with 'is not { } x' followed by throw, so no null-forgiving operator appears in the readable sources, and the Employee and Supplier overview cards bind Region again alongside City and Country.

Not verified: the diff carried by the review item is incomplete — the CallingPython.md patch is truncated mid-hunk and seven patches are omitted entirely (src/MeshWeaver.Documentation/Data/GUI/DataBinding.md, src/MeshWeaver.Documentation/Data/GUI/LayoutAreas.md, the new src/MeshWeaver.Layout/LayoutTemplate.cs, the ContainerControl.cs change, test/LayoutAreaDataBakeSites.allow, test/MeshWeaver.Documentation.Test/LayoutAreaDataBakeRatchetGuard.cs and test/MeshWeaver.Layout.Test/LayoutTemplateTest.cs) — so nothing is asserted about the public LayoutTemplate API, the internal IDeclaresViews surface, the ratchet-budget reduction or the unread documentation; the platform contracts the feeds rely on (Workspace.GetMeshNodeStream(), host.ViewerLocale()) are not in the diff either. The carried diff also redacts some identifiers, so quotes are of readable fragments: the PR description's evidence section claims 17 in-mesh cases in the 8 suites, where the readable diff carries 16 case entries.

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

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

question samples/Graph/Data/Northwind/Article/Source/ArticleLayoutAreas.cs

HeaderFeed resolves CultureInfo.GetCultureInfo(host.ViewerLocale()) as its first statement — at template-construction time, before the observable pipeline and so outside the .Catch<string, Exception> that guards every later failure in the feed. GetCultureInfo throws CultureNotFoundException for an unrecognized name; whether ViewerLocale() can ever return one is not visible in this diff. If it can, building the Overview throws for the whole area instead of degrading to the logged-and-shown fallback the feed otherwise promises. The same construction-time lookup stands in the EmploymentFeed of samples/Graph/Data/Northwind/Employee/Source/EmployeeNodeLayoutAreas.cs and in the [ADDRESS] twin samples/Graph/Data/ACME/Article/Source/ArticleLayoutAreas.cs; resolving the culture inside the Select, where the [PERSON_NAME] applies, would keep the feed's error contract intact.

nit samples/Graph/Data/Northwind/Article/Source/ArticleLayoutAreas.cs

Header composes authored values into markdown without escaping: each tag is wrapped as a backtick code span and the thumbnail becomes an image link built by interpolation. The replaced code HTML-encoded every tag (HttpUtility.HtmlEncode); a tag containing a backtick now breaks out of its code span, and a thumbnail path containing ')' or spaces breaks the image link. Harmless for authored sample content, but these samples exist to be copied and the lost escaping travels with the pattern. The same composition is in the [ADDRESS] twin samples/Graph/Data/ACME/Article/Source/ArticleLayoutAreas.cs.

nit samples/Graph/Data/Northwind/Product/Source/ProductNodeLayoutAreas.cs

The two /data ids are inline string literals — "listingStatus" in OverviewTemplate and "stockStatus" in InventoryTemplate, both repeated as literals in ProductViewTests — while the same change defines public constants for the ids it introduces everywhere else (ArticleLayoutAreas.HeaderDataId, EmployeeNodeLayoutAreas.EmploymentDataId, PrimeReportLayoutAreas.ReportDataId). A constant would keep the Product sample on the pattern the other converted samples now model.

⚠️ 🚨 The diff is INCOMPLETE: 1 patch(es) truncated and 7 omitted (budget 150000 characters, 20000 per file) — say so in the review summary and do not assert anything about what you could not read.


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

@rbuergi

rbuergi commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Disposition of the file-level findings on head 059897e (no blocking, no should-fix):

  • question (culture lookup outside the feed's Catch): answered on the previous head (issuecomment-5928307953) — ViewerLocale() only yields "en" or "de" and never throws, and invariant-globalization mode is not enabled anywhere, so GetCultureInfo cannot fail there. No change.
  • nit (unescaped tag/thumbnail composition in the Article header): accepted as a sample-quality nit; the content is authored sample data. Left for a follow-up rather than spending another review round on this head.
  • nit (Product's inline "/data" id literals): accepted; same as above.

@rbuergi
rbuergi changed the base branch from feat/databinding-scan-guard to main October 2, 2026 09:12
The base (#5940) and the sibling (#5946) are on main. The data-bake ratchet's
TotalBudget is the combined value: 73 seeded, minus 6 converted by #5946, minus
14 converted here = 53, which is the sum of test/LayoutAreaDataBakeSites.allow
on the merged tree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rbuergi
rbuergi enabled auto-merge October 2, 2026 09:18
rbuergi added a commit that referenced this pull request Oct 2, 2026
…nding-b4-samples-2

#5940 and #5946 are on main and #5951 carries them. The data-bake ratchet is
the combined state: the ContentLayoutArea line left with #5946, the two
SocialMedia lines leave here, and TotalBudget is 51 — the sum of
test/LayoutAreaDataBakeSites.allow on the merged tree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rbuergi
rbuergi merged commit 93692b7 into main Oct 2, 2026
rbuergi added a commit that referenced this pull request Oct 2, 2026
…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>
@rbuergi
rbuergi deleted the feat/databinding-b4-samples 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