Skip to content

fix(service): stop scheduler wrappers before reinstalling on Windows - #7313

Closed
luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:codex/fix-windows-install-wrapper-cleanup-20261018
Closed

luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:codex/fix-windows-install-wrapper-cleanup-20261018

Conversation

@luvs01

@luvs01 luvs01 commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Windows install preparation now requests the existing, installation-scoped wrapper cleanup used by ocx stop after all recorded/conflicting/requested service managers have stopped and before stopping the tracked proxy. This addresses the cleanup gap where a surviving Task Scheduler launcher can respawn the old proxy during reinstall, including when its registration is already absent.
  • Manager-stop failures and live Desktop supervision still refuse before wrapper cleanup. Tests inject the cleanup dependency to avoid invoking real process termination. The five new regressions live in their own registered test file, and the service contract documents the ordering and limits.
  • Wrapper termination remains best-effort: this layer does not confirm that a surviving wrapper exited or that the replacement serves successfully. This change does not establish the cause of the original installation failure.

Verification

Recorded with Bun 1.4.3; these are separate runs, not additive totals:

  • Baseline: bun test tests/service/service.test.ts -t 'install preparation' with the production change removed produced 4 pass / 2 assertion failures (the two positive cleanup cases). Restoring the change made the five new regressions pass; their final moved-file run, bun test tests/service/service-install-wrapper-cleanup.test.ts, produced 5 pass / 0 fail.
  • Final layout: bun test tests/service/service-install-wrapper-cleanup.test.ts tests/service/service.test.ts tests/test-layout-tooling.test.ts — 238 pass / 3 skip / 0 fail, 1,268 assertions. The three skipped cases concern Windows definition ACL/UTF-16 fixtures.
  • Earlier isolation correction, before moving the five tests: bun test tests/service/service.test.ts tests/service/service-runtime-preflight.test.ts tests/service/service-ownership-handover.test.ts tests/service/service-desktop-runtime-preflight.test.ts — 266 tests / 0 fail. This is historical coverage, not a final-layout total.
  • bun node_modules/typescript/bin/tsc --noEmit — exit 0. The direct compiler entry bypassed a junction-related bun x tsc shim-resolution failure.
  • bun scripts/file-size-ratchet.ts, bun scripts/structure-ssot.ts, and bun scripts/privacy-scan.ts — passed; git diff --check passed.

The full local suite and a live Windows reinstall E2E were not run. Concurrent worktrees share test resources; validation here targets the changed ordering, refusal controls, mock isolation and layout, with broader coverage left to CI. A manual stop observation on the unpatched runtime is not patched E2E evidence. No GUI changes.

Current-head CI at a7647fb1740ec7a7443c4c2dadcd536d58b80c98: Cross-platform CI 39133137509 and Service lifecycle 39133137536 completed successfully. Windows test shards, Windows Task Scheduler and macOS launchd jobs were skipped; skipped jobs are not passing platform validation. Ingwannu's focused review on this head found no additional correctness blocker, and no new actionable feedback is present. CodeRabbit skipped its review while this PR was Draft; its success status is not review approval. Author-owned readiness is complete; any required maintainer sponsorship/security review remains a before-merge responsibility.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.
  • Current-head CI is complete and existing actionable review feedback is addressed for review readiness.

Summary by CodeRabbit

  • Bug Fixes
    • Windows service-install preparation now attempts to stop relevant wrapper processes after service managers stop and before tracked-proxy cleanup. Wrapper cleanup also runs when no manager stop is needed, but is skipped if stopping a manager fails.
    • Wrapper cleanup is limited to Windows; installations under active Desktop supervision remain protected.
  • Tests
    • Added coverage for cleanup ordering, failure handling, and platform-specific behavior.

Reuse the installation-scoped stop helper after manager shutdown and before tracked-proxy cleanup. Preserve refusal ordering and isolate Windows mock tests; add focused regression and layout coverage.
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 6c27282f-9b68-430f-a189-ac1c4e05a0f3
📥 Commits

Reviewing files that changed from the base of the PR and between 8640c2f and a7647fb.

📒 Files selected for processing: 9
  • scripts/test-layout/layout.json
  • src/service/orchestration.ts
  • structure/ops/service-and-sidecars.md
  • tests/fixtures/test-layout-expected.json
  • tests/service/service-desktop-runtime-preflight.test.ts
  • tests/service/service-install-wrapper-cleanup.test.ts
  • tests/service/service-ownership-handover.test.ts
  • tests/service/service-runtime-preflight.test.ts
  • tests/service/service.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Service-install preparation now performs Windows service-wrapper cleanup after successful manager-stop checks and before stopping the tracked proxy. Tests cover cleanup ordering, failure and refusal paths, and non-Windows behavior. The documentation and test-layout mappings were updated.

