<!-- task=m-backtest-analysis-surface/01_contract_surface plan=0 tag=BAS-CONTRACT -->

# Plan - BAS-CONTRACT

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

`CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 필수다. 구현 후 검증을 실행하고, active 파일은 그대로 둔 채 리뷰 준비를 보고한다. 사용자 결정, 외부 환경 준비, 범위 충돌이 없이는 안전하게 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거를 남기고 멈춘다. archive, `complete.log`, 최종 판정은 code-review 전용이다.

## 배경

`Backtest Analysis Surface`는 현재 `BacktestResult`가 `starting_cash`, `ending_equity`, `trades`, `positions`만 노출해 operator summary와 비교 표면을 만들기 어렵다. 먼저 protobuf contract와 generated Go/Dart surface를 확장해야 worker storage와 client/API boundary 작업이 같은 타입을 기준으로 진행된다.

## 사용자 리뷰 요청 흐름

구현 중 차단 조건은 active `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 이를 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/backtest-loop/milestones/backtest-analysis-surface.md`
- `packages/contracts/proto/alt/v1/backtest.proto`
- `packages/contracts/proto/alt/v1/common.proto`
- `packages/contracts/proto/alt/v1/market.proto`
- `services/api/internal/contracts/parser_map.go`
- `services/api/internal/contracts/parser_map_test.go`
- `apps/client/lib/src/contracts/alt_contracts.dart`
- `apps/client/test/contracts/alt_contracts_test.dart`
- `apps/client/lib/src/integrations/socket/alt_socket_client.dart`
- `apps/client/test/integrations/socket/alt_socket_client_test.dart`
- `bin/contracts-gen`
- `bin/contracts-check`
- `bin/test`
- `bin/lint`
- `packages/contracts/gen/go/go.mod`
- `apps/client/pubspec.yaml`

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

- Contract parser coverage exists for current backtest messages in `services/api/internal/contracts/parser_map_test.go:15` and `apps/client/test/contracts/alt_contracts_test.dart:12`.
- No existing tests cover summary metrics, equity curve/time-series contracts, run list/detail contracts, or compare-runs contracts because the messages do not exist.
- Generated Go/Dart drift is covered by `bin/contracts-check`.

### 심볼 참조

- Renamed/removed symbols: none. This plan must use additive protobuf fields/messages only.

### 분할 판단

- Split policy evaluated before writing plan files.
- Shared task group: `agent-task/m-backtest-analysis-surface`.
- `01_contract_surface`: independent foundation for protobuf schema, generated Go/Dart output, and parser registration.
- `02+01_worker_analysis_store`: depends on `01_contract_surface` for final type names and field shapes.
- `03+01,02_api_client_boundary`: depends on `01_contract_surface` and `02+01_worker_analysis_store` so API/client boundary tests reflect actual query behavior.
- Split is required because protocol/schema changes, storage/migration work, and API/client boundary tests have different risk profiles and verification commands.

### 범위 결정 근거

- Include only protobuf schema, generated outputs, and parser map/test updates.
- Exclude worker engine/storage changes; those belong to `02+01_worker_analysis_store`.
- Exclude UI screen design and socket runtime behavior; those belong to later operator surface work.
- Do not hand-edit generated Go/Dart files; use `bin/contracts-gen`.

### 빌드 등급

- build lane: `cloud-G07`; review lane: `cloud-G07`.
- Rationale: protocol/schema plus generated Go/Dart and API/client parser registration is cross-domain and review-sensitive.

## 구현 체크리스트

- [ ] [BAS-CONTRACT-1] `backtest.proto`에 additive analysis messages를 추가하고 기존 field number를 변경하지 않는다.
- [ ] [BAS-CONTRACT-2] `bin/contracts-gen`으로 generated Go/Dart output을 갱신하고 손수 편집하지 않는다.
- [ ] [BAS-CONTRACT-3] API와 Flutter parser map에 새 메시지를 등록하고 parser round-trip tests를 확장한다. 검증: Flutter client가 표시할 수 있는 result contract가 존재한다.
- [ ] [BAS-CONTRACT-4] `bin/contracts-check`, `go test ./services/api/...`, `cd apps/client && flutter test test/contracts/alt_contracts_test.dart`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [BAS-CONTRACT-1] Add analysis protobuf messages

문제: `packages/contracts/proto/alt/v1/backtest.proto:65`의 `BacktestResult`는 ending equity, trades, positions만 있어 summary metrics와 equity curve를 wire format으로 표현할 수 없다. `backtest.proto:73`에는 단일 result 조회만 있고 list/detail/compare 요청이 없다.

해결 방법:

Before:

```proto
65 message BacktestResult {
66   string run_id = 1;
67   Price starting_cash = 2;
68   Price ending_equity = 3;
69   repeated BacktestTrade trades = 4;
70   repeated BacktestPosition positions = 5;
71 }
```

After:

```proto
message BacktestSummaryMetrics {
  Price starting_cash = 1;
  Price ending_equity = 2;
  Decimal total_return = 3;
  int32 trade_count = 4;
}

