<!-- task=m-persistence-worker-backbone/01_storage_foundation plan=1 tag=REVIEW_STORAGE -->

# Plan - REVIEW_STORAGE

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 필수 단계다. 구현 후 검증 명령을 실행하고 실제 출력과 구현 메모를 기록한 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 범위 변경, 외부 환경 준비, 또는 계획 충돌로 막히면 active review stub의 `사용자 리뷰 요청` 섹션에 정확한 증거와 재개 조건을 적고 멈춘다. 구현 에이전트는 `USER_REVIEW.md`, archive log, `complete.log`를 만들지 않는다.

## 배경

첫 리뷰(`code_review_cloud_G07_0.log`)는 FAIL이다. storage foundation 자체는 컴파일되고 worker fresh tests, `bin/test`, `bin/lint`, `bin/build`는 재실행 통과했지만, 계획에 통합된 live migration 검증이 실패 출력만 남은 상태로 완료 처리되었고, migration command 로그와 generated check script에 repo에서 고칠 수 있는 결함이 남았다.

## 사용자 리뷰 요청 흐름

구현 중 사용자 결정이나 외부 환경 준비가 필요하면 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. Docker/field DB/Redis 환경이 끝까지 준비되지 않아 `[REVIEW_STORAGE-1]`의 성공 검증을 만들 수 없으면, 실패한 명령의 실제 stdout/stderr와 재개 조건을 적고 멈춘다. code-review가 검증 후 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## 분석 결과

### 읽은 파일

- `agent-task/m-persistence-worker-backbone/01_storage_foundation/plan_cloud_G07_0.log`
- `agent-task/m-persistence-worker-backbone/01_storage_foundation/code_review_cloud_G07_0.log`
- `agent-ops/rules/project/domain/worker/rules.md`
- `agent-ops/rules/project/domain/operations/rules.md`
- `agent-ops/rules/private/testing-env.md`
- `services/worker/cmd/alt-worker-migrate/main.go`
- `bin/worker-storage-check`
- `bin/contracts-check`

### 빌드 등급

- build lane: `cloud-G07`, review lane: `cloud-G07`.
- 후속 작업은 shell workflow, generated check contract, live infra verification trust를 포함하므로 `cloud-G07`을 유지한다.

## 구현 체크리스트

- [ ] [REVIEW_STORAGE-1] STORAGE-1 통합 검증을 성공 출력 또는 정당한 사용자 리뷰 요청으로 회복한다.
- [ ] [REVIEW_STORAGE-2] migration command 로그에서 `DATABASE_URL` secret 노출을 제거하고 redaction test를 추가한다.
- [ ] [REVIEW_STORAGE-3] worker storage generated check를 snapshot diff 방식으로 바꿔 새 파일 drift를 잡는다.
- [ ] `services/worker` fresh test와 workspace 회귀 검증을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

이 follow-up은 `01_storage_foundation` 안에서 첫 리뷰의 Required 항목만 닫는다. `02+01_worker_runtime`은 이 디렉터리에 `complete.log`가 생긴 뒤 진행되어야 한다.

### [REVIEW_STORAGE-1] Verification Recovery

#### 문제

Archived review `code_review_cloud_G07_0.log`의 `[STORAGE-1]`은 local PostgreSQL/Redis 실행과 migration command DB 접속 확인까지 통합 검증으로 요구한다. 그러나 기록된 최종 검증은 Docker 없음, compose 실행 실패, `bin/infra-check` 실패뿐이고 사용자 리뷰 요청도 `없음`으로 남았다.

#### 해결 방법

- Docker 가능한 환경 또는 field host에서 local compose 기준 PostgreSQL/Redis를 실행한다.
- `bin/infra-check`가 성공한 뒤 `services/worker` migration command가 `config.Load()`의 `DATABASE_URL`로 DB에 접속하고 migration을 적용하는 성공 출력을 남긴다.
- 현재 Codex 컨테이너처럼 Docker/pg_isready/Redis 등 외부 전제 때문에 계속 불가능하면 이 항목을 완료로 체크하지 말고, active `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청`에 정확한 실패 명령, stdout/stderr, 재개 조건을 적는다.
- 실제 비밀이 들어간 `DATABASE_URL` 출력은 리뷰 파일에 붙이지 않는다. 필요한 경우 password를 제거한 redacted value나 환경 상태만 기록한다.

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

- [ ] `agent-task/m-persistence-worker-backbone/01_storage_foundation/CODE_REVIEW-cloud-G07.md`: 성공 검증 출력 또는 정당한 사용자 리뷰 요청을 기록한다.

#### 테스트 결정

새 unit test는 필요 없다. 이 항목은 live infra/migration 검증 신뢰도 회복이 목적이다.

