<!-- task=specialized_agent_contract plan=0 tag=API -->

# Specialized Agent Proto-Socket Contract Plan

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

구현 마지막 단계에서 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 반드시 채운다. 검증 명령을 실행하고 실제 출력과 구현 메모를 기록한 뒤, active 파일은 그대로 둔 채 review ready로 보고한다. 판정, 로그 rename, `complete.log`, archive 이동은 code-review-skill 전용이다.

## 배경

현재 활성 마일스톤은 OTO 같은 specialized domain agent가 기존 Edge-Node proto-socket 흐름을 node-compatible peer로 재사용할 때의 Edge 쪽 계약을 정리하는 단계다. 코드와 proto는 이미 generic Node 중심의 registration/config/run/command 흐름을 갖고 있지만, agent kind, registry/config/message boundary, reconnect 정책이 아직 문서상 완료되지 않았다. 이번 계획은 구현을 넓히지 않고 마일스톤 문서 안에서 후속 bootstrap/enrollment가 추측 없이 이어받을 수 있는 결정 기준을 닫는다.

## 분석 결과

### 읽은 파일

- `agent-ops/roadmap/current.md`
- `agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md`
- `agent-ops/roadmap/milestones/agent-bootstrap-oto-enrollment.md`
- `docs/architecture.md`
- `docs/deploy-dev.md`
- `proto/iop/runtime.proto`
- `apps/edge/internal/transport/server.go`
- `apps/edge/internal/node/registry.go`
- `apps/edge/internal/node/store.go`
- `apps/edge/internal/node/mapper.go`

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

- 마일스톤 문서 갱신: 기존 자동 테스트 없음. `git diff --check`와 deterministic `rg --sort path` 검증으로 문서 상태를 확인한다.
- proto/schema/Go 구현 변경: 이번 계획 범위에서 제외하므로 Go 테스트는 필수 검증에서 제외한다.

### 심볼 참조

- none. 이번 작업은 rename/remove 없이 문서 계약만 갱신한다.

### 분할 판단

분할 정책을 먼저 평가했다. 남은 item-id는 `agent-kind`, `registry-entry`, `config-boundary`, `message-boundary`, `reconnect-policy`, `bootstrap-precondition`로 나뉘지만 모두 같은 마일스톤 문서의 계약 결정이며 구현 산출물도 하나다. registry 결정이 나머지 기준의 배경이 되지만 별도 코드/API 산출물을 먼저 완료해야 하는 의존 관계는 없고, 여러 subtask로 나누면 같은 파일 충돌과 중복 리뷰가 생긴다. 따라서 단일 계획이 더 안전하다.

### 범위 결정 근거

수정 대상은 `agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md`로 제한한다. `proto/iop/runtime.proto`, `apps/edge/internal/**`, `apps/node/internal/**`는 현재 코드 근거로만 읽고 수정하지 않는다. `agent-bootstrap-oto-enrollment.md`, `docs/architecture.md`, `docs/deploy-dev.md`는 기존 책임 경계와 후속 마일스톤 참조용으로만 사용하고, 이번 계획에서 직접 갱신하지 않는다.

### 빌드 등급

Build lane: `local-G04`; Review lane: `local-G04`. 문서-only 변경이고 검증은 deterministic 검색과 whitespace check로 충분하지만, protocol/registry 경계 판단이 있어 G04로 둔다.

## 구현 체크리스트

- [ ] `agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md`에 agent kind와 registry entry 계약을 추가하고 `[agent-kind]`, `[registry-entry]`를 완료 상태로 갱신한다.
- [ ] config/message/reconnect 계약을 추가하고 `[config-boundary]`, `[message-boundary]`, `[reconnect-policy]`를 완료 상태로 갱신한다.
- [ ] bootstrap 선행 조건과 완료 기준 정합성을 정리하고 `[bootstrap-precondition]` 및 충족된 완료 기준을 갱신한다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 실제 출력이 계획의 기대 결과와 일치하는지 확인한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] Agent Kind And Registry Entry Contract

#### 문제

`agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md:33`와 `:34`의 `[agent-kind]`, `[registry-entry]`가 미완료다. 코드상 `apps/edge/internal/node/registry.go:13-20`의 `NodeEntry`는 `NodeID`, `Alias`, `Client`, index만 갖고, `server.go:156-162`에서 registration record를 그대로 connected entry로 등록한다. 따라서 문서에 Edge-side registration record가 agent kind를 소유하고, connected entry가 어떤 lifecycle/capability를 최소로 가져야 하는지 결정 기준을 추가해야 한다.

