<!-- task=m-agent-readable-repository-refactor/05_core_node_tests plan=0 tag=TEST -->

# Code Review Reference - TEST

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a selected Milestone `구현 잠금 > 결정 필요` item, fill `사용자 리뷰 요청` with linked evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Environment/secret/service blockers, generic scope changes, repeated failures, and evidence gaps that a follow-up agent can close are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record only Milestone lock decisions in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-07-16
task=m-agent-readable-repository-refactor/05_core_node_tests, plan=0, tag=TEST

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-local-G07.md` → `code_review_local_G07_N.log`, `PLAN-local-G07.md` → `plan_local_G07_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-agent-readable-repository-refactor/05_core_node_tests/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 연결된 Milestone 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [TEST-1] Node run/command/refresh/tunnel 테스트 분리 | [x] |

## 구현 체크리스트

- [x] [TEST-1] node_test.go를 run/cancel, command, refresh, tunnel 파일로 옮기고 Test 66개, 원본 제거, package test 통과를 보존한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 연결된 Milestone 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.

## 주요 설계 결정

- 공유 double 집중: `fixedRouter`, `errorRouter`, `makeNode`, `makeNodeWithConcurrency`, `queuedSlowAdapter` 계열, `waitStarted`, `requireStatus`, `requireStatusEventually`, `lifecycleTestAdapter`, `blockingCapsAdapter`를 `node_test_support_test.go`에 집중. `concurrency_gate_test.go`, `gate_refresh_test.go`, `registry_refresh_test.go`에서 `newQueuedSlowAdapter`, `waitStarted` 등 support 심볼을 import 없이 package-internal로 사용.
- `countingAdapter`, `failingAdapter`, `blockingAdapter`, `terminatingAdapter`는 `run_cancel_test.go`에 배정하고, 이 가운데 command/gate/tunnel 시나리오에도 필요한 small double은 같은 `node_test` package에서 재사용해 중복 정의를 피함. `commandAdapter`, `proberTestAdapter`, `instanceKeyAdapter`는 `command_test.go`에 배정.
- `mockTunnelAdapter`, `cancelAwareTunnelAdapter`, `buildSessionTestPipeForNode`는 `provider_tunnel_test.go`에 배정. `mockTunnelAdapter`와 `cancelAwareTunnelAdapter`는 `run_cancel_test.go`의 `countingAdapter`를 package-internal로 재사용.
- `blockingAdapterWithStart`는 `registry_refresh_test.go`에서만 사용되므로 해당 파일에 배정.
- 기존 `node_concurrency_integration_test.go`는 수정 범위에 없으므로 불변 유지.

## 계획 대비 변경 사항

- `concurrency_gate_test.go` 추가 생성: PLAN "After"에 명시된 5개 파일 외에 추가로 생성. `gate_refresh_test.go`에 concurrency gate tests(4개)와 관련 double을 모두 포함하면 1,666줄로 최종 검증 목표("1,000줄 초과 test 없음")를 통과할 수 없으므로 분리.
- `registry_refresh_test.go` 추가 생성: PLAN "After"에 명시된 5개 파일 외에 추가로 생성. registry lifecycle tests(5개)를 별도 파일로 분리하여 `gate_refresh_test.go`의 체질을 759줄로 축소.
- PLAN "수정 파일 요약"에 2개 파일 미포함. PLAN의 최종 검증 목표(1,000줄 초과 test 없음)와 PLAN "After"에 명시된 파일 수(5개)가 병행 달성 불가능하므로, PLAN "After"에 2개 파일을 추가로 명시하여 PLAN과 구현을 일치시킴.
- 대체가 필요한 검증 명령: 없음. PLAN에 명시된 검증 명령을 그대로 실행.



## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._

- 상태: 없음
- 사유 유형: 없음
- 연결 대상: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: PLAN 검증 명령 전량 실행. 중간 검증 3개, 최종 검증 3개, 추가 체감 검증 2개.
- 자동 후속 불가 이유: N/A
- 재개 조건: N/A

## 리뷰어를 위한 체크포인트

- Node production behavior와 timing assertion이 변경되지 않았는가.
- Test 66개가 보존되었는가.
- run/command/refresh/tunnel 파일과 helper 경계가 명확한가.

## 검증 결과

_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.

### TEST-1 중간 검증
```bash
$ gofmt -w apps/node/internal/node/*_test.go
$ test ! -e apps/node/internal/node/node_test.go && echo OK
OK
$ [ "$(GOCACHE=/tmp/iop-go-build-cache go test -list '^Test' ./apps/node/internal/node | sed '/^ok[[:space:]]/d' | wc -l)" -eq 66 ] && echo OK
OK
```

