<!-- task=m-node-multi-target-serving-foundation/07+02_runtime_concurrency plan=0 tag=REFACTOR -->

# Plan - REFACTOR

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

구현 완료 전 `CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운다. 사용자 전용 blocker는 review stub에 기록하고 직접 질문하지 않는다.

## 배경

proto-socket은 nonce/pending request로 멀티 호출을 실을 수 있지만, Node runtime이 실제 동시 실행 제한과 queue/reject/timeout 정책을 적용해야 안정적이다. 현재 `runtime.concurrency`와 adapter capability의 `MaxConcurrency`는 실행 path에서 실질적인 gate로 보이지 않는다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub에 기록한다. code-review가 후속 상태를 결정한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/node-multi-target-serving-foundation.md`
- Task ids:
  - `runtime-concurrency`: `runtime.concurrency`와 adapter capability가 Node 멀티 호출에서 실제 제한 또는 스케줄링 정책으로 적용된다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/node-smoke.md`
- `apps/node/internal/node/node.go`
- `apps/node/internal/node/run_manager.go`
- `apps/node/internal/node/node_test.go`
- `apps/node/internal/runtime/types.go`
- `apps/node/internal/transport/session.go`
- `apps/node/internal/adapters/registry.go`
- `proto/iop/runtime.proto`

### 테스트 환경 규칙

- test_env: `local`
- concurrency logic은 `go test -race` 또는 deterministic ordering test가 권장된다. 최종 계약은 `go test -race -count=1 ./apps/node/internal/node/...`와 `go test -count=1 ./apps/node/...`다.

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

- `Node.OnRunRequest`는 adapter 실행 전 concurrency permit을 획득하지 않는다 (`apps/node/internal/node/node.go:122`).
- `run_manager`는 active run tracking/cancel 중심이고 scheduling/limit 정책이 없다.
- background run은 goroutine으로 바로 실행되어 global 또는 adapter별 limit을 우회할 수 있다 (`apps/node/internal/node/node.go:132`).

### 심볼 참조

- rename/remove 예정 심볼: 없음. `NodeRuntimeConfig.Concurrency`, `runtime.Capabilities.MaxConcurrency`, `RunRequest.Background`, `runManager` 참조를 확인한다.

### 분할 판단

- predecessor `02`: adapter registry namespace 완료 필요. 현재 active plan, complete 없음.
- route catalog/provider profile과 독립적으로 Node runtime gate를 구현할 수 있어 `03/04/05/06`에는 의존하지 않는다.

### 범위 결정 근거

- proto-socket 자체의 멀티 요청 구현을 다시 작성하지 않는다. transport는 요청을 실어 나르는 계층으로 두고 Node runtime scheduling만 담당한다.
- policy는 하나만 선택한다. queue/reject/timeout 중 여러 정책을 동시에 노출하지 않는다.

### 빌드 등급

- build: `cloud-G07`, review: `cloud-G08`. concurrency는 hard-to-review failure mode가 있어 cloud lane으로 둔다.

## 의존 관계 및 구현 순서

- `07+02_runtime_concurrency`는 `02+01_adapter_registry` 완료 후 구현한다.

## 구현 체크리스트

- [ ] Node runtime global concurrency와 adapter/profile concurrency 중 적용 우선순위를 정의한다.
- [ ] Foreground/background run 모두 동일한 scheduling/limit 정책을 통과한다.
- [ ] 제한 초과 요청의 queue/reject/timeout 중 하나를 선택하고 error/event/store 상태를 테스트로 고정한다.
- [ ] race/order test를 추가하고 최종 검증을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] Runtime Concurrency Gate

- 문제: `Node.OnRunRequest`는 store insert 후 바로 adapter `Execute`를 호출한다 (`apps/node/internal/node/node.go:127`). runtime concurrency config와 adapter capability `MaxConcurrency`가 실행 제한으로 연결되어 있지 않다.
- 해결 방법: Node에 scheduler/permit manager를 두고 global runtime limit과 adapter/profile limit을 계산한다. policy는 우선 `reject` 또는 bounded wait timeout 중 하나로 고정하고, background/foreground 모두 같은 permit path를 탄다. cancellation과 store completion status가 permit 획득 전/후에서 일관되게 남도록 한다.
- 수정 파일 및 체크리스트:
  - [ ] `apps/node/internal/node/node.go`: run execution을 scheduler permit으로 감싼다.
  - [ ] `apps/node/internal/node/run_manager.go`: active run tracking과 scheduling 책임을 분리하거나 확장한다.
  - [ ] `apps/node/internal/runtime/types.go`: capability/concurrency metadata 확인.
  - [ ] `proto/iop/runtime.proto`: 필요한 config 필드가 이미 충분한지 확인.
- 테스트 작성: 추가한다. `node_test.go`에 blocking adapter 두 개를 이용해 limit 1에서 두 번째 요청이 정의된 정책대로 reject/timeout/queue 되는지, background run도 gate를 통과하는지 검증한다. race test가 통과해야 한다.
- 중간 검증:
  - `go test -race -count=1 ./apps/node/internal/node/...`

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/node/internal/node/node.go` | REFACTOR-1 |
| `apps/node/internal/node/run_manager.go` | REFACTOR-1 |
| `apps/node/internal/node/node_test.go` | REFACTOR-1 |
| `apps/node/internal/runtime/types.go` | REFACTOR-1 |
| `proto/iop/runtime.proto` | REFACTOR-1 |

## 최종 검증

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

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