<!-- task=m-workspace-port-env-standardization/01_service_defaults plan=1 tag=REVIEW_PORT_DEFAULTS -->

# Plan - REVIEW_PORT_DEFAULTS

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

`CODE_REVIEW-local-G07.md`의 구현 에이전트 소유 섹션 작성까지가 구현입니다. 변경 후 검증을 실행하고 실제 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 두고 리뷰를 요청하세요. 사용자 결정, 사용자 소유 외부 환경, 범위 충돌이 없이는 직접 질문하지 말고 `사용자 리뷰 요청` 섹션에 근거를 남깁니다. 최종 archive, `complete.log`, roadmap 갱신은 code-review/runtime 책임입니다.

## 배경

이전 리뷰(`code_review_local_G06_0.log`)에서 service default literal 자체는 계획과 맞는 것으로 확인했지만, API default test가 외부 `ALT_WORKER_SOCKET_URL` 환경변수에 오염되는 결함이 발견되었다. 이 follow-up은 해당 test hermeticity만 고친다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active `CODE_REVIEW-local-G07.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 사용자에게 직접 질문하지 않고, code-review가 해당 요청을 검증해 필요할 때만 `USER_REVIEW.md`를 작성한다.

## 분석 결과

### 근거

- archived review: `agent-task/m-workspace-port-env-standardization/01_service_defaults/code_review_local_G06_0.log`
- 실패 재현:

```bash
ALT_WORKER_SOCKET_URL=ws://example.invalid/socket go test ./services/api/internal/config
```

실패 요지: `TestLoadDefaultsIncludeLocalWebSocketOrigins`가 worker URL default를 기대하면서 `ALT_WORKER_SOCKET_URL`을 비우지 않아 외부 env 값을 읽는다.

### 범위 결정 근거

- 수정 대상은 `services/api/internal/config/config_test.go`로 제한한다.
- production config literal, worker config, worker README는 이미 이전 구현과 리뷰 중 보정으로 기준값에 맞아 있으므로 되돌리지 않는다.
- `deployments/local/**`, `bin/**`, root `README.md`, CLI/client URL 참조는 이 subtask 범위가 아니다.

### 빌드 등급

- build/review: `local-G07`. 결함이 명확하고 deterministic 재현 명령이 있으며, follow-up은 API config test 한 파일의 hermeticity 보강이다.

## 구현 체크리스트

- [ ] `TestLoadDefaultsIncludeLocalWebSocketOrigins`에서 `ALT_WORKER_SOCKET_URL`을 비워 default assertion이 외부 env에 흔들리지 않게 한다.
- [ ] `ALT_WORKER_SOCKET_URL=ws://example.invalid/socket go test ./services/api/internal/config`, `go test ./services/api/...`, `go test ./services/worker/...`, stale default `rg` 검증을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_PORT_DEFAULTS-1] API default test hermeticity

문제: `services/api/internal/config/config_test.go:8`의 `TestLoadDefaultsIncludeLocalWebSocketOrigins`가 `cfg.WorkerSocketURL` default를 검증하면서 `ALT_WORKER_SOCKET_URL`을 비우지 않는다. 외부 환경에 해당 env가 있으면 default 검증이 외부 값을 읽고 실패한다.

Before:

```go
t.Setenv("ALT_API_WS_ORIGIN_PATTERNS", "")

cfg := Load()
```

해결 방법: `cfg := Load()` 전에 `t.Setenv("ALT_WORKER_SOCKET_URL", "")`를 추가한다. 대안으로 worker URL default assertion을 `TestLoadWorkerSocketURL`에만 남길 수 있지만, 중복 assertion을 유지한다면 반드시 이 테스트 안에서 env를 제어한다.

수정 파일 및 체크리스트:

- [ ] `services/api/internal/config/config_test.go`

테스트 작성: 기존 테스트 보강만 수행한다. 새 테스트 파일은 만들지 않는다.

중간 검증:

```bash
ALT_WORKER_SOCKET_URL=ws://example.invalid/socket go test ./services/api/internal/config
```

기대 결과: exit code 0. 외부 env가 있어도 default test가 `t.Setenv("ALT_WORKER_SOCKET_URL", "")`로 격리되어 통과한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/api/internal/config/config_test.go` | REVIEW_PORT_DEFAULTS-1 |

## 최종 검증

```bash
ALT_WORKER_SOCKET_URL=ws://example.invalid/socket go test ./services/api/internal/config
go test ./services/api/...
go test ./services/worker/...
rg --sort path -n "127\\.0\\.0\\.1:8081|localhost:5432|localhost:6379|ALT_WORKER_PORT.*8081" services/api/internal/config services/worker/internal/config services/worker/README.md
```

기대 결과: 세 `go test` 명령은 exit code 0. 마지막 `rg`는 exit code 1/no output으로 old service default가 남지 않았음을 보여야 한다.

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