<!-- task=m-performance-hotspot-optimization/13_kotlin_ws_diagnostics plan=1 tag=REVIEW_TEST -->

# Plan - REVIEW_TEST

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

`CODE_REVIEW-local-G08.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 필수입니다. 구현 후 active 파일은 그대로 두고 리뷰 준비를 보고하세요. 사용자만 결정할 수 있는 범위 변경, 외부 환경, secret, 사용자 소유 장비가 막으면 리뷰 stub의 `사용자 리뷰 요청` 섹션에 근거를 기록하고 멈추세요. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 마세요. `USER_REVIEW.md`, 로그 아카이브, `complete.log` 작성은 code-review 전용입니다. 명령 재실행이나 산출물 수집으로 닫을 수 있는 증거 공백은 사용자 리뷰 요청이 아닙니다.

## 배경

이 후속은 `code_review_local_G07_0.log`의 FAIL Required 2건만 닫는다. 현재 Kotlin WS diagnostics는 focused stress와 crosstest compile은 통과하지만, `WsClient` public API가 늘었고 필수 `./gradlew test`가 WSS open timeout으로 실패한다. 14번 이후 dependent subtask가 진행되려면 13번 active task가 PASS되어야 하므로, 진단 계측 범위 안에서 API와 검증 게이트를 먼저 닫는다.

## 사용자 리뷰 요청 흐름

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

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/code-review/SKILL.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-roadmap/current.md`
- `agent-roadmap/milestones/performance-hotspot-optimization.md`
- `agent-test/local/rules.md`
- `agent-test/local/proto-socket-performance-baseline.md`
- `agent-test/local/kotlin-smoke.md`
- `agent-ops/rules/project/domain/kotlin/rules.md`
- `agent-task/m-performance-hotspot-optimization/13_kotlin_ws_diagnostics/plan_local_G07_0.log`
- `agent-task/m-performance-hotspot-optimization/13_kotlin_ws_diagnostics/code_review_local_G07_0.log`
- `kotlin/build.gradle.kts`
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt`
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsServer.kt`
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/BaseClient.kt`
- `kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt`
- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt`
- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/WsTest.kt`
- `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TlsWsTest.kt`
- `kotlin/crosstest/stress.kt`
- `kotlin/build/test-results/test/TEST-com.tokilabs.proto_socket.TlsWsTest.xml`

### 테스트 환경 규칙

`test_env=local`을 사용한다. `agent-test/local/rules.md`가 있었고 읽었다. Kotlin 변경이므로 `agent-test/local/kotlin-smoke.md`의 필수 검증 `cd kotlin && ./gradlew test`를 적용한다. 성능 diagnostics 출력은 `agent-test/local/proto-socket-performance-baseline.md`의 보조 검증 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --quick --lang kotlin --transport ws --profile roundtrip,payload`로 확인한다. crosstest source set 접근 방식 변경은 `cd kotlin && ./gradlew compileCrosstestKotlin`로 확인한다.

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

- Public API leak: 기존 테스트는 public surface 증가를 직접 막지 않는다. 구현 후 `rg --sort path "fun getMetricsDiagnostics|getMetricsDiagnostics"`로 public method 제거와 남은 call site를 확인한다.
- WSS open timeout: `TlsWsTest`는 WSS send/receive와 request-response를 검증하지만 현재 `websocket open timed out`이 재현된다. 실패 원인 안정화 후 단독 `TlsWsTest`와 전체 `./gradlew test` 모두 PASS해야 한다.

### 심볼 참조

- `getMetricsDiagnostics`: `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt`, `kotlin/crosstest/stress.kt`에 있음. 제거하거나 비공개화하면 `stress.kt` provider call site를 함께 고친다.
- renamed/removed public protocol symbols 없음.

### 분할 판단

split 정책을 평가했다. 선택된 active task는 `agent-task/m-performance-hotspot-optimization/13_kotlin_ws_diagnostics`이고 이미 split subtask다. 이 후속은 G07 review의 Required 2건을 같은 subtask 안에서 닫는 repair loop이므로 새 sibling subtask를 만들지 않는다. `14+13_kotlin_ws_transport_hardening`, `15+14_kotlin_ws_reference_guard`는 13번 PASS 후 진행해야 하므로 현재 follow-up은 13번 디렉터리 안에 유지한다.

### 범위 결정 근거

수정 범위는 Kotlin WS diagnostics 접근 방식, WSS test/open 안정화, 해당 검증 출력에 한정한다. `proto/**`, Dart/Go/Python/TypeScript 구현, package version, roadmap 문서 갱신은 제외한다. Kotlin WS 성능 최적화 자체는 14번 계획 범위로 남긴다.

### 빌드 등급

`local-G08`: Required 이슈가 명확하고 Kotlin 단일 도메인이지만, WSS timeout 안정화와 crosstest source-set API 경계 복구가 함께 필요하다.

## 구현 체크리스트

- [ ] `WsClient.getMetricsDiagnostics()` public API leak를 제거하고 crosstest diagnostic access를 repo-internal 경로로 유지한다.
- [ ] WSS open timeout 재현 원인을 코드 또는 테스트 setup에서 안정화하고 `TlsWsTest` 단독 검증을 PASS로 만든다.
- [ ] `cd kotlin && ./gradlew test`, `cd kotlin && ./gradlew compileCrosstestKotlin`, focused stress 명령을 실행해 actual stdout/stderr를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_TEST-1] Restore Internal Diagnostics Boundary

