<!-- task=m-agent-readable-repository-refactor/06_cli_adapter plan=2 tag=REVIEW_REVIEW_REFACTOR_ADAPTER_CLI -->

# CLI adapter baseline·검증 신뢰 재복구 계획

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

검증 실행과 active `CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션 작성이 구현의 마지막 단계다. 실제 구현 내용, 계획 대비 변경, 설계 결정, 명령별 stdout/stderr를 채운 뒤 active 파일을 그대로 두고 리뷰 준비 완료를 보고한다. 최종 판정, log rename, `complete.log`, task archive는 code-review 전용이다.

선택된 Milestone의 `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 review stub의 `사용자 리뷰 요청`에 정확한 연결 대상과 근거를 기록하고 중단한다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하거나 `USER_REVIEW.md`를 만들거나 active 파일을 archive하거나 `complete.log`를 쓰지 않는다. 외부 CLI 로그인·provider·endpoint·secret·service 준비, 일반 범위 충돌, 반복 실패, 검증 증거 공백은 사용자 리뷰 요청이 아니라 검증 blocker 또는 다음 follow-up 근거다.

## 배경

두 번째 리뷰에서도 package/Node 회귀와 HEAD 기준 CLI ratchet 자체는 통과했지만 command builder 중복과 경계 테스트 공백, 이전 루프가 만든 baseline 상향 항목이 남았다. 더 중요하게는 기록된 test stdout이 실제 소스·재실행과 일치하지 않았고, 현재 runner에 설치된 `claude`, `codex`, `opencode`를 모두 미설치로 기록해 필수 full-cycle evidence를 대체했다. 이 follow-up은 소스 보완과 검증 신뢰 복구를 함께 닫는다.

## 사용자 리뷰 요청 흐름

구현 에이전트는 선택된 Milestone lock 결정만 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식의 active review `사용자 리뷰 요청`에 기록한다. 직접 사용자 prompt는 금지하며, code-review가 요청의 정당성을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## Archive Evidence Snapshot

- Prior plan: `agent-task/m-agent-readable-repository-refactor/06_cli_adapter/plan_cloud_G08_1.log`
- Prior review: `agent-task/m-agent-readable-repository-refactor/06_cli_adapter/code_review_cloud_G08_1.log`
- Verdict: `FAIL`
- Issue summary: Required 4, Suggested 0, Nit 0.
- Required:
  - context/non-context command builder가 env/cwd 적용을 중복하고 새 경계 테스트가 command/path와 args를 검증하지 않음.
  - 이전 실패 루프의 증가·신규 CLI readability baseline 항목이 남아 있음.
  - 기록된 fresh test 이름과 stdout이 실제 source 및 reviewer rerun과 일치하지 않음.
  - 현재 PATH에 있는 `claude`, `codex`, `opencode`를 미설치로 기록해 실제 profile full-cycle을 수행하지 않음.
- Affected files: `apps/node/internal/adapters/cli/command.go`, `apps/node/internal/adapters/cli/cli_workspace_test.go`, `scripts/readability_baseline.json`, active review stub.
- Reviewer verification:
  - `go test -count=1 ./apps/node/...` PASS.
  - 정확한 `^TestCLIBuildCmdWithoutContextAppliesEnvAndCwd$` rerun PASS, 그러나 archived review의 정규식에서는 이 테스트가 실행되지 않았음.
  - `make readability-audit`, HEAD baseline 기준 `cli_regressions=0`, `gofmt -d`, `git diff --check` PASS.
  - 현재 command inventory: `claude=/config/.npm-global/bin/claude` (`2.1.212`), `codex=/config/.npm-global/bin/codex` (`0.144.5`), `opencode=/config/.npm-global/bin/opencode` (`1.18.3`), `antigravity` 미발견.
- 추가 세부 문맥이 필요할 때만 위 두 prior log를 좁게 읽는다. `agent-task/archive/**`를 탐색하지 않는다.
- Roadmap carryover: 없음. prior plan/review에 `Roadmap Targets`가 없으며 이 follow-up도 특정 Milestone Task 완료 체크를 주장하지 않는다.