#### 중간 검증

```bash
command -v docker || test -x /Applications/Docker.app/Contents/Resources/bin/docker
```

```bash
DOCKER="$(command -v docker || printf '%s' /Applications/Docker.app/Contents/Resources/bin/docker)" && "$DOCKER" compose -f deployments/local/docker-compose.yml up -d postgres redis
```

```bash
bin/infra-check
```

```bash
(cd services/worker && go run ./cmd/alt-worker-migrate)
```

### [REVIEW_STORAGE-2] Migration Log Redaction

#### 문제

`services/worker/cmd/alt-worker-migrate/main.go:18`이 `DATABASE_URL` 전체를 `slog`에 기록한다. URL에는 `postgres://user:password@host/db` 형태의 credential이 들어갈 수 있어 local/field/운영 로그에 secret이 남는다.

#### 해결 방법

- migration command 시작 로그에서 raw `DATABASE_URL`을 제거한다.
- 필요한 디버그 정보는 `database_url_set=true`, `database_host`, `database_name`처럼 password 없는 metadata만 남긴다.
- redaction helper를 둘 경우 parse 실패 입력과 password 포함 URL을 검증하는 test를 추가한다.

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

- [ ] `services/worker/cmd/alt-worker-migrate/main.go`: raw `DATABASE_URL` logging을 제거하거나 redacted metadata로 교체한다.
- [ ] `services/worker/cmd/alt-worker-migrate/main_test.go`: password 포함 URL이 로그/metadata helper 결과에 남지 않는지 검증한다.

#### 테스트 결정

작성: `services/worker/cmd/alt-worker-migrate/main_test.go`

테스트명 후보:

- `TestDatabaseURLLogMetadataRedactsPassword`
- `TestDatabaseURLLogMetadataRejectsRawSecret`

#### 중간 검증

```bash
(cd services/worker && go test -count=1 ./cmd/alt-worker-migrate)
```

### [REVIEW_STORAGE-3] Generated Check Drift Detection

#### 문제

`bin/worker-storage-check:11`은 generation 뒤 `git diff --exit-code`만 확인한다. checkout에 `services/worker/internal/storage/postgres/sqlc` generated files가 빠진 상태라면 `sqlc generate`가 새 untracked 파일을 만들 수 있는데, `git diff`는 untracked 파일을 drift로 보지 않는다. 이러면 typed query generation check가 false pass할 수 있다.

#### 해결 방법

- `bin/contracts-check` 패턴처럼 generated output directory를 임시 디렉터리에 snapshot한다.
- `bin/worker-storage-gen` 실행 후 snapshot과 실제 output을 `diff -ru`로 비교한다.
- 새 파일, 삭제, 수정이 있으면 diff를 stderr로 출력하고 실패한다.
- 이 방식은 active 작업의 untracked 새 파일 여부와 무관하게 현재 파일 내용 기준 drift만 검증한다.

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

- [ ] `bin/worker-storage-check`: snapshot, `trap`, `diff -ru`, drift exit flow를 추가한다.

#### 테스트 결정

별도 shell unit test는 만들지 않는다. 현재 generated output이 있는 상태에서 `bin/worker-storage-check`가 통과해야 한다.

#### 중간 검증

```bash
bin/worker-storage-check
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/worker/cmd/alt-worker-migrate/main.go` | REVIEW_STORAGE-2 |
| `services/worker/cmd/alt-worker-migrate/main_test.go` | REVIEW_STORAGE-2 |
| `bin/worker-storage-check` | REVIEW_STORAGE-3 |
| `agent-task/m-persistence-worker-backbone/01_storage_foundation/CODE_REVIEW-cloud-G07.md` | REVIEW_STORAGE-1, final evidence |

## 최종 검증

```bash
bin/worker-storage-check
```

```bash
(cd services/worker && go test -count=1 ./cmd/alt-worker-migrate ./internal/storage/...)
```

```bash
(cd services/worker && go test -count=1 ./...)
```

```bash
command -v docker || test -x /Applications/Docker.app/Contents/Resources/bin/docker
```

```bash
DOCKER="$(command -v docker || printf '%s' /Applications/Docker.app/Contents/Resources/bin/docker)" && "$DOCKER" compose -f deployments/local/docker-compose.yml up -d postgres redis
```

```bash
bin/infra-check
```

```bash
(cd services/worker && go run ./cmd/alt-worker-migrate)
```

```bash
bin/test
```

```bash
bin/lint
```

```bash
bin/build
```

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. live infra 검증이 환경 전제로 막히면 성공으로 체크하지 말고 `사용자 리뷰 요청`을 채운다.
