<!-- task=03_go_typescript_process_cleanup plan=0 tag=CROSSTEST_PROCESS -->

# Plan - CROSSTEST_PROCESS

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

**구현 마지막 단계에서 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 반드시 채워야 한다. 이 파일이 비어 있으면 작업은 완료가 아니다.**
구현 체크리스트를 기준으로 작업하고, 계획과 리뷰 stub의 체크리스트를 모두 완료하며, 중간/최종 검증을 실행한 실제 출력을 리뷰 파일에 기록한다. 리뷰 파일의 `이 파일을 읽는 리뷰 에이전트에게`에 있는 archive 지시와 `코드리뷰 전용 체크리스트`는 리뷰 에이전트 전용이므로 실행하거나 수정하지 않는다.

## 배경

Go server의 TypeScript client crosstest는 `npx tsx` wrapper를 실행한다. timeout은 `CommandContext`로 걸려 있지만 wrapper process가 개입하고 pipe reader wait가 별도 bound 없이 `wg.Wait()`에 묶여 있다. 로컬 `tsx`를 직접 실행하고 `exec.Cmd.WaitDelay`를 사용해 timeout/pipe cleanup contract를 더 명확하게 만든다.

## 분석 결과

### 읽은 파일

- `go/crosstest/go_typescript.go`
- `README.md`

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

- timeout 경로의 wrapper child cleanup과 pipe wait delay: 별도 회귀 테스트 없음.
- 정상 경로의 TypeScript client PASS line parsing: `go run ./crosstest/go_typescript.go`가 TCP/WS/TLS/WSS 정상 경로를 확인한다.

### 심볼 참조

- renamed/removed symbol: none.
- `runTypescriptClient` call site: `go/crosstest/go_typescript.go:135`, `:169`, `:198`, `:232`, `:261`, `:295`, `:324`, `:358`.

### 분할 판단

split decision policy를 먼저 평가했다. 이 task는 Go 도메인의 한 runner 파일만 다룬다. Dart/Python의 subprocess API와 Kotlin runner 정리는 별도 검증과 다른 failure mode를 가지므로 sibling task로 분리했다.

Sibling task:

- `01_kotlin_subprocess_cleanup`: Kotlin server runner 정리.
- `02_dart_typescript_process_cleanup`: Dart server runner 정리.
- `03_go_typescript_process_cleanup`: 이 task.
- `04_python_typescript_process_cleanup`: Python server runner 정리.

### 범위 결정 근거

`go/crosstest/go_dart.go`, `go/crosstest/go_python.go`, `go/crosstest/go_kotlin.go`는 TypeScript wrapper 문제가 아니므로 제외한다. Go core implementation과 TypeScript client helper는 변경하지 않는다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. Go subprocess orchestration, stdout/stderr parsing, timeout exit-status contract를 다루는 terminal-agent 작업이다.

## 구현 체크리스트

- [ ] [CROSSTEST_PROCESS-1] Go server TypeScript client runner가 로컬 `tsx`를 직접 실행하고 pipe wait delay를 bounded 처리한다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 실제 출력을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [CROSSTEST_PROCESS-1] Go TypeScript subprocess cleanup

#### 문제

`go/crosstest/go_typescript.go:370`은 `args := []string{"tsx", ...}`를 만든 뒤 `go/crosstest/go_typescript.go:380`에서 `exec.CommandContext(ctx, "npx", args...)`를 실행한다. `go/crosstest/go_typescript.go:402`에서 `cmd.Wait()` 후 `go/crosstest/go_typescript.go:403`의 `wg.Wait()`는 pipe scan goroutine 종료를 무제한 기다린다.

#### 해결 방법

`typescriptDir/node_modules/.bin/tsx`를 직접 실행한다. `cmd.WaitDelay = 5 * time.Second`를 설정해 process exit 후 pipe close가 지연될 때 `cmd.Wait()`가 무제한 대기하지 않게 한다. `wg.Wait()`도 channel + timeout으로 감싸고, timeout이면 명확한 error를 반환한다.

Before (`go/crosstest/go_typescript.go:370`):

```go
args := []string{
    "tsx",
    "crosstest/go_typescript_client.ts",
```

After:

```go
tsxBin := filepath.Join(typescriptDir, "node_modules", ".bin", "tsx")
args := []string{
    "crosstest/go_typescript_client.ts",
```

Before (`go/crosstest/go_typescript.go:380`):

```go
cmd := exec.CommandContext(ctx, "npx", args...)
cmd.Dir = typescriptDir
```

After:

```go
cmd := exec.CommandContext(ctx, tsxBin, args...)
cmd.Dir = typescriptDir
cmd.WaitDelay = 5 * time.Second
```

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

- [ ] `go/crosstest/go_typescript.go`: local `tsx` 경로를 사용.
- [ ] `go/crosstest/go_typescript.go`: `cmd.WaitDelay` 설정.
- [ ] `go/crosstest/go_typescript.go`: `wg.Wait()`를 bounded wait로 감싸고 timeout error를 반환.

#### 테스트 작성

별도 테스트 파일은 작성하지 않는다. 이 파일은 `//go:build ignore` executable crosstest이고 정상 경로는 existing runner로 직접 검증한다. timeout fixture는 별도 도구가 필요해 이번 task 범위에서 제외한다.

#### 중간 검증

```bash
cd go
go run ./crosstest/go_typescript.go
```

예상 결과: `PASS all go-server/typescript-client crosstests passed`.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `go/crosstest/go_typescript.go` | CROSSTEST_PROCESS-1 |

## 최종 검증

```bash
cd go
go run ./crosstest/go_typescript.go
```

예상 결과: PASS. Go test cache는 해당 없는 `go run` 검증이다.

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