#### 해결 방법

마일스톤 문서에 `## 계약 결정` 섹션을 만들고 agent kind와 registry entry 결정을 먼저 둔다. proto field 추가는 후속 조건으로 남기고, 현재 마일스톤은 token이 가리키는 Edge-side record에서 kind를 판별한다는 기준을 명확히 한다.

Before (`agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md:30-36`):

```markdown
## 필수 기능

- [x] [node-flow-map] 기존 Edge-Node 등록, config, run/event, command, heartbeat 흐름이 specialized agent 관점에서 매핑되어 있다.
- [ ] [agent-kind] Edge registry에서 generic Node와 specialized domain agent를 구분하는 기준 후보가 정리되어 있다.
- [ ] [registry-entry] connected entry가 agent kind, capability, lifecycle을 가질 수 있는지, 기존 `NodeEntry`/registry를 확장할지 별도 registry로 분리할지 기준이 정리되어 있다.
```

After 방향:

```markdown
## 계약 결정

### Agent Kind / Registry Entry

- `RegisterRequest`에는 당장 kind field를 추가하지 않는다.
- Edge-side registration record가 `agent_kind`를 소유하며 초기 후보는 `generic-node`, `oto-agent`다.
- connected entry는 `agent_kind`, capability summary, lifecycle state를 담을 수 있는 agent entry로 확장하는 방향을 1차 후보로 둔다.
- 별도 registry는 generic Node와 specialized agent의 routing/index/display 규칙이 분리되어야 할 때 선택한다.
```

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

- [ ] `agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md`에 `Agent Kind / Registry Entry` 계약을 추가한다.
- [ ] `[agent-kind]`, `[registry-entry]`를 `[x]`로 바꾸되, 본문 결정 근거가 없는 체크만 하지 않는다.
- [ ] `NodeEntry` 구현 확정이나 schema 변경 지시를 넣지 않는다.

#### 테스트 작성

테스트 작성 skip. 문서 계약 갱신이며 런타임 동작 변경이 없다.

#### 중간 검증

```bash
rg --sort path -n "\[x\] \[(agent-kind|registry-entry)\]|Agent Kind / Registry Entry|agent_kind|generic-node|oto-agent" agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md
```

기대 결과: 두 item-id가 `[x]`로 출력되고, 계약 섹션과 `agent_kind`, `generic-node`, `oto-agent` 근거가 함께 출력된다.

### [API-2] Config Message And Reconnect Boundary

#### 문제

`agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md:35-38`의 `[config-boundary]`, `[message-boundary]`, `[reconnect-policy]`가 미완료다. `proto/iop/runtime.proto:132-149`는 `RegisterRequest(token)`과 `RegisterResponse.config NodeConfigPayload`만 제공하고, `RunRequest/RunEvent`와 `NodeCommandRequest/Response`는 `runtime.proto:21-113`의 generic Node execution/command envelope다. `server.go:142-145`는 duplicate connection을 현재 "node already connected"로 거부하므로 specialized agent 관점의 replace/reject 기준도 문서화가 필요하다.

#### 해결 방법

같은 `## 계약 결정` 섹션에 config, message, reconnect 하위 결정을 추가한다. 기준은 "registration smoke까지는 기존 handshake와 config 전달 패턴 재사용, OTO 전용 build/deploy semantics는 metadata/result로 장기 고정하지 않고 후속 전용 payload 필요 조건을 기록"이다.

After 방향:

```markdown
### Config / Message Boundary

- `RegisterResponse`는 accepted/node_id/alias/config 패턴을 유지한다.
- generic Node에는 `NodeConfigPayload`를 그대로 보낸다.
- `oto-agent`에는 최소 runtime identity/config만 공통 handshake에서 전달하고, build/deploy 전용 설정은 후속 OTO config message나 typed payload가 필요해질 때 분리한다.
- `RunRequest/RunEvent`, `CancelRequest`, `NodeCommandRequest/Response`는 envelope와 request-response 패턴만 재사용한다.
- artifact/log/progress/build-result 의미는 Node adapter stream으로 확정하지 않고 OTO 전용 payload 후보로 둔다.

### Reconnect / Duplicate Policy

- 같은 agent identity의 중복 연결 기본값은 reject다.
- 명시적인 reconnect token/session generation이 생기기 전에는 기존 연결 자동 대체를 하지 않는다.
- 후속 구현에서 replace를 허용할 경우 old connection close reason과 audit event가 먼저 정의되어야 한다.
```

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

