Repository navigation
Kernel: a control result is rendered, not also dumped as text - #861
sierragolflima wants to merge 5 commits into
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>
There was a problem hiding this comment.
Pull request overview
Fixes kernel cell output so that when a script’s last expression returns a layout control, the control is rendered via UpdateView but not also logged as text (avoiding StackControl { ... } record dumps in the output pane). Adds an integration test that asserts the distinction between control results (no dump) and scalar results (still logged as the only learner-visible output).
Changes:
- Guard
KernelExecutorresult-logging soIUiControlreturn values are not logged asToString(). - Add
KernelControlResultNotLoggedTestto assert: control result produces noStackControl { ... }dump, while scalar result still produces the expected logged marker.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| test/MeshWeaver.Hosting.Monolith.Test/KernelControlResultNotLoggedTest.cs | New integration test validating control results aren’t logged while scalar results still are. |
| src/MeshWeaver.Kernel.Hub/KernelExecutor.cs | Prevents duplicate output by skipping the result log line when the return value is an IUiControl. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Test Results 64 files 64 suites 34m 44s ⏱️ For more details on these failures, see this check. Results for commit 52b6429. ♻️ This comment has been updated with latest results. |
…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>
Test Results (shard 0)367 tests 363 ✅ 5m 14s ⏱️ Results for commit dcf0458. ♻️ This comment has been updated with latest results. |
Test Results (shard 5)1 538 tests 1 432 ✅ 7m 12s ⏱️ For more details on these failures, see this check. Results for commit dcf0458. ♻️ This comment has been updated with latest results. |
Test Results (shard 3)1 125 tests 1 125 ✅ 4m 3s ⏱️ Results for commit dcf0458. ♻️ This comment has been updated with latest results. |
Test Results (shard 2)2 006 tests 2 005 ✅ 5m 35s ⏱️ Results for commit dcf0458. ♻️ This comment has been updated with latest results. |
Test Results (shard 4)1 110 tests 1 101 ✅ 6m 6s ⏱️ For more details on these failures, see this check. Results for commit dcf0458. ♻️ This comment has been updated with latest results. |
Test Results (shard 1)1 547 tests 1 358 ✅ 6m 39s ⏱️ Results for commit dcf0458. ♻️ This comment has been updated with latest results. |
Pull request was closed
|
Closing without merging. The approach here is wrong, and the reason is worth recording. This suppressed the result log when the value implements That behaviour is a documented contract, not an incidental assertion.
For a script there is no rendered surface, so the log line is the only output the run produces. The decision therefore cannot be made from the value's type — both callers legitimately return controls, and only one of them has somewhere to draw. Narrowing it by caller is the shape that matches reality, but there is no existing discriminator: both the script path ( Continued in #876, with reproduction steps and four candidate approaches. The test added here, |
The defect
A cell whose last expression is a control printed the control's record
ToString()into its own output pane, beside the thing it describes:Reported on https://memex.meshweaver.cloud/RiskTransfer/01-GrossToNet, under the rendered "The 2025 Loss Book" grid.
The cause
KernelExecutorhandled a non-null result twice:The fix
Guard the log on the result not being a control. The log line stays for everything else — for
1 + 1it is the only output a learner sees — so this checks the type rather than removing the line.IUiControlis the interfaceUiControlimplements, so it covers every control.The test asserts both directions
Silencing the logger outright would suppress the dump and quietly break every scalar cell. A one-sided test would pass on that wrong fix, so
KernelControlResultNotLoggedTestpins the distinction, measured on one run:StackControl { Id = , Style = , … }scalar-result-42-markerscalar-result-42-markerOne thing the test encodes deliberately
Each cell gets its own activity node, and the assertion waits for a terminal status before reading. The activity log is replaced per submission, not accumulated — 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, so that reasoning is written into the test summary rather than left to be rediscovered.
Verification
dotnet build src/MeshWeaver.Kernel.Hub -c Release -warnaserror— clean, before and after merging currentmainmain(12 commits) before openingNot addressed here
Whether these cells should be executable on a read-only course page at all is a separate design question and is deliberately left open.
🤖 Generated with Claude Code