<!-- task=m-control-plane-edge-wire-baseline/03+01,02_local_smoke plan=0 tag=EDGE_CONN -->

# Plan - EDGE_CONN Local Smoke

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

구현의 마지막 단계는 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 검증 출력으로 채우는 것이다. 검증을 실행하고, 실제 stdout/stderr를 붙이고, active 파일을 유지한 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 범위 충돌, 외부 환경/secret 준비, 제품 결정이 필요하면 review stub의 `사용자 리뷰 요청`을 근거와 함께 채우고 멈춘다. 단순 증거 공백은 후속 에이전트가 재실행할 수 있으므로 사용자 리뷰 요청으로 올리지 않는다.

## 배경

두 번째 Epic의 완료 검증은 “로컬 Control Plane과 Edge를 함께 띄웠을 때 hello가 성공한다”이다. Control Plane과 Edge 내부 패키지는 서로 다른 `internal` 경계라 단일 Go integration test로 묶기 어렵다. 그래서 실제 binaries/process를 띄우는 local smoke를 추가해 사용자가 기대한 운영 경로를 검증한다.

## 사용자 리뷰 요청 흐름

구현 중 차단 사유가 생기면 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션을 사용한다. code-review가 요청 타당성을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/control-plane-portal-ops/PHASE.md`
- `agent-roadmap/phase/control-plane-portal-ops/milestones/control-plane-edge-wire-baseline.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-test/local/control-plane-smoke.md`
- `agent-test/local/edge-smoke.md`
- `Makefile`
- `scripts/e2e-smoke.sh`
- `scripts/dev/edge.sh`
- `scripts/dev/node.sh`
- `apps/control-plane/cmd/control-plane/main.go`
- `apps/edge/cmd/edge/main.go`
- `configs/control-plane.yaml`
- `configs/edge.yaml`

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

- Existing `scripts/e2e-smoke.sh` validates Edge-Node runtime, not Control Plane-Edge wire hello.
- `Makefile test-e2e` does not run any Control Plane-Edge process smoke.
- Control Plane and Edge package tests can pass while config/process integration is broken.

### 심볼 참조

- 제거/rename할 심볼 없음.
- `test-e2e` target: `Makefile:75`.
- Existing smoke script pattern: `scripts/e2e-smoke.sh:1`.

### 분할 판단

Split policy를 먼저 평가했다. 이 subtask는 `agent-task/m-control-plane-edge-wire-baseline/03+01,02_local_smoke`이며 `01_cp_edge_endpoint`와 `02+01_edge_connector`의 `complete.log`가 모두 선행되어야 한다. Process orchestration, shell error handling, log evidence는 endpoint/connector implementation과 다른 risk profile이라 별도 plan으로 분리했다.

### 범위 결정 근거

이 subtask는 local smoke script와 Makefile target만 추가한다. 기존 Edge-Node `scripts/e2e-smoke.sh`, OpenAI/Ollama smoke, Node bootstrap UX, Docker compose healthcheck는 바꾸지 않는다. Smoke는 secret이나 private endpoint를 tracked 파일에 쓰지 않는다.

### 빌드 등급

build=`cloud-G08`, review=`cloud-G08`. 이유: shell process orchestration, port readiness, long-running process cleanup, log-based acceptance가 포함된다.

## 의존 관계 및 구현 순서

이 디렉터리명은 `03+01,02_local_smoke`다. 같은 task group의 `01_cp_edge_endpoint`와 `02+01_edge_connector`가 모두 `complete.log`를 만든 뒤 시작한다.

## 구현 체크리스트

- [ ] [EDGE_CONN-1] Control Plane-Edge wire local smoke script를 추가해 실제 CP/Edge process hello 성공과 disconnect를 검증한다.
- [ ] [EDGE_CONN-2] Makefile에 smoke target을 추가하고 `test-e2e` 흐름에 포함할지 명시적으로 반영한다.
- [ ] 중간/최종 검증 명령을 실행하고 출력이 기대와 일치하는지 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [EDGE_CONN-1] Local process smoke script

#### 문제

[scripts/e2e-smoke.sh](/config/workspace/iop/scripts/e2e-smoke.sh:1)는 Edge-Node smoke다. Control Plane-Edge hello success를 검증하는 script가 없다.

Before:

```bash
# scripts/e2e-smoke.sh:1
#!/usr/bin/env bash
set -euo pipefail
```

#### 해결 방법

`scripts/e2e-control-plane-edge-wire.sh`를 추가한다.

- `mktemp -d` 아래 `control-plane.yaml`, `edge.yaml`, log files를 생성한다.
- Random free ports를 배정한다. Control Plane HTTP, Client WS, Edge TCP wire, Edge node transport, Edge bootstrap, Edge metrics가 충돌하지 않아야 한다.
- `go run ./apps/control-plane/cmd/control-plane serve --config "$CP_CONFIG"`를 background로 시작한다.
- Edge wire TCP port가 열릴 때까지 wait한다.
- `go run ./apps/edge/cmd/edge serve --config "$EDGE_CONFIG"`를 background로 시작한다.
- CP/Edge logs에서 hello accepted marker와 connector connected marker를 기다린다.
- Edge process를 종료하고 CP log에서 disconnected marker를 기다린다.
- failure 시 두 로그를 출력하고 non-zero로 종료한다.
- trap에서 background process cleanup을 보장한다.

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

- [ ] `scripts/e2e-control-plane-edge-wire.sh`: strict shell script 추가.
- [ ] Script log marker는 구현된 CP/Edge logger message와 정확히 맞춘다.
- [ ] Script는 tracked config를 수정하지 않고 temp config만 사용한다.

#### 테스트 작성

Shell smoke 자체가 테스트다. `bash -n scripts/e2e-control-plane-edge-wire.sh`와 실제 script 실행을 검증한다. Shellcheck는 있으면 실행하고 없으면 기존 smoke처럼 skip message를 남긴다.

#### 중간 검증

```bash
bash -n scripts/e2e-control-plane-edge-wire.sh
```

기대: syntax check passes.

### [EDGE_CONN-2] Makefile target

#### 문제

[Makefile](/config/workspace/iop/Makefile:75)의 `test-e2e`는 기존 auxiliary smoke와 OpenAI/Ollama smoke만 실행한다. Control Plane-Edge wire smoke를 호출할 target이 없다.

Before:

```make
# Makefile:75
test-e2e:
	@echo "NOTE: test-e2e runs auxiliary smoke plus fake Ollama OpenAI serving; completion still requires user-flow verification when changing runtime paths."
	./scripts/e2e-smoke.sh
	./scripts/e2e-openai-ollama.sh
