<!-- task=02_dart_crosstest_process_cleanup plan=0 tag=TEST -->

# Dart Crosstest Process Cleanup

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

**구현 완료의 마지막 단계는 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 모두 채우는 것이다.**
아래 구현 체크리스트와 리뷰 stub의 동일한 체크리스트를 끝까지 수행하고, 중간/최종 검증을 실행한 실제 출력으로 `CODE_REVIEW-cloud-G07.md`를 채운다. 리뷰 파일의 `이 파일을 읽는 리뷰 에이전트에게` 아카이브 지시는 실행하지 말고, `코드리뷰 전용 체크리스트`도 수정하지 않는다.

## 배경

Dart 서버 크로스테스트 중 Go/Python/Kotlin 클라이언트 subprocess를 띄우는 러너가 timeout 이후 stdout/stderr stream completion을 무제한 대기한다. TypeScript 클라이언트 방향에는 이미 `_streamTimeout`이 있으므로 같은 보호를 나머지 Dart 러너에 맞춘다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/project/domain/dart/rules.md`
- `dart/crosstest/dart_go.dart`
- `dart/crosstest/dart_python.dart`
- `dart/crosstest/dart_kotlin.dart`
- `dart/crosstest/dart_typescript.dart`
- `dart/pubspec.yaml`

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

- timeout 후 stream drain 종료: 별도 unit test 없음. 실제 `dart run crosstest/dart_*.dart` 명령이 회귀 검증이다.
- 정상 PASS scenario 수집: 기존 `_validateResultLines`가 검증한다.

### 심볼 참조

- renamed/removed symbol: none.
- 관련 참조 검색: `rg --sort path -n "Process\\.start|process\\.exitCode\\.timeout|Future\\.wait\\(\\[stdoutDone, stderrDone\\]\\)|_streamTimeout" dart/crosstest`.

### 분할 판단

분할 정책을 먼저 평가했다. 이 작업은 Go/Dart/TypeScript 런타임별 subprocess API가 다르므로 분할한다.

- `01_go_crosstest_process_cleanup`: 의존성 없음.
- `02_dart_crosstest_process_cleanup`: 의존성 없음.
- `03_typescript_crosstest_process_cleanup`: 의존성 없음.

### 범위 결정 근거

이 계획은 `dart/crosstest/dart_go.dart`, `dart/crosstest/dart_python.dart`, `dart/crosstest/dart_kotlin.dart`만 수정한다. `dart/crosstest/dart_typescript.dart`는 reference로만 사용한다. `agent-task/archive/**`와 상대 언어 client helper는 제외한다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. subprocess timeout, stdout/stderr stream, long-running crosstest command의 종료 계약을 다룬다.

## 구현 체크리스트

- [ ] `dart_go.dart`, `dart_python.dart`, `dart_kotlin.dart`에 `_streamTimeout` 상수를 추가한다.
- [ ] 세 파일의 `Future.wait([stdoutDone, stderrDone])`에 bounded timeout과 명확한 error message를 적용한다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 실제 출력을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [TEST-1] Harden Dart subprocess stream cleanup

#### 문제

- [dart_go.dart](/config/workspace/proto-socket/dart/crosstest/dart_go.dart:324)는 timeout 시 child process만 kill하고 [dart_go.dart](/config/workspace/proto-socket/dart/crosstest/dart_go.dart:328)에서 stream 완료를 무제한 대기한다.
- [dart_python.dart](/config/workspace/proto-socket/dart/crosstest/dart_python.dart:327)와 [dart_kotlin.dart](/config/workspace/proto-socket/dart/crosstest/dart_kotlin.dart:327)도 같은 구조다.

Before:

```dart
// dart/crosstest/dart_go.dart:324
final code = await process.exitCode.timeout(_processTimeout, onTimeout: () {
  process.kill(ProcessSignal.sigkill);
  return -1;
});
await Future.wait([stdoutDone, stderrDone]);
```

#### 해결 방법

`dart_typescript.dart`의 `_streamTimeout` 패턴을 세 파일에 적용한다. 각 파일 상단의 `_processTimeout` 근처에 `const _streamTimeout = Duration(seconds: 5);`를 추가하고, stream wait에 `.timeout(_streamTimeout, onTimeout: ...)`을 붙인다.

After:

```dart
const _processTimeout = Duration(seconds: 20);
const _streamTimeout = Duration(seconds: 5);

final code = await process.exitCode.timeout(_processTimeout, onTimeout: () {
  process.kill(ProcessSignal.sigkill);
  return -1;
});
await Future.wait([stdoutDone, stderrDone])
    .timeout(_streamTimeout, onTimeout: () {
  throw StateError('go-client $mode/$phase streams did not finish');
});
```

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

- [ ] `dart/crosstest/dart_go.dart`: `_streamTimeout`과 stream wait timeout 추가.
- [ ] `dart/crosstest/dart_python.dart`: `_streamTimeout`과 stream wait timeout 추가.
- [ ] `dart/crosstest/dart_kotlin.dart`: `_streamTimeout`과 stream wait timeout 추가.

#### 테스트 작성

별도 unit test는 작성하지 않는다. 이 파일들은 cross-language runner이고 timeout failure는 실제 subprocess 명령에서 검증한다.

#### 중간 검증

```bash
cd dart && dart test
```

기대 결과: exit code 0.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `dart/crosstest/dart_go.dart` | TEST-1 |
| `dart/crosstest/dart_python.dart` | TEST-1 |
| `dart/crosstest/dart_kotlin.dart` | TEST-1 |

## 최종 검증

```bash
cd dart && dart test
cd dart && dart run crosstest/dart_go.dart
cd dart && dart run crosstest/dart_python.dart
cd dart && dart run crosstest/dart_kotlin.dart
rg --sort path -n "_streamTimeout|streams did not finish|Future\\.wait\\(\\[stdoutDone, stderrDone\\]\\)" dart/crosstest/dart_go.dart dart/crosstest/dart_python.dart dart/crosstest/dart_kotlin.dart dart/crosstest/dart_typescript.dart
```

기대 결과: 모든 실행 명령 exit code 0. `rg` 결과에서 수정 대상 3개 파일은 `_streamTimeout`과 `streams did not finish`를 포함한다.

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