iop/agent-ops/skills/project/dev-runtime-deploy/SKILL.md
toki 8620512d32 docs(ops): dev 런타임과 운영 계획을 갱신한다
Ornith provider pool의 현재 구성과 동시성 검증 근거를 일치시키고, stream gate 운영 모드와 관련 작업 규칙을 함께 추적하기 위해 반영한다.
2026-08-15 07:38:24 +09:00

29 KiB

name description
dev-runtime-deploy 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로 대체하지 않는다.
  • dev-runtime 배포 범위에서 apps/agent/**와 정확한 package packages/go/agenttask는 제외한다. packages/go/agentprovider/**, packages/go/agentruntime, packages/go/credentiallease는 Edge/mac Node가 사용하므로 제외하지 않는다.

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를 기준으로 한다.
  • 원격 runner의 non-login SSH는 Go/Flutter 경로가 비어 있을 수 있다. 실행 전에 PATH=/opt/homebrew/bin:/Users/toki/SDK/flutter/bin:/Users/toki/go/bin:/Users/toki/.pub-cache/bin:$PATH를 설정하거나 /bin/zsh -lc로 toolchain 경로를 확인한다.
  • 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할 수 있는지 확인한다.
  • For a deployment that first merges a feature source into dev, run git fetch --prune origin dev main <feature> --tags, then git remote prune origin, and require the recorded exact feature SHA to match the fetched remote feature SHA. For a regular dev deployment, run git fetch --prune origin dev main --tags, then git remote prune origin.
  • Use git ls-remote --heads origin 'refs/heads/release/*' as the authoritative remote release-head check. Treat stale local remote-tracking refs removed by prune as cleanup evidence, not as remote release blockers.
  • 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 확정

    • Run git fetch --prune origin dev main --tags in the remote runner checkout, then git remote prune origin, and clean-sync local dev to origin/dev. When the deployment first merges a feature source, fetch the exact feature ref with git fetch --prune origin dev main <feature> --tags before pruning the remote-tracking namespace.
    • Determine active remote releases only from the authoritative output of git ls-remote --heads origin 'refs/heads/release/*'. Record changes to local refs/remotes/origin/release/* before and after prune only as stale-ref cleanup evidence.
    • 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 기준으로 Control Plane, Edge, Node와 공용 runtime package를 테스트한다. apps/agent/**와 정확한 package packages/go/agenttask는 dev-runtime 범위에서 제외한다.

    • zsh의 newline word splitting이나 package-parallel 실행에 의존하지 않는다. 아래 package 목록을 한 package씩 순차 실행한다. agentprovider/catalog의 짧은 process probe는 package 병렬 부하에서 timeout이 날 수 있으므로 병렬 실패만으로 source 실패를 단정하지 않고 순차 실행 결과를 기준으로 한다.

      while IFS= read -r package; do
        go test -count=1 "$package"
      done < <(
        go list ./apps/control-plane/... ./apps/edge/... ./apps/node/... ./packages/go/... ./scripts/... |
          sed '/^iop\/packages\/go\/agenttask$/d'
      )
      
    • 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를 모두 다시 빌드한다.

    • 네 binary 모두 -trimpath로 빌드한다.

      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
      
    • stale binary가 의심되거나 config refresh subcommand, admin port, version 출력이 맞지 않으면 clean sync부터 다시 시작한다.

    • go version -m의 module source commit, SHA-256, 산출물 경로, timestamp, 크기, 실행 가능 여부를 기록하고 네 binary가 DEPLOY_SHA를 가리키는지 확인한다.

  6. 빌드 후 기본 동작 테스트

    • 빌드된 Edge binary로 config check, config refresh --help, config refresh --mode dry-run을 실행한다.
    • openai.enabled=true이면 openai.provider_id가 비어 있지 않아야 한다. 누락 시 runtime의 ignored edge.yaml을 현재 provider identity에 맞게 보완하고 원본을 release별 경로로 백업한 뒤 다시 config check한다. token과 header는 출력하지 않는다.
    • 빌드 후에도 4단계의 동일한 순차 package 테스트를 실행한다. 실행하지 못하면 사유와 남은 위험을 보고한다.
    • dry-run이 rejected 또는 예상 밖 restart_required를 반환하면 배포를 멈추고 config diff를 보고한다.
    • Flutter test/build가 tracked ios/Flutter/*.xcconfig, macos/Flutter/*.xcconfig에 CocoaPods include를 추가하거나 untracked ios/Podfile, macos/Podfile을 만들 수 있다. proto diff와 구분해 확인한 뒤 이번 검증이 만든 정확한 파일만 원복·제거하고 checkout을 clean으로 되돌린다.
  7. 배포와 재시작

    • candidate Edge를 먼저 재시작해 18082, 18083, 18084, 19093 listener를 확인한 뒤 Node를 시작한다. 잘못된 config payload로 Node가 non-retryable internal config error를 받고 종료된 상태에서는 Edge만 고쳐도 Node가 자동 복귀하지 않는다.
    • Edge와 mac-codex-node(CLI adapter + mac-mlx-vllm provider vllm-mlx process)는 원격 runner에서 빌드 산출물 기준으로 재시작한다.
    • GX10 node는 Linux ARM64 node binary를 배포하고 기존 node process를 재시작한다.
    • 처음 교체할 때 원본은 pre-<release>로 보존한다. 같은 release의 후속 candidate를 재배포하면 원본 backup을 덮어쓰지 말고 현재 실패 candidate를 pre-<release>-<short-sha>로 옮긴 뒤 교체한다.
    • 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으로 접속한다. 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. Run the OpenAI-compatible capacity smoke

    • Qualify /v1/responses and /v1/chat/completions separately. Do not fail solely because the unimplemented legacy /v1/completions endpoint is absent.
    • Use a short request that asks for a structured 700-1200-token answer and explicitly bounds provider-native thinking. Compute the emitted JSON Unicode rune count, runes/4 + runes/16 estimate, and context class. Do not reuse long-context or repetition fixtures as a normal-capacity oracle.
    • In managed mode, authenticate GET /v1/credentials/routes with the same principal token used at OpenAI ingress. Require one active exact route alias. An explicit resource_selector must intersect with one exact healthy provider snapshot; default intersects the route profile/upstream model and model group with every matching healthy provider snapshot.
    • Run scripts/e2e-openai-managed-capacity-smoke.sh for one endpoint and route at a time. Require the emitted request to classify as normal. For an explicit selector, send the selected provider's capacity plus one request. For a default pool, send the sum of every eligible matching provider's capacity plus one and require each provider's observed peak to reach its own capacity. If it classifies as long, fail this normal-capacity gate and use the separate long-context admission smoke with long_context_capacity; never add capacity from a provider excluded by the authenticated route.
    • Keep current projected Ornith cases separate: qualify the ornith:35b default pool through GX10 4 + OneXPlayer 3 with RTX excluded, and qualify ornith-fast only through rtx5090-lemonade. Run Chat and Responses independently for each alias. Do not mutate routes, capacities, or timeout values to make the smoke pass.
    • Require HTTP 200 for every request, exactly one endpoint-native success terminal and one [DONE] per stream, selected-provider peak in_flight equal to eligible capacity, queued >= 1, and selected final counters 0/0. Treat a missing route match, changed capacity, wrong context class, missing status sample, or incomplete terminal as a fail-closed release blocker.
    • Every invocation must allocate a distinct mode-0700 directory under ignored agent-test/runs/**. Accept only request/result/status files bound to that invocation's manifest and timestamps. Preserve raw routes, request bodies, response bodies, curl errors, token/header values, route ids, slot ids, prompts, and output only inside that directory; retain only the script's allowlisted sanitized summary as task or tracked evidence.
    • For unprojected provider pools, retain the existing model-group capacity rule. The current unprojected baseline is Qwen qwen3.6:35b on mac-mlx-vllm capacity 2 (three requests). Stopped Laguna is rollback-only and has no active provider capacity.
    • Allow Qwen and Ornith reasoning/thinking text as normal output. For Ornith, compare Pi high thinking events with off zero-thinking events and final text. For agent/tool-call qualification, test forced, automatic, streaming, and multi-turn tool calls separately from capacity qualification.
  10. git-flow release finish와 tag 반영

  • 빌드 전·후 테스트, 배포 후 연결 검증, /v1/responses/v1/chat/completions capacity smoke가 모두 성공했는지 다시 확인한다. Managed route가 있으면 scripts/e2e-openai-managed-capacity-smoke.sh의 네 Ornith route/endpoint case와 current-run provenance gate가 모두 통과해야 한다.
  • 하나라도 실패했거나 필수 검증이 실행되지 않았으면 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를 유지한다.
  • git flow release finish -h에서 --keepremote 지원 여부를 먼저 확인한다. 지원하면 git flow release finish --keepremote -m "Release dev-<count>" dev-<count>를 사용한다. 지원하지 않는 구현에서는 -p/--push를 주지 않은 git flow release finish -m "Release dev-<count>" dev-<count>가 원격 release branch를 건드리지 않는지 help로 확인한 뒤 사용한다. 옵션 파싱 실패는 ref mutation 전 실패인지 확인하고 같은 명령을 추측해 반복하지 않는다.
  • 생성된 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 삭제를 확인한다.
  • 원격 runner도 git fetch --prune origin dev main --tags, clean dev sync, local release branch 삭제 순서로 정리한다. ignored runtime config와 build artifact는 삭제하지 않는다.
  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 간격 조정을 제안한다.

재발 차단 진단

증상 원인 판정 조치
non-login SSH에서 go: command not found runner PATH 미초기화 PATH를 명시하거나 login zsh에서 command -v go/flutter/protoc를 확인한다.
agentprovider/catalog version probe timeout 여러 package 동시 실행에 따른 짧은 probe 경합 가능성 전체 package를 순차 재실행한다. 순차 실패일 때만 source blocker로 판정한다.
Windows cross-build가 Unix file owner 타입에서 실패 OS별 credential key-file 검증 분리 누락 packages/go/credentiallease의 Unix/Windows test와 실제 Windows ACL smoke를 통과시킨 뒤 다시 빌드한다.
Edge 로그의 openai_compat adapter instance key "<provider-id>" conflicts with provider id profile-backed provider와 같은 이름의 정상 backing을 중복 emit하는 mapper 또는 stale Edge provider/adapter 설정이나 agent orchestration을 삭제하지 않는다. go test -race ./apps/edge/internal/node와 candidate Edge source identity를 확인하고 Edge를 rebuild/restart한다.
Node가 internal config error 후 재접속하지 않음 config rejection은 일시 네트워크 단절과 달리 process를 종료할 수 있음 fixed Edge를 먼저 올린 뒤 mac/GX10/OneXPlayer/RTX5090 Node를 각각 다시 시작한다.
Edge service test 종료 후 in_flight가 남음 같은 clock 값에서 run ID가 충돌한 회귀 가능성 go test -race ./apps/edge/internal/service와 run ID 동시성 회귀 테스트를 확인한다.
git flow release finish --keepremote가 option parse 단계에서 실패 설치된 git-flow 구현이 해당 long option을 지원하지 않음 ref 무변경을 확인하고 help에 따라 no-push finish를 사용한 뒤 atomic push에서 release 삭제를 수행한다.

위 오류는 dev-runtime Edge/Node 배포 문제다. 이를 통과시키기 위해 agent-ops/rules/common/**, common orchestration dispatch.py, apps/agent/**를 수정·삭제하지 않는다.

실행 결과 검증

  • 원격 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를 안전하게 재개했는가
  • 빌드 전 dev-runtime 범위의 순차 Go 테스트와 필요한 추가 전체 테스트가 통과했는가
  • 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에 넣지 않는다.