Skip to content

Verify Windows UIA rename and Edit Details dispatch through native edit buffers - #509

Merged
coneilen merged 1 commit into
mainfrom
coneilen-microsoft-uia-rename-outcome-probe
Sep 29, 2026
Merged

coneilen merged 1 commit into
mainfrom
coneilen-microsoft-uia-rename-outcome-probe

Conversation

@coneilen

Copy link
Copy Markdown
Collaborator

Summary

The Node update/rename parity row recorded that the live Rename dialog opened and closed on Return. It did not record what the submit actually dispatched, and Edit Details was never opened, cancelled, or submitted. This PR extends the Windows UIA live gate to drive both dialogs end to end and assert the dispatched command.

While probing, the first gate implementation failed in two ways:

  • the rename dispatched the old title UIA loop A;
  • Edit Details stayed open with "Recap: no changes yet".

Both failures were gate artifacts, not product defects. The helpers wrote and read the dialog's edit controls with cross-process SetWindowText/GetWindowText. Across processes, these calls touch only the window manager's stored caption, never the EDIT control's buffer. So the gate's readback echoed its own write, while the app's in-process GetWindowTextW read the real, unchanged buffer. The helpers now use WM_SETTEXT/WM_GETTEXTLENGTH/WM_GETTEXT, which are marshalled cross-process, and still send the EN_CHANGE notification.

Changes

  • Tools/windows/uia-live-gate.ps1:
    • New GetDlgItem-based SetEditTextById/EditTextById helpers, using WM_SETTEXT/WM_GETTEXT. FirstEditText also reads with WM_GETTEXT.
    • Rename probe: targets Title edit id 9904, then asserts the dispatched node id and replacement title (UIA_RENAME_INPUT, UIA_RENAME_DISPATCH). It logs the graph and sidebar titles (UIA_RENAME_OUTCOME) but does not assert them.
    • Edit Details probe:
      • opens the dialog, cancels it, and asserts it closed without dispatching anything;
      • reopens it, sets Goal summary (id 9100), submits, and asserts the dialog closed and updateNode dispatched that goalSummary.
  • graphcode-windows/src/App.zig: an additive UIA fixture hook only.
    • Mutation 7 now shows the project surface before renaming.
    • New mutation 21 opens Edit Details for node A.
    • The hook is in mutateUiaFixture, away from terminal and workspace key dispatch.
  • Tools/windows/uia-live-gate.ps1, command-log reads: the shell's UIA recorder writes daemon-command.json by truncating and then writing, so the file can exist while its write handle is still open. File.ReadAllText demands FileShare.Read and threw a sharing violation at the pre-existing needs-you Stop step during full validation. A new Read-DaemonCommandLog helper opens the file with ReadWrite|Delete sharing and retries until the text is complete JSON. All six command-log reads use it. No assertion changed.
  • Tools/windows/Tests/ValidationRunner.Tests.ps1: source contracts requiring the new gate steps, WM_SETTEXT/WM_GETTEXT edit access, and the tolerant command-log read.

The ledger is unchanged: Node update/rename stays Partial.

What this does not establish

  • Graph/sidebar propagation. The gate forces daemon connection failure (GRAPHCODE_UIA_CONNECTION_FAILURE=1) and runs no daemon, so the graph and sidebar still show UIA loop A after the rename. The gate logs this, and I do not claim propagation.
  • What the dispatch evidence covers. It comes from the gate's command log under a forced connection failure. It shows the UI built the right renameNode/updateNode request; it does not show the daemon applied it. Verify Windows daemon mutation acceptance and restart persistence against a real graphcoded process #507 covers daemon acceptance and restart persistence separately.
  • Keyboard and pixels. Only the rename submit uses Return; the Edit Details buttons are driven with WM_COMMAND. Nothing here covers keyboard-only activation of Edit Details or rendered pixels.
  • Stale command-log reads. A stale but complete command record could only be accepted if it matched the specific assertion at that call site. Rename and submit require the exact node and title/summary. Needs-you Stop and reorder delete the log before acting. Two edges remain unhardened: a cancel-triggered write that lands after the post-close read, and Remove-Item -ErrorAction SilentlyContinue failing silently on an open handle.
  • Orphaned zmx daemons. Locally, zmx --daemon processes survived each gate run even though the gate logged UIA_PROCESS_TREE_CLEANUP=verified. I stopped them by PID. This happened on every run before this change too; it is not addressed here.

Test plan

RED: pwsh -NoProfile -File Tools\windows\Tests\ValidationRunner.Tests.ps1 (new contract, before gate changes) -> exit 1, "UIA gate does not verify rename dispatch/result or Edit Details open, cancel, and submit"
RED: pwsh -NoProfile -File Tools\windows\uia-live-gate.ps1 with the first SetWindowText-based helpers -> behavioral failure, UIA_RENAME_INPUT observed 'UIA renamed loop' but UIA_RENAME_DISPATCH title=UIA loop A titleMatches=False, and Edit Details stayed open with "Recap: no changes yet" (gate threw "Edit Details submission left the dialog open")
GREEN: pwsh -NoProfile -File Tools\windows\Tests\ValidationRunner.Tests.ps1 -> ValidationRunner.Tests.ps1: PASS
GREEN: pwsh -NoProfile -File Tools\windows\uia-live-gate.ps1 with WM_SETTEXT/WM_GETTEXT helpers -> exit 0, UIA_RENAME_DISPATCH title=UIA renamed loop titleMatches=True, UIA_EDIT_DETAILS open=True cancel=closed commandUnchanged=True, UIA_UPDATE_NODE_DISPATCH goalSummary=UIA details submitted, renameDialogPassed=true
RED: pwsh -NoProfile -File Tools\windows\validate.ps1 -Task windows-shell -SkipTrayLive (WM_SETTEXT helpers, ReadAllText command-log reads) -> exit 1, all 673 Zig tests and shell smoke/stress/handoff/tray contract passed, rename and Edit Details dispatch passed, then uia-live-gate.ps1:4180 ReadAllText threw a sharing violation on daemon-command.json
RED: pwsh -NoProfile -File Tools\windows\Tests\ValidationRunner.Tests.ps1 (tolerant-read contract against the pre-fix gate) -> exit 1, "UIA gate reads the daemon command log without tolerating the recorder's open write handle"
GREEN: pwsh -NoProfile -File Tools\windows\Tests\ValidationRunner.Tests.ps1 (with Read-DaemonCommandLog) -> ValidationRunner.Tests.ps1: PASS
REGRESSION: pwsh -NoProfile -File Tools\windows\validate.ps1 -Task windows-shell -SkipTrayLive -> exit 0, All 673 tests passed, scaffold contract PASS (52 source files), concurrent two-shell daemon handoff PASS, smoke/stress PASS, tray daemon contract PASS, UIA gate renameDialogPassed=true with UIA_RENAME_DISPATCH titleMatches=True and UIA_UPDATE_NODE_DISPATCH goalSummary=UIA details submitted

Checklist

  • I have read the Contributing Guidelines
  • I have signed off my commits (git commit -s) per the DCO
  • Tests pass locally (make test) — not applicable to a Windows-only change; Windows validation is listed under Test plan
  • Code follows the existing style (make check) — macOS/Swift lint; no Swift touched
  • I added the test/contract before the implementation and observed the intended RED failure

Extend the Windows UIA live gate for the Node update/rename row: drive the
Rename dialog Title edit (id 9904) and assert the dispatched renameNode title,
and open, cancel, reopen, and submit Edit Details (Goal summary id 9100),
asserting cancel dispatches nothing and submit dispatches updateNode.

Write and read the dialog edits with WM_SETTEXT/WM_GETTEXT. Cross-process
SetWindowText/GetWindowText only touch the stored caption, so the gate read
back its own write while the app submitted the unchanged buffer.

Read daemon-command.json with shared access and retry until it holds complete
JSON; the shell's recorder truncates then writes, so File.ReadAllText could hit
a sharing violation against its open write handle.

Graph/sidebar propagation is logged but not asserted: the gate forces daemon
connection failure.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
@coneilen
coneilen merged commit b382c2c into main Sep 29, 2026
16 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