<!-- task=01_internal_target_naming plan=0 tag=REFACTOR -->

# Code Review Reference - REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every section below is filled in.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-05-10
task=01_internal_target_naming, plan=0, tag=REFACTOR

## 이 파일을 읽는 리뷰 에이전트에게

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료 후 반드시 아래 순서로 아카이브하세요.

1. `CODE_REVIEW-cloud-G09.md` → `code_review_cloud_G09_N.log` (N = 기존 code_review_*.log 수)
2. `PLAN-cloud-G09.md` → `plan_cloud_G09_M.log` (M = 기존 plan_*.log 수)
3. PASS인 경우 `complete.log` 작성 후 종료. WARN/FAIL인 경우 새 routed plan + review 스텁 작성.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REFACTOR-1] Proto execution target fields | [x] |
| [REFACTOR-2] Runtime/domain target naming | [x] |
| [REFACTOR-3] Store, CLI, and console naming boundary | [x] |
| [REFACTOR-4] Search cleanup and explicit exceptions | [x] |

## 계획 대비 변경 사항

- `proto/iop/job.proto`의 `ScheduleRequest`이 아닌 `Job.model`은 placeholder 상태이므로 수정하지 않았다. 계획이 명시한 "compile/contract consistency 시에만"에 해당하지 않아 그대로 둔다.
- `packages/policy/engine.go`의 `Apply/Validate(adapter, model, ...)` 시그니처는 placeholder이며 어떤 호출자도 없으므로 수정하지 않았다. 향후 policy 엔진 본 구현 시 함께 갱신한다.
- `packages/jobs/jobs.go`의 `Job.Model` 필드도 동일한 이유로 placeholder 상태에서 보존했다.
- `packages/config/config.go`의 `EdgeConsoleConf.Model` 및 `LoadEdge`의 `console.model` → `console.agent` 폴백은 의도적으로 legacy 호환 경로로 유지했다.
- store 마이그레이션은 `runs.model` 컬럼을 `target`으로 RENAME하는 단일 ALTER TABLE로 처리했다 (`apps/node/internal/store/store.go` `migrateRunsTable`). 신규 DB에서는 schema가 직접 `target`으로 생성된다.
- 테스트 파일(특히 cli blackbox)에서 외부 CLI 출력 fixture(`"Model not found"`, `"model unavailable"`)와 `--model` external flag는 의도적 예외이므로 변경하지 않았다.
- `apps/node/internal/adapters/cli/status/codex.go:86`의 정규식 `(Tip:|model:)`는 외부 CLI 출력 패턴이므로 그대로 둔다.

## 주요 설계 결정

- **Proto field number 보존**: `runtime.proto`의 `RunRequest.target = 3`, `CancelRequest.target = 3`, `NodeCommandRequest.target = 4`, `NodeCommandResponse.target = 4`, `control.proto`의 `ScheduleRequest.target = 2`로 이름만 바꾸고 번호를 유지해 wire 호환성을 보장한다.
- **이름 매핑**: 내부 도메인 타입 `Model`/`Models` → `Target`/`Targets`. `runtime.Capabilities.Models`도 `Targets`로 변경(어댑터 선택 가능 실행 대상 목록 의미).
- **CLI adapter 의미**: `cliAgentName(spec)`는 `spec.Target`을 그대로 반환. CLI 어댑터 한정으로 target은 profile/agent 이름을 의미한다.
- **Store 마이그레이션**: 기존 local DB에 `model` 컬럼만 있는 경우 `ALTER TABLE runs RENAME COLUMN model TO target`으로 무손실 마이그레이션. 신규 DB는 처음부터 `target` 컬럼 사용.
- **EdgeConsoleConf 호환**: `Model` 필드와 `ResolveAgent()` 폴백을 그대로 유지. `LoadEdge`에서 `console.model`만 명시되면 `Console.Agent`로 복사하는 로직 보존.
- **TerminateSession 시그니처**: `TerminateSession(ctx, target, sessionID)`로 변경. node 측 호출 부에서 `req.GetTarget()`을 전달.