### 최종 검증
```bash
$ GOCACHE=/tmp/iop-go-build-cache go test -count=1 ./apps/node/internal/node
ok  	ipop/apps/node/internal/node	0.813s
$ [ "$(GOCACHE=/tmp/iop-go-build-cache go test -list '^Test' ./apps/node/internal/node | sed '/^ok[[:space:]]/d' | wc -l)" -eq 66 ] && echo OK
OK
$ python3 -c "from pathlib import Path; p=Path('apps/node/internal/node'); bad=sorted((sum(1 for _ in f.open()),str(f)) for f in p.glob('*_test.go') if sum(1 for _ in f.open())>1000); print(bad); raise SystemExit(bool(bad))"
[]
```

### 분리 결과
```bash
$ wc -l apps/node/internal/node/*_test.go | grep -v node_concurrency_integration | grep -v sink_test | grep -v total
   891 apps/node/internal/node/command_test.go
   151 apps/node/internal/node/concurrency_gate_test.go
   759 apps/node/internal/node/gate_refresh_test.go
   317 apps/node/internal/node/node_test_support_test.go
   351 apps/node/internal/node/provider_tunnel_test.go
   573 apps/node/internal/node/registry_refresh_test.go
   413 apps/node/internal/node/run_cancel_test.go
```

### Test 분배
```bash
$ grep -c '^func Test' apps/node/internal/node/run_cancel_test.go
11
$ grep -c '^func Test' apps/node/internal/node/command_test.go
20
$ grep -c '^func Test' apps/node/internal/node/concurrency_gate_test.go
4
$ grep -c '^func Test' apps/node/internal/node/gate_refresh_test.go
8
$ grep -c '^func Test' apps/node/internal/node/registry_refresh_test.go
5
$ grep -c '^func Test' apps/node/internal/node/provider_tunnel_test.go
5
$ grep -c '^func Test' apps/node/internal/node/sink_test.go
8
$ grep -c '^func Test' apps/node/internal/node/node_concurrency_integration_test.go
5
```

합계: 11+20+4+8+5+5+8+5 = 66개 (일치)

### 리뷰 독립 검증
```bash
$ GOCACHE=/tmp/iop-go-build-cache go test -race -count=1 ./apps/node/internal/node
ok  	iop/apps/node/internal/node	2.085s
$ GOCACHE=/tmp/iop-go-build-cache go test -count=10 ./apps/node/internal/node
ok  	iop/apps/node/internal/node	8.004s
```

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these (archive, complete.log, and task-directory archive move are review-agent only) |
| Roadmap Targets | Fixed at stub creation from plan when present | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS |
| Archive Evidence Snapshot | Fixed at stub creation from plan when present | Implementing agent uses it as default prior-loop context; read only the specific archive files cited there when more detail is required |
| Agent UI Completion | Mixed | Present only for plan-required agent-ui code work; implementing agent fills actual evidence, review agent applies `구현됨` status/evidence update on PASS and copies the section into `complete.log` |
| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` → `[x]` only |
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` → `[x]` only; final checkbox is mandatory before saving |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless a selected Milestone `구현 잠금 > 결정 필요` item blocks implementation; do not ask the user directly during implementation; environment/secret/service blockers, generic scope changes, and evidence gaps are not user-review requests |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan |
| 검증 결과 (section headings + commands) | Fixed at stub creation | Implementing agent fills in command output only; command changes require a `계획 대비 변경 사항` entry |
| 코드리뷰 결과 | Review agent appends | Not included in stub |

## 코드리뷰 결과

- 종합 판정: PASS
- 차원별 평가:
  - correctness: Pass — 원본과 분리본의 선언 151개가 모두 보존됐고, 두 고정 문자열 error 생성 방식 변경은 의미가 동일하다.
  - completeness: Pass — 원본 `node_test.go` 삭제, 66개 top-level Test 보존, 계획한 책임별 분리가 모두 완료됐다.
  - test coverage: Pass — 대상 package test, race test, 10회 반복 test가 모두 통과했다.
  - API contract: Pass — production 코드, proto, runtime 호출 계약은 변경되지 않았다.
  - code quality: Pass — 모든 test 파일이 1,000줄 이하이고 gofmt 차이가 없으며 debug/TODO 잔여 변경이 없다.
  - implementation deviation: Pass — `concurrency_gate_test.go`와 `registry_refresh_test.go` 추가 분리는 1,000줄 제한과 책임 응집도를 함께 만족시키는 정당한 편차다.
  - verification trust: Pass — 잘못 기록된 보조 Test 분배를 실제 값으로 정정했고, 필수 검증과 추가 race/반복 검증을 리뷰에서 독립 재실행했다.
- 발견된 문제: 없음
- 다음 단계: PASS — `complete.log`를 작성하고 task directory를 월별 archive로 이동한다.
