Skip to content

[Bug]: Update recovery can replace a managed service with an unsupervised detached proxy #7043

Closed

Description

@flokosti96

Client or integration

Other

Area

Service lifecycle

Summary

If background-service repair fails or is judged non-viable after ocx update, the updater falls back to a detached proxy (src/update/index.ts:554-579, invoked from :904-959) and treats a healthy endpoint as full recovery. The process is no longer supervised by launchd/systemd: a crash is not restarted, and the next launchctl kickstart races with the detached process for the port.

Reproduction

From the 2.84.0 source path, with an isolated install or mocked service backend:

  1. Start with an installed, managed service.
  2. Run update recovery with service repair failing and the listen port free.
  3. Let the direct-start fallback pass its identity/health probe.
  4. Compare the serving PID with the PID registered in the launchd job.

We did not break our live hub to reproduce this; we guard against it in a wrapper by checking that the launchd job PID equals ~/.opencodex/ocx.pid after every update and restarting through launchd otherwise.

Version

@bitkyc08/opencodex 2.84.0

Operating system

macOS 27 (launchd); Linux/systemd follows the same code path.

Provider and model

n/a

Logs or error output

The fallback deletes OCX_SERVICE, spawns with detached: true and unref(), then only verifies serving identity.

Redacted configuration

Hub mode, LaunchAgent com.opencodex.proxy.

Proposed fix

For an originally managed service prefer manager-mediated recovery (launchctl kickstart -k / systemctl --user restart). If a detached emergency start stays intentional, return an explicit degraded-supervision result with a non-zero exit code instead of reporting recovery as complete, and add a regression that checks the manager PID against the serving PID.

Related: #4141, #4236, #4173.

Screenshots and supporting files

No response

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    platformOS/service/tray/ACL (Windows-heavy, not Windows-only)
    serviceService lifecycle (WinSW/launchd/scheduler)
    on Oct 13, 2026
  2. lidge-jun commented on Oct 13, 2026

    @lidge-jun
    Owner

    Fixed on dev by #7074 (b54a21c). After a failed or non-viable post-update service refresh, both ocx update lanes first ask launchd (kickstart -k) or systemd (systemctl --user restart) to restart the job. Recovery counts only when the serving PID is the manager's main PID or its direct child. Otherwise the detached fallback runs with an UNSUPERVISED warning and the update exits non-zero. A manager restart that is still pending starts no competing proxy. The dashboard update worker (src/update/job.ts) keeps its own fallthrough for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplatformOS/service/tray/ACL (Windows-heavy, not Windows-only)serviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions