<!-- task=m-node-resource-model-unification/02+01_node_admission plan=1 tag=REVIEW_REFACTOR -->

# Node Admission Review Follow-up Plan

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

이 계획은 code-review FAIL 후속이다. 구현 중 직접 사용자에게 질문하지 말고, 선택된 Milestone lock 결정만 review stub의 `사용자 리뷰 요청`에 기록한다. 이번 이슈는 사용자 리뷰 gate 대상이 아니며 repo-local test repair로 해결한다. 구현 뒤에는 반드시 `CODE_REVIEW-local-G04.md`의 구현 에이전트 소유 섹션을 채운다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/node-resource-model-unification.md`
- Task ids:
  - `node-admission`: Node admission global gate removal and resource capacity preservation
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- Archived plan: `agent-task/m-node-resource-model-unification/02+01_node_admission/plan_local_G06_0.log`
- Archived review: `agent-task/m-node-resource-model-unification/02+01_node_admission/code_review_local_G06_0.log`
- Verdict: FAIL
- Required summary: `apps/node/internal/node/node_test.go:2798`의 `return`이 `TestConfigRefreshFailedAdapterStartDoesNotRollbackConfig` 테스트 함수 자체를 종료해 failed refresh assertion과 cleanup을 도달 불가능하게 만든다.
- Affected files: `apps/node/internal/node/node_test.go`
- Reviewer direct repairs already applied: stale global-gate 주석 일부를 `apps/node/internal/node/node_test.go`와 `apps/node/internal/node/node_concurrency_integration_test.go`에서 adapter-capacity 의미로 정리했다.
- Verification evidence: reviewer reran `go test -count=1 -timeout 120s ./apps/node/...`; command passed, but verification trust remains failed because the required failed-refresh assertion is skipped before execution.
- Roadmap carryover: `node-admission` Roadmap Completion still applies and must not be claimed until the repaired test provides trustworthy SDD `S03`/`S04` evidence.
- Allowed archive reread: if more context is needed, read only the two archived files listed above.

## 범위 결정 근거

Node admission implementation itself is not reopened in this loop. The required repair is limited to restoring meaningful regression coverage for the failed config refresh path that was claimed as part of the node-admission evidence.

## 구현 체크리스트

- [x] `TestConfigRefreshFailedAdapterStartDoesNotRollbackConfig`의 두 번째 run start 대기를 `return` 없이 관측 가능하게 고친다.
- [x] 실패 refresh 이후 `FAILED` 응답, 기존 blocking adapter/gate 보존, held run cleanup이 모두 실제로 실행되는 assertion을 유지/추가한다.
- [x] `go test -count=1 -run TestConfigRefreshFailedAdapterStartDoesNotRollbackConfig ./apps/node/internal/node`와 `go test -count=1 -timeout 120s ./apps/node/...`를 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [x] `CODE_REVIEW-local-G04.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REFACTOR-1] Restore Failed Refresh Regression Coverage

**문제:** `apps/node/internal/node/node_test.go:2798`의 `return`은 두 번째 blocking run start를 기다리는 루프 안에서 테스트 함수 전체를 종료한다. 따라서 아래의 failing CLI adapter refresh, `NODE_CONFIG_REFRESH_STATUS_FAILED` assertion, held run cleanup은 실행되지 않는다.

**해결 방법:** 두 번째 run start를 별도 signal로 관측하게 만들고 조기 `return`을 제거한다. 예를 들어 `blockingAdapterWithStart.started`를 close-once channel이 아니라 buffered start event channel로 바꾸고, 첫 번째 run과 두 번째 run을 각각 `<-started`로 기다린다. 그 다음 failed refresh assertion을 실행하고, 두 held run을 모두 unblock해서 goroutine이 남지 않게 한다.

**추가 검증:** failed refresh 뒤에도 기존 `blocking` adapter가 계속 사용 가능하다는 assertion을 추가하면 좋다. 예: held run cleanup 이후 `blocking` adapter로 짧은 후속 run을 실행해 old registry/router state가 보존되었음을 확인한다.

**수정 파일 및 체크리스트:**

- [x] `apps/node/internal/node/node_test.go` — 조기 `return` 제거, 두 번째 run start 관측 방식 수정
- [x] `apps/node/internal/node/node_test.go` — failed refresh status와 기존 adapter/gate 보존 assertion이 실제 실행되도록 보강
- [x] `apps/node/internal/node/node_test.go` — held run cleanup이 항상 실행되도록 정리

**중간 검증:**

```bash
go test -count=1 -run TestConfigRefreshFailedAdapterStartDoesNotRollbackConfig ./apps/node/internal/node
```

**최종 검증:**

```bash
go test -count=1 -timeout 120s ./apps/node/...
```
