<!-- task=m-model-group-long-context-admission/04+01,02_status_logs plan=0 tag=STATUS_LOGS -->

# Plan - STATUS_LOGS

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

이 task는 `01_input_estimator`와 `02+01_long_capacity`의 `complete.log`가 생긴 뒤 시작한다. 구현 완료 후 review stub의 구현 에이전트 소유 섹션과 검증 출력을 채우고 active 파일을 유지한다. `make proto`가 필요한 경우 생성물을 직접 편집하지 않는다. 사용자에게 직접 묻지 말고 Milestone lock blocker만 `사용자 리뷰 요청` 섹션에 기록한다.

## 배경

Milestone S08은 Control Plane status 또는 Edge log로 long admission 판단을 재구성할 수 있어야 한다. estimator와 long slot state가 생겨도 status/log 표면에 `estimated_input_tokens`, `context_class`, `long_context_capacity`, `long_in_flight`, queue reason이 남지 않으면 운영자가 왜 queue가 밀렸는지 알 수 없다.

## 사용자 리뷰 요청 흐름

사용자 리뷰 요청은 selected Milestone lock decision에 한정해 active review stub에 기록한다. 환경 준비, protoc 미설치, dev provider 미가동은 검증 blocker 또는 follow-up이지 사용자 리뷰 요청이 아니다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/model-group-long-context-admission.md`
- Task ids:
  - `status-logs`: status/log에 estimated_input_tokens, context_class, long_context_capacity, long_in_flight, long queue reason 기록
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/phase/operational-observability-provider-management/milestones/model-group-long-context-admission.md`
- `agent-roadmap/sdd/operational-observability-provider-management/model-group-long-context-admission/SDD.md`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-contract/index.md`
- `agent-contract/inner/edge-node-runtime-wire.md`
- `agent-contract/inner/control-plane-edge-wire.md`
- `proto/iop/runtime.proto`
- `Makefile`
- `apps/edge/internal/service/status_provider.go`
- `apps/edge/internal/service/status_provider_test.go`
- `apps/edge/internal/service/model_queue.go`
- `apps/edge/internal/service/model_queue_test.go`
- `apps/edge/internal/service/run_dispatch.go`
- `apps/edge/internal/controlplane/connector.go`
- `apps/edge/internal/controlplane/connector_test.go` (provider snapshots relay 구간 확인)
- `apps/edge/internal/openai/chat_handler.go`
- `apps/edge/internal/openai/responses_handler.go`

### SDD 기준

- SDD: `agent-roadmap/sdd/operational-observability-provider-management/model-group-long-context-admission/SDD.md`, 상태 `[승인됨]`.
- 대상 Acceptance: S08 / Milestone Task `status-logs`.
- Evidence Map: Control Plane status 또는 Edge log sample.
- 적용: provider snapshot에는 long slot 상태를 노출하고, request/admission log에는 estimate/class/queue reason을 남긴다.

### 테스트 환경 규칙

- test_env: `local`.
- local edge smoke profile을 적용한다.
- proto 변경은 `Makefile`의 `proto` target을 사용한다. preflight로 `command -v protoc`와 `command -v protoc-gen-go`를 실행한다.
- 최종 검증은 proto generation 후 service/controlplane/transport/wire Go tests를 fresh 실행한다.

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

- ProviderSnapshot에는 long capacity/in-flight field가 없다. proto/generated code/test 갱신 필요.
- Edge log sample은 현재 tests에서 직접 검증하지 않는다. 가능하면 zap observer 또는 event metadata test를 추가하고, 불가능하면 service status snapshot test를 필수 evidence로 둔다.
- Control Plane relay는 existing provider snapshot pass-through tests가 있으나 새 fields assertion이 없다.

### 심볼 참조

- renamed/removed symbol: none.
- proto additions: `ProviderSnapshot.long_context_capacity`, `ProviderSnapshot.long_in_flight`, 필요 시 `long_queued` 또는 `queue_reason`.
- generated call sites: `proto/gen/iop/runtime.pb.go`는 `make proto`로 갱신한다. 직접 편집 금지.

### 분할 판단

- shared task group: `agent-task/m-model-group-long-context-admission`.
- 현재 subtask `04+01,02_status_logs`는 predecessor indices `01`, `02`에 의존한다.
- 작성 시점에 두 predecessor `complete.log` 모두 없다. 구현 시작 전 active 또는 archived predecessor completion이 필요하다.
- dev smoke evidence는 06에서 수집한다.

### 범위 결정 근거

- admission algorithm 변경은 02/03 범위다. 이 plan은 이미 존재하는 estimate/class/long counters를 노출한다.
- 외부 Control Plane API 신규 기능은 만들지 않는다. 기존 Edge status snapshot relay에 field를 추가한다.
- client Dart proto가 소비하는 변경은 범위 밖이다. 실제 client 소비가 확인되면 별도 plan에서 `make proto-dart`를 다룬다.

### 빌드 등급

- `local-G07`: proto/status/log contract 변경이 있지만 변경 표면이 내부 wire와 local tests에 한정된다.

## 의존 관계 및 구현 순서

- `01_input_estimator` complete 필요: `agent-task/m-model-group-long-context-admission/01_input_estimator/complete.log`.
- `02+01_long_capacity` complete 필요: `agent-task/m-model-group-long-context-admission/02+01_long_capacity/complete.log`.

## 구현 체크리스트

- [ ] `ProviderSnapshot`와 관련 inner contract에 long capacity/in-flight 노출 필드를 추가하고 generated Go proto를 `make proto`로 갱신한다.
- [ ] service status snapshot이 `long_context_capacity`, `long_in_flight`, 필요한 queued/reason 정보를 채우게 한다.
- [ ] dispatch/queue log 또는 event metadata에 `estimated_input_tokens`, `context_class`, queue reason을 남긴다. 검증: status 또는 log sample로 admission 판단을 재구성할 수 있다.
- [ ] control-plane relay tests가 새 provider snapshot fields를 보존하는지 검증한다.
- [ ] proto preflight, `make proto`, 관련 Go tests를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [STATUS_LOGS-1] ProviderSnapshot long fields

### 문제

- [proto/iop/runtime.proto](/config/workspace/iop/proto/iop/runtime.proto:122)의 `ProviderSnapshot`은 `capacity`, `in_flight`, `queued`만 있고 long slot state가 없다.
- [apps/edge/internal/service/status_provider.go](/config/workspace/iop/apps/edge/internal/service/status_provider.go:20)는 provider snapshots를 Control Plane relay가 그대로 사용하게 만든다.

### 해결 방법

- `ProviderSnapshot`에 새 int32 fields를 추가한다. 기존 field numbers 1-12 뒤를 사용한다.
- `edge-node-runtime-wire.md`, `control-plane-edge-wire.md`에 field 의미를 갱신한다.
- `make proto`로 generated Go를 갱신한다.
- queue snapshot 생성 시 provider별 long capacity/current long in-flight를 채운다.

예상 proto:

```proto
int32 long_context_capacity = 13;
int32 long_in_flight = 14;
int32 long_queued = 15;
```

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

- [ ] `proto/iop/runtime.proto`
- [ ] `proto/gen/iop/runtime.pb.go` (`make proto` 산출물)
- [ ] `agent-contract/inner/edge-node-runtime-wire.md`
- [ ] `agent-contract/inner/control-plane-edge-wire.md`
- [ ] `apps/edge/internal/service/status_provider.go`
- [ ] `apps/edge/internal/service/status_provider_test.go`
- [ ] `apps/edge/internal/controlplane/connector_test.go`

### 테스트 작성

- [ ] status provider test: configured long capacity와 active long inflight가 snapshot field로 나온다.
- [ ] controlplane connector test: provider snapshot long fields가 relay 중 보존된다.

### 중간 검증

```bash
command -v protoc
command -v protoc-gen-go
make proto
go test -count=1 ./apps/edge/internal/service ./apps/edge/internal/controlplane
```

## [STATUS_LOGS-2] Admission log and queue reason evidence

### 문제

- `estimated_input_tokens`와 `context_class`는 request metadata로 전달되더라도 queue decision reason과 함께 운영 log에 남지 않으면 S08 재구성이 어렵다.

### 해결 방법

- dispatch enqueue/blocked/selected log 또는 event metadata에 `estimated_input_tokens`, `context_class`, provider id, queue reason(`long_context_capacity_full`, `capacity_full`, `dispatched`)을 남긴다.
- logger가 없는 내부 path라면 service result dispatch metadata 또는 event bus에 넣고 log emission이 가능한 boundary에서 zap fields로 출력한다.

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

- [ ] `apps/edge/internal/service/model_queue.go`: queue reason state.
- [ ] `apps/edge/internal/service/run_dispatch.go`: request estimate/class log fields.
- [ ] `apps/edge/internal/openai/chat_handler.go`, `responses_handler.go`: metadata keys가 01과 일치하는지 확인.
- [ ] `apps/edge/internal/service/model_queue_test.go`: reason이 long slot full일 때 남는지 확인.

### 테스트 작성

- [ ] long slot full로 queue된 item의 reason이 `long_context_capacity_full`.
- [ ] normal request dispatch log/metadata가 long slot reason 없이 `context_class=normal`을 유지.

### 중간 검증

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

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `proto/iop/runtime.proto` | STATUS_LOGS-1 |
| `proto/gen/iop/runtime.pb.go` | STATUS_LOGS-1 |
| `agent-contract/inner/edge-node-runtime-wire.md` | STATUS_LOGS-1 |
| `agent-contract/inner/control-plane-edge-wire.md` | STATUS_LOGS-1 |
| `apps/edge/internal/service/status_provider.go` | STATUS_LOGS-1 |
| `apps/edge/internal/service/status_provider_test.go` | STATUS_LOGS-1 |
| `apps/edge/internal/controlplane/connector_test.go` | STATUS_LOGS-1 |
| `apps/edge/internal/service/model_queue.go` | STATUS_LOGS-2 |
| `apps/edge/internal/service/run_dispatch.go` | STATUS_LOGS-2 |
| `apps/edge/internal/service/model_queue_test.go` | STATUS_LOGS-2 |

## 최종 검증

```bash
command -v protoc
command -v protoc-gen-go
make proto
go test -count=1 ./apps/edge/internal/service ./apps/edge/internal/controlplane ./apps/edge/internal/transport ./apps/node/internal/transport ./apps/control-plane/internal/wire
```

기대 결과: 모든 명령 PASS. `make proto` 후 generated Go diff가 proto field 추가와 일치해야 한다.

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