<!-- task=m-live-trading-boundary/01_broker_port plan=1 tag=REVIEW_LIVE_PORT -->

# Plan - REVIEW_LIVE_PORT

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 설계 결정, 명령 출력(stdout/stderr)을 기록한 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 최종 판정, 로그 rename, `complete.log`, archive 이동은 code-review 전용이다.

구현 중 사용자만 결정할 수 있는 사항, 사용자 소유 외부 환경/secret, 또는 계획 범위 충돌 없이는 안전하게 진행할 수 없으면 active review stub의 `사용자 리뷰 요청` 섹션에 정확한 결정, 근거, 실행 명령/출력, 재개 조건을 기록하고 중단한다. 구현 에이전트는 사용자에게 직접 묻거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니다.

## 배경

1차 리뷰는 live capability surface의 핵심 생성/등록은 확인했지만, Flutter client parser map, Hello capability advertisement, live request validation, API error-path tests가 빠져 FAIL 판정을 받았다. 이 follow-up은 기존 broker-port 범위 안에서 누락된 runtime contract 연결과 검증 증거만 보완한다.

## 사용자 리뷰 요청 흐름

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

## Roadmap Targets

- Milestone: `agent-roadmap/phase/trading-expansion/milestones/live-trading-boundary.md`
- Task ids:
  - `broker-port`: broker adapter port가 paper/live 공통 경계를 갖는다.
- Completion mode: check-on-pass

## 리뷰 근거

- Archived plan: `agent-task/m-live-trading-boundary/01_broker_port/plan_local_G07_0.log`
- Archived review: `agent-task/m-live-trading-boundary/01_broker_port/code_review_cloud_G06_0.log`
- Verdict: FAIL

## 범위 결정 근거

이 follow-up은 `GetLiveBrokerCapabilities` request/response가 API, worker, CLI, Flutter client parser 경계에서 일관되게 동작하도록 마감한다. 실제 KIS 주문 제출, 계좌 조회, order lifecycle, risk guard, audit trail, roadmap 상태 변경은 범위 밖이다. `packages/contracts/gen/**`와 `apps/client/lib/src/generated/**`는 새 schema 변경 없이 손대지 않는다.

## 구현 체크리스트

- [ ] [REVIEW_LIVE_PORT-1] Flutter client `altParserMap()`과 contract parser test가 live capability messages를 등록한다.
- [ ] [REVIEW_LIVE_PORT-2] API/worker `HelloResponse.capabilities`가 live capability handler registration과 동기화된다.
- [ ] [REVIEW_LIVE_PORT-3] API/worker live capability handlers가 빈 `account_id`를 typed `invalid_request`로 거절한다.
- [ ] [REVIEW_LIVE_PORT-4] API live handler error-path tests와 최종 검증 출력이 review artifact에 실제 stdout/stderr로 기록된다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_LIVE_PORT-1] Client Parser Map

#### 문제

`apps/client/lib/src/generated/alt/v1/live_trading.pb.dart`는 생성됐지만 `apps/client/lib/src/contracts/alt_contracts.dart`는 live generated file을 import하지 않고, `altParserMap()`도 live capability request/response/capability parser를 등록하지 않는다. Flutter socket client가 live capability payload를 받으면 parser map에서 type을 찾지 못할 수 있다.

#### 해결 방법

`alt_contracts.dart`에 `live_trading.pb.dart` import를 추가하고 아래 메시지를 등록한다.

- `GetLiveBrokerCapabilitiesRequest`
- `GetLiveBrokerCapabilitiesResponse`
- `LiveBrokerCapability`

`apps/client/test/contracts/alt_contracts_test.dart`도 같은 메시지를 expected list에 추가하고 parser count를 갱신한다. 이 subtask에서 `LiveOrder`, `LiveAccountSnapshot`, `LivePositionSnapshot`, `LiveAuditEvent`는 top-level runtime payload가 아니므로 등록하지 않는다.

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

- [ ] `apps/client/lib/src/contracts/alt_contracts.dart`
- [ ] `apps/client/test/contracts/alt_contracts_test.dart`

#### 중간 검증

```bash
cd apps/client && flutter test test/contracts/alt_contracts_test.dart
```

기대 결과: exit code 0.

### [REVIEW_LIVE_PORT-2] Hello Capability Sync

#### 문제

