<!-- task=m-node-resource-model-unification/04+01,02,03_dev_runtime_profile plan=0 tag=TEST -->

# Dev Runtime Single Mac Node Profile Plan

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

이 계획은 `01_contract_schema`, `02+01_node_admission`, `03+01_edge_dispatch_status` 완료 후 구현한다. 구현 뒤에는 반드시 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 채운다. 원격 runner, secret, provider 접근 문제가 있으면 사용자에게 묻지 말고 검증 결과와 남은 위험으로 기록한다.

## 배경

사용자는 mac에 연결된 Codex CLI와 MLX vLLM provider가 node 두 개가 아니라 하나의 node id/alias 아래 resource로 나열되기를 원한다. 현재 dev 문서와 inventory는 `mac-codex-node`와 `mac-mlx-vllm-node`를 분리하고 4-node 기준을 섞어 둔다. 이 subtask는 구현 결과를 dev-runtime 기준에 반영하고, 3 connected nodes + 3 provider candidates로 배포 검증한다.

## 사용자 리뷰 요청 흐름

선택된 Milestone의 구현 잠금은 해제되어 있으므로 기본값은 `없음`이다. 원격 host, token, provider 상태, port 충돌, smoke 불안정은 사용자 리뷰 요청이 아니라 검증 blocker/후속 evidence로 기록한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/node-resource-model-unification.md`
- Task ids:
  - `dev-runtime-profile`: Dev runtime single Mac node profile and capacity smoke
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-test/dev/inventory.yaml`
- `agent-test/dev/rules.md`
- `agent-test/dev/edge-smoke.md`
- `agent-test/dev/node-smoke.md`
- `agent-test/dev/platform-common-smoke.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/node-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `docs/edge-local-dev-guide.md`
- `agent-ops/skills/project/dev-runtime-deploy/SKILL.md`
- `scripts/dev/edge.sh`
- `scripts/dev/node.sh`
- `scripts/dev/web.sh`
- `configs/edge.yaml`
- `apps/edge/internal/edgecmd/node_register.go`
- `apps/edge/internal/edgecmd/edgecmd_test.go`
- `apps/edge/internal/bootstrap/runtime.go`
- `apps/edge/internal/bootstrap/runtime_test.go`
- `agent-roadmap/phase/operational-observability-provider-management/milestones/node-resource-model-unification.md`
- `agent-roadmap/sdd/operational-observability-provider-management/node-resource-model-unification/SDD.md`

### SDD 기준

선택된 Milestone은 `SDD: 필요`이며 `agent-roadmap/sdd/operational-observability-provider-management/node-resource-model-unification/SDD.md`가 `[승인됨]`, SDD 잠금 `해제` 상태다. 이 subtask는 Acceptance Scenario `S07`과 Milestone Task `dev-runtime-profile`을 대상으로 한다.

Evidence Map은 dev-runtime clean deploy, connected nodes/provider candidates 확인, `/v1/responses`, `/v1/chat/completions`, capacity accounting smoke evidence를 요구한다. 따라서 구현 체크리스트는 Mac resource merge, dev docs alignment, config check/refresh handling, total capacity 10과 queued >= 1 smoke 기록을 포함한다.

### 테스트 환경 규칙

test_env는 plan 기본값 `local`이지만 이 subtask는 dev-runtime 원격 배포 검증을 포함한다. `agent-test/dev/inventory.yaml`, `agent-test/dev/edge-smoke.md`, `agent-test/dev/node-smoke.md`를 추가로 읽고 dev preflight를 계획에 포함한다. 필수 local unit은 `go test -count=1 ./...`이고, 원격 검증은 clean sync/rebuild 후 `config check`, `config refresh --mode dry-run`, `/v1/models`, `/v1/responses`, `/v1/chat/completions` capacity smoke다.

### 테스트 환경 프리플라이트

- runner: `ssh toki@toki-labs.com`
- repo root: `/Users/toki/agent-work/iop-dev`
- Edge config: `build/dev-runtime/edge.yaml`
- Edge id: `edge-toki-labs-dev`
- binaries: `build/dev-runtime/bin/edge`, `build/dev-runtime/bin/iop-node`, `build/dev-runtime/bin/iop-node-linux-arm64`, `build/dev-runtime/bin/iop-node-windows-amd64.exe`
- ports: Control Plane `18001`, OpenAI `18083`, Edge-Node TCP `18084`, refresh admin `19093`
- source sync: clean `origin/main` sync and `go test ./...` before rebuild.
- expected nodes after change: `mac-codex-node`, `gx10-vllm-node`, `onexplayer-lemonade-node`.
- expected provider candidates: `gx10-vllm=4`, `onexplayer-lemonade=3`, `mac-mlx-vllm=3`.

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

- `build/dev-runtime/edge.yaml` is runtime artifact, not tracked; unit tests cannot prove remote config was actually merged.
- Capacity smoke is timing-sensitive; plan must record max observed `in_flight` and `queued`, not just HTTP success.
- Dev docs currently disagree: deploy skill mentions 3 connected nodes while `agent-test/dev/*` and docs still say 4 nodes.

### 심볼 참조

삭제/rename symbol 없음. config/resource id changes:

- remove separate `mac-mlx-vllm-node` runtime node process from dev profile.
- keep provider id `mac-mlx-vllm` under `mac-codex-node` so `models[].providers` can remain stable.

### 분할 판단

이 subtask는 `04+01,02,03_dev_runtime_profile`이다. predecessors `01`, `02`, `03` 모두 `complete.log`가 필요하다. 현재 모두 active plan 상태이며 `complete.log`가 없다.

### 범위 결정 근거

This task does not rework Edge/Node source behavior beyond prior subtasks. It updates dev profile/docs and performs deployment validation. Production/corp environment is excluded.

### 빌드 등급

`cloud-G07`: remote runner, multi-host runtime, Windows/macOS/Linux node bootstrap, and external provider capacity smoke are central.

## 의존 관계 및 구현 순서

`04+01,02,03_dev_runtime_profile` must wait for sibling `01_contract_schema`, `02+01_node_admission`, and `03+01_edge_dispatch_status` completion. No additional hidden dependency is added.

## 구현 체크리스트

- [ ] dev-runtime config/profile에서 `mac-codex-node` 하나에 CLI adapter와 `mac-mlx-vllm` OpenAI-compatible provider resource를 함께 둔다.
- [ ] `mac-mlx-vllm-node` 별도 node/process/log 기준을 제거하거나 legacy note로 낮추고, provider id `mac-mlx-vllm`은 유지한다.
- [ ] `agent-test/dev/*`, `agent-test/local/*`, `docs/edge-local-dev-guide.md`, dev-runtime deploy skill의 node/provider 기준을 3 connected nodes + 3 provider candidates로 일치시킨다.
- [ ] dev-runtime clean sync, rebuild, config check, refresh dry-run/apply 또는 restart-required handling을 수행한다.
- [ ] `/v1/responses`와 `/v1/chat/completions` capacity smoke에서 total capacity 10, queued >= 1을 관측하고 완료 후 0/0 회복을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [TEST-1] Dev Profile Merge For Mac Resources

**문제:** `agent-test/dev/inventory.yaml:49`는 `mac-codex-node`를 CLI node로, `:69`는 `mac-mlx-vllm-node`를 별도 provider node로 둔다. 사용자의 원하는 구조는 같은 mac node identity 아래 CLI와 MLX provider resource가 함께 나열되는 것이다.

**해결 방법:** dev-runtime `edge.yaml` candidate에서 `mac-codex-node` adapters에 CLI와 `openai_compat_instances[name=mac-mlx-vllm]`를 같이 두고, `providers[]`에 `id=mac-mlx-vllm`, `adapter=mac-mlx-vllm`, `capacity=3`을 둔다. `models[].providers.mac-mlx-vllm`는 유지한다.

Example target shape:

```yaml
nodes:
  - id: mac-codex-node
    alias: mac-codex
    adapters:
      cli:
        enabled: true
      openai_compat_instances:
        - name: mac-mlx-vllm
          enabled: true
          provider: vllm-mlx
          endpoint: http://127.0.0.1:8002/v1
          capacity: 3
    providers:
      - id: mac-mlx-vllm
        type: vllm-mlx
        category: local_inference
        adapter: mac-mlx-vllm
        capacity: 3
```

**수정 파일 및 체크리스트:**

- [ ] remote `build/dev-runtime/edge.yaml` candidate
- [ ] `agent-test/dev/inventory.yaml`
- [ ] `agent-test/dev/edge-smoke.md`
- [ ] `agent-test/dev/node-smoke.md`
- [ ] `agent-test/local/edge-smoke.md`
- [ ] `agent-test/local/node-smoke.md`

**테스트 작성:** tracked test rule/docs 변경은 unit test 대신 deterministic grep 검증을 둔다. Remote `config check`가 schema test 역할을 한다.

**중간 검증:**

```bash
rg --sort path -n "4-node|4개 Node|mac-mlx-vllm-node|connected non-candidate" agent-test/dev agent-test/local docs/edge-local-dev-guide.md agent-ops/skills/project/dev-runtime-deploy/SKILL.md
```

### [TEST-2] Dev Docs And Deploy Skill Alignment

**문제:** `docs/edge-local-dev-guide.md:133`부터 provider candidates와 `:136` connected non-candidate가 4-node 기준으로 남아 있고, `agent-test/dev/edge-smoke.md:46`도 4-node 연결을 말한다. deploy skill은 이미 3개 node connected 기준을 일부 사용한다.

**해결 방법:** 모든 dev-runtime 문서의 표현을 "3 connected nodes, 3 provider candidates, mac node has CLI + MLX provider resource"로 통일한다. Mac MLX process 운영 파일은 vllm-mlx provider process 로그로 유지하되 별도 iop-node 로그 기준은 제거한다.

**수정 파일 및 체크리스트:**

- [ ] `docs/edge-local-dev-guide.md`
- [ ] `agent-ops/skills/project/dev-runtime-deploy/SKILL.md`
- [ ] `agent-test/dev/rules.md`
- [ ] `agent-test/dev/edge-smoke.md`
- [ ] `agent-test/dev/node-smoke.md`
- [ ] `agent-test/local/edge-smoke.md`
- [ ] `agent-test/local/node-smoke.md`

**테스트 작성:** docs-only consistency grep을 사용한다.

**중간 검증:**

```bash
rg --sort path -n "4-node|4개 Node|4개 node|mac-mlx-vllm-node|node-mac-mlx-vllm" agent-test/dev agent-test/local docs/edge-local-dev-guide.md agent-ops/skills/project/dev-runtime-deploy/SKILL.md
```

### [TEST-3] Remote Dev Runtime Smoke

**문제:** source 변경만으로는 사용자가 원하는 runtime 구조가 실제 dev environment에서 동작하는지 확인할 수 없다. 별도 mac MLX node process가 남으면 SQLite lock이나 duplicate node confusion이 재발할 수 있다.

**해결 방법:** remote runner를 clean sync/rebuild하고 Edge/mac/gx10/onexplayer runtime을 새 config로 재시작한다. Control Plane status에서 connected node가 3개인지, `mac-codex-node` snapshot에 CLI resource와 `mac-mlx-vllm` provider resource가 같이 보이는지 확인한다.

**수정 파일 및 체크리스트:**

- [ ] remote `/Users/toki/agent-work/iop-dev/build/dev-runtime/edge.yaml`
- [ ] remote process scripts/commands used for Edge and Node restart
- [ ] `CODE_REVIEW-cloud-G07.md` verification output

**테스트 작성:** no unit test. 실제 remote smoke가 test다.

**중간 검증:**

```bash
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git status --short --branch && git log --oneline -1 && go test ./...'
```

### [TEST-4] Capacity Smoke With Provider-only Concurrency

**문제:** 새 구조에서 mac CLI와 mac MLX provider가 같은 node id를 공유하므로, provider capacity accounting이 node-wide gate 없이 provider id별로 독립 유지되어야 한다.

**해결 방법:** `/v1/responses`와 `/v1/chat/completions` 각각 capacity+1 동시 요청을 보내고, Control Plane `provider_snapshots`에서 `gx10-vllm + onexplayer-lemonade + mac-mlx-vllm` total `in_flight=10`, `queued>=1`, 완료 후 `0/0`을 기록한다. CLI 호출은 별도 provider queue를 차지하지 않는지 status로 확인한다.

**수정 파일 및 체크리스트:**

- [ ] remote smoke command/output 기록
- [ ] `CODE_REVIEW-cloud-G07.md` capacity evidence

**테스트 작성:** remote smoke evidence. 요청별 node assignment 공개 API가 없으므로 aggregate snapshot으로 판정한다.

**중간 검증:**

```bash
ssh toki@toki-labs.com 'curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs-dev/status'
```

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `agent-test/dev/inventory.yaml` | TEST-1 |
| `agent-test/dev/rules.md` | TEST-2 |
| `agent-test/dev/edge-smoke.md` | TEST-1, TEST-2 |
| `agent-test/dev/node-smoke.md` | TEST-1, TEST-2 |
| `agent-test/local/edge-smoke.md` | TEST-1, TEST-2 |
| `agent-test/local/node-smoke.md` | TEST-1, TEST-2 |
| `docs/edge-local-dev-guide.md` | TEST-2 |
| `agent-ops/skills/project/dev-runtime-deploy/SKILL.md` | TEST-2 |
| remote `build/dev-runtime/edge.yaml` | TEST-1, TEST-3, TEST-4 |

## 최종 검증

```bash
go test -count=1 ./...
```

```bash
ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git status --short --branch && git log --oneline -1 && test -x build/dev-runtime/bin/edge && build/dev-runtime/bin/edge --config build/dev-runtime/edge.yaml config check && build/dev-runtime/bin/edge --config build/dev-runtime/edge.yaml config refresh --mode dry-run --addr 127.0.0.1:19093'
```

```bash
ssh toki@toki-labs.com 'curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs-dev/status && curl -fsS http://127.0.0.1:18083/v1/models'
```

Capacity smoke command may use a temporary script under `/tmp` on the runner. Record the exact script path and command in the review file; do not add it to the repo. Expected result: responses and chat completions each observe total provider `in_flight=10`, `queued>=1`, and final provider snapshots recover to `in_flight=0`, `queued=0`.

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