<!-- task=m-provider-resource-admission-ownership-alignment/15+14_controlplane_connected_mapping plan=0 tag=REFACTOR -->

# Control Plane connected snapshot mapping

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

선행 14의 matching active/archive `complete.log`를 확인한 뒤 구현한다. 구현 에이전트는 코드·테스트 변경, 구현 검증, active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성까지만 수행한다. 모두 채운 뒤 active pair를 유지하고 구현 실행을 종료한다. 이 저장 상태가 runtime의 `review-ready` 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. code-review 실행, 역할 전환, 판정, review 전용 섹션 수정, archive/log rename, `USER_REVIEW.md`·`complete.log` 작성, 후속 pair 생성·구현은 금지한다. runtime은 사용자에게 묻거나 준비 완료를 보고하지 않고 별도 review-agent instance를 즉시 배정하며 같은 agent의 새 turn·resume·compaction으로 대체하지 않는다. 선택 Milestone의 `구현 잠금 > 결정 필요`만 linked evidence와 함께 review stub의 `사용자 리뷰 요청`에 기록하고 같은 file-state handoff를 사용한다.

## 배경

선행 children이 configured offline Node/provider를 service snapshot에 보존하고 exact effective tuple을 만든다. 이 closure child는 `NodeSnapshot.Connected`를 Control Plane wire에 전달하면서 config/private transport redaction을 유지하고 전체 회귀 evidence를 닫는다.

## 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:
  - `offline-snapshot`: configured offline Node/provider와 reconnect snapshot 수렴
- Completion mode: check-on-pass

## 분석 결과

### 세분화 경계

- 이 child는 Control Plane `connected` mapping, config redaction, connected/offline provider tuple 직렬화와 최종 회귀를 소유한다.
- catalog/connectivity join은 10, offline tuple은 14의 완료 계약을 소비하며 proto 원본/생성물은 변경하지 않는다.
- `offline-snapshot` Roadmap Targets는 모든 선행 child를 거치는 이 자연스러운 closure에만 둔다.

### 변경 범위

- `apps/edge/internal/controlplane/connector.go`
- `apps/edge/internal/controlplane/connector_test.go`

## 구현 체크리스트

- [ ] Control Plane `EdgeNodeSnapshot.connected`가 DTO 값을 전달하고 config/private transport 정보는 계속 노출하지 않는다.
- [ ] connected/offline 두 Node와 exact provider tuple의 wire 직렬화를 검증한다.
- [ ] combined race, Edge/전체 회귀와 보조 entrypoint smoke 결과 또는 blocker를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우고 active pair를 유지한 채 구현 실행을 종료한다. 이 저장 상태가 runtime의 review-ready 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. 구현 에이전트는 code-review를 실행하거나 review 전용 작업을 수행하지 않는다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] Control Plane connected mapping

문제: `apps/edge/internal/controlplane/connector.go:367-374`가 `Connected: true`를 하드코딩한다.

해결 방법: `NodeSnapshot.Connected`를 wire `EdgeNodeSnapshot.connected`로 그대로 전달하고 기존 `Config:nil` non-leak 원칙을 유지한다.

```go
nodes = append(nodes, &iop.EdgeNodeSnapshot{
	Connected: s.Connected,
	Config:    nil,
})
```

수정 파일 및 체크리스트:

- [ ] `apps/edge/internal/controlplane/connector.go`: bool mapping.
- [ ] `apps/edge/internal/controlplane/connector_test.go`: connected/offline 두 Node와 provider tuple 직렬화.

테스트 작성: status provider fixture에 explicit true/false를 넣고 wire bool, exact offline tuple, `Config == nil`을 함께 검증한다.

## 의존 관계 및 구현 순서

- `14+10_offline_provider_tuple`의 matching `complete.log`가 필요하다. 14는 10을 선행하므로 이 child가 원본 전체의 closure다.
- mapping test 뒤 combined race, Edge/전체 회귀, mock smoke를 수행한다.

## 최종 검증

- `gofmt -d apps/edge/internal/controlplane/connector.go apps/edge/internal/controlplane/connector_test.go` → 출력 없음.
- `go test -count=1 ./apps/edge/internal/controlplane` → PASS.
- `go test -race -count=1 ./apps/edge/internal/service ./apps/edge/internal/controlplane` → PASS.
- `go test -count=1 ./apps/edge/...` → PASS.
- `go test -count=1 ./...` → PASS.
- `IOP_E2E_PROFILE=mock ./scripts/e2e-smoke.sh` → 보조 entrypoint PASS 또는 명시 blocker.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우고 active pair를 유지한 채 구현 실행을 종료한다. 이 저장 상태가 runtime의 `review-ready` 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. 구현 에이전트는 code-review를 실행하거나 review 전용 작업을 수행하지 않고, runtime은 별도 review 에이전트 instance에 즉시 인계한다.
