<!-- task=m-openai-compatible-think-control/05+01,02,03,04_dev_smoke plan=0 tag=TEST -->

# Code Review Reference - TEST

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> Start only after predecessors `01`, `02`, `03`, and `04` have `complete.log`.
> Fill implementation-owned sections and verification output, then stop with active files in place. Finalization is review-agent-only.

## 개요

date=2026-07-03
task=m-openai-compatible-think-control/05+01,02,03,04_dev_smoke, plan=0, tag=TEST

## Roadmap Targets

- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md`
- Task ids:
  - `dev-smoke`: 실제 dev provider pool에서 `think=false`, omitted default, `include_reasoning=false` 요청을 실행하고 provider raw trace와 Edge SSE를 비교한다.
- Completion mode: check-on-pass

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

> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다.

이 review는 외부 dev-runtime 증거의 신뢰성을 확인한다. source ref와 binary freshness, full test 결과, provider pool 연결 상태, capacity observation, 그리고 think-control raw trace/SSE 비교가 모두 있어야 PASS다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [TEST-1] Remote Runner Preflight | [x] |
| [TEST-2] Clean Sync, Full Test, Rebuild, Restart | [x] |
| [TEST-3] Think-Control SSE And Provider Trace | [x] |
| [TEST-4] Capacity Health Evidence | [x] |

## 구현 체크리스트

- [x] Predecessor `complete.log` for `01`, `02`, `03`, and `04`를 확인한 뒤 시작한다. (모두 archive에서 PASS 확인)
- [x] Remote runner inventory를 재확인하고 source ref, dirty state, branch, HEAD를 기록한다.
- [x] Clean sync 기준 ref를 확정한다. 원격은 `8838e0a`에 머물러 있었고 local/origin `main`은 이미 `eea8dd0`(milestone 01~04 구현 포함)를 갖고 있어 stale `origin/main` 문제는 없었다. `git fetch origin main && git reset --hard origin/main && git clean -fd`로 clean sync했다.
- [x] Remote runner에서 `go test ./...`를 빌드 전 실행한다. 전체 PASS.
- [x] dev-runtime Edge/mac/Linux ARM64/Windows AMD64 Node binary를 같은 source ref(`eea8dd0`)에서 rebuild한다.
- [x] 빌드 후 `config check`, `config refresh --help`, `config refresh --mode dry-run`, `go test ./...`를 실행한다. 전체 PASS/OK.
- [x] Edge, mac-codex-node, gx10-vllm-node, onexplayer-lemonade-node를 dev-runtime 절차대로 재시작하고 port/process/status를 확인한다. 3개 node 모두 `connected:true`.
- [x] `/v1/models`가 `qwen3.6:35b`를 노출하는지 확인한다.
- [x] `/v1/responses`와 `/v1/chat/completions` capacity smoke를 capacity+1(11개) 기준으로 실행하고 provider `in_flight/queued` snapshot을 남겼다. 둘 다 총 `in_flight=10`, 합산 `queued=3` 관측, 완료 후 전부 회복.
- [x] `/v1/chat/completions`에서 omitted default, `think=false`, `include_reasoning=false` 세 케이스를 stream으로 실행하고 Edge SSE와 provider raw trace를 비교했다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 실행 내용과 검증 출력으로 채운다.

## 코드리뷰 전용 체크리스트

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] active plan/review 파일을 `.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고하고 roadmap을 직접 수정하지 않는다.
- [x] WARN/FAIL이면 다음 active plan/review 파일 또는 정당한 `USER_REVIEW.md`를 작성한다.

## 계획 대비 변경 사항

