Repository navigation
fix(tests): modal smoke intermittently loses its seeded draft - #1941
shanselman merged 1 commit into
Conversation
Wait for the visible exact draft and enabled Send action before modal navigation. Keep the existing composer identity and immediate return-value assertions unchanged. Co-authored-by: Copilot App <223556219+users.noreply.github.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
Native draft-retention proofThese are complete owned-window captures of synthetic fixture content, not a production conversation. The local runs' separate real-profile metadata guards failed, so these captures do not establish clean-host isolation. Before: reproduced failureOriginal modal test on Run After: exact seeded draft retainedFinal eight-line test-only patch on Run The after source corresponds to commit |
|
Codex review: needs maintainer review before merge. What this changesThe modal UI smoke test waits for its exact seeded draft and enabled Send action before navigating. Example: The Chat destination case opens a Settings-origin dialog after seeding "Keep this draft behind the shared-root dialog".
Review scores
ProductKind: Test only · Worth it: Yes · Fix scope: Complete Merge readiness✅ Ready for maintainer review Keep open: this collaborator-authored PR provides a focused repair for a demonstrated test-input race while preserving the original retention assertions; no introduced defect was found. Priority: P2 Before mergeNone. FindingsNone. Agent review detailsHow this fits togetherThe native UI fixture drives the real Companion executable through UI Automation and local MCP; the composer binds native textbox changes to its view model, whose state controls Send availability. flowchart LR
A[Native UI fixture] --> B[UI Automation draft input]
B --> C[Reactor textbox callback]
C --> D[Composer view model]
D --> E[Enabled Send action]
E --> F[Modal navigation]
F --> G[Immediate retention assertions]
Technical reviewBest possible solution: Keep the acknowledgement in the existing modal test before navigation and preserve all immediate retention and identity assertions. Do we have a high-confidence way to reproduce the issue? The original test navigates immediately after UIA SetValue, and the supplied failed native trace records reconciliation overwriting text before the bound callback accepts it; this review did not execute a reproduction. Is this the best way to solve the issue? The eight-line check is the smallest complete test repair: it establishes accepted input through existing observable state without retrying retention, retyping, adding hooks, or changing production behavior. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against ef1df54dfe95. Provenance checked
TestingProof path: shipped entry point. SecurityNone. EvidenceWhat I checked:
Review metrics
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment Reviewed October 30, 2026, 4:15 PM ET / 20:15 UTC. |
Resolve GatewayFixtureSettingsModalUiTests.cs with main's equivalent draft-readiness wait from openclaw#1941. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>


