<!-- task=m-bridge-boundary-hardening/03_adapter_config_typed plan=0 tag=API -->

# Plan - API

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

이 작업은 구현 후 active 파일을 유지하고, 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운 뒤 리뷰 준비 상태로 멈춘다. 구현 중 사용자 결정, 사용자 소유 외부 환경, 또는 계획 범위 충돌 없이는 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션에 근거를 남기고 중단한다. 구현 중 사용자에게 직접 질문하거나 `USER_REVIEW.md`, `complete.log`, archive log를 만들지 않는다.

## 배경

Milestone의 `adapter-config-typed` Task는 `AdapterConfig.settings`를 legacy fallback으로만 남기고, Edge가 새 adapter config를 typed oneof/proto 메시지로만 생성한다는 계약을 고정하는 작업이다. 현재 CLI/Ollama/VLLM은 typed config를 사용하지만 Edge mapper의 mock adapter payload는 `structpb.NewStruct(nil)`로 `settings`를 채워 신규 payload에서도 legacy 필드를 사용한다. 이 plan은 mock까지 typed oneof로 옮기고, 기존 Node legacy fallback은 호환 경로로 유지한다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 프롬프트는 금지하며, code-review가 요청 타당성을 검증하고 실제 `USER_REVIEW.md` 생성을 소유한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/bridge-boundary-hardening.md`
- Task ids:
  - `adapter-config-typed`: `AdapterConfig.settings`는 구버전 Edge payload fallback으로만 허용하고, Edge mapper와 신규 config는 typed oneof/proto 메시지를 사용한다는 guard를 테스트로 고정한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/bridge-boundary-hardening.md`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/node-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-test/local/testing-smoke.md`
- `agent-ops/rules/project/domain/edge/rules.md`
- `agent-ops/rules/project/domain/node/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `proto/iop/runtime.proto`
- `apps/edge/internal/node/mapper.go`
- `apps/edge/internal/node/mapper_test.go`
- `apps/edge/internal/transport/server_test.go`
- `apps/node/internal/adapters/factory.go`
- `apps/node/internal/adapters/factory_internal_test.go`
- `apps/node/internal/adapters/adapters_blackbox_test.go`
- `apps/node/internal/bootstrap/module_test.go`
- `apps/node/internal/transport/integration_test.go`
- `Makefile`

### 테스트 환경 규칙

- test_env: `local`.
- `agent-test/local/rules.md`를 읽었고, domain routing에 따라 `edge-smoke`, `node-smoke`, `platform-common-smoke`, 사용자 실행 파이프라인 영향 기준으로 `testing-smoke`를 읽었다.
- 적용 명령: `make proto && make proto-dart && go test -count=1 ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/node/internal/adapters ./proto/gen/...`.
- 사전 확인 결과: `go test -count=1 ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/node/internal/adapters ./proto/gen/...`는 현재 checkout에서 성공했다.
- 도구 확인 결과: `protoc`, `protoc-gen-go`, `protoc-gen-dart`가 현재 환경에 있다.
- Milestone 검증 명령은 `make proto && go test ...`이지만, proto 변경 시 tracked Dart binding drift를 막기 위해 `make proto-dart`도 최종 검증에 포함한다. 구현자가 Dart generation을 생략하면 이유와 남은 위험을 review stub에 기록한다.

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

- `apps/edge/internal/node/mapper_test.go`는 CLI/Ollama/VLLM typed payload를 검증한다.
- `apps/edge/internal/transport/server_test.go`는 Edge transport payload의 adapter config를 검증한다.
- `apps/node/internal/adapters/factory_internal_test.go`와 `apps/node/internal/bootstrap/module_test.go`는 legacy `settings` fallback 경로를 보유한다.
- 현재 공백: Edge가 생성하는 mock adapter config에서 `settings == nil`이고 typed mock config가 설정된다는 guard가 없다.

### 심볼 참조

- 변경 예정: `AdapterConfig` oneof, `BuildConfigPayload`, Edge mapper/transport tests.
- 유지 예정: Node `BuildFromPayload`의 legacy `settings` fallback, bootstrap legacy regression tests.
- 현재 legacy 생성 지점: `apps/edge/internal/node/mapper.go`의 mock adapter branch가 `structpb.NewStruct(nil)`를 `Settings`에 채운다.

### 분할 판단

- split decision policy를 적용했다.
- 공유 task group: `m-bridge-boundary-hardening`.
- sibling subtasks:
  - `01_edge_run_surface`: Edge run surface. 독립.
  - `02_terminal_core_boundary`: Node terminal package/interface boundary. 독립.
  - `03_adapter_config_typed`: typed adapter config contract. 독립.
- 이 subtask는 다른 sibling의 `complete.log`를 필요로 하지 않는다.

### 범위 결정 근거

