fix(dev-runtime): 배포 검증 실패를 수정한다
원격 macOS에서 빈 prompt 인자가 oneshot CLI에 전달되어 cwd 테스트가 실패했고, app-server cwd 검증은 고정 sleep 레이스에 의존했다. dev 배포가 같은 기준으로 반복되도록 inventory와 capacity smoke 절차도 함께 정리한다.
This commit is contained in:
parent
36d8393a10
commit
a47331f21d
13 changed files with 662 additions and 16 deletions
|
|
@ -94,6 +94,7 @@
|
|||
|
||||
## 스킬 라우팅
|
||||
|
||||
- dev 배포, dev-runtime 배포, Edge/Node dev 환경 배포, provider pool 배포, OpenAI-compatible capacity smoke 검증: `agent-ops/skills/project/dev-runtime-deploy/SKILL.md`
|
||||
- 사용자 실행 파이프라인 검증, repo 내부 edge-node 진단, 메시지 2회 왕복, edge command 응답, 보조 E2E smoke, full-cycle 실제 구동, `scripts/dev/edge.sh`/`scripts/dev/node.sh` 진단 테스트: `agent-ops/skills/project/e2e-smoke/SKILL.md`
|
||||
- field 테스트 포트, artifact/bootstrap HTTP, 외부 테스트 환경: `agent-test/local/rules.md`를 따른다.
|
||||
- bootstrap/install UX, Agent Bootstrap, specialized agent 등록, Control Plane enrollment: `testing` domain rule과 `agent-test/local/rules.md`를 따른다.
|
||||
|
|
|
|||
130
agent-ops/skills/project/dev-runtime-deploy/SKILL.md
Normal file
130
agent-ops/skills/project/dev-runtime-deploy/SKILL.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
---
|
||||
name: dev-runtime-deploy
|
||||
version: 1.0.0
|
||||
description: dev 배포, dev-runtime 배포, Edge/Node dev 환경 배포 요청에서 clean sync, 전체 테스트, rebuild, 원격 배포, OpenAI-compatible capacity smoke를 수행하는 절차
|
||||
---
|
||||
|
||||
# dev-runtime-deploy
|
||||
|
||||
## 목적
|
||||
|
||||
dev-runtime provider pool을 제품 검증이 끝난 상태로 배포한다. 배포는 원격 checkout 동기화, 전체 테스트, 전체 rebuild, Edge/Node 재시작, provider snapshot 기반 capacity 검증까지 포함한다.
|
||||
|
||||
## 언제 호출할지
|
||||
|
||||
- 사용자가 `dev 배포`, `dev-runtime 배포`, `배포해봐`처럼 dev 환경 배포를 요청할 때
|
||||
- Edge, mac CLI node, GX10 vLLM node, OneXPlayer Lemonade node로 이루어진 dev-runtime provider pool을 갱신할 때
|
||||
- OpenAI-compatible `/v1/responses` 또는 `/v1/chat/completions` 경로가 provider capacity만큼 채워지는지 검증할 때
|
||||
- dev 환경의 remote runner, node 접속 정보, provider capacity, model alias 변경을 배포 절차에 반영할 때
|
||||
|
||||
## 입력
|
||||
|
||||
- `env`: 배포 대상 환경. 기본값은 `dev`이다.
|
||||
- `model`: OpenAI-compatible model alias. 지정하지 않으면 dev 환경 문서의 기준 model을 사용한다.
|
||||
- `capacity_targets`: provider별 기대 capacity. 지정하지 않으면 dev 환경 인벤토리 또는 `agent-test/dev/*` 문서에서 읽는다.
|
||||
- `source_ref`: 배포할 git ref. 지정하지 않으면 원격 runner의 기본 배포 branch 기준을 따른다.
|
||||
|
||||
## 먼저 확인할 것
|
||||
|
||||
- [ ] `agent-ops/rules/project/domain/testing/rules.md`를 읽고 사용자 실행 파이프라인 검증 기준을 확인한다.
|
||||
- [ ] dev 환경은 `agent-test/dev/inventory.yaml`을 먼저 읽는다. 파일이 없으면 `agent-test/dev/rules.md`, `agent-test/dev/edge-smoke.md`, `agent-test/dev/node-smoke.md`로 fallback하고, 구조화 inventory 누락을 보고한다.
|
||||
- [ ] dev-runtime provider pool과 compose/local profile을 섞지 않는다. dev-runtime은 native Edge/Node runtime과 dev-runtime config를 기준으로 한다.
|
||||
- [ ] OneXPlayer SSH 접속 정보는 현재 host 기준 `ssh r0bin@192.168.0.59`이다. `toki` 사용자명 또는 remote runner를 경유한 OneXPlayer 접속을 사용하지 않는다.
|
||||
- [ ] 현재 구현의 completion 검증 대상은 legacy `/v1/completions`가 아니라 `/v1/chat/completions`이다. `/v1/completions`는 route가 구현되어 있을 때만 별도 검증한다.
|
||||
- [ ] token, secret header, bootstrap token, private key 경로는 최종 보고에 원문으로 출력하지 않는다.
|
||||
|
||||
## 실행 절차
|
||||
|
||||
1. **환경 인벤토리 확정**
|
||||
- 배포 대상 runner, repo path, Edge id, Control Plane status URL, OpenAI base URL, Edge admin URL, Node SSH 정보를 문서에서 확정한다.
|
||||
- provider pool 대상 model alias와 provider별 capacity를 확정한다.
|
||||
- 필수 정보가 없거나 서로 충돌하면 배포를 시작하지 말고 누락/충돌 항목을 보고한다.
|
||||
|
||||
2. **원격 checkout clean sync**
|
||||
- 원격 runner checkout에서 `git fetch` 후 배포 기준 ref로 `git reset --hard`를 수행한다.
|
||||
- dirty 파일은 보존 대상으로 보지 않는다. 배포 전 clean 상태를 만든다.
|
||||
- 기본 cleanup은 `git clean -fd`이다. `git clean -fdx`는 config, token, secret, runtime artifact까지 삭제할 수 있으므로 사용하지 않는다.
|
||||
- sync 후 `git status --short --branch`와 `git log --oneline -1`을 기록한다.
|
||||
|
||||
3. **빌드 전 전체 테스트**
|
||||
- clean source 기준으로 `go test ./...`를 실행한다.
|
||||
- client/Flutter, proto, Makefile, script, config 변경이 배포 범위에 포함되면 해당 도메인 규칙의 전체 테스트도 추가한다.
|
||||
- 전체 테스트가 실패하면 build/deploy를 진행하지 않고 실패 패키지와 핵심 오류를 보고한다.
|
||||
|
||||
4. **전체 rebuild**
|
||||
- 같은 source ref에서 dev-runtime Edge binary, mac node binary, Linux ARM64 node binary, Windows AMD64 node binary를 모두 다시 빌드한다.
|
||||
- stale binary가 의심되거나 `config refresh` subcommand, admin port, version 출력이 맞지 않으면 clean sync부터 다시 시작한다.
|
||||
- 빌드 산출물 경로, timestamp, 크기, 실행 가능 여부를 기록한다.
|
||||
|
||||
5. **빌드 후 기본 동작 테스트**
|
||||
- 빌드된 Edge binary로 `config check`, `config refresh --help`, `config refresh --mode dry-run`을 실행한다.
|
||||
- 빌드 후에도 `go test ./...`를 실행한다. 실행하지 못하면 사유와 남은 위험을 보고한다.
|
||||
- dry-run이 `rejected` 또는 예상 밖 `restart_required`를 반환하면 배포를 멈추고 config diff를 보고한다.
|
||||
|
||||
6. **배포와 재시작**
|
||||
- Edge와 mac CLI node는 원격 runner에서 빌드 산출물 기준으로 재시작한다.
|
||||
- GX10 node는 Linux ARM64 node binary를 배포하고 기존 node process를 재시작한다.
|
||||
- OneXPlayer node는 현재 host에서 `ssh r0bin@192.168.0.59`로 접속한다. artifact가 remote runner에 있으면 현재 host를 통해 전달한 뒤 Windows host에서 교체한다.
|
||||
- OneXPlayer에서는 SSH 세션 안의 `Start-Process`로 장기 실행을 시작하지 않는다. `Win32_Process.Create` 또는 동등한 세션 독립 실행 방식으로 `iop-node.exe --config node.yaml serve`를 시작한다.
|
||||
|
||||
7. **배포 후 연결 검증**
|
||||
- Edge, OpenAI-compatible listener, Node TCP, admin port, Control Plane status port가 열려 있는지 확인한다.
|
||||
- Control Plane status에서 Edge가 connected이고 dev-runtime 기준 3개 node가 connected인지 확인한다.
|
||||
- 각 node의 `provider_snapshots`에서 provider `id`, `capacity`, `in_flight`, `queued`, `health`, `served_models`를 확인한다.
|
||||
- `/v1/models`가 대상 model alias를 노출하는지 확인한다.
|
||||
|
||||
8. **OpenAI-compatible capacity smoke**
|
||||
- `/v1/responses`와 `/v1/chat/completions`를 각각 검증한다. legacy `/v1/completions`는 구현되어 있지 않으면 실패로 보지 않는다.
|
||||
- 표준 부하 프롬프트는 짧은 토큰 응답을 요구하지 않는다. 700~1200 token 수준의 구조화된 답변을 유도해 요청이 동시에 관측될 시간을 만든다.
|
||||
- endpoint별로 총 provider capacity + 1개 요청을 동시에 보낸다. 예: capacity가 `4 + 3 = 7`이면 8개 동시 호출을 보낸다.
|
||||
- 환경 문서에 더 작은 aggregate smoke 기준이 남아 있더라도, 배포 완료 판정은 이 capacity+1 기준을 우선한다.
|
||||
- 요청 실행 중 Control Plane status를 반복 polling하여 대상 provider들의 `in_flight` 합이 총 capacity에 도달하고 `queued` 합이 1 이상이 되는 순간을 증거로 남긴다.
|
||||
- 각 provider의 `in_flight`가 자기 capacity를 넘지 않고, 적어도 한 번은 기대 capacity까지 차는지 확인한다.
|
||||
- 모든 요청 완료 후 같은 status에서 대상 provider들의 `in_flight=0`, `queued=0`으로 돌아오는지 확인한다.
|
||||
- Qwen 계열 reasoning/thinking 텍스트는 정상 응답으로 허용한다. exact-output match를 smoke 성공 기준으로 삼지 않는다.
|
||||
|
||||
9. **결과 보고**
|
||||
- source ref, clean sync 결과, 테스트 결과, 빌드 산출물, process/port 상태, connected node 목록, provider capacity snapshot, capacity smoke 관측값을 보고한다.
|
||||
- 실패한 단계가 있으면 다음 단계를 진행했는지 여부를 명확히 구분한다.
|
||||
- capacity smoke가 타이밍 문제로 관측 실패했으면 요청 성공과 별도로 `capacity 관측 미충족`으로 보고하고, 프롬프트 길이 또는 status polling 간격 조정을 제안한다.
|
||||
|
||||
## 실행 결과 검증
|
||||
|
||||
- [ ] 원격 runner checkout이 배포 기준 ref로 clean sync되었는가
|
||||
- [ ] 빌드 전 `go test ./...`와 필요한 추가 전체 테스트가 통과했는가
|
||||
- [ ] dev-runtime Edge/mac/Linux ARM64/Windows AMD64 binary가 같은 source ref에서 rebuild되었는가
|
||||
- [ ] 빌드 후 config check, refresh help, refresh dry-run, 전체 테스트가 통과했는가
|
||||
- [ ] Edge, mac CLI node, GX10 vLLM node, OneXPlayer Lemonade node가 재시작되고 3개 node가 connected 상태인가
|
||||
- [ ] OneXPlayer 접속과 실행이 `r0bin@192.168.0.59` 및 세션 독립 실행 방식으로 수행되었는가
|
||||
- [ ] `/v1/responses` capacity smoke에서 총 capacity만큼 `in_flight`가 차고 초과 요청이 queue에 잡혔는가
|
||||
- [ ] `/v1/chat/completions` capacity smoke에서 총 capacity만큼 `in_flight`가 차고 초과 요청이 queue에 잡혔는가
|
||||
- [ ] 완료 후 provider `in_flight=0`, `queued=0`으로 회복되었는가
|
||||
- 검증 실패 시: 실패 단계, 실패한 host/provider/endpoint, 관측된 snapshot, 진행 중단 여부를 보고한다.
|
||||
|
||||
## 출력 형식
|
||||
|
||||
```text
|
||||
dev-runtime 배포 결과
|
||||
- Source: <branch/ref/commit>, clean=<yes|no>
|
||||
- Pre-build tests: <command> - <pass|fail|not-run>
|
||||
- Build: edge=<path>, mac-node=<path>, linux-arm64-node=<path>, windows-amd64-node=<path>
|
||||
- Post-build checks: config-check=<pass|fail>, refresh-help=<pass|fail>, refresh-dry-run=<status>, tests=<pass|fail|not-run>
|
||||
- Deployment: edge=<pid/status>, mac-node=<pid/status>, gx10=<pid/status>, onexplayer=<pid/status>
|
||||
- Ports: <port summary>
|
||||
- Nodes: <node_id connected summary>
|
||||
- Providers: <provider_id capacity/in_flight/queued/health summary>
|
||||
- OpenAI-compatible: models=<pass|fail>, responses-capacity=<pass|fail>, chat-completions-capacity=<pass|fail>
|
||||
- Capacity evidence: <endpoint별 max in_flight/queued snapshot>
|
||||
- Blockers/Risk: <없음 또는 내용>
|
||||
```
|
||||
|
||||
## 금지 사항
|
||||
|
||||
- dirty checkout이나 stale binary를 그대로 배포하지 않는다.
|
||||
- `git clean -fdx`를 기본 cleanup으로 사용하지 않는다.
|
||||
- 빌드 전 전체 테스트 실패 후 배포를 계속하지 않는다.
|
||||
- OneXPlayer에 `toki` 사용자명으로 접속하거나 remote runner에서 다시 OneXPlayer로 SSH 접속하지 않는다.
|
||||
- OneXPlayer 장기 실행을 Windows OpenSSH 세션 내부 `Start-Process`에 의존하지 않는다.
|
||||
- Qwen reasoning/thinking 출력을 실패로 판정하거나 exact-output smoke를 기본 성공 기준으로 삼지 않는다.
|
||||
- OpenAI-compatible 요청 성공만으로 capacity 검증 성공을 선언하지 않는다. provider snapshot의 `in_flight/queued` 관측을 함께 남긴다.
|
||||
- 이 프로젝트 전용 배포 절차를 `agent-ops/rules/common/_templates` 또는 common skill에 넣지 않는다.
|
||||
56
agent-test/README.md
Normal file
56
agent-test/README.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# agent-test 환경 확장 기준
|
||||
|
||||
이 디렉터리는 테스트 환경별 실행 기준과 도메인/검증 시나리오별 profile을 둔다.
|
||||
새 환경(`qa`, `staging`, `dev-gpu`, `dev-team-a` 등)을 추가할 때는 기존 환경을 임의로 복사하지 말고 이 기준과 `_templates/`를 먼저 따른다.
|
||||
|
||||
## 환경 디렉터리
|
||||
|
||||
- 환경 디렉터리는 `agent-test/<env>/` 형식을 사용한다.
|
||||
- `<env>`는 소문자 영문, 숫자, 하이픈만 사용한다.
|
||||
- 각 환경에는 반드시 `agent-test/<env>/rules.md`를 둔다.
|
||||
- 도메인/검증 시나리오별 문서는 `agent-test/<env>/<test-profile>.md` 형식을 사용한다.
|
||||
- 기본 도메인 smoke profile은 기존 도메인 이름을 유지해 `node-smoke.md`, `edge-smoke.md`, `control-plane-smoke.md`, `client-smoke.md`, `platform-common-smoke.md`, `testing-smoke.md`처럼 둔다.
|
||||
|
||||
## rules.md 표준 섹션
|
||||
|
||||
새 `rules.md`는 아래 섹션 순서를 유지한다.
|
||||
|
||||
1. `공통 규칙`
|
||||
2. `기본 환경`
|
||||
3. `포트 매핑`
|
||||
4. `런타임 프로필`
|
||||
5. `프리플라이트`
|
||||
6. `노드/Provider 인벤토리 위치`
|
||||
7. `Field/bootstrap 반복 테스트 기준`
|
||||
8. `라우팅`
|
||||
9. `라우팅 규칙`
|
||||
|
||||
섹션이 해당 환경에 직접 필요하지 않더라도 삭제하지 말고 `없음`, `해당 없음`, 또는 대상 profile 링크를 남긴다.
|
||||
|
||||
## 확장 원칙
|
||||
|
||||
- 환경 공통값은 `rules.md`에 둔다.
|
||||
- 실제 노드, provider, bootstrap, model endpoint, workspace, SSH user/IP 같은 상세 인벤토리는 agent가 구조적으로 읽어야 하면 `inventory.yaml`에 두고, 사람용 설명과 도메인별 판정 기준은 해당 도메인 profile에 둔다.
|
||||
- 상위 `rules.md`에는 상세값을 복제하지 말고 `노드/Provider 인벤토리 위치`와 `라우팅`으로 연결한다.
|
||||
- compose, native Edge, dev-runtime provider pool처럼 같은 환경 안의 실행 모드는 `런타임 프로필`에서 분리한다.
|
||||
- 같은 포트 이름은 모든 환경에서 같은 행 이름을 쓴다. 값이 없으면 `해당 없음` 또는 `후보 <port>`로 둔다.
|
||||
- shared remote runner를 쓰는 환경은 `repo root`, `sync 기준`, `프리플라이트`를 반드시 명시한다.
|
||||
- secret, token, API key, private credential 원문은 `agent-test/`, `docs/`, `agent-roadmap/`에 기록하지 않는다.
|
||||
- private IP와 SSH user는 테스트 접속에 필요한 환경값이면 기록할 수 있다. 단, 잘못된 user가 발견되면 해당 env rules/profile과 사람용 guide를 함께 정정한다.
|
||||
- `agent-test/local/`은 local/private 기준이라 git 추적 제외될 수 있다. 추적 여부와 상관없이 현재 workspace의 운영 기준으로는 같은 구조를 유지한다.
|
||||
|
||||
## 새 환경 추가 절차
|
||||
|
||||
1. `_templates/env-rules-template.md`를 `agent-test/<env>/rules.md`로 복사한다.
|
||||
2. `<env>`, 날짜, runner, repo root, 포트, runtime profile을 채운다.
|
||||
3. agent가 반복해서 읽어야 하는 host/node/provider 값이 있으면 `_templates/inventory-template.yaml`을 사용해 `agent-test/<env>/inventory.yaml`을 만든다.
|
||||
4. 기존 도메인 smoke profile이 필요하면 `_templates/test-profile-template.md`를 사용해 `agent-test/<env>/<domain>-smoke.md`를 만든다.
|
||||
5. `rules.md`의 `노드/Provider 인벤토리 위치`와 `라우팅`에 생성한 inventory와 profile을 연결한다.
|
||||
6. remote runner나 external provider를 쓰면 `프리플라이트`에 확인할 항목을 구체화한다.
|
||||
7. local/test/dev 등 기존 환경과 공존해야 하면 `포트 매핑`에 충돌하지 않는 값을 기록한다.
|
||||
8. `rg --no-ignore`로 잘못된 SSH user, workspace, port 재사용, secret 원문이 없는지 확인한다.
|
||||
|
||||
## 현재 표준 구현
|
||||
|
||||
- `agent-test/local/rules.md`
|
||||
- `agent-test/dev/rules.md`
|
||||
101
agent-test/_templates/env-rules-template.md
Normal file
101
agent-test/_templates/env-rules-template.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
---
|
||||
test_env: <env>
|
||||
last_rule_updated_at: <YYYY-MM-DD>
|
||||
---
|
||||
|
||||
# <env> 테스트 규칙
|
||||
|
||||
**현재 문서를 반드시 끝까지 정독하고 작업한다. 다 읽지 않고 즉각 작업은 금지한다.**
|
||||
**<env> 테스트 환경의 핵심 실행 모드와 local/dev/qa 등 다른 환경과의 공존 기준을 이 문서에 둔다.**
|
||||
|
||||
## 공통 규칙
|
||||
|
||||
- <env> 테스트/검증은 이 파일을 기준으로 판단한다.
|
||||
- 작업 완료 검증은 변경 범위 기준으로 선택한다.
|
||||
- 필수 검증을 실행하지 못하면 차단 사유로 보고한다.
|
||||
- 최종 보고에는 실행 명령, 결과, 생략 사유, 남은 위험을 남긴다.
|
||||
- 환경값, secret, 개인 endpoint는 tracked docs/roadmap에 쓰지 않는다.
|
||||
- token/secret 원문은 원격 환경에서 주입하고, shell stdout/stderr와 최종 보고에 출력하지 않는다.
|
||||
- 테스트용 Docker 환경을 작성/수정할 때는 Docker Compose `networks`, IPAM subnet, static IPv4, `extra_hosts`, host publish 문서 어디에도 host LAN/VPN과 충돌하는 대역을 사용하지 않는다.
|
||||
|
||||
## 기본 환경
|
||||
|
||||
- host: <기본 실행 host 또는 runner SSH>
|
||||
- repo root: <원격/로컬 repo root>
|
||||
- sync 기준: <source sync 판단 기준>
|
||||
- env file: <compose/env file 기준 또는 해당 없음>
|
||||
- compose identity: <COMPOSE_PROJECT_NAME / network 또는 해당 없음>
|
||||
- port: <핵심 포트 요약>
|
||||
- optional field ports: <선택 포트 또는 해당 없음>
|
||||
- runtime: <Go/Flutter/Docker/외부 runtime>
|
||||
- package manager: <Go modules / Makefile / Flutter pub 등>
|
||||
- docker: <Docker 사용 기준>
|
||||
- external service: <외부 서비스 URL/host 요약>
|
||||
- model endpoint: <OpenAI-compatible 등 모델 endpoint>
|
||||
- credential: secret/token/API key 원문은 문서에 기록하지 않는다.
|
||||
|
||||
## 포트 매핑
|
||||
|
||||
| 용도 | local/test | dev | <env> |
|
||||
|---|---:|---:|---:|
|
||||
| Web preview | `13000-13099` | `13001` | `<port 또는 해당 없음>` |
|
||||
| Control Plane HTTP | `18000` | `18001` | `<port 또는 해당 없음>` |
|
||||
| CP Client WS | `19080` | `19001` | `<port 또는 해당 없음>` |
|
||||
| CP-Edge wire | `19081` | `19002` | `<port 또는 해당 없음>` |
|
||||
| Edge-Node TCP | `19090` | `19003` | `<port 또는 해당 없음>` |
|
||||
| Edge artifact/bootstrap | `18080` | `18082` | `<port 또는 해당 없음>` |
|
||||
| Edge OpenAI-compatible | `18081` | `18083` | `<port 또는 해당 없음>` |
|
||||
| Edge metrics | `19092` | `19101` | `<port 또는 해당 없음>` |
|
||||
| PostgreSQL host publish | `15400` | `15401` | `<port 또는 해당 없음>` |
|
||||
| Redis host publish | `16300` | `16301` | `<port 또는 해당 없음>` |
|
||||
|
||||
<환경 안에서 compose/native/dev-runtime처럼 Edge-Node TCP가 갈라지면 여기에 명시한다.>
|
||||
|
||||
## 런타임 프로필
|
||||
|
||||
- local quick check: 현재 checkout에서 가능한 quick check를 우선 실행한다.
|
||||
- remote runner: <SSH, repo root, 어떤 evidence에 쓰는지>
|
||||
- compose <env> stack: <compose file/env file/project/network/주요 포트>
|
||||
- native/direct Edge profile: <필요 시 artifact/openai/metrics/edge-node 포트>
|
||||
- provider pool profile: <필요 시 config path, model alias, Edge-Node TCP>
|
||||
- external provider field: <필요 시 SSH/user/IP/provider endpoint>
|
||||
|
||||
## 프리플라이트
|
||||
|
||||
- plan 작성 시 필수 검증이 현재 checkout을 벗어나 원격 runner, field/bootstrap, 외부 provider, Docker/code-server, emulator/device, 공유 장기 runtime을 사용하면 먼저 테스트 환경 프리플라이트를 계획에 기록한다.
|
||||
- 테스트 환경 프리플라이트에는 runner, repo root/workdir, branch/HEAD/dirty 상태, local 변경과 원격 source 동기화 여부, binary/artifact 경로와 필요한 help/version 출력, config path, runtime identity, port/process 상태, 외부 host, OS/arch 가정을 포함한다.
|
||||
- 프리플라이트에서 dirty/divergent checkout, stale artifact, 잘못된 identity, missing command, closed port, host OS 불일치, source 미동기화가 확인되면 plan은 먼저 setup/sync/rebuild 단계를 만들거나 blocker로 보고한다. remote deploy 환경에서 dirty 변경을 보존하지 않는 정책이면 배포 전 clean sync와 rebuild를 기본 단계로 둔다. profile 값을 이미 참이라고 가정한 검증 명령만 쓰지 않는다.
|
||||
|
||||
## 노드/Provider 인벤토리 위치
|
||||
|
||||
- machine-readable 인벤토리 기준: `agent-test/<env>/inventory.yaml` 또는 `해당 없음`
|
||||
- Edge/OpenAI-compatible 입력 표면 상세 기준: `agent-test/<env>/edge-smoke.md`
|
||||
- Node 접속과 bootstrap 상세 기준: `agent-test/<env>/node-smoke.md`
|
||||
- 공통 provider config 계약 기준: `agent-test/<env>/platform-common-smoke.md`
|
||||
- compose stack 기준: `agent-test/<env>/control-plane-smoke.md`, `agent-test/<env>/client-smoke.md`, `agent-test/<env>/testing-smoke.md`
|
||||
|
||||
## Field/bootstrap 반복 테스트 기준
|
||||
|
||||
- field/bootstrap 검증은 이 환경의 runner, checkout, artifact 기준으로 수행한다. 세부 Edge/Node profile은 해당 env의 `edge-smoke.md`와 `node-smoke.md`를 따른다.
|
||||
- compose stack과 native/provider-pool profile이 서로 다른 Edge-Node TCP를 쓰면 두 프로필을 섞어서 판정하지 않는다.
|
||||
- Node bootstrap은 Edge의 `node register`가 출력한 OS별 완성 명령을 그대로 사용한다. 사용자에게 안내하는 명령에는 임의 placeholder, 수동 token 치환, `IOP_*=` named environment parameter를 넣지 않는다.
|
||||
- token, API key, private credential 원문은 tracked docs, roadmap, 테스트 규칙에 기록하지 않는다. 실행 증거에는 token을 마스킹하거나 명령 생성 사실만 남긴다.
|
||||
- Linux/macOS Node는 생성된 `curl | bash` 계열 명령을 사용한다. Windows Node는 native PowerShell bootstrap을 기본으로 사용한다.
|
||||
- provider capacity, model/provider mapping의 live apply는 해당 Edge binary가 `config refresh`를 제공하는 경우에만 사용한다. refresh 지원이 필요한 환경에서 subcommand나 admin port가 없으면 stale binary로 보고 clean sync/rebuild를 먼저 수행한다.
|
||||
- Edge process restart 또는 일시 단절 후에는 Node reconnect 정책을 검증한다. retry 한계를 넘겨 Node process가 종료된 경우에만 해당 Node host에서 새 bootstrap 실행이 필요하다.
|
||||
|
||||
## 라우팅
|
||||
|
||||
- node / smoke / node 실행 파이프라인 baseline: `agent-test/<env>/node-smoke.md`
|
||||
- edge / smoke / edge 실행 그룹과 입력 표면 baseline: `agent-test/<env>/edge-smoke.md`
|
||||
- control-plane / smoke / control-plane health와 wire baseline: `agent-test/<env>/control-plane-smoke.md`
|
||||
- client / smoke / Flutter client와 IOP console package baseline: `agent-test/<env>/client-smoke.md`
|
||||
- platform-common / smoke / 공통 설정과 protobuf 계약 baseline: `agent-test/<env>/platform-common-smoke.md`
|
||||
- testing / smoke / 테스트 도구와 full-cycle 검증 baseline: `agent-test/<env>/testing-smoke.md`
|
||||
|
||||
## 라우팅 규칙
|
||||
|
||||
- 여러 항목이 맞으면 모두 읽는다.
|
||||
- 도메인 매핑이나 domain rule이 있으면 각 도메인의 `<domain>-smoke` 문서를 기본 baseline으로 둔다.
|
||||
- 도메인이 아직 없을 때만 `project-smoke`를 fallback baseline으로 둔다.
|
||||
- 도메인/검증 시나리오별 문서는 다른 테스트 문서로 라우팅하지 않는다.
|
||||
57
agent-test/_templates/inventory-template.yaml
Normal file
57
agent-test/_templates/inventory-template.yaml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
test_env: <env>
|
||||
profile: <profile-name>
|
||||
last_updated_at: <YYYY-MM-DD>
|
||||
|
||||
source:
|
||||
remote_runner:
|
||||
ssh: <user@host 또는 해당 없음>
|
||||
repo_root: <repo root 또는 해당 없음>
|
||||
clean_sync:
|
||||
- <sync command 또는 해당 없음>
|
||||
dirty_policy: <preserve|discard|manual-review>
|
||||
|
||||
edge:
|
||||
id: <edge-id 또는 해당 없음>
|
||||
config_path: <edge config path 또는 해당 없음>
|
||||
control_plane_http: <url 또는 해당 없음>
|
||||
control_plane_status_url: <url 또는 해당 없음>
|
||||
bootstrap_http_public: <url 또는 해당 없음>
|
||||
openai_base_url_public: <url 또는 해당 없음>
|
||||
openai_base_url_runner: <url 또는 해당 없음>
|
||||
edge_node_tcp_public: <host:port 또는 해당 없음>
|
||||
admin_addr_runner: <host:port 또는 해당 없음>
|
||||
|
||||
build:
|
||||
binaries:
|
||||
edge: <path 또는 해당 없음>
|
||||
node_macos: <path 또는 해당 없음>
|
||||
node_linux_arm64: <path 또는 해당 없음>
|
||||
node_windows_amd64: <path 또는 해당 없음>
|
||||
|
||||
model:
|
||||
alias: <model alias 또는 해당 없음>
|
||||
provider_capacity_total: <number 또는 0>
|
||||
capacity_smoke:
|
||||
endpoints:
|
||||
- /v1/responses
|
||||
- /v1/chat/completions
|
||||
concurrent_requests: capacity_plus_one
|
||||
expected_total_in_flight: <number 또는 0>
|
||||
expected_min_queued: 1
|
||||
prompt_policy: long_reasoning_allowed
|
||||
exact_output_match: false
|
||||
|
||||
nodes:
|
||||
- id: <node-id>
|
||||
alias: <node-alias>
|
||||
role: <role>
|
||||
ssh: <user@host 또는 해당 없음>
|
||||
ssh_origin: <current_host|remote_runner|not_applicable>
|
||||
workspace: <path 또는 해당 없음>
|
||||
provider_pool_candidate: <true|false>
|
||||
provider:
|
||||
id: <provider-id 또는 해당 없음>
|
||||
type: <provider type 또는 해당 없음>
|
||||
endpoint: <url 또는 해당 없음>
|
||||
served_model: <served model 또는 해당 없음>
|
||||
capacity: <number 또는 0>
|
||||
79
agent-test/_templates/test-profile-template.md
Normal file
79
agent-test/_templates/test-profile-template.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
test_env: <env>
|
||||
test_profile: <test-profile>
|
||||
domain: <domain|project-wide>
|
||||
verification_type: <smoke|unit|integration|e2e|model|migration|manual|full-cycle>
|
||||
last_rule_updated_at: <YYYY-MM-DD>
|
||||
---
|
||||
|
||||
# <test-profile> <env> 테스트
|
||||
|
||||
## 읽기 조건
|
||||
|
||||
- <이 도메인/검증 시나리오의 테스트, 검증, 실행 조건 판단이 필요한 경우>
|
||||
|
||||
## 적용 범위
|
||||
|
||||
- <검증 대상 entrypoint, command, API, UX, profile, service>
|
||||
|
||||
## 분류
|
||||
|
||||
- domain: <domain|project-wide>
|
||||
- verification_type: <smoke|unit|integration|e2e|model|migration|manual|full-cycle>
|
||||
- scope: <검증 대상 변경 범위 요약>
|
||||
|
||||
## 환경
|
||||
|
||||
- host:
|
||||
- port:
|
||||
- runtime:
|
||||
- package manager:
|
||||
- docker:
|
||||
- external service:
|
||||
- model endpoint:
|
||||
- credential: secret/token/API key 원문은 문서에 기록하지 않는다.
|
||||
|
||||
## 명령
|
||||
|
||||
- setup:
|
||||
- lint:
|
||||
- unit:
|
||||
- smoke:
|
||||
- e2e:
|
||||
- model:
|
||||
- full-cycle:
|
||||
|
||||
## 필수 검증
|
||||
|
||||
- <작업 완료 전 반드시 실행하거나 판단해야 하는 검증>
|
||||
|
||||
## 보조 검증
|
||||
|
||||
- <실행하면 좋지만 필수 검증을 대체하지 않는 smoke/helper 검증>
|
||||
|
||||
## 판정 기준
|
||||
|
||||
- <통과로 판단할 출력, 상태, UX, artifact, endpoint 조건>
|
||||
|
||||
## 기준 출력 예시
|
||||
|
||||
```text
|
||||
<필요한 경우 기대 출력 예시>
|
||||
```
|
||||
|
||||
## 차단 기준
|
||||
|
||||
- <테스트를 계속할 수 없는 환경/권한/도구/서비스 조건>
|
||||
|
||||
## 보고 항목
|
||||
|
||||
- 실행한 명령:
|
||||
- 성공한 검증:
|
||||
- 실패/차단된 검증:
|
||||
- 생략 사유:
|
||||
- 남은 위험:
|
||||
|
||||
## 금지 사항
|
||||
|
||||
- secret, token, 개인 endpoint 원문은 tracked 파일에 기록하지 않는다.
|
||||
|
||||
|
|
@ -3,7 +3,7 @@ test_env: dev
|
|||
test_profile: edge-smoke
|
||||
domain: edge
|
||||
verification_type: smoke
|
||||
last_rule_updated_at: 2026-06-12
|
||||
last_rule_updated_at: 2026-06-24
|
||||
---
|
||||
|
||||
# edge-smoke dev 테스트
|
||||
|
|
@ -41,6 +41,40 @@ last_rule_updated_at: 2026-06-12
|
|||
- model endpoint: dev OpenAI-compatible base URL 후보 `http://toki-labs.com:18083/v1`
|
||||
- credential: token/secret 원문은 문서에 기록하지 않는다.
|
||||
|
||||
## dev-runtime provider pool 인벤토리
|
||||
|
||||
dev-runtime provider pool과 3-node 연결 상태를 점검할 때는 `agent-test/dev/inventory.yaml`의 machine-readable 값을 우선하고, 원격 runner `ssh toki@toki-labs.com`의 `/Users/toki/agent-work/iop-dev` checkout을 기준으로 한다.
|
||||
|
||||
- Edge config: `build/dev-runtime/edge.yaml`
|
||||
- Edge id: `edge-toki-labs-dev`
|
||||
- Control Plane HTTP: `http://127.0.0.1:18001`
|
||||
- bootstrap HTTP: `http://toki-labs.com:18082`
|
||||
- Edge OpenAI-compatible base URL: `http://toki-labs.com:18083/v1`
|
||||
- Edge-Node TCP transport: `toki-labs.com:18084`
|
||||
- model alias: `qwen3.6:35b`
|
||||
|
||||
노드 후보:
|
||||
|
||||
- mac CLI node: `mac-codex-node` / `mac-codex`
|
||||
- SSH/user: `ssh toki@toki-labs.com`
|
||||
- 목적: `cli` adapter, `codex app-server`
|
||||
- workspace: `/Users/toki/agent-work/iop-workspace/nomadcode`
|
||||
- GX10 vLLM node: `gx10-vllm-node` / `gx10-vllm`
|
||||
- SSH/user: `ssh toki@192.168.0.91`
|
||||
- provider endpoint: `http://192.168.0.91:8001/v1`
|
||||
- served model: `nvidia/Qwen3.6-35B-A3B-NVFP4`
|
||||
- capacity baseline: `4`
|
||||
- workspace: `/home/toki/iop-gx10-vllm`
|
||||
- OneXPlayer Lemonade node: `onexplayer-lemonade-node` / `onexplayer-lemonade`
|
||||
- SSH/user: `ssh r0bin@192.168.0.59`
|
||||
- 접속 기준: 현재 작업 호스트에서 직접 SSH
|
||||
- provider endpoint: `http://192.168.0.59:13305/v1`
|
||||
- served model: `Qwen3.6-35B-A3B-MTP-GGUF`
|
||||
- capacity baseline: `3`
|
||||
- workspace: `C:/Users/r0bin/iop-field`
|
||||
|
||||
OneXPlayer Lemonade Node는 원격 runner나 Edge host에서 다시 SSH하거나 proxy process로 띄우지 않는다. 현재 작업 호스트에서 OneXPlayer Windows host에 `ssh r0bin@192.168.0.59`로 직접 접속한 뒤 generated PowerShell bootstrap을 실행한다.
|
||||
|
||||
## 명령
|
||||
|
||||
- setup:
|
||||
|
|
@ -69,6 +103,9 @@ last_rule_updated_at: 2026-06-12
|
|||
- node 로컬 `[node-message]` payload 라인 목록과 edge `[node-*-message]` payload 라인 목록이 run별로 내용/순서까지 동일해야 한다.
|
||||
- edge complete는 같은 run의 마지막 `[node-*-message]` 이후에만 정상이다.
|
||||
- OpenAI-compatible smoke에서 `/healthz`, `/v1/models`, `/v1/responses`가 기대 상태로 응답한다.
|
||||
- dev-runtime capacity smoke는 `/v1/responses`와 `/v1/chat/completions` 각각에 provider capacity 총합 + 1개 동시 요청을 보내고, Control Plane status의 `provider_snapshots`에서 총 `in_flight`가 capacity 총합에 도달하며 `queued`가 1 이상 잡히는지 확인한다. 현재 `gx10-vllm=4`, `onexplayer-lemonade=3`이면 endpoint별 8개 동시 요청에서 총 `in_flight=7`, `queued>=1` 관측을 기준으로 한다.
|
||||
- capacity smoke 완료 후 대상 provider의 `in_flight=0`, `queued=0` 회복을 확인한다.
|
||||
- Qwen 계열 provider-pool smoke는 thinking/reasoning 텍스트가 포함될 수 있다. 추론 출력 자체를 실패로 보지 말고 HTTP 성공, model alias, final marker 포함 여부, provider node log/run count 증가로 판정한다. 응답 전체가 특정 token과 정확히 같은지 비교하는 strict exact-match는 이 profile의 기본 판정으로 쓰지 않는다.
|
||||
- bootstrap 사용자 명령은 완성된 URL과 positional token 하나만 포함한다.
|
||||
|
||||
## 기준 출력 예시
|
||||
|
|
|
|||
80
agent-test/dev/inventory.yaml
Normal file
80
agent-test/dev/inventory.yaml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
test_env: dev
|
||||
profile: dev-runtime-provider-pool
|
||||
last_updated_at: "2026-06-24"
|
||||
|
||||
source:
|
||||
remote_runner:
|
||||
ssh: toki@toki-labs.com
|
||||
repo_root: /Users/toki/agent-work/iop-dev
|
||||
clean_sync:
|
||||
- git fetch origin main
|
||||
- git reset --hard origin/main
|
||||
- git clean -fd
|
||||
dirty_policy: discard
|
||||
|
||||
edge:
|
||||
id: edge-toki-labs-dev
|
||||
config_path: build/dev-runtime/edge.yaml
|
||||
control_plane_http: http://127.0.0.1:18001
|
||||
control_plane_status_url: http://127.0.0.1:18001/edges/edge-toki-labs-dev/status
|
||||
bootstrap_http_public: http://toki-labs.com:18082
|
||||
openai_base_url_public: http://toki-labs.com:18083/v1
|
||||
openai_base_url_runner: http://127.0.0.1:18083/v1
|
||||
edge_node_tcp_public: toki-labs.com:18084
|
||||
admin_addr_runner: 127.0.0.1:19093
|
||||
|
||||
build:
|
||||
binaries:
|
||||
edge: build/dev-runtime/bin/edge
|
||||
node_macos: build/dev-runtime/bin/iop-node
|
||||
node_linux_arm64: build/dev-runtime/bin/iop-node-linux-arm64
|
||||
node_windows_amd64: build/dev-runtime/bin/iop-node-windows-amd64.exe
|
||||
|
||||
model:
|
||||
alias: qwen3.6:35b
|
||||
provider_capacity_total: 7
|
||||
capacity_smoke:
|
||||
endpoints:
|
||||
- /v1/responses
|
||||
- /v1/chat/completions
|
||||
concurrent_requests: capacity_plus_one
|
||||
expected_total_in_flight: 7
|
||||
expected_min_queued: 1
|
||||
prompt_policy: long_reasoning_allowed
|
||||
exact_output_match: false
|
||||
|
||||
nodes:
|
||||
- id: mac-codex-node
|
||||
alias: mac-codex
|
||||
role: cli
|
||||
ssh: toki@toki-labs.com
|
||||
workspace: /Users/toki/agent-work/iop-workspace/nomadcode
|
||||
provider_pool_candidate: false
|
||||
adapters:
|
||||
- cli
|
||||
- id: gx10-vllm-node
|
||||
alias: gx10-vllm
|
||||
role: vllm-provider
|
||||
ssh: toki@192.168.0.91
|
||||
workspace: /home/toki/iop-gx10-vllm
|
||||
provider_pool_candidate: true
|
||||
provider:
|
||||
id: gx10-vllm
|
||||
type: vllm
|
||||
endpoint: http://192.168.0.91:8001/v1
|
||||
served_model: nvidia/Qwen3.6-35B-A3B-NVFP4
|
||||
capacity: 4
|
||||
- id: onexplayer-lemonade-node
|
||||
alias: onexplayer-lemonade
|
||||
role: lemonade-provider
|
||||
ssh: r0bin@192.168.0.59
|
||||
ssh_origin: current_host
|
||||
workspace: C:/Users/r0bin/iop-field
|
||||
provider_pool_candidate: true
|
||||
provider:
|
||||
id: onexplayer-lemonade
|
||||
type: lemonade
|
||||
endpoint: http://192.168.0.59:13305/v1
|
||||
served_model: Qwen3.6-35B-A3B-MTP-GGUF
|
||||
capacity: 3
|
||||
windows_process_start: Win32_Process.Create
|
||||
|
|
@ -3,7 +3,7 @@ test_env: dev
|
|||
test_profile: node-smoke
|
||||
domain: node
|
||||
verification_type: smoke
|
||||
last_rule_updated_at: 2026-06-12
|
||||
last_rule_updated_at: 2026-06-24
|
||||
---
|
||||
|
||||
# node-smoke dev 테스트
|
||||
|
|
@ -40,6 +40,30 @@ last_rule_updated_at: 2026-06-12
|
|||
- model endpoint: dev OpenAI-compatible base URL 후보 `http://toki-labs.com:18083/v1`
|
||||
- credential: token/secret 원문은 문서에 기록하지 않는다.
|
||||
|
||||
## dev-runtime Node 접속 기준
|
||||
|
||||
dev-runtime의 실제 3-node 연결을 점검할 때는 원격 runner `ssh toki@toki-labs.com`의 `/Users/toki/agent-work/iop-dev` checkout과 `build/dev-runtime/edge.yaml`을 기준으로 한다. Node는 dev-runtime provider pool 기준에서 Edge-Node TCP `toki-labs.com:18084`로 붙는다.
|
||||
|
||||
- mac CLI node: `mac-codex-node` / `mac-codex`
|
||||
- SSH/user: `ssh toki@toki-labs.com`
|
||||
- 목적: `cli` adapter, `codex app-server`
|
||||
- workspace: `/Users/toki/agent-work/iop-workspace/nomadcode`
|
||||
- GX10 vLLM node: `gx10-vllm-node` / `gx10-vllm`
|
||||
- SSH/user: `ssh toki@192.168.0.91`
|
||||
- provider endpoint: `http://192.168.0.91:8001/v1`
|
||||
- served model: `nvidia/Qwen3.6-35B-A3B-NVFP4`
|
||||
- workspace: `/home/toki/iop-gx10-vllm`
|
||||
- OneXPlayer Lemonade node: `onexplayer-lemonade-node` / `onexplayer-lemonade`
|
||||
- SSH/user: `ssh r0bin@192.168.0.59`
|
||||
- 접속 기준: 현재 작업 호스트에서 직접 SSH
|
||||
- provider endpoint: `http://192.168.0.59:13305/v1`
|
||||
- served model: `Qwen3.6-35B-A3B-MTP-GGUF`
|
||||
- workspace: `C:/Users/r0bin/iop-field`
|
||||
|
||||
GX10은 Linux/ARM64 bootstrap, OneXPlayer는 Windows native PowerShell bootstrap을 기본으로 한다. OneXPlayer는 현재 작업 호스트에서 직접 접속해 세팅하며, 원격 runner나 Edge host에서 `node-onexplayer-lemonade.yaml`로 proxy 실행하지 않는다.
|
||||
|
||||
OneXPlayer에서 SSH 세션 안의 `Start-Process`로 `iop-node.exe`를 띄우면 SSH 세션 종료와 함께 process가 정리될 수 있다. dev 반복 배포에서는 `Win32_Process.Create` 또는 동등한 세션 독립 실행 방식으로 `C:/Users/r0bin/iop-field`에서 `iop-node.exe --config node.yaml serve`를 시작하고, WMI/process query와 `iop-node.log`의 `connected to edge` 로그로 유지 여부를 확인한다.
|
||||
|
||||
## 명령
|
||||
|
||||
- setup:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
test_env: dev
|
||||
last_rule_updated_at: 2026-06-12
|
||||
last_rule_updated_at: 2026-06-24
|
||||
---
|
||||
|
||||
# dev 테스트 규칙
|
||||
|
|
@ -13,6 +13,7 @@ last_rule_updated_at: 2026-06-12
|
|||
- dev 테스트/검증은 이 파일을 기준으로 판단한다.
|
||||
- 작업 완료 검증은 변경 범위 기준으로 선택한다.
|
||||
- 필수 검증을 실행하지 못하면 차단 사유로 보고한다.
|
||||
- 새 테스트 환경을 추가하거나 환경 구조를 바꿀 때는 `agent-test/README.md`와 `agent-test/_templates/`의 확장 기준을 따른다.
|
||||
- 최종 보고에는 실행 명령, 결과, 생략 사유, 남은 위험을 남긴다.
|
||||
- 환경값, secret, 개인 endpoint는 tracked docs/roadmap에 쓰지 않는다.
|
||||
- token/secret 원문은 원격 환경에서 주입하고, shell stdout/stderr와 최종 보고에 출력하지 않는다.
|
||||
|
|
@ -23,7 +24,7 @@ last_rule_updated_at: 2026-06-12
|
|||
|
||||
- host: dev runtime evidence는 원격 runner `ssh toki@toki-labs.com`의 `/Users/toki/agent-work/iop-dev` 기준으로 수행한다.
|
||||
- repo root: 명령은 원격 checkout `/Users/toki/agent-work/iop-dev` 기준으로 실행한다.
|
||||
- sync 기준: 원격 runner를 사용하는 경우 local uncommitted 변경은 원격 repo에 자동 반영되지 않는다. 동기화되지 않았으면 현재 변경분 검증으로 보지 않는다.
|
||||
- sync 기준: dev 배포 전 원격 runner checkout은 `git fetch origin main`, `git reset --hard origin/main`, `git clean -fd`로 clean 상태를 만든 뒤 빌드한다. dev runner의 dirty 변경은 보존 대상으로 보지 않는다.
|
||||
- env file: dev stack은 `docker compose --env-file .env.dev.example ...`로 명시한다.
|
||||
- compose identity: `COMPOSE_PROJECT_NAME=iop-dev-agent`, `IOP_COMPOSE_NETWORK=iop-dev-agent-net`.
|
||||
- port: web/dev preview `13001`, Control Plane HTTP `18001`, Portal/Control Plane wire test endpoint `19001`, CP-Edge wire `19002`, Edge-Node TCP transport `19003`, Postgres host publish `15401`, Redis host publish `16301`.
|
||||
|
|
@ -50,10 +51,47 @@ last_rule_updated_at: 2026-06-12
|
|||
| PostgreSQL host publish | `15400` | `15401` |
|
||||
| Redis host publish | `16300` | `16301` |
|
||||
|
||||
dev-runtime provider pool은 compose Edge-Node TCP `19003`이 아니라 native Edge listen `18084`를 사용한다. 세부 기준은 `agent-test/dev/edge-smoke.md`와 `agent-test/dev/node-smoke.md`를 따른다.
|
||||
|
||||
## 런타임 프로필
|
||||
|
||||
- local quick check: 현재 checkout에서 Go quick check를 우선 실행한다.
|
||||
- remote runner: dev runtime evidence, Flutter client, Docker compose, field/bootstrap, 외부 runtime evidence는 `ssh toki@toki-labs.com`의 `/Users/toki/agent-work/iop-dev` 기준으로 수행한다.
|
||||
- compose dev stack: `.env.dev.example`, `COMPOSE_PROJECT_NAME=iop-dev-agent`, `IOP_COMPOSE_NETWORK=iop-dev-agent-net`, Edge-Node TCP `19003`을 사용한다.
|
||||
- Edge direct dev profile: artifact/bootstrap `18082`, OpenAI-compatible `18083`, metrics `19101`을 필요할 때만 사용한다.
|
||||
- dev-runtime provider pool: `/Users/toki/agent-work/iop-dev/build/dev-runtime/edge.yaml`과 Edge-Node TCP `toki-labs.com:18084`를 사용한다. 3-node/provider 세부는 `agent-test/dev/edge-smoke.md`와 `agent-test/dev/node-smoke.md`를 따른다.
|
||||
- external provider field: GX10 vLLM은 `ssh toki@192.168.0.91`, OneXPlayer Lemonade는 현재 작업 호스트에서 `ssh r0bin@192.168.0.59`로 직접 접속해 확인한다. OneXPlayer 접속은 원격 runner 경유를 필수 조건으로 보지 않는다.
|
||||
|
||||
## 프리플라이트
|
||||
|
||||
- plan 작성 시 필수 검증이 현재 checkout을 벗어나 원격 runner, field/bootstrap, 외부 provider, Docker/code-server, emulator/device, 공유 장기 runtime을 사용하면 먼저 테스트 환경 프리플라이트를 계획에 기록한다.
|
||||
- 테스트 환경 프리플라이트에는 runner, repo root/workdir, branch/HEAD/dirty 상태, local 변경과 원격 source 동기화 여부, binary/artifact 경로와 필요한 help/version 출력, config path, runtime identity, port/process 상태, 외부 host, OS/arch 가정을 포함한다.
|
||||
- 프리플라이트에서 dirty/divergent checkout 또는 stale artifact가 확인되면 dev 배포에서는 먼저 원격 checkout을 clean sync하고 dev-runtime 바이너리를 rebuild한다. 잘못된 identity, missing command, closed port, host OS 불일치, source 미동기화가 확인되면 plan은 setup/sync/rebuild 단계를 만들거나 blocker로 보고한다. profile 값을 이미 참이라고 가정한 검증 명령만 쓰지 않는다.
|
||||
|
||||
## 노드/Provider 인벤토리 위치
|
||||
|
||||
- dev-runtime provider pool machine-readable 기준: `agent-test/dev/inventory.yaml`
|
||||
- dev-runtime provider pool과 Edge/OpenAI-compatible 입력 표면 상세 기준: `agent-test/dev/edge-smoke.md`
|
||||
- dev-runtime Node 접속과 bootstrap 상세 기준: `agent-test/dev/node-smoke.md`
|
||||
- 공통 provider config 계약 기준: `agent-test/dev/platform-common-smoke.md`
|
||||
- compose dev stack 기준: `agent-test/dev/control-plane-smoke.md`, `agent-test/dev/client-smoke.md`, `agent-test/dev/testing-smoke.md`
|
||||
|
||||
## Field/bootstrap 반복 테스트 기준
|
||||
|
||||
- field/bootstrap 검증은 원격 runner의 `/Users/toki/agent-work/iop-dev` checkout과 dev-runtime artifact를 기준으로 수행한다. 세부 Edge/Node profile은 `agent-test/dev/edge-smoke.md`와 `agent-test/dev/node-smoke.md`를 따른다.
|
||||
- compose dev stack은 Edge-Node TCP `19003`을 사용하고, dev-runtime provider pool은 native Edge listen `18084`를 사용한다. 두 프로필을 섞어서 판정하지 않는다.
|
||||
- Node bootstrap은 Edge의 `node register`가 출력한 OS별 완성 명령을 그대로 사용한다. 사용자에게 안내하는 명령에는 임의 placeholder, 수동 token 치환, `IOP_*=` named environment parameter를 넣지 않는다.
|
||||
- token, API key, private credential 원문은 tracked docs, roadmap, 테스트 규칙에 기록하지 않는다. 실행 증거에는 token을 마스킹하거나 명령 생성 사실만 남긴다.
|
||||
- Linux/macOS Node는 생성된 `curl | bash` 계열 명령을 사용한다. Windows Node는 native PowerShell bootstrap을 기본으로 사용한다.
|
||||
- dev-runtime 배포는 clean sync 후 `build/dev-runtime/bin/edge`, mac node, Linux/Windows node binary를 같은 source 기준으로 rebuild한다. 배포 후 `edge config refresh --help`, `19093` port, `config refresh --mode dry-run`을 확인한다.
|
||||
- provider capacity, model/provider mapping은 `config check`와 `config refresh --mode dry-run`을 통과한 뒤 `config refresh --mode apply`로 반영한다. refresh subcommand 또는 `19093` admin port가 없으면 바이너리 rebuild 누락으로 보고 먼저 rebuild한다.
|
||||
- Edge process restart 또는 일시 단절 후에는 Node reconnect 정책을 검증한다. retry 한계를 넘겨 Node process가 종료된 경우에만 해당 Node host에서 새 bootstrap 실행이 필요하다.
|
||||
|
||||
## 라우팅
|
||||
|
||||
- node / smoke / node 실행 파이프라인 baseline: `agent-test/dev/node-smoke.md`
|
||||
- edge / smoke / edge 실행 그룹과 입력 표면 baseline: `agent-test/dev/edge-smoke.md`
|
||||
- dev-runtime provider pool, 3-node 연결, GX10 vLLM, OneXPlayer Lemonade, mac CLI node 점검: `agent-test/dev/edge-smoke.md`, `agent-test/dev/node-smoke.md`
|
||||
- control-plane / smoke / control-plane health와 wire baseline: `agent-test/dev/control-plane-smoke.md`
|
||||
- client / smoke / Flutter client와 IOP console package baseline: `agent-test/dev/client-smoke.md`
|
||||
- platform-common / smoke / 공통 설정과 protobuf 계약 baseline: `agent-test/dev/platform-common-smoke.md`
|
||||
|
|
|
|||
|
|
@ -1077,13 +1077,8 @@ echo '{"id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{}}}'
|
|||
}
|
||||
defer proc.close()
|
||||
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
markerPath := filepath.Join(workspace, "cwd.txt")
|
||||
cwdBytes, err := os.ReadFile(markerPath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read marker file: %v", err)
|
||||
}
|
||||
cwdBytes := readFileEventually(t, markerPath, 2*time.Second)
|
||||
cwd := strings.TrimSpace(string(cwdBytes))
|
||||
|
||||
resolvedWorkspace, err := os.Readlink(workspace)
|
||||
|
|
@ -1095,3 +1090,21 @@ echo '{"id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{}}}'
|
|||
t.Errorf("expected process cwd to be %q or %q, got %q", workspace, resolvedWorkspace, cwd)
|
||||
}
|
||||
}
|
||||
|
||||
func readFileEventually(t *testing.T, path string, timeout time.Duration) []byte {
|
||||
t.Helper()
|
||||
|
||||
deadline := time.Now().Add(timeout)
|
||||
var lastErr error
|
||||
for {
|
||||
b, err := os.ReadFile(path)
|
||||
if err == nil {
|
||||
return b
|
||||
}
|
||||
lastErr = err
|
||||
if time.Now().After(deadline) {
|
||||
t.Fatalf("failed to read file %s within %s: %v", path, timeout, lastErr)
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ import (
|
|||
|
||||
func (c *CLI) executeOneShot(ctx context.Context, spec runtime.ExecutionSpec, profile config.CLIProfileConf, sink runtime.EventSink) error {
|
||||
prompt := extractPrompt(spec.Input)
|
||||
args := append(append([]string{}, profile.Args...), prompt)
|
||||
args := append([]string{}, profile.Args...)
|
||||
if prompt != "" {
|
||||
args = append(args, prompt)
|
||||
}
|
||||
_, err := c.executeCommand(ctx, spec, profile, args, prompt, sink)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,20 @@ curl -fsS http://toki-labs.com:18000/edges/edge-toki-labs/status
|
|||
|
||||
현재 GX10 vLLM과 OneXPlayer Lemonade를 같은 model alias로 묶어 검증하는 dev-runtime 기준은 원격 runner의 동기화된 iop checkout과 `build/dev-runtime/edge.yaml`이다.
|
||||
|
||||
배포 전 원격 runner checkout은 보존 대상이 아니다. 항상 clean sync 후 dev-runtime binary를 다시 빌드한다.
|
||||
|
||||
```bash
|
||||
cd /Users/toki/agent-work/iop-dev
|
||||
git fetch origin main
|
||||
git reset --hard origin/main
|
||||
git clean -fd
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
기준 주소:
|
||||
|
||||
- Control Plane status: 원격 host의 `http://127.0.0.1:18001`
|
||||
|
|
@ -118,9 +132,17 @@ curl -fsS http://toki-labs.com:18000/edges/edge-toki-labs/status
|
|||
- provider candidate: `onexplayer-lemonade` on `onexplayer-lemonade-node`, capacity `3`
|
||||
- connected non-candidate: `mac-codex-node`
|
||||
|
||||
OneXPlayer Lemonade Node는 원격 runner나 Edge host에서 proxy process로 띄우지 않는다. Windows host에 직접 SSH로 접속한 뒤, 그 host 안에서 generated PowerShell bootstrap 명령을 실행한다. 이때 Lemonade provider endpoint는 Windows host 로컬에서 접근 가능한 값을 기준으로 검증한다.
|
||||
OneXPlayer Lemonade Node는 원격 runner나 Edge host에서 다시 SSH하거나 proxy process로 띄우지 않는다. 현재 작업 호스트에서 Windows host에 `ssh r0bin@192.168.0.59`로 직접 접속한 뒤, 그 host 안에서 generated PowerShell bootstrap 명령을 실행한다. 이때 Node 작업 경로는 `$HOME\iop-field`이며, Lemonade provider endpoint는 Windows host 로컬에서 접근 가능한 값을 기준으로 검증한다.
|
||||
|
||||
capacity, provider mapping, model alias 변경은 실행 중 Edge에 `config refresh`로 반영한다. 후보 `edge.yaml` 수정 후 `config check`, dry-run, apply 순서로 진행한다. listen port, Edge identity, bootstrap artifact dir처럼 live apply가 위험한 값은 `restart_required`로 보고되며 Edge process 재시작이 필요하다.
|
||||
SSH 세션 안의 `Start-Process`는 세션 종료와 함께 `iop-node.exe`가 정리될 수 있다. 반복 배포에서는 Windows host에서 `Win32_Process.Create` 방식으로 세션 독립 실행한다.
|
||||
|
||||
```powershell
|
||||
$work = "$HOME\iop-field"
|
||||
$cmd = 'cmd.exe /c "cd /d C:\Users\r0bin\iop-field && iop-node.exe --config node.yaml serve >> iop-node.wmi.stdout.log 2>> iop-node.wmi.stderr.log"'
|
||||
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = $cmd; CurrentDirectory = $work }
|
||||
```
|
||||
|
||||
capacity, provider mapping, model alias 변경은 후보 `edge.yaml` 수정 후 `config check`, refresh dry-run, refresh apply 순서로 반영한다. `config refresh` subcommand나 `19093` admin port가 없으면 dev-runtime binary rebuild 누락으로 보고 clean sync/rebuild부터 다시 수행한다.
|
||||
|
||||
dev-runtime 번들은 바이너리를 `build/dev-runtime/bin/edge`에 둔다. 명령은 그 경로를 `EDGE_BIN`으로 잡고 실행한다.
|
||||
|
||||
|
|
@ -140,12 +162,17 @@ Node host OS 재부팅은 필요하지 않다. Edge process 재시작이나 일
|
|||
3. Edge process를 재시작하고 bootstrap 재실행 없이 3개 Node 연결이 회복되는지 확인한다.
|
||||
4. `http://toki-labs.com:18083/healthz`와 `/v1/models`를 확인한다.
|
||||
5. capacity를 `gx10-vllm=4`, `onexplayer-lemonade=3`로 맞춘 후보 config를 refresh apply하고 Edge process가 유지되는지 확인한다.
|
||||
6. `qwen3.6:35b`로 동시 4개 `/v1/chat/completions` 요청을 보낸다.
|
||||
7. capacity `4/3` 기준이면 동시 in-flight 전제에서 aggregate 배정 기대값은 `gx10-vllm` 2개, `onexplayer-lemonade` 2개다.
|
||||
6. `qwen3.6:35b`로 `/v1/responses`와 `/v1/chat/completions` 각각에 provider capacity 총합 + 1개 동시 요청을 보낸다.
|
||||
7. capacity `gx10-vllm=4`, `onexplayer-lemonade=3` 기준이면 endpoint별 8개 동시 요청에서 Control Plane status의 provider snapshot이 총 `in_flight=7`, `queued>=1`을 한 번 이상 보여야 한다.
|
||||
8. 요청 완료 후 provider snapshot이 `in_flight=0`, `queued=0`으로 회복되는지 확인한다.
|
||||
|
||||
Qwen 계열 모델은 thinking/reasoning 텍스트를 포함해 응답할 수 있다. 이 dev smoke에서는 thinking 출력을 실패로 보지 않고, HTTP 성공, final marker 포함, provider log/run count 증가를 기준으로 판정한다.
|
||||
|
||||
현재 공개 API는 개별 request의 최종 `node_id`를 응답에 노출하지 않는다. 요청별 배정을 확정해야 할 때는 Edge dispatch trace/log를 추가한 뒤 판정한다.
|
||||
|
||||
## 7. Smoke
|
||||
## 7. 기본 Smoke
|
||||
|
||||
아래는 dev-runtime provider pool이 아니라 기본 field/local OpenAI-compatible profile 기준 예시다. dev-runtime provider pool 검증은 위의 `18083`/`qwen3.6:35b` 기준을 따른다.
|
||||
|
||||
```bash
|
||||
curl -fsS http://toki-labs.com:18081/v1/models
|
||||
|
|
|
|||
Loading…
Reference in a new issue