API는 `apiLiveHandlers(worker)`로 `GetLiveBrokerCapabilitiesRequest`를 등록하지만 `capabilitiesForSession()`에는 live capability가 없다. Worker도 `liveHandlers(deps)`를 등록하지만 `capabilitiesForDeps()`가 `deps.Live != nil`일 때 live capability를 광고하지 않는다.

#### 해결 방법

API `capabilitiesForSession()`에는 registered handler surface로서 `"live-trading"`을 추가한다. Worker `capabilitiesForDeps()`에는 `deps.Live != nil`일 때 `"live-trading"`을 추가한다. 기존 capability tests에 live case를 추가하고, API `TestCapabilitiesAndHandlersSync`가 live handler와 capability 동기화를 검증하게 한다.

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

- [ ] `services/api/internal/socket/handlers.go`
- [ ] `services/api/internal/socket/server_test.go`
- [ ] `services/worker/internal/socket/handlers.go`
- [ ] `services/worker/internal/socket/server_test.go`

#### 중간 검증

```bash
go test -count=1 ./services/api/internal/socket ./services/worker/internal/socket
```

기대 결과: exit code 0.

### [REVIEW_LIVE_PORT-3] Live Capability Request Validation

#### 문제

`GetLiveBrokerCapabilitiesRequest`는 `account_id`를 갖지만 API/worker live handlers가 빈 값을 그대로 worker/service로 전달한다. 1차 plan은 API live forwarding validation을 요구했고, paper/live request boundary는 malformed operator input을 typed error로 닫는 패턴을 유지해야 한다.

#### 해결 방법

API handler와 worker handler 모두 `req.GetAccountId() == ""`이면 service/worker 연결 전에 `invalid_request` typed response를 반환한다. 메시지는 live trading context를 드러내도록 `invalid live trading request: account_id is required`처럼 작성한다.

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

- [ ] `services/api/internal/socket/live.go`
- [ ] `services/api/internal/socket/live_test.go`
- [ ] `services/worker/internal/socket/live.go`
- [ ] `services/worker/internal/socket/live_test.go`

#### 중간 검증

```bash
go test -count=1 ./services/api/internal/socket ./services/worker/internal/socket
```

기대 결과: exit code 0.

### [REVIEW_LIVE_PORT-4] API Error-Path Coverage And Verification Evidence

#### 문제

1차 plan은 API live timeout/unavailable mapping coverage를 요구했지만 `services/api/internal/socket/live_test.go`에는 `workerclient.ErrUnavailable`, `workerclient.ErrTimeout`, nil worker response test가 없다. 또한 1차 review artifact는 `bin/lint`를 Flutter/Dart toolchain 부재로 skip했다고 기록했지만, review environment에서는 `/sdk/flutter/bin/flutter`가 있고 `bin/lint`가 exit code 0으로 끝났다.

#### 해결 방법

`services/api/internal/socket/live_test.go`에 아래 cases를 추가한다.

- `Connect` 또는 worker call이 `workerclient.ErrUnavailable`을 반환하면 `unavailable`.
- worker call이 `workerclient.ErrTimeout`을 반환하면 `timeout`.
- worker call이 nil response를 반환하면 `internal`.

최종 `CODE_REVIEW-cloud-G06.md`의 검증 결과에는 `command -v flutter`, `bin/lint`, focused/full Go tests, client parser test의 실제 stdout/stderr를 기록한다. `bin/lint` analyzer info는 현재 command exit code가 0이면 실패로 보지 않되 출력은 그대로 남긴다.

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

- [ ] `services/api/internal/socket/live_test.go`
- [ ] `agent-task/m-live-trading-boundary/01_broker_port/CODE_REVIEW-cloud-G06.md`

#### 중간 검증

```bash
go test -count=1 ./services/api/internal/socket
command -v flutter
bin/lint
```

기대 결과: exit code 0. `bin/lint`가 analyzer info를 출력해도 command exit code가 0이면 통과로 기록한다.

## 최종 검증

```bash
bin/contracts-check
go test -count=1 ./packages/domain/...
go test -count=1 ./packages/contracts/gen/go/...
go test -count=1 ./services/worker/...
go test -count=1 ./services/api/...
go test -count=1 ./apps/cli/...
cd apps/client && flutter test test/contracts/alt_contracts_test.dart
command -v flutter
bin/lint
```

기대 결과: 모든 명령 exit code 0. 검증 결과에는 실제 stdout/stderr를 붙인다. `bin/lint`가 analyzer info를 출력하더라도 exit code가 0이면 그 출력을 그대로 기록한다.
