Skip to content

[Bug]: status and doctor ignore an identity-verified live proxy when ocx.pid is missing #618

Description

@luvs01

Client or integration

Codex CLI

Area

CLI

Summary

When the proxy is healthy and identity-verified through runtime-port.json plus /healthz, but ocx.pid is missing or stale, OpenCodex's own findLiveProxy() correctly finds the live process. However, ocx status --json reports proxy.running: false with pid: null, and ocx doctor reports that no proxy is running and recommends a restart.

I expected read-only diagnostics to use the same identity-verified liveness result as lifecycle and OAuth-health paths. A missing PID file should remain a separate warning; it should not turn a verified live proxy into a stopped one.

This matters because status --json is the machine-readable diagnostics contract, doctor suppresses live service memory/runtime information, and the restart hint is incorrect while the service is healthy.

Reproduction

This state was observed after normal Windows Task Scheduler service operation. No PID or runtime file was removed for this report.

Environment state:

~/.opencodex/ocx.pid: absent
runtime-port.json: {"pid":39196,"port":10100}
process 39196: alive, OpenCodex Bun CLI, start --port 10100
GET /healthz: service=opencodex, version=2.7.42, pid=39196, port=10100
  1. Confirm the identity-verified liveness helpers find the proxy:

    findLiveProxy()      -> {"pid":39196,"port":10100}
    ocx health --json    -> {"ok":true,"pid":39196,"port":10100}
    
  2. Run ocx status --json.

  3. Observe that the same response says both running:false and health.ok:true:

    {
      "proxy": {
        "running": false,
        "pid": null,
        "health": {
          "ok": true,
          "url": "http://127.0.0.1:10100/healthz",
          "message": "ok v2.7.42, uptime ..."
        }
      }
    }
  4. Run ocx doctor.

  5. Observe:

    no running ocx proxy process found
    no running ocx proxy found (no live pid/runtime record)
    The ocx proxy is not running ... Restart it ...
    

The OAuth-health section in that same doctor run did not claim the proxy was unavailable because that path already uses findLiveProxy(), so doctor is internally inconsistent.

A fallback-port orphan can be worse: status ignores the runtime target and may report both running:false and health.ok:false, along with the wrong health/dashboard URL.

Version

  • Released package: @bitkyc08/opencodex 2.7.42
  • Also reproduced against current dev: ca7b1049f6c198311ae260e8f1db019fcc759877

The relevant status, doctor, and liveness source is unchanged between the installed package and this dev revision.

Operating system

Microsoft Windows 11 Pro 25H2, x64 (build 26200.8894)

Provider and model

Not provider-specific.

Logs or error output

# ocx status --json
"proxy":{"running":false,"pid":null,"health":{"ok":true,"url":"http://127.0.0.1:10100/healthz","message":"ok v2.7.42, uptime ..."}}

# ocx doctor
no running ocx proxy process found
no running ocx proxy found (no live pid/runtime record)
The ocx proxy is not running ... Restart it ...

Screenshots and supporting files

Current dev source:

  • src/server/proxy-liveness.ts:93-143: findLiveProxy() intentionally recovers from a missing/corrupt PID file using the runtime record, then verifies OpenCodex health identity and the expected PID.
  • tests/proxy-liveness.test.ts:95-109: an existing regression explicitly expects an orphaned runtime record to be adopted.
  • src/cli/status.ts:132-137,231-246: status calls readPid(), only reads runtime state when that succeeds, and defines JSON running as Boolean(pid && health.ok).
  • src/cli/doctor.ts:396-399,745-757,815-822: doctor independently treats a missing PID file as stopped, suppresses live runtime diagnostics, and emits the restart hint.
  • src/oauth/health.ts:323-335: the OAuth doctor path already uses findLiveProxy(), causing the internal contradiction.

Redacted configuration

{
  "listenPort": 10100,
  "serviceBackend": "scheduler",
  "providerSpecific": false
}

Checks

  • I searched open and closed issues and pull requests for runtime-port.json, ocx.pid, findLiveProxy, the emitted doctor messages, and orphan-proxy combinations.
  • I removed secrets, tokens, account details, request credentials, personal paths, usernames, and response contents.

Root cause

findLiveProxy() already implements the safe orphan-recovery contract: a runtime record is discovery-only and must pass OpenCodex /healthz identity and expected-PID checks before it is returned. Status and several doctor sections bypass that helper and require readPid() first, so they discard the verified orphan-recovery result.

Suggested safe direction

Use identity-checked findLiveProxy() for read-only status and doctor discovery, while preserving readPid() or equivalent strict ownership checks for destructive actions. Never trust runtime-port.json by itself.

Keep “PID file missing or stale” as a separate diagnostic rather than mapping it to running:false. Suggested regressions:

  1. status --json reports a verified orphan proxy as running with its resolved PID and port.
  2. Doctor uses its live process/runtime endpoint and does not emit the stopped/restart hint.
  3. A stale runtime record or foreign listener remains rejected.
  4. An identity-verified orphan on a fallback port supplies the correct health and dashboard URLs.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions