<!-- task=m-codex-app-server-streaming-migration/01_appserver_rpc_client plan=0 tag=API -->
# Code Review Reference - API

> 구현 에이전트 경고: 이 파일은 구현 마지막 단계에서 반드시 갱신한다. `구현 완료 기록`, `구현 체크리스트`, `검증 출력`을 실제 내용으로 채우기 전에는 작업 완료를 선언하지 않는다.

## 개요
- 날짜: 2026-06-12
- Task: `m-codex-app-server-streaming-migration/01_appserver_rpc_client`
- Plan: `PLAN-cloud-G07.md`
- Tag: `API`

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/codex-app-server-streaming-migration.md`
- Task ids:
  - `mode-router`: CLI adapter에 `codex-app-server` mode를 추가하고 executor/session reporter 라우팅을 분리한다.
  - `rpc-lifecycle`: `codex app-server --stdio` 프로세스를 시작한 뒤 `initialize`, `initialized`, `thread/start`, `turn/start` 흐름을 안정적으로 처리한다.
- Completion mode: check-on-pass

## 리뷰 에이전트 지침
- `PLAN-cloud-G07.md`를 먼저 읽고 구현 범위가 plan을 넘지 않았는지 확인한다.
- app-server RPC가 newline JSON `{id, method, params}` 형태인지 확인한다.
- process lifecycle, context cancel, duplicate close, request id response matching을 우선 리뷰한다.
- archive는 명시 요청 없이 읽지 않는다.

## 구현 완료 기록
| 항목 | 구현 에이전트 기록 |
| --- | --- |
| 변경 요약 | `modeCodexAppServer` 상수 추가, `codexAppServerExecutor`/`codexAppServerSession`/`codexAppServerProc` 신규 구현, CLI router/reporter 연결, `shouldAutostartPersistentProfile` 제외 처리, newline-delimited JSON RPC (id/method/params, jsonrpc 없음) stdin/stdout 구현, initialize→initialized→thread/start 시퀀스, sync.Once 기반 중복 close 방어 |
| 주요 파일 | `apps/node/internal/adapters/cli/cli.go` (API-1), `apps/node/internal/adapters/cli/codex_app_server.go` (API-2, API-3, 신규), `apps/node/internal/adapters/cli/cli_internal_test.go` (API-1 테스트), `apps/node/internal/adapters/cli/codex_app_server_internal_test.go` (API-2, API-3 테스트, 신규) |
| 범위 외 변경 여부 | 없음. `handleSessionList` 스냅샷 테스트 기댓값만 새 executor 반영으로 업데이트 |
| 남은 리스크 | `codexAppServerInit`의 `thread/start` 응답에서 threadId 필드명이 실제 Codex CLI 버전에 따라 다를 수 있음 (`threadId` vs `id` 둘 다 처리함). 실제 CLI 연결 검증은 cloud-G07 등급으로 local/cloud runner 필요 |

## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
| --- | --- |
| API-1 새 mode를 CLI adapter 라우터에 연결 | 완료 |
| API-2 app-server stdio 프로세스와 RPC lifecycle 구현 | 완료 |
| API-3 세션 시작의 최소 골격까지 연결 | 완료 |

## 구현 체크리스트
- [x] `codex app-server --stdio`용 mode 상수와 executor/session 타입을 추가한다.
- [x] `CLI.New`, `executorFor`, `sessionReporterFor`, `shouldAutostartPersistentProfile`, `Stop`에 새 executor를 연결한다.
- [x] newline JSON RPC request writer와 response/notification reader를 구현한다.
- [x] `initialize` request와 `initialized` notification을 startup sequence로 검증한다.
- [x] process close가 중복 호출과 context cancel에서 안전하게 동작하게 한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드 리뷰 전용 체크리스트
- [ ] `codex-exec` 기존 경로가 회귀하지 않았다.
- [ ] app-server mode가 legacy persistent startup으로 들어가지 않는다.
- [ ] request/notification reader goroutine 누수가 없다.
- [ ] 실패 시 runtime error 또는 Go error가 호출자에게 관측 가능하다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._

- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

## 검증 출력
```text
$ go test ./apps/node/internal/adapters/cli -count=1 -timeout=60s
ok  	iop/apps/node/internal/adapters/cli	42.513s