## 리뷰어를 위한 체크포인트

- Proto field numbers are preserved and generated code came from `make proto`.
- Internal execution target is named `target`, while external/model-specific exceptions are intentional.
- CLI profiles are not described as models in common execution code.
- Store migration is local and does not introduce central Job/Event Store design.
- README/docs/control-plane future features were not added.

## 검증 결과

### REFACTOR-1 중간 검증
```bash
$ make proto
protoc \
	--go_out=. \
	--go_opt=module=iop \
	--proto_path=. \
	proto/iop/runtime.proto \
	proto/iop/node.proto \
	proto/iop/control.proto \
	proto/iop/job.proto

$ go test ./proto/gen/...
?   	iop/proto/gen/iop	[no test files]
```

### REFACTOR-2 중간 검증
```bash
$ go test ./apps/node/internal/runtime/... ./apps/node/internal/router/... ./apps/node/internal/node/...
?   	iop/apps/node/internal/runtime	[no test files]
ok  	iop/apps/node/internal/router	0.004s
ok  	iop/apps/node/internal/node	0.008s
```

### REFACTOR-3 중간 검증
```bash
$ go test ./apps/node/internal/store/... ./apps/node/internal/adapters/cli/... ./apps/edge/cmd/edge/... ./packages/config/...
ok  	iop/apps/node/internal/store	0.038s
ok  	iop/apps/node/internal/adapters/cli	87.429s
ok  	iop/apps/edge/cmd/edge	0.005s
ok  	iop/packages/config	0.005s
```

### REFACTOR-4 중간 검증
```bash
$ rg -n "\bmodel\b|\bModel\b" proto/iop apps packages configs --glob '!**/README.md'
proto/iop/job.proto:21:  string    model       = 5;                   # Job placeholder; not finalized
configs/edge.yaml:86:              - "--model"                         # external CLI flag
packages/policy/engine.go:11:	Apply(ctx context.Context, adapter, model string, policy Spec) (Spec, error)
packages/policy/engine.go:13:	Validate(ctx context.Context, adapter, model string, policy Spec) error
packages/jobs/jobs.go:21:	Model      string            `json:"model"`  # Job placeholder
packages/config/config.go:43:	Model      string `mapstructure:"model"       yaml:"model"`  # legacy console fallback
packages/config/config.go:53:	return c.Model
packages/config/config.go:155:	if !v.InConfig("console.agent") && v.InConfig("console.model") {
packages/config/config.go:156:		cfg.Console.Agent = cfg.Console.Model
packages/config/config_test.go:91,101                                   # legacy fallback test
apps/node/internal/store/store.go:82-84                                 # migration: ALTER TABLE runs RENAME COLUMN model TO target
apps/node/internal/store/store_test.go:21                               # legacy schema fixture for migration test
apps/node/internal/adapters/cli/lifecycle_blackbox_test.go:77,124       # local loop var named `model`; non-functional
apps/node/internal/adapters/cli/oneshot_blackbox_test.go:210,235,361,390 # external CLI JSON output fixtures ("Model not found", "model unavailable")
apps/node/internal/adapters/cli/status/codex.go:86                      # regex of external CLI output: (Tip:|model:)
```
모두 의도적 예외(외부 API/CLI 경계, legacy 호환, placeholder, 마이그레이션 코드, 외부 출력 fixture)이다.

