<!-- task=m-vllm-provider-serving-validation/01_spark_container plan=1 tag=VLLM_CONTAINER -->
# Code Review: DGX Spark vLLM container 기동 검증

## 개요

- Plan: `PLAN-cloud-G07.md`
- Roadmap Task: `spark-container`
- Spec Scenario: `S01`

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/vllm-provider-serving-validation.md`
- Task: `spark-container`

## Spec Targets

- SDD: `agent-roadmap/sdd/inference-provider-extension/vllm-provider-serving-validation/SDD.md`
- Scenario: `S01`

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

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

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

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G07.md` -> `code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md` -> `plan_cloud_G07_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-vllm-provider-serving-validation/01_spark_container/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다.
4. PASS이고 task group이 `m-vllm-provider-serving-validation`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [VLLM_CONTAINER-1] vLLM image/tag/digest 후보 확인 | [x] |
| [VLLM_CONTAINER-2] DGX Spark launch command와 cache/volume 기준 정리 | [x] |
| [VLLM_CONTAINER-3] `/v1/models` health check 검증 | [x] |

## 구현 체크리스트

- [x] DGX Spark field host에서 ARM64/Blackwell용 vLLM OpenAI-compatible server image/tag와 digest 후보를 확인한다.
- [x] model cache/volume 경로와 launch command를 정리하고, token/secret이 stdout 또는 tracked 파일에 남지 않게 실행한다.
- [x] vLLM container를 기동하고 provider local health endpoint `http://127.0.0.1:8001/v1/models`가 served model을 반환하는지 검증한다.
- [x] container 이름, image digest/tag, model cache/volume, launch command, health check 출력 요약을 review stub에 기록한다.
- [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_cloud_G07_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_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/m-vllm-provider-serving-validation/01_spark_container/`를 `agent-task/archive/YYYY/MM/m-vllm-provider-serving-validation/01_spark_container/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-vllm-provider-serving-validation`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-vllm-provider-serving-validation/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. sibling task가 남아 parent를 유지했다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.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가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.

## 계획 대비 변경 사항

1. **포트 변경: 8000 → 8001**
   - 사유: DGX Spark host의 8000 포트를 기존 Whisper API Server(`whisper_server` container)가 이미 점유 중.
   - 변경: `-p 8001:8000` (host 8001 → container 내부 8000). 검증 명령에서 포트를 8001로 대체.

2. **`--gpu-memory-utilization 0.87` 추가**
   - 사유: default 0.92 기준 110.06 GiB 요구 vs. 실제 free 108 GiB 미충족. `python` 4088 MiB, `Xorg` 43 MiB 등 기타 프로세스 상주.
   - 변경: 0.87 (≈ 104 GiB 요구)로 낮춰 기동 성공.

3. **Ollama 모델 사전 unload 필요**
   - 사유: `qwen3.6:35b-a3b-bf16` (~82 GB)가 로드된 상태여서 메모리 부족. `ollama stop` API 호출로 unload 후 진행.
   - 이 조건은 재기동 시 재현될 수 있음. vLLM 기동 전 Ollama 모델 unload 또는 `--gpu-memory-utilization` 조정이 필요.

4. **이미지 및 모델 신규 pull/download 필요**
   - 계획의 `vllm/vllm-openai:nightly-aarch64` 이미지가 host에 없어 `docker pull` 수행 (21.3 GB, ~10분).
   - `nvidia/Qwen3.6-35B-A3B-NVFP4` 모델이 host에 없어 HuggingFace에서 다운로드 수행 (22 GB). `huggingface_hub` 패키지를 `pip3 install --break-system-packages`로 설치 후 진행.

5. **`--max-model-len 32768`, `--dtype auto` 추가**
   - 표준 기동 파라미터로 추가. context 제한 없이 최대값 32768 사용.

## 주요 설계 결정

1. **image 선택: `vllm/vllm-openai:nightly-aarch64` 채택**
   - Docker Hub에서 현재 날짜(2026-06-17) 기준 가장 최신 ARM64 nightly 태그. `cu129-nightly-aarch64`도 동일 날짜 존재하나, plan 명세와 일치하는 `nightly-aarch64`를 우선 채택.
   - stable 릴리스 `v0.23.0-aarch64-cu129-ubuntu2404`도 후보지만, Blackwell/new kernel feature 접근성 고려해 nightly 사용.

2. **GB10 NVFP4 native 미지원 확인**
   - vLLM 로그: "Your GPU does not have native support for FP4 computation but FP4 quantization is being used. Weight-only FP4 compression will be used leveraging the Marlin kernel."
   - GB10은 FP4 native 연산 없이 Marlin kernel을 통한 weight-only 압축으로 동작. 성능 저하 가능성 있음. 후속 config/smoke plan에서 실제 throughput 확인 필요.

3. **model cache 위치: `/home/toki/Data/models/` (외부 마운트 NVMe)**
   - `/home/toki/Data` (ext4, 1.8 TB NVMe)에 384 GB Ollama 모델이 이미 상주. 동일 위치에 `/home/toki/Data/models/nvidia/Qwen3.6-35B-A3B-NVFP4/` 경로 생성.
   - container volume: `-v /home/toki/Data/models:/models`

4. **Docker nvidia runtime 미등록 상태에서 `--gpus all` 동작 확인**
   - `/etc/docker/daemon.json` 없음, docker info에 nvidia runtime 미등록 상태.
   - `--gpus all` 플래그가 정상 동작하는 이유: `nvidia-container-toolkit` 1.18.2가 설치되어 있고 `nvidia-container-runtime` binary가 `/usr/bin/`에 존재해 Docker가 자동 감지.

## 사용자 리뷰 요청

- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

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

- private host, token, secret이 tracked 파일이나 검증 출력에 남지 않았는지 확인한다.
- `/v1/models` health check가 실제 DGX Spark field host의 local provider endpoint에서 실행되었는지 확인한다.
- image tag뿐 아니라 digest 또는 동등한 고정 evidence가 남았는지 확인한다.

## 검증 결과

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

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.

### VLLM_CONTAINER-1 중간 검증

```bash
$ DGX_SPARK_SSH="<DGX_SPARK_SSH from agent-test/local/rules.md>" ssh "$DGX_SPARK_SSH" 'docker image inspect vllm/vllm-openai:nightly-aarch64 --format "{{json .RepoDigests}}"'
["vllm/vllm-openai@sha256:1aef087aa5159bcb8f8cb91301ecdf2f6daa6aa41420706afe30b6a9a7001858"]
```

추가 image 정보:
- 태그: `vllm/vllm-openai:nightly-aarch64`
- 사이즈: 21.3 GB
- vLLM 버전: `0.23.1rc1.dev101+g4c6266331`
- 아키텍처: aarch64 (ARM64)
- pull 날짜: 2026-06-17

### VLLM_CONTAINER-2 중간 검증 (launch command, cache/volume)

실행 명령:
```bash
docker run -d \
  --name iop-vllm-qwen36 \
  --gpus all \
  -p 8001:8000 \
  -v /home/toki/Data/models:/models \
  vllm/vllm-openai:nightly-aarch64 \
  --model /models/nvidia/Qwen3.6-35B-A3B-NVFP4 \
  --served-model-name nvidia/Qwen3.6-35B-A3B-NVFP4 \
  --host 0.0.0.0 \
  --port 8000 \
  --dtype auto \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.87
```

모델 캐시:
- host 경로: `/home/toki/Data/models/nvidia/Qwen3.6-35B-A3B-NVFP4/`
- container 내부 경로: `/models/nvidia/Qwen3.6-35B-A3B-NVFP4`
- 파일 구성: `model-00001-of-00003.safetensors` (9.4 GB) + `model-00002-of-00003.safetensors` (9.4 GB) + `model-00003-of-00003.safetensors` (3.2 GB) + 메타데이터
- 총 크기: ~22 GB
- 소스: HuggingFace `nvidia/Qwen3.6-35B-A3B-NVFP4` (gated: False, public)

### 최종 검증

```bash
$ DGX_SPARK_SSH="<DGX_SPARK_SSH from agent-test/local/rules.md>" ssh "$DGX_SPARK_SSH" 'set -eu
docker image inspect vllm/vllm-openai:nightly-aarch64 --format "{{json .RepoDigests}}"
docker ps --filter name=iop-vllm-qwen36 --format "{{.Names}} {{.Image}} {{.Status}}"
curl -fsS http://127.0.0.1:8001/v1/models'
["vllm/vllm-openai@sha256:1aef087aa5159bcb8f8cb91301ecdf2f6daa6aa41420706afe30b6a9a7001858"]
iop-vllm-qwen36 vllm/vllm-openai:nightly-aarch64 Up 6 minutes
{"object":"list","data":[{"id":"nvidia/Qwen3.6-35B-A3B-NVFP4","object":"model","created":1781684240,"owned_by":"vllm","root":"/models/nvidia/Qwen3.6-35B-A3B-NVFP4","parent":null,"max_model_len":32768,"permission":[{"id":"modelperm-90788b710a5b5b4c","object":"model_permission","created":1781684240,"allow_create_engine":false,"allow_sampling":true,"allow_logprobs":true,"allow_search_indices":false,"allow_view":true,"allow_fine_tuning":false,"organization":"*","group":null,"is_blocking":false}]}]}
```

host 환경 요약:
- GPU: NVIDIA GB10 (Grace Blackwell), driver 580.126.09, CUDA 13.0
- 아키텍처: aarch64
- 총 통합 메모리: 119.64 GiB
- vLLM model 로딩 시간: 108.44초 (safetensors 3 shards), 모델 메모리: 20.37 GiB
- NVFP4 backend: Marlin (GB10은 FP4 native 미지원, weight-only 압축 동작)
- 확정 endpoint (후속 plan 기준): `http://<DGX_SPARK_HOST>:8001/v1` (Edge/Node에서 접근 가능한 host/port는 `agent-test/local/rules.md`의 local-only 값 기준)

---

> **[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.

## 코드리뷰 결과

- 종합 판정: PASS
- 차원별 평가:
  - correctness: Pass - ARM64 vLLM image digest, launch command, cache/volume, container running 상태, `/v1/models` served model evidence가 S01 요구와 일치한다.
  - completeness: Pass - 계획된 세 항목과 review stub completion checklist가 모두 채워졌고, 8001 포트 변경은 충돌 회피 사유와 검증 명령 대체가 기록되어 있다.
  - test coverage: Pass - 최종 field command를 리뷰 중 재실행했고 동일 digest/container/model 응답을 확인했다.
  - API contract: Pass - served model `nvidia/Qwen3.6-35B-A3B-NVFP4`와 후속 Edge/Node base URL 기준이 OpenAI-compatible provider 경계로 기록되어 있다.
  - code quality: Pass - 코드 변경 없음. task artifact의 private SSH target/host IP 표기는 `<DGX_SPARK_SSH>`와 `<DGX_SPARK_HOST>`로 정리했다.
  - plan deviation: Pass - host port 8000 점유로 `8001:8000`을 사용한 변경은 구현 섹션에 근거가 있으며 SDD S01의 provider health evidence를 해치지 않는다.
  - verification trust: Pass - 리뷰 중 동일 원격 검증 명령을 재실행해 image digest, running container, `/v1/models` served model 응답을 확인했다.
  - spec conformance: Pass - SDD `S01` Evidence Map의 `docker image inspect`, launch command, health check `/v1/models` output이 충족되었다.
- 발견된 문제: 없음
- 다음 단계: PASS - `complete.log` 작성 후 task directory를 archive로 이동한다.
