Skip to content

test(desktop): make the two Linux-only tests run on Windows - #177

Merged
github-actions[bot] merged 1 commit into
mainfrom
claude/daily-repo-scan-v8fvqs
Aug 11, 2026
Merged

test(desktop): make the two Linux-only tests run on Windows#177
github-actions[bot] merged 1 commit into
mainfrom
claude/daily-repo-scan-v8fvqs

Conversation

@dizhaky

@dizhaky dizhaky commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Clears the last actionable follow-up from the Windows lane work. Both tests were POSIX-only by accident rather than design, and the Windows job found both on its first run.

The two fixes

update-relaunch.test.ts rooted its fixture at the bare literal /home/u/.hermes/hermes-agent. resolveUnpackedRelease normalizes its execPath with path.resolve, which on Windows prepends the current drive — so a driveless root can never equal the resolved exec path:

expected  \home\u\.hermes\hermes-agent\apps\desktop\release\linux-unpacked
actual    null            # because path.resolve gave D:\home\u\...

ROOT is now path.resolve(...) of the same literal: a no-op on POSIX, and both sides agree on Windows.

windows-hermes-path.test.ts hard-coded /venv/lib/python3.12/site-packages in its POSIX case — while the Windows case three tests above already builds its expectation with path.join. The implementation picks the layout from isWindows but still joins with the host separator, so the literal never matched on Windows. Now built with path.join, matching its sibling.

Verification: simulated Windows semantics

Neither a Windows host nor vitest is available in my sandbox — the test files use extensionless imports, which vite resolves and bare Node doesn't. So rather than assert a Linux pass and call it done (which would prove nothing about a Windows-only bug), I built faithful replicas of both implementations with the path flavour injected, giving path.resolve the runner's real cwd so the drive-letter prepend is reproduced rather than assumed.

Run under both posix and win32 semantics, before and after:

BEFORE (literals — what main has):  11 passed, 3 failed
    win32  FAIL  exec under unpacked
    win32  FAIL  unpacked itself
    win32  FAIL  venv POSIX layout
AFTER  (this change):               14 passed, 0 failed

The simulation independently reproduces the CI failures. Note it shows three where CI reported two: "unpacked itself" is the second assertion inside the first test, which vitest never reached because it stops at the first failure in a test. That's consistent, not a discrepancy.

The neighbouring negative assertions — AppImage mount, system install, dev electron, empty path — were included in the simulation and hold under both flavours, so resolving ROOT doesn't weaken them.

Not included

These two files are still not in the Windows lane's test:desktop:win-install list. I'd rather land the fix and let a later change add them, than widen the lane in the same PR that claims to fix them — the last two rounds on that lane were both caused by me over-including files. Adding them is a one-line change once this is on main and they've been seen green there.

Follow-ups still open

  • electron-builder can't be imported under vitest on Windows (likely upstream).
  • Windows' no-mux SSH path has no coverage — the well-covered mux path is the one Windows never takes.

Generated by Claude Code

Both were POSIX-only by accident rather than design, and both were found by
the Windows lane's first run.

update-relaunch.test.ts rooted its fixture at the bare literal
/home/u/.hermes/hermes-agent. resolveUnpackedRelease normalizes its execPath
with path.resolve, which on Windows prepends the current drive, so a driveless
root could never equal the resolved exec path. ROOT is now path.resolve of the
same literal — a no-op on POSIX, and it makes both sides agree on Windows.

windows-hermes-path.test.ts hard-coded /venv/lib/python3.12/site-packages in
its POSIX case, while the Windows case three tests above already built its
expectation with path.join. The implementation picks the layout from
isWindows but still joins with the host separator, so the literal never
matched on Windows. Now built with path.join, matching the sibling.

Verified by simulating Windows path semantics, since neither a Windows host
nor vitest is available here — the test files use extensionless imports, which
vite resolves and bare Node does not. Faithful replicas of both
implementations were run with the path flavour injected and path.resolve given
the runner's real cwd, so the drive-letter prepend is reproduced rather than
assumed.

The simulation reproduced the CI failures before fixing them: under win32 the
old code failed exactly the two reported assertions plus the second assertion
inside the first test, which vitest never reached because it stops at the
first failure in a test. After the change, 14 passed and 0 failed across both
posix and win32. The neighbouring negative assertions — AppImage mount, system
install, dev electron, empty path — were included and hold under both
flavours, so resolving ROOT does not weaken them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8
@github-actions
github-actions Bot merged commit 1770376 into main Aug 11, 2026
11 of 13 checks passed
@github-actions
github-actions Bot deleted the claude/daily-repo-scan-v8fvqs branch August 11, 2026 02:09
github-actions Bot pushed a commit that referenced this pull request Aug 11, 2026
Held back from #177 deliberately — over-including files caused both earlier
rounds on this lane, so the fix landed first and the widening comes now that
both files are cross-platform on main. Four files to six.

The check I owe, since these are whole files (16 and 22 tests) rather than
just the two assertions repaired in #177: in the first full-suite Windows run,
job 93652696640, the only failures from these two files were
update-relaunch.test.ts:54 and windows-hermes-path.test.ts:177. Every other
test in them was observed passing on a Windows runner. The ssh-connection
failures from that run are in a file that stays excluded.

