Skip to content

fix(service): make Windows scheduler stop actually stop the proxy - #780

Merged
Wibias merged 8 commits into
devfrom
fix/764-windows-service-stop
Jul 31, 2026
Merged

fix(service): make Windows scheduler stop actually stop the proxy#780
Wibias merged 8 commits into
devfrom
fix/764-windows-service-stop

Conversation

@Wibias

@Wibias Wibias commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Partial progress on #764 (scheduler stop hardening: orphan discovery, verified PID kills, MS-account preflight, WinSW prompting). Restart-window stop verification already landed separately on dev.

The --native switch half of #764 stays open — do not treat this as a full close.

Test plan

  • CI green
  • Windows service stop regression coverage

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Wibias, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5a828a40-7261-4aa8-ba21-976f074af3c2

📥 Commits

Reviewing files that changed from the base of the PR and between b0dee82 and 0ef0e08.

📒 Files selected for processing (2)
  • src/service.ts
  • tests/service.test.ts
📝 Walkthrough

Walkthrough

The PR validates proxy PIDs, hardens Windows scheduler and native-service transitions, prevents non-interactive WinSW prompts, and verifies proxy termination before reporting a successful service stop.

Changes

Windows service lifecycle safeguards

Layer / File(s) Summary
Proxy identity validation
src/server/proxy-liveness.ts, tests/proxy-liveness.test.ts
Health-reported PIDs must be positive safe integers and pass exact identity verification. Invalid PIDs remain null, while configured-port discovery retains its pid-file fallback.
Windows installation and task removal guards
src/lib/winsw.ts, src/service.ts, tests/winsw.test.ts, tests/service.test.ts
Native installation rejects Microsoft-account users before state changes. Scheduler asset removal requires confirmed task deletion. WinSW rejects non-interactive password prompts.
Service stop and proxy cleanup
src/service.ts, tests/service.test.ts
Cleanup verifies tracked and discovered proxy identities, handles scheduler stop behavior, and fails when a proxy remains active.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant stopWindows
  participant findLiveProxy
  participant stopProxy
  stopWindows->>findLiveProxy: discover live proxy
  findLiveProxy-->>stopWindows: identity-verified PID
  stopWindows->>stopProxy: terminate verified proxy
  stopWindows->>findLiveProxy: verify proxy termination
  findLiveProxy-->>stopWindows: no live proxy or active proxy
Loading

Possibly related PRs