message BacktestEquityPoint {
  int64 timestamp_unix_ms = 1;
  Price equity = 2;
}

message BacktestResult {
  string run_id = 1;
  Price starting_cash = 2;
  Price ending_equity = 3;
  repeated BacktestTrade trades = 4;
  repeated BacktestPosition positions = 5;
  BacktestSummaryMetrics summary = 6;
  repeated BacktestEquityPoint equity_curve = 7;
}
```

Also add additive request/response messages:

```proto
message ListBacktestRunsRequest {
  BacktestRunStatus status = 1;
}

message ListBacktestRunsResponse {
  repeated BacktestRun runs = 1;
}

message GetBacktestRunDetailRequest {
  string run_id = 1;
}

message GetBacktestRunDetailResponse {
  BacktestRun run = 1;
  BacktestResult result = 2;
}

message CompareBacktestRunsRequest {
  repeated string run_ids = 1;
}

message CompareBacktestRunsResponse {
  repeated BacktestResult results = 1;
}
```

수정 파일 및 체크리스트:

- [ ] `packages/contracts/proto/alt/v1/backtest.proto`에 additive messages/fields를 추가한다.
- [ ] 기존 field number `1..5`와 enum values `0..5`를 변경하지 않는다.
- [ ] `common.proto`의 `Decimal`과 `market.proto`의 `Price`를 재사용한다.

테스트 작성: parser map tests are updated in BAS-CONTRACT-3 after generation.

중간 검증:

```bash
bin/contracts-gen
```

Expected: command exits 0 and generated Go/Dart files update.

### [BAS-CONTRACT-2] Regenerate contracts

문제: `bin/contracts-gen:25` generates `common.proto`, `market.proto`, `backtest.proto`; generated files under `packages/contracts/gen/go` and `apps/client/lib/src/generated` must match schema.

해결 방법: run `bin/contracts-gen`; do not hand-edit generated files.

수정 파일 및 체크리스트:

- [ ] `packages/contracts/gen/go/alt/v1/backtest.pb.go` is regenerated.
- [ ] `apps/client/lib/src/generated/alt/v1/backtest.pb.dart` is regenerated.
- [ ] `apps/client/lib/src/generated/alt/v1/backtest.pbjson.dart` is regenerated.
- [ ] `apps/client/lib/src/generated/alt/v1/backtest.pbenum.dart` changes only if generator output requires it.

테스트 작성: no new hand-written tests in this item; drift is checked by `bin/contracts-check`.

중간 검증:

```bash
bin/contracts-check
```

Expected: exits 0 with no generated drift.

### [BAS-CONTRACT-3] Register parser maps

문제: `services/api/internal/contracts/parser_map.go:19` and `apps/client/lib/src/contracts/alt_contracts.dart:15` register current backtest messages only. New messages will not parse unless both parser maps and tests are expanded.

해결 방법:

Before:

```go
19 protoSocket.TypeNameOf(&altv1.StartBacktestRequest{}): parserFor(func() proto.Message { return &altv1.StartBacktestRequest{} }),
23 protoSocket.TypeNameOf(&altv1.GetBacktestResultRequest{}): parserFor(func() proto.Message { return &altv1.GetBacktestResultRequest{} }),
25 protoSocket.TypeNameOf(&altv1.BacktestResult{}): parserFor(func() proto.Message { return &altv1.BacktestResult{} }),
```

After:

```go
protoSocket.TypeNameOf(&altv1.ListBacktestRunsRequest{}): parserFor(func() proto.Message { return &altv1.ListBacktestRunsRequest{} }),
protoSocket.TypeNameOf(&altv1.ListBacktestRunsResponse{}): parserFor(func() proto.Message { return &altv1.ListBacktestRunsResponse{} }),
protoSocket.TypeNameOf(&altv1.GetBacktestRunDetailRequest{}): parserFor(func() proto.Message { return &altv1.GetBacktestRunDetailRequest{} }),
protoSocket.TypeNameOf(&altv1.GetBacktestRunDetailResponse{}): parserFor(func() proto.Message { return &altv1.GetBacktestRunDetailResponse{} }),
protoSocket.TypeNameOf(&altv1.CompareBacktestRunsRequest{}): parserFor(func() proto.Message { return &altv1.CompareBacktestRunsRequest{} }),
protoSocket.TypeNameOf(&altv1.CompareBacktestRunsResponse{}): parserFor(func() proto.Message { return &altv1.CompareBacktestRunsResponse{} }),
```

수정 파일 및 체크리스트:

- [ ] `services/api/internal/contracts/parser_map.go` registers new request/response/result helper messages.
- [ ] `services/api/internal/contracts/parser_map_test.go` expected message list includes the new messages.
- [ ] `apps/client/lib/src/contracts/alt_contracts.dart` registers the generated Dart message parsers.
- [ ] `apps/client/test/contracts/alt_contracts_test.dart` expected message list and count are updated.

테스트 작성: update existing parser round-trip tests in Go and Dart.

중간 검증:

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

Expected: both commands exit 0.

### [BAS-CONTRACT-4] Contract verification

문제: Schema/generation/parser changes need deterministic repository-level verification before downstream tasks start.

해결 방법: run focused contract/API/client tests first, then leave full milestone smoke to dependent plans.

수정 파일 및 체크리스트:

- [ ] Run `bin/contracts-check`.
- [ ] Run `go test ./packages/contracts/gen/go/...`.
- [ ] Run `go test ./services/api/...`.
- [ ] Run `cd apps/client && flutter test test/contracts/alt_contracts_test.dart`.

테스트 작성: no extra tests beyond BAS-CONTRACT-3.

중간 검증:

```bash
bin/contracts-check
go test ./packages/contracts/gen/go/...
go test ./services/api/...
cd apps/client && flutter test test/contracts/alt_contracts_test.dart
```

Expected: all commands exit 0. Go test cache output is acceptable for unchanged packages after generated output is verified by `bin/contracts-check`.

## 의존 관계 및 구현 순서

This task has no predecessor. It must produce a review-ready implementation before `02+01_worker_analysis_store` and `03+01,02_api_client_boundary` start.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/contracts/proto/alt/v1/backtest.proto` | BAS-CONTRACT-1 |
| `packages/contracts/gen/go/alt/v1/backtest.pb.go` | BAS-CONTRACT-2 |
| `apps/client/lib/src/generated/alt/v1/backtest.pb.dart` | BAS-CONTRACT-2 |
| `apps/client/lib/src/generated/alt/v1/backtest.pbjson.dart` | BAS-CONTRACT-2 |
| `apps/client/lib/src/generated/alt/v1/backtest.pbenum.dart` | BAS-CONTRACT-2 |
| `services/api/internal/contracts/parser_map.go` | BAS-CONTRACT-3 |
| `services/api/internal/contracts/parser_map_test.go` | BAS-CONTRACT-3 |
| `apps/client/lib/src/contracts/alt_contracts.dart` | BAS-CONTRACT-3 |
| `apps/client/test/contracts/alt_contracts_test.dart` | BAS-CONTRACT-3 |

## 최종 검증

```bash
bin/contracts-check
go test ./packages/contracts/gen/go/...
go test ./services/api/...
cd apps/client && flutter test test/contracts/alt_contracts_test.dart
git diff --check
```

Expected: all commands exit 0; generated output has no drift. Go test cache output is acceptable after `bin/contracts-check` passes.

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