<!-- task=04_python_typescript_process_cleanup plan=0 tag=CROSSTEST_PROCESS -->

# Plan - CROSSTEST_PROCESS

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

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

## 배경

Python server의 TypeScript client crosstest는 `npx tsx` wrapper를 실행하고 timeout 시 direct process만 kill한다. wrapper child가 남거나 `communicate()` 이후 cleanup이 지연되면 실패 경로가 흐릿해질 수 있다. 로컬 `tsx`를 직접 실행하고 timeout cleanup을 명확히 한다.

## 분석 결과

### 읽은 파일

- `python/crosstest/python_typescript.py`
- `README.md`

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

- timeout 경로의 process group cleanup: 별도 회귀 테스트 없음.
- 정상 경로의 TypeScript client PASS line parsing: `python3 crosstest/python_typescript.py`가 TCP/WS/TLS/WSS 정상 경로를 확인한다.

### 심볼 참조

- renamed/removed symbol: none.
- `run_typescript_client` call site: `python/crosstest/python_typescript.py:70`, `:86`, `:111`, `:127`, `:176`, `:199`, `:232`, `:256`.

### 분할 판단

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

Sibling task:

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

### 범위 결정 근거

`python/crosstest/python_dart.py`, `python/crosstest/python_go.py`, `python/crosstest/python_kotlin.py`는 TypeScript wrapper 문제가 아니므로 제외한다. Python core implementation과 TypeScript client helper는 변경하지 않는다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. Python subprocess orchestration, stdout/stderr capture, timeout cleanup contract를 다루는 terminal-agent 작업이다.

## 구현 체크리스트

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

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

#### 문제

`python/crosstest/python_typescript.py:269`는 `args = ["tsx", ...]`를 만든 뒤 `python/crosstest/python_typescript.py:278`에서 `asyncio.create_subprocess_exec("npx", *args, ...)`를 실행한다. timeout 시 `python/crosstest/python_typescript.py:288`에서 direct process만 kill한다.

#### 해결 방법

`typescript_package_dir() / "node_modules" / ".bin" / "tsx"`를 직접 실행한다. POSIX 환경에서는 `start_new_session=True`로 실행하고 timeout 시 `os.killpg(process.pid, signal.SIGKILL)`을 우선 사용하되, 실패하면 `process.kill()`로 fallback한다. 필요한 import는 `os`, `signal`을 추가한다.

Before (`python/crosstest/python_typescript.py:269`):

```python
args = [
    "tsx",
    "crosstest/python_typescript_client.ts",
```

After:

```python
tsx_bin = ts_dir / "node_modules" / ".bin" / "tsx"
args = [
    str(tsx_bin),
    "crosstest/python_typescript_client.ts",
```

Before (`python/crosstest/python_typescript.py:278`):

```python
process = await asyncio.create_subprocess_exec(
    "npx",
    *args,
```

After:

```python
process = await asyncio.create_subprocess_exec(
    *args,
    start_new_session=True,
```

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

- [ ] `python/crosstest/python_typescript.py`: `os`, `signal` import 추가.
- [ ] `python/crosstest/python_typescript.py`: local `tsx` 직접 실행.
- [ ] `python/crosstest/python_typescript.py`: timeout 시 process group kill + fallback cleanup 적용.

#### 테스트 작성

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

#### 중간 검증

```bash
cd python
python3 crosstest/python_typescript.py
```

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

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `python/crosstest/python_typescript.py` | CROSSTEST_PROCESS-1 |

## 최종 검증

```bash
cd python
python3 crosstest/python_typescript.py
```

예상 결과: PASS.

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