<!-- task=m-operator-client-api-core-integration/02+01_socket_state plan=0 tag=API -->

# Plan - Socket State Core

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

구현 완료 전 active `CODE_REVIEW-*-G??.md`의 구현 소유 섹션을 실제 내용과 검증 출력으로 채운다. 사용자 전용 blocker만 `사용자 리뷰 요청`에 기록하고 멈춘다. code-review 전용 종결 작업은 수행하지 않는다.

## 배경

현재 socket state는 enum 네 값뿐이라 timeout, disconnect reason, handshake failure 같은 운영 상태를 UI copy 밖에서 보존하지 못한다. Milestone의 `socket-core`와 `error-core` 일부를 만족하려면 core state object와 controller test가 필요하다. 이 작업은 `01_contract_mapping`의 transport/result 용어를 재사용한다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 review stub의 `사용자 리뷰 요청`에 기록한다. code-review가 검증 후 `USER_REVIEW.md` 필요 여부를 판단한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operator-surface/milestones/operator-client-api-core-integration.md`
- Task ids:
  - `socket-core`: API socket 연결, 해제, timeout 상태를 화면 없는 client state로 표현한다.
  - `error-core`: unavailable/error/disconnected 상태가 UI copy가 아닌 안정적인 client state로 남는다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/client-smoke.md`
- `agent-ops/rules/project/domain/client/rules.md`
- `apps/client/lib/src/integrations/socket/socket_connection_controller.dart`
- `apps/client/lib/src/integrations/socket/alt_socket_client.dart`
- `apps/client/lib/src/integrations/socket/socket_endpoint.dart`
- `apps/client/lib/src/features/dashboard/presentation/dashboard_screen.dart`
- `apps/client/test/widget_test.dart`
- `apps/client/test/integrations/socket/alt_socket_client_test.dart`
- `apps/client/pubspec.yaml`

### 테스트 환경 규칙

`test_env=local`; client-smoke 적용. 기본 명령은 `cd apps/client && flutter test`; socket runtime behavior는 관련 integration/unit test 실행 가능 여부를 확인한다. 이 plan은 fake connector 단위 test로 처리하고 실제 API socket smoke는 생략 근거를 review에 남긴다.

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

`SocketConnectionController`의 `connect/disconnect/error` 전이는 직접 test가 없다. timeout 상태도 현재 enum에 없다. 이 plan에서 controller unit test를 추가한다.

### 심볼 참조

`SocketConnectionState`는 `dashboard_screen.dart`, `widget_test.dart`, `socket_connection_controller.dart`에서 참조된다. 제거하지 말고 필요하면 compatible getter/label adapter를 유지한다.

### 분할 판단

dependent split plan이다. predecessor `01_contract_mapping`의 active/archived `complete.log`가 필요하다. 구현 시작 전 `agent-task/m-operator-client-api-core-integration/01_contract_mapping/complete.log` 또는 matching archive complete.log를 확인한다. 현재 계획 작성 시점에는 predecessor가 아직 active plan 상태라 미충족이다.

### 범위 결정 근거

화면 layout 변경은 제외한다. dashboard는 기존 enum 의존이 깨질 때 최소 adapter만 수정한다. 실제 WebSocket 서버, API service, worker는 제외한다.

### 빌드 등급

build=`cloud-G06`, review=`cloud-G06`. state model 변경이 widget/controller call site를 건드리며 timeout/error semantics가 review 대상이다.

## 의존 관계 및 구현 순서

디렉터리명 `02+01_socket_state`에 따라 sibling `01_contract_mapping` PASS `complete.log`가 먼저 필요하다. 구현자는 시작 전에 predecessor completion을 확인하고 review에 경로를 기록한다.

## 구현 체크리스트

- [ ] socket core state 타입을 추가하고 `disconnected/connecting/connected/error/timeout`의 stable code를 보존한다. 검증: `cd apps/client && flutter test test/integrations/socket/socket_connection_controller_test.dart`
- [ ] `SocketConnectionController`가 성공, disconnect callback, connect failure, hello timeout/failure를 state로 남기게 한다. 검증: `cd apps/client && flutter test test/integrations/socket/socket_connection_controller_test.dart`
- [ ] 기존 dashboard/widget 테스트가 깨지지 않도록 presentation label adapter를 최소 수정한다.
- [ ] `cd apps/client && flutter test`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] Socket core state 타입 도입

#### 문제

`apps/client/lib/src/integrations/socket/socket_connection_controller.dart:8`의 enum은 상태 이유나 timeout/error code를 담을 수 없다.

```dart
// apps/client/lib/src/integrations/socket/socket_connection_controller.dart:8
enum SocketConnectionState {
  disconnected,
  connecting,
  connected,
  error,
}
```

#### 해결 방법

기존 enum을 유지하거나 대체하되, presentation이 stable `status`와 optional `error`를 읽을 수 있게 한다. 후속 UI copy가 아닌 core field로 `reasonCode`, `endpoint`, `lastError`를 둔다.

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

- [ ] `apps/client/lib/src/integrations/socket/socket_connection_controller.dart`
- [ ] `apps/client/test/integrations/socket/socket_connection_controller_test.dart`
- [ ] `apps/client/lib/src/features/dashboard/presentation/dashboard_screen.dart`
- [ ] `apps/client/test/widget_test.dart`

#### 테스트 작성

작성한다. fake connector를 주입해 connecting -> connected, connected -> disconnected, failure -> error, timeout -> timeout/error reason을 확인한다.

#### 중간 검증

`cd apps/client && flutter test test/integrations/socket/socket_connection_controller_test.dart` exit code 0.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/client/lib/src/integrations/socket/socket_connection_controller.dart` | API-1 |
| `apps/client/lib/src/features/dashboard/presentation/dashboard_screen.dart` | API-1 |
| `apps/client/test/integrations/socket/socket_connection_controller_test.dart` | API-1 |
| `apps/client/test/widget_test.dart` | API-1 |

## 최종 검증

```bash
cd apps/client && flutter test
```

기대 결과: exit code 0. 실제 API socket integration smoke는 이 plan 범위에서 실행하지 않으며 fake connector state test로 대체한다.

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