<!-- task=m-provider-resource-admission-ownership-alignment/11+08,13,15_reconnect_candidate_recovery plan=1 tag=REVIEW_REFACTOR -->

# Code Review Reference - REVIEW_REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> This implementation model must differ from the plan and review models. Fill implementation-owned sections, report `review-ready`, and stop. Do not review or start another agent.
> If a selected Milestone `구현 잠금 > 결정 필요` item blocks implementation, record it in `사용자 리뷰 요청`. Record other blockers in the implementation-owned evidence; they are not user-facing stopping states.
> A later review model consumes this file state.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) belongs only to the review model.
> `review-ready` ends the current invocation. `USER_REVIEW.md` stops the loop for a decision; `complete.log` ends the task.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-07-22
task=m-provider-resource-admission-ownership-alignment/11+08,13,15_reconnect_candidate_recovery, plan=1, tag=REVIEW_REFACTOR

## 역할 모델

- Plan: `root-followup-plan`
- Implementation: `pending`
- Review: `pending`

> Runtime만 최초 역할 시작 시 해당 identity를 기록한다. 기록된 identity는 이 pair에서 변경하지 않으며, 재시도는 같은 model identity를 사용한다. 세 identity는 모두 달라야 한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md)
- Task ids:
  - `reconnect-candidate-recovery`: accepted reconnect가 dispatch-ready generation만 후보로 복구하고 기존 waiter를 terminal까지 정확히 한 번 실행
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- 이전 task: `agent-task/m-provider-resource-admission-ownership-alignment/11+08,13,15_reconnect_candidate_recovery`
- 이전 plan/review: `plan_cloud_G08_0.log`, `code_review_cloud_G08_0.log`; verdict=`FAIL`.
- Required: RegisterResponse/config/handler 설치 전 pump로 첫 request 유실 가능; 실제 Node reconnect+waiter+terminal+counter 0 통합 evidence 없음; 직접 scripts/dev user-flow 없음; live preflight rc=3.
- generation fence/reconnect candidate rebuild는 보존한다. legacy role marker 부재는 사용자 명시 예외이므로 차단 사유가 아니다.
- 세부 문맥이 필요할 때만 위 두 log와 `NEXT_STATE.md`를 읽는다.

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

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
> Review 모델은 plan/implementation 모델과 달라야 한다. product source/test를 수정하거나 plan을 실행하지 않는다.
> Review는 후속 PLAN/CODE_REVIEW pair, `USER_REVIEW.md`, `complete.log` 중 정확히 하나를 남긴 뒤 종료한다. archive log만 남기고 종료하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G10.md` → `code_review_cloud_G10_1.log`, `PLAN-cloud-G09.md` → `plan_cloud_G09_1.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 task를 archive한다. WARN/FAIL이면 `USER_REVIEW.md`를 쓰거나 다른 Plan 모델을 호출해 후속 pair를 만든다.
4. PASS이면 완료 이벤트 metadata에 `reconnect-candidate-recovery`와 S15/terminal/user-flow evidence를 준비한다. roadmap 수정은 런타임 책임이다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| REVIEW_REFACTOR-1 Explicit Node dispatch-ready handshake | [x] |
| REVIEW_REFACTOR-2 Actual Node reconnect waiter terminal regression | [x] |
| REVIEW_REFACTOR-3 Wire contract and living spec sync | [x] |

## 구현 체크리스트

- [x] RegisterResponse/config 적용과 Node handler 설치가 끝난 뒤 Node가 보내는 명시적 ready request/ack를 추가하고, ready 전 accepted connection을 모든 실행 dispatch·refresh push·connected snapshot/event에서 제외한다.
- [x] ready accept가 current client/generation에서 정확히 한 번 `HandleNodeConnect`와 global pump를 실행하고 duplicate/stale/rejected ready는 no-op/reject가 되도록 registry·transport·service ordering 회귀를 추가한다.
- [x] 실제 `iop-node` bootstrap/reconnect와 이미 queue된 waiter를 한 integration test에서 구동해 RunRequest 수신·terminal 1회·중복 dispatch 0회·provider lease/normal/long/queued counter 0 수렴을 검증한다.
- [x] Edge-Node wire 계약과 living spec의 registration 흐름을 response → config/handler → ready ack → dispatch 가능 순서로 동기화한다.
- [ ] 대상/반복/race/전체 Go 회귀와 보조 mock smoke는 통과했다. 다만 기본 `scripts/dev` profile의 adapter 모호성과 live preflight rc=3으로 직접 user-flow terminal/reconnect cycle 및 live `normal-10`은 완료하지 못했으며, 아래에 exact blocker와 재개 조건을 기록했다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채웠다. review-ready를 보고한 뒤 현재 실행을 종료한다. code-review를 실행하거나 다음 에이전트를 시작하지 않는다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. 구현 에이전트는 수정하거나 체크하지 않는다.

