Repository navigation
Integration: all 10 open PRs in one merge (Actions outage workaround) - #875
Conversation
A cell whose last expression is a control printed the control's record
ToString() into its own output pane, beside the thing it describes:
StackControl { Id = , Style = , Readonly = , Skins = System.Collections.
Immutable.ImmutableList`1[MeshWeaver.Layout.Skin], Class = , IsClickable
= False, DataContext = , ... }
Visible under the loss-book grid on RiskTransfer/01-GrossToNet.
KernelExecutor handled a non-null result twice: UpdateView renders it, and
then the same object was logged via ToString(). The log line is correct for
every other result — for `1 + 1` it is the only output the learner sees — so
this guards on the type rather than removing the line.
The test asserts BOTH directions on one run, because silencing the logger
outright would suppress the dump and quietly break every scalar cell:
without the fix control log: StackControl { ... } scalar log: scalar-result-42-marker
with the fix control log: (empty) scalar log: scalar-result-42-marker
Each cell gets its own activity node and the assertion waits for a TERMINAL
status before reading. That is not incidental: the activity log is REPLACED
per submission, not accumulated, so two cells on one activity leaves only the
second cell's log — an earlier draft of this test passed twice against a log
that never contained the value under test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eter CI builds Release with -warnaserror, where CS9107 is an error: the primary constructor's `output` parameter was both captured by the test body and passed to the base constructor. In Debug it is only a warning, so `dotnet test` never surfaced it — I built the source project with CI's flags and the test project without them. Fixed at the root as AGENTS.md prescribes: use `Output`, the member MeshWeaver.Fixture.TestBase already exposes. No suppression. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The mesh menu items now read Create/Import/Export MeshNode (en) and
MeshNode erstellen/importieren/exportieren (de), so they are clearly
mesh-node operations, not file upload/download. The AI and GitHub top-bar
menu buttons now bind their Title to the existing menu.ai / menu.github
catalog keys ("AI menu" / "GitHub menu"), matching the Node and Mesh
buttons instead of the hard-coded "AI" / "GitHub".
No new localization keys (en/de parity preserved); display-text only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gration/all-open-prs
…g' into integration/all-open-prs
…to integration/all-open-prs
…integration/all-open-prs
…-main' into integration/all-open-prs
…c-guard' into integration/all-open-prs
…ntegration/all-open-prs
…ive' into integration/all-open-prs
…gration/all-open-prs
…g' into integration/all-open-prs
…to integration/all-open-prs
…integration/all-open-prs
…-main' into integration/all-open-prs
…c-guard' into integration/all-open-prs
…ntegration/all-open-prs
…ive' into integration/all-open-prs
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR improves end-to-end reliability and correctness across layout rendering, documentation executable blocks, and CI/CD delivery gates, while also tightening UI labeling/styling consistency.
Changes:
- Fixes multiple flaky/incorrect E2E and integration assertions (catalog selector, editor example markers, async recompute polling, render-block shape).
- Corrects layout binding behavior (BindMany publishing, ItemTemplate DataContext path) and avoids double-output for control results in kernel execution.
- Strengthens CI/CD correctness by gating delivery on the required check and adding evidence gating for test execution.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/MeshWeaver.Portal.E2E.Test/HomePageRegionsTest.cs | Updates catalog assertion to target MeshSearch container instead of nonexistent tabs. |
| test/MeshWeaver.Portal.E2E.Test/DocExamplesRenderTest.cs | Fixes Editor doc example selector/marker to match generated form output. |
| test/MeshWeaver.Persistence.Test/DocExecutableBlocksTest.cs | Adds a structural test preventing --render blocks from ending with statements. |
| test/MeshWeaver.Hosting.PostgreSql.Test/GroupMembershipRecomputeTests.cs | Removes order-dependence by polling until recompute conditions converge. |
| test/MeshWeaver.Hosting.Monolith.Test/KernelControlResultNotLoggedTest.cs | Adds regression test ensuring controls render without being dumped into cell output. |
| test/MeshWeaver.Content.Test/VersionHistoryTest.cs | Tightens per-step timeouts to stay within method timeout and improve diagnostics. |
| src/MeshWeaver.Messaging.Hub/Localization/strings.en.json | Clarifies mesh menu labels (Create/Import/Export MeshNode). |
| src/MeshWeaver.Messaging.Hub/Localization/strings.de.json | German equivalents for clearer mesh menu labels. |
| src/MeshWeaver.Layout/Template.cs | Fixes BindMany(IEnumerable) to delegate to stream overload and publish collection data. |
| src/MeshWeaver.Layout/EditorExtensions.cs | Makes editor labels honor Display + DisplayName consistently via shared helper. |
| src/MeshWeaver.Kernel.Hub/KernelExecutor.cs | Suppresses logging for IUiControl return values to avoid duplicate output. |
| src/MeshWeaver.Graph/VersionLayoutArea.cs | Reworks rollback to use stream Update (owner-minted versions) and respond reliably. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-06-styled-buttons.md | Adds “What’s New” entry documenting button styling fix and usage. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-06-meshnode-menu-labels.md | Adds “What’s New” entry documenting clearer menu labels/tooltips. |
| src/MeshWeaver.Documentation/Data/GUI/NodeMenu.md | Fixes render-block trailing semicolon issue (expression-ending requirement). |
| src/MeshWeaver.Documentation/Data/GUI/DataBinding/ItemTemplate.md | Updates BindMany example to a binding-safe shape and explains why. |
| src/MeshWeaver.Documentation/Data/DataMesh/NodeTypeConfiguration.md | Fixes render-block trailing semicolon issue (expression-ending requirement). |
| src/MeshWeaver.Documentation/Data/DataMesh/CRUD.md | Fixes render-block trailing semicolon issue (expression-ending requirement). |
| src/MeshWeaver.Documentation/Data/Architecture/ReleaseToProductionPipeline.md | Adds detailed architecture doc for release-to-production delivery hops. |
| src/MeshWeaver.Documentation/Data/Architecture/MeshNodeVersioning.md | Documents “never author Version” guidance and SemVer expectations. |
| src/MeshWeaver.Data/Workspace.cs | Converts workspace teardown to synchronous Dispose and removes async disposable bag. |
| src/MeshWeaver.Data/IWorkspace.cs | Changes workspace contract from IAsyncDisposable to IDisposable. |
| src/MeshWeaver.Blazor/wwwroot/standard-page-layout.css | Adds CTA pill styling using ::part + CSS custom properties across shadow DOM. |
| src/MeshWeaver.Blazor/Components/ItemTemplate.razor | Fixes DataContext path composition based on whether Data is a pointer. |
| src/MeshWeaver.Blazor/Components/ButtonView.razor | Forwards Class/Style to FluentButton so authored styling reaches the host. |
| src/MeshWeaver.Blazor.Portal/Layout/PortalLayoutBase.razor | Localizes AI/GitHub button Title attributes for consistent tooltips. |
| AGENTS.md | Adds guidance about strict main sync enforcement and CI expectations. |
| .github/workflows/main-cd.yml | Adds required-check gate and introduces portal-next image build job. |
| .github/workflows/dotnet-test.yml | Hardens test gating against cancellation and adds evidence gate for trx presence. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| portal-next-image: | ||
| name: "Build + push portal-next image" | ||
| if: >- | ||
| github.event.workflow_run.conclusion == 'success' && | ||
| github.event.workflow_run.event == 'push' && | ||
| github.event.workflow_run.head_branch == 'main' | ||
| runs-on: ubuntu-latest |
| name: "Alert: CD failed on main" | ||
| needs: [portal-image, migration-image, plugin-test-image] | ||
| needs: [portal-image, migration-image, plugin-test-image, portal-next-image] |
| /// surface for reading and mutating entities mapped to the hub's address. | ||
| /// </summary> | ||
| public interface IWorkspace : IAsyncDisposable | ||
| public interface IWorkspace : IDisposable |
| /// raw call returns whatever's on disk at the moment of invocation and can | ||
| /// race the WriteVersion side of the just-completed save. | ||
| /// </summary> | ||
| /// <summary> | ||
| /// Per-STEP wait budget. Every await in this class is bounded by it, and the sum of the | ||
| /// steps on any path stays inside the 20 s method timeout. | ||
| /// | ||
| /// <para>🚨 Why this exists: the awaits used to run on <c>Emit()</c>'s 10 s default, and the | ||
| /// rollback poll claimed <c>ReadNodeTimeout</c> (60 s) — inside a <c>Timeout = 20000</c> test. | ||
| /// Those bounds contradict each other: the method timeout always fired first, so a slow step | ||
| /// produced "Test execution timed out after 20000 milliseconds" naming NOTHING (main | ||
| /// 2026-08-06, shard 4). A bound larger than the method timeout is not a bound; it is a | ||
| /// guarantee of an undiagnosable failure. 4 s is ~10x the observed per-operation cost in this | ||
| /// project (246 tests in 96 s), so a step that exceeds it is stuck, not slow — and it now says | ||
| /// which step.</para> | ||
| /// </summary> | ||
| private static TimeSpan Step => TimeSpan.FromSeconds(4); |
| hub.GetMeshNodeStream(msg.Path) | ||
| .Update(_ => historicalNode with { Version = 0 }) | ||
| .Subscribe( | ||
| _ => hub.Post(new DataChangeResponse(hub.Version, new ActivityLog("Rollback")), | ||
| o => o.ResponseFor(request)), | ||
| updateEx => hub.Post(new DataChangeResponse(hub.Version, | ||
| new ActivityLog("Rollback").Fail($"Rollback write failed: {updateEx.Message}")), | ||
| o => o.ResponseFor(request))); |
Test Results (shard 0)367 tests 363 ✅ 4m 54s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
Test Results (shard 4)1 110 tests 1 103 ✅ 5m 48s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
Test Results (shard 5)1 538 tests 1 434 ✅ 5m 31s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
Test Results (shard 3) 10 files 10 suites 5m 25s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
Test Results (shard 1)1 547 tests 1 358 ✅ 6m 44s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
Test Results (shard 2)2 009 tests 2 008 ✅ 5m 58s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
Test Results 64 files 64 suites 34m 24s ⏱️ Results for commit 6b898ff. ♻️ This comment has been updated with latest results. |
This PR renames three menu labels in strings.{en,de}.json:
menu.create Create -> Create MeshNode
menu.import Import -> Import MeshNode
menu.export Export -> Export MeshNode
MenuAccessControlTest matches the menu's label set with SetEquals, so a renamed
label means the predicate can NEVER be satisfied: the stream keeps emitting, the
assertion keeps rejecting, and the test burns its full 20s and reports a timeout.
All four tests in the class failed that way on CI.
The timeout is what made this look environmental rather than like the stale
expectation it is -- the failure says only "did not emit a value matching the
predicate", never which labels it actually saw. Running the test from a worktree
based on main (i.e. WITHOUT this rename) passes in 2s, which reinforced the wrong
conclusion. It reproduces deterministically on this branch.
Five expectations updated: the two exact label sets and the three Any/FirstOrDefault
label lookups. 9/9 green on this branch.
(main's newly merged assertion diagnostics now print the last observed value on
timeout, so the next occurrence of this shape names the mismatching labels directly.)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hx6BiUYBu5U2Zdnom4Uz4X
…anges
This PR stops KernelExecutor logging a return value that is an IUiControl: the
control is already rendered by UpdateView, so also logging its record ToString()
prints "HtmlControl { Id = , Style = ... }" into the output pane beside the very
thing it describes. That is the intended behaviour.
ScriptExecutionInUserHomeTest asserted exactly the line now suppressed:
* Contains("[fireworks]") -- "fireworks return value lands as the terminal message"
* TakeUntil(o => o.Count >= 5) and Count.Should().Be(5) -- "4 progress + return value"
so both tests waited for a 5th message that no longer exists and timed out. The
timeout is why this read as a CI-only flake rather than the stale expectation it
is: the assertion reports only "did not emit a value matching the predicate",
never that the predicate had become unsatisfiable.
Updated to the new contract: the log carries the 4 progress lines, and a rendered
control must NOT also appear as its record ToString(). The >= 3 distinct-snapshot
assertion (the real subject of the streaming test -- that the executor does not
block the activity hub) is unaffected: counts still tick 1..4.
Also merges main and fix/meshnode-menu-labels, whose label rename broke
MenuAccessControlTest the same way. Both classes verified on this branch:
Security.Test 9/9, AI.Test 9/9.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hx6BiUYBu5U2Zdnom4Uz4X
WorkspaceOperations.UpdateStream hard-throws Data source ChangeLogRecord for partition is not initialized. when a change arrives before that stream's hub has finished starting (!stream.Hub.Started.IsCompleted). All three tests wrote immediately after GetHost().GetWorkspace(), i.e. they raced startup with nothing making them wait for it. The race is invisible locally -- the whole class runs in ~340 ms -- and fires on a loaded CI runner, where it surfaced as a lone unrelated-looking failure on a PR that only renames menu labels. Added GetStartedWorkspace(), which waits for the source's seeded record "1" to be observable before returning the workspace. That is the ACTUAL readiness condition, not a sleep (WritingTests.md), and it is what the other tests in the file already rely on implicitly. Applied to all three tests, including the one that posts DataChangeRequest via the client hub -- it reaches the same guard, just through the message pipeline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hx6BiUYBu5U2Zdnom4Uz4X
…bling FileSystem_ProductLaunch_CreatableTypes_ShouldIncludeTodo failed on CI with Expected the observable to emit a value within 5s, but it did not. The observable emitted nothing at all. on the FIRST read of a mesh-backed node. That read waits for the mesh to hydrate the partition; it is not a quick in-memory lookup. 5s was an unjustified outlier: the very next call in the same helper -- part of the same logical operation -- already allows 60s, and the method timeout is 60s. On a cold 2-core runner the read had not produced its first emission yet. This is a bound ALIGNMENT, stated plainly rather than dressed up as a root-cause fix: the read does complete (21/21 green locally in ~7s), and a genuine wedge still fails here -- just at the same 60s the rest of the operation already uses, instead of 12x sooner for no stated reason. Both copies of the helper (the integration and the filesystem test class) carried the same outlier. Note the "emitted nothing at all" half of that message is new -- main's assertion diagnostics now distinguish a silent stream from one that emitted non-matching values, which is what made this diagnosable at a glance instead of guesswork. Also merges fix/meshnode-menu-labels for the DataChangeLogTest startup-race fix, which this branch is equally exposed to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hx6BiUYBu5U2Zdnom4Uz4X
One CI run instead of ten. GitHub Actions has been in a major outage since ~15:22 UTC — workflow runs are failing or never created. Every trigger was tried against the individual PRs and none produced a usable run:
workflow_dispatch×10synchronize)A push is the most reliable
pull_requesttrigger there is, so this is the event→run-creation pipeline being down, not runner starvation. Nothing on the client side can produce a check.This branch merges all ten open PRs so a single run can clear the queue when Actions recovers.
Contents
docs/release-pipelinefix/kernel-uicontrol-tostring-logfix/doc-example-layout-areasfeat/cd-ships-portal-nextdocs/version-authoring-and-merge-mainfix/button-stylefix/flake-sweepfix/rollback-refused-by-monotonic-guardfix/meshnode-menu-labelsfix/workspace-dispose-sync-reactive#868 is excluded — it already merged to main.
Verification
-c Release -p:CIRun=true -warnaserrorMeshWeaver.Hosting.PostgreSql.Test: 634 passed / 0 failed on the combined tree.github/workflows/dotnet-test.ymloverlap between A --render block ending in ';' renders an empty skeleton forever #863 and CI cannot report green on zero evidence, and a starved job must not block delivery #871 auto-merged coherently — file parses, all four jobs (precheck,build,test,collect-results) intact, both sets of changes presentTradeoff — read before merging
This is a workaround, not a preference. Merging here means:
If Actions recovers before this is needed, prefer merging the ten individually — they already have auto-merge enabled and
strict_required_status_checks_policyis nowfalse, so they no longer invalidate each other and will merge themselves as each goes green. Close this branch in that case.No What's New entry: this adds no change of its own; each constituent PR carries its own.