Repository navigation
Description
Client or integration
Codex CLI
Area
Service lifecycle
Summary
A Remote Link Child can keep serving as a connected client from an in-memory connection snapshot after its durable client record has disappeared from config.json. The Home sees the tunnel as connected, the relayed catalog matches, and the Child's /readyz reports link: available, but every CLI on the Child reads ocx connect status --json as disconnected. The Home's pinned ocx sync --expect-link <id> is therefore refused with child-link-mismatch:disconnected (exit 5) on every run.
The supported recovery path also fails: the Child refuses ocx disconnect (and GOAT's re-link, which disconnects first) because there is no client record to tear down, while the link token and the running client runtime remain. The machine is stuck until someone hand-cleans state.
Expected: either the runtime notices its durable record is gone and stops serving as a client (or reports the divergence in status/readyz), or ocx disconnect can tear down an orphaned link token and runtime so the Home can re-link.
Reproduction
Observed on a macOS Child (Desktop 2.93.0):
- Child linked to a Home; Desktop runtime started on Oct 28 and kept running.
- On Nov 4 the default
~/.opencodex/config.jsonwas replaced (writer not yet identified); it now has neitherclientnorruntimeRole. No pending-connect marker. - Child
GET /healthzreportsrole: client, same PID as before;GET /readyzreportsstatus: ready,link.state: available. - Child
ocx connect status --json(both the Desktop shim and the app-bundled CLI):state: disconnected. - Home
ocx sync --json: that Child skipped aschild-link-mismatch:disconnected, exit 5 from the remote command; overall exit 0. - Re-link through disconnect: Child refuses the connection change.
Source anchors: src/client/runtime.ts reads connected state once at startup and passes the snapshot to the listener; src/client/machine-listener.ts retains it and /readyz reports availability rather than durable ownership; src/client/state.ts readClientConnectionState returns disconnected for a config with no client/role; src/client/sync-expectation.ts correctly refuses on that verdict.
Version
Child 2.93.0 (Desktop); Home 2.97.0; source checked at dev 553a621
Operating system
macOS (Child and Home)
Provider and model
No response
Logs or error output
Home ocx sync --json child row:
{"linkId":"lnk_…","state":"skipped","reason":"child-link-mismatch:disconnected","exit":5}
Re-link: disconnect step failed: refused the connection changeScreenshots and supporting files
No response
Redacted configuration
{"runtimeRole": "<absent>", "client": "<absent>"}Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
github-actions commentedon Nov 6, 2026
Automated translation bookkeeping — detected language: English.
lidge-jun commentedon Nov 6, 2026
Part 1 landed on dev via #8249 (cdb64a9): a Remote Link Child now reports
client_state_changedin readiness and status when its saved connection no longer matches the runtime startup snapshot. The operator recovery path and theocx config importguard are in #8253 (security review in progress). Keeping this issue open until that lands.lidge-jun commentedon Nov 7, 2026
Fixed on dev by #8249 (cdb64a9: readiness/status report
client_state_changedwhen the saved connection no longer matches the runtime) and #8253 (ebeb1dc: operator-confirmedocx disconnect --orphaned-token --yesmoves an orphaned link token into a private backup, refusing on a Hub, non-loopback binds, admission credentials or installed services;ocx config importno longer replaces a connected client record). Security review passed.chore(pr-assets): add #8243 client_state_changed dashboard banner
fix(link): follow up orphan-token and client_state_changed reviews (#…