<!-- task=m-live-trading-boundary/02+01_order_lifecycle plan=2 tag=REVIEW_REVIEW_LIVE_ORDER -->

# Plan - REVIEW_REVIEW_LIVE_ORDER

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

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

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

## 배경

두 번째 리뷰(`code_review_cloud_G07_1.log`)에서 live submit validation이 아직 계획 수준까지 닫히지 않았다고 판정했다. Flutter parser map과 confirmation gate call-count 테스트는 개선됐지만, confirmed malformed order가 direct service path에서 broker port에 도달할 수 있고, live limit price currency mapping도 보존되지 않는다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 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:
  - `order-lifecycle`: 주문 생성, 제출, 체결, 취소, 실패 lifecycle이 정의된다.
- Completion mode: check-on-pass

## 분석 결과

### 리뷰 근거

- `services/worker/internal/livetrading/service.go:107`의 `validateIntent`는 quantity를 parse하지 않고 빈 값과 정확한 `"0"`만 막는다.
- 같은 service path는 `SubmitRequest.AccountID`를 검사하지 않아 direct caller가 빈 account id를 broker까지 전달할 수 있다.
- `services/worker/internal/socket/live_mapping.go:51`은 proto currency enum을 `.String()`으로 domain currency에 넣어 `CURRENCY_KRW` 같은 wire enum name을 저장한다.
- `services/worker/internal/socket/live_mapping.go:102`는 live order response limit price에 amount만 넣고 currency를 비운다.
- `services/worker/internal/livetrading/service_test.go:127`의 malformed test는 missing quantity만 다루고, non-positive/nonnumeric quantity, empty account, limit price validation, currency round-trip을 다루지 않는다.

### 범위 결정 근거

이 follow-up은 live submit boundary의 malformed order 방어와 limit price currency mapping만 다룬다. broker selector, risk/kill switch, durable audit, real KIS network placement, account sync는 sibling subtask 범위다.

### 빌드 등급

Build lane `cloud-G07`, review lane `cloud-G07`를 유지한다. 이 이슈는 live order가 broker port에 도달하는 safety boundary와 contract mapping을 함께 건드리므로 같은 판단 강도를 유지한다.

## 구현 체크리스트

- [ ] [REVIEW_REVIEW_LIVE_ORDER-1] live submit validation과 limit price currency mapping을 service/boundary 양쪽에서 완성한다.
- [ ] [REVIEW_REVIEW_LIVE_ORDER-2] focused verification과 affected checks를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_LIVE_ORDER-1] Live Submit Boundary Completion

#### 문제

confirmed live submit이 아래 malformed shape로도 broker port까지 갈 수 있다.

- direct service caller의 empty `account_id`
- `quantity.amount.value`가 `-1`, `0.0`, `abc` 같은 non-positive/nonnumeric decimal인 경우
- optional `limit_price.amount.value`가 negative/nonnumeric인 경우

또한 live limit price currency는 inbound에서 enum name으로 잘못 저장되고 outbound에서 비워진다.

#### 해결 방법

`services/worker/internal/livetrading/service.go`에서 broker 호출 전에 service-level validation을 완성한다.

- `req.AccountID` required
- `intent.instrument_id` required
- `intent.side`는 `buy` 또는 `sell`
- `intent.quantity.amount.value` required, numeric, strictly greater than zero
- `intent.type` required, custom string은 허용
- optional `intent.limit_price.amount.value`가 있으면 numeric and non-negative

Decimal 검증은 `math/big.Rat` 또는 동등한 정확한 decimal parser를 사용한다. float 변환은 사용하지 않는다. error는 `ErrInvalidIntent`를 wrap해서 worker socket에서 `invalid_request`로 매핑되게 한다.

`services/worker/internal/socket/live_mapping.go`에서는 live limit price currency mapping을 기존 socket helper 패턴과 맞춘다.

- proto `Currency` -> domain `market.Currency`: `CURRENCY_KRW`는 `KRW`, `CURRENCY_USD`는 `USD`, unsupported는 empty/default로 두지 말고 invalid_request가 되도록 한다.
- domain `market.Currency` -> proto `Currency`: live order response의 `LimitPrice.Currency`를 채운다.

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

- [ ] `services/worker/internal/livetrading/service.go`에 account id와 decimal validation을 추가한다.
- [ ] `services/worker/internal/socket/live_mapping.go`에 live limit price currency 변환을 추가하거나 기존 shared helper를 재사용한다.
- [ ] `services/worker/internal/livetrading/service_test.go`에 empty account id, `0.0`, negative, nonnumeric quantity, negative limit price가 `ErrInvalidIntent`와 broker call count 0을 보장하는 테스트를 추가한다.
- [ ] `services/worker/internal/socket/live_test.go`에 live limit price currency round-trip 또는 invalid currency mapping 테스트를 추가한다.

#### 중간 검증

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

기대 결과: exit code 0.

### [REVIEW_REVIEW_LIVE_ORDER-2] Verification

#### 문제

이 follow-up은 worker runtime boundary와 live contract mapping을 수정하므로 focused worker checks와 주변 parser/forwarder checks를 다시 확인해야 한다.

#### 해결 방법

다음 명령을 checkout root 기준으로 실행하고 실제 stdout/stderr를 review stub에 기록한다.

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

- [ ] `bin/contracts-check`를 실행한다.
- [ ] `go test -count=1 ./packages/contracts/gen/go/...`를 실행한다.
- [ ] `go test -count=1 ./services/worker/internal/livetrading ./services/worker/internal/socket`를 실행한다.
- [ ] `go test -count=1 ./services/api/internal/socket ./services/api/internal/workerclient`를 실행한다.
- [ ] `go test -count=1 ./apps/cli/internal/operator`를 실행한다.
- [ ] `cd apps/client && flutter test test/contracts/alt_contracts_test.dart`를 실행한다.
- [ ] `bin/lint`를 실행한다.
- [ ] `git diff --check`를 실행한다.

#### 중간 검증

```bash
bin/contracts-check
go test -count=1 ./packages/contracts/gen/go/...
go test -count=1 ./services/worker/internal/livetrading ./services/worker/internal/socket
go test -count=1 ./services/api/internal/socket ./services/api/internal/workerclient
go test -count=1 ./apps/cli/internal/operator
cd apps/client && flutter test test/contracts/alt_contracts_test.dart
bin/lint
git diff --check
```

기대 결과: 모두 exit code 0. `bin/lint`의 기존 Mattermost `avoid_print` info는 exit code 0이면 pre-existing info로 기록할 수 있다.

## 최종 검증

```bash
bin/contracts-check
go test -count=1 ./packages/contracts/gen/go/...
go test -count=1 ./services/worker/internal/livetrading ./services/worker/internal/socket
go test -count=1 ./services/api/internal/socket ./services/api/internal/workerclient
go test -count=1 ./apps/cli/internal/operator
cd apps/client && flutter test test/contracts/alt_contracts_test.dart
bin/lint
git diff --check
```

기대 결과: 모두 exit code 0. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
