<!-- task=m-proto-socket-infrastructure-communication-rail/13+11,12_client_diagnostics plan=2 tag=REVIEW_REVIEW_API -->

# Plan - REVIEW_REVIEW_API Failed Reconnect Evidence Fix

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

이 계획은 `code_review_cloud_G07_1.log`의 Required findings만 닫는다. 범위를 키우지 말고 failed reconnect stale diagnostics regression 테스트와 review stub 증거 정정만 수행한다. 로컬 테스트/검증은 `agent-test/local/rules.md`에 따라 실행하지 말고, 허용된 원격/검증 환경에서 실제 stdout/stderr를 회수한다. 사용자 결정, 사용자 소유 외부 환경, 범위 충돌로 막히면 active review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거와 재개 조건을 채우고 멈춘다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/workflow-core/milestones/proto-socket-infrastructure-communication-rail.md`
- Task ids:
  - `diagnostics`: connection id, protocol version, channel name, error code를 로그와 디버그 표면에서 확인할 수 있게 한다.
- Completion mode: check-on-pass

## 배경

2차 리뷰에서 production reset 로직과 task service diagnostics coverage는 대체로 충족된 것으로 보였지만, plan이 요구한 `failed reconnect` stale diagnostics regression 테스트가 실제 파일에 없었다. active review stub은 존재하지 않는 테스트를 완료 증거로 기록해 verification trust도 실패했다.

## 범위 결정 근거

- 기본 수정 범위는 `apps/client/test/integrations/proto_socket_lifecycle_test.dart`와 active `CODE_REVIEW-cloud-G07.md`로 제한한다.
- production `apps/client/lib/src/integrations/proto_socket/proto_socket_lifecycle.dart`는 새 regression이 현재 구현에서 실패할 때만 최소 수정한다.
- `proto_socket_task_service_test.dart`, `widget_test.dart`, app UI, contracts, core, roadmap은 이번 follow-up에서 수정하지 않는다.

## 구현 체크리스트

- [ ] `proto_socket_lifecycle_test.dart`에 이전 envelope diagnostics 기록 후 실패하는 reconnect가 `failed` 상태에서 `connectionId`, `channel`, `action`, `errorCode`, `timestamp`를 모두 비우는 regression을 추가한다.
- [ ] active `CODE_REVIEW-cloud-G07.md`의 구현 기록과 검증 요약을 실제 추가된 failed reconnect 테스트와 일치하게 정정한다.
- [ ] 허용된 원격/검증 환경에서 `cd apps/client && flutter test test/integrations/proto_socket_lifecycle_test.dart`를 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] 허용된 원격/검증 환경에서 `cd apps/client && flutter test test/integrations/proto_socket_lifecycle_test.dart test/integrations/proto_socket_task_service_test.dart test/widget_test.dart`, `cd apps/client && flutter test`, `cd apps/client && flutter analyze --no-fatal-infos`를 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_REVIEW_API-1] Failed Reconnect Regression Evidence

### 문제

[apps/client/test/integrations/proto_socket_lifecycle_test.dart](/config/workspace/nomadcode/apps/client/test/integrations/proto_socket_lifecycle_test.dart:285)의 connect failure 테스트는 fresh lifecycle에서 `failed` 상태와 `lastError`만 검증한다. 계획이 요구한 "이전 envelope 기록 후 failed reconnect 시 stale diagnostics 제거"를 고정하지 못한다. 또한 active review stub은 존재하지 않는 `failed reconnect clears prior connection diagnostics` 테스트를 추가했다고 기록했다.

### 해결 방법

`ProtoSocketLifecycle` 테스트에 아래 흐름을 추가한다.

1. 첫 연결 후 response/event envelope로 `connection_id`, `channel`, `action`, `error.code`, `timestamp`를 diagnostics에 기록한다.
2. 재연결 시도 전에 기존 연결을 정리한다.
3. 다음 `connect()`가 실패하도록 fake connector를 설정한다.
4. `connect()`가 throw한 뒤 diagnostics가 `failed` 상태이고 `connectionId`, `channel`, `action`, `errorCode`, `timestamp`가 모두 `null`인지 검증한다.

현재 production reset 로직이 맞다면 테스트 추가만으로 통과해야 한다. 실패할 때만 `proto_socket_lifecycle.dart`의 failed reset 경로를 최소 수정한다.

### 중간 검증

```bash
cd apps/client && flutter test test/integrations/proto_socket_lifecycle_test.dart
```

허용된 원격/검증 환경에서 실행하고 실제 stdout/stderr를 review stub에 기록한다.

## 최종 검증

```bash
cd apps/client && flutter test test/integrations/proto_socket_lifecycle_test.dart test/integrations/proto_socket_task_service_test.dart test/widget_test.dart
cd apps/client && flutter test
cd apps/client && flutter analyze --no-fatal-infos
```

허용된 원격/검증 환경에서 실행하고 실제 stdout/stderr를 review stub에 기록한다. 기존 analyzer `avoid_print` info baseline은 새 오류로 확대하지 않는다.

## 리뷰어 체크포인트

- 실제 `proto_socket_lifecycle_test.dart`에 failed reconnect stale diagnostics regression이 존재하는가.
- 새 테스트가 fresh connect failure만 검증하지 않고, 이전 envelope diagnostics가 있는 상태에서 실패 전환 후 stale field 제거를 검증하는가.
- review stub의 구현 기록과 검증 요약이 실제 테스트 이름/개수/출력과 일치하는가.
- follow-up이 production/UI/widget/task service 범위를 불필요하게 다시 넓히지 않았는가.