## 분석 결과

### 읽은 파일

- 규칙/라우팅:
  - `agent-ops/rules/project/rules.md`
  - `agent-ops/rules/common/rules-roadmap.md`
  - `agent-ops/rules/project/domain/node/rules.md`
  - `agent-ops/rules/project/domain/testing/rules.md`
  - `agent-ops/rules/common/rules-agent-spec.md`
  - `agent-ops/skills/common/router.md`
  - `agent-ops/skills/common/code-review/SKILL.md`
  - `agent-ops/skills/common/plan/SKILL.md`
  - `agent-ops/skills/project/e2e-smoke/SKILL.md`
  - `agent-test/local/rules.md`
  - `agent-test/local/node-smoke.md`
  - `agent-test/local/testing-smoke.md`
- roadmap/spec/contract:
  - `agent-roadmap/current.md`
  - `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
  - `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-readable-repository-refactor.md`
  - `agent-spec/index.md`
  - `agent-spec/runtime/edge-node-execution.md`
  - `agent-contract/index.md`
  - `agent-contract/inner/edge-node-runtime-wire.md`
- source/data:
  - `apps/node/internal/adapters/cli/command.go`
  - `apps/node/internal/adapters/cli/workspace.go`
  - `apps/node/internal/adapters/cli/profile.go`
  - `apps/node/internal/adapters/cli/cli.go`
  - `apps/node/internal/adapters/cli/oneshot.go`
  - `apps/node/internal/adapters/cli/codex_app_server.go`
  - `apps/node/internal/adapters/cli/codex_app_server_process.go`
  - `apps/node/internal/adapters/cli/opencode_sse.go`
  - `apps/node/internal/adapters/cli/opencode_sse_events.go`
  - `apps/node/internal/adapters/cli/persistent.go`
  - `apps/node/internal/adapters/cli/persistent_process.go`
  - `apps/node/internal/adapters/cli/emitters.go`
  - `apps/node/internal/adapters/cli/emitter_stream_json.go`
  - `apps/node/internal/adapters/cli/emitter_profile_json.go`
  - `apps/node/internal/adapters/cli/persistent_output_filter.go`
  - `apps/node/internal/adapters/cli/persistent_output_filter_terminal.go`
  - `apps/node/internal/adapters/cli/persistent_output_filter_claude.go`
  - `apps/node/internal/adapters/cli/persistent_output_filter_claude_helpers.go`
  - `scripts/readability_baseline.json`
  - `scripts/readability_audit.py`의 audit/ratchet identity·comparison 구간
  - `scripts/dev/edge.sh`
  - `scripts/dev/node.sh`
  - `configs/edge.yaml`
  - `configs/node.yaml`
- tests/review evidence:
  - `apps/node/internal/adapters/cli/cli_workspace_test.go`
  - `agent-task/m-agent-readable-repository-refactor/06_cli_adapter/plan_cloud_G08_1.log`
  - `agent-task/m-agent-readable-repository-refactor/06_cli_adapter/code_review_cloud_G08_1.log`

### SDD 기준

선택 Milestone은 `SDD: 불필요`다. 외부 API/proto/config schema나 runtime 책임 경계를 바꾸지 않고 동일 package 내부 helper/test와 readability baseline/evidence만 보정하는 동작 보존형 follow-up이다.

### 테스트 환경 규칙

- `test_env=local`.
- `agent-test/local/rules.md`가 존재해 읽었고 `agent-test/local/node-smoke.md`, `agent-test/local/testing-smoke.md`를 적용한다.
- fresh output이 핵심이므로 모든 필수 Go 명령에 `-count=1`을 사용하고 stdout/stderr를 실제 실행에서 직접 기록한다.
- 대상 package, `./apps/node/...`, readability current/HEAD ratchet, `gofmt -d`, `git diff --check`를 deterministic 검증으로 사용한다.
- 사용자 실행 pipeline 검증은 `e2e-smoke mode=real-cli`, `profiles=claude,antigravity,codex,opencode`의 실제 Edge/Node entrypoint 절차를 따른다.

테스트 환경 프리플라이트:

- runner/workdir: 현재 local runner, `/config/workspace/iop`.
- branch/HEAD/dirty state: detached branch(`git branch --show-current` 무출력), HEAD `57f0eaa71766a2b4eb53a94ec4df60a577d4a760`, 여러 split subtask가 공유하는 dirty worktree. 다른 subtask 변경을 되돌리거나 baseline 전체로 덮어쓰지 않는다.
- source sync: 현재 worktree를 `go run`/fresh build로 직접 실행하고 stale binary를 재사용하지 않는다.
- command inventory: `claude`, `codex`, `opencode`는 위 Archive Evidence Snapshot의 절대 경로와 version으로 가용하고 `antigravity`만 없다. 구현 검증 직전에 다시 확인한다.
- config: tracked `configs/*.yaml`은 수정하지 않고 `/tmp` 복사본을 사용한다. 실제 임시 경로와 선택 profile을 review에 기록한다.
- runtime: `scripts/dev/edge.sh`, `scripts/dev/node.sh`는 executable이며 충돌 없는 임시 localhost port를 사용한다.
- external state: 로그인/provider/endpoint 상태는 아직 확정되지 않았다. 설치된 CLI는 실제 실행 후 실패 지점의 명령, exit status, stderr로만 blocker를 인정한다.
- OS/arch: `Linux 6.1.0-28-amd64 x86_64`.
- 누락된 CLI를 검증 중 다운로드하거나 repo 안에 tool/log를 만들지 않는다.

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

- `buildCmdWithoutContext` direct test는 cwd/env/error만 보고 command/path와 args를 확인하지 않는다.
- test 이름이 계획 regex와 달라 archived review의 targeted 명령에서 direct test가 실행되지 않았다.
- Codex app-server/OpenCode/persistent lifecycle cwd tests와 package/Node 회귀는 통과한다.
- actual CLI full-cycle evidence는 없다. 설치된 세 profile의 same-session message x2, event ordering, command/status/terminate 결과가 필요하다.

### 심볼 참조

- public/API symbol 변경 없음.
- test symbol `TestCLIBuildCmdWithoutContextAppliesEnvAndCwd`는 정의 1곳뿐이며 active verification regex와 일치하도록 `TestBuildCmdWithoutContextAppliesEnvAndCwd`로 변경한다.
- `buildCmdWithoutContext` 호출자는 `codex_app_server_process.go`, `opencode_sse.go`, `persistent_process.go`와 direct test다. lifecycle 호출 구조는 유지한다.

### 분할 판단

split decision policy를 평가했다. 이 작업은 이미 split된 `06_cli_adapter`의 단일 follow-up이며, helper/test/baseline/evidence가 같은 판정으로 닫혀야 한다. source 보정만 별도 완료해도 real CLI evidence가 없으면 task가 완료되지 않고, evidence만 분리하면 동일 dirty worktree와 active review를 중복 소유하게 된다. 새 domain/API 경계나 predecessor도 없으므로 현재 subtask 안의 단일 plan이 안전하다.

### 범위 결정 근거

- runtime event/session/cancellation 동작, config/proto/spec/contract/roadmap은 변경하지 않는다.
- `codex_app_server*`, `opencode_sse*`, `persistent*` lifecycle 구현은 builder 호출이 이미 연결됐으므로 동작 수정하지 않는다.
- `scripts/readability_read_sets.json`과 baseline의 비-CLI entry/global metadata/병렬 subtask 변경은 수정하지 않는다.
- tracked `configs/*.yaml`, `scripts/dev/*.sh`는 검증 입력일 뿐 수정하지 않는다.
- 새 dependency/package/tool을 추가하지 않는다.

### 빌드 등급

`cloud-G08`. 소스 수정은 작지만 외부 CLI/TUI full-cycle, process/terminal evidence, 반복된 verification trust 실패를 함께 복구해야 한다.

## 구현 체크리스트

- [ ] command builder의 공통 env/cwd 적용 중복을 제거하고 exact command/args/env/cwd/error 경계 테스트를 검증 정규식과 일치시킨다.
- [ ] readability baseline의 CLI entry만 HEAD 이하로 surgical 복구하고 비-CLI 병렬 변경을 보존한다.
- [ ] 실제 source에 존재하는 테스트만 매칭하는 fresh targeted/package/Node 검증 stdout/stderr를 재수집한다.
- [ ] 현재 설치된 `claude`, `codex`, `opencode`의 real CLI full-cycle을 수행하고 `antigravity` 및 실제 downstream blocker를 profile별 원문 증거로 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REFACTOR_ADAPTER_CLI-1] command builder와 경계 테스트 완결

문제: `apps/node/internal/adapters/cli/command.go:21-48`은 `prepareWorkspaceDir`, `Dir`, `Env` 적용을 두 builder에 중복한다. `apps/node/internal/adapters/cli/cli_workspace_test.go:420-455`는 command/path와 args를 assert하지 않고 이름도 계획의 targeted regex와 다르다.

해결 방법:

Before (`apps/node/internal/adapters/cli/command.go:21-48`):

```go
func buildCmd(ctx context.Context, command string, args []string, env []string, workspace string) (*exec.Cmd, error) {
	cmd := exec.CommandContext(ctx, command, args...)
	dir, err := prepareWorkspaceDir(workspace)
	// duplicated Dir/Env application
}

func buildCmdWithoutContext(command string, args []string, env []string, workspace string) (*exec.Cmd, error) {
	cmd := exec.Command(command, args...)
	dir, err := prepareWorkspaceDir(workspace)
	// duplicated Dir/Env application
}
```

After:

```go
func configureCmd(cmd *exec.Cmd, env []string, workspace string) (*exec.Cmd, error) {
	dir, err := prepareWorkspaceDir(workspace)
	if err != nil {
		return nil, err
	}
	if dir != "" {
		cmd.Dir = dir
	}
	if len(env) > 0 {
		cmd.Env = append(cmd.Environ(), env...)
	}
	return cmd, nil
}

func buildCmd(ctx context.Context, command string, args []string, env []string, workspace string) (*exec.Cmd, error) {
	return configureCmd(exec.CommandContext(ctx, command, args...), env, workspace)
}
```

`buildCmdWithoutContext`도 같은 `configureCmd`를 사용한다. process context/lifetime과 lifecycle 호출자는 바꾸지 않는다.

수정 파일 및 체크리스트:

- [ ] `apps/node/internal/adapters/cli/command.go`: 공통 `*exec.Cmd` 설정 helper로 env/cwd/error path를 한 곳에 둔다.
- [ ] `apps/node/internal/adapters/cli/cli_workspace_test.go`: test를 `TestBuildCmdWithoutContextAppliesEnvAndCwd`로 맞추고 `cmd.Path`/`cmd.Args`, env, cwd, invalid workspace error를 assert한다.
- [ ] lifecycle 세 호출부의 `buildCmdWithoutContext` 사용을 유지하고 직접 `exec.Command` 재도입이 없는지 확인한다.

테스트 작성: 수정한다. `apps/node/internal/adapters/cli/cli_workspace_test.go`의 direct builder test를 위 이름으로 바꾸고 exact command/args/env/cwd/error assertions를 추가한다. 별도 fixture는 필요 없다.

중간 검증:

```bash
rg -n --sort path 'exec\.Command\(' apps/node/internal/adapters/cli/{codex_app_server.go,codex_app_server_process.go,opencode_sse.go,persistent.go,persistent_process.go}
rg -n --sort path '^func TestBuildCmdWithoutContextAppliesEnvAndCwd|^func configureCmd|^func buildCmd' apps/node/internal/adapters/cli/{command.go,cli_workspace_test.go}
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 -v ./apps/node/internal/adapters/cli -run '^(TestBuildCmdWithoutContextAppliesEnvAndCwd|TestCodexAppServerProcCwd|TestOpencodeLocalServerCwd_(Workspace|DirOverride)|TestCLIPersistentNonTerminalCwd)$'
```

첫 검색은 `command.go` 외 lifecycle 파일에서 직접 `exec.Command`가 없어야 하고, 정확한 targeted tests가 모두 `=== RUN`/PASS로 표시되어야 한다.

### [REVIEW_REVIEW_REFACTOR_ADAPTER_CLI-2] CLI baseline 상향·stale entry 제거

문제: `scripts/readability_baseline.json:125-171`은 HEAD보다 큰 `codex_app_server.go=674`, `opencode_sse.go=892`, `persistent.go=755`와 새 `persistent_output_filter_claude.go=586` entry를 남긴다. 현재 source는 HEAD baseline으로 `cli_regressions=0`이므로 이 상향은 필요하지 않다.

해결 방법:

Before (`scripts/readability_baseline.json:125-171`):

```json
{"path":"apps/node/internal/adapters/cli/codex_app_server.go","value":674}
{"path":"apps/node/internal/adapters/cli/opencode_sse.go","value":892}
{"path":"apps/node/internal/adapters/cli/persistent.go","value":755}
{"path":"apps/node/internal/adapters/cli/persistent_output_filter_claude.go","value":586}
```

After: CLI-prefixed file/function entry만 HEAD baseline과 비교해 current-only stale identity를 제거하고 같은 identity의 `value`/`level`을 HEAD보다 높이지 않는다. baseline 전체 재생성, `git checkout`/파일 전체 덮어쓰기, 비-CLI entry 수정은 금지한다.

수정 파일 및 체크리스트:

- [ ] `scripts/readability_baseline.json`: `apps/node/internal/adapters/cli/` entry만 surgical edit한다.
- [ ] `scripts/readability_read_sets.json`: 수정하지 않는다.
- [ ] global `generated_at`, 비-CLI value/reason/order와 다른 split subtask 변경을 그대로 보존한다.

테스트 작성: Go test는 작성하지 않는다. baseline schema/current ratchet/HEAD CLI ratchet과 entry comparison script가 regression test다.

중간 검증:

```bash
make readability-audit
python3 - <<'PY'
import json
import subprocess
from scripts import readability_audit as audit

prefix = "apps/node/internal/adapters/cli/"
head = json.loads(subprocess.check_output(
    ["git", "show", "HEAD:scripts/readability_baseline.json"],
    text=True,
))
current_baseline = json.load(open("scripts/readability_baseline.json", encoding="utf-8"))

def identity(entry):
    return (entry["path"], entry["metric"], entry.get("function", ""))

rank = {"warning": 1, "split_review": 2, "exception": 3}
problems = []
for section in ("file_thresholds", "function_thresholds"):
    head_map = {identity(e): e for e in head[section] if e["path"].startswith(prefix)}
    for entry in current_baseline[section]:
        if not entry["path"].startswith(prefix):
            continue
        before = head_map.get(identity(entry))
        if before is None:
            problems.append(f"current-only {identity(entry)}")
        elif rank[entry["level"]] > rank[before["level"]]:
            problems.append(f"level increased {identity(entry)}: {before['level']} -> {entry['level']}")
        elif entry["value"] > before["value"]:
            problems.append(f"value increased {identity(entry)}: {before['value']} -> {entry['value']}")

for problem in problems:
    print(problem)
print(f"cli_baseline_problems={len(problems)}")
raise SystemExit(1 if problems else 0)
PY
python3 - <<'PY'
import json
import subprocess
from scripts import readability_audit as audit

current = audit.audit(audit.collect_files("worktree"))
baseline = json.loads(subprocess.check_output(
    ["git", "show", "HEAD:scripts/readability_baseline.json"],
    text=True,
))
regressions = [
    issue for issue in audit.ratchet_check(current, baseline, None)
    if issue["path"].startswith("apps/node/internal/adapters/cli/")
]
for issue in regressions:
    print(audit._render_issue(issue))
print(f"cli_regressions={len(regressions)}")
raise SystemExit(1 if regressions else 0)
PY
git diff -- scripts/readability_baseline.json scripts/readability_read_sets.json
```

두 count가 모두 0이어야 하고 마지막 diff에서 비-CLI 병렬 변경이 이 follow-up 때문에 사라지거나 바뀌지 않아야 한다.

### [REVIEW_REVIEW_REFACTOR_ADAPTER_CLI-3] 실제 테스트 stdout/stderr 재수집

문제: archived review `code_review_cloud_G08_1.log:243-280`은 실행 regex가 매칭하지 않는 builder test와 source에 없는 `TestCLIAppServerExecutorExecute`, `TestCLIPersistentExecutorExecute`, `TestStatusParser`를 `=== RUN`으로 기록했다.

해결 방법: source test discovery를 먼저 저장하고, 항목 1의 anchored regex와 fresh package/status/Node 명령을 그대로 실행한다. `...`, 합성된 aggregate test 이름, 과거 elapsed time을 쓰지 않는다. 출력이 길면 `/tmp`에 `tee`한 정확한 명령/경로를 기록하되 active review에는 exit code와 실제 stdout/stderr를 재구성 없이 붙인다.

수정 파일 및 체크리스트:

- [ ] active `CODE_REVIEW-cloud-G08.md`: 실제 `rg`/Go test 명령과 출력만 기록한다.
- [ ] `/tmp/iop-cli-*-plan2.log`: 필요할 때만 temporary evidence로 사용하고 repo 내부 log/tool을 만들지 않는다.
- [ ] 각 기록된 `=== RUN` 이름이 source discovery에 존재하고 명령 regex에 실제 매칭되는지 확인한다.

테스트 작성: 새 test는 작성하지 않는다. 항목 1의 test 보강과 기존 suites를 fresh 실행한다.

중간 검증:

```bash
rg -n --sort path '^func Test' apps/node/internal/adapters/cli apps/node/internal/adapters/cli/status | tee /tmp/iop-cli-test-discovery-plan2.log
set -o pipefail
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 -v ./apps/node/internal/adapters/cli -run '^(TestBuildCmdWithoutContextAppliesEnvAndCwd|TestCodexAppServerProcCwd|TestOpencodeLocalServerCwd_(Workspace|DirOverride)|TestCLIPersistentNonTerminalCwd)$' 2>&1 | tee /tmp/iop-cli-targeted-plan2.log
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 -v ./apps/node/internal/adapters/cli ./apps/node/internal/adapters/cli/status 2>&1 | tee /tmp/iop-cli-package-plan2.log
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 ./apps/node/... 2>&1 | tee /tmp/iop-node-plan2.log
```

모든 pipeline exit가 0이고 review 출력이 `/tmp` 원문과 일치해야 한다.

### [REVIEW_REVIEW_REFACTOR_ADAPTER_CLI-4] 설치된 real CLI full-cycle 증거 확보

문제: archived review `code_review_cloud_G08_1.log:296-320,373-378`은 현재 설치된 세 CLI까지 executable missing으로 기록했다. same-session message x2, node-local/edge-rendered payload ordering, `/nodes`, `/capabilities`, `/transport`, `/sessions`, `/status`, `/terminate-session` evidence가 없다.

해결 방법: preflight를 현재 shell에서 다시 실행하고 tracked config를 수정하지 않는 `/tmp` profile별 config로 `scripts/dev/edge.sh`와 `scripts/dev/node.sh`를 별도 process로 실행한다. `claude`, `codex`, `opencode`는 command 존재만으로 blocker 처리하지 말고 실제 startup/register 및 profile run까지 진행한다. 로그인/provider/endpoint/workspace 권한에서 실패하면 실제 command, exit status, stderr, 완료되지 않은 cycle, 재개 조건을 profile별로 남긴다. `antigravity`만 `command -v` 미발견을 설치 blocker로 기록할 수 있다.

수정 파일 및 체크리스트:

- [ ] `claude`, `codex`, `opencode`, `antigravity` 각각 command path/version 또는 missing exit를 기록한다.
- [ ] `/tmp` config 경로, dynamic port, Edge/Node process 명령을 profile별로 기록한다.
- [ ] 가능한 profile은 same-session message x2와 sent/start/message/complete ordering, node-local payload == edge-rendered payload를 기록한다.
- [ ] `/nodes`, `/capabilities`, `/transport`, `/sessions`, `/status`, persistent profile의 `/terminate-session` 결과를 기록한다.
- [ ] 실패 profile은 실제 실행 명령, exit status, stderr, 미완료 cycle, 재개 조건을 기록한다.

테스트 작성: 외부 CLI 통합 검증이므로 Go test를 추가하지 않는다. `e2e-smoke` real CLI 절차가 검증이다.

중간 검증:

```bash
pwd
git branch --show-current
git rev-parse HEAD
git status --short
uname -srm
for c in claude antigravity codex opencode; do
  if path="$(command -v "$c")"; then
    printf '%s=%s\n' "$c" "$path"
    "$c" --version
  else
    status=$?
    printf '%s=NOT_FOUND exit=%d\n' "$c" "$status"
  fi
done
test -x scripts/dev/edge.sh
test -x scripts/dev/node.sh
```

이어 `e2e-smoke scope="CLI adapter baseline and verification trust recovery" mode=real-cli profiles="claude,antigravity,codex,opencode" config_strategy="tracked configs unchanged; profile-specific /tmp copies and dynamic localhost ports"`를 수행한다. output format은 `agent-ops/skills/project/e2e-smoke/SKILL.md`를 따르고, 네 profile 모두 PASS 또는 실제 downstream blocker가 있어야 한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/node/internal/adapters/cli/command.go` | 1 |
| `apps/node/internal/adapters/cli/cli_workspace_test.go` | 1 |
| `scripts/readability_baseline.json` | 2 |
| `CODE_REVIEW-cloud-G08.md` | 3, 4 |

## 의존 관계 및 구현 순서

1. 항목 1의 helper/test를 고친다.
2. 항목 2에서 CLI baseline entry만 복구한다.
3. 항목 3의 deterministic 검증을 fresh 실행한다.
4. 동일 source/config를 기준으로 항목 4의 real CLI full-cycle 또는 downstream blocker를 수집한다.
5. 실제 출력으로 active review를 채운다.

## 최종 검증

```bash
gofmt -d apps/node/internal/adapters/cli/*.go apps/node/internal/adapters/cli/status/*.go
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 -v ./apps/node/internal/adapters/cli -run '^(TestBuildCmdWithoutContextAppliesEnvAndCwd|TestCodexAppServerProcCwd|TestOpencodeLocalServerCwd_(Workspace|DirOverride)|TestCLIPersistentNonTerminalCwd)$'
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 ./apps/node/internal/adapters/cli ./apps/node/internal/adapters/cli/status
GOCACHE=/tmp/iop-go-cache-review-fix-2 go test -count=1 ./apps/node/...
make readability-audit
python3 - <<'PY'
import json
import subprocess
from scripts import readability_audit as audit

current = audit.audit(audit.collect_files("worktree"))
baseline = json.loads(subprocess.check_output(
    ["git", "show", "HEAD:scripts/readability_baseline.json"],
    text=True,
))
regressions = [
    issue for issue in audit.ratchet_check(current, baseline, None)
    if issue["path"].startswith("apps/node/internal/adapters/cli/")
]
for issue in regressions:
    print(audit._render_issue(issue))
print(f"cli_regressions={len(regressions)}")
raise SystemExit(1 if regressions else 0)
PY
git diff --check
```

이후 `e2e-smoke scope="CLI adapter baseline and verification trust recovery" mode=real-cli profiles="claude,antigravity,codex,opencode" config_strategy="tracked configs unchanged; profile-specific /tmp copies and dynamic localhost ports"`를 실행한다. 설치된 profile은 실제 full-cycle 또는 executable discovery 이후의 구체적 downstream blocker가 있어야 하고, `antigravity`는 현재 missing command 증거를 남긴다.

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