Fix Windows UIA gate owned modal lookup - #502
Merged
Merged
Conversation
coneilen
force-pushed
the
coneilen-microsoft-uia-foreground-acquisition
branch
from
September 28, 2026 21:47
bcfd100 to
7c702bc
Compare
Resolve visible update dialogs by their owning process and HWND when desktop UIA enumeration omits them. Assert visible shell root access, report native activation outcomes and actionable fixture path limits, and correct Partial parity evidence without claiming full validation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Signed-off-by: Colin Neilens <coneilen@microsoft.com>
coneilen
force-pushed
the
coneilen-microsoft-uia-foreground-acquisition
branch
from
September 28, 2026 21:55
7c702bc to
78e83e2
Compare
3 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Windows UIA gate could not locate a visible update dialog by walking the
desktop UIA root, even though the shell and modal HWNDs existed and UIA could
resolve them directly. Look up top-level dialogs as desktop children, falling
back to the visible HWND owned by the launched shell when desktop enumeration
omits them. This does not claim Windows/macOS UI parity.
Changes
graphcode-rootresolves;record whether its root was accessible while another window held foreground.
traversal misses it; retain the dialog's Name/button assertions and the
click-opened dialog check.
maximum private TEMP root length when the fixture path guard fails.
inspection from real keyboard/focus and action-result evidence; all remain
Partial.Why this matters beyond the gate
About a dozen
Partialledger rows carried the same verbatim residual: "thecurrent live attempt stopped at foreground acquisition before UIA root
access." That sentence is inverted, and this change documents why.
The gate acquires the UIA root at
uia-live-gate.ps1:1466-1467viaFromHandle($process.MainWindowHandle), roughly 400 lines before the firstexecuted
Ensure-ShellForeground(line 1862). Earlier textual matches aredeclarations, not calls. So a run that fails at foreground has already passed
the root check.
The ordering argument alone would be weak, so it is backed empirically: across
four runs the root was resolved while a different process held foreground,
logged as
UIA_ROOT_ACCESS ... background=True. Foreground is not aprerequisite for UIA root access on this desktop.
The real failure was
RootElement.FindFirst(TreeScope.Descendants, Name=...)returning null for a visible, shell-owned dialog.
TreeScope.Childrenalsoreturned null in a run where that modal was both visible and foreground,
which rules foreground out as the cause entirely. Desktop-root enumeration is
unreliable for windows created after the client connects; the PID-scoped
FromHandlefallback is what actually fixes it.Consequence for planning, recorded so it is not rediscovered:
inspection): split-view destination and row identities; toolbar Name/role/
state; File/Loop/Terminal menu enablement; node Rename / Edit Details menu
presence; canvas/background/node/edge popup contents; sketch-promotion and
custody New Child menu presence; UI Automation tree and HelpText.
F6/Jump/keyboard discovery; focus retention and keyboard activation;
rendered pixels; actual menu activation results (rename, promotion, New
Child); provider-backed panel navigation; daemon acceptance/persistence;
IME and dead keys.
Limits
All evidence is local Console /
WinSta0\Defaultonly. Nothing hereestablishes CI-runner desktop or session behavior; the
windows-shelljobdesktop was never exercised. The background-foreground observations were
opportunistic rather than constructed — another application happened to
hold foreground — so they are observed, repeated (4/4 runs), and logged
unconditionally, but they are not a designed experiment that forces a foreign
foreground window. The full live gate is not reliably green.
Test plan
RED: pwsh -NoProfile -File Tools\windows\Tests\ValidationRunner.Tests.ps1 -> exit 1, "UIA gate does not use the owned modal HWND when desktop-tree lookup omits it" before the fallback.
GREEN: pwsh -NoProfile -File Tools\windows\Tests\ValidationRunner.Tests.ps1 -> exit 0, ValidationRunner.Tests.ps1: PASS after the fix.
REGRESSION: pwsh -NoProfile -File Tools\windows\uia-live-gate.ps1 -Shell graphcode-windows\zig-out\bin\graphcode-windows.exe -Zmx .graphcode-tools\providers\zmx\zig-out\bin\zmx.exe -> visible background UIA root and owned modal resolved, real foreground acquired; full run exited 1 at intermittent selection-event assertion.
Local live gate with short private TEMP (
D:\gc-uia-63609b39) asserted avisible background
GraphCodeWindowsShellHWND,graphcode-root, anon-null raw first child, and the owned update modal's Name/Later button via
FromHandle.SetForegroundWindow=Trueand observed foreground ownershipwere recorded later.
AttachThreadInput(foreground)returned FALSE withGetLastError=87in a successful activation, so it was not the blocker.The original failed call was
AutomationElement.RootElement.FindFirstreturning null; no Win32
GetLastErrorapplies to that UIA result.The baseline full
validate.ps1 -Task windows-shell -SkipTrayLiverun passed650/650 Zig tests and shell smoke/stress, then stopped before app launch
because its private TEMP root exceeded the lease path budget (282/232).
One later local run emitted the complete UIA result JSON but its parent output
pipeline did not exit; later direct runs exited 1 on intermittent,
unrelated hover, settings-save, ToggleState, or selection-event assertions.
The shell fixture also logged
Unable to start graphcoded.exe. Thosepaths and CI-runner desktop/session behavior were not diagnosed here.
git diff --check origin/main...HEADexited 0.Checklist
git commit -s) per the DCOmake test): macOS/Xcode is unavailable on this Windows host; the relevant Windows source contracts pass, but the full live gate remains intermittent.make check): macOS/Xcode lint is unavailable on this Windows host.