### 최종 검증
```bash
$ make proto
protoc --go_out=. --go_opt=module=iop --proto_path=. proto/iop/runtime.proto proto/iop/node.proto proto/iop/control.proto proto/iop/job.proto

$ gofmt -w apps packages proto
(no output)

$ go test ./packages/config ./apps/edge/cmd/edge/... ./apps/node/internal/...
ok  	iop/packages/config
ok  	iop/apps/edge/cmd/edge
ok  	iop/apps/edge/internal/node
ok  	iop/apps/edge/internal/transport
ok  	iop/apps/node/internal/adapters
ok  	iop/apps/node/internal/adapters/cli
ok  	iop/apps/node/internal/adapters/cli/status
ok  	iop/apps/node/internal/bootstrap
ok  	iop/apps/node/internal/node
ok  	iop/apps/node/internal/router
ok  	iop/apps/node/internal/store
ok  	iop/apps/node/internal/transport

$ go test ./...
ok  	iop/apps/edge/cmd/edge
ok  	iop/apps/edge/internal/node
ok  	iop/apps/edge/internal/transport
ok  	iop/apps/node/internal/adapters
ok  	iop/apps/node/internal/adapters/cli
ok  	iop/apps/node/internal/adapters/cli/status
ok  	iop/apps/node/internal/bootstrap
ok  	iop/apps/node/internal/node
ok  	iop/apps/node/internal/router
ok  	iop/apps/node/internal/store
ok  	iop/apps/node/internal/transport
ok  	iop/packages/config
(all PASS; remaining packages have no test files)

$ rg -n "\bmodel\b|\bModel\b" proto/iop apps packages configs --glob '!**/README.md'
(see REFACTOR-4 결과 — 모두 의도적 예외)
```

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every section: completion table, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.

---

## 코드리뷰 결과

### 종합 판정

PASS

### 차원별 평가

| 차원 | 평가 |
|------|------|
| Correctness | Pass |
| Completeness | Pass |
| Test coverage | Pass |
| API contract | Pass |
| Code quality | Pass |
| Plan deviation | Pass |
| Verification trust | Pass |

### 발견된 문제

- Nit: `packages/config/config.go:108-119` — gofmt가 `CompletionMarkerConf` 타입 폭 정렬에 맞춰 인접 필드 tag column에 공백 1칸을 추가했다. 이번 task로 인한 의미 변경은 없고 사전부터 존재하던 정렬 불일치를 보정한 것이다. 별도 fix 불필요.

### 검토 근거

- `proto/gen/iop/runtime.pb.go`/`control.pb.go`에 모든 `Target` 필드(번호 3,3,4,4,2)와 `GetTarget()` getter가 생성되어 있다(`runtime.pb.go:174,231,521,572,598,657,690,749`, `control.pb.go:89,133`). field number 보존 OK.
- `rg "GetModel\(\)|Model:" apps packages` 결과 0건 — 내부 호출부에 stale reference 없음.
- 잔여 `\bmodel\b|\bModel\b` 매치 모두 의도적 예외(legacy console.model 폴백, Job/Policy placeholder, store migration 코드, 외부 CLI 출력 fixture/regex, `--model` external flag, store_test의 legacy schema). CODE_REVIEW의 "계획 대비 변경 사항"에 모두 분류·기록됨.
- `apps/node/internal/store/store.go:81-91`의 `migrateRunsTable`가 legacy `runs.model` 컬럼을 `ALTER TABLE … RENAME COLUMN model TO target`으로 무손실 마이그레이션. `store_test.go:127-181`의 `TestStore_MigratesExistingRunsTable`/`TestStore_MigrationIsIdempotent`가 legacy schema seed 후 migration·재오픈을 검증하며 PASS.
- `EdgeConsoleConf.Model` legacy fallback과 `LoadEdge`의 `console.model`→`Console.Agent` 복사 경로 보존(`packages/config/config.go:43,53,155-156`); `config_test.go:91-102`가 fallback 동작을 검증하며 PASS.
- `runtime.SessionTerminator.TerminateSession(ctx, target, sessionID)` 시그니처 변경에 맞춰 node.go(`OnCancel`)와 cli adapter(`TerminateSession`) 호출부가 일관되게 `req.GetTarget()`/`agent` 인자를 전달.
- `go test ./...` 전체 PASS, `gofmt -l apps packages proto` clean.

### 다음 단계

PASS — 추가 plan 라우팅 없음. 아카이브 후 `complete.log` 작성.