Suggested reviewers: ingwannu, lidge-jun

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses scheduler stopping, orphan recovery, PID verification, liveness checks, safe uninstall, Microsoft-account validation, and non-interactive WinSW handling, but not environment-variable passthrough [#764]. Add OPENCODEX_ADMIN_AUTH_TOKEN and OPENCODEX_ACL_TIMEOUT_MS to the generated WinSW environment configuration, with regression tests [#764].
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: fixing Windows scheduler service stopping so the proxy stops reliably.
Out of Scope Changes check ✅ Passed All changes support the linked service-lifecycle issue, including scheduler stopping, proxy recovery, native-service safety, WinSW prompting, and related regression tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch fix/764-windows-service-stop
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/764-windows-service-stop

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 085be23e08

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/service.ts Outdated
Comment thread src/service.ts
Comment thread src/service.ts
Comment thread src/service.ts Outdated
@github-actions github-actions Bot added the bug Something isn't working label Jul 30, 2026
@Wibias

Wibias commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

[shipping-github] Status

Not merge-ready yet. Required CI is green except windows-latest (unrelated full-suite / PowerShell timeouts outside the service-stop scope). Re-running failed jobs once more (flake budget).

Wibias added 4 commits July 31, 2026 02:13
Wait through the scheduler wrapper restart window when schtasks /end fails, and verify health-reported PIDs before stopProxy during service cleanup.
CI merges PR heads with dev; both sides added the proxy-liveness import, which broke typecheck with duplicate identifiers.
Restores cross-platform typecheck when both branches added the same proxy-liveness import.
lidge-jun added a commit that referenced this pull request Jul 31, 2026
…oundary

Windows CI died with `panic(...): Internal assertion failure` and no `(fail)`
line — four runs across `dev`, #771, #780 and #781. The crash header names the
shape: `workers_spawned(9) workers_terminated(8)`, one worker never reclaimed,
and it lands exactly at the `api-storage-policy` -> `api-storage` file
boundary. That suite is the only one that spawns policy workers.

`Worker.terminate()` returns void and does not wait for the thread to go away.
Under `bun test --isolate` the harness reclaims a file's realm at the boundary,
so a worker still exiting at that instant trips a Bun-internal assertion and
takes the whole run down. macOS and Linux tolerate the same race, which is why
it reads as a Windows-only flake.

`worker-lifecycle.ts` tracks live workers and terminates them through the
`close` event, so callers can await the thread actually being gone rather than
a timer they hope is long enough; a 5s cap keeps a wedged worker from hanging
teardown. Both storage jobs settle their run promise after that await, and the
policy suite's `afterEach` now drains.

devlog `_plan/260730_remote_issue_merge_round/150` reproduced this panic twice
against an unchanged tree, confirmed the same tree passed in PR context, and
left this defence as the follow-up if it recurred. It recurred.

Evidence: 6190 pass / 0 fail across 445 files, typecheck clean, privacy scan
green. The regression test asserts a worker was really spawned before checking
it is gone, so it cannot pass vacuously.
@Wibias

Wibias commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: gated

lidge-jun added a commit that referenced this pull request Jul 31, 2026
…#764)

`ocx service stop` reported success and restored native Codex while a proxy
was still listening, leaving both pointing at each other.

The cause is that `ops.stop()` reports the outcome of the STOP COMMAND, not
of the process. A Windows scheduler task whose wrapper survives `schtasks
/end` respawns its child a few seconds later, so a stop that returned success
can still leave a live proxy. The tracked-pid cleanup does not catch it
either: the respawned child writes a pid this process never recorded, and
`stopTrackedProxyIfRunning` returns "none" the moment the pid file is absent.

Stop is now verified instead of inferred. After the manager and the tracked
proxy are stopped, the command polls for a live proxy across the observed
restart window; if one answers, it reports the port, leaves native Codex
alone, and exits non-zero. Restoring the config on top of a running proxy is
the part that turns a failed stop into a broken installation, so that is the
step that must not happen on an unverified stop.

Deliberately different from PR #780, which waits only when `schtasks /end`
returns an ERROR. The reported case is an /end that SUCCEEDS while the
wrapper lives — on that path there is nothing for the command to report, so
waiting on its exit status cannot help. That PR's other work (orphan
discovery, PID verification, Microsoft-account preflight) is untouched here
and still worth reviewing separately.

Four tests on an injected clock, so no wall-clock sleeping. Ablation removing
the restart-window polling in favour of a single probe: 1 pass / 3 fail,
including the respawn case itself; restored 4/4. One test asserts a genuinely
stopped proxy returns null — without it the check could report a survivor
every time and strand native Codex unrestored, which is worse than the bug.
Another asserts a throwing probe is not read as absence, since an unreachable
health endpoint means unknown, not stopped.

87 pass across service, proxy-liveness and both tray suites. Windows behavior
needs the matrix CI; the logic here is clock-injected and platform-neutral.
@lidge-jun

Copy link
Copy Markdown
Owner

Half of what this PR addresses landed on codex/260731-pr-merge-round (2d0c6a99c + 5530b8c63), by a different route — leaving this open, since the rest of your work here is untouched and still worth reviewing.

Where the approaches differ. This PR waits ~6.5 seconds when schtasks /end returns an error. But the failure #764 reports is an /end that succeeds while the wrapper survives and respawns its child seconds later. On that path the stop command has nothing to report, so keying the wait on its exit status cannot catch it. What landed instead always verifies: after the manager and tracked proxy are stopped, it polls for a live proxy across the restart window, and refuses to restore native Codex if one answers — because restoring the config on top of a running proxy is what turns a failed stop into a broken install.

A correction I had to make there, which is relevant if you revisit this: my first version ran that wait on every platform. Review caught it. launchd and systemd do not bring a child back after unload/stop, so every macOS and Linux user would have paid a Windows-specific delay on every stop — a worse everyday bug than the one being fixed. It is now scoped to supervisors that can actually respawn.

Still open here and not duplicated: the orphan discovery, PID verification against the process table rather than trusting health-reported values, the Microsoft-account preflight, and the interactive WinSW prompting. Those are independent improvements; the proxy-liveness behavior tests are the strongest part.