- 계획은 GX10/OneXPlayer가 Linux/Windows에서 각각 `bin/edge`류 build 산출물을 그대로 배치하는 것을 전제로 서술했지만, 실제 두 host의 기존 배치 관례는 (a) GX10: `/home/toki/iop-gx10-vllm/iop-node`에 직접 이진 파일, `iop-node.prev-<timestamp>` 백업 관례, (b) OneXPlayer: `C:/Users/r0bin/iop-field/iop-node.exe`에 직접 이진 파일, `iop-node.exe.prev-<timestamp>` 백업 관례였다. 기존 host 관례를 그대로 따라 배치했다 (계획의 경로 표현과 실제 배치 대상 파일명이 다를 뿐 절차상 차이는 없음).
- OneXPlayer에서 최초 Win32_Process.Create 시도는 CommandLine에 중첩 큰따옴표를 직접 넣어 PowerShell 파싱 오류(`ParserError`)가 발생했다. 이를 우회하기 위해 로컬에서 `.bat` 스크립트(환경변수 설정 + `iop-node.exe` 실행)를 만들어 scp로 전달한 뒤 `Win32_Process.Create`의 CommandLine을 `cmd.exe /c <bat경로>` 형태로 단순화해서 세션 독립 실행을 유지했다. `Start-Process`는 SSH 세션 내부에서 사용하지 않았다.
- TEST-3 provider raw trace 확보를 위해 계획에 명시되지 않았던 임시 조치로 `apps/node/internal/adapters/openai_compat`의 기존 trace 기능(`IOP_OPENAI_COMPAT_TRACE_STREAM=true` 환경변수, 코드 변경 아님, 기존 구현에 이미 존재)을 3개 node 프로세스에 켜서 재시작했다. TEST-3 증거 수집 후 다시 trace 없이 재시작해 원래 상태로 되돌렸다(최종 검증 시점 3-node 재연결 재확인 완료).
- provider raw trace 소스는 계획이 가정한 "provider 서버 자체 로그"가 아니라 Node의 `openai_compat` adapter가 남기는 "provider stream raw chunk" 로그(`reasoning_len`, `raw_has_open_think` 등)였다. GX10 vLLM 서버 프로세스는 root 권한으로 떠 있어 toki 계정에서 서버 자체 stdout/stderr에 접근할 수 없었고, mac-mlx-vllm/onexplayer-lemonade도 자체 request-body 로그를 남기지 않는다. Node adapter의 raw response chunk trace는 provider가 실제로 reasoning을 생성했는지(`reasoning_len`, `raw_has_open_think`)를 직접 보여주므로 S05 검증 목적(생성 여부 vs 노출 여부 구분)에는 충분하다고 판단했다. Request body 자체(예: `chat_template_kwargs.enable_thinking`)의 직접 관측은 이 smoke에서 하지 않았다 — 해당 매핑은 predecessor `02+01_node_provider_mapping`의 단위 테스트로 이미 검증됨.
- 세 케이스 모두 실제로는 `gx10-vllm` provider(priority 0)가 처리했다. 요청이 idle 상태에서 단일 요청으로 들어갈 때 priority 0 provider가 우선 선택되는 것으로 관측되었으며, 계획에서 provider를 명시적으로 고정하는 절차는 없었으므로 실제 라우팅 결과를 그대로 채택했다.

## 주요 설계 결정

- Source ref: `eea8dd0` (local/origin/main과 동일, milestone 01~04 구현 전부 포함). 원격 checkout은 이 ref로 clean sync 후 재빌드했다.
- Masking policy: bearer token(`sk-local` 포함), node 등록 token, private key 경로는 이 문서에 원문으로 남기지 않았다. curl 호출에는 사용했으나 결과 로그에서 값은 마스킹 처리했다.
- Capacity smoke 프롬프트는 depth-first/breadth-first 비교 900단어 에세이 요청으로, capacity+1(11개) 동시 요청을 `/v1/responses`, `/v1/chat/completions` 각각에 실행했다.
- Skipped: `git clean -fdx`는 사용하지 않았고 `git clean -fd`만 사용했다(스킬 금지 사항 준수). Windows onexplayer 접속은 계획대로 현재 host에서 직접 `ssh r0bin@192.168.0.59`로 수행했고 `toki` 경유 접속은 하지 않았다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._

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

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

- Source ref가 predecessor 구현을 포함하고, remote binary가 같은 ref에서 rebuild되었는지 확인한다.
- Full `go test ./...` pre/post 결과가 있거나, 누락 사유와 위험이 명확한지 확인한다.
- Raw trace/SSE evidence가 세 케이스 모두에 대해 있고, token/API key/private path가 마스킹되었는지 확인한다.
- `include_reasoning=false`는 generation disable이 아니라 exposure disable로 판정했는지 확인한다.
- Capacity smoke는 request success만이 아니라 provider snapshot의 `in_flight/queued` 관측을 포함하는지 확인한다.

## 검증 결과

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

### TEST-1 중간 검증
```bash
$ ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git status --short --branch && git log --oneline -1 && test -f build/dev-runtime/edge.yaml && test -x build/dev-runtime/bin/edge && test -x build/dev-runtime/bin/iop-node'
## main...origin/main
8838e0a fix(openai): reasoning alias를 처리한다
edge.yaml OK
edge bin OK
iop-node bin OK
```
사전 확인 결과 원격은 `8838e0a`로 stale했다 (local/origin `main`은 `eea8dd0`). 로컬 `git log origin/main -1`도 `eea8dd0`이므로 stale `origin/main` 문제는 아니고, 원격 checkout만 뒤처져 있었다. TEST-2에서 clean sync로 해소했다.

### TEST-2 중간 검증
Clean sync:
```bash
$ ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git fetch origin main && git reset --hard origin/main && git clean -fd && git status --short --branch && git log --oneline -1'
From https://git.toki-labs.com/toki/iop
 * branch            main       -> FETCH_HEAD
   8838e0a..eea8dd0  main       -> origin/main
HEAD is now at eea8dd0 feat: add think-control API fields and dev smoke tests
## main...origin/main
eea8dd0 feat: add think-control API fields and dev smoke tests
```

빌드 전 전체 테스트: 전 패키지 `ok` (실패 없음, `iop/apps/edge/...`, `iop/apps/node/...`, `iop/packages/go/...` 등 전부 포함).

Rebuild (source ref `eea8dd0`):
```bash
$ go build -trimpath -o build/dev-runtime/bin/edge ./apps/edge/cmd/edge
$ go build -trimpath -o build/dev-runtime/bin/iop-node ./apps/node/cmd/node
$ GOOS=linux GOARCH=arm64 go build -trimpath -o build/dev-runtime/bin/iop-node-linux-arm64 ./apps/node/cmd/node
$ GOOS=windows GOARCH=amd64 go build -trimpath -o build/dev-runtime/bin/iop-node-windows-amd64.exe ./apps/node/cmd/node
-rwxr-xr-x  edge                             21993234 bytes
-rwxr-xr-x  iop-node                         27168258 bytes
-rwxr-xr-x  iop-node-linux-arm64             26253618 bytes
-rwxr-xr-x  iop-node-windows-amd64.exe       28501504 bytes
```

빌드 후 동작 확인:
```bash
$ build/dev-runtime/bin/edge --config build/dev-runtime/edge.yaml config check
OK build/dev-runtime/edge.yaml

$ build/dev-runtime/bin/edge --config build/dev-runtime/edge.yaml config refresh --help
(--mode, --addr, --config-path 플래그 정상 노출)

$ build/dev-runtime/bin/edge --config build/dev-runtime/edge.yaml config refresh --mode dry-run --addr 127.0.0.1:19093
{"status":"applied","mode":"dry_run","changes":[],"summary":"no changes detected","changed_nodes":[],"changed_providers":[],"changed_models":[],"restart_required_paths":[]}

$ go test ./...   # 재실행, 전체 ok
```

재시작 후 연결 확인:
```bash
$ ssh toki@toki-labs.com 'curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs-dev/status | jq "{edge_id, nodes: [.nodes[] | {node_id, connected}]}"'
{
  "edge_id": "edge-toki-labs-dev",
  "nodes": [
    {"node_id": "mac-codex-node", "connected": true},
    {"node_id": "gx10-vllm-node", "connected": true},
    {"node_id": "onexplayer-lemonade-node", "connected": true}
  ]
}
```

```bash
$ ssh toki@toki-labs.com 'curl -fsS -H "Authorization: Bearer <masked>" http://127.0.0.1:18083/v1/models | jq ".data[].id"'
"qwen3.6:35b"
```