$ go test ./apps/node/... -count=1 -timeout=120s
ok  	iop/apps/node/cmd/node	0.009s
ok  	iop/apps/node/internal/adapters	0.008s
ok  	iop/apps/node/internal/adapters/cli	42.541s
?   	iop/apps/node/internal/adapters/cli/internal/testutil	[no test files]
ok  	iop/apps/node/internal/adapters/cli/status	39.840s
?   	iop/apps/node/internal/adapters/mock	[no test files]
ok  	iop/apps/node/internal/adapters/ollama	0.007s
ok  	iop/apps/node/internal/adapters/vllm	0.007s
ok  	iop/apps/node/internal/bootstrap	0.262s
ok  	iop/apps/node/internal/node	0.118s
ok  	iop/apps/node/internal/router	0.005s
?   	iop/apps/node/internal/runtime	[no test files]
ok  	iop/apps/node/internal/store	0.045s
ok  	iop/apps/node/internal/terminal	0.444s
ok  	iop/apps/node/internal/transport	5.133s
```

## 리뷰어 체크포인트
- `go test ./apps/node/internal/adapters/cli -count=1`
- `go test ./apps/node/... -count=1`

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - Correctness: Fail
  - Completeness: Fail
  - Test coverage: Fail
  - API contract: Fail
  - Code quality: Pass
  - Plan deviation: Fail
  - Verification trust: Fail
- 발견된 문제:
  - Required - `apps/node/internal/adapters/cli/codex_app_server.go:285`: `send`가 response channel과 `p.done`을 같은 `select`에서 기다리기 때문에, 서버가 정상 response를 쓴 직후 stdout을 닫으면 response가 이미 도착했어도 `process exited`가 선택될 수 있습니다. 실제로 `go test ./apps/node/internal/adapters/cli -run '^TestCodexAppServerSend_RequestIDMonotone$' -count=20 -timeout=30s`가 `send 2: codex app-server process exited`로 실패했습니다. `p.done` 분기에서 먼저 pending response를 비차단으로 확인하거나, response dispatch와 process-exit close 순서를 조정해 이미 받은 response를 우선 반환하도록 고치고 회귀 테스트를 안정화하세요.
  - Required - `apps/node/internal/adapters/cli/codex_app_server.go:341`: `thread/start` 응답에서 `threadId`/`id`가 모두 비어도 `codexAppServerInit`이 빈 thread id를 성공으로 반환합니다. 계획은 `thread/start`까지 호출해 Codex thread id를 session에 저장하는 것이므로, thread id가 없으면 명시적 error를 반환하고 missing-id 테스트를 추가하세요.
- 다음 단계: WARN/FAIL 후속 `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성한다.

### 리뷰 중 실행한 검증

```text
$ go test ./apps/node/internal/adapters/cli -run 'TestCodexAppServer|TestExecutorForMode|TestCLIStartSkipsCodexAppServerPersistentStartup|TestHandleSessionList' -count=1 -timeout=60s
ok  	iop/apps/node/internal/adapters/cli	0.004s

$ go test ./apps/node/internal/adapters/cli -count=1 -timeout=60s
--- FAIL: TestCodexAppServerSend_RequestIDMonotone (0.00s)
    codex_app_server_internal_test.go:341: send 2: codex app-server process exited
FAIL
FAIL	iop/apps/node/internal/adapters/cli	42.498s
FAIL

$ go test ./apps/node/internal/adapters/cli -run '^TestCodexAppServerSend_RequestIDMonotone$' -count=20 -timeout=30s
--- FAIL: TestCodexAppServerSend_RequestIDMonotone (0.00s)
    codex_app_server_internal_test.go:341: send 2: codex app-server process exited
FAIL
FAIL	iop/apps/node/internal/adapters/cli	0.004s
FAIL

$ go test ./apps/node/... -count=1 -timeout=120s
ok  	iop/apps/node/cmd/node	0.009s
ok  	iop/apps/node/internal/adapters	0.008s
ok  	iop/apps/node/internal/adapters/cli	42.540s
?   	iop/apps/node/internal/adapters/cli/internal/testutil	[no test files]
ok  	iop/apps/node/internal/adapters/cli/status	39.878s
?   	iop/apps/node/internal/adapters/mock	[no test files]
ok  	iop/apps/node/internal/adapters/ollama	0.007s
ok  	iop/apps/node/internal/adapters/vllm	0.007s
ok  	iop/apps/node/internal/bootstrap	0.265s
ok  	iop/apps/node/internal/node	0.118s
ok  	iop/apps/node/internal/router	0.005s
?   	iop/apps/node/internal/runtime	[no test files]
ok  	iop/apps/node/internal/store	0.040s
ok  	iop/apps/node/internal/terminal	0.436s
ok  	iop/apps/node/internal/transport	5.144s
```

## 코드리뷰 전용 종결 체크리스트

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append했다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-cloud-G07.md`를 `code_review_cloud_G07_0.log`로 아카이브했다.
- [x] active `PLAN-cloud-G07.md`를 `plan_cloud_G07_0.log`로 아카이브했다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인했다.
- [x] WARN/FAIL이고 user-review gate가 트리거되지 않았으므로 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않았다.