One note if you rebase: several of the service checks are source-text assertions rather than behavior tests, so they pass whether or not the behavior holds. The stop verification that landed uses an injected clock and asserts probe counts, which may be a useful pattern for the PID work.

#764 stays open for its --native switch half.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server/proxy-liveness.ts (1)

106-118: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Three copies of the same PID-safety gate across two files. killablePid and verifiedReportedPid in src/server/proxy-liveness.ts, and verifiedKillTarget in src/service.ts, all implement the same logic: reject non-safe/non-positive PIDs, call a verifier, and require the verifier to echo back the exact candidate before treating it as killable. This is exactly the kind of security-sensitive check (gate on what can be terminated) that should live in one place so a future hardening (e.g., an extra check against process start-time) doesn't get applied to only one or two of the three copies.

  • src/server/proxy-liveness.ts#L106-L118: extract a single verifiedSafePid(candidate, verifyPidFn) helper (e.g., export it from src/config.ts next to verifyPidIdentity) and have killablePid and verifiedReportedPid both call it.
  • src/service.ts#L1694-L1698: replace verifiedKillTarget's body with a call to the same shared helper, passing verifyPidIdentity.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/proxy-liveness.ts` around lines 106 - 118, Centralize the PID
safety gate in a shared verifiedSafePid(candidate, verifyPidFn) helper, located
with verifyPidIdentity in src/config.ts and exported for reuse. In
src/server/proxy-liveness.ts lines 106-118, update killablePid and
verifiedReportedPid to delegate to this helper; in src/service.ts lines
1694-1698, replace verifiedKillTarget’s duplicated body with the same helper
using verifyPidIdentity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/service.ts`:
- Around line 2037-2038: Wrap the entire case "stop": body in its own block so
schedulerEndOk is block-scoped to that case. Preserve the existing stop-case
logic and behavior while ensuring the let declaration cannot leak across the
switch body.
- Around line 1443-1459: Update readWindowsPrincipalSource to replace
execFileSync with the repository’s Bun-native subprocess pattern, enforce a 5000
ms timeout, and await or otherwise handle its completion as required by that
API. Return the trimmed principal source on successful output, and return null
for timeouts, non-zero exits, missing PowerShell, or other probe failures.

In `@tests/proxy-liveness.test.ts`:
- Around line 148-149: Update the test invoking findLiveProxy for the
healthz-reported PID case to pass an explicit verifyPidFn that rejects the PID,
such as a function returning null. Keep the existing expectation and
configuration unchanged, matching the deterministic override pattern used by the
sibling tests.

---

Outside diff comments:
In `@src/server/proxy-liveness.ts`:
- Around line 106-118: Centralize the PID safety gate in a shared
verifiedSafePid(candidate, verifyPidFn) helper, located with verifyPidIdentity
in src/config.ts and exported for reuse. In src/server/proxy-liveness.ts lines
106-118, update killablePid and verifiedReportedPid to delegate to this helper;
in src/service.ts lines 1694-1698, replace verifiedKillTarget’s duplicated body
with the same helper using verifyPidIdentity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: da399858-474f-418a-ba5c-1e29d1ad5a26

📥 Commits

Reviewing files that changed from the base of the PR and between afe2aa3 and 1df9c82.

📒 Files selected for processing (6)
  • src/lib/winsw.ts
  • src/server/proxy-liveness.ts
  • src/service.ts
  • tests/proxy-liveness.test.ts
  • tests/service.test.ts
  • tests/winsw.test.ts

Comment thread src/service.ts
Comment on lines +1443 to +1459
function readWindowsPrincipalSource(): string | null {
if (process.platform !== "win32") return null;
const ps = join(process.env.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
if (!existsSync(ps)) return null;
try {
const out = execFileSync(ps, [
"-NoLogo",
"-NoProfile",
"-NonInteractive",
"-Command",
"(Get-LocalUser -Name $env:USERNAME -ErrorAction SilentlyContinue).PrincipalSource",
], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true }).trim();
return out || null;
} catch {
return null;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Inspect the implementation, its call sites, and the project runtime metadata.
printf '%s\n' '--- source context ---'
sed -n '1410,1475p' src/service.ts
printf '%s\n' '--- call sites ---'
rg -n -C 3 'readWindowsPrincipalSource|execFileSync' src/service.ts
printf '%s\n' '--- runtime metadata ---'
rg -n -i 'bun|engines|runtime' package.json bunfig.toml README.md .github 2>/dev/null | head -120

Repository: lidge-jun/opencodex

Length of output: 14627


🌐 Web query:

Bun 1.3.14 execFileSync timeout option child_process documentation

💡 Result:

In Bun 1.3.14, the child_process.execFileSync method supports the timeout option within its options object [1][2][3]. When provided, the timeout option (specified in milliseconds) instructs the parent process to send the signal defined by the killSignal property (which defaults to SIGTERM) if the child process runs for longer than the specified duration [4][5]. While the API documentation indicates support for this option [1][2][3], users have reported issues in specific environments, such as on Windows, where execFileSync and spawnSync may hang despite a timeout being set [6]. In such cases, the process may not terminate as expected, leading to a hang rather than a timed-out error [6]. Bun development has been actively working on improving the compatibility and stability of child_process methods, including explicitly adding and refining support for timeout in synchronous child process methods in recent updates [7].

Citations:


🏁 Script executed:

# Inspect the native-install call path and the declared Bun version.
printf '%s\n' '--- native install references ---'
rg -n -C 5 'installWindowsNative|assertWindowsNativeServiceAccountSupported|service install|--native' src/service.ts src/cli.ts src/cli 2>/dev/null | head -240
printf '%s\n' '--- package runtime declarations ---'
sed -n '20,70p' package.json
printf '%s\n' '--- local runtime availability ---'
command -v bun || true
bun --version 2>/dev/null || true

Repository: lidge-jun/opencodex

Length of output: 16543


🌐 Web query:

site:github.com/oven-sh/bun/issues/32011 execFileSync timeout Windows details

💡 Result:

In Node.js, the execFileSync method supports a timeout option which specifies, in milliseconds, how long a child process is allowed to run [1][2][3]. If the process exceeds this time, it is killed using the signal specified by killSignal (defaulting to SIGTERM) [1][2][3]. Key details regarding the timeout behavior on Windows include: 1. Process Exit Requirement: execFileSync will not return until the child process has completely exited, even after a timeout has occurred [1][3]. If the child process ignores the kill signal and continues running, the parent process will remain waiting until the child finally exits [1][4]. 2. Error Handling: If a process times out, execFileSync will throw an error [1][3]. This error object contains the full result of the underlying spawnSync operation [1][3]. 3. Known Behavioral Issues: In some runtime environments (such as Bun, which implements these child_process APIs), attempting to spawn certain native Windows executables directly may result in an ETIMEDOUT error or a hang, even with a timeout specified [5]. In these cases, wrapping the execution using shell: true or explicitly calling cmd /c is often required to achieve the expected behavior [5].

Citations:


🌐 Web query:

Bun 1.3.14 child_process execFileSync timeout Windows implementation issue

💡 Result:

In Bun 1.3.14, issues related to timeout behavior in child_process.execFileSync on Windows typically stem from how Bun's underlying subprocess implementation handles process spawning and timer management on the Windows platform [1][2]. Specific identified issues and behaviors include: 1. Stale Clock/Timer Issues: A known issue involves the synchronous spawn implementation (spawnSync, which execFileSync uses) relying on a cached per-VM libuv loop for the timeout timer [1]. If the loop's cached clock remains idle and goes stale, a timeout can trigger prematurely, resulting in an immediate termination of the child process, an exit code of null, and empty stdout/stderr [1]. 2. Spawning Native Executables: Users have reported that execFileSync and spawnSync may hang indefinitely—eventually throwing an ETIMEDOUT error—when attempting to spawn certain native Windows executables directly without a shell wrapper [2]. In these cases, using { shell: true } often serves as a workaround, as it bypasses the specific spawn path causing the hang [2]. 3. Resource Contention: Under high load, particularly in CI/CD environments on Windows (which lack native fork support and are more expensive for process creation), synchronous child process spawning can occasionally exceed expected time limits due to OS-level scheduler starvation or resource constraints (e.g., Windows Defender scanning) [3]. Bun implements node:child_process by wrapping its native Zig/Rust-based Bun.spawnSync primitives [4]. Developers encountering these issues are often advised to verify if the behavior persists when using { shell: true } (if applicable to their command) or to ensure that the environment is not oversubscribed during process-heavy tasks [2][3]. Fixes for these spawning and timing mechanisms are managed via the oven-sh/bun repository's issue tracker [1][5][6].

Citations:


🏁 Script executed:

# Check the exact dependency declaration and whether tests cover the Windows principal probe.
printf '%s\n' '--- package header and dependencies ---'
sed -n '1,75p' package.json
printf '%s\n' '--- principal probe tests and mocks ---'
rg -n -C 4 'PrincipalSource|MicrosoftAccount|assertWindowsNativeServiceAccountSupported|execFileSync|process.platform' tests src | head -260

Repository: lidge-jun/opencodex

Length of output: 20208


🏁 Script executed:

# Inspect the repository's Bun-native Windows subprocess wrapper and its timeout behavior.
printf '%s\n' '--- Windows ACL subprocess implementation ---'
sed -n '70,125p' src/lib/windows-secret-acl.ts
printf '%s\n' '--- timeout-related subprocess patterns ---'
rg -n -C 5 'Bun\.spawnSync|timeoutMs|timeout:|ETIMEDOUT|execFileSync.*hang|hung' src tests | head -280

Repository: lidge-jun/opencodex

Length of output: 20592


Bound the Windows principal probe and avoid execFileSync

At src/service.ts:1448-1454, add timeout: 5000 so ordinary PowerShell stalls use the existing null fallback. Bun can still hang in synchronous node:child_process Windows paths despite this option. Use the repository’s Bun-native subprocess pattern with an explicit timeout, and map timeout or non-zero exit to null.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/service.ts` around lines 1443 - 1459, Update readWindowsPrincipalSource
to replace execFileSync with the repository’s Bun-native subprocess pattern,
enforce a 5000 ms timeout, and await or otherwise handle its completion as
required by that API. Return the trimmed principal source on successful output,
and return null for timeouts, non-zero exits, missing PowerShell, or other probe
failures.

