Repository navigation
[Feature]: extract proxy process-state ownership from config persistence #2378
Description
Area
Service lifecycle
What are you trying to accomplish?
Separate live proxy process-state ownership from persisted configuration ownership without changing startup, shutdown, status, service, update, or stale-state cleanup behavior.
What prevents this today?
src/config.ts owns both persisted config loading/writes and the live process records used by the proxy: ocx.pid, runtime-port.json, PID parsing, liveness checks, command-line identity verification, and snapshot-guarded cleanup. Internal callers that need only process state therefore depend on the broad config persistence module, and lifecycle correctness tests remain mixed into config tests.
The ownership is also split across distant parts of the file: path helpers and PID/runtime-port I/O are not one contiguous block. A mechanical extraction must therefore be guided by symbols and tests rather than line ranges.
What should OpenCodex do?
- Introduce one leaf module for proxy process state under the existing config namespace, without creating a second runtime implementation.
- Move the PID/runtime-port path helpers,
RuntimePortState, read/write/remove helpers, PID parsing, cheap liveness probe, command-line recognition, and full identity verification into that module. - Keep
src/config.tsas a compatibility facade that re-exports the existing public symbols during the migration window. - Migrate internal CLI, service, update, doctor, liveness, and restart callers to the leaf module in the same focused PR.
- Move process-state characterization into a dedicated test file while retaining config-path coverage where config ownership is the behavior under test.
- Update
structure/01_runtime.mdandstructure/02_config-and-codex-home.mdto name the process-state owner and the boundary withOPENCODEX_HOMEresolution.
Required invariants:
ocx.pidandruntime-port.jsonpaths and serialized shapes stay compatible, includingRuntimePortState.attestationSecret.readPid()continues to require liveness plus the OCX start-command identity;readAlivePid()remains the cheap non-destructive probe; destructive callers continue to useverifyPidIdentity().EPERM, WMIC-to-PowerShell fallback, Unixps, timeouts, and the per-PID memo remain unchanged.- expected-PID and snapshot-guarded removals keep their existing TOCTOU protections.
- writes continue through the existing atomic writer and config-directory hardening.
- no persisted config schema, provider, routing, GUI, or wording behavior changes.
Example usage or interface
import {
readAlivePid,
readRuntimePort,
verifyPidIdentity,
} from "./config/process-state";Existing downstream imports remain valid for one migration window:
import { readAlivePid } from "./config";Acceptance criteria:
- Characterization covers path resolution, malformed PID/runtime records, expected-PID filtering, concurrent rewrite guards,
EPERM, command-line recognition, and destructive identity verification. - The dedicated process-state tests, remaining config tests, stale-state purge, proxy liveness/port reclaim, strict typecheck, and the full Bun suite are evaluated on the exact PR head.
- The leaf is the sole implementation;
src/config.tscontains compatibility re-exports only.
Alternatives or workarounds
- Leave process state in
src/config.ts: lowest churn, but preserves unrelated filesystem/process coupling. - Move callers without a compatibility facade: rejected because external tests and downstream imports may rely on the existing exports.
- Create
src/runtime/for this one leaf: possible later, but a new namespace is unnecessary for a behavior-preserving first slice;src/config/process-state.tskeeps path-resolution dependencies local and reviewable.
Additional context
[Decision Log]
- Purpose: isolate live process ownership from persisted config ownership without changing runtime behavior.
- Existing constraints: process state depends on the resolved OpenCodex home, atomic writes, directory hardening, and cross-platform process identity checks.
- Alternatives considered: keep the mixed module, perform a flag-day import rewrite, or introduce a second abstraction while retaining old helpers.
- Chosen approach: one leaf implementation under
src/config/, compatibility re-exports, characterization first, then internal import migration. - Why: it reduces dependency breadth while preserving one source of truth and the current lifecycle contract.
- Tradeoff: a temporary facade remains, but the PR stays mechanical and independently reviewable from provider validation work.
This is separate from #2379 and should land in its own PR to keep two high-risk shared-module moves independently reviewable.
Checks
- I searched existing issues and documentation.
- This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
- I removed secrets and personal data.
Activity
lidge-jun commentedon Aug 22, 2026
리뷰 · 우선순위 46 / 80
설명: 이 이슈는 설정 파일 일과 프록시가 살아 있는지 보는 일을 src/config.ts 에서 가르자고 한다. 지금 CURRENT
devHEAD 는378d889c5이다. 이번 시간에 origin/dev 가 af5dd16 에서 여기로 옮겼다. 착지한 코드는 #2359 호출 불가 모델 제외(Closes #2330), #2376 번 1.4 메모리 문서+하니스, #2377 WP7 기록이다. package.json 은 2.27.0 이다. 지금 HEAD 의 src/config.ts 는 3975줄이다. 이슈가 말한 약 240줄짜리 한 덩어리는 지금 파일이 아니다. getPidPath 와 getRuntimePortPath 는 1663줄 근처다. writePid 는 3446줄이다. verifyPidIdentity 는 3862줄이다. 경로 헬퍼와 실제 읽기쓰기가 떨어져 있다. resolvePidPath 는 624줄이다. src/runtime 폴더는 지금 HEAD 에 없다. 이미 있는 잎은 src/config/provider-name.ts 와 src/types.ts 배럴+src/types/* 이다. RuntimePortState 에는 attestationSecret 이 있다. 이 값은 설정 디렉터리로 보호하고 밖으로 안 보낸다. readPid 는 살아 있음과 ocx 시작 명령 확인을 같이 한다. readAlivePid 는 싼 확인만 한다. 지우는 쪽은 verifyPidIdentity 를 쓴다. EPERM, 윈도 WMIC 다음 파워셸, 유닉스 ps, PID 메모, 스냅샷 가드 삭제가 여기 있다. 호출자는 src/cli/index.ts 시작과 종료, src/cli/status.ts, src/cli/doctor.ts, src/service.ts, src/update/index.ts 와 job.ts 다. 테스트는 tests/config.test.ts 와 tests/stale-state-purge.test.ts, tests/proxy-liveness.test.ts 에 섞여 있다. 이슈는 동작을 바꾸지 말라고 했다. 시작 설계를 다시 하지 말라고 했다. config.ts 를 호환 창구로 남겨 공개 이름을 한동안 재수출하라고 했다. 사용자 길이 버그가 아니라 모듈 경계 일이라서 46.src/config.ts 라인 1663 - getPidPath. 이슈의 240줄 덩어리 시작으로 적힌 자리. 실제 쓰기는 훨씬 아래다
src/config.ts 라인 3446 - writePid. 설정 디렉터리 가드와 atomicWriteFile 을 쓴다. 설정 저장과 같은 파일을 만진다
src/config.ts 라인 3458 - RuntimePortState. attestationSecret 이 있다. 옮길 때 이 필드를 빠뜨리면 안 된다
src/config.ts 라인 3843 - readAlivePid 는 싼 확인. 라인 3862 verifyPidIdentity 는 지우는 쪽 확인. 둘을 합치면 안 된다
src/runtime - 지금 HEAD 에 폴더가 없다. 이슈가 예시로 든 경로는 새로 만들어야 한다
메인테이너의 판단이 필요한 지점
너의 추천
새 PR 을 연다. 먼저 특징 테스트를 옮기고, 그다음 잎 하나와 config.ts 재수출만 넣는다. 동작은 한 줄도 바꾸지 않는다. src/runtime 은 지금 없으니 폴더를 만들지 기존 src/config 패턴을 따를지는 메인테이너가 고른다. #2379 와 같은 PR 에 넣지 않는다. 지금 닫지 말 것. types.ts 스플릿과 겹치면 닫고 리베이스하지 않는다. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.
이 댓글은 grok-bot이 작성했습니다
[-][Architecture]: extract proxy process-state ownership from config.ts without behavior changes[/-][+][Feature]: extract proxy process-state ownership from config persistence[/+]Ingwannu commentedon Aug 22, 2026
Implemented the behavior-preserving extraction in draft PR #2387 against
dev.The PR keeps
src/config.tsas the compatibility facade, moves the single implementations intosrc/config/{paths,atomic-write,process-state}.ts, migrates lifecycle-only callers, adds dedicated process-state characterization, and updates the runtime/config structure documents.Exact-head verification completed:
git diff --check: passedtests/request-pacing.test.tspasses 14/14 on both the PR head and clean currentdevwhen rerun in isolationI left the PR as draft and requested @lidge-jun because the author cannot approve or merge their own PR. This is a TypeScript compatibility/import-boundary refactor on the repository's sole integration line,
dev.lidge-jun commentedon Aug 23, 2026
Closed by #2387, squash-merged to
devas b6c7c0a.OpenCodex-home paths, atomic writes, and PID/runtime-port ownership now live in three acyclic config leaf modules, with
src/config.tsretaining its compatibility exports. Lifecycle, management, service, OAuth, and update callers import process state directly and their destructive identity checks are unchanged. Independent review found no dropped runtime export, no import cycle, and no core-to-Lab edge; 472 pass / 0 fail across eight suites, a synthesized current-dev merge at 473 / 0 with typecheck green, and CI 29 pass.Two test-ownership follow-ups are recorded in the devlog rather than held against the refactor:
tests/process-state.test.tsdoes not yet exercisereadAlivePid(),verifyPidIdentity(), or the EPERM behavior this issue asked for, andtests/config.test.ts:2216still duplicates process-state characterization.Closing by hand because PRs here target
dev.lidge-jun commentedon Aug 23, 2026
Landed via #2387 at b6c7c0a