Skip to content

Fix Windows UIA gate owned modal lookup - #502

Merged
coneilen merged 1 commit into
mainfrom
coneilen-microsoft-uia-foreground-acquisition
Sep 28, 2026
Merged

coneilen merged 1 commit into
mainfrom
coneilen-microsoft-uia-foreground-acquisition

Conversation

@coneilen

Copy link
Copy Markdown
Collaborator

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

  • Require a visible GraphCode shell window when graphcode-root resolves;
    record whether its root was accessible while another window held foreground.
  • Resolve the shell-owned update dialog through its HWND when desktop UIA
    traversal misses it; retain the dialog's Name/button assertions and the
    click-opened dialog check.
  • Record exact native activation results/last-error values and explain the
    maximum private TEMP root length when the fixture path guard fails.
  • Correct five affected parity-ledger rows to separate background UIA
    inspection from real keyboard/focus and action-result evidence; all remain
    Partial.

Why this matters beyond the gate

About a dozen Partial ledger rows carried the same verbatim residual: "the
current 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-1467 via
FromHandle($process.MainWindowHandle), roughly 400 lines before the first
executed Ensure-ShellForeground (line 1862). Earlier textual matches are
declarations, 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 a
prerequisite 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.Children also
returned 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
FromHandle fallback is what actually fixes it.

Consequence for planning, recorded so it is not rediscovered:

  • Now obtainable without foreground (UIA presence/name/role/state, HMENU
    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.
  • Still genuinely blocked (needs real input injection or true focus):
    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\Default only. Nothing here
establishes CI-runner desktop or session behavior; the windows-shell job
desktop 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 a
visible background GraphCodeWindowsShell HWND, graphcode-root, a
non-null raw first child, and the owned update modal's Name/Later button via
FromHandle. SetForegroundWindow=True and observed foreground ownership
were recorded later. AttachThreadInput(foreground) returned FALSE with
GetLastError=87 in a successful activation, so it was not the blocker.
The original failed call was AutomationElement.RootElement.FindFirst
returning null; no Win32 GetLastError applies to that UIA result.

The baseline full validate.ps1 -Task windows-shell -SkipTrayLive run passed
650/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. Those
paths and CI-runner desktop/session behavior were not diagnosed here.
git diff --check origin/main...HEAD exited 0.

Checklist

  • I have read the Contributing Guidelines
  • I have signed off my commits (git commit -s) per the DCO
  • Tests pass locally (make test): macOS/Xcode is unavailable on this Windows host; the relevant Windows source contracts pass, but the full live gate remains intermittent.
  • Code follows the existing style (make check): macOS/Xcode lint is unavailable on this Windows host.
  • I added the test/contract before the implementation and observed the intended RED failure

@coneilen
coneilen force-pushed the coneilen-microsoft-uia-foreground-acquisition branch from bcfd100 to 7c702bc Compare September 28, 2026 21:47
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
coneilen force-pushed the coneilen-microsoft-uia-foreground-acquisition branch from 7c702bc to 78e83e2 Compare September 28, 2026 21:55
@coneilen
coneilen merged commit e866bf6 into main Sep 28, 2026
17 of 18 checks passed
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