<!-- task=12_real_cli_idle_validation plan=0 tag=RCI -->

# 12 Real CLI Idle Validation Plan - RCI

## 이 파일을 읽는 구현 에이전트에게

**필수: 구현 마지막에는 반드시 `CODE_REVIEW-cloud-G09.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 명령 출력으로 채운다.** 이 task는 11번 full E2E validation 리뷰 FAIL의 큰 후속 작업이다. 범위는 real CLI profile 검증 신뢰 회복, 10분 idle transport regression 확인, 그리고 검증 중 발견된 작은 문서 불일치 수정에 한정한다.

기본 `configs/*.yaml`은 수정하지 않는다. 외부 CLI profile이 실행 불가하면 mock으로 대체하지 말고 profile별 `BLOCKED` 또는 `FAILED`로 기록한다. 검증 출력에는 `...`를 쓰지 말고, 너무 길면 exact command와 저장 로그 경로를 남긴다.

## 배경

11번 review는 `go test`와 mock smoke는 통과했지만, 실행 가능한 real CLI profile 중 gemini만 실행했고 10분 idle monitor는 미실행이었다. 또한 E2E 검증 출력 일부가 생략/요약되어 plan의 stdout/stderr evidence 계약을 충족하지 못했다. `apps/node/README.md`도 07번 이후 구현된 NodeCommand surface를 아직 `USAGE_STATUS`만 지원한다고 설명한다.

## 분석 결과

### 읽은 파일

- `agent-task/11_full_e2e_validation/code_review_cloud_G09_1.log`
- `agent-task/11_full_e2e_validation/plan_cloud_G09_1.log`
- `scripts/e2e-smoke.sh`
- `configs/edge.yaml`
- `apps/node/README.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-ops/skills/project/e2e-smoke/SKILL.md`

### 테스트 커버리지 공백

- `scripts/e2e-smoke.sh`에는 idle wait/monitor 옵션이 없다. 현재는 `/status` 이후 바로 `/exit`로 종료한다.
- `claude`, `gemini`, `codex`, `opencode` command path가 모두 존재하지만 11번에서는 gemini만 실제 smoke를 수행했다.
- 11번 review file은 E2E 출력에 `...`, `(동일한 실행 결과)`, `(매칭 항목 다수)`를 사용해 검증 재현성이 낮다.
- `apps/node/README.md`는 `NodeCommandRequest` 설명에서 `USAGE_STATUS`만 언급한다.

### 심볼 참조

- none. 새 public Go symbol 변경은 계획하지 않는다.

### 범위 결정 근거

- 수정 허용 파일은 `scripts/e2e-smoke.sh`, `apps/node/README.md`, `agent-task/12_real_cli_idle_validation/CODE_REVIEW-cloud-G09.md`이다.
- Real profile 실패가 adapter/runtime 버그로 확인되면 이 task에서 무리하게 고치지 않고 profile별 실패 로그와 별도 후속 필요 범위를 기록한다.
- 기본 `configs/edge.yaml`, `configs/node.yaml`은 임시 config source로만 읽고 수정하지 않는다.

### 빌드 등급

- Build `cloud-G09`: shell/bin orchestration, external CLI, long-running 10분 idle monitor, stdout/stderr evidence 계약이 포함된다.
- Review `cloud-G09`: 긴 로그 신뢰성, profile별 실패 분류, idle marker 검출 방식 재검토가 필요하다.

## 구현 체크리스트

- [ ] [RCI-1] `scripts/e2e-smoke.sh`에 opt-in idle monitor를 추가한다.
- [ ] [RCI-2] 실행 가능한 real CLI profile 전체를 실제 smoke로 검증하고 profile별 결과를 기록한다.
- [ ] [RCI-3] `apps/node/README.md`의 NodeCommand 설명을 현재 구현과 맞춘다.
- [ ] [RCI-4] 검증 결과를 무생략 stdout/stderr 또는 저장 로그 경로로 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

1. RCI-1과 RCI-3을 먼저 구현한다.
2. 빠른 mock idle(`IOP_E2E_IDLE_SECONDS=2`)로 harness가 동작하는지 확인한다.
3. real profiles를 각각 실행한다.
4. 최소 하나의 real profile, 우선 gemini, 에서 `IOP_E2E_IDLE_SECONDS=600` 10분 idle monitor를 수행한다.

### [RCI-1] opt-in idle monitor 추가

#### 문제

`scripts/e2e-smoke.sh:147`부터 `scripts/e2e-smoke.sh:163`까지는 명령 cycle 이후 바로 `/exit`를 보낸다. 10분 idle regression을 검증할 수 있는 옵션이 없다.

#### 해결 방법

- `IDLE_SECONDS="${IOP_E2E_IDLE_SECONDS:-0}"`를 추가한다.
- `/status` 이후 `/exit` 전에 `IDLE_SECONDS > 0`이면 edge/node log line count를 baseline으로 잡고 지정 시간 동안 sleep한다.
- idle window에 새로 추가된 log lines만 검사한다. 금지 marker는 `transport_closed`, `heartbeat_timeout`, `node unregistered`, `disconnected from edge`, `transport_close_reason`이다.
- `/exit` 이후 정상 종료에서 생기는 `transport_closed`는 실패로 세지 않도록 idle window 검사와 기존 final failure marker 검사를 분리한다.

#### 수정 파일 및 체크리스트

- [ ] `scripts/e2e-smoke.sh`에 `IOP_E2E_IDLE_SECONDS` 옵션 추가
- [ ] idle window 전용 marker scan 추가
- [ ] 기존 mock smoke 기본 동작 유지

#### 테스트 작성

별도 Go 테스트는 작성하지 않는다. shell script 동작은 실제 `make test-e2e`로 검증한다.

#### 중간 검증

```bash
IOP_E2E_IDLE_SECONDS=2 make test-e2e
```

Expected: mock smoke PASS. idle window에서 transport close marker가 없어야 한다.

### [RCI-2] real CLI profile 전체 검증

#### 문제

11번에서는 `claude`, `gemini`, `codex`, `opencode` command path가 모두 존재했지만 gemini만 실제 smoke를 수행했다. 풀테스트 기준 real CLI profile 검증이 불완전하다.

#### 해결 방법

- `for c in claude gemini codex opencode; do command -v "$c" || true; done` 결과를 기록한다.
- 각 profile을 독립 실행하고 로그를 `/tmp/iop-rci-<profile>.log` 같은 경로에 저장한다.
- exit 0이면 `PASSED`, command/auth/provider/endpoint 문제면 `BLOCKED`, 실행 error event면 `FAILED`로 기록한다.
- 최소 gemini 또는 사용 가능한 stable profile 하나는 `IOP_E2E_IDLE_SECONDS=600`으로 10분 idle monitor를 수행한다.

#### 수정 파일 및 체크리스트

- [ ] `agent-task/12_real_cli_idle_validation/CODE_REVIEW-cloud-G09.md`에 profile별 command, exit code, 로그 path 기록
- [ ] 10분 idle monitor profile과 결과 기록
- [ ] 실패 profile은 원인과 후속 필요 범위 기록

#### 테스트 작성

테스트 코드는 작성하지 않는다. 외부 CLI 실제 실행 로그가 검증이다.

#### 중간 검증

```bash
for c in claude gemini codex opencode; do command -v "$c" || true; done
mkdir -p /tmp/iop-rci-logs
for p in claude gemini codex opencode; do IOP_E2E_PROFILE="$p" make test-e2e > "/tmp/iop-rci-logs/${p}.log" 2>&1; echo "$p status=$? log=/tmp/iop-rci-logs/${p}.log"; done
IOP_E2E_PROFILE=gemini IOP_E2E_IDLE_SECONDS=600 make test-e2e > /tmp/iop-rci-logs/gemini-idle-600.log 2>&1
```

Expected: profile별 결과가 PASS/FAILED/BLOCKED로 기록된다. 10분 idle monitor는 idle window marker 없이 PASS해야 한다.

### [RCI-3] Node README command 설명 갱신

#### 문제

`apps/node/README.md`는 `NodeCommandRequest`가 현재 `USAGE_STATUS`만 지원한다고 설명한다. 07번 완료 후 node는 `CAPABILITIES`, `SESSION_LIST`, `TRANSPORT_STATUS`도 처리한다.

#### 해결 방법

Node Commands 섹션에 현재 command 목록과 adapter별 지원 경계를 짧게 반영한다.

#### 수정 파일 및 체크리스트

- [ ] `apps/node/README.md`의 `NodeCommandRequest` bullet 갱신
- [ ] `Node Commands` 목록에 `CAPABILITIES`, `SESSION_LIST`, `TRANSPORT_STATUS` 추가

#### 테스트 작성

문서 수정만으로 별도 테스트는 작성하지 않는다. `rg`로 stale 문구 제거를 확인한다.

#### 중간 검증

```bash
rg --sort path -n "현재는 `USAGE_STATUS`|CAPABILITIES|SESSION_LIST|TRANSPORT_STATUS" apps/node/README.md
```

Expected: stale "현재는 `USAGE_STATUS`를 지원한다" 문구가 없어지고 새 command 설명이 보인다.

### [RCI-4] 검증 evidence 무생략 기록

#### 문제

11번 review file은 E2E 출력 일부를 `...`와 요약으로 대체했다. 이는 review 재현성을 떨어뜨린다.

#### 해결 방법

긴 명령은 `/tmp/iop-rci-logs/*.log`로 저장하고, review file에 exact command, exit code, 저장 경로, 핵심 tail/head 또는 full output을 기록한다. 출력 재구성용 `...`는 사용하지 않는다.

#### 수정 파일 및 체크리스트

- [ ] `CODE_REVIEW-cloud-G09.md`에 exact command와 stdout/stderr evidence 기록
- [ ] 너무 긴 로그는 저장 경로와 검증한 marker를 함께 기록
- [ ] `...` 생략이 없는지 최종 검색

#### 테스트 작성

테스트 코드는 작성하지 않는다. evidence format 검증은 `rg`로 확인한다.

#### 중간 검증

```bash
rg --sort path -n "\\.\\.\\.|동일한 실행 결과|매칭 항목 다수" agent-task/12_real_cli_idle_validation/CODE_REVIEW-cloud-G09.md
```

Expected: 구현 소유 검증 결과에 재구성 생략 표현이 없어야 한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `scripts/e2e-smoke.sh` | RCI-1 |
| `apps/node/README.md` | RCI-3 |
| `agent-task/12_real_cli_idle_validation/CODE_REVIEW-cloud-G09.md` | RCI-2, RCI-4 |

## 최종 검증

```bash
go test -count=1 ./...
IOP_E2E_IDLE_SECONDS=2 make test-e2e
for c in claude gemini codex opencode; do command -v "$c" || true; done
mkdir -p /tmp/iop-rci-logs
for p in claude gemini codex opencode; do IOP_E2E_PROFILE="$p" make test-e2e > "/tmp/iop-rci-logs/${p}.log" 2>&1; echo "$p status=$? log=/tmp/iop-rci-logs/${p}.log"; done
IOP_E2E_PROFILE=gemini IOP_E2E_IDLE_SECONDS=600 make test-e2e > /tmp/iop-rci-logs/gemini-idle-600.log 2>&1
git diff -- configs/edge.yaml configs/node.yaml
rg --sort path -n "\\.\\.\\.|동일한 실행 결과|매칭 항목 다수" agent-task/12_real_cli_idle_validation/CODE_REVIEW-cloud-G09.md
```

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