Comment thread src/service.ts Outdated
Comment thread tests/proxy-liveness.test.ts
Owner review: #764 is an /end that succeeds while the wrapper respawns, so waiting only when /end errors cannot catch it. Keep orphan/PID cleanup and the immediate live-proxy refuse-success guard; restart-window verification stays on the separate stop-verification path.
@Wibias

Wibias commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

[shipping-github] Addressed owner feedback — removed the schtasks /end-error wait (wrong for the succeed-then-respawn #764 case); kept orphan discovery, PID verification, MS-account preflight, WinSW prompting, and the immediate live-proxy refuse-success guard. Restart-window polling remains on the separate stop-verification path.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/service.ts`:
- Around line 2044-2048: Update the service stop flow around
stopTrackedProxyForServiceCommand and findLiveProxy to poll for the complete
scheduler restart window after stopWindows(), rather than relying on
findLiveProxy’s single 1500ms health request. Keep the stop command unsuccessful
if a respawned proxy becomes live during that window, and add a regression test
covering delayed Windows-wrapper respawn.

In `@tests/service.test.ts`:
- Around line 675-682: The test “Windows scheduler stop does not wait on
schtasks /end failure” should execute serviceCommand("stop") instead of
inspecting source text. Mock the scheduler /end operation to fail and inject a
fake delay or clock, then assert that proxy cleanup runs and the stop command
completes without waiting; keep the regression test near the existing service
stop tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c4f657f9-a6e1-446a-82b6-ab44596bfb59

📥 Commits

Reviewing files that changed from the base of the PR and between 1df9c82 and b0dee82.

📒 Files selected for processing (3)
  • src/service.ts
  • tests/proxy-liveness.test.ts
  • tests/service.test.ts

Comment thread src/service.ts Outdated
Comment thread tests/service.test.ts
Resolve the service.ts conflict by retaining verifiedKillTarget/orphan cleanup from this PR and adopting proxyStillLiveAfterStop from tip for the succeed-then-respawn #764 path.
@Wibias

Wibias commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

Merging this.

Why it helps: finishes the remaining Windows service-stop hardening on top of tip — verified PID/orphan cleanup, Microsoft-account preflight, and interactive WinSW prompting — without re-landing the restart-window verification already on dev.

@Wibias
Wibias merged commit 12eae74 into dev Jul 31, 2026
20 of 21 checks passed
@Wibias
Wibias deleted the fix/764-windows-service-stop branch July 31, 2026 05:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants