---
test_env: dev-corp
test_profile: node-smoke
domain: node
verification_type: smoke
last_rule_updated_at: 2026-07-13
---

# node-smoke dev-corp 테스트

## 읽기 조건

- `apps/node/**` 변경 또는 dev-corp node 실행, adapter, transport, router, store 검증 판단이 필요한 경우

## 적용 범위

- `apps/node/cmd/node/**`
- `apps/node/internal/bootstrap/**`
- `apps/node/internal/node/**`
- `apps/node/internal/runtime/**`
- `apps/node/internal/router/**`
- `apps/node/internal/transport/**`
- `apps/node/internal/adapters/**`
- `apps/node/internal/store/**`
- dev-corp Linux ARM64/macOS Node bootstrap과 provider endpoint 연결

## 분류

- domain: node
- verification_type: smoke
- scope: dev-corp node 실행 파이프라인과 Edge 연결 baseline

## 환경

- host: local checkout. provider evidence가 필요하면 mac-mini `ssh fe@172.24.63.178`을 사용한다.
- Edge runtime evidence: public `iop.ai.kr`를 기준으로 한다.
- port: compose Edge-Node TCP transport `19006`, native provider-pool Edge-Node TCP 후보 `18087`
- runtime: Go `1.24`
- package manager: Go modules / Makefile
- docker: unit/smoke quick check는 Docker를 요구하지 않는다. compose dev-corp 검증은 mac-mini에서 수행한다.
- external service: dev-corp Edge runtime 후보는 `iop.ai.kr:18087`이다. mac-mini local endpoint와 reverse tunnel은 dev-corp Edge 경로로 사용하지 않는다.
- model endpoint: dev-corp OpenAI-compatible base URL 기본 후보 `https://digitalplatform.iop.ai.kr/v1`; direct Edge listener 확인이 필요할 때만 `http://digitalplatform.iop.ai.kr:18086/v1`
- credential: token/secret/API key 원문은 문서에 기록하지 않는다.

## dev-corp Node 접속 기준

dev-corp의 실제 3-node 연결을 점검할 때는 각 provider host의 `~/iop-dev-corp-field/node.yaml`을 확인하고, `transport.edge_addr`가 `iop.ai.kr:18087`인지 검증한다.

mac-mini `ssh fe@172.24.63.178`의 `/Users/fe/agent-work/iop-dev-corp` checkout은 provider SSH runner로만 사용한다.

retired mac-mini local route와 reverse tunnel route는 Edge 연결로 사용하지 않는다.

- DGX Spark 01 vLLM node: `corp-dgx-spark-01-vllm-node` / `corp-dgx-spark-01-vllm`
  - SSH/user: mac-mini에서 `ssh digitalcommerce_dgx_spark_01@192.168.2.2`
  - provider endpoint: `http://192.168.2.2:8003/v1`
  - Edge adapter endpoint: node-local `http://127.0.0.1:8003/v1`
  - Edge addr: `iop.ai.kr:18087`
  - served model: `ornith:35b`
  - capacity baseline 후보: `4`
  - runtime capacity/context/KV: Docker container `iop-vllm-ornith35b-fp8`, image `vllm/vllm-openai:nightly-aarch64`, `vllm=0.23.1rc1.dev1042+g8e981630c`, `--max-num-seqs 4`, `--max-model-len 262144`, `--gpu-memory-utilization 0.47`; agent/tool-call profile `--enable-auto-tool-choice`, `--tool-call-parser qwen3_xml`, `--reasoning-parser qwen3`, `--trust-remote-code`; 2026-07-13 startup log 기준 GPU KV cache `783,347` tokens, `262144` full-context concurrency `2.99x`
  - start script: `/home/digitalcommerce_dgx_spark_01/start_vllm_ornith35b_docker_8003.sh`
  - workspace: `/home/digitalcommerce_dgx_spark_01`
- DGX Spark 02 vLLM node: `corp-dgx-spark-02-vllm-node` / `corp-dgx-spark-02-vllm`
  - SSH/user: mac-mini에서 `ssh dplab@192.168.2.4`
  - provider endpoint: `http://192.168.2.4:8005/v1`
  - Edge adapter endpoint: node-local `http://127.0.0.1:8005/v1`
  - Edge addr: `iop.ai.kr:18087`
  - served model: `ornith:35b`
  - capacity baseline 후보: `4`
  - runtime capacity/context/KV: Docker container `iop-vllm-ornith35b-fp8`, image `vllm/vllm-openai:nightly-aarch64`, `vllm=0.23.1rc1.dev1042+g8e981630c`, `--max-num-seqs 4`, `--max-model-len 262144`, `--gpu-memory-utilization 0.50`; agent/tool-call profile `--enable-auto-tool-choice`, `--tool-call-parser qwen3_xml`, `--reasoning-parser qwen3`, `--trust-remote-code`; 2026-07-13 startup log 기준 GPU KV cache `1,074,276` tokens, `262144` full-context concurrency `4.10x`
  - start script: `/home/dplab/start_vllm_ornith35b_docker_8005.sh`
  - workspace: `/home/dplab`
  - 주의: Docker publish 때문에 host endpoint는 `8005`, container endpoint는 `8000`이다. `8000`, `8001`, `8002`, `8004`를 Spark02 Ornith 기본 endpoint로 쓰지 않는다.