문제: [WsClient.kt](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt:53)의 `getMetricsDiagnostics()`는 기본 public 가시성이다. G07 계획은 [plan_local_G07_0.log](/config/workspace/proto-socket/agent-task/m-performance-hotspot-optimization/13_kotlin_ws_diagnostics/plan_local_G07_0.log:11)에서 제품 API 변경 없이 diagnostics만 추가한다고 했고, 구현 체크리스트도 [plan_local_G07_0.log](/config/workspace/proto-socket/agent-task/m-performance-hotspot-optimization/13_kotlin_ws_diagnostics/plan_local_G07_0.log:71)에서 public API 미확장을 요구했다.

해결 방법: `WsClient`의 public diagnostic method를 제거하거나 public surface에서 숨긴다. `kotlin/crosstest/stress.kt`는 public `WsClient` API에 의존하지 않는 repo-internal 방식으로 metrics를 읽게 바꾼다. 예시는 방향만 제시하며, 실제 구현은 Kotlin source set 구조에 맞춰 가장 작은 변경을 선택한다.

Before:

```kotlin
// WsClient.kt:53
fun getMetricsDiagnostics(): LongArray {
    val s = metrics.snapshot()
    return longArrayOf(s.maxStaged, s.droppedCount, s.totalCopyNanos, s.receivedCount)
}
```

After:

```kotlin
// 예: public method 제거. crosstest는 별도 repo-internal adapter/reflection/friend path로 snapshot을 읽는다.
internal fun getMetricsSnapshot(): WsMetricsSnapshot = metrics.snapshot()
```

수정 파일 및 체크리스트:

- [ ] `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt`: public `getMetricsDiagnostics()` 제거 또는 비공개화.
- [ ] `kotlin/crosstest/stress.kt`: `StressClientHandle.wsMetrics` provider가 public `WsClient` API에 의존하지 않게 수정.
- [ ] `kotlin/build.gradle.kts`: friend/source-set 설정이 필요할 때만 최소 변경한다.

테스트 작성: 별도 unit test는 생략한다. 대신 `rg --sort path "fun getMetricsDiagnostics|getMetricsDiagnostics" kotlin`로 public method/call-site 제거를 확인하고, `compileCrosstestKotlin`으로 crosstest 접근 방식을 검증한다.

중간 검증:

```bash
rg --sort path "fun getMetricsDiagnostics|getMetricsDiagnostics" kotlin
cd kotlin && ./gradlew compileCrosstestKotlin
```

기대 결과: `rg` 결과가 없거나 public `WsClient` method가 없음을 보여준다. `compileCrosstestKotlin`은 `BUILD SUCCESSFUL`이다.

### [REVIEW_TEST-2] Stabilize WSS Mandatory Test Gate

문제: [TlsWsTest.kt](/config/workspace/proto-socket/kotlin/src/test/kotlin/com/tokilabs/proto_socket/TlsWsTest.kt:87)의 `dialWssWithRetry`가 review 재실행에서 `websocket open timed out`으로 실패했다. 전체 `./gradlew test`뿐 아니라 단독 `./gradlew test --tests "com.tokilabs.proto_socket.TlsWsTest"`도 실패했으므로 G07 검증 기록의 “단독 실행은 항상 PASS” 주장은 닫히지 않았다.

해결 방법: WSS server start/open handshake 경로를 deterministic하게 만든다. 우선 `TlsWsTest` setup/teardown, `WsServer.start/stop`, `dialWsUrl` open/failure handling, client/server close ordering 중 timeout 원인을 분리한다. 필요한 경우 test setup을 보강해 server readiness와 close cleanup을 보장하되, WSS public behavior를 완화하지 않는다.

수정 파일 및 체크리스트:

- [ ] `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TlsWsTest.kt`: WSS open timeout 재현 원인을 안정화하는 test setup/teardown 보강.
- [ ] `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt`: open/failure/close handling이 timeout 원인이면 최소 수정.
- [ ] `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsServer.kt`: server readiness/close ordering이 timeout 원인이면 최소 수정.

테스트 작성: 기존 `TlsWsTest.testWssSendReceive`와 `testWssRequestResponse`가 regression test다. 새 테스트는 같은 실패를 더 좁게 재현할 때만 추가한다.

중간 검증:

```bash
cd kotlin && ./gradlew test --tests "com.tokilabs.proto_socket.TlsWsTest"
```

기대 결과: `BUILD SUCCESSFUL`.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt` | REVIEW_TEST-1, REVIEW_TEST-2 if needed |
| `kotlin/crosstest/stress.kt` | REVIEW_TEST-1 |
| `kotlin/build.gradle.kts` | REVIEW_TEST-1 if needed |
| `kotlin/src/test/kotlin/com/tokilabs/proto_socket/TlsWsTest.kt` | REVIEW_TEST-2 |
| `kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsServer.kt` | REVIEW_TEST-2 if needed |

## 최종 검증

```bash
rg --sort path "fun getMetricsDiagnostics|getMetricsDiagnostics" kotlin
```

```bash
cd kotlin && ./gradlew test --tests "com.tokilabs.proto_socket.TlsWsTest"
```

```bash
cd kotlin && ./gradlew test
```

```bash
cd kotlin && ./gradlew compileCrosstestKotlin
```

```bash
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --quick --lang kotlin --transport ws --profile roundtrip,payload
```

기대 결과: public diagnostic accessor가 남지 않고, Gradle/TlsWs/crosstest compile은 `BUILD SUCCESSFUL`, focused stress는 Kotlin WS roundtrip/payload rows를 PASS로 기록한다.

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