iop/agent-ops/skills/project/dev-runtime-deploy/SKILL.md

21 KiB

name version description
dev-runtime-deploy 1.0.7 dev 배포, dev-runtime 배포, Edge/Node dev 환경 배포 요청에서 dev commit count 기반 git-flow release를 만들고 clean sync, 전체 테스트, rebuild, 원격 배포, OpenAI-compatible capacity smoke, release finish와 tag push를 수행하는 절차

dev-runtime-deploy

목적

dev-runtime provider pool을 dev 기준 git-flow release로 배포한다. dev commit count로 release version을 만들고 release branch에서 전체 테스트, rebuild, Edge/Node 재시작, provider snapshot 기반 capacity 검증을 완료한 뒤에만 release를 finish하고 tag를 원격에 반영한다.

언제 호출할지

  • 사용자가 dev 배포, dev-runtime 배포, 배포해봐처럼 dev 환경 배포를 요청할 때
  • Edge, mac-codex-node(CLI adapter + mac-mlx-vllm provider resource), GX10 vLLM node, OneXPlayer Lemonade node, RTX5090 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/* 문서에서 읽는다.
  • 배포 기준 branch는 항상 dev이며 다른 source_ref로 대체하지 않는다.

Git Flow release 규칙

  • develop branch는 dev, production branch는 main을 사용한다.
  • release version은 clean sync된 origin/dev HEAD에서 git rev-list --count HEAD로 계산한 dev-<commit-count>이다.
  • release branch는 git-flow 기본 prefix를 적용한 release/dev-<commit-count>, tag는 dev-<commit-count>를 사용한다.
  • 별도 버전 파일은 만들지 않는다. release branch와 최종 tag가 배포 버전 기록이다.
  • release branch에서 빌드와 배포를 수행하고 모든 필수 테스트와 live capacity smoke가 성공한 경우에만 git flow release finish를 실행한다.
  • finish는 local production/develop merge와 tag 생성을 수행하고, 검증된 main, dev, tag, release branch 삭제를 atomic push로 원격에 함께 반영한다.
  • 검증 실패 시 finish, tag 생성, main/dev 반영을 수행하지 않고 release branch를 유지한다.
  • 같은 version의 게시된 release branch가 있고 tag가 없으면 새 branch를 만들지 않고 해당 release를 재개한다.

먼저 확인할 것

  • agent-ops/rules/project/domain/testing/rules.md를 읽고 사용자 실행 파이프라인 검증 기준을 확인한다.
  • go build -o /tmp/iop-inventory-query ./scripts/inventory-query로 current checkout query binary를 만든다.
  • /tmp/iop-inventory-query --env dev로 env projection을 먼저 확인한다.
  • 필요한 selector별 bounded 조회는 아래 명령으로 실행한다:
    • node: /tmp/iop-inventory-query --env dev --node <node-id-or-alias>
    • provider: /tmp/iop-inventory-query --env dev --provider <provider-id>
    • model: /tmp/iop-inventory-query --env dev --model <model-alias>
  • 직접 실행 exit 2가 schema/file 오류일 때만 canonical inventory 전체 읽기로 fallback하고, exit 1은 zero-match로 보고한다.
  • dev-runtime provider pool과 compose/local profile을 섞지 않는다. dev-runtime은 native Edge/Node runtime과 dev-runtime config를 기준으로 한다.
  • provider runtime option은 agent-test/inventory-dev.yaml의 model family별 값을 우선한다. 현재 Qwen은 mac-mlx-vllm의 tool_call_parser=qwen, reasoning_parser=qwen3, default_chat_template_kwargs.enable_thinking=true를 사용한다. GX10 Laguna는 tool_call_parser=poolside_v1, reasoning_parser=poolside_v1, default_chat_template_kwargs.enable_thinking=true, Pi preserve_thinking=true와 host /home/toki/iop-gx10-vllm/laguna-s-2.1-thinking.jinja<think>\n generation prefix를 사용한다. Gemma/Qwen/Laguna parser와 chat template profile을 서로 복사하지 않는다.
  • OneXPlayer SSH 접속 정보는 현재 host 기준 ssh r0bin@192.168.0.59이다. toki 사용자명 또는 remote runner를 경유한 OneXPlayer 접속을 사용하지 않는다.
  • RTX5090 SSH는 현재 작업 호스트의 local SSH config alias ssh iop-dev-rtx5090을 사용한다. 이 alias는 public-key batch 인증을 사용하며, host identity와 공개키 지문은 inventory의 rtx5090-lemonade-node.ssh_access에서 확인한다.
  • 현재 구현의 completion 검증 대상은 legacy /v1/completions가 아니라 /v1/chat/completions이다. /v1/completions는 route가 구현되어 있을 때만 별도 검증한다.
  • 원격 runner에 git-flow가 설치되어 있고 gitflow.branch.master=main, gitflow.branch.develop=dev, gitflow.prefix.release=release/인지 확인한다.
  • shallow clone이 아니며 origin/dev, origin/main, tag를 fetch할 수 있는지 확인한다.
  • origin/mainorigin/dev의 ancestor인지 확인한다. 아니면 배포하지 않고 branch 정합화를 먼저 요구한다.
  • 계산된 tag가 이미 local이나 origin에 있으면 삭제·이동·덮어쓰기하지 않고 완료 상태 또는 partial finish 상태를 보고한다.
  • 계산된 release/dev-<count> 이외의 release branch가 있으면 중단한다. AVH git-flow는 다른 release가 진행 중이면 새 release start를 허용하지 않는다.
  • 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. dev clean sync와 release version 확정

    • 원격 runner checkout에서 git fetch origin dev main --tags 후 local devorigin/dev로 clean sync한다.
    • dirty 파일은 보존 대상으로 보지 않는다. 배포 전 clean 상태를 만든다.
    • 기본 cleanup은 git clean -fd이다. git clean -fdx는 config, token, secret, runtime artifact까지 삭제할 수 있으므로 사용하지 않는다.
    • shallow clone이 아닌지, HEADorigin/dev가 같은 commit인지, origin/mainorigin/dev의 ancestor인지 확인한다.
    • local mainorigin/main과 같은 commit으로 맞춘다.
    • sync 후 git status --short --branch, git log --oneline -1, git rev-list --count HEAD를 기록한다.
    • commit count가 <count>이면 release version을 dev-<count>로 확정한다.
    • 이 시점의 origin/devDEV_BASE_SHA, origin/mainMAIN_BASE_SHA로 기록한다.
  3. git-flow release 시작

    • dev-<count> local/remote tag가 없어야 한다.
    • release/dev-<count>가 local과 origin에 모두 없으면 clean dev에서 git flow release start dev-<count>git flow release publish dev-<count>를 실행한다.
    • tag 없이 origin의 release/dev-<count>만 있으면 git flow release track dev-<count>로 checkout하여 기존 release를 재개한다. local branch도 있으면 local/remote가 같은 commit이고 clean한 경우에만 그대로 재개한다.
    • 다른 release branch가 있거나 같은 release의 local/remote가 diverge한 상태에서는 자동 삭제·reset하지 않고 중단한다.
    • release HEAD는 DEV_BASE_SHA와 같거나 그 descendant여야 한다.
    • 빌드·배포할 release HEAD를 DEPLOY_SHA, 그 tree를 DEPLOY_TREE로 기록한다.
  4. 빌드 전 전체 테스트

    • clean source 기준으로 go test ./...를 실행한다.
    • client/Flutter, proto, Makefile, script, config 변경이 배포 범위에 포함되면 해당 도메인 규칙의 전체 테스트도 추가한다.
    • 전체 테스트가 실패하면 build/deploy를 진행하지 않고 실패 패키지와 핵심 오류를 보고한다.
  5. 전체 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, 크기, 실행 가능 여부를 기록한다.
  6. 빌드 후 기본 동작 테스트

    • 빌드된 Edge binary로 config check, config refresh --help, config refresh --mode dry-run을 실행한다.
    • 빌드 후에도 go test ./...를 실행한다. 실행하지 못하면 사유와 남은 위험을 보고한다.
    • dry-run이 rejected 또는 예상 밖 restart_required를 반환하면 배포를 멈추고 config diff를 보고한다.
  7. 배포와 재시작

    • Edge와 mac-codex-node(CLI adapter + mac-mlx-vllm provider vllm-mlx process)는 원격 runner에서 빌드 산출물 기준으로 재시작한다.
    • GX10 node는 Linux ARM64 node binary를 배포하고 기존 node process를 재시작한다.
    • GX10 Laguna vLLM container를 재생성할 때 host template /home/toki/iop-gx10-vllm/laguna-s-2.1-thinking.jinja를 container /run/iop/laguna-s-2.1-thinking.jinja에 read-only bind하고 --chat-template로 지정한다. stock template로 되돌리면 enabled 요청이 첫 생성 토큰으로 </think>를 내보내 Pi thinking이 비는 회귀가 생길 수 있다.
    • 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를 시작한다.
    • RTX5090 node는 현재 host에서 ssh iop-dev-rtx5090으로 접속한다. 2026-07-26 기준 IOP 관련 Windows 부팅 owner는 없고, operator는 C:/Users/r0bin/iop-field/remote-llm-toggle.ps1 또는 이를 한 번 호출하는 RemoteLLM_mode.ahk로 수동 전환한다. IOP dev 배포는 Startup shortcut, Run entry, Task Scheduler, Windows service를 생성하거나 복원하지 않는다. 기본 Toggle은 상태를 반전시키므로 배포 자동화에서 호출하지 말고 -Action Status|Up|Down을 명시한다. Node binary만 즉시 재시작할 때는 Win32_Process.Create 또는 동등한 세션 독립 방식을 사용하고 SSH 세션 내부의 Start-Process에 장기 실행을 의존하지 않는다.
    • RTX5090 Lemonade는 host=0.0.0.0, CUDA backend, Q5 GGUF + Q8 KV, context 262144 기준을 inventory와 대조한다. localhost-only bind는 Node에서 provider endpoint에 접속할 수 없으므로 배포 완료로 보지 않는다.
  8. 배포 후 연결 검증

    • Edge, OpenAI-compatible listener, Node TCP, admin port, Control Plane status port가 열려 있는지 확인한다.
    • Control Plane status에서 Edge가 connected이고 dev-runtime 기준 4개 node가 connected인지 확인한다.
    • 각 node의 provider_snapshots에서 provider id, capacity, in_flight, queued, health, served_models를 확인한다.
    • /v1/models가 대상 model alias를 노출하는지 확인한다.
  9. OpenAI-compatible capacity smoke

    • /v1/responses/v1/chat/completions를 각각 검증한다. legacy /v1/completions는 구현되어 있지 않으면 실패로 보지 않는다.
    • 표준 부하 프롬프트는 짧은 토큰 응답을 요구하지 않는다. 700~1200 token 수준의 구조화된 답변을 유도해 요청이 동시에 관측될 시간을 만든다.
    • endpoint별로 선택한 model group의 총 provider capacity + 1개 요청을 동시에 보낸다. 현재 Laguna laguna-s:2.1은 GX10 capacity 4이므로 5개, Ornith ornith:35b는 OneXPlayer 3 + RTX5090 1이므로 5개, Qwen qwen3.6:35b는 mac-mlx-vllm 2이므로 3개 동시 호출이다.
    • 환경 문서에 더 작은 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과 Laguna reasoning/thinking 텍스트는 정상 응답으로 허용한다. Laguna think smoke는 같은 요청의 Pi high에서 thinking_start/thinking_delta/thinking_end, off에서 thinking event 0개와 최종 text를 대조한다. agentic smoke는 tool-call 전후 reasoning, tool result, 최종 text를 모두 확인한다. exact-output match를 smoke 성공 기준으로 삼지 않는다.
    • Pi/Cline형 agent/tool-call 경계를 검증할 때는 forced tool call, auto tool call, streaming delta.tool_calls, multi-turn tool result 후 최종 답변을 provider direct와 Edge OpenAI-compatible 경로에서 나눠 확인한다. raw native marker나 reasoning text가 assistant content로 새면 해당 model/runtime의 parser/template profile 미확정으로 보고한다.
  10. git-flow release finish와 tag 반영

  • 빌드 전·후 테스트, 배포 후 연결 검증, /v1/responses/v1/chat/completions capacity smoke가 모두 성공했는지 다시 확인한다.
  • 하나라도 실패했거나 필수 검증이 실행되지 않았으면 finish하지 않고 release/dev-<count> branch를 유지한다.
  • 현재 release HEAD가 DEPLOY_SHA와 같은지 확인한다. 달라졌으면 배포 산출물과 source가 달라진 것이므로 finish하지 않는다.
  • finish 직전에 git fetch origin dev main --tags를 다시 실행하고 origin/dev=DEV_BASE_SHA, origin/main=MAIN_BASE_SHA, remote tag 없음이 모두 유지되는지 확인한다. 하나라도 달라졌으면 finish하지 않고 release branch를 유지한다.
  • 모든 검증과 ref 고정이 성공하면 git flow release finish --keepremote -m "Release dev-<count>" dev-<count>로 local finish와 tag 생성을 수행한다.
  • 생성된 local dev-<count> tag의 tree가 DEPLOY_TREE와 같은지 확인한다. 다르면 원격에 push하지 않는다.
  • tag tree가 같으면 git push --atomic origin refs/heads/main:refs/heads/main refs/heads/dev:refs/heads/dev refs/tags/dev-<count>:refs/tags/dev-<count> :refs/heads/release/dev-<count>로 production/develop/tag 반영과 remote release branch 삭제를 한 번에 수행한다.
  • local finish 검증이나 atomic push가 실패하면 DEPLOY_SHA로 detach한 뒤 local main=MAIN_BASE_SHA, dev=DEV_BASE_SHA, release/dev-<count>=DEPLOY_SHA를 복원하고 생성된 local tag를 삭제한 다음 release branch로 돌아간다. remote는 atomic push 전 상태여야 한다.
  • 성공 후 local과 origin의 main, dev 반영 상태, local/remote tag 존재, local/remote release branch 삭제를 확인한다.
  1. 결과 보고
  • source ref, clean sync 결과, 테스트 결과, 빌드 산출물, process/port 상태, connected node 목록, provider capacity snapshot, capacity smoke 관측값을 보고한다.
  • release version, release branch publish, finish, main/dev 반영, local/remote tag 상태를 보고한다.
  • 실패한 단계가 있으면 다음 단계를 진행했는지 여부를 명확히 구분한다.
  • capacity smoke가 타이밍 문제로 관측 실패했으면 요청 성공과 별도로 capacity 관측 미충족으로 보고하고, 프롬프트 길이 또는 status polling 간격 조정을 제안한다.

실행 결과 검증

  • 원격 runner local devorigin/dev로 clean sync되었는가
  • origin/mainorigin/dev의 ancestor이고 local main/dev가 원격 기준과 일치하는가
  • dev HEAD commit count로 dev-<count> version을 계산했는가
  • release/dev-<count> branch를 새로 게시했거나 동일 version의 기존 branch를 안전하게 재개했는가
  • 빌드 전 go test ./...와 필요한 추가 전체 테스트가 통과했는가
  • dev-runtime Edge/mac/Linux ARM64/Windows AMD64 binary가 같은 release branch commit에서 rebuild되었는가
  • 빌드 후 config check, refresh help, refresh dry-run, 전체 테스트가 통과했는가
  • Edge, mac-codex-node, GX10 vLLM node, OneXPlayer Lemonade node, RTX5090 Lemonade node가 재시작되고 4개 node(mac-codex, gx10-vllm, onexplayer-lemonade, rtx5090-lemonade)가 connected 상태인가
  • OneXPlayer 접속과 실행이 r0bin@192.168.0.59 및 세션 독립 실행 방식으로 수행되었는가
  • RTX5090 접속이 ssh iop-dev-rtx5090 public-key batch 인증으로 성공하고, IOP 관련 boot autostart가 없으며, 수동 toggle의 exact Ornith profile·0.0.0.0:13305 listener·Node Edge 연결이 확인되고 Startup/Run/Task/Service 항목을 생성하지 않았는가.
  • /v1/responses capacity smoke에서 총 capacity만큼 in_flight가 차고 초과 요청이 queue에 잡혔는가
  • /v1/chat/completions capacity smoke에서 총 capacity만큼 in_flight가 차고 초과 요청이 queue에 잡혔는가
  • 완료 후 provider in_flight=0, queued=0으로 회복되었는가
  • 모든 필수 검증 성공 후에만 release finish를 실행했는가
  • finish 직전 origin main/dev가 시작 시점 SHA와 같은지 재검증했는가
  • dev-<count> tag tree가 실제 배포한 release tree와 같은가
  • atomic push로 origin main/dev와 tag가 함께 반영되고 remote release branch가 삭제되었는가
  • 검증 실패 시: 실패 단계, 실패한 host/provider/endpoint, 관측된 snapshot, 진행 중단 여부를 보고한다.

출력 형식

dev-runtime 배포 결과
- Release: version=<dev-count>, branch=<release/dev-count>, finish=<done|not-run|partial>, tag=<local/remote status>
- 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>, rtx5090=<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으로 사용하지 않는다.
  • dev 이외의 branch나 임의 source ref를 dev release 기준으로 사용하지 않는다.
  • shallow clone이나 origin/dev와 HEAD가 다른 상태에서 release version을 계산하지 않는다.
  • origin/mainorigin/dev의 ancestor가 아닌 상태에서 release를 시작하지 않는다.
  • 기존 tag를 자동 삭제, 이동, 덮어쓰기하지 않는다.
  • 같은 release의 local/remote branch가 diverge한 상태를 자동 reset하지 않는다.
  • 빌드 전 전체 테스트 실패 후 배포를 계속하지 않는다.
  • 필수 테스트, 배포 후 연결 검증, capacity smoke 중 하나라도 실패하거나 실행되지 않았는데 release를 finish하거나 tag를 생성하지 않는다.
  • tag tree와 실제 배포 tree가 다른 상태에서 원격 tag를 push하지 않는다.
  • main, dev, tag를 개별 push하여 원격에 partial finish 상태를 만들지 않는다.
  • OneXPlayer에 toki 사용자명으로 접속하거나 remote runner에서 다시 OneXPlayer로 SSH 접속하지 않는다.
  • OneXPlayer 장기 실행을 Windows OpenSSH 세션 내부 Start-Process에 의존하지 않는다.
  • RTX5090 Node용 Windows Task Scheduler 항목을 생성하거나 재생성하지 않는다.
  • Qwen reasoning/thinking 출력을 실패로 판정하거나 exact-output smoke를 기본 성공 기준으로 삼지 않는다.
  • Qwen provider를 agent/tool-call 용도로 쓰면서 provider별 --tool-call-parser/--chat-template 검증 없이 배포 완료로 선언하지 않는다.
  • OpenAI-compatible 요청 성공만으로 capacity 검증 성공을 선언하지 않는다. provider snapshot의 in_flight/queued 관측을 함께 남긴다.
  • 이 프로젝트 전용 배포 절차를 agent-ops/rules/common/_templates 또는 common skill에 넣지 않는다.