- [ ] `config-boundary`, `message-boundary`, `reconnect-policy` 결정을 본문에 추가한다.
- [ ] `[config-boundary]`, `[message-boundary]`, `[reconnect-policy]`를 `[x]`로 갱신한다.
- [ ] `NodeConfigPayload`를 OTO 장기 설정 포맷으로 확정하지 않는다.
- [ ] duplicate 기본값과 replace 허용 조건을 분리해 쓴다.

#### 테스트 작성

테스트 작성 skip. 문서-only 계약이며 proto와 Go transport를 변경하지 않는다.

#### 중간 검증

```bash
rg --sort path -n "\[x\] \[(config-boundary|message-boundary|reconnect-policy)\]|Config / Message Boundary|Reconnect / Duplicate Policy|NodeConfigPayload|RunRequest/RunEvent|reject|replace" agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md
```

기대 결과: 세 item-id가 `[x]`로 출력되고, config/message/reconnect 결정 키워드가 출력된다.

### [API-3] Bootstrap Preconditions And Milestone Closure

#### 문제

`agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md:39`의 `[bootstrap-precondition]`이 미완료이고, `:43-48`의 완료 기준도 아직 체크되지 않았다. 후속 `agent-bootstrap-oto-enrollment.md:16-22`는 사용자 결정이 필요한 잠금 상태이므로, 이번 마일스톤은 bootstrap UX나 credential 정책을 결정하면 안 된다. 대신 후속 마일스톤이 의존할 transport/handshake 선행 조건과 run/command smoke 범위만 정리해야 한다.

#### 해결 방법

bootstrap precondition 하위 섹션을 추가하고, 현재 마일스톤이 보장하는 조건과 후속 마일스톤으로 넘기는 결정을 나눈다. 충족된 완료 기준은 `[x]`로 바꾸되, 후속 locked milestone의 사용자 결정 항목은 완료 처리하지 않는다.

After 방향:

```markdown
### Bootstrap Preconditions

- 후속 bootstrap/enrollment는 Edge outbound proto-socket listener, token 기반 registration, accepted/node_id/alias response, heartbeat를 선행 조건으로 가정할 수 있다.
- agent kind는 bootstrap token/registration record에 묶인다.
- bootstrap command UX, credential 보안 기준, 초기 capability/run 준비 범위는 `Agent Bootstrap과 OTO 등록` 마일스톤의 잠금 결정으로 남긴다.
- 이번 마일스톤의 run/command smoke 요구는 registration 이후 envelope compatibility 확인 기준까지만 둔다.
```

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

- [ ] `Bootstrap Preconditions` 계약을 추가한다.
- [ ] `[bootstrap-precondition]`을 `[x]`로 갱신한다.
- [ ] 완료 기준 중 이번 계약으로 충족된 항목만 `[x]`로 갱신한다.
- [ ] 후속 bootstrap 마일스톤의 잠금 결정 항목을 이번 문서에서 임의 확정하지 않는다.

#### 테스트 작성

테스트 작성 skip. 후속 마일스톤 입력 조건을 문서화하는 작업이다.

#### 중간 검증

```bash
rg --sort path -n "\[x\] \[bootstrap-precondition\]|Bootstrap Preconditions|Agent Bootstrap과 OTO 등록|registration 이후 envelope compatibility|credential 보안 기준" agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md
```

기대 결과: `[bootstrap-precondition]`이 `[x]`로 출력되고, 후속 잠금 결정과 이번 마일스톤 선행 조건이 분리되어 출력된다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md` | API-1, API-2, API-3 |

## 최종 검증

Go test cache output policy: Go 테스트를 실행하지 않는다. 이번 작업은 문서-only이고 런타임/스키마 동작 변경이 없다.

```bash
git diff --check
```

기대 결과: 출력 없음, exit 0.

```bash
rg --sort path -n "\[x\] \[(agent-kind|registry-entry|config-boundary|message-boundary|reconnect-policy|bootstrap-precondition)\]" agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md
```

기대 결과: 여섯 개 item-id가 모두 `[x]`로 출력된다.

```bash
rg --sort path -n "Agent Kind / Registry Entry|Config / Message Boundary|Reconnect / Duplicate Policy|Bootstrap Preconditions|proto schema와 생성 코드를 변경하지 않는다|Edge registry/API/DB schema를 구현하지 않는다" agent-ops/roadmap/milestones/specialized-agent-proto-socket-foundation.md
```

기대 결과: 네 개 계약 섹션과 기존 범위 제외 문장이 출력된다.

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