- [x] ready 이전 Registry entry의 provider-pool/refresh/snapshot gate는 동작하지만 direct run/tunnel/cancel/command가 observation resolver를 우회함을 확인해 Required로 기록했다.
- [x] ready request가 handler 설치 뒤 전송되고 current client 최초 transition만 generation activation/pump/event를 만드는지 확인했다.
- [x] actual Node reconnect regression이 waiter queue를 먼저 증명하고 dispatch 1회, terminal 1회, duplicate ready/terminal no-op, lease/normal/long/queued 0을 단언하는지 확인했다.
- [x] proto 원본/생성물/Edge·Node parser·contract/spec이 같은 ready 순서를 설명하고 임시 재생성 생성물과 tracked Go 생성물이 일치함을 확인했다.
- [x] 직접 scripts/dev user-flow transcript를 보조 mock smoke와 구분해 대조했고 terminal/reconnect/payload-order evidence 미충족을 Required로 기록했다.
- [x] live preflight rc=3의 exact blocker/해제 조건/재검증 명령이 있고 성공으로 오인하지 않았음을 독립 재실행으로 확인했다.
- [x] `코드리뷰 결과`에 `FAIL`을 append하고 차원별 평가와 Required 두 건을 일치시켰다.
- [x] 사용자가 예전 task로 명시한 legacy identity 예외에 따라 `pending` marker를 독립 차단으로 삼지 않았고, follow-up Plan은 별도 `gpt-5.6-terra` Plan 모델에게 위임했다.
- [x] active review를 `code_review_cloud_G10_1.log`, plan을 `plan_cloud_G09_1.log`로 archive했다.
- [x] archive 전에 `NEXT_STATE.md`를 plan=1/target=plan으로 작성하고 finalization 끝까지 유지했다.
- [ ] PASS이면 complete.log에 `Roadmap Completion: reconnect-candidate-recovery`, S15 actual reconnect/terminal/counter/user-flow evidence를 기록하고 task directory를 월별 archive로 이동한다.
- [ ] PASS이면 runtime용 Milestone 완료 이벤트 metadata를 준비하고 roadmap/update-roadmap을 직접 호출하지 않는다.
- [x] user-review gate가 아닌 `FAIL`로 별도 Plan 모델이 `PLAN-local-G08.md`/`CODE_REVIEW-local-G09.md` follow-up pair 하나를 작성했고 현재 리뷰 모델은 구현하지 않았다.

## 계획 대비 변경 사항

- 제품 동작의 계획 이탈은 없다. `make proto`로 `runtime.pb.go`를 재생성했으며 Edge-Node wire 소비자가 Go뿐이므로 `make proto-dart`는 실행하지 않았다.
- `apps/node/internal/bootstrap/module_test.go`의 mock ready responder는 `NodeReadyResponse`를 socket write 완료 뒤에만 test channel로 알리도록 보정했다. 이전에는 request 수신 시점에 채널을 열어 Edge close가 response 수신과 경합할 수 있었고, `TestReconnectSupervisorExhaustsRetries`가 간헐적으로 initial retry 3회만 관측했다. 이 변경은 production retry 정책이 아니라 test fixture의 established 경계를 정확히 표현한다.
- 실제 `scripts/dev` transcript는 기본 profile의 기존 adapter instance 모호성으로 terminal/reconnect cycle까지 진행하지 못했다. 기본 config나 router 해석을 이 ready-handoff 작업 범위에서 변경하지 않고 blocker로 남겼다.

## 주요 설계 결정

- accepted registration은 Node ID ownership과 config 전달만 하는 pending 단계다. Node는 config 적용, adapter start, `Session.SetHandler` 후 `NodeReadyRequest`를 보내며, current client의 첫 ready transition만 generation activation, `HandleNodeConnect`, global waiter pump, connected event를 만든다.
- pending entry는 duplicate ownership claim에는 남지만 dispatch candidate, refresh recipient, connected snapshot/event에는 보이지 않는다. 같은 current owner의 duplicate ready는 successful idempotent ack이고 stale/superseded owner는 reject한다.
- `TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce`는 in-process Edge와 실제 빌드한 `iop-node` subprocess, blocking alternate CLI provider 및 reconnect CLI provider를 사용한다. waiter queue 확인 뒤 reconnect-ready dispatch 1회, 실제 terminal 1회, duplicate ready/terminal 뒤 추가 dispatch 없음, provider lease·normal/long/queued counter 0을 단언한다.
- bootstrap retry test의 ready responder는 response packet을 `QueuePacket`으로 기록한 뒤 알리므로 test가 ready ack 전 TCP 연결을 닫지 않는다.

## 사용자 리뷰 요청

_선택된 Milestone `구현 잠금 > 결정 필요`가 구현을 막을 때만 채운다. 이 섹션을 포함한 모든 구현 소유 섹션을 채운 뒤 `review-ready`를 보고하고 종료한다. code-review를 실행하거나 review model을 시작하지 않는다._

- 상태: 해당 없음
- 사유 유형: 없음
- 연결 대상: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: Milestone `구현 잠금 > 결정 필요` 항목 없음. scripts/dev 및 live endpoint 문제는 이 섹션의 user-review 사유가 아니라 아래 검증 blocker다.
- 후속으로 해결할 수 없는 이유: 없음
- 재개 조건: 없음

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

- RegisterResponse는 config 전달/ownership claim까지만 하고 ready ack 전 어느 path도 Node에 실행·command·refresh를 dispatch하지 않는가.
- handler 설치 뒤 ready request가 성공해야 supervisor owner가 established되고, stale/duplicate ready가 generation/pump/event를 반복하지 않는가.
- reconnect waiter가 실제 Node에서 terminal까지 정확히 한 번 실행되고 terminal/disconnect 경쟁 뒤 모든 lease/counter가 0인가.
- wire contract/spec, 직접 scripts/dev transcript, mock smoke, live preflight blocker/재검증이 서로 다른 evidence 층으로 정직하게 기록됐는가.

## 검증 결과

아래 명령의 실제 stdout/stderr를 붙인다. 변경한 명령은 `계획 대비 변경 사항`에 이유를 기록한다. 긴 출력은 `/tmp` 저장 경로와 생성 명령을 함께 기록한다.

### Proto와 정적 검사

`make proto`

`gofmt -d apps/edge/internal/node/registry.go apps/edge/internal/node/registry_test.go apps/edge/internal/transport/server.go apps/edge/internal/transport/connection_handlers.go apps/edge/internal/transport/integration_test.go apps/edge/internal/service/provider_resolution.go apps/edge/internal/service/service.go apps/edge/internal/service/status_provider.go apps/edge/internal/service/service_internal_test.go apps/edge/internal/service/status_provider_test.go apps/edge/internal/service/queue_dispatch_test.go apps/edge/internal/bootstrap/runtime.go apps/edge/internal/bootstrap/runtime_refresh_node_test.go apps/edge/internal/bootstrap/runtime_test_support_test.go apps/edge/internal/bootstrap/reconnect_readiness_integration_test.go apps/node/internal/transport/parser.go apps/node/internal/transport/parser_test.go apps/node/internal/transport/session.go apps/node/internal/transport/session_test.go apps/node/internal/transport/client.go apps/node/internal/transport/client_test.go apps/node/internal/bootstrap/module.go apps/node/internal/bootstrap/module_test.go`

`git diff --check -- proto/iop/runtime.proto proto/gen/iop/runtime.pb.go apps/edge/internal/node apps/edge/internal/transport apps/edge/internal/bootstrap apps/edge/internal/service apps/node/internal/transport apps/node/internal/bootstrap agent-contract/inner/edge-node-runtime-wire.md agent-spec/runtime/edge-node-execution.md agent-spec/runtime/provider-pool-config-refresh.md`

`rg --sort path -n 'NodeReady(Request|Response)|Mark.*Ready|DispatchReady|HandleNodeConnect|notifyNodeConnected' proto/iop apps/edge apps/node agent-contract/inner/edge-node-runtime-wire.md agent-spec/runtime`

_실제 출력:_

```text
$ 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 -d <계획의 23개 Go 파일>
(출력 없음)

$ git diff --check -- <계획의 proto/Edge/Node/contract/spec 대상>
(출력 없음)

$ rg --sort path -n 'NodeReady(Request|Response)|Mark.*Ready|DispatchReady|HandleNodeConnect|notifyNodeConnected' ...
exit=0; proto producer/consumer, Edge registry/transport/service lifecycle, Node SetHandler→SignalReady, 계약/spec callsite를 확인했다.
주요 lifecycle callsite: apps/node/internal/bootstrap/module.go:121 (SignalReady), apps/edge/internal/transport/connection_handlers.go:157 (current-owner ready transition), :172 (notifyNodeConnected), apps/edge/internal/bootstrap/runtime.go:113 (Service.HandleNodeConnect wiring).
```

### 대상 readiness 회귀

`go test -count=20 -timeout 180s ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/node/internal/transport ./apps/node/internal/bootstrap -run 'Ready|Register|Reconnect'`

_실제 출력:_

```text
ok   iop/apps/edge/internal/node       0.016s
ok   iop/apps/edge/internal/transport  8.745s
ok   iop/apps/node/internal/transport  0.013s
ok   iop/apps/node/internal/bootstrap  8.882s
```

### Actual Node reconnect integration

`go test -count=10 -timeout 300s ./apps/edge/internal/bootstrap -run '^TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$'`

`go test -race -count=1 -timeout 300s ./apps/edge/internal/bootstrap -run '^TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$'`

_실제 출력:_

```text
$ go test -count=10 ...TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$
ok   iop/apps/edge/internal/bootstrap  28.633s

$ go test -race -count=1 ...TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$
ok   iop/apps/edge/internal/bootstrap  3.525s
```

### Race와 전체 회귀

`go test -race -count=1 -timeout 300s ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/edge/internal/bootstrap ./apps/edge/internal/service ./apps/node/internal/transport ./apps/node/internal/bootstrap`

`go test -count=1 -timeout 300s ./apps/edge/... ./apps/node/...`

`go test -count=1 -timeout 600s ./...`

_실제 출력:_

```text
$ go test -race -count=1 -timeout 300s <6 readiness packages>
ok   iop/apps/edge/internal/node       1.022s
ok   iop/apps/edge/internal/transport  5.743s
ok   iop/apps/edge/internal/bootstrap  5.528s
ok   iop/apps/edge/internal/service    6.991s
ok   iop/apps/node/internal/transport  6.603s
ok   iop/apps/node/internal/bootstrap  2.469s

$ go test -count=1 -timeout 300s ./apps/edge/... ./apps/node/...
exit=0

$ go test -count=1 -timeout 600s ./...
exit=0
```

### scripts/dev 실제 user-flow

- terminal A: `cd /config/workspace/iop && ./scripts/dev/edge.sh`
- terminal B: `cd /config/workspace/iop && ./scripts/dev/node.sh`
- edge console: `/nodes`, 같은 session message 2회, `/capabilities`, `/transport`, `/sessions`, persistent profile이면 `/terminate-session`; reconnect 뒤 message cycle 1회 반복.
- 각 run의 node local payload와 edge rendered payload 내용/순서, complete가 마지막 payload 뒤 한 번만 오는 transcript를 기록한다.

_실제 transcript 또는 blocker:_

```text
실행: ./scripts/dev/edge.sh + ./scripts/dev/node.sh
evidence: /tmp/iop-reconnect-ready-dev-20260722T042035Z/{edge.log,node-1.log}

[edge] IOP Edge console listening on 0.0.0.0:9090
[node0-evt] connected reason="registered"
node-1: connected to edge

[edge] sent run_id=... adapter=cli target=codex session=default
[node0-evt] error ... "router: adapter \"cli\" is ambiguous: matches instance keys [claude-tui codex codex-exec]; use an instance key"
(같은 session의 두 번째 message도 동일 오류)
node local log에는 두 prompt의 `[edge-message]`와 RunRequest 수신이 있다.
```