```

#### 해결 방법

`test-control-plane-edge-wire` phony target을 추가한다. `test-e2e`에 포함하되, 출력 note를 Control Plane-Edge wire smoke 포함으로 갱신한다. If runtime cost or flakiness is discovered during implementation, do not silently exclude it; record the reason in `계획 대비 변경 사항`.

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

- [ ] `Makefile`: `.PHONY`에 target 추가.
- [ ] `Makefile`: `test-control-plane-edge-wire` target 추가.
- [ ] `Makefile`: `test-e2e`에서 새 script 호출 추가.

#### 테스트 작성

별도 unit test 없음. Make target 실행이 검증이다.

#### 중간 검증

```bash
make test-control-plane-edge-wire
```

기대: Control Plane starts, Edge connects, hello succeeds, Edge disconnect updates CP state, script exits 0.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `scripts/e2e-control-plane-edge-wire.sh` | EDGE_CONN-1 |
| `Makefile` | EDGE_CONN-2 |

## 최종 검증

```bash
go test -count=1 ./apps/control-plane/... ./apps/edge/... ./packages/config ./packages/hostsetup
make test-control-plane-edge-wire
```

기대: Go tests pass with fresh execution and the local Control Plane-Edge wire smoke exits 0. Go test cache output is not acceptable for this plan; use `-count=1`.

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