One gap observation could not cover: vitest stops at the first failing
assertion in a test, so the second assertion of the test at :53 was never
reached on Windows. The win32 simulation covers it explicitly and it passes
after the repair — 14 passed, 0 failed across posix and win32.

Selection re-verified: six of the project's 80 test files, with before-pack,
stage-native-deps and ssh-connection still excluded.


Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8

Co-authored-by: Claude <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Aug 11, 2026
The last open item from the Windows-lane work. Seven files now.

Inspected before adding rather than adding and hoping: over-including
unverified files caused rounds #174 and #175, and since #176 the lane is a
required check, so being wrong now blocks everyone's PRs rather than just
mine. The sweep covered Windows-hostile syscalls, separator-dependent
assertions and shell assumptions.

It found a third instance of the defect class behind #177:
`assert.match(a, /\/[0-9a-f]{16}\.sock$/)` against controlSocketPath, which
builds with path.join — a leading-slash regex can only match on POSIX. Now
asserted on path.basename(a), which is separator-independent and is what the
sun_path limit is actually about. Checked under both path flavours.

Everything else in the file is safe for stated reasons rather than by
assumption: the /var/folders/ check is a negative assertion; ControlPath
passes through baseSshOptions verbatim, which does no path joining; the
`cd '/home/me/project'` assertion is a remote shell command and remotes are
always POSIX; and the path.join calls create directories inside the two tests
that already carry win32 guards.

Also corrects the workflow header, which #179 had made false — it still said
ssh-connection was POSIX-only and that making it cross-platform was tracked as
follow-up, which is precisely what #179 did.

Remaining exposure is unknown-unknowns across ~40 tests that cannot be
executed from this sandbox. If the lane goes red on this, the fix is to drop
ssh-connection back out of the list — one word, and the test repairs stand on
their own.


Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8

Co-authored-by: Claude <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Aug 11, 2026
…it (#183)

The same defect turned up three times across #177 and #180: a hard-coded
absolute POSIX path meeting a path the code builds with path.join. On Windows
path.join emits backslashes and path.resolve prepends a drive, so the two sides
can never be equal and the assertion is dead on that platform — silently,
because the file had only ever run on Linux. Two were found by the Windows lane
going red; the third by reading a file before adding it. One at a time, after
the fact, on a required check.

The rule does NOT ban leading-slash literals. A blanket ban is unusable: the
seven lane files hold 71 absolute POSIX literals, and all but the three above
are inputs — a fake execPath, a ControlPath handed to ssh, a path the stub
filesystem is asked about. Coping with those is the job of the code under test.
The defect is where a literal meets a computed path, so the rule keys on that
meeting: path.join onto a POSIX root (fix: wrap in path.resolve, a no-op on
POSIX), a comparison against a POSIX literal, and a regex that opens with a
path separator. "Opens with" rather than "contains" keeps the shebang check and
the remote-shell-command assertion — both legitimately POSIX, both in lane
files today — quiet.

Scoped to the suites in test:desktop:win-install, and that list is parsed from
package.json rather than restated in the config. A second copy fails silently:
a suite added to the lane but missing from the config gets no cross-platform
linting at exactly the moment it starts needing it.

Verified by observation, not assertion. Run over the pre-fix files (1770376^,
50e2b2b^) the rule reports exactly the three known defects and nothing else,
and none of them on the current files. The self-maintenance claim was proved
the same way: a probe file with a known defect drew no report until its name
alone was added to the lane script — no config edit — after which it did.

Two false positives are kept and annotated rather than engineered away.
windows-hermes-path compares against /root/venv/Scripts/python.exe twice, and
both are safe because every path helper that resolver touches is injected by
makeDeps and joins with '/'. The disables carry that reason, which is the rule
earning its keep — "why is this POSIX literal safe on Windows?" is what the
next person adding a suite needs answered.

The rule's own tests caught two bugs in it first: expect(x).toBe(v) puts the
expected value at argument 0, not 1, so expect-style assertions were never
checked; and the lane parser consumed the token after every flag, so a boolean
-u swallowed the suite name behind it. It now consumes values only for known
value-taking flags, erring towards a glob that matches nothing rather than
silently dropping a suite. Separately, the first disable comments did not work
at all — eslint-disable-next-line followed by more comment lines applies to the
next comment. Found by running lint, not by reading it.

lint now covers eslint-rules/ and scripts/*.test.mjs, because three lane suites
live in scripts/ and were outside `eslint src/ electron/`. The rest of scripts/
stays unlinted; it carries 10 pre-existing errors that are not this change.
eslint becomes a declared root devDependency — it was only ever an
auto-installed peer, and the rule's tests import RuleTester from it. The
lockfile delta is mechanical peer-marker removal with no version movement.

check:lint 0 errors (89 warnings, unchanged), test:desktop:platforms 976
passed, lane script 117 passed.


Claude-Session: https://claude.ai/code/session_012689txgT12g2hjRczcUZi8

Co-authored-by: Claude <noreply@anthropic.com>
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.

2 participants