재빌드/재시작 대상: Edge(`toki-labs.com`), mac-codex-node(같은 host, `iop-node --config node-codex.yaml`), gx10-vllm-node(`192.168.0.91`, linux-arm64 바이너리 교체 + `iop-node.prev-<timestamp>` 백업), onexplayer-lemonade-node(`192.168.0.59`, windows-amd64 바이너리 교체 + `iop-node.exe.prev-<timestamp>` 백업, 현재 host에서 직접 SSH, `Win32_Process.Create`로 세션 독립 실행).

### TEST-3 중간 검증

공통: `/v1/chat/completions`, `stream=true`, `model=qwen3.6:35b`, prompt="Solve a two-step logic puzzle and explain the answer briefly.". 세 요청 모두 실제로는 `gx10-vllm` provider(priority 0)가 처리했다(node-side `openai_compat` trace `run_id`로 상호 확인). provider raw trace는 Node `openai_compat` adapter의 기존 stream trace 로그(`IOP_OPENAI_COMPAT_TRACE_STREAM=true`)에서 얻었다.

**Case 1 — omitted default**
```bash
$ curl -sS -N -H "Authorization: Bearer <masked>" -d '{"model":"qwen3.6:35b","stream":true,"messages":[...]}' http://127.0.0.1:18083/v1/chat/completions
```
- Edge SSE: `reasoning_content` 청크 1381개 관측, `content` 청크 188개, 정상 `finish_reason":"stop"` + `[DONE]`으로 종료.
- Provider raw trace(gx10-vllm, 동일 run_id): `reasoning_len` 값 다수 non-zero(1~4자 단위 청크 다수), `raw_has_open_think:false`(think 태그 자체는 없고 델타 단위 reasoning 필드로 옴). → provider가 실제 reasoning을 생성했고 Edge가 기본 노출 정책대로 그대로 노출.

**Case 2 — `think=false`**
```bash
$ curl -sS -N -H "Authorization: Bearer <masked>" -d '{"model":"qwen3.6:35b","stream":true,"think":false,"messages":[...]}' http://127.0.0.1:18083/v1/chat/completions
```
- Edge SSE: `reasoning_content` 0건. 정상 `finish_reason":"stop"` + `[DONE]`.
- Provider raw trace(gx10-vllm, 동일 run_id, 235개 청크): `reasoning_len:0` 전 구간, `raw_has_open_think:false` 전 구간. → provider 레벨에서 reasoning 생성 자체가 비활성화됨(단순 노출 억제가 아니라 생성 비활성화로 확인).

**Case 3 — `include_reasoning=false`**
```bash
$ curl -sS -N -H "Authorization: Bearer <masked>" -d '{"model":"qwen3.6:35b","stream":true,"include_reasoning":false,"messages":[...]}' http://127.0.0.1:18083/v1/chat/completions
```
- Edge SSE: `reasoning_content` 0건, `content` 236건 관측. 정상 `finish_reason":"stop"` + `[DONE]`.
- Provider raw trace(gx10-vllm, 동일 run_id): `reasoning_len` non-zero 다수(1~4자 단위 청크 다수, case 1과 유사 분포). → provider는 reasoning을 그대로 생성했지만 Edge가 노출만 억제함(생성 비활성화가 아니라 노출 비활성화로 확인, 계획의 판정 기준과 일치).

### TEST-4 중간 검증

`/v1/chat/completions` capacity+1(11개 동시 요청, 900단어 에세이 프롬프트, non-stream):
```bash
$ (11개 동시 curl 실행) → chat_1..chat_11 전부 HTTP 200
$ ssh toki@toki-labs.com 'curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs-dev/status | jq -c "[.nodes[].provider_snapshots[] | {id, capacity, in_flight, queued}]"'
[{"id":"mac-mlx-vllm","capacity":3,"in_flight":3,"queued":1},{"id":"gx10-vllm","capacity":4,"in_flight":4,"queued":1},{"id":"onexplayer-lemonade","capacity":3,"in_flight":3,"queued":1}]
```
peak 관측: 총 `in_flight=10`(=capacity 합), 합산 `queued=3`(요구치 `>=1` 충족). 완료 후 재조회 시 세 provider 전부 `in_flight=0, queued=0` 회복.

