<!-- task=m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke plan=0 tag=TEST -->

# Code Review Reference - TEST

> **[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.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a selected Milestone `구현 잠금 > 결정 필요` item, fill `사용자 리뷰 요청` with linked evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Environment/secret/service blockers, generic scope changes, repeated failures, and evidence gaps that a follow-up agent can close are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record only Milestone lock decisions in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-06-23
task=m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke, plan=0, tag=TEST

## Roadmap Targets

- Milestone: `agent-roadmap/phase/update-plane-self-update-foundation/milestones/runtime-reconnect-config-refresh.md`
- Task ids:
  - `field-reconnect`: `toki-labs.com` dev-runtime에서 Edge restart 후 GX10 Linux Node와 OneXPlayer Windows Node가 bootstrap 재실행 없이 재접속한다.
  - `field-refresh`: `gx10-vllm=4`, `onexplayer-lemonade=3` capacity 변경을 refresh로 반영하고 Edge process restart 없이 `qwen3.6:35b` 동시 4개 요청이 성공한다.
  - `docs`: bootstrap/reconnect/refresh 운영 방법과 제한 사항이 `apps/edge/README.md`, `docs/edge-local-dev-guide.md`, agent-test field 기준에 반영된다.
- Completion mode: check-on-pass

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

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

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

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G08.md` -> `code_review_cloud_G08_N.log`, `PLAN-cloud-G08.md` -> `plan_cloud_G08_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 연결된 Milestone 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [TEST-1] Field Reconnect Evidence | [ ] (환경 차단: 원격 dev-runtime 전체 오프라인) |
| [TEST-2] Field Refresh And Concurrent Requests | [ ] (환경/계약 차단: 스택 오프라인 + dev-runtime config에 refresh 미설정) |
| [TEST-3] Docs And Field Rule Consistency | [ ] (로컬 결정적 텍스트 검사는 PASS, field 교차검증은 차단) |

## 구현 체크리스트

- [ ] `TEST-1` 원격 dev-runtime에서 Edge restart 후 bootstrap 재실행 없이 3개 Node가 회복되는 evidence를 수집한다. 검증: Control Plane status와 Edge node TCP connection 수가 3개 Node 기준으로 회복된다. (차단: 원격 dev-runtime의 Control Plane/Edge/3 Node 프로세스가 전부 종료된 상태라 restart 대상 PID와 회복 대상 연결이 존재하지 않는다. `검증 결과` 참조)
- [ ] `TEST-2` `gx10-vllm=4`, `onexplayer-lemonade=3` capacity를 refresh apply로 반영하고 Edge PID 유지와 `qwen3.6:35b` 동시 4개 요청 성공 evidence를 수집한다. 검증: aggregate 기대 배정은 capacity 4/3 기준 `gx10-vllm` 2개, `onexplayer-lemonade` 2개이며, 요청별 node id 확정은 dispatch trace가 구현된 경우에만 판정한다. (차단: 스택 오프라인 + `build/dev-runtime/edge.yaml`에 `refresh:` block이 없어 refresh listener(19093)가 존재하지 않는다. `검증 결과` 참조)
- [ ] `TEST-3` docs와 agent-test field 기준이 실제 field 결과와 일치하는지 확인하고, 필요한 경우 문서만 보정한다. (부분: tracked diff 범위 검사와 stale wording 검사는 PASS. field 결과가 없어 docs vs 실제 동작 교차검증은 미수행. 필드 결과가 docs를 반증하지 않았으므로 docs는 보정하지 않음)
- [ ] 최종 검증 명령을 모두 실행하고 실제 stdout/stderr를 `CODE_REVIEW-cloud-G08.md`에 붙여 넣는다. (원격 contract 명령은 실행했으나 환경 오프라인으로 모두 exit 1. 실제 출력/exit code를 `검증 결과`에 기록)
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

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

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G08_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G08_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/`를 `agent-task/archive/YYYY/MM/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-runtime-reconnect-config-refresh/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G08.md`와 `CODE_REVIEW-cloud-G08.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 연결된 Milestone 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.

## 계획 대비 변경 사항

코드 파일은 수정하지 않았다. docs도 보정하지 않았다(아래 사유). 검증 명령은 plan의 고정 계약을 그대로 실행했고, 환경 진단을 위해 추가 read-only 명령만 보조로 사용했다. 다음 사항은 plan 계약과 실제 원격 환경의 불일치이며, 이번 패스에서 closing할 수 없어 follow-up 대상으로 기록한다.

1. **원격 dev-runtime 전체 오프라인 (환경 차단).** plan의 TEST-1/TEST-2는 "이미 실행 중인 Edge"를 전제로 PID를 잡아 restart/refresh한다. 실제로는 `toki-labs.com`의 Control Plane(18001), Edge(18083/18084), 3개 Node 프로세스가 모두 종료된 상태다(2026-06-21 clean shutdown, PID 파일은 stale). 18001/18083/18084/19093 전부 CLOSED. 따라서 `test -n "$BEFORE_PID"` 단계에서 즉시 실패하여 restart/refresh/concurrent 단계에 도달하지 못한다.

2. **plan 검증 명령의 binary 이름 결함.** plan은 `EDGE_BIN`을 `command -v iop-edge` → `./build/bin/iop-edge` → `./build/dev-runtime/iop-edge` 순으로 찾는다. 실제 dev-runtime edge 바이너리는 `build/dev-runtime/bin/edge`이며 `iop-edge`라는 이름은 원격에 존재하지 않는다. 그 결과 `test -n "$EDGE_BIN"`에서 silent exit 1이 난다(처음 TEST-1 실행 시 무출력 exit 1의 원인). 스택이 살아 있었더라도 plan 명령은 이 결함만으로 실패한다.

3. **dev-runtime config에 `refresh:` block 부재 (TEST-2 계약 차단).** TEST-3에서 검증 중인 docs diff는 `refresh.enabled/listen`을 문서/예시로 추가했지만, 실제 실행 config인 `build/dev-runtime/edge.yaml`에는 `refresh:` block이 없다. 따라서 refresh listener(`127.0.0.1:19093`)가 뜨지 않으며(포트 CLOSED 확인), 스택을 cold-start하더라도 `config refresh --mode apply`가 연결할 대상이 없다. dev-runtime config에 refresh block을 추가하는 것은 환경 설정 변경으로, plan의 "코드 파일 수정 없음" 범위와 TEST-2 계약 전제를 벗어난다.

4. **docs 미보정 사유.** plan TEST-3은 "field run이 다른 운영 한계를 입증한 경우에만 docs를 보정"하도록 한다. field run 자체가 수행되지 못했으므로 docs를 보정할 근거가 없어 그대로 둔다. 다만 docs/edge-local-dev-guide.md와 README가 `config refresh` 라이브 반영과 Node reconnect(10s×10)를 단정하는데, 실제 dev-runtime는 refresh 미설정 + 스택 오프라인이라 field로 입증되지 않은 상태임을 follow-up이 인지해야 한다.

이 항목들은 Milestone `구현 잠금 > 결정 필요`가 아니라 외부 환경 readiness + plan/contract 결함이므로 `사용자 리뷰 요청`이 아니라 검증 결과/후속 plan으로 처리한다.

## 주요 설계 결정

- **evidence 위조 금지.** 스택이 오프라인이므로 reconnect/refresh/concurrent evidence를 만들어내지 않고, 실제 contract 명령의 stdout/stderr와 exit code, 그리고 원인 진단을 그대로 기록했다.
- **원격 스택 cold-start 미시도.** dev-runtime 런처는 `scripts/dev/*.sh`(repo `go run` + `configs/*.yaml`)가 아니라 `build/dev-runtime/bin/*` 바이너리 + `build/dev-runtime/*.yaml` config 기반이며, 그 cold-start 시퀀스가 문서화되어 있지 않다. 다수의 장기 실행 서비스를 원격 사용자 머신에서 임의 기동하는 것은 plan 범위 밖이고, TEST-2는 refresh config 부재라는 하드 블로커가 별도로 있어 스택만 띄워도 통과 불가하다. 따라서 임의 기동/환경 변경 대신 차단을 정확히 기록하는 쪽을 택했다.
- **provider는 정상.** GPU provider는 살아 있다: vLLM(LAN, `qwen3.6:35b`=`nvidia/Qwen3.6-35B-A3B-NVFP4` 서빙)과 lemonade(LAN) 모두 `/v1/models` 응답 정상. 차단은 provider가 아니라 Mac 측 오케스트레이션(CP/Edge/Node) 부재와 plan/contract 결함이다.
- **민감값 마스킹.** LAN provider endpoint IP, node token 원문은 tracked review output에 남기지 않고 마스킹했다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._

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

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

- `field-reconnect` evidence가 bootstrap 재실행 없이 Edge restart 후 3 Node 회복을 보여주는지 확인한다.
- `field-refresh` evidence가 refresh apply, Edge PID 유지, four concurrent success를 모두 포함하는지 확인한다.
- docs와 agent-test field 기준이 field 결과와 모순되지 않는지 확인한다.
- token/API key/private endpoint 원문이 tracked docs, roadmap, review output에 노출되지 않았는지 확인한다.

## 검증 결과

_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.

### 환경 사전 진단 (보조 read-only)

원격 dev-runtime 상태 확인. plan contract 명령이 무출력 exit 1로 끝난 원인을 규명하기 위해 read-only 진단을 수행했다.

```text
$ ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev
  ps for dev-runtime/bin/(edge|control-plane|iop-node); listening ports'
NONE_RUNNING
port 18001: CLOSED      # Control Plane status
port 18083: CLOSED      # Edge OpenAI-compatible
port 18084: CLOSED      # Edge-Node TCP
port 19093: CLOSED      # refresh listener
$ curl --max-time 5 http://127.0.0.1:18001/edges/edge-toki-labs/status
curl: (7) Failed to connect to 127.0.0.1 port 18001 after 0 ms: Couldn't connect to server

# stale PID 파일(프로세스 부재): edge.pid=9524, control-plane.pid=744, node-codex.pid=13484
# 로그상 CP/Edge/3 Node 모두 2026-06-21 local_shutdown 으로 정상 종료됨.

# 실제 edge 바이너리 경로 (plan이 찾는 iop-edge 가 아님)
$ ls build/dev-runtime/bin/edge   -> 존재 (build/dev-runtime/bin/edge)
$ command -v iop-edge             -> NONE
$ ls build/bin                    -> iop-node-windows-amd64, iop-node-windows-arm64 (edge 없음)

# refresh block 부재
$ grep -nA3 '^refresh:' build/dev-runtime/edge.yaml   -> (no match, exit 1)
# edge.yaml capacity 는 이미 목표값: gx10-vllm capacity=4, onexplayer-lemonade capacity=3

# provider 는 정상 (차단 원인 아님)
$ curl http://<vllm-gx10-LAN>/v1/models      -> 200, id=nvidia/Qwen3.6-35B-A3B-NVFP4, owned_by=vllm
$ curl http://<lemonade-onexplayer-LAN>/v1/models -> 200, owned_by=lemonade
```

### TEST-1 중간 검증
```bash
$ ssh toki@toki-labs.com 'set -euo pipefail
cd /Users/toki/agent-work/iop-dev
mkdir -p /tmp/iop-field-evidence
EDGE_CONFIG=build/dev-runtime/edge.yaml
EDGE_BIN="$(command -v iop-edge || true)"
if [ -z "$EDGE_BIN" ] && [ -x ./build/bin/iop-edge ]; then EDGE_BIN=./build/bin/iop-edge; fi
if [ -z "$EDGE_BIN" ] && [ -x ./build/dev-runtime/iop-edge ]; then EDGE_BIN=./build/dev-runtime/iop-edge; fi
test -n "$EDGE_BIN"
BEFORE_PID="$(pgrep -f "iop-edge.*${EDGE_CONFIG}" | head -n 1)"
test -n "$BEFORE_PID"
curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs/status | tee /tmp/iop-field-evidence/reconnect-before-status.json
(lsof -nP -iTCP:18084 -sTCP:ESTABLISHED 2>/dev/null || ss -tn state established "( sport = :18084 )" 2>/dev/null || true) | tee /tmp/iop-field-evidence/reconnect-before-tcp.txt
kill "$BEFORE_PID"
for i in $(seq 1 20); do if ! kill -0 "$BEFORE_PID" 2>/dev/null; then break; fi; sleep 1; done
nohup "$EDGE_BIN" --config "$EDGE_CONFIG" serve > /tmp/iop-field-evidence/reconnect-edge-restart.stdout.log 2>&1 &
AFTER_PID="$!"
echo "before_pid=$BEFORE_PID after_pid=$AFTER_PID"
for i in $(seq 1 120); do
  curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs/status > /tmp/iop-field-evidence/reconnect-after-status.json && break || true
  sleep 1
done
(lsof -nP -iTCP:18084 -sTCP:ESTABLISHED 2>/dev/null || ss -tn state established "( sport = :18084 )" 2>/dev/null || true) | tee /tmp/iop-field-evidence/reconnect-after-tcp.txt
cat /tmp/iop-field-evidence/reconnect-after-status.json
'
# (무출력) — EDGE_BIN 미해결(iop-edge 없음) + edge 프로세스 부재로 `test -n "$EDGE_BIN"`/`test -n "$BEFORE_PID"`에서
# set -e 즉시 종료. restart/회복 단계 미도달.
TEST1_EXIT=1
```

### TEST-2 중간 검증
```bash
$ ssh toki@toki-labs.com 'set -euo pipefail
cd /Users/toki/agent-work/iop-dev
mkdir -p /tmp/iop-field-evidence
EDGE_CONFIG=build/dev-runtime/edge.yaml
EDGE_BIN="$(command -v iop-edge || true)"
if [ -z "$EDGE_BIN" ] && [ -x ./build/bin/iop-edge ]; then EDGE_BIN=./build/bin/iop-edge; fi
if [ -z "$EDGE_BIN" ] && [ -x ./build/dev-runtime/iop-edge ]; then EDGE_BIN=./build/dev-runtime/iop-edge; fi
test -n "$EDGE_BIN"
REFRESH_ADDR="$(python3 - <<'"'"'PY'"'"'
from pathlib import Path
import re
p=Path("build/dev-runtime/edge.yaml")
s=p.read_text()
m=re.search(r"(?ms)^refresh:\n(?:^[ \t]+.*\n)*?^[ \t]+listen:[ \t]*\"?([^\"\n]+)\"?", s)
print(m.group(1).strip() if m else "127.0.0.1:19093")
PY
)"
EDGE_PID_BEFORE="$(pgrep -f "iop-edge.*${EDGE_CONFIG}" | head -n 1)"
test -n "$EDGE_PID_BEFORE"
"$EDGE_BIN" --config "$EDGE_CONFIG" config check | tee /tmp/iop-field-evidence/refresh-config-check.txt
"$EDGE_BIN" --config "$EDGE_CONFIG" config refresh --mode dry-run --addr "$REFRESH_ADDR" | tee /tmp/iop-field-evidence/refresh-dry-run.json
"$EDGE_BIN" --config "$EDGE_CONFIG" config refresh --mode apply --addr "$REFRESH_ADDR" | tee /tmp/iop-field-evidence/refresh-apply.json
EDGE_PID_AFTER="$(pgrep -f "iop-edge.*${EDGE_CONFIG}" | head -n 1)"
printf "edge_pid_before=%s edge_pid_after=%s\n" "$EDGE_PID_BEFORE" "$EDGE_PID_AFTER" | tee /tmp/iop-field-evidence/refresh-pid.txt
test "$EDGE_PID_BEFORE" = "$EDGE_PID_AFTER"
curl -fsS http://toki-labs.com:18083/healthz | tee /tmp/iop-field-evidence/refresh-healthz.txt
curl -fsS http://toki-labs.com:18083/v1/models | tee /tmp/iop-field-evidence/refresh-models.json
python3 - <<'"'"'PY'"'"' | tee /tmp/iop-field-evidence/refresh-concurrent-4.jsonl
import concurrent.futures, json, urllib.request
url = "http://toki-labs.com:18083/v1/chat/completions"
payload = {
  "model": "qwen3.6:35b",
  "messages": [{"role": "user", "content": "Reply with exactly IOP_FIELD_REFRESH_OK."}],
  "max_tokens": 32,
  "temperature": 0
}
def one(i):
    data = json.dumps(payload).encode()
    req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=300) as resp:
        body = json.loads(resp.read().decode())
    return {"index": i, "status": "ok", "id": body.get("id"), "model": body.get("model"), "usage": body.get("usage"), "content": body.get("choices", [{}])[0].get("message", {}).get("content", "")}
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as ex:
    for item in ex.map(one, range(4)):
        print(json.dumps(item, ensure_ascii=False))
PY
'
# (무출력) — TEST-1과 동일하게 EDGE_BIN 미해결 + edge 프로세스 부재로 `test -n "$EDGE_BIN"`/`test -n "$EDGE_PID_BEFORE"`
# 에서 set -e 즉시 종료. config check/refresh/concurrent 단계 미도달.
# 추가 계약 차단: build/dev-runtime/edge.yaml 에 refresh: block 부재 → 19093 listener 없음(CLOSED).
TEST2_EXIT=1
```

### TEST-3 중간 검증 (로컬 — PASS)
```bash
$ git diff -- apps/edge/README.md docs/edge-local-dev-guide.md
# tracked diff 은 reconnect/refresh 문서 변경만 포함 (PASS).
# apps/edge/README.md: config refresh dry-run/apply 명령 2줄 추가 + "Config Refresh와 Node Reconnect" 섹션 추가
#   (refresh listen 예시, config check→dry-run→apply 순서, runtime-mutable/restart_required/rejected 구분,
#    Node reconnect 기본 10s 간격 최대 10회 정책).
# docs/edge-local-dev-guide.md: refresh.enabled/listen 예시 추가, hot-reload 불가/bootstrap 재실행 문구를
#   config refresh + reconnect 정책 문구로 교체, 반복 검증 순서를 Edge restart→reconnect→refresh apply→concurrent 로 갱신.
# (전체 diff 본문은 작업 세션 git diff 출력과 동일. 무관 파일 변경 없음.)
```

```bash
$ rg --sort path -n "hot reload되지 않는다|자동 재등록 루프를 보장하지 않으므로|Edge process restart 후 새 capacity" apps/edge/README.md docs/edge-local-dev-guide.md agent-test/local/rules.md agent-test/local/edge-smoke.md
exit=1   # no matches → '! rg ...' 형태 계약 PASS (stale pre-refresh 문구 없음)
```

### 최종 검증
```bash
$ git diff --check
exit=0   # no output → PASS (whitespace 오류 없음)
```

```bash
$ rg --sort path -n "hot reload되지 않는다|자동 재등록 루프를 보장하지 않으므로|Edge process restart 후 새 capacity" apps/edge/README.md docs/edge-local-dev-guide.md agent-test/local/rules.md agent-test/local/edge-smoke.md
exit=1   # no matches → '! rg ...' 형태 계약 PASS
```

```bash
$ ssh toki@toki-labs.com 'test -s /tmp/iop-field-evidence/reconnect-after-status.json && test -s /tmp/iop-field-evidence/reconnect-after-tcp.txt && test -s /tmp/iop-field-evidence/refresh-apply.json && test -s /tmp/iop-field-evidence/refresh-concurrent-4.jsonl && wc -l /tmp/iop-field-evidence/refresh-concurrent-4.jsonl'
FINAL_EXIT=1   # FAIL — evidence 파일 미생성 (스택 오프라인으로 TEST-1/TEST-2 미수행). wc -l 4 미충족.
```

---

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

## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these |
| Roadmap Targets | Fixed at stub creation from plan | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS |
| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` to `[x]` only |
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` to `[x]` only; final checkbox is mandatory before saving |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless a selected Milestone `구현 잠금 > 결정 필요` item blocks implementation |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan |
| 검증 결과 | Implementing agent | Fill actual stdout/stderr only |
| 코드리뷰 결과 | Review agent appends | Not included in stub |

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Fail
  - API contract: Fail
  - code quality: Pass
  - implementation deviation: Fail
  - verification trust: Fail
  - spec conformance: Fail
- 발견된 문제:
  - Required: `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:47`와 `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:53`에서 `field-reconnect`가 미완료로 남아 있고, TEST-1은 `TEST1_EXIT=1`로 restart/회복 단계에 도달하지 못했다(`agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:187`). SDD S16과 Milestone `field-reconnect`는 remote dev field status, TCP connection evidence, 3 Node reconnect without bootstrap rerun을 요구한다(`agent-roadmap/sdd/update-plane-self-update-foundation/runtime-reconnect-config-refresh/SDD.md:102`, `agent-roadmap/sdd/update-plane-self-update-foundation/runtime-reconnect-config-refresh/SDD.md:125`, `agent-roadmap/phase/update-plane-self-update-foundation/milestones/runtime-reconnect-config-refresh.md:78`). 후속에서는 dev-runtime Edge/Control Plane/Node baseline을 실제로 기동 또는 준비한 뒤, bootstrap 재실행 없이 Edge restart 전후 status와 TCP evidence를 수집해야 한다.
  - Required: `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:48`와 `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:54`에서 `field-refresh`가 미완료로 남아 있고, TEST-2도 `TEST2_EXIT=1`로 `config check`, refresh dry-run/apply, `/healthz`, `/v1/models`, 동시 4개 요청을 전혀 수행하지 못했다(`agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:241`). SDD S17과 Evidence Map은 refresh result evidence와 remote dev 4 concurrent OpenAI-compatible request evidence를 요구한다(`agent-roadmap/sdd/update-plane-self-update-foundation/runtime-reconnect-config-refresh/SDD.md:103`, `agent-roadmap/sdd/update-plane-self-update-foundation/runtime-reconnect-config-refresh/SDD.md:126`). 후속에서는 `refresh.enabled/listen`이 실제 dev-runtime config에 반영된 상태에서 dry-run/apply JSON, Edge PID 유지, 4개 동시 요청 성공 evidence를 남겨야 한다.
  - Required: plan의 검증 명령은 `iop-edge`, `./build/bin/iop-edge`, `./build/dev-runtime/iop-edge`만 찾지만(`agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/PLAN-cloud-G08.md:148`, `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/PLAN-cloud-G08.md:195`), 구현 에이전트와 리뷰 재확인 모두 실제 dev-runtime binary가 `build/dev-runtime/bin/edge`임을 확인했다(`agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:83`, `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:147`). 이 때문에 스택이 준비돼도 기존 plan 명령은 실패한다. 후속 plan은 실제 binary path를 사용하거나 dev-runtime package에 `iop-edge` 이름을 준비하도록 검증 계약을 고쳐야 한다.
  - Required: `docs/edge-local-dev-guide.md:123`은 원격 repo root 기준 dev-runtime config에 `./iop-edge`를 사용하라고 안내하지만, 현재 dev-runtime 기준은 `/Users/toki/agent-work/iop-dev`와 `build/dev-runtime/edge.yaml`이고, 실제 binary path는 `build/dev-runtime/bin/edge`다. 또한 review evidence는 `build/dev-runtime/edge.yaml`에 `refresh:` block이 없고 19093 listener가 닫혀 있음을 보여준다(`agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:85`, `agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:152`). 후속에서는 docs/agent-test field 기준과 실제 dev-runtime artifact/config를 맞춘 뒤 TEST-3을 다시 닫아야 한다.
  - Required: 최종 검증의 remote evidence 파일 확인이 `FINAL_EXIT=1`로 실패해 `reconnect-after-status.json`, `reconnect-after-tcp.txt`, `refresh-apply.json`, `refresh-concurrent-4.jsonl`의 required evidence가 생성되지 않았다(`agent-task/m-runtime-reconnect-config-refresh/07+01,03,04,05,06_field_docs_smoke/CODE_REVIEW-cloud-G08.md:276`). 후속에서는 evidence 파일 생성과 `refresh-concurrent-4.jsonl` 4라인을 최종 검증으로 재확인해야 한다.
- 다음 단계: WARN/FAIL user-review gate는 트리거하지 않는다. active plan/review를 로그로 아카이브한 뒤 같은 task directory에 후속 `PLAN-cloud-G08.md`와 `CODE_REVIEW-cloud-G08.md`를 작성한다.