기본 `configs/edge.yaml`의 console adapter가 generic `cli`인 반면 Node config에는 세 CLI instance가 있어 terminal 이전 resolve가 실패했다. 따라서 `/capabilities`·`/transport`·`/sessions`·`/terminate-session`과 reconnect 뒤 complete cycle은 이 profile에서 검증하지 못했다. 재개하려면 기본 dev console이 target `codex`를 단일 CLI instance로 resolve하도록 별도 범위에서 profile/router contract를 정리한 뒤, 같은 두 프로세스 흐름을 처음부터 재실행한다.

### 보조 mock smoke

`IOP_E2E_BIND_TIMEOUT=60 IOP_E2E_PROFILE=mock ./scripts/e2e-smoke.sh`

_실제 출력:_

```text
IOP_E2E_BIND_TIMEOUT=60 IOP_E2E_PROFILE=mock ./scripts/e2e-smoke.sh
...
[node0-evt] start → [node0-msg] IOP_E2E_ACK_SHORT → IOP_E2E_ACK_SHORT_TAIL → complete
[node0-evt] start → [node0-msg] IOP_E2E_READY_SHORT → IOP_E2E_READY_SHORT_TAIL → complete
[node0-evt] start → [node0-msg] IOP_E2E_BYE_SHORT → IOP_E2E_BYE_SHORT_TAIL → complete
[e2e] Auxiliary smoke test PASSED.
```

이 결과는 mock 보조 evidence이며 위 직접 dev profile blocker를 대체하지 않는다.

### Live provider preflight와 재검증

`./scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-reconnect-ready-preflight`

- rc=0: provider identity/health/capacity evidence 기록.
- rc=3: exact failed command, `/tmp` evidence 경로, endpoint/identity 해제 조건 기록; 성공으로 간주하지 않는다.

`./scripts/e2e-long-context-admission-smoke.sh --preflight --scenario normal-10 --out-dir /tmp/iop-reconnect-ready-normal-10`

- preflight rc=0일 때 실행한다. 모든 HTTP 성공, peak capacity/queue, 최종 normal/long/queued 0을 기록한다.
- 이전 rc=3 blocker가 해소되면 같은 명령을 재실행한다.

_실제 출력 또는 blocker/revalidation:_

```text
./scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-reconnect-ready-preflight
preflight_rc=3

BLOCKER: /models unreachable
  curl -fsS --connect-timeout 10 http://toki-labs.com:18083/v1/models
BLOCKER: status unreachable
  curl -fsS --connect-timeout 10 http://127.0.0.1:18001/edges/edge-toki-labs-dev/status
evidence=/tmp/iop-reconnect-ready-preflight
```

`normal-10`은 preflight가 rc=0일 때만 실행하므로 실행하지 않았다. 재개 조건은 (1) base URL의 `/v1/models`가 reachable하고, (2) Control Plane status가 provider identity/health/capacity를 반환하는 것이다. 충족 뒤 같은 preflight를 재실행하고, 이어서 `./scripts/e2e-long-context-admission-smoke.sh --preflight --scenario normal-10 --out-dir /tmp/iop-reconnect-ready-normal-10`으로 final normal/long/queued counter 0을 재검증한다.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING]** completion table, checklist, 변경 사항, 설계 결정, 검증 출력/차단 근거를 모두 채운 뒤 `review-ready`를 보고하고 종료한다. code-review를 실행하거나 다음 에이전트를 시작하지 않는다.

## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header/개요/Roadmap/Archive/checkpoints | Fixed | 구현 에이전트 수정 금지 |
| 역할 모델 | Mixed | Plan 고정; Runtime이 pending identity를 1회 기록 |
| 구현 표/체크리스트/변경/설계/검증 | Implementing agent | 실제 내용과 stdout/stderr 필수 |
| 코드리뷰 전용 체크리스트/결과 | Review agent | 구현 에이전트 수정 금지 |
| 사용자 리뷰 요청 | Implementing agent | Milestone lock 결정만 |

## 코드리뷰 결과