Changes: Service-install cleanup

Layer / File(s) Summary
Preparation cleanup
src/service/orchestration.ts
ServiceInstallPreparationDeps now supports an optional killServiceWrappers callback. On Windows, preparation invokes the callback or the default wrapper-cleanup function after manager-stop checks and before tracked-proxy cleanup. A manager-stop failure prevents wrapper cleanup.
Cleanup validation and documentation
tests/service/*, tests/fixtures/test-layout-expected.json, scripts/test-layout/layout.json, structure/ops/service-and-sidecars.md
Tests check cleanup ordering, cases with no manager stop, manager-stop failures, non-Windows behavior, and Desktop supervision refusal. The documentation describes the cleanup sequence and its limits. The new test is assigned to the service shard.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant prepareServiceInstall
  participant ServiceManagers
  participant WindowsWrapperProcesses
  participant TrackedProxy
  prepareServiceInstall->>ServiceManagers: Stop applicable managers
  prepareServiceInstall->>WindowsWrapperProcesses: Terminate wrappers on Windows
  prepareServiceInstall->>TrackedProxy: Stop tracked proxy
Loading
Merge Risk: ⚪ Minimal · up to a7647

The preparation sequence can continue if wrapper termination fails. No issue identified here requires a change before merge.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (3 skipped: 3… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed 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 and concisely describes the main change: stopping scheduler wrappers on Windows before service reinstallation. It matches the implementation and test coverage.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (3 skipped: 3 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Oct 18, 2026

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Correctness review at a7647fb: the new cleanup is placed after every manager stop and before tracked-proxy shutdown, and preserves the early Desktop-supervision and manager-refusal exits. Reusing the existing install-scoped wrapper helper keeps the change narrow. The structure document accurately describes its best-effort limitation, and the new test is registered in both maps.

Independent Linux/Bun 1.4.3 verification in fresh homes and a capped cgroup: 55 tests passed across service-install-wrapper-cleanup, service-runtime-preflight, service-ownership-handover and service-desktop-runtime-preflight (including all five new ordering/refusal cases). The current-head Cross-platform CI run 39133137509 and Service lifecycle run 39133137536 are successful. The Windows schtasks job was skipped; neither the injected platform tests nor that hosted result proves a real Windows reinstall or wrapper exit.

No additional correctness blocker found in this focused change. Please complete the author-owned current-head readiness checklist when the draft is ready for review. I have kept the draft/readiness state intact; no merge or service operation was performed.

@luvs01
luvs01 marked this pull request as ready for review October 18, 2026 14:09
@luvs01
luvs01 requested a review from lidge-jun as a code owner October 18, 2026 14:09
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-18T14:09:42.225853Z a7647fb Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Correctness approval at unchanged head a7647fb, now marked ready (current dev base 8640c2f). The install-scoped wrapper cleanup remains after successful manager stops and before tracked-listener cleanup, with Desktop supervision and manager-refusal exits ahead of it. Both test maps and the structure limitation are documented.

The 55 focused Linux/Bun 1.4.3 tests recorded in my previous review 5563299114 were executed at this exact unchanged head, so they were not rerun just for another receipt. Current-head functional CI, gates/Typecheck and Service lifecycle are successful. The Windows schtasks lane was skipped, so actual Windows reinstall/wrapper exit remains unverified.

The later Codex comment reports review-account usage exhaustion and supplies no source finding; that account-limit message is not a functional CI failure or an instruction to spend credits. This manual correctness review does not waive a real unresolved finding. No account-consent action, workflow dispatch, new scan or merge performed.

lidge-jun added a commit that referenced this pull request Oct 19, 2026
…ate paths and shim token handling (B5) (#7397)

* fix(oauth): allow dismissing a settled failed login flow (carry #7379)

Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com>

* fix(providers): preserve explicit API-key mode when keys are unavailable (carry #7304)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(dsh): bound account profile response reads (carry #7333)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(dsh): drain server fixtures before removing homes (carry #7305)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(claude-cli): keep local errors out of subscription cooldown (carry #7343)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(claude): bound Desktop library reads and preflight writes (carry #7301)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(service): stop scheduler wrappers before Windows reinstall (carry #7313)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(startup): require RunAtLoad before Desktop relaunch (carry #7277)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): strip OpenSSL startup variables from updater child env (carry #7342)

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(codex): keep the service token out of bypassed shim launches

All three Codex shims loaded the service API token into OPENCODEX_API_AUTH_TOKEN before checking OCX_SHIM_BYPASS, so a bypassed native passthrough launch handed the proxy data-plane token to the real Codex and its descendants. The POSIX, CMD and PowerShell shims now skip the token load under bypass; the Unix revision marker moves to 4 so installed wrappers are refreshed.

loadServiceTokenFromFile reads the inherited OCX_API_TOKEN_FILE through a no-follow, nonblocking descriptor, accepts only a regular file of at most 4 KiB and returns only a single-line printable token.

* test(claude): wait for a real ctime transition before requiring rejection

Re-applying the same utimes moves ctime only after the kernel clock ticks, so the real ctime case from #7301 often observed no change and the reader correctly returned {}. Repeat the call until ctime has advanced (bounded), assert that precondition, then require desktop_config_not_regular.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(google-antigravity): admit a probed project_id fallback in account import (carry #7385)

An Antigravity account whose Cloud Code Assist project is not auto-discovered was rejected with missing_project even when the operator knows its project. A Cockpit record may now carry a bounded project_id (Google Cloud project grammar, 6-30 chars, exact match). Discovery keeps precedence; the fallback is admitted only after the account quota probe succeeds with that account own access token against that project. Probe refusal, probe errors and cancellation write nothing. No shared default project.

Co-authored-by: yobushka <51312852+yobushka@users.noreply.github.com>

* fix(quota): name a closed reason when an OAuth account quota probe fails

Anthropic per-account quota rows reported quotaUnavailable with no reason, and Antigravity reported account_unavailable for any credential-side throw. The Anthropic usage read now reports a closed code for an HTTP status class, an unusable body or a thrown dispatch, and a probe that cannot obtain a credential reports account_unavailable without dispatching. Antigravity distinguishes a credential refresh deadline (timeout). Codes reuse the existing closed QUOTA_FAILURE_CODES set, carry no upstream text and never change account health.

* test(claude): match the symlink-resolved rollback target in the picker restore case

The atomic writer renames onto the symlink-resolved target, so on macOS (/var -> /private/var) the rollback rename never matched the fixture path and the restore-failure injection did not fire. Compare both spellings.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(google-antigravity): cancel the import project probe with the import request

probeAntigravityUsageQuota accepts an optional caller signal that cancels every request of the probe and stops before the models fallback; the import verifier forwards the import signal and never admits after cancellation.

* fix(codex): upgrade installed Windows shims that load the token before bypass

CMD and PowerShell wrappers now carry a Windows revision marker. A marked wrapper without it (installed before the bypass-token fix) is obsolete: installCodexShim and autoRestoreCodexShim rewrite it in place over the same backing launcher instead of reporting it healthy or already installed, and diagnostics report it unhealthy. On Windows the service token reader also binds the opened descriptor to the path by identity, so a link swapped in after lstat is refused.

* test(codex): mark the in-place Windows diagnostics fixture with the current revision

* fix(codex): refresh obsolete Windows shims without clobbering a concurrent replacement

The obsolete-wrapper refresh truncated whatever occupied the wrapper path. It now moves the observed wrapper aside and proves it is the probed file, stages the current wrapper beside it, and publishes with a hard link that refuses an occupied path. A concurrent replacement is restored or kept untouched and the refresh reports deferred.

* docs(structure): record the Windows shim refresh transaction

* fix(codex): create the Windows shim refresh stage exclusively and resume partial upgrades

The refresh stage is now created with O_CREAT|O_EXCL (and O_NOFOLLOW on POSIX) under an independent random name, and publication, withdrawal and cleanup are bound to the identity of the file this refresh created, so a planted link is never written through. Auto-restore resumes a Windows revision-only sibling mix (current plus obsolete wrappers) instead of deferring forever after one transient publish failure.

* fix(codex): bind Windows shim refresh rollback and recovery to observed identities

Publication keeps a linked entry only if it is the created stage, and withdraws a link to a swapped stage (file or symlink) while leaving independent replacements. Restoring the moved wrapper requires the aside to still be the moved file. Automatic revision recovery now refreshes only the admitted obsolete wrappers and first re-verifies every current sibling, so a replacement during the stability wait is never adopted.

* fix(codex): never displace a Windows shim where its replacement cannot be published

The refresh proves hard-link support in the wrapper directory with a throwaway pair before moving the wrapper aside, and if a restore link still fails it falls back to an identity-checked rename onto the empty path, so the launcher never stays missing.

---------

Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com>
Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Co-authored-by: yobushka <51312852+yobushka@users.noreply.github.com>
@lidge-jun

Copy link
Copy Markdown
Owner

Carried into #7397 (squash dbb908f) on dev with a Co-authored-by trailer, as part of the B5 OAuth/accounts/service hardening bundle. It ships in the next release (2.90.0). Thanks!

@lidge-jun lidge-jun closed this Oct 19, 2026
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.

3 participants