Skip to content

Keep every open project's graph live in the Windows shell - #664

Merged
coneilen merged 1 commit into
mainfrom
coneilen-fix-windows-live-graph-updates
Oct 8, 2026
Merged

coneilen merged 1 commit into
mainfrom
coneilen-fix-windows-live-graph-updates

Conversation

@coneilen

@coneilen coneilen commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes two live-graph-update defects from the Dev Box qualification of 0.1.78-windows.beta17 (4ab2fcf4). First, the qualification failure ProjectLiveUpdates: after a second project was opened with Ctrl+O, the shell stopped applying live updates for the earlier project. Second, a non-gating finding: presence nodesChanged deltas were ignored, so a loop awaiting input did not appear in Needs you until some unrelated full snapshot arrived.

Changes

  • Root cause 1 (DaemonClient.zig): every (re)dial sent a v2 hello with subscription.projectPaths set to the single most recently opened project. The daemon (DaemonConnectionChannel.isSubscribed) then dropped graphChanged for every other open project, including Core after Destructive was opened. The shell is a sidebar client (restoreOpenProjects), the same role the macOS app plays on its unfiltered v1 connection. So the hello now carries no filter. subscription_path still records the focused project and still triggers the existing drained re-dial, so the App open, reject and rollback flows do not change. The hello construction moved into a testable helloFrame.
  • Root cause 2 (GraphModel.zig, Wire.zig, App.zig): the shell never sends announce, but the daemon sends deltas to v2 clients anyway. Commit f6b8af41 (Windows daemon port) narrowed the capability gate in GraphStore.notifyClients(nodesChanged:) to v1 connections only (V2 clients use the replay envelope for the delta), and the shell had no handler. I fixed this in the shell, not in GraphcodeKit: the daemon sends deltas to v2 on purpose, and a shell-side fix also avoids full snapshots on every presence tick.
    • Wire.EventKind.nodes_changed, matched on the "nodesChanged": key.
    • Model.applyNodesChanged mirrors macOS AppFeature.foldDelta. It clones the held summary, replaces nodes by ID, ignores unknown loops, unknown projects, and deltas no newer than the held revision (now parsed from snapshots), then applies the merged graph through the same applyGraph path as a snapshot (decodeGraph was split into decode + apply). Attention, activity, worktree-binding invalidation and the selected legacy graph are all handled by that path.
    • App.onFrameWithEffects treats .nodes_changed like .graph_changed, including the accessibility republish. This is two lines plus one test in App.zig.
  • Tools/windows/windows-shell.ps1: the stub-daemon gate had required subscriptionSeen (a filtered hello), which encoded this defect. It now fails if any hello narrows delivery. reconnectObserved still proves the re-dial hellos were sent. subscriptionSeen stays in the stub report because uia-live-gate.ps1 requires the key to exist.
  • graphcode-windows/README.md: documents both behaviors and their evidence limits.
  • No GraphcodeKit or macOS changes.

Test plan

RED: zig 0.15.2 test src\DaemonClient.zig -target x86_64-windows-msvc -lc -ladvapi32 --test-filter "opening a second project keeps" -> 0 passed 1 failed, TestUnexpectedResult at the Core admission assertion (hello filtered to Destructive only)
RED: zig 0.15.2 test src\GraphModel.zig --test-filter "nodesChanged presence delta" -> 0 passed 1 failed, expected 1, found 0 Needs-you entries after the awaitingInput delta
GREEN: same two focused commands -> 1/1 passed each
REGRESSION: pwsh validate.ps1 -Task windows-shell -ShellPart unit -SkipTrayLive -ShellValidationRoot C:\gcp\v -> Windows shell scaffold contract PASS, 55 of 55 sections executed, App 891/891 passed including the new App nodesChanged test; script exit 1 only from post-run profile isolation cleanup (see notes)

Both RED failures were behavioral, not compile errors: each test used only APIs that existed before the fix (helloFrame was added first as a no-behavior-change refactor). After rebasing on 607494c0 (which includes #662, #663 and #665): the full App test root passed 899/899 (including the new App test), DaemonClient 188/188 and GraphModel 160/160. The CI run on the previous head 44224583 passed every Windows job after one rerun. Its first windows-shell integration attempt failed in "Scrubbed production shell startup" with exit 0xC0000142 (STATUS_DLL_INIT_FAILED): pwsh failed at process start, before printing anything, after smoke/stress and the stub-daemon gate had passed with subscriptionSeen:false.

Notes and limits:

  • validate.ps1 exited 1 after every section passed. Its isolation cleanup reported that %USERPROFILE%\.graphcode\graphcode-windows.log changed during the run. The same cleanup error appeared in an earlier run that stopped before any App test executed (0 App.test lines), so the leak is pre-existing and outside this change. That earlier run also hit the worktree-Git fixture path budget because of the long worktree path; the short -ShellValidationRoot avoided it.
  • The defect 1 test shows that the shell's hello no longer narrows delivery. Its admission predicate mirrors DaemonConnectionChannel.isSubscribed. It did not run against a live graphcoded.
  • I did not run the integration part (release build, live smoke, UIA gate), Swift, or macOS. Unit evidence does not replace the Dev Box rerun of the Ctrl+O multi-project repro and the awaitingInput Needs-you timing.

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 target; not run (Windows-only change, Windows unit suite above)
  • Code follows the existing style (make check) — macOS Swift lint; no Swift changed
  • I added the test/contract before the implementation and observed the intended RED failure

The shell's v2 hello subscribed only to the most recently opened project, so
after Ctrl+O the daemon filtered out graphChanged events for every other open
project (beta17 ProjectLiveUpdates). The shell is a sidebar client, so the
hello now never narrows delivery.

The daemon sends v2 clients presence ticks as nodesChanged deltas, which the
shell ignored, so Needs you stayed stale until an unrelated snapshot. The
model now folds deltas into the held snapshot by node ID with a revision
guard and applies the result as a snapshot, matching macOS foldDelta.

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-fix-windows-live-graph-updates branch from 4422458 to b87d674 Compare October 8, 2026 22:49
@coneilen
coneilen merged commit 880e6a3 into main Oct 8, 2026
25 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