Skip to content

Accept the daemon's canonical reply for the shell's own folder open - #633

Merged
coneilen merged 1 commit into
mainfrom
coneilen-microsoft-windows-preview-rebuild
Oct 5, 2026
Merged

coneilen merged 1 commit into
mainfrom
coneilen-microsoft-windows-preview-rebuild

Conversation

@coneilen

@coneilen coneilen commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Beta7 failed the attended Dev Box ProductionCoreProjectVisibility gate. Native
Ctrl+O registered Core exactly once in the production daemon (the CLI lists
Core C:/GraphCode-Fixtures/Core), but the shell never showed the project row.

Root cause: the shell discarded the daemon's own reply to its open request.

  • Path spelling: the native picker returns C:\GraphCode-Fixtures\Core. The
    production daemon canonicalizes it to C:/GraphCode-Fixtures/Core and
    answers the openProject request with that spelling. onFrameWithEffects
    checks the incoming graph path against the pending open byte-for-byte
    (Wire.isCurrentGraphPath). So it dropped the reply and left the backslash
    pending open in place, and every later graph frame for that project was
    dropped too.
  • Request ID case: the daemon echoes request IDs in uppercase (Swift
    UUID.uuidString), while the shell generates lowercase IDs. The App-level
    v2 correlation compared them byte-for-byte, so real open rejections were
    never correlated either. DaemonClient.completeRequest already compared
    them case-insensitively.

Why earlier gates passed: every fixture echoed the shell's own path spelling
and lowercase request ID, and the scrubbed registered-project case registered
through the CLI, which restores the daemon's canonical spelling. The real-daemon
round trip, the only test that speaks the production wire format, was not run
by validate.ps1 or CI.

Changes

  • App.adoptCanonicalOpenPath: when a graphChanged reply is provably for
    the shell's own in-flight open, it adopts the daemon's canonical path before
    the stale-frame filter runs. On v2, "provably" means the case-insensitive
    request ID matches. On v1, which has no IDs, it means the paths are equivalent
    apart from separator and ASCII case (Wire.sameLocalProjectPath).
    Uncorrelated publications are still filtered.
  • The v2 open-rejection correlation now compares request IDs
    case-insensitively.
  • DaemonRoundTripTests asserts the production contract the fix relies on:
    • a backslash openProject path is answered by a graphChanged response
      with the same request ID (ignoring case);
    • the response carries the canonical forward-slash path.
  • validate.ps1 now runs DaemonRoundTrip.Live.Tests.ps1 against the built
    production daemon in Windows shell integration, and a WindowsShell.Tests.ps1
    contract keeps it there.

Test plan

RED: zig test src\App.zig ... --test-filter "graph publication" with pinned Zig 0.15.2 -> 8 passed, 2 failed; canonical-path reply dropped (current graph stayed B), uppercase rejection left pending open set (expected 0, found 1)
GREEN: zig test src\App.zig ... --test-filter "graph publication" with pinned Zig 0.15.2 -> All 10 tests passed
REGRESSION: zig test src\App.zig full suite -> All 744 tests passed; zig test src\Wire.zig -> All 153 tests passed; DaemonRoundTrip.Live.Tests.ps1 with the beta7 graphcoded.exe -> REAL_DAEMON_ROUNDTRIP: PASS

Additional evidence:

  • Real-daemon round trip: the new request-ID assertion first failed
    against the real beta7 daemon. It expected
    00000000-0000-4000-8000-c5cc31d533d1 and found
    00000000-0000-4000-8000-C5CC31D533D1; that is how the case defect was
    found. After the fix it printed DAEMON_OPEN_CANONICAL in all three phases.
  • Scrubbed live gate: a source-built ReleaseSafe shell built with
    -Dworktrees-deferred=true, run against the beta7 daemon and CLI, gave
    SCRUBBED_SHELL_STARTUP: PASS; executed=5.
  • Full local run:
    validate.ps1 -Task windows-shell -SkipTrayLive -ShellValidationRoot C:\v7
    -> unit 53/53 sections, App 744/744, scrubbed startup 5/5, and the new Real daemon wire round trip PASS. The run then failed in the local UIA gate: the attribution added in Make UIA gate popup activation deterministic and attribute wait timeouts #631 shows WinDirStat, an unrelated operator app, holding foreground at "project-row New Loop". This is recorded as a local desktop failure, not a pass.
  • Exact-head CI run 37389038155 passed Windows shell integration, including the new round-trip step (3 DAEMON_OPEN_CANONICAL assertions and REAL_DAEMON_ROUNDTRIP: PASS), scrubbed startup 5/5 and the live UIA gate, along with unit shards and packaging.

Limits and honesty:

  • Live native picker: I could not drive the native folder picker
    deterministically on this shared desktop. A UIA-pattern probe closed the
    dialog without returning a folder in all four attempts. No local live picker
    run is claimed. The attended Dev Box rerun on a new candidate is still
    required.
  • Beta7 fresh-relaunch observation: it was a single snapshot at about 5 s
    that contained no ListItem at all, not even the Default workspace item
    every shell exposes. It is inconclusive about project rows. Locally, a fresh
    beta7 shell restores a daemon-registered Core row in about 0.5 s.
  • Process note: during this investigation, one probe run accidentally
    registered a scratch fixture in the operator's real ~\.graphcode, because
    the Swift daemon ignores a USERPROFILE override. Those two files were
    removed. No such probe is part of this change.
  • macOS: make test and make check were not run. The change is limited to
    the Windows Zig shell and Windows validation scripts.

Checklist

  • I have read the Contributing Guidelines
  • I have signed off my commits (git commit -s) per the DCO
  • Tests pass locally (make test)
  • Code follows the existing style (make check)
  • I added the test/contract before the implementation and observed the intended RED failure

The native folder picker returns a backslash path such as C:\a. The
production daemon canonicalizes it and answers the openProject request with
C:/a, echoing the request ID in uppercase. The shell compared both the path
and the request ID byte-for-byte, so it discarded the reply and kept the
pending open forever: the project registered in the daemon but never
appeared in the shell (beta7 ProductionCoreProjectVisibility). The same
uppercase echo meant v2 open rejections were never correlated either.

Adopt the daemon's canonical path when the reply is provably for the shell's
own in-flight open (case-insensitive request ID on v2, separator/case path
equivalence on v1), compare request IDs case-insensitively, assert the
daemon contract in the real-daemon round trip, and run that round trip in
Windows shell validation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
@coneilen
coneilen merged commit 1bd0398 into main Oct 5, 2026
25 checks passed
coneilen added a commit that referenced this pull request Oct 5, 2026
Record the immutable, unpublished 0.1.78-windows.beta8 candidate built from
1bd0398 with #633's canonical folder-open reply fix. Beta7 is failed and
superseded by the Dev Box ProductionCoreProjectVisibility result and kept
unchanged. Exact artifact stays complete; the other six gates and the
98/62/36 parity ledger are unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
@coneilen coneilen mentioned this pull request Oct 5, 2026
2 of 5 tasks
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