Related: #1940 (feat: pin Gateway pages beside chat). This standalone fix contains no page-pin changes and does not modify that branch.
What Problem This Solves
Fixes: the shared-root dialog smoke test intermittently reports an empty retained draft when it navigates before the composer has accepted its synthetic input.
User Impact
User impact: no shipping behavior change. The existing five-case native UI test now establishes its draft precondition before exercising dialog navigation.
Why This Change Was Made
UIA
ValuePattern.SetValuecan change the native textbox before Reactor's deferredTextChangedcallback updates the view model. The reproduced failure navigated away in that gap, and a controlled render overwrote the native text with the still-empty view-model draft.The eight added lines wait for the visible exact draft text and enabled Send action before navigation. In this fresh fixture there are no attachments, and the Send action is derived from
ChatComposerViewModel.CanSend. Native text alone is not the acknowledgement.The test still checks the original composer runtime ID and immediate draft equality on return. There is no final-return retry, retyping, fixed sleep, new test hook, product change, or change to the five theory cases. END240 is explicitly outside this PR.
Evidence
All local observations below were collected on October 30, 2026. Counts were re-read from actual TRX result rows, not inferred from process exit codes.
Verified before/after screenshot evidence. Both GitHub-hosted images were downloaded again and matched their original SHA256 hashes byte-for-byte.
baseline-release8295c80c30fae01b29872161b5d448308a5b8a0f, original testentry-ack-only-releasenative-event-trace-releasenative-event-trace-release-2fix-debugef1df54dplus exactly this eight-line patch, no product instrumentationfix-release-unsignedBoth reproduced failures were
SharedRootDialog_DefersNavigationAndRejectsNativeBinding(destination: Chat, settingsOrigin: True), at the original line 153: expectedKeep this draft behind the shared-root dialog, actual"".The failed instrumented replay, not the passing reruns, establishes the local ordering defect:
TextChanging: 45 characters; view-model draft length 0, revision 0TextChangedoccurs without the bound callbackThe first instrumented run captured the opposite ordering: the callback received all 45 characters before reconciliation. Instrumentation can perturb timing; it nevertheless reproduced and recorded the overwrite. The source of the pending render was not separately instrumented.
Exact source contract and prior CI comparison
The installed
Microsoft.UI.Reactorpackage was0.1.0-preview.12, pinned to microsoft/microsoft-ui-reactor commit b2a71d4ba0d8923a64c6e9c580a0f3318544d72f:Element.cs, lines 3277-3282: theTextChangedtrampoline checks suppression, then reads the currenttb.Text.Element.cs, lines 3306-3314: textbox Value uses the deferred controlled-property path.PropEntry.cs, lines 740-779: native drift is written back throughWriteSuppressed.These explain why a native value can disappear before its first accepted view-model update. Reactor and the product composer are not modified by this PR.
621f90a309b0a8d87c5295a0bbbc7d722dd10b7e7d7962f0ce57d3fd8b5c891424c59a3b515ce373ec6baa75d89b32240f60d2717a29c2e210348bfdThe original Split 5 Release failure was local, not hosted. The matching hosted signature does not establish an identical cause without its own trace. The earlier
7d7962f0candidate also waited after returning; that extra wait has not been shown necessary and is deliberately absent here.Retained artifact hashes and runtime identity
These digests identify retained local evidence; they are not public download links or signed attestations. No raw settings, tokens, identities, unrelated desktop content, or full application logs are published.
A69EAF912759AA2CEC8E844C3C03F3E7B8A69561703C761639FA7F1AE8673A4Abaseline-release/modal.trx435FDE4C62A69A1924A666906C5D6B41115E71084A616BD5F60BD201246507CEnative-event-trace-release-2/modal.trx2C88101491AE59821F38F5306A59847B0DBBABC9293ACFC951A278154843AB8AE94A177FE1552C5C217832A1A1AF5A8CE39D834DB18FD6B2FF25C3CE32D3B10F5C00FEE598C1A7270321B48931A17A6F49E62DF879E089ECF2C4FA875EA3B8C4fix-debug/modal.trx49E6B21F2B223AB2E96D051710F3B4F933AE8003E0B2D74F142EE8922CB5FDADfix-release-unsigned/modal.trxD2539886B823B1C7BC465A3F23C927FCE16B62689351F07A81EBD70887F3C93D0BDA7C87057E776A5BC01C075D6EC7AB7E759D7C4DC77DA70A75A1B3684D7925Shared.trxF640FB271C339EECDD0AB7D3F7ADF62B5C8CCEC2BBE4F2B854F5F28F42D34827Tray.trx3471594D9B6FFA07785D6360C0BAC69C34DE9812BDE89D8C6F8177617053B9C9BD5FC78C6B263A0E386D03A9B52914F79CAC5BF8E130AA354ECB811D76B47E93BC3259956DC0494A4D21D98E6CF0F60579AA753642002DEF4A6D23F1A4599E349E7EBB3307DC57F8162F00601FCD11BF94B47746980FC6712024A698A0C49DE9E3A8045865546831E032A44F6DA87564C087005AD2A753C581F9722158CFEC9AC0C61CA95BEEB1E4F00603BD0EDC58524F4907395E7379FDEC6BAAE287595790The final Debug and Release runner
source.jsonrecords match the full current patch exactly. Each configuration's fiverun.jsonmanifests match its recorded post-build app hashes. Tests used--no-buildafter identity capture.Before capture: run
6140fd7b9a2c47319a4959e6e8bab33c, 18:57:15.896570 UTC, original test plus tracing on8295c80c. After capture: runf1e8f35bc13a40a599fca9f36c8bbdfa, 19:06:28.440609 UTC, final Release source onef1df54dplus this patch. Both are owned-windowPrintWindow(PW_RENDERFULLCONTENT)captures of synthetic fixture content. The sidebar differs because the baseline is the page-pin branch; this is a draft-retention comparison, not visual layout proof. The final Debug screenshot has the same pixels/hash but its own run and timestamp.Change Type
Scope
winnodeRequired proof pools
none: only the existing hosted native UI test's input precondition changes. No shipping UI, Gateway, permission, installer, architecture, or custom hardware contract changes. The focused local fixture observations are supplementary and are not a completedwindows-winui-interactivepool.Validation
Source tested:
ef1df54dfe95a8b0a2ae8033425561136d8a70efplus the exact final uncommitted patch identified above. Publication commit:a2fb7ef9d0bc4e530ac12e790573740706b1ba78, tree7b82f5acee2f5453df3aaff2b5f98a0544031117. These are retained pre-commit executions with source correspondence, not new executions after committing. There was no rebase or product-source change..\build.ps1dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --no-restore --nologo -v:minimal --results-directory $artifacts --logger 'trx;LogFileName=Shared.trx'dotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restore --nologo -v:minimal --results-directory $artifacts --logger 'trx;LogFileName=Tray.trx'$Configuration = 'Debug'$Configuration = 'Release'git diff --checkgit apply --reverse --check <retained-final-patch>.\scripts\Get-CiChangeClassification.ps1 -EventName pull_request -ChangedPaths 'tests\OpenClaw.Tray.UITests\GatewayFixtureSettingsModalUiTests.cs' -Humanui_tests; no CI dispatchef1df54d,--max-priority P3The required Shared/Tray projects were built before their
--no-restoreruns, preventing a first-run zero-test false pass.$artifactsis the invocation-specific evidence directory, not a shared or latest-results directory.Exact focused command, cases, and harness corrections
The session-owned runner executed this command for each selected
$Configuration;$artifactsidentifies that run's output directory:null, falseChannels, falseSkills, falseChat, falseChat, trueEarlier failed attempts were retained rather than counted as passes. The first non-Dev Release build required a signed cleanup helper; the documented intentional-local-test override
RequireSignedCleanupHost=falsewas then used. The first required closeout had two executable-resolution failures because the runner's bounded PATH omitted Windows PowerShell. AddingC:\Windows\System32\WindowsPowerShell\v1.0made the two targeted tests pass (2/2), and the entire required build/Shared/Tray sequence was rerun with the results above. No repository code was changed to address either harness issue.Real Behavior Proof
ef1df54dfe95a8b0a2ae8033425561136d8a70efplus exactly this eight-line patch. Publication commita2fb7ef9d0bc4e530ac12e790573740706b1ba78has corresponding source, but was not the embedded binary commit during these runs.Yes/No/N/A): Yes. The exact evidence comment and both image URLs were read back; downloaded image hashes match the originals.last-chat-state.jsonalso retained its 999-byte size but changed timestamp, within the Shared test window. An unowned app was running; attribution is unknown, and it was not stopped or modified. No clean-isolation, signed-release, normal keyboard-input, real Gateway, ARM64, whole-suite UI, or overall merge-readiness claim is made. Historical hosted runs lack causal traces. END240 was not investigated.Security Impact
Yes/No): No.Yes/No): No.Yes/No): No.Yes/No): No.Yes/No): No.Yes, explain the risk and mitigation: N/A. Only synthetic-input readiness in an existing test changes.Compatibility and Migration
Yes/No): Yes.Yes/No): No product configuration changes. The existing unsigned local Release test override is documented above.Yes/No): No.Review Conversations
No review conversations have been resolved. The independent rubber-duck assessment found no blocking issue and judged the change ready for human review. The separate scoped shared-autoreview source review attempted Codex through the installed helper and stopped on HTTP 401, so no clean P0-P3 helper report exists. This review result is disclosed, not treated as a successful helper run. Author-side simplification retained only the eight-line entry acknowledgement and all original retention/identity assertions.