`/v1/responses` capacity+1(11개 동시 요청, 동일 900단어 프롬프트):
```bash
$ (11개 동시 curl 실행) → resp_1..resp_11 전부 HTTP 200
$ ssh toki@toki-labs.com 'curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs-dev/status | jq -c "[.nodes[].provider_snapshots[] | {id, capacity, in_flight, queued}]"'
[{"id":"mac-mlx-vllm","capacity":3,"in_flight":3,"queued":1},{"id":"gx10-vllm","capacity":4,"in_flight":4,"queued":1},{"id":"onexplayer-lemonade","capacity":3,"in_flight":3,"queued":1}]
```
peak 관측: 총 `in_flight=10`, 합산 `queued=3`. 완료 후 세 provider 전부 `in_flight=0, queued=0` 회복 확인.

### 최종 검증
```bash
$ ssh toki@toki-labs.com 'cd /Users/toki/agent-work/iop-dev && git status --short --branch && git log --oneline -1'
## main...origin/main
eea8dd0 feat: add think-control API fields and dev smoke tests
```

```bash
$ ssh toki@toki-labs.com 'export PATH=/opt/homebrew/bin:$PATH && cd /Users/toki/agent-work/iop-dev && go test ./...'
(전 패키지 ok, 실패 없음)
```

```bash
$ ssh toki@toki-labs.com 'curl -fsS -H "Authorization: Bearer <masked>" http://127.0.0.1:18083/v1/models | jq ".data[].id"'
"qwen3.6:35b"
```

```bash
$ ssh toki@toki-labs.com 'curl -fsS http://127.0.0.1:18001/edges/edge-toki-labs-dev/status | jq "{edge_id, nodes: [.nodes[] | {node_id, connected}]}"'
{"edge_id":"edge-toki-labs-dev","nodes":[{"node_id":"mac-codex-node","connected":true},{"node_id":"gx10-vllm-node","connected":true},{"node_id":"onexplayer-lemonade-node","connected":true}]}
```
TEST-3 증거 수집을 위해 켰던 node trace(`IOP_OPENAI_COMPAT_TRACE_STREAM`)는 TEST-4 이후 3개 node를 trace 없이 재시작하여 원복했고, 위 최종 상태는 원복 이후 재확인한 결과다.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - Correctness: Pass
  - Completeness: Fail
  - Test coverage: Fail
  - API contract: Pass
  - Code quality: Pass
  - Implementation deviation: Fail
  - Verification trust: Fail
  - Spec conformance: Fail
- 발견된 문제:
  - Required: `agent-task/m-openai-compatible-think-control/05+01,02,03,04_dev_smoke/CODE_REVIEW-cloud-G07.md:66`에 따르면 `omitted default`, `think=false`, `include_reasoning=false` 세 TEST-3 케이스가 모두 `gx10-vllm` provider에서만 처리됐다. 하지만 Milestone `dev-smoke`는 dev-runtime 세 provider에서 smoke가 통과해야 한다고 요구하고(`agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md:54`), SDD Evidence Map도 `dev-smoke` 완료 evidence에 provider별 관측 기록을 요구한다(`agent-roadmap/sdd/knowledge-tool-optimization-extension/openai-compatible-think-control/SDD.md:85`). Capacity smoke는 세 provider가 connected/healthy이고 capacity queue가 동작한다는 증거일 뿐, mac vLLM-MLX와 OneXPlayer Lemonade에서 think-control raw trace/SSE 동작이 실제로 맞는지는 증명하지 못한다. Follow-up에서는 provider별로 `omitted default`, `think=false`, `include_reasoning=false`를 라우팅/관측하고, 각 provider id와 run id, Edge SSE reasoning/content 관측, node/provider raw trace 관측을 마스킹된 실제 출력으로 기록해야 한다.
- 다음 단계: FAIL follow-up plan/review를 작성해 provider별 S05 smoke evidence를 보강한다.
