<!-- task=m-oto-agent-registry-implementation/02+01_registry_transport plan=0 tag=OAR02 -->

# OTO Agent Registry - Registry and Transport

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성은 필수다. 구현 후 검증을 실행하고 실제 변경 내용과 stdout/stderr를 채운 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, 또는 범위 충돌 없이는 진행할 수 없을 때만 review stub의 `사용자 리뷰 요청` 섹션에 근거를 적고 중단한다. 재실행으로 해소 가능한 증거 공백은 사용자 리뷰 요청이 아니다.

## 배경

`NodeStore`가 kind를 보존한 뒤에는 연결된 entry와 registration ack 경로가 그 kind를 잃지 않아야 한다. 현재 `NodeRegistry`와 transport server는 모든 연결을 node로만 취급한다. 이 계획은 OTO agent 연결을 같은 토큰 경로로 받되, entry kind와 중복 거부 사유를 구분한다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. `USER_REVIEW.md` 작성과 검증은 code-review가 담당한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/oto-agent-registry-implementation.md`
- Task ids:
  - `connected-entry`: 연결된 OTO agent가 Edge 내부 registry entry로 노출된다.
  - `duplicate-policy`: 동일 OTO identity/token 중복 연결 정책과 거부 사유가 구분된다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/domain/edge/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-test/local/testing-smoke.md`
- `apps/edge/internal/node/registry.go`
- `apps/edge/internal/node/registry_test.go`
- `apps/edge/internal/node/mapper.go`
- `apps/edge/internal/node/mapper_test.go`
- `apps/edge/internal/node/store.go`
- `apps/edge/internal/transport/server.go`
- `apps/edge/internal/transport/server_test.go`
- `apps/edge/internal/transport/integration_test.go`

### 테스트 환경 규칙

`test_env=local`이다. 적용 프로필은 `edge-smoke`, `platform-common-smoke`, `testing-smoke`다. 계약 명령은 `go test -count=1 ./apps/edge/internal/node ./apps/edge/internal/transport`와 최종 `go test -count=1 ./apps/edge/...`다.

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

- `NodeEntry.AgentKind` 보존: 신규 registry/mapper 테스트 필요.
- OTO token 연결 후 registry entry kind 확인: 신규 transport test 필요.
- 동일 OTO identity/token 중복 연결 거부 사유: 신규 transport test 필요.
- 기존 generic node 중복 거부 문구 회귀: 기존 테스트 보강 필요.

### 심볼 참조

rename/remove 없음. 관련 call site는 `node.NewRegistry`, `NodeRegistry.Register`, `NodeRegistry.List`, `mapper.BuildConfigPayload`, `transport.Server.onNodeConnected`, `transport.Server.HandleRegister`, transport/server/integration tests다.

### 분할 판단

공유 task group은 `m-oto-agent-registry-implementation`이다. 이 작업은 `02+01_registry_transport`이며 predecessor `01_config_store`의 `complete.log`가 필요하다. 현재 작성 시점에는 predecessor가 아직 완료되지 않았으므로 구현 에이전트는 시작 전 `agent-task/m-oto-agent-registry-implementation/01_config_store/complete.log` 또는 archive의 matching `01_* /complete.log`를 확인해야 한다.

### 범위 결정 근거

이 단계는 registry entry와 transport registration 경로만 수정한다. service snapshot 노출은 `03+01,02_service_snapshots`, CLI bootstrap command는 다음 milestone, proto/schema와 Control Plane wire 변경은 범위 밖이다.

### 빌드 등급

`local-G07`: 연결 경로와 중복 정책을 건드리지만 기존 transport 테스트로 재현 가능한 bounded 변경이다.

## 구현 체크리스트

- [ ] 시작 전 `01_config_store`의 `complete.log`로 predecessor 완료를 확인한다.
- [ ] `apps/edge/internal/node/registry.go`에 entry kind/lifecycle 필드를 추가하고 기존 registry 동작을 유지한다.
- [ ] `apps/edge/internal/node/mapper.go`가 OTO agent record에서도 안전한 config payload를 만들도록 필요한 기본값만 보강한다.
- [ ] `apps/edge/internal/transport/server.go`에서 token으로 찾은 record의 kind를 registry entry에 전달하고 OTO 중복 거부 사유를 구분한다.
- [ ] registry, mapper, transport tests를 추가/보강하고 중간 및 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [OAR02-1] Registry entry kind and lifecycle

#### 문제

`apps/edge/internal/node/registry.go:13`의 `NodeEntry`는 `ID`, `Alias`, `Role`만 공개한다. OTO agent가 연결되어도 내부 registry에서 일반 node와 구분되지 않는다.

#### 해결 방법

`NodeEntry.AgentKind`와 `LifecycleState`를 추가한다. empty kind는 `generic-node`, empty lifecycle은 `connected`로 방어한다. `DisplayLabel`은 이번 범위에서 유지한다.

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

- [ ] `apps/edge/internal/node/registry.go`: 필드 및 register-time 기본값 추가.
- [ ] `apps/edge/internal/node/registry_test.go`: OTO entry kind/lifecycle, 기존 list/get 회귀 테스트 추가.

#### 테스트 작성

작성한다. `TestRegistryRegisterPreservesAgentKind`와 lifecycle 기본값 테스트를 추가한다.

#### 중간 검증

```bash
go test -count=1 ./apps/edge/internal/node
```

예상 결과: node package 테스트 PASS.

### [OAR02-2] Transport registration kind and duplicate reason

#### 문제

`apps/edge/internal/transport/server.go:147`의 registration handler는 token record를 찾은 뒤 모든 연결을 node로 등록한다. `server.go:156` 부근의 중복 연결 거부도 OTO agent와 generic node를 구분하지 않는다.

#### 해결 방법

record의 `AgentKind`를 `NodeEntry`로 복사한다. 동일 ID가 이미 연결된 경우 `oto-agent`는 `oto agent already connected`, 그 외는 기존 node duplicate 문구를 유지한다.

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

- [ ] `apps/edge/internal/transport/server.go`: entry 생성과 duplicate reason 분기 추가.
- [ ] `apps/edge/internal/transport/server_test.go`: OTO registration entry kind와 duplicate reason 테스트 추가.
- [ ] `apps/edge/internal/transport/integration_test.go`: 필요 시 end-to-end registration smoke 보강.

#### 테스트 작성

작성한다. OTO token registration, duplicate OTO registration, generic duplicate 회귀 assertion을 추가한다.

#### 중간 검증

```bash
go test -count=1 ./apps/edge/internal/transport
```

예상 결과: transport package 테스트 PASS.

## 의존 관계 및 구현 순서

이 task directory의 `+01`은 `01_config_store` 완료 의존성을 뜻한다. 구현 전 predecessor `complete.log`를 확인한다. 구현 순서는 registry entry 필드 추가 후 transport 연결 경로 보강이다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/edge/internal/node/registry.go` | OAR02-1 |
| `apps/edge/internal/node/registry_test.go` | OAR02-1 |
| `apps/edge/internal/node/mapper.go` | OAR02-2 |
| `apps/edge/internal/node/mapper_test.go` | OAR02-2 |
| `apps/edge/internal/transport/server.go` | OAR02-2 |
| `apps/edge/internal/transport/server_test.go` | OAR02-2 |
| `apps/edge/internal/transport/integration_test.go` | OAR02-2 |

## 최종 검증

```bash
go test -count=1 ./apps/edge/internal/node ./apps/edge/internal/transport
```

예상 결과: node/transport package 테스트 PASS. Go test cache output은 허용하지 않는다.

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