- 종합 판정: `FAIL`
- Legacy identity 예외: 사용자가 본 pair를 예전 작업으로 명시하고 리뷰 진행을 지시해 `Implementation`/`Review`의 `pending` marker는 이번 판정의 독립 차단 사유로 삼지 않았다.

### 차원별 평가

| 차원 | 판정 | 근거 |
|------|------|------|
| Correctness | Fail | direct run/tunnel/cancel/command가 pending registry entry를 계속 해결해 ready 전 wire dispatch가 가능하다. |
| Completeness | Fail | 계획의 전체 dispatch-ready gate와 필수 user-flow/live 검증이 완료되지 않았다. |
| Test coverage | Fail | provider-pool reconnect 통합 회귀는 충분하지만 pending direct wire 표면을 자체는 회귀가 없고 직접 user-flow가 terminal까지 실행되지 않았다. |
| API contract | Fail | active Edge-Node contract의 ready ack 전 run/tunnel/command 금지와 실제 direct service 경로가 불일치한다. |
| Code quality | Pass | 새 ready handshake, generation field, proto 생성물과 문서는 구조적으로 일관되고 포맷/정적 검사를 통과했다. |
| Implementation deviation | Fail | 구현은 계획의 “모든 실행 dispatch·command”가 아니라 provider-pool 후보/refresh/snapshot 중심으로만 ready lookup을 적용했다. |
| Verification trust | Pass | proto 재생성 비교, 반복/통합/race/전체 Go 회귀, mock smoke와 live preflight rc=3을 리뷰에서 독립 재현했고 기록과 일치했다. |
| Spec conformance | Pass | SDD S15의 actual Node reconnect 즉시 pump, terminal 1회, counter 0 회귀와 race evidence는 통과했다. |

### 발견된 문제

- **Required** — `apps/edge/internal/service/run_submit.go:56`, `apps/edge/internal/service/provider_tunnel.go:258`, `apps/edge/internal/service/run_cancel.go:28`, `apps/edge/internal/service/run_cancel.go:62`, `apps/edge/internal/service/node_command.go:37`, `apps/edge/internal/service/node_command.go:150`, `apps/edge/internal/service/node_command.go:183`: dispatch-ready 전용으로 `ResolveReady`를 추가했지만 이 direct wire 경로는 여전히 observation용 `ResolveNode` → `Registry.Resolve`를 사용한다. accepted/pending Node의 `Client`에 `RunRequest`, `ProviderTunnelRequest`, `CancelRequest`, `NodeCommandRequest`를 보낼 수 있어 handler-ready 계약을 우회한다. **수정:** observation resolver와 dispatch resolver를 service 경계에서 명시적으로 분리하고 모든 Node-bound send/request 경로를 ready-only resolver로 전환한 뒤, accepted-but-pending client가 ready 전 위 메시지를 하나도 수신하지 않고 ready 후에만 수신함을 통합 회귀로 고정한다.
- **Required** — `CODE_REVIEW-cloud-G10.md:74`, `CODE_REVIEW-cloud-G10.md:214`: 계획에 포함된 직접 `scripts/dev/edge.sh` + `scripts/dev/node.sh` full-cycle이 generic `cli` instance 모호성으로 terminal 전에 실패했고 reconnect cycle, payload 동일성/순서, `/capabilities`, `/transport`, `/sessions`, `/terminate-session`을 검증하지 못했다. live preflight도 리뷰 재실행에서 rc=3(`/models`, Control Plane status 미도달)으로 `normal-10` counter 수렴이 미검증이다. **수정:** 기본 config를 오염시키지 않고 스크립트가 지원하는 `IOP_EDGE_CONFIG`/`IOP_NODE_CONFIG`에 단일 deterministic CLI instance의 임시 profile을 주입해 두 프로세스 메시지·command·reconnect cycle을 끝까지 재검증한다. live endpoint가 준비되면 동일 preflight과 `normal-10`을 재실행해 최종 normal/long/queued 0을 증명한다.

### 다음 단계

- `FAIL`: 다른 Plan 모델이 위 Required 항목을 반영한 follow-up PLAN/CODE_REVIEW pair를 같은 task path에 작성한다. 현재 리뷰 모델은 구현하지 않는다.