- legacy `AdapterConfig.settings` fallback 즉시 제거는 Milestone 범위 제외이므로 제거하지 않는다.
- adapter execution behavior, provider defaults, terminal bridge protocol은 변경하지 않는다.
- proto field number는 새 oneof field를 추가해 호환성을 유지하고 기존 `settings = 3`, `cli = 4`, `ollama = 5`, `vllm = 6` 번호는 재사용하지 않는다.

### 빌드 등급

- `cloud-G06`: proto 계약과 Edge/Node 양쪽 테스트를 함께 만지지만 동작 변경은 mock config payload guard에 제한되고 실행 경로는 deterministic하다.

## 구현 체크리스트

- [ ] Mock adapter config를 typed oneof/proto 메시지로 추가하고 generated Go/Dart 바인딩을 동기화한다.
- [ ] Edge mapper와 transport tests가 신규 Edge-generated payload에서 `settings`를 사용하지 않음을 검증하게 한다.
- [ ] Node legacy fallback tests는 유지하고, 필요한 경우 typed mock config가 기존 mock adapter와 호환됨을 검증한다.
- [ ] 사용자 실행 파이프라인 영향에 대해 보조 smoke/full-cycle 수행 여부 또는 생략 사유를 검증 결과에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] Typed Mock Adapter Config

문제: 신규 Edge mapper payload가 mock adapter에 대해 legacy `settings`를 사용한다.

Before:

```go
// apps/edge/internal/node/mapper.go
settings, err := structpb.NewStruct(nil)
if err != nil {
	return nil, err
}
config = &runtimev1.AdapterConfig{Adapter: adapter, Settings: settings}
```

해결 방법: `proto/iop/runtime.proto`에 empty `MockAdapterConfig` message를 추가하고 `AdapterConfig.config` oneof에 새 field로 연결한다. Edge mapper는 mock adapter에 `AdapterConfig_Mock`을 채우며 `Settings`는 nil로 둔다. Node adapter factory는 mock config를 명시적으로 요구하지 않는 현재 동작을 유지하되, typed mock config가 들어와도 실패하지 않도록 필요한 테스트를 보강한다.

수정 파일 및 체크리스트:

- [ ] `proto/iop/runtime.proto`: `MockAdapterConfig` message와 `AdapterConfig.mock` oneof field 추가.
- [ ] `proto/gen/go/iop/runtime/v1/runtime.pb.go`: `make proto`로 재생성.
- [ ] `apps/client/lib/gen/iop/runtime/v1/runtime.pb.dart`: `make proto-dart`로 재생성.
- [ ] `apps/client/lib/gen/iop/runtime/v1/runtime.pbenum.dart`: 필요 시 `make proto-dart`로 재생성.
- [ ] `apps/client/lib/gen/iop/runtime/v1/runtime.pbjson.dart`: 필요 시 `make proto-dart`로 재생성.
- [ ] `apps/edge/internal/node/mapper.go`: mock branch에서 typed mock config 사용, `structpb` import 제거.
- [ ] `apps/edge/internal/node/mapper_test.go`: mock/cli/ollama/vllm Edge-generated config 모두 `Settings == nil`이고 적절한 typed config를 갖는다는 guard 추가.
- [ ] `apps/edge/internal/transport/server_test.go`: transport payload 검증에서 legacy settings가 신규 payload에 섞이지 않음을 확인.
- [ ] `apps/node/internal/adapters/factory_internal_test.go`: 기존 legacy fallback tests 유지, typed mock config 호환 guard가 필요하면 추가.

테스트 작성: 기존 mapper/transport/factory test 파일 안에 case를 추가한다. 새 테스트 파일은 만들지 않는다.

중간 검증:

```bash
make proto
make proto-dart
go test -count=1 ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/node/internal/adapters ./proto/gen/...
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `proto/iop/runtime.proto` | API-1 |
| `proto/gen/go/iop/runtime/v1/runtime.pb.go` | API-1 |
| `apps/client/lib/gen/iop/runtime/v1/runtime.pb.dart` | API-1 |
| `apps/client/lib/gen/iop/runtime/v1/runtime.pbenum.dart` | API-1 |
| `apps/client/lib/gen/iop/runtime/v1/runtime.pbjson.dart` | API-1 |
| `apps/edge/internal/node/mapper.go` | API-1 |
| `apps/edge/internal/node/mapper_test.go` | API-1 |
| `apps/edge/internal/transport/server_test.go` | API-1 |
| `apps/node/internal/adapters/factory_internal_test.go` | API-1 |

## 최종 검증

```bash
make proto
make proto-dart
go test -count=1 ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/node/internal/adapters ./proto/gen/...
```

예상 결과: proto generation succeeds without tracked drift, listed Go packages all pass.

사용자 실행 파이프라인 영향 기록: config/proto contract가 runtime startup payload에 닿으므로 보조 smoke/full-cycle 실제 구동을 수행했으면 명령과 출력을 붙이고, 수행하지 못했으면 `testing-smoke` 기준으로 사유와 남은 위험을 `CODE_REVIEW`에 기록한다.

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