- Mac Studio vLLM-MLX node: `corp-mac-studio-mlx-vllm-node` / `corp-mac-studio-mlx-vllm`
  - SSH/user: mac-mini에서 `ssh dc_dev@192.168.2.3`
  - provider endpoint: `http://192.168.2.3:8004/v1`
  - Edge adapter endpoint: node-local `http://127.0.0.1:8004/v1`
  - Edge addr: `iop.ai.kr:18087`
  - Edge provider catalog type: `openai_compat`; provider runtime type remains `vllm-mlx`.
  - served model: `mlx-community/gemma-4-26b-a4b-it-nvfp4`
  - capacity baseline 후보: `5` (provider catalog capacity; current runtime headroom `--max-num-seqs 6`)
  - runtime capacity/context/KV: `vllm-mlx=0.4.0`, python `/Users/dc_dev/vllm-env-0.4.0/bin/python`, `--continuous-batching`, `--max-num-seqs 6`, `--prefill-batch-size 6`, `--completion-batch-size 6`, `--chunked-prefill-tokens 1024`, `--disable-prefix-cache`, `--max-request-tokens 262144`, requested KV `262144x3` mapped to `--max-kv-size 786432`; agent/tool-call profile `--enable-auto-tool-choice`, `--tool-call-parser gemma4`, `--reasoning-parser gemma4`, `--default-chat-template-kwargs '{"enable_thinking":true}'`
  - start script: `/Users/dc_dev/iop-dev-corp-field/start_vllm_mlx_8004.sh`
  - workspace: `/Users/dc_dev`
  - process manager: 2026-06-25 기준 detached `screen` session `vllm_mlx_8004`; 이 host는 Python `pyexpat` 로딩에 `DYLD_LIBRARY_PATH=/opt/homebrew/opt/expat/lib`가 필요하다.

DGX Spark nodes는 Linux/ARM64 bootstrap을 기본으로 한다. Mac Studio node는 macOS bootstrap을 기본으로 한다. Windows native bootstrap은 dev-corp provider pool 기본 대상이 아니다.

Mac Studio의 secondary `http://192.168.2.3:8005/v1` endpoint는 기본 Node/provider pool 검증 대상이 아니다. 별도 alias/capacity 정책이 확정된 후 추가한다.

## 런타임 설정/검증 상태

- capacity `4`는 `262144` max context 요청 4개가 항상 100% context를 채운다는 보장이 아니다. dev-corp 운영 기준은 일반 호출이 prompt+generated KV 기준으로 max context의 `50-70%`를 사용한다는 가정이다.
- `context_window_max=262144`, `capacity=4`에서 KV `524,288` tokens / full-context concurrency `2.0x`는 lower bound이고, 운영 target은 KV `734,004-786,432` tokens / full-context concurrency `2.8x-3.0x`이다. 이 metric이 catalog capacity `4`보다 작다는 이유만으로 under-capacity로 판정하지 않되, `2.0x-2.8x`는 workload-specific smoke 없이는 운영 적합으로 보지 않는다.
- capacity smoke는 provider admission, queue behavior, health, completion 후 `in_flight=0`/`queued=0` 회복을 검증한다. 모든 capacity slot이 동시에 `262144` tokens를 100% 채울 수 있는지 검증하는 테스트가 아니다.
- DGX Spark 01에는 Ornith `8003` 기준 capacity `4`, context window `262144`, `--gpu-memory-utilization 0.47`을 반영했다. vLLM에는 vLLM-MLX식 `--max-kv-size`가 없으므로 실제 KV cache는 startup log의 `GPU KV cache size`로 검증한다.
- DGX Spark 01은 2026-07-13 재기동 후 `http://192.168.2.2:8003` 기준 `/health` 200, `/v1/models`, 직접 API, IOP `ornith:35b` smoke를 통과했다. 같은 로그에서 GPU KV cache `783,347` tokens, `262144` tokens/request concurrency `2.99x`가 확인됐다.
- DGX Spark 02에는 Ornith `8005` 기준 capacity `4`, context window `262144`, `--gpu-memory-utilization 0.50`을 반영했다. Docker `iop-vllm-ornith35b-fp8`는 host `8005` -> container `8000` 기준으로 동작하며, `/health`, `/v1/models`, 직접 API, IOP `ornith:35b` smoke를 통과했다.
- Spark의 Gemma4 `8002`/`8004` runtime은 2026-07-13 Ornith IOP provider 전환을 위해 내린 상태로 본다. Gemma4 provider pool은 Mac Studio `192.168.2.3:8004`만 기본 대상으로 둔다.
- Mac Studio에는 `vllm-mlx=0.4.0`, provider catalog capacity `5`, context window `262144`, requested KV `262144x3` 기준을 continuous batching 유지, runtime headroom `--max-num-seqs 6`, `--max-request-tokens 262144`, `--max-kv-size 786432`, `--disable-prefix-cache`로 반영했고 `/health`, `/v1/models`, 직접 API non-stream/stream auto tool-call, streaming multi-turn tool-result final answer를 확인했다.
- Gemma provider-pool은 Mac Studio vLLM-MLX provider에서 `default_thinking_token_budget: 1024` 기준으로 thinking을 기본 활성화한다. Edge/Node adapter 요청에서 `chat_template_kwargs.enable_thinking=true`가 적용되는 방향으로 검증한다.
- Spark Ornith provider는 `--enable-auto-tool-choice`, `--tool-call-parser qwen3_xml`, `--reasoning-parser qwen3`, `--trust-remote-code`, `--runner generate`를 둔다. Gemma4 provider는 Mac Studio vLLM-MLX `8004`만 기본 대상으로 하며 별도 chat template override 없이 `--continuous-batching`, `--disable-prefix-cache`, `--enable-auto-tool-choice`, `--tool-call-parser gemma4`, `--reasoning-parser gemma4`, `--default-chat-template-kwargs '{"enable_thinking":true}'`를 둔다. Qwen provider는 dev-runtime 문서의 Qwen 전용 parser/template 값을 따른다.
- Mac Studio vLLM-MLX의 위 값은 구동 가능한 최종 체크포인트다. 잔여 이슈로 Gemma4 thought channel delimiter가 최종 content에 누수될 수 있으며, 이 경우 runtime option 미세 조정보다 Edge/provider adapter sanitizer를 우선 검토한다. 추가 튜닝은 Spark vLLM 설정과 분리된 별도 실험으로만 수행한다.
- Gemma provider를 agent/tool-call 용도로 검증할 때는 일반 chat smoke와 별도로 forced tool call, auto tool call, streaming `delta.tool_calls`, multi-turn tool result 후 최종 답변을 확인한다. raw `<|tool_call>`/`<|"|>` marker나 thought channel text가 assistant content로 새면 provider parser/template profile 또는 Edge relay 경계 문제로 판정한다.
- provider catalog의 admission queue timeout은 두지 않는다. provider catalog `queue_timeout_ms=0`이고, Node `openai_compat_instances` adapter queue/request budget은 30분 기준인 `queue_timeout_ms=1800000`, `request_timeout_ms=1800000`으로 맞춘다.
- 2026-07-08 재확인 기준 DGX Spark 02는 mac-mini에서 SSH, provider `/health`, `/v1/models`가 회복됐고 직접 API auto/streaming tool-call smoke를 통과했다. 이때의 `/v1/responses` capacity 결과와 2026-07-09 `/v1/chat/completions` 15개 aggregate concurrency 결과는 legacy evidence이며, current public Edge 표준 smoke는 2026-07-13 기준 model-specific `ornith:35b` 9/6, `gemma4:26b` 9/6 동시 요청이다.

## 2026-07-09 연결/용량 검증 상태

- DGX Spark 01, DGX Spark 02, Mac Studio Node는 각 host의 `~/iop-dev-corp-field/node.yaml`에서 `edge_addr: "iop.ai.kr:18087"`로 실행된다.
- 2026-07-13 live status 기준 세 Node 모두 connected이며 provider snapshot은 Spark01 Ornith capacity `4`, Spark02 Ornith capacity `4`, Mac Studio Gemma4 capacity `5`이다. Public OpenAI-compatible route에서 `ornith:35b` 9/6, `gemma4:26b` 9/6 동시 요청이 모두 성공했고 완료 후 `in_flight=0`, `queued=0`, `healthy`로 회복했다. 사용자-facing 기본 base URL은 `https://digitalplatform.iop.ai.kr/v1`이다.
- Provider-pool passthrough 계약은 selected provider가 지원하는 OpenAI-compatible 표준 field와 provider extension field를 보존한다. `/v1/responses`는 capacity 성공 기준이 아니라 provider-dependent passthrough/relay 검증으로 분리한다. Provider가 지원하면 raw passthrough 성공을 확인하고, provider가 미지원하면 provider status/body가 IOP 변환 없이 relay되는지 확인한다.

## 명령

- setup:
- lint:
- unit: `go test ./apps/node/...`
- smoke: `./scripts/e2e-smoke.sh`는 기본 포트 임시 설정을 쓰는 보조 smoke이므로 dev-corp 포트 override 필요 여부를 먼저 확인한다.
- e2e: `make test-e2e`
- provider-health: mac-mini에서 `curl -fsS http://192.168.2.2:8003/health`, `curl -fsS http://192.168.2.4:8005/health`, `curl -fsS http://192.168.2.3:8004/health`
- full-cycle: repo 내부 edge-node 진단과 사용자 실행 cycle 수동 검증

## 필수 검증

- 변경한 node 패키지 또는 `go test ./apps/node/...`를 실행한다.
- 실행 요청, stream, cancel, status, session, adapter registry 경로를 바꾼 경우 repo 내부 edge-node 진단과 full-cycle 실제 구동 기준을 함께 적용한다.
- vLLM/OpenAI-compatible adapter 설정을 바꾼 경우 mac-mini에서 provider `/health`와 `/v1/models`를 먼저 확인하고, 이후 Edge OpenAI-compatible 경로에서 model alias 후보 `gemma4:26b`, `ornith:35b` 또는 작업에서 확정한 alias가 노출되는지 확인한다.
- dev-corp Edge runtime으로 연결하는 경우 Node가 `iop.ai.kr:18087` native provider-pool TCP를 사용하고 mac-mini local route, reverse tunnel route, local/test/dev baseline으로 붙지 않는지 확인한다.
- Node bootstrap UX는 Edge가 출력한 완성 명령을 사용하고, 사용자에게 수동 `node.yaml` 편집이나 named env parameter를 기본 경로로 요구하지 않는다.

## 보조 검증

- `./scripts/e2e-smoke.sh`는 mock adapter 기반 보조 smoke로 사용한다.
- `make test-e2e`는 보조 smoke이며 full-cycle 실제 구동을 대체하지 않는다.

## 판정 기준

- node 등록 후 edge console에서 node가 조회된다.
- 같은 session에서 메시지 2회가 start, 기대 payload를 포함한 `[node-*-message]`, 같은 run의 complete 순서로 edge 화면에 도착한다.
- node 로컬 `[node-message]` payload 라인 목록과 edge `[node-*-message]` payload 라인 목록이 run별로 내용/순서까지 동일해야 한다.
- edge complete는 같은 run의 마지막 `[node-*-message]` 이후에만 정상이다.
- command 결과가 `[node-*-<command>]` 또는 명확한 성공/unsupported/error 출력으로 edge 화면에 표시된다.
- provider nodes는 mac-mini에서 내부 endpoint로 `/health`와 `/v1/models`가 성공해야 한다.

## 기준 출력 예시

```text
curl -fsS http://192.168.2.2:8003/health
curl -fsS http://192.168.2.4:8005/health
curl -fsS http://192.168.2.3:8004/health
```

## 차단 기준

- mac-mini 또는 내부 provider node SSH 접근이 불가능하다.
- dev-corp Edge-Node TCP 후보 port 접근이 불가능하다.
- 필수 provider endpoint가 닫혀 있거나 `/v1/models`가 기대 모델을 노출하지 않는다.
- DGX Spark 02가 provider port down과 SSH banner exchange timeout을 동시에 보인다.
- Mac Studio vLLM-MLX node를 재시작해야 하는데 `8004` runtime의 `screen` session 또는 `DYLD_LIBRARY_PATH=/opt/homebrew/opt/expat/lib` 적용 여부를 확인할 수 없다.
- 외부 CLI profile 검증에 필요한 CLI 설치, 계정, provider 상태가 없다.

## 보고 항목

- 실행한 명령:
- 성공한 검증:
- 실패/차단된 검증:
- 생략 사유:
- 남은 위험:

## 금지 사항

- 사용자 실행 파이프라인 변경을 unit test만으로 완료 처리하지 않는다.
- `proto/gen/iop/*.pb.go` 생성 파일을 직접 수정하지 않는다.
- 사용자가 명시적으로 요청하지 않았는데 mac-mini 내부 경로를 Edge runtime 또는 Node `edge_addr` 기본값으로 승격하지 않는다.
- secret, token, API key 원문은 tracked 파일에 기록하지 않는다.
