chore(i18n): refresh ko translations

This commit is contained in:
openclaw-docs-i18n[bot] 2026-04-30 18:41:40 +00:00
parent 69aa85de32
commit 4b9fa9cdff
5 changed files with 764 additions and 755 deletions

View File

@ -1,75 +1,75 @@
---
read_when:
- CI 작업이 실행되었거나 실행되지 않은 이유를 이해해야 합니다
- CI 작업이 실행되었거나 실행되지 않은 이유를 파악해야 합니다
- 실패한 GitHub Actions 검사를 디버깅하고 있습니다
- 릴리스 검증 실행 또는 재실행을 조율하고 있습니다
summary: CI 작업 그래프, 범위 게이트, 릴리스 포괄 항목, 동등한 로컬 명령어
- 릴리스 검증 실행 또는 재실행을 조율하는 중입니다
summary: CI 작업 그래프, 범위 게이트, 릴리스 포괄 항목 및 로컬 명령어 대응 항목
title: CI 파이프라인
x-i18n:
generated_at: "2026-04-30T09:34:58Z"
generated_at: "2026-04-30T18:38:44Z"
model: gpt-5.5
provider: openai
source_hash: a9c18f0801864ca1030aac9ea81117b011bd7936388984a1809ce3ae6e906e62
source_hash: a24afc27606ac7f4e9ead89acdd319bffa23336610f8a6cd8b576ea1a5b233dd
source_path: ci.md
workflow: 16
---
OpenClaw CI는 `main`푸시할 때마다, 그리고 모든 풀 리퀘스트에서 실행됩니다. `preflight` 작업은 diff를 분류하고 관련 없는 영역만 변경된 경우 비용이 큰 레인을 끕니다. 수동 `workflow_dispatch` 실행은 의도적으로 스마트 범위 지정을 우회하고 릴리스 후보와 광범위한 검증을 위해 전체 그래프를 전개합니다. Android 레인은 `include_android`를 통해 옵트인 상태로 유지됩니다. 릴리스 전용 Plugin 커버리지는 별도의 [`Plugin 사전 릴리스`](#plugin-prerelease) 워크플로에 있으며, [`전체 릴리스 검증`](#full-release-validation) 또는 명시적인 수동 디스패치에서만 실행됩니다.
OpenClaw CI는 `main`대한 모든 push와 모든 pull request에서 실행됩니다. `preflight` 작업은 diff를 분류하고 관련 없는 영역만 변경된 경우 비용이 큰 lane을 끕니다. 수동 `workflow_dispatch` 실행은 의도적으로 스마트 범위 지정을 우회하고 release candidate와 광범위한 검증을 위해 전체 그래프를 확장합니다. Android lane은 `include_android`를 통해 opt-in 상태로 유지됩니다. release 전용 Plugin 적용 범위는 별도의 [`Plugin Prerelease`](#plugin-prerelease) workflow에 있으며 [`Full Release Validation`](#full-release-validation) 또는 명시적인 수동 dispatch에서만 실행됩니다.
## 파이프라인 개요
## Pipeline 개요
| 작업 | 목적 | 실행 시점 |
| 작업 | 목적 | 실행 시점 |
| -------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------- |
| `preflight` | 문서 전용 변경, 변경된 범위, 변경된 확장을 감지하고 CI 매니페스트를 빌드합니다 | 드래프트가 아닌 푸시와 PR에서 항상 |
| `security-scm-fast` | `zizmor`를 통한 개인 키 감지 및 워크플로 감사 | 드래프트가 아닌 푸시와 PR에서 항상 |
| `security-dependency-audit` | npm 권고에 대한 의존성 없는 프로덕션 lockfile 감사 | 드래프트가 아닌 푸시와 PR에서 항상 |
| `security-fast` | 빠른 보안 작업을 위한 필수 집계 | 드래프트가 아닌 푸시와 PR에서 항상 |
| `check-dependencies` | 프로덕션 Knip 의존성 전용 패스와 미사용 파일 허용 목록 가드 | Node 관련 변경 |
| `build-artifacts` | `dist/`, Control UI, 빌드된 아티팩트 검사, 재사용 가능한 다운스트림 아티팩트 빌드 | Node 관련 변경 |
| `checks-fast-core` | 번들/Plugin 계약/프로토콜 검사와 같은 빠른 Linux 정확성 레인 | Node 관련 변경 |
| `checks-fast-contracts-channels` | 안정적인 집계 검사 결과가 있는 샤딩된 채널 계약 검사 | Node 관련 변경 |
| `checks-node-core-test` | 채널, 번들, 계약, 확장 레인을 제외한 코어 Node 테스트 샤드 | Node 관련 변경 |
| `check` | 샤딩된 기본 로컬 게이트에 해당: 프로덕션 타입, 린트, 가드, 테스트 타입, 엄격한 스모크 | Node 관련 변경 |
| `check-additional` | 아키텍처, 경계, 확장 표면 가드, 패키지 경계, gateway-watch 샤드 | Node 관련 변경 |
| `build-smoke` | 빌드된 CLI 스모크 테스트와 시작 메모리 스모크 | Node 관련 변경 |
| `checks` | 빌드된 아티팩트 채널 테스트 검증기 | Node 관련 변경 |
| `checks-node-compat-node22` | Node 22 호환성 빌드 및 스모크 레인 | 릴리스를 위한 수동 CI 디스패치 |
| `check-docs` | 문서 포매팅, 린트, 깨진 링크 검사 | 문서 변경 |
| `skills-python` | Python 기반 Skills용 Ruff + pytest | Python Skills 관련 변경 |
| `checks-windows` | Windows 전용 프로세스/경로 테스트와 공유 런타임 import 지정자 회귀 검사 | Windows 관련 변경 |
| `macos-node` | 공유 빌드 아티팩트를 사용하는 macOS TypeScript 테스트 레인 | macOS 관련 변경 |
| `macos-swift` | macOS 앱용 Swift 린트, 빌드, 테스트 | macOS 관련 변경 |
| `android` | 두 flavor의 Android 단위 테스트와 디버그 APK 빌드 하나 | Android 관련 변경 |
| `test-performance-agent` | 신뢰된 활동 이후 일일 Codex 느린 테스트 최적화 | main CI 성공 또는 수동 디스패치 |
| `preflight` | docs 전용 변경, 변경된 범위, 변경된 extension을 감지하고 CI manifest를 빌드 | draft가 아닌 push 및 PR에서 항상 |
| `security-scm-fast` | `zizmor`를 통한 private key 감지 및 workflow 감사 | draft가 아닌 push 및 PR에서 항상 |
| `security-dependency-audit` | npm advisory에 대한 dependency 없는 production lockfile 감사 | draft가 아닌 push 및 PR에서 항상 |
| `security-fast` | 빠른 security 작업에 필요한 aggregate | draft가 아닌 push 및 PR에서 항상 |
| `check-dependencies` | production Knip dependency 전용 pass 및 사용하지 않는 파일 allowlist guard | Node 관련 변경 |
| `build-artifacts` | `dist/`, Control UI, 빌드된 artifact 검사 및 재사용 가능한 downstream artifact 빌드 | Node 관련 변경 |
| `checks-fast-core` | bundled/plugin-contract/protocol 검사 같은 빠른 Linux correctness lane | Node 관련 변경 |
| `checks-fast-contracts-channels` | 안정적인 aggregate 검사 결과가 있는 sharded channel contract 검사 | Node 관련 변경 |
| `checks-node-core-test` | channel, bundled, contract, extension lane을 제외한 core Node test shard | Node 관련 변경 |
| `check` | sharded main local gate와 동등: prod type, lint, guard, test type, strict smoke | Node 관련 변경 |
| `check-additional` | architecture, boundary, extension-surface guard, package-boundary, gateway-watch shard | Node 관련 변경 |
| `build-smoke` | 빌드된 CLI smoke test 및 startup-memory smoke | Node 관련 변경 |
| `checks` | 빌드된 artifact channel test용 verifier | Node 관련 변경 |
| `checks-node-compat-node22` | Node 22 compatibility build 및 smoke lane | release를 위한 수동 CI dispatch |
| `check-docs` | docs formatting, lint, broken-link 검사 | docs 변경 |
| `skills-python` | Python 기반 skill용 Ruff + pytest | Python skill 관련 변경 |
| `checks-windows` | Windows 특정 process/path test 및 공유 runtime import specifier regression | Windows 관련 변경 |
| `macos-node` | 공유 빌드 artifact를 사용하는 macOS TypeScript test lane | macOS 관련 변경 |
| `macos-swift` | macOS app용 Swift lint, build, test | macOS 관련 변경 |
| `android` | 두 flavor의 Android unit test 및 debug APK build 하나 | Android 관련 변경 |
| `test-performance-agent` | 신뢰된 활동 이후 일일 Codex slow-test 최적화 | main CI 성공 또는 수동 dispatch |
## 빠른 실패 순서
## Fail-fast 순서
1. `preflight`가 어떤 레인이 존재할지를 결정합니다. `docs-scope``changed-scope` 로직은 이 작업 내부의 단계이며, 독립 실행형 작업이 아닙니다.
2. `security-scm-fast`, `security-dependency-audit`, `security-fast`, `check`, `check-additional`, `check-docs`, `skills-python`은 더 무거운 아티팩트 및 플랫폼 매트릭스 작업을 기다리지 않고 빠르게 실패합니다.
3. `build-artifacts`는 빠른 Linux 레인과 겹쳐 실행되므로 공유 빌드가 준비되는 즉시 다운스트림 소비자가 시작할 수 있습니다.
4. 그다음 더 무거운 플랫폼 및 런타임 레인이 전개됩니다: `checks-fast-core`, `checks-fast-contracts-channels`, `checks-node-core-test`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, `android`.
1. `preflight`는 어떤 lane이 존재할지 결정합니다. `docs-scope``changed-scope` logic은 이 작업 안의 step이지 독립적인 작업이 아닙니다.
2. `security-scm-fast`, `security-dependency-audit`, `security-fast`, `check`, `check-additional`, `check-docs`, `skills-python`은 더 무거운 artifact 및 platform matrix 작업을 기다리지 않고 빠르게 실패합니다.
3. `build-artifacts`는 빠른 Linux lane과 겹쳐 실행되므로 shared build가 준비되는 즉시 downstream consumer가 시작될 수 있습니다.
4. 그 다음 더 무거운 platform 및 runtime lane이 확장됩니다: `checks-fast-core`, `checks-fast-contracts-channels`, `checks-node-core-test`, `checks`, `checks-windows`, `macos-node`, `macos-swift`, `android`.
같은 PR 또는 `main` ref에 새 푸시가 도착하면 GitHub가 대체된 작업을 `cancelled`로 표시할 수 있습니다. 같은 ref의 최신 실행도 실패하지 않는 한 이를 CI 잡음으로 취급하세요. 집계 샤드 검사는 `!cancelled() && always()`를 사용하므로 일반적인 샤드 실패는 계속 보고하지만, 전체 워크플로가 이미 대체된 뒤에는 큐에 들어가지 않습니다. 자동 CI 동시성 키는 버전이 지정되어 있으므로(`CI-v7-*`) 오래된 큐 그룹의 GitHub 측 좀비가 새 main 실행을 무기한 차단할 수 없습니다. 수동 전체 제품군 실행은 `CI-manual-v1-*`를 사용하며 진행 중인 실행을 취소하지 않습니다.
같은 PR 또는 `main` ref에 더 새로운 push가 도착하면 GitHub가 대체된 작업을 `cancelled`로 표시할 수 있습니다. 같은 ref의 최신 실행도 실패하지 않는 한 이를 CI noise로 취급하세요. Aggregate shard 검사는 `!cancelled() && always()`를 사용하므로 일반적인 shard 실패는 계속 보고하지만 전체 workflow가 이미 대체된 뒤에는 queue에 들어가지 않습니다. 자동 CI concurrency key는 versioned(`CI-v7-*`)되어 있어 GitHub 쪽의 오래된 queue group에 남은 zombie가 더 새로운 main 실행을 무기한 차단할 수 없습니다. 수동 full-suite 실행은 `CI-manual-v1-*`를 사용하며 진행 중인 실행을 취소하지 않습니다.
## 범위와 라우팅
## 범위 및 routing
범위 로직`scripts/ci-changed-scope.mjs`에 있으며 `src/scripts/ci-changed-scope.test.ts`단위 테스트로 커버됩니다. 수동 디스패치는 changed-scope 감지를 건너뛰고 preflight 매니페스트가 모든 범위 영역이 변경된 것처럼 동작하게 합니다.
범위 logic`scripts/ci-changed-scope.mjs`에 있으며 `src/scripts/ci-changed-scope.test.ts`unit test로 보호됩니다. 수동 dispatch는 changed-scope 감지를 건너뛰고 preflight manifest가 모든 scoped 영역이 변경된 것처럼 동작하게 만듭니다.
- **CI 워크플로 편집**은 Node CI 그래프와 워크플로 린팅을 검증하지만, 그 자체만으로 Windows, Android, macOS 네이티브 빌드를 강제하지 않습니다. 해당 플랫폼 레인은 플랫폼 소스 변경으로 범위가 유지됩니다.
- **CI 라우팅 전용 편집, 선택된 저비용 코어 테스트 fixture 편집, 좁은 Plugin 계약 헬퍼/테스트 라우팅 편집**은 빠른 Node 전용 매니페스트 경로를 사용합니다: `preflight`, 보안, 단일 `checks-fast-core` 작업. 변경이 빠른 작업이 직접 실행하는 라우팅 또는 헬퍼 표면으로 제한된 경우 이 경로는 빌드 아티팩트, Node 22 호환성, 채널 계약, 전체 코어 샤드, 번들 Plugin 샤드, 추가 가드 매트릭스를 건너뜁니다.
- **Windows Node 검사**는 Windows 전용 프로세스/경로 래퍼, npm/pnpm/UI 실행기 헬퍼, 패키지 매니저 구성, 해당 레인을 실행하는 CI 워크플로 표면으로 범위가 지정됩니다. 관련 없는 소스, Plugin, install-smoke, 테스트 전용 변경은 Linux Node 레인에 남습니다.
- **CI workflow 편집**은 Node CI graph와 workflow linting을 검증하지만, 그 자체만으로 Windows, Android, macOS native build를 강제하지는 않습니다. 해당 platform lane은 platform source 변경에 scoped된 상태로 유지됩니다.
- **CI routing 전용 편집, 선택된 저비용 core-test fixture 편집, 좁은 Plugin contract helper/test-routing 편집**은 빠른 Node 전용 manifest path를 사용합니다: `preflight`, security, 단일 `checks-fast-core` task. 변경이 빠른 task가 직접 실행하는 routing 또는 helper surface로 제한된 경우 해당 path는 build artifact, Node 22 compatibility, channel contract, 전체 core shard, bundled-plugin shard, additional guard matrix를 건너뜁니다.
- **Windows Node 검사**는 Windows 특정 process/path wrapper, npm/pnpm/UI runner helper, package manager config, 그리고 해당 lane을 실행하는 CI workflow surface로 scoped됩니다. 관련 없는 source, Plugin, install-smoke, test 전용 변경은 Linux Node lane에 남습니다.
가장 느린 Node 테스트 패밀리는 각 작업이 실행기를 과도하게 예약하지 않으면서 작게 유지되도록 분할되거나 균형 조정됩니다. 채널 계약은 세 개의 가중 샤드로 실행되고, 작은 코어 단위 레인은 짝지어지며, auto-reply는 네 개의 균형 잡힌 워커로 실행됩니다(reply 하위 트리는 agent-runner, dispatch, commands/state-routing 샤드로 분할됨). agentic Gateway/Plugin 구성은 빌드된 아티팩트를 기다리는 대신 기존 소스 전용 agentic Node 작업에 분산됩니다. 광범위한 브라우저, QA, 미디어, 기타 Plugin 테스트는 공유 Plugin catch-all 대신 전용 Vitest 구성을 사용합니다. include-pattern 샤드는 CI 샤드 이름을 사용해 타이밍 항목을 기록하므로 `.artifacts/vitest-shard-timings.json`이 전체 구성과 필터링된 샤드를 구분할 수 있습니다. `check-additional`은 패키지 경계 compile/canary 작업을 함께 유지하고 런타임 토폴로지 아키텍처를 gateway watch 커버리지와 분리합니다. 경계 가드 샤드는 하나의 작업 안에서 작은 독립 가드들을 동시에 실행합니다. Gateway watch, 채널 테스트, 코어 지원 경계 샤드`dist/``dist-runtime/`가 이미 빌드된 뒤 `build-artifacts` 안에서 동시에 실행됩니다.
가장 느린 Node test family는 각 작업이 runner를 과도하게 예약하지 않으면서 작게 유지되도록 분리되거나 균형 조정됩니다. channel contract는 세 개의 weighted shard로 실행되고, 작은 core unit lane은 pair로 묶이며, auto-reply는 네 개의 balanced worker로 실행됩니다(reply subtree는 agent-runner, dispatch, commands/state-routing shard로 분리). agentic gateway/plugin config는 built artifact를 기다리는 대신 기존 source 전용 agentic Node 작업 전반에 분산됩니다. 광범위한 browser, QA, media 및 miscellaneous Plugin test는 shared Plugin catch-all 대신 전용 Vitest config를 사용합니다. Include-pattern shard는 CI shard 이름을 사용해 timing entry를 기록하므로 `.artifacts/vitest-shard-timings.json`은 전체 config와 filtered shard를 구분할 수 있습니다. `check-additional`은 package-boundary compile/canary 작업을 함께 유지하고 runtime topology architecture를 gateway watch coverage와 분리합니다. boundary guard shard는 작은 독립 guard를 하나의 작업 안에서 동시에 실행합니다. Gateway watch, channel test, core support-boundary shard`dist/``dist-runtime/`가 이미 빌드된 뒤 `build-artifacts` 안에서 동시에 실행됩니다.
Android CI는 `testPlayDebugUnitTest``testThirdPartyDebugUnitTest`를 모두 실행한 다음 Play 디버그 APK를 빌드합니다. 서드파티 flavor에는 별도의 소스 세트나 매니페스트가 없습니다. 이 단위 테스트 레인은 SMS/통화 기록 BuildConfig 플래그로 flavor를 계속 컴파일하면서, Android 관련 푸시마다 중복 디버그 APK 패키징 작업을 피합니다.
Android CI는 `testPlayDebugUnitTest``testThirdPartyDebugUnitTest`를 모두 실행한 뒤 Play debug APK를 빌드합니다. third-party flavor에는 별도 source set이나 manifest가 없습니다. 해당 unit-test lane은 SMS/call-log BuildConfig flag로 flavor를 계속 compile하면서도 Android 관련 push마다 중복 debug APK packaging 작업을 피합니다.
`check-dependencies` 샤드는 `pnpm deadcode:dependencies`(최신 Knip 버전에 고정된 프로덕션 Knip 의존성 전용 패스이며, `dlx` 설치를 위해 pnpm의 최소 릴리스 나이가 비활성화됨)와 `pnpm deadcode:unused-files`를 실행합니다. 후자는 Knip의 프로덕션 미사용 파일 발견 결과를 `scripts/deadcode-unused-files.allowlist.mjs`와 비교합니다. 미사용 파일 가드는 PR이 검토되지 않은 새 미사용 파일을 추가하거나 오래된 허용 목록 항목을 남길 때 실패하면서도, Knip이 정적으로 해석할 수 없는 의도적인 동적 Plugin, 생성물, 빌드, 라이브 테스트, 패키지 브리지 표면은 보존합니다.
`check-dependencies` shard는 `pnpm deadcode:dependencies`(최신 Knip version에 고정되고 `dlx` install에 대해 pnpm의 minimum release age가 비활성화된 production Knip dependency 전용 pass)와 `pnpm deadcode:unused-files`를 실행합니다. 후자는 Knip의 production unused-file finding을 `scripts/deadcode-unused-files.allowlist.mjs`와 비교합니다. unused-file guard는 PR이 새롭게 review되지 않은 unused file을 추가하거나 stale allowlist entry를 남겨두면 실패하며, Knip이 statically resolve할 수 없는 의도적인 dynamic Plugin, generated, build, live-test, package bridge surface는 보존합니다.
## 수동 디스패치
## 수동 dispatch
수동 CI 디스패치는 일반 CI와 같은 작업 그래프를 실행하지만 모든 비 Android 범위 레인을 강제로 켭니다: Linux Node 샤드, 번들 Plugin 샤드, 채널 계약, Node 22 호환성, `check`, `check-additional`, 빌드 스모크, 문서 검사, Python Skills, Windows, macOS, Control UI i18n. 독립 실행형 수동 CI 디스패치는 `include_android=true`일 때만 Android를 실행합니다. 전체 릴리스 엄브렐라는 `include_android=true`를 전달해 Android를 활성화합니다. Plugin 사전 릴리스 정적 검사, 릴리스 전용 `agentic-plugins` 샤드, 전체 확장 배치 스윕, Plugin 사전 릴리스 Docker 레인은 CI에서 제외됩니다. Docker 사전 릴리스 제품군은 `Full Release Validation`이 릴리스 검증 게이트를 활성화한 상태로 별도의 `Plugin Prerelease` 워크플로를 디스패치할 때만 실행됩니다.
수동 CI dispatch는 일반 CI와 같은 작업 graph를 실행하지만 모든 non-Android scoped lane을 강제로 켭니다: Linux Node shard, bundled-plugin shard, channel contract, Node 22 compatibility, `check`, `check-additional`, build smoke, docs check, Python Skills, Windows, macOS, Control UI i18n. 독립 실행형 수동 CI dispatch는 `include_android=true`일 때만 Android를 실행합니다. full release umbrella는 `include_android=true`를 전달해 Android를 활성화합니다. Plugin prerelease static check, release 전용 `agentic-plugins` shard, 전체 extension batch sweep, Plugin prerelease Docker lane은 CI에서 제외됩니다. Docker prerelease suite는 `Full Release Validation`이 release-validation gate를 활성화한 상태로 별도의 `Plugin Prerelease` workflow를 dispatch할 때만 실행됩니다.
수동 실행은 고유한 동시성 그룹을 사용하므로 릴리스 후보 전체 제품군이 같은 ref의 다른 푸시나 PR 실행에 의해 취소되지 않습니다. 선택적 `target_ref` 입력을 사용하면 신뢰된 호출자가 선택한 디스패치 ref의 워크플로 파일을 사용하면서 브랜치, 태그 또는 전체 커밋 SHA에 대해 해당 그래프를 실행할 수 있습니다.
수동 실행은 고유한 concurrency group을 사용하므로 release-candidate full suite가 같은 ref의 다른 push 또는 PR 실행에 의해 취소되지 않습니다. 선택적 `target_ref` input은 신뢰된 caller가 선택한 dispatch ref의 workflow file을 사용하면서 branch, tag 또는 full commit SHA에 대해 해당 graph를 실행할 수 있게 합니다.
```bash
gh workflow run ci.yml --ref release/YYYY.M.D
@ -77,19 +77,19 @@ gh workflow run ci.yml --ref main -f target_ref=<branch-or-sha> -f include_andro
gh workflow run full-release-validation.yml --ref main -f ref=<branch-or-sha>
```
## 실행기
## Runner
| 러너 | 작업 |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ubuntu-24.04` | `preflight`, 빠른 보안 작업 및 집계(`security-scm-fast`, `security-dependency-audit`, `security-fast`), 빠른 프로토콜/계약/번들 검사, 샤된 채널 계약 검사, lint를 제외한 `check` 샤드, `check-additional` 샤드 및 집계, Node 테스트 집계 검증기, 문서 검사, Python Skills, workflow-sanity, labeler, auto-response; install-smoke 사전 검도 GitHub 호스팅 Ubuntu를 사용하므로 Blacksmith 매트릭스가 더 일찍 대기열에 들어갈 수 있음 |
| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, 더 가벼운 extension 샤드, `checks-fast-core`, `checks-node-compat-node22`, `check-prod-types`, `check-test-types` |
| `ubuntu-24.04` | `preflight`, 빠른 보안 작업 및 집계(`security-scm-fast`, `security-dependency-audit`, `security-fast`), 빠른 프로토콜/계약/번들 검사, 샤된 채널 계약 검사, lint를 제외한 `check` 샤드, `check-additional` 샤드 및 집계, Node 테스트 집계 검증기, 문서 검사, Python Skills, workflow-sanity, labeler, auto-response; install-smoke 사전 검도 GitHub 호스팅 Ubuntu를 사용하므로 Blacksmith 매트릭스를 더 일찍 대기열에 넣을 수 있습니다 |
| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, 더 가벼운 확장 샤드, `checks-fast-core`, `checks-node-compat-node22`, `check-prod-types`, `check-test-types` |
| `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`, build-smoke, Linux Node 테스트 샤드, 번들 Plugin 테스트 샤드, `android` |
| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(CPU에 충분히 민감하여 8 vCPU가 절약한 것보다 더 많은 비용이 들었음); install-smoke Docker 빌드(32-vCPU 대기열 시간 비용이 절약한 것보다 더 많았음) |
| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(CPU에 충분히 민감해서 8 vCPU가 절약한 것보다 더 많은 비용이 들었습니다); install-smoke Docker 빌드(32-vCPU 대기열 시간 비용이 절약한 것보다 더 컸습니다) |
| `blacksmith-16vcpu-windows-2025` | `checks-windows` |
| `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw``macos-node`; 포크는 `macos-latest`폴백 |
| `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw``macos-swift`; 포크는 `macos-latest`폴백 |
| `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw``macos-node`; 포크는 `macos-latest`대체됩니다 |
| `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw``macos-swift`; 포크는 `macos-latest`대체됩니다 |
## 로컬 동등 명령
## 로컬 대응 항목
```bash
pnpm changed:lanes # inspect the local changed-lane classifier for origin/main...HEAD
@ -117,27 +117,27 @@ pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifac
## 전체 릴리스 검증
`Full Release Validation`은 "릴리스 전에 모든 것을 실행"하기 위한 수동 상위 워크플로입니다. 브랜치, 태그 또는 전체 커밋 SHA를 받아 해당 대상으로 수동 `CI` 워크플로를 디스패치하고, 릴리스 전용 Plugin/패키지/정적/Docker 증을 위해 `Plugin Prerelease`를 디스패치하며, 설치 스모크, 패키지 승인, Docker 릴리스 경로 스위트, live/E2E, OpenWebUI, QA Lab 패리티, Matrix, Telegram 레인을 위해 `OpenClaw Release Checks`를 디스패치합니다. 게시된 패키지 명세가 제공되면 게시 후 `NPM Telegram Beta E2E` 워크플로도 실행할 수 있습니다.
`Full Release Validation`은 "릴리스 전에 모든 것을 실행"하기 위한 수동 상위 워크플로입니다. 분기, 태그 또는 전체 커밋 SHA를 받아 해당 대상에 대해 수동 `CI` 워크플로를 디스패치하고, 릴리스 전용 Plugin/패키지/정적/Docker 증을 위해 `Plugin Prerelease`를 디스패치하며, 설치 스모크, 패키지 승인, Docker 릴리스 경로 스위트, 라이브/E2E, OpenWebUI, QA Lab 패리티, Matrix, Telegram 레인을 위해 `OpenClaw Release Checks`를 디스패치합니다. 게시된 패키지 사양이 제공되면 게시 후 `NPM Telegram Beta E2E` 워크플로도 실행할 수 있습니다.
`release_profile`은 릴리스 검사에 전달되는 live/제공자 범위를 제어합니다.
`release_profile`은 릴리스 검사로 전달되는 라이브/프로바이더 범위를 제어합니다.
- `minimum`은 가장 빠른 OpenAI/core 릴리스 핵심 레인을 유지합니다.
- `stable`은 안정 제공자/백엔드 세트를 추가합니다.
- `full`은 광범위한 권고 제공자/미디어 매트릭스를 실행합니다.
- `minimum`은 가장 빠른 OpenAI/코어 릴리스 핵심 레인을 유지합니다.
- `stable`은 안정 프로바이더/백엔드 세트를 추가합니다.
- `full`은 광범위한 권고 프로바이더/미디어 매트릭스를 실행합니다.
상위 워크플로는 디스패치된 하위 실행 ID를 기록하며, 최종 `Verify full validation` 작업은 현재 하위 실행 결론을 다시 확인하고 각 하위 실행의 가장 느린 작업 표를 추가합니다. 하위 워크플로를 다시 실행하여 성공 상태가 되면, 상위 검증기 작업만 다시 실행해 상위 결과와 타이밍 요약을 새로 고치세요.
상위 워크플로는 디스패치된 하위 실행 ID를 기록하며, 마지막 `Verify full validation` 작업은 현재 하위 실행 결론을 다시 확인하고 각 하위 실행의 가장 느린 작업 표를 추가합니다. 하위 워크플로를 다시 실행해 녹색으로 바뀌면, 상위 검증기 작업만 다시 실행하여 상위 결과와 시간 요약을 갱신합니다.
복구를 위해 `Full Release Validation``OpenClaw Release Checks`는 모두 `rerun_group`을 받습니다. 릴리스 후보에는 `all`, 일반 전체 CI 하위 작업만에는 `ci`, 모든 릴리스 하위 작업에는 `release-checks`, 또는 더 좁은 그룹인 상위 워크플로의 `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, `npm-telegram`을 사용하세요. 이렇게 하면 집중 수정 후 실패한 릴리스 박스 재실행 범위를 제한할 수 있습니다.
복구를 위해 `Full Release Validation``OpenClaw Release Checks`는 모두 `rerun_group`을 받습니다. 릴리스 후보에는 `all`, 일반 전체 CI 하위만에는 `ci`, 모든 릴리스 하위에는 `release-checks`, 더 좁은 그룹으로는 상위 워크플로에서 `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, `qa-live` 또는 `npm-telegram`을 사용합니다. 이렇게 하면 집중 수정 후 실패한 릴리스 박스의 재실행 범위가 제한됩니다.
`OpenClaw Release Checks`는 신뢰된 워크플로 ref를 사용해 선택된 ref를 한 번 `release-package-under-test` tarball로 해석한 다음, 해당 아티팩트를 live/E2E 릴리스 경로 Docker 워크플로와 패키지 승인 샤드 모두에 전달합니다. 이렇게 하면 릴리스 박스 전반에서 패키지 바이트가 일관되게 유지되고 동일한 후보를 여러 하위 작업에서 다시 패키징하지 않아도 됩니다.
`OpenClaw Release Checks`는 신뢰할 수 있는 워크플로 ref를 사용해 선택한 ref를 한 번 `release-package-under-test` tarball로 해석한 다음, 해당 아티팩트를 라이브/E2E 릴리스 경로 Docker 워크플로와 패키지 승인 샤드 모두에 전달합니다. 이렇게 하면 릴리스 박스 전반에서 패키지 바이트가 일관되게 유지되고, 동일 후보를 여러 하위 작업에서 다시 패킹하지 않아도 됩니다.
## Live 및 E2E 샤드
## 라이브 및 E2E 샤드
릴리스 live/E2E 하위 작업은 광범위한 네이티브 `pnpm test:live` 커버리지를 유지하지만, 하나의 직렬 작업 대신 `scripts/test-live-shard.mjs`를 통해 이름 있는 샤드로 실행합니다.
릴리스 라이브/E2E 하위 워크플로는 광범위한 네이티브 `pnpm test:live` 커버리지를 유지하지만, 하나의 직렬 작업 대신 `scripts/test-live-shard.mjs`를 통해 이름이 지정된 샤드로 실행합니다.
- `native-live-src-agents`
- `native-live-src-gateway-core`
- 제공자 필터링된 `native-live-src-gateway-profiles` 작업
- 프로바이더로 필터링된 `native-live-src-gateway-profiles` 작업
- `native-live-src-gateway-backends`
- `native-live-test`
- `native-live-extensions-a-k`
@ -145,57 +145,57 @@ pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifac
- `native-live-extensions-openai`
- `native-live-extensions-o-z-other`
- `native-live-extensions-xai`
- 분할 미디어 audio/video 샤드 및 제공자 필터링된 music 샤드
- 분할된 미디어 오디오/비디오 샤드 및 프로바이더로 필터링된 음악 샤드
이렇게 하면 동일한 파일 커버리지를 유지하면서 느린 live 제공자 실패를 더 쉽게 재실행하고 진단할 수 있습니다. 집계 `native-live-extensions-o-z`, `native-live-extensions-media`, `native-live-extensions-media-music` 샤드 이름은 수동 일회성 재실행에 계속 유효합니다.
이렇게 하면 동일한 파일 커버리지를 유지하면서 느린 라이브 프로바이더 실패를 더 쉽게 다시 실행하고 진단할 수 있습니다. 집계 `native-live-extensions-o-z`, `native-live-extensions-media`, `native-live-extensions-media-music` 샤드 이름은 수동 일회성 재실행에 계속 유효합니다.
네이티브 live 미디어 샤드는 `Live Media Runner Image` 워크플로가 빌드한 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`에서 실행됩니다. 해당 이미지는 `ffmpeg``ffprobe`를 미리 설치하며, 미디어 작업은 설정 전에 바이너리만 검증합니다. Docker 기반 live 스위트는 일반 Blacksmith 러너에 유지하세요. 컨테이너 작업은 중첩 Docker 테스트를 실행하기에 적합하지 않습니다.
네이티브 라이브 미디어 샤드는 `Live Media Runner Image` 워크플로가 빌드한 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`에서 실행됩니다. 해당 이미지는 `ffmpeg``ffprobe`를 미리 설치합니다. 미디어 작업은 설정 전에 바이너리만 검증합니다. Docker 기반 라이브 스위트는 일반 Blacksmith 러너에서 유지하세요. 컨테이너 작업은 중첩 Docker 테스트를 시작하기에 적합하지 않습니다.
Docker 기반 live 모델/백엔드 샤드는 선택된 커밋마다 별도의 공유 `ghcr.io/openclaw/openclaw-live-test:<sha>` 이미지를 사용합니다. live 릴리스 워크플로는 해당 이미지를 한 번 빌드하고 푸시한 다음, Docker live 모델, Gateway, CLI 백엔드, ACP bind, Codex harness 샤드가 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 실행됩니다. 이러한 샤드가 전체 소스 Docker 대상을 독립적으로 다시 빌드한다면 릴리스 실행이 잘못 구성된 것이며 중복 이미지 빌드로 벽시계 시간을 낭비하게 됩니다.
Docker 기반 라이브 모델/백엔드 샤드는 선택된 커밋마다 별도의 공유 `ghcr.io/openclaw/openclaw-live-test:<sha>` 이미지를 사용합니다. 라이브 릴리스 워크플로는 해당 이미지를 한 번 빌드하고 푸시한 다음, Docker 라이브 모델, Gateway, CLI 백엔드, ACP 바인드, Codex 하네스 샤드는 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 실행됩니다. 해당 샤드가 전체 소스 Docker 대상을 독립적으로 다시 빌드한다면 릴리스 실행 구성이 잘못된 것이며, 중복 이미지 빌드로 실제 시간을 낭비하게 됩니다.
## 패키지 승인
질문이 "설치 가능한 OpenClaw 패키지가 제품으로 작동하는가?"라면 `Package Acceptance`를 사용하세요. 이는 일반 CI와 다릅니다. 일반 CI는 소스 트리를 검증하는 반면, 패키지 승인은 설치 또는 업데이트 후 사용자가 실행하는 동일한 Docker E2E harness를 통해 단일 tarball을 검증합니다.
"설치 가능한 OpenClaw 패키지가 제품으로서 작동하는가?"가 질문일 때 `Package Acceptance`를 사용합니다. 이는 일반 CI와 다릅니다. 일반 CI는 소스 트리를 검증하는 반면, 패키지 승인은 설치 또는 업데이트 후 사용자가 실행하는 동일한 Docker E2E 하네스를 통해 단일 tarball을 검증합니다.
### 작업
1. `resolve_package``workflow_ref`를 체크아웃하고, 하나의 패키지 후보를 해석하, `.artifacts/docker-e2e-package/openclaw-current.tgz`를 쓰고, `.artifacts/docker-e2e-package/package-candidate.json`을 쓰고, 둘 다 `package-under-test` 아티팩트로 업로드하며, GitHub 단계 요약에 소스, 워크플로 ref, 패키지 ref, 버전, SHA-256, 프로필을 출력합니다.
2. `docker_acceptance``ref=workflow_ref``package_artifact_name=package-under-test``openclaw-live-and-e2e-checks-reusable.yml`을 호출합니다. 재사용 워크플로는 해당 아티팩트를 다운로드하고, tarball 인벤토리를 검증하고, 필요할 때 패키지 다이제스트 Docker 이미지를 준비하며, 워크플로 체크아웃을 패키징하는 대신 해당 패키지를 대상으로 선택된 Docker 레인을 실행합니다. 프로필이 여러 대상 `docker_lanes`를 선택하면 재사용 워크플로는 패키지와 공유 이미지를 한 번 준비한 다음, 해당 레인을 고유한 아티팩트를 가진 병렬 대상 Docker 작업으로 팬아웃합니다.
3. `package_telegram`은 선택적으로 `NPM Telegram Beta E2E`를 호출합니다. `telegram_mode``none`이 아니면 실행되며, Package Acceptance가 하나를 해석한 경우 동일한 `package-under-test` 아티팩트를 설치합니다. 독립 실행형 Telegram 디스패치는 여전히 게시된 npm 명세를 설치할 수 있습니다.
4. `summary`는 패키지 해석, Docker 승인 또는 선택적 Telegram 레인이 실패하면 워크플로를 실패 처리합니다.
1. `resolve_package``workflow_ref`를 체크아웃하고, 하나의 패키지 후보를 해석하, `.artifacts/docker-e2e-package/openclaw-current.tgz`를 쓰고, `.artifacts/docker-e2e-package/package-candidate.json`을 쓰고, 둘 다 `package-under-test` 아티팩트로 업로드한 다음, GitHub 단계 요약에 소스, 워크플로 ref, 패키지 ref, 버전, SHA-256, 프로필을 출력합니다.
2. `docker_acceptance``ref=workflow_ref``package_artifact_name=package-under-test``openclaw-live-and-e2e-checks-reusable.yml`을 호출합니다. 재사용 가능한 워크플로는 해당 아티팩트를 다운로드하고, tarball 인벤토리를 검증하며, 필요할 때 패키지 다이제스트 Docker 이미지를 준비하고, 워크플로 체크아웃을 패킹하는 대신 해당 패키지에 대해 선택된 Docker 레인을 실행합니다. 프로필이 여러 대상 `docker_lanes`를 선택하면, 재사용 가능한 워크플로는 패키지와 공유 이미지를 한 번 준비한 다음 해당 레인을 고유한 아티팩트를 가진 병렬 대상 Docker 작업으로 팬아웃합니다.
3. `package_telegram`은 선택적으로 `NPM Telegram Beta E2E`를 호출합니다. `telegram_mode``none`이 아닐 때 실행되며, Package Acceptance가 패키지를 해석한 경우 동일한 `package-under-test` 아티팩트를 설치합니다. 독립 실행형 Telegram 디스패치는 게시된 npm 사양도 계속 설치할 수 있습니다.
4. `summary`는 패키지 해석, Docker 승인 또는 선택적 Telegram 레인이 실패한 경우 워크플로를 실패 처리합니다.
### 후보 소스
- `source=npm``openclaw@beta`, `openclaw@latest` 또는 `openclaw@2026.4.27-beta.2` 같은 정확한 OpenClaw 릴리스 버전만 허용합니다. 게시된 베타/안정 버전 수락에 이것을 사용하세요.
- `source=ref`는 신뢰할 수 있는 `package_ref` 브랜치, 태그 또는 전체 커밋 SHA를 패킹합니다. 리졸버는 OpenClaw 브랜치/태그를 가져오고, 선택된 커밋이 저장소 브랜치 기록 또는 릴리스 태그에서 도달 가능한지 확인하며, 분리된 워크트리에 의존성을 설치한 뒤 `scripts/package-openclaw-for-docker.mjs`로 패킹합니다.
- `source=url`은 HTTPS `.tgz`를 다운로드하며, `package_sha256`이 필요합니다.
- `source=artifact``artifact_run_id``artifact_name`에서 하나의 `.tgz`를 다운로드합니다. `package_sha256`은 선택 사항이지만 외부에 공유되는 아티팩트에는 제공하는 것이 좋습니다.
- `source=npm``openclaw@beta`, `openclaw@latest` 또는 `openclaw@2026.4.27-beta.2` 같은 정확한 OpenClaw 릴리스 버전만 허용합니다. 게시된 베타/안정 버전 승인에 사용하세요.
- `source=ref`는 신뢰할 수 있는 `package_ref` 브랜치, 태그 또는 전체 커밋 SHA를 패킹합니다. 해석기는 OpenClaw 브랜치/태그를 가져오고, 선택한 커밋이 저장소 브랜치 기록 또는 릴리스 태그에서 도달 가능한지 확인하며, 분리된 작업 트리에 종속성을 설치한 뒤 `scripts/package-openclaw-for-docker.mjs`로 패킹합니다.
- `source=url`은 HTTPS `.tgz`를 다운로드합니다. `package_sha256`은 필수입니다.
- `source=artifact``artifact_run_id``artifact_name`에서 `.tgz` 하나를 다운로드합니다. `package_sha256`은 선택 사항이지만 외부에 공유되는 아티팩트에는 제공하는 것이 좋습니다.
`workflow_ref``package_ref`를 분리해 두세요. `workflow_ref`는 테스트를 실행하는 신뢰할 수 있는 워크플로/하네스 코드입니다. `package_ref``source=ref`일 때 패킹되는 소스 커밋입니다. 이렇게 하면 현재 테스트 하네스가 오래된 워크플로 로직을 실행하지 않고도 오래된 신뢰할 수 있는 소스 커밋을 검증할 수 있습니다.
`workflow_ref``package_ref`를 분리해 두세요. `workflow_ref`는 테스트를 실행하는 신뢰할 수 있는 워크플로/하네스 코드입니다. `package_ref``source=ref`일 때 패킹되는 소스 커밋입니다. 이렇게 하면 현재 테스트 하네스가 오래된 워크플로 로직을 실행하지 않고도 이전의 신뢰할 수 있는 소스 커밋을 검증할 수 있습니다.
### 스위트 프로필
### 제품군 프로필
- `smoke``npm-onboard-channel-agent`, `gateway-network`, `config-reload`
- `package``npm-onboard-channel-agent`, `doctor-switch`, `update-channel-switch`, `bundled-channel-deps-compat`, `plugins-offline`, `plugin-update`
- `package``npm-onboard-channel-agent`, `doctor-switch`, `update-channel-switch`, `upgrade-survivor`, `bundled-channel-deps-compat`, `plugins-offline`, `plugin-update`
- `product``package``mcp-channels`, `cron-mcp-cleanup`, `openai-web-search-minimal`, `openwebui` 추가
- `full` — OpenWebUI를 포함한 전체 Docker 릴리스 경로 청크
- `custom` — 정확한 `docker_lanes`; `suite_profile=custom`일 때 필
- `full` — OpenWebUI가 포함된 전체 Docker 릴리스 경로 청크
- `custom` — 정확한 `docker_lanes`; `suite_profile=custom`일 때 필
`package` 프로필은 오프라인 Plugin 커버리지를 사용하므로 게시된 패키지 검증이 실시간 ClawHub 가용성에 의해 막히지 않습니다. 선택 사항인 Telegram 레인은 `NPM Telegram Beta E2E`에서 `package-under-test` 아티팩트를 재사용하며, 독립 실행형 디스패치를 위해 게시된 npm 사양 경로를 유지합니다.
`package` 프로필은 오프라인 Plugin 커버리지를 사용하므로 게시된 패키지 검증이 실시간 ClawHub 가용성에 좌우되지 않습니다. 선택적 Telegram 레인은 `NPM Telegram Beta E2E`에서 `package-under-test` 아티팩트를 재사용하며, 게시된 npm 사양 경로는 독립 실행형 디스패치를 위해 유지됩니다.
릴리스 검사는 `source=ref`, `package_ref=<release-ref>`, `workflow_ref=<release workflow ref>`, `suite_profile=custom`, `docker_lanes='bundled-channel-deps-compat plugins-offline'`, `telegram_mode=mock-openai`패키지 수락을 호출합니다. 릴리스 경로 Docker 청크는 겹치는 패키지/업데이트/Plugin 레인을 포함합니다. 패키지 수락은 동일하게 확인된 패키지 타볼에 대해 아티팩트 네이티브 번들 채널 호환성, 오프라인 Plugin, Telegram 증명을 유지합니다. 크로스 OS 릴리스 검사는 여전히 OS별 온보딩, 설치 관리자, 플랫폼 동작을 포함합니다. 패키지/업데이트 제품 검증은 패키지 수락부터 시작해야 합니다. Windows 패키지 및 설치 관리자 fresh 레인도 설치된 패키지가 원시 절대 Windows 경로에서 browser-control 재정의를 가져올 수 있는지 확인합니다. OpenAI 크로스 OS agent-turn 스모크는 설정된 경우 기본적으로 `OPENCLAW_CROSS_OS_OPENAI_MODEL` 사용하고, 그렇지 않으면 `openai/gpt-5.4-mini`를 사용하므로 설치 및 Gateway 증명이 빠르고 결정적으로 유지됩니다.
릴리스 검사는 `source=ref`, `package_ref=<release-ref>`, `workflow_ref=<release workflow ref>`, `suite_profile=custom`, `docker_lanes='bundled-channel-deps-compat plugins-offline'`, `telegram_mode=mock-openai`Package Acceptance를 호출합니다. 릴리스 경로 Docker 청크는 겹치는 패키지/업데이트/Plugin 레인을 포함합니다. Package Acceptance는 같은 해석된 패키지 tarball에 대해 아티팩트 네이티브 번들 채널 호환성, 오프라인 Plugin, Telegram 증거를 유지합니다. Cross-OS 릴리스 검사는 여전히 OS별 온보딩, 설치 프로그램, 플랫폼 동작을 포함합니다. 패키지/업데이트 제품 검증은 Package Acceptance로 시작해야 합니다. Windows 패키지 및 설치 프로그램 신규 레인은 설치된 패키지가 원시 절대 Windows 경로에서 브라우저 제어 오버라이드를 가져올 수 있는지도 검증합니다. OpenAI Cross-OS 에이전트 턴 스모크는 설정된 경우 `OPENCLAW_CROSS_OS_OPENAI_MODEL`을 기본값으로 사용하고, 그렇지 않으면 `openai/gpt-5.4-mini`를 사용하므로 설치 및 Gateway 증거가 빠르고 결정적으로 유지됩니다.
### 레거시 호환성 기간
패키지 수락에는 이미 게시된 패키지를 위한 제한된 레거시 호환성 기간이 있습니다. `2026.4.25-beta.*`를 포함해 `2026.4.25`까지의 패키지는 호환성 경로를 사용할 수 있습니다.
Package Acceptance에는 이미 게시된 패키지를 위한 제한된 레거시 호환성 기간이 있습니다. `2026.4.25-beta.*`를 포함해 `2026.4.25`까지의 패키지는 호환성 경로를 사용할 수 있습니다.
- `dist/postinstall-inventory.json`의 알려진 비공개 QA 항목은 타볼에서 생략된 파일을 가리킬 수 있습니다.
- `dist/postinstall-inventory.json`의 알려진 비공개 QA 항목은 tarball에서 생략된 파일을 가리킬 수 있습니다.
- 패키지가 해당 플래그를 노출하지 않는 경우 `doctor-switch``gateway install --wrapper` 지속성 하위 사례를 건너뛸 수 있습니다.
- `update-channel-switch`타볼에서 파생된 가짜 git 픽스처에서 누락된 `pnpm.patchedDependencies`를 정리할 수 있으며, 누락된 지속 `update.channel`로그로 남길 수 있습니다.
- `update-channel-switch`tarball에서 파생된 가짜 git fixture에서 누락된 `pnpm.patchedDependencies`를 정리할 수 있으며, 누락된 지속 `update.channel`기록할 수 있습니다.
- Plugin 스모크는 레거시 설치 기록 위치를 읽거나 누락된 마켓플레이스 설치 기록 지속성을 허용할 수 있습니다.
- `plugin-update`는 설치 기록 및 재설치 없음 동작이 변경되지 않아야 한다는 요구사항은 유지하면서 config 메타데이터 마이그레이션을 허용할 수 있습니다.
- `plugin-update`는 설치 기록과 재설치 없음 동작이 변경되지 않아야 한다는 요구를 유지하면서 구성 메타데이터 마이그레이션을 허용할 수 있습니다.
게시된 `2026.4.26` 패키지는 이미 제공된 로컬 빌드 메타데이터 스탬프 파일에 대해서도 경고할 수 있습니다. 이후 패키지는 최신 계약을 충족해야 합니다. 동일한 조건은 경고하거나 건너뛰는 대신 실패합니다.
게시된 `2026.4.26` 패키지도 이미 배포된 로컬 빌드 메타데이터 스탬프 파일에 대해 경고할 수 있습니다. 이후 패키지는 최신 계약을 충족해야 합니다. 같은 조건은 경고하거나 건너뛰는 대신 실패합니다.
### 예시
@ -238,27 +238,27 @@ gh workflow run package-acceptance.yml \
-f docker_lanes='install-e2e plugin-update'
```
실패한 패키지 수락 실행을 디버그할 때는 `resolve_package` 요약에서 시작해 패키지 소스, 버전, SHA-256을 확인하세요. 그런 다음 `docker_acceptance` 하위 실행과 해당 Docker 아티팩트`.artifacts/docker-tests/**/summary.json`, `failures.json`, 레인 로그, 단계 타이밍, 재실행 명령을 검사하세요. 전체 릴리스 검증을 다시 실행하는 대신 실패한 패키지 프로필 또는 정확한 Docker 레인을 다시 실행하는 것을 선호하세요.
실패한 패키지 승인 실행을 디버그할 때는 `resolve_package` 요약에서 시작해 패키지 소스, 버전, SHA-256을 확인하세요. 그런 다음 `docker_acceptance` 하위 실행과 해당 Docker 아티팩트를 검사하세요. `.artifacts/docker-tests/**/summary.json`, `failures.json`, 레인 로그, 단계별 시간, 재실행 명령을 확인합니다. 전체 릴리스 검증을 다시 실행하는 대신 실패한 패키지 프로필 또는 정확한 Docker 레인을 다시 실행하는 것을 선호하세요.
## 설치 스모크
별도의 `Install Smoke` 워크플로는 자체 `preflight` 작업을 통해 동일한 범위 스크립트를 재사용합니다. 이 워크플로는 스모크 커버리지를 `run_fast_install_smoke``run_full_install_smoke`로 나눕니다.
별도의 `Install Smoke` 워크플로는 자체 `preflight` 작업을 통해 같은 범위 스크립트를 재사용합니다. 스모크 커버리지를 `run_fast_install_smoke``run_full_install_smoke`로 나눕니다.
- **빠른 경로**는 Docker/패키지 표면, 번들 Plugin 패키지/매니페스트 변경, 또는 Docker 스모크 작업이 실행하는 핵심 Plugin/채널/Gateway/Plugin SDK 표면을 건드리는 pull request에 대해 실행됩니다. 소스 전용 번들 Plugin 변경, 테스트 전용 편집, 문서 전용 편집은 Docker 작업자를 예약하지 않습니다. 빠른 경로는 루트 Dockerfile 이미지를 한 번 빌드하고, CLI를 확인하며, agents delete shared-workspace CLI 스모크를 실행하고, 컨테이너 gateway-network e2e를 실행하며, 번들 확장 빌드 인자를 확인하고, 240초 집계 명령 제한 시간 아래에서 제한된 번들 Plugin Docker 프로필을 실행합니다. 각 시나리오의 Docker 실행은 별도로 제한됩니다.
- **전체 경로**는 야간 예약 실행, 수동 디스패치, workflow-call 릴리스 검사, 그리고 설치 관리자/패키지/Docker 표면을 실제로 건드리는 pull request에 대해 QR 패키지 설치 및 설치 관리자 Docker/업데이트 커버리지를 유지합니다. 전체 모드에서 install-smoke는 하나의 대상 SHA GHCR 루트 Dockerfile 스모크 이미지를 준비하거나 재사용한 다음, QR 패키지 설치, 루트 Dockerfile/Gateway 스모크, 설치 관리자/업데이트 스모크, 빠른 번들 Plugin Docker E2E를 별도 작업으로 실행하여 설치 관리자 작업이 루트 이미지 스모크 뒤에서 기다리지 않게 합니다.
- **빠른 경로**는 Docker/패키지 표면, 번들 Plugin 패키지/매니페스트 변경, 또는 Docker 스모크 작업이 실행하는 코어 Plugin/채널/Gateway/Plugin SDK 표면을 건드리는 풀 리퀘스트에서 실행됩니다. 소스 전용 번들 Plugin 변경, 테스트 전용 편집, 문서 전용 편집은 Docker 워커를 예약하지 않습니다. 빠른 경로는 루트 Dockerfile 이미지를 한 번 빌드하고, CLI를 확인하고, 에이전트 삭제 공유 작업 공간 CLI 스모크를 실행하고, 컨테이너 Gateway 네트워크 e2e를 실행하고, 번들 확장 빌드 인수를 검증하며, 240초 집계 명령 제한 시간 내에서 제한된 번들 Plugin Docker 프로필을 실행합니다. 각 시나리오의 Docker 실행은 별도로 제한됩니다.
- **전체 경로**는 야간 예약 실행, 수동 디스패치, workflow-call 릴리스 검사, 그리고 실제로 설치 프로그램/패키지/Docker 표면을 건드리는 풀 리퀘스트를 위해 QR 패키지 설치 및 설치 프로그램 Docker/업데이트 커버리지를 유지합니다. 전체 모드에서 install-smoke는 대상 SHA GHCR 루트 Dockerfile 스모크 이미지 하나를 준비하거나 재사용한 다음, QR 패키지 설치, 루트 Dockerfile/Gateway 스모크, 설치 프로그램/업데이트 스모크, 빠른 번들 Plugin Docker E2E를 별도 작업으로 실행하여 설치 프로그램 작업이 루트 이미지 스모크 뒤에서 대기하지 않도록 합니다.
`main` 푸시(병합 커밋 포함)는 전체 경로를 강제하지 않습니다. 변경 범위 로직이 푸시에서 전체 커버리지를 요청하더라도 워크플로는 빠른 Docker 스모크를 유지하고 전체 설치 스모크는 야간 또는 릴리스 검증에 맡깁니다.
`main` 푸시(머지 커밋 포함)는 전체 경로를 강제하지 않습니다. 변경 범위 로직이 푸시에서 전체 커버리지를 요청하더라도 워크플로는 빠른 Docker 스모크를 유지하고 전체 설치 스모크는 야간 또는 릴리스 검증에 맡깁니다.
느린 Bun 전역 설치 image-provider 스모크는 `run_bun_global_install_smoke`로 별도로 게이트됩니다. 이는 야간 일정과 릴리스 검사 워크플로에서 실행되며, 수동 `Install Smoke` 디스패치는 이를 선택할 수 있지만 pull request와 `main` 푸시에서는 실행되지 않습니다. QR 및 설치 관리자 Docker 테스트는 각각 자체 설치 중심 Dockerfile을 유지합니다.
느린 Bun 전역 설치 이미지 공급자 스모크는 `run_bun_global_install_smoke`로 별도 제어됩니다. 야간 일정과 릴리스 검사 워크플로에서 실행되며, 수동 `Install Smoke` 디스패치는 이를 선택할 수 있지만 풀 리퀘스트와 `main` 푸시는 실행하지 않습니다. QR 및 설치 프로그램 Docker 테스트는 자체 설치 중심 Dockerfile을 유지합니다.
## 로컬 Docker E2E
`pnpm test:docker:all`하나의 공유 라이브 테스트 이미지를 미리 빌드하고, OpenClaw를 npm 타볼로 한 번 패킹하며, 두 개의 공유 `scripts/e2e/Dockerfile` 이미지를 빌드합니다.
`pnpm test:docker:all`공유 라이브 테스트 이미지 하나를 미리 빌드하고, OpenClaw를 npm tarball로 한 번 패킹한 뒤, 두 개의 공유 `scripts/e2e/Dockerfile` 이미지를 빌드합니다.
- 설치 관리자/업데이트/Plugin 의존성 레인을 위한 기본 Node/Git 러너
- 일반 기능 레인을 위해 동일한 타볼`/app`에 설치하는 기능 이미지
- 설치 프로그램/업데이트/Plugin 종속성 레인을 위한 기본 Node/Git 러너
- 일반 기능 레인을 위해 같은 tarball`/app`에 설치하는 기능 이미지
Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, 플래너 로직은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, 러너는 선택된 계획만 실행합니다. 스케줄러는 `OPENCLAW_DOCKER_E2E_BARE_IMAGE``OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`로 레인별 이미지를 선택한 다음, `OPENCLAW_SKIP_DOCKER_BUILD=1`로 레인을 실행합니다.
Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, 플래너 로직은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, 러너는 선택된 계획만 실행합니다. 스케줄러는 레인별로 `OPENCLAW_DOCKER_E2E_BARE_IMAGE``OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`를 사용해 이미지를 선택한 다음, `OPENCLAW_SKIP_DOCKER_BUILD=1`로 레인을 실행합니다.
### 조정 가능 항목
@ -267,82 +267,82 @@ Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, 플래
| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 일반 레인의 메인 풀 슬롯 수입니다. |
| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 공급자 민감 tail 풀 슬롯 수입니다. |
| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 공급자가 제한하지 않도록 하는 동시 라이브 레인 상한입니다. |
| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 동시 npm 설치 레인 상한입니다. |
| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 동시 npm 설치 레인 상한입니다. |
| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 동시 다중 서비스 레인 상한입니다. |
| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | Docker 데몬 생성 폭주를 피하기 위한 레인 시작 간 시차입니다. 시차가 없도록 하려면 `0`으로 설정하세요. |
| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | Docker 데몬 생성 폭주를 피하기 위한 레인 시작 간 지연입니다. 지연을 없애려면 `0`으로 설정하세요. |
| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 레인별 폴백 제한 시간(120분)입니다. 선택된 라이브/tail 레인은 더 엄격한 상한을 사용합니다. |
| `OPENCLAW_DOCKER_ALL_DRY_RUN` | unset | `1`이면 레인을 실행하지 않고 스케줄러 계획을 출력합니다. |
| `OPENCLAW_DOCKER_ALL_LANES` | unset | 쉼표로 구분된 정확한 레인 목록입니다. 정리 스모크를 건너뛰어 에이전트가 실패한 레인 하나를 재현할 수 있게 합니다. |
| `OPENCLAW_DOCKER_ALL_LANES` | unset | 쉼표로 구분된 정확한 레인 목록입니다. 에이전트가 실패한 레인 하나를 재현할 수 있도록 정리 스모크를 건너뜁니다. |
유효 상한보다 무거운 레인도 빈 풀에서는 시작할 수 있으며, 이후 용량을 해제할 때까지 단독으로 실행됩니다. 로컬 집계는 Docker를 사전 점검하고, 오래된 OpenClaw E2E 컨테이너를 제거하며, 활성 레인 상태를 내보내고, longest-first 정렬을 위해 레인 타이밍을 지속하며, 기본적으로 첫 실패 후 새 pooled 레인 스케줄링을 중지합니다.
유효 상한보다 무거운 레인도 빈 풀에서는 시작할 수 있으며, 이후 용량을 해제할 때까지 단독으로 실행됩니다. 로컬 집계는 Docker를 사전 점검하고, 오래된 OpenClaw E2E 컨테이너를 제거하고, 활성 레인 상태를 내보내고, 가장 긴 항목 우선 정렬을 위해 레인 시간을 지속하며, 기본적으로 첫 실패 이후 새 풀 레인의 스케줄링을 중단합니다.
### 재사용 가능한 라이브/E2E 워크플로
재사용 가능한 라이브/E2E 워크플로는 `scripts/test-docker-all.mjs --plan-json`에 필요한 패키지, 이미지 종류, 라이브 이미지, 레인, 자격 증명 커버리지를 묻습니다. 그런 다음 `scripts/docker-e2e.mjs`가 해당 계획을 GitHub 출력 및 요약으로 변환합니다. 이 스크립트`scripts/package-openclaw-for-docker.mjs`를 통해 OpenClaw를 패킹하거나, 현재 실행 패키지 아티팩트를 다운로드하거나, `package_artifact_run_id`에서 패키지 아티팩트를 다운로드합니다. 또한 타볼 인벤토리를 검증하고, 계획에 패키지 설치 레인이 필요한 경우 Blacksmith의 Docker 레이어 캐시를 통해 패키지 digest 태그가 붙은 bare/functional GHCR Docker E2E 이미지를 빌드하고 푸시하며, 재빌드하는 대신 제공된 `docker_e2e_bare_image`/`docker_e2e_functional_image` 입력 또는 기존 패키지 digest 이미지를 재사용합니다. Docker 이미지 pull은 시도당 180초 제한 시간으로 제한되어 재시도되므로 멈춘 레지스트리/캐시 스트림이 CI 중요 경로의 대부분을 소비하는 대신 빠르게 재시도됩니다.
재사용 가능한 라이브/E2E 워크플로는 `scripts/test-docker-all.mjs --plan-json`에 필요한 패키지, 이미지 종류, 라이브 이미지, 레인, 자격 증명 커버리지를 묻습니다. 그런 다음 `scripts/docker-e2e.mjs`가 해당 계획을 GitHub 출력 및 요약으로 변환합니다. 이 워크플로`scripts/package-openclaw-for-docker.mjs`를 통해 OpenClaw를 패킹하거나, 현재 실행 패키지 아티팩트를 다운로드하거나, `package_artifact_run_id`에서 패키지 아티팩트를 다운로드합니다. tarball 인벤토리를 검증합니다. 계획에 패키지 설치 레인이 필요할 때 Blacksmith의 Docker 레이어 캐시를 통해 패키지 다이제스트 태그가 붙은 bare/functional GHCR Docker E2E 이미지를 빌드하고 푸시합니다. 그리고 다시 빌드하는 대신 제공된 `docker_e2e_bare_image`/`docker_e2e_functional_image` 입력 또는 기존 패키지 다이제스트 이미지를 재사용합니다. Docker 이미지 pull은 시도별 180초 제한 시간으로 제한해 재시도하므로, 멈춘 레지스트리/캐시 스트림이 CI 중요 경로 대부분을 소비하지 않고 빠르게 재시도됩니다.
### 릴리스 경로 청크
릴리스 Docker 커버리지는 더 작은 청크 작업을 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 실행하므로 각 청크는 필요한 이미지 종류만 pull하고 동일한 가중치 스케줄러를 통해 여러 레인을 실행합니다.
릴리스 Docker 커버리지는 `OPENCLAW_SKIP_DOCKER_BUILD=1`더 작은 청크 작업을 실행하므로 각 청크는 필요한 이미지 종류만 pull하고 같은 가중 스케줄러를 통해 여러 레인을 실행합니다.
- `OPENCLAW_DOCKER_ALL_PROFILE=release-path`
- `OPENCLAW_DOCKER_ALL_CHUNK=core | package-update-openai | package-update-anthropic | package-update-core | plugins-runtime-plugins | plugins-runtime-services | plugins-runtime-install-a..h | bundled-channels`
현재 릴리스 Docker 청크는 `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services`, `plugins-runtime-install-a`부터 `plugins-runtime-install-h`, `bundled-channels-core`, `bundled-channels-update-a`, `bundled-channels-update-discord`, `bundled-channels-update-b`, `bundled-channels-contracts`입니다. 집계 `bundled-channels` 청크는 수동 일회성 재실행용으로 계속 사용할 수 있으며, `plugins-runtime-core`, `plugins-runtime`, `plugins-integrations` 집계 Plugin/런타임 별칭으로 유지됩니다. `install-e2e` 레인 별칭은 두 제공자 설치 관리자 레인 모두에 대한 집계 수동 재실행 별칭으로 유지됩니다. `bundled-channels` 청크는 직렬 올인원 `bundled-channel-deps` 레인 대신 분할된 `bundled-channel-*``bundled-channel-update-*` 레인을 실행합니다.
현재 릴리스 Docker 청크는 `core`, `package-update-openai`, `package-update-anthropic`, `package-update-core`, `plugins-runtime-plugins`, `plugins-runtime-services`, `plugins-runtime-install-a`부터 `plugins-runtime-install-h`, `bundled-channels-core`, `bundled-channels-update-a`, `bundled-channels-update-discord`, `bundled-channels-update-b`, `bundled-channels-contracts`입니다. 집계 `bundled-channels` 청크는 수동 일회성 재실행 계속 사용할 수 있으며, `plugins-runtime-core`, `plugins-runtime`, `plugins-integrations` 집계 Plugin/런타임 별칭으로 유지됩니다. `install-e2e` 레인 별칭은 두 제공자 설치 관리자 레인 집계 수동 재실행 별칭으로 유지됩니다. `bundled-channels` 청크는 직렬 올인원 `bundled-channel-deps` 레인이 아니라 분할된 `bundled-channel-*``bundled-channel-update-*` 레인을 실행합니다.
OpenWebUI는 전체 릴리스 경로 커버리지가 요청할 때 `plugins-runtime-services`에 포함되며, OpenWebUI 전용 디스패치에 대해서만 독립형 `openwebui` 청크를 유지합니다. 번들 채널 업데이트 레인은 일시적인 npm 네트워크 실패에 대해 한 번 재시도합니다.
OpenWebUI는 전체 릴리스 경로 범위가 요청할 때 `plugins-runtime-services`에 포함되며, OpenWebUI 전용 디스패치에 대해서만 독립형 `openwebui` 청크를 유지합니다. 번들 채널 업데이트 레인은 일시적인 npm 네트워크 실패에 대해 한 번 재시도합니다.
각 청크는 레인 로그, 타이밍, `summary.json`, `failures.json`, 단계 타이밍, 스케줄러 계획 JSON, 느린 레인 표, 레인별 재실행 명령이 포함된 `.artifacts/docker-tests/`를 업로드합니다. 워크플로 `docker_lanes` 입력은 청크 작업 대신 준비된 이미지를 대상으로 선택된 레인을 실행하므로, 실패한 레인 디버깅을 하나의 대상 Docker 작업으로 제한하고 해당 실행에 대한 패키지 아티팩트를 준비, 다운로드 또는 재사용합니다. 선택된 레인이 라이브 Docker 레인인 경우, 대상 작업은 해당 재실행을 위해 라이브 테스트 이미지를 로컬에서 빌드합니다. 생성된 레인별 GitHub 재실행 명령에는 해당 값이 있을 때 `package_artifact_run_id`, `package_artifact_name`, 준비된 이미지 입력이 포함되므로, 실패한 레인이 실패한 실행의 정확한 패키지와 이미지를 재사용할 수 있습니다.
각 청크는 레인 로그, 타이밍, `summary.json`, `failures.json`, 단계 타이밍, 스케줄러 계획 JSON, 느린 레인 표, 레인별 재실행 명령이 포함된 `.artifacts/docker-tests/`를 업로드합니다. 워크플로 `docker_lanes` 입력은 청크 작업 대신 준비된 이미지에 대해 선택된 레인을 실행하므로, 실패한 레인 디버깅을 하나의 대상 Docker 작업으로 한정하고 해당 실행을 위해 패키지 아티팩트를 준비, 다운로드 또는 재사용합니다. 선택된 레인이 라이브 Docker 레인인 경우, 대상 작업은 해당 재실행을 위해 라이브 테스트 이미지를 로컬에서 빌드합니다. 생성된 레인별 GitHub 재실행 명령에는 해당 값이 있을 때 `package_artifact_run_id`, `package_artifact_name`, 준비된 이미지 입력이 포함되므로 실패한 레인이 실패한 실행의 정확한 패키지와 이미지를 재사용할 수 있습니다.
```bash
pnpm test:docker:rerun <run-id> # Docker 아티팩트를 다운로드하고 결합/레인별 대상 재실행 명령을 출력합니다
pnpm test:docker:timings <summary> # 느린 레인 및 단계 중요 경로 요약
pnpm test:docker:rerun <run-id> # download Docker artifacts and print combined/per-lane targeted rerun commands
pnpm test:docker:timings <summary> # slow-lane and phase critical-path summaries
```
예약된 라이브/E2E 워크플로는 전체 릴리스 경로 Docker 제품군을 매일 실행합니다.
## Plugin 사전 릴리스
`Plugin Prerelease`는 더 비용이 큰 제품/패키지 커버리지이므로, `Full Release Validation` 또는 명시적 운영자가 디스패치하는 별도 워크플로입니다. 일반 풀 리퀘스트, `main` 푸시, 독립 실행형 수동 CI 디스패치에서는 해당 제품군을 꺼 둡니다. 이 워크플로는 번들 Plugin 테스트를 여덟 개의 확장 워커에 균형 있게 분산합니다. 해당 확장 샤드 작업은 한 번에 최대 두 개의 Plugin 구성 그룹을 실행하며, 그룹당 하나의 Vitest 워커와 더 큰 Node 힙을 사용하여 가져오기가 많은 Plugin 배치가 추가 CI 작업을 만들지 않게 합니다.
`Plugin Prerelease`는 더 비용이 큰 제품/패키지 범위이므로, `Full Release Validation` 또는 명시적 운영자가 디스패치하는 별도 워크플로입니다. 일반 풀 리퀘스트, `main` 푸시, 독립형 수동 CI 디스패치는 해당 제품군을 꺼 둡니다. 이 워크플로는 번들 Plugin 테스트를 여덟 개 확장 워커에 균형 있게 분산합니다. 이러한 확장 샤드 작업은 가져오기가 많은 Plugin 배치가 추가 CI 작업을 만들지 않도록 더 큰 Node 힙과 그룹당 하나의 Vitest 워커로 한 번에 최대 두 개의 Plugin 구성 그룹을 실행합니다.
## QA Lab
QA Lab에는 기본 스마트 범위 지정 워크플로 외부에 전용 CI 레인이 있습니다.
QA Lab에는 기본 스마트 범위 워크플로 외부에 전용 CI 레인이 있습니다.
- `Parity gate` 워크플로는 일치하는 PR 변경과 수동 디스패치에서 실행됩니다. 이 워크플로는 비공개 QA 런타임을 빌드하고 모의 GPT-5.5 및 Opus 4.6 에이전트 팩을 비교합니다.
- `QA-Lab - All Lanes` 워크플로는 `main`에서 매일 밤 그리고 수동 디스패치에서 실행됩니다. 이 워크플로는 모의 패리티 게이트, 라이브 Matrix 레인, 라이브 Telegram 및 Discord 레인을 병렬 작업으로 펼칩니다. 라이브 작업은 `qa-live-shared` 환경을 사용하고, Telegram/Discord는 Convex 임대를 사용합니다.
- `Parity gate` 워크플로는 일치하는 PR 변경과 수동 디스패치에서 실행됩니다. 이 워크플로는 비공개 QA 런타임을 빌드하고 모의 GPT-5.5 및 Opus 4.6 에이전트 팩을 비교합니다.
- `QA-Lab - All Lanes` 워크플로는 `main`에서 매일 밤 수동 디스패치에서 실행됩니다. 이 워크플로는 모의 패리티 게이트, 라이브 Matrix 레인, 라이브 Telegram 및 Discord 레인을 병렬 작업으로 확장합니다. 라이브 작업은 `qa-live-shared` 환경을 사용하며, Telegram/Discord는 Convex 임대를 사용합니다.
릴리스 검사는 결정적 모의 제공자와 모의 한정 모델(`mock-openai/gpt-5.5` 및 `mock-openai/gpt-5.5-alt`)로 Matrix 및 Telegram 라이브 전송 레인을 실행하여, 채널 계약을 라이브 모델 지연 시간 및 일반 제공자 Plugin 시작에서 격리합니다. 라이브 전송 Gateway는 메모리 검색을 비활성화합니다. QA 패리티가 메모리 동작을 별도로 다루기 때문입니다. 제공자 연결성은 별도의 라이브 모델, 네이티브 제공자, Docker 제공자 제품군에서 다룹니다.
릴리스 검사는 결정적 모의 제공자와 모의 한정 모델(`mock-openai/gpt-5.5` 및 `mock-openai/gpt-5.5-alt`)로 Matrix 및 Telegram 라이브 전송 레인을 실행하여 채널 계약을 라이브 모델 지연 시간과 일반 제공자 Plugin 시작으로부터 격리합니다. 라이브 전송 Gateway는 QA 패리티가 메모리 동작을 별도로 다루므로 메모리 검색을 비활성화합니다. 제공자 연결성은 별도의 라이브 모델, 네이티브 제공자, Docker 제공자 제품군에서 다룹니다.
Matrix는 예약 및 릴리스 게이트에 `--profile fast`를 사용하며, 체크아웃된 CLI가 지원할 때만 `--fail-fast`를 추가합니다. CLI 기본값과 수동 워크플로 입력은 `all`로 유지됩니다. 수동 `matrix_profile=all` 디스패치는 항상 전체 Matrix 커버리지`transport`, `media`, `e2ee-smoke`, `e2ee-deep`, `e2ee-cli` 작업으로 샤딩합니다.
Matrix는 예약 및 릴리스 게이트에 `--profile fast`를 사용하며, 체크아웃된 CLI가 지원할 때만 `--fail-fast`를 추가합니다. CLI 기본값과 수동 워크플로 입력은 `all`로 유지됩니다. 수동 `matrix_profile=all` 디스패치는 항상 전체 Matrix 범위`transport`, `media`, `e2ee-smoke`, `e2ee-deep`, `e2ee-cli` 작업으로 샤딩합니다.
`OpenClaw Release Checks`도 릴리스 승인 전에 릴리스에 중요한 QA Lab 레인을 실행합니다. 해당 QA 패리티 게이트는 후보 및 기준 팩을 병렬 레인 작업으로 실행한 다음, 최종 패리티 비교를 위해 두 아티팩트를 작은 보고서 작업으로 다운로드합니다.
`OpenClaw Release Checks`도 릴리스 승인 전에 릴리스 핵심 QA Lab 레인을 실행합니다. 이 QA 패리티 게이트는 후보 및 기준 팩을 병렬 레인 작업으로 실행한 다음, 최종 패리티 비교를 위해 작은 보고서 작업으로 두 아티팩트를 모두 다운로드합니다.
변경이 실제로 QA 런타임, 모델 팩 패리티 또는 패리티 워크플로가 소유한 표면을 건드리지 않는 한 PR 랜딩 경로를 `Parity gate` 뒤에 두지 마세요. 일반적인 채널, 구성, 문서 또는 단위 테스트 수정의 경우 선택적 신호로 취급하고 범위 지정된 CI/검사 증거를 따르세요.
변경이 실제로 QA 런타임, 모델 팩 패리티 또는 패리티 워크플로가 소유한 표면을 건드리지 않는 한 PR 랜딩 경로를 `Parity gate` 뒤에 두지 마세요. 일반 채널, 구성, 문서 또는 단위 테스트 수정의 경우 이를 선택적 신호로 취급하고 범위 지정된 CI/검사 증거를 따르세요.
## CodeQL
`CodeQL` 워크플로는 전체 저장소 스윕이 아니라, 의도적으로 좁게 잡은 1차 보안 스캐너입니다. 매일 실행, 수동 실행, 드래프트가 아닌 풀 리퀘스트 보호 실행은 Actions 워크플로 코드와 가장 위험도가 높은 JavaScript/TypeScript 표면을 스캔하며, 높은/심각한 `security-severity`로 필터링된 고신뢰도 보안 쿼리를 사용합니다.
`CodeQL` 워크플로는 전체 저장소 스윕이 아니라 의도적으로 좁은 1차 보안 스캐너입니다. 매일, 수동, 비초안 풀 리퀘스트 가드 실행은 Actions 워크플로 코드와 가장 위험도가 높은 JavaScript/TypeScript 표면을 높은/치명적 `security-severity`로 필터링된 높은 신뢰도의 보안 쿼리로 스캔합니다.
풀 리퀘스트 보호는 가볍게 유지됩니다. `.github/actions`, `.github/codeql`, `.github/workflows`, `packages`, `src` 아래 변경에 대해서만 시작하며, 예약된 워크플로와 동일한 고신뢰도 보안 매트릭스를 실행합니다. Android 및 macOS CodeQL은 PR 기본값에서 제외됩니다.
풀 리퀘스트 가드는 가볍게 유지됩니다. `.github/actions`, `.github/codeql`, `.github/workflows`, `packages`, `src` 아래의 변경에 대해서만 시작되며, 예약된 워크플로와 동일한 높은 신뢰도의 보안 매트릭스를 실행합니다. Android 및 macOS CodeQL은 PR 기본값에서 제외됩니다.
### 보안 범주
### 보안 카테고리
| 범주 | 표면 |
| 카테고리 | 표면 |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `/codeql-security-high/core-auth-secrets` | 인증, 비밀, 샌드박스, Cron, Gateway 기준선 |
| `/codeql-security-high/channel-runtime-boundary` | 핵심 채널 구현 계약과 채널 Plugin 런타임, Gateway, Plugin SDK, 비밀, 감사 접점 |
| `/codeql-security-high/network-ssrf-boundary` | 핵심 SSRF, IP 파싱, 네트워크 가드, 웹 가져오기, Plugin SDK SSRF 정책 표면 |
| `/codeql-security-high/mcp-process-tool-boundary` | MCP 서버, 프로세스 실행 헬퍼, 아웃바운드 전달, 에이전트 도구 실행 게이트 |
| `/codeql-security-high/plugin-trust-boundary` | Plugin 설치, 로더, 매니페스트, 레지스트리, 런타임 의존성 스테이징, 소스 로딩, Plugin SDK 패키지 계약 신뢰 표면 |
| `/codeql-security-high/core-auth-secrets` | 인증, 비밀, 샌드박스, cron, gateway 기준선 |
| `/codeql-security-high/channel-runtime-boundary` | 핵심 채널 구현 계약과 채널 Plugin 런타임, gateway, Plugin SDK, 비밀, 감사 접점 |
| `/codeql-security-high/network-ssrf-boundary` | 핵심 SSRF, IP 파싱, 네트워크 가드, 웹 가져오기, Plugin SDK SSRF 정책 표면 |
| `/codeql-security-high/mcp-process-tool-boundary` | MCP 서버, 프로세스 실행 헬퍼, 아웃바운드 전달, 에이전트 도구 실행 게이트 |
| `/codeql-security-high/plugin-trust-boundary` | Plugin 설치, 로더, 매니페스트, 레지스트리, 런타임 의존성 스테이징, 소스 로딩, Plugin SDK 패키지 계약 신뢰 표면 |
### 플랫폼별 보안 샤드
- `CodeQL Android Critical Security` — 예약된 Android 보안 샤드입니다. 워크플로 사니티가 허용하는 가장 작은 Blacksmith Linux 러너에서 CodeQL Android 앱을 수동으로 빌드합니다. `/codeql-critical-security/android` 아래에 업로드합니다.
- `CodeQL macOS Critical Security` — 주간/수동 macOS 보안 샤드입니다. Blacksmith macOS에서 CodeQL macOS 앱을 수동으로 빌드하고, 업로드된 SARIF에서 의존성 빌드 결과를 필터링하며, `/codeql-critical-security/macos` 아래에 업로드합니다. macOS 빌드는 깨끗한 상태에서도 런타임을 지배하므로 일일 기본값 외부에 유지됩니다.
- `CodeQL Android Critical Security` — 예약된 Android 보안 샤드입니다. 워크플로 정상성 검사가 허용하는 가장 작은 Blacksmith Linux 러너에서 CodeQL을 위해 Android 앱을 수동으로 빌드합니다. `/codeql-critical-security/android` 아래에 업로드합니다.
- `CodeQL macOS Critical Security` — 주간/수동 macOS 보안 샤드입니다. Blacksmith macOS에서 CodeQL을 위해 macOS 앱을 수동으로 빌드하고, 업로드된 SARIF에서 의존성 빌드 결과를 필터링하며, `/codeql-critical-security/macos` 아래에 업로드합니다. macOS 빌드가 정상일 때도 런타임을 지배하므로 일일 기본값 외부에 유지됩니다.
### 중요 품질 범주
### 치명적 품질 카테고리
`CodeQL Critical Quality`이에 대응하는 비보안 샤드입니다. 이 샤드는 더 작은 Blacksmith Linux 러너에서 좁지만 가치가 높은 표면을 대상으로 오류 심각도, 비보안 JavaScript/TypeScript 품질 쿼리만 실행합니다. 풀 리퀘스트 보호는 의도적으로 예약 프로필보다 작습니다. 드래프트가 아닌 PR은 에이전트 명령/모델/도구 실행 및 응답 디스패치 코드, 구성 스키마/마이그레이션/IO 코드, 인증/비밀/샌드박스/보안 코드, 핵심 채널 및 번들 채널 Plugin 런타임, Gateway 프로토콜/서버 메서드, 메모리 런타임/SDK 연결 코드, MCP/프로세스/아웃바운드 전달, 제공자 런타임/모델 카탈로그, 세션 진단/전달 큐, Plugin 로더, Plugin SDK/패키지 계약 또는 Plugin SDK 응답 런타임 변경에 대해 일치하는 `agent-runtime-boundary`, `config-boundary`, `core-auth-secrets`, `channel-runtime-boundary`, `gateway-runtime-boundary`, `memory-runtime-boundary`, `mcp-process-runtime-boundary`, `provider-runtime-boundary`, `session-diagnostics-boundary`, `plugin-boundary`, `plugin-sdk-package-contract`, `plugin-sdk-reply-runtime` 샤드만 실행합니다. CodeQL 구성 및 품질 워크플로 변경은 열두 개 PR 품질 샤드를 모두 실행합니다.
`CodeQL Critical Quality`대응되는 비보안 샤드입니다. 더 작은 Blacksmith Linux 러너에서 좁은 고가치 표면에 대해 오류 심각도, 비보안 JavaScript/TypeScript 품질 쿼리만 실행합니다. 이 풀 리퀘스트 가드는 의도적으로 예약된 프로파일보다 작습니다. 비초안 PR은 에이전트 명령/모델/도구 실행 및 응답 디스패치 코드, 구성 스키마/마이그레이션/IO 코드, 인증/비밀/샌드박스/보안 코드, 핵심 채널 및 번들 채널 Plugin 런타임, gateway 프로토콜/서버 메서드, 메모리 런타임/SDK 연결부, MCP/프로세스/아웃바운드 전달, 제공자 런타임/모델 카탈로그, 세션 진단/전달 큐, Plugin 로더, Plugin SDK/패키지 계약 또는 Plugin SDK 응답 런타임 변경에 대해 일치하는 `agent-runtime-boundary`, `config-boundary`, `core-auth-secrets`, `channel-runtime-boundary`, `gateway-runtime-boundary`, `memory-runtime-boundary`, `mcp-process-runtime-boundary`, `provider-runtime-boundary`, `session-diagnostics-boundary`, `plugin-boundary`, `plugin-sdk-package-contract`, `plugin-sdk-reply-runtime` 샤드만 실행합니다. CodeQL 구성 및 품질 워크플로 변경은 열두 개 PR 품질 샤드를 모두 실행합니다.
수동 디스패치는 다음을 허용합니다.
@ -350,40 +350,40 @@ Matrix는 예약 및 릴리스 게이트에 `--profile fast`를 사용하며,
profile=all|agent-runtime-boundary|config-boundary|core-auth-secrets|channel-runtime-boundary|gateway-runtime-boundary|memory-runtime-boundary|mcp-process-runtime-boundary|plugin-boundary|plugin-sdk-package-contract|plugin-sdk-reply-runtime|provider-runtime-boundary|session-diagnostics-boundary
```
좁은 프로필은 하나의 품질 샤드를 독립적으로 실행하기 위한 교육/반복 훅입니다.
좁은 프로파일은 하나의 품질 샤드를 격리하여 실행하기 위한 학습/반복 훅입니다.
| 범주 | 영역 |
| 범주 | 표면 |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/codeql-critical-quality/core-auth-secrets` | 인증, 시크릿, 샌드박스, Cron, Gateway 보안 경계 코드 |
| `/codeql-critical-quality/config-boundary` | Config 스키마, 마이그레이션, 정규화, I/O 계약 |
| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 프로토콜 스키마와 서버 메서드 계약 |
| `/codeql-critical-quality/channel-runtime-boundary` | 코어 채널 및 번들 채널 Plugin 구현 계약 |
| `/codeql-critical-quality/agent-runtime-boundary` | 명령 실행, 모델/프로바이더 디스패치, 자동 응답 디스패치와 큐, ACP 제어 평면 런타임 계약 |
| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 서버와 도구 브리지, 프로세스 감독 헬퍼, 아웃바운드 전달 계약 |
| `/codeql-critical-quality/memory-runtime-boundary` | 메모리 호스트 SDK, 메모리 런타임 파사드, 메모리 Plugin SDK 별칭, 메모리 런타임 활성화 연결부, 메모리 doctor 명령 |
| `/codeql-critical-quality/session-diagnostics-boundary` | 응답 큐 내부 구현, 세션 전달 큐, 아웃바운드 세션 바인딩/전달 헬퍼, 진단 이벤트/로그 번들 영역, 세션 doctor CLI 계약 |
| `/codeql-critical-quality/plugin-sdk-reply-runtime` | Plugin SDK 인바운드 응답 디스패치, 응답 페이로드/청/런타임 헬퍼, 채널 응답 옵션, 전달 큐, 세션/스레드 바인딩 헬퍼 |
| `/codeql-critical-quality/provider-runtime-boundary` | 모델 카탈로그 정규화, 프로바이더 인증과 탐색, 프로바이더 런타임 등록, 프로바이더 기본값/카탈로그, 웹/검색/fetch/임베딩 레지스트리 |
| `/codeql-critical-quality/ui-control-plane` | 제어 UI 부트스트랩, 로컬 속성, Gateway 제어 흐름, 작업 제어 평면 런타임 계약 |
| `/codeql-critical-quality/web-media-runtime-boundary` | 코어 웹 fetch/검색, 미디어 I/O, 미디어 이해, 이미지 생성, 미디어 생성 런타임 계약 |
| `/codeql-critical-quality/plugin-boundary` | 로더, 레지스트리, 공개 영역, Plugin SDK 진입점 계약 |
| `/codeql-critical-quality/plugin-sdk-package-contract` | 게시된 패키지 측 Plugin SDK 소스와 Plugin 패키지 계약 헬퍼 |
| `/codeql-critical-quality/core-auth-secrets` | 인증, 시크릿, 샌드박스, Cron, Gateway 보안 경계 코드 |
| `/codeql-critical-quality/config-boundary` | 구성 스키마, 마이그레이션, 정규화, IO 계약 |
| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 프로토콜 스키마와 서버 메서드 계약 |
| `/codeql-critical-quality/channel-runtime-boundary` | 핵심 채널과 번들 채널 Plugin 구현 계약 |
| `/codeql-critical-quality/agent-runtime-boundary` | 명령 실행, 모델/공급자 디스패치, 자동 응답 디스패치와 큐, ACP 제어 평면 런타임 계약 |
| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 서버와 도구 브리지, 프로세스 감독 헬퍼, 아웃바운드 전달 계약 |
| `/codeql-critical-quality/memory-runtime-boundary` | 메모리 호스트 SDK, 메모리 런타임 퍼사드, 메모리 Plugin SDK 별칭, 메모리 런타임 활성화 글루, 메모리 doctor 명령 |
| `/codeql-critical-quality/session-diagnostics-boundary` | 응답 큐 내부, 세션 전달 큐, 아웃바운드 세션 바인딩/전달 헬퍼, 진단 이벤트/로그 번들 표면, 세션 doctor CLI 계약 |
| `/codeql-critical-quality/plugin-sdk-reply-runtime` | Plugin SDK 인바운드 응답 디스패치, 응답 페이로드/청크 처리/런타임 헬퍼, 채널 응답 옵션, 전달 큐, 세션/스레드 바인딩 헬퍼 |
| `/codeql-critical-quality/provider-runtime-boundary` | 모델 카탈로그 정규화, 공급자 인증과 검색, 공급자 런타임 등록, 공급자 기본값/카탈로그, 웹/검색/가져오기/임베딩 레지스트리 |
| `/codeql-critical-quality/ui-control-plane` | 제어 UI 부트스트랩, 로컬 속성, Gateway 제어 흐름, 작업 제어 평면 런타임 계약 |
| `/codeql-critical-quality/web-media-runtime-boundary` | 핵심 웹 가져오기/검색, 미디어 IO, 미디어 이해, 이미지 생성, 미디어 생성 런타임 계약 |
| `/codeql-critical-quality/plugin-boundary` | 로더, 레지스트리, 공개 표면, Plugin SDK 진입점 계약 |
| `/codeql-critical-quality/plugin-sdk-package-contract` | 게시된 패키지 측 Plugin SDK 소스와 플러그인 패키지 계약 헬퍼 |
품질 결과를 예약, 측정, 비활성화 또는 확장할 때 보안 신호를 흐리지 않도록, 품질은 보안과 분리된 상태로 유지됩니다. Swift, Python, 번들 Plugin CodeQL 확장은 좁은 프로필의 런타임과 신호가 안정된 뒤에만 범위가 지정되거나 샤딩된 후속 작업으로 다시 추가해야 합니다.
품질은 보안과 별도로 유지되므로 품질 발견 사항을 보안 신호를 흐리지 않고 예약, 측정, 비활성화 또는 확장할 수 있습니다. Swift, Python, 번들 Plugin CodeQL 확장은 좁은 프로필의 런타임과 신호가 안정된 뒤에만 범위가 지정되거나 샤딩된 후속 작업으로 다시 추가해야 합니다.
## 유지 관리 워크플로
### Docs Agent
### 문서 에이전트
`Docs Agent` 워크플로는 기존 문서를 최근 병합된 변경 사항과 맞게 유지하기 위한 이벤트 기반 Codex 유지 관리 레인입니다. 순수한 일정은 없습니다. `main`에서 성공한 비봇 push CI 실행이 이를 트리거할 수 있으며, 수동 디스패치로 직접 실행할 수도 있습니다. workflow-run 호출은 `main`이 이미 이동했거나 지난 한 시간 안에 건너뛰지 않은 다른 Docs Agent 실행이 생성된 경우 건너뜁니다. 실행되면 이전의 건너뛰지 않은 Docs Agent 소스 SHA부터 현재 `main`까지의 커밋 범위를 검토하므로, 시간당 한 번의 실행으로 마지막 문서 점검 이후 누적된 모든 main 변경 사항을 다룰 수 있습니다.
`Docs Agent` 워크플로는 최근 랜딩된 변경 사항과 기존 문서를 정렬하기 위한 이벤트 기반 Codex 유지 관리 레인입니다. 순수한 일정은 없습니다. `main`에서 봇이 아닌 성공한 푸시 CI 실행이 이를 트리거할 수 있고, 수동 디스패치로 직접 실행할 수 있습니다. 워크플로 실행 호출은 `main`이 이미 आगे로 이동했거나, 건너뛰지 않은 다른 Docs Agent 실행이 지난 1시간 안에 생성된 경우 건너뜁니다. 실행되면 이전에 건너뛰지 않은 Docs Agent 소스 SHA부터 현재 `main`까지의 커밋 범위를 검토하므로, 시간당 한 번의 실행으로 마지막 문서 패스 이후 누적된 모든 main 변경 사항을 처리할 수 있습니다.
### Test Performance Agent
### 테스트 성능 에이전트
`Test Performance Agent` 워크플로는 느린 테스트를 위한 이벤트 기반 Codex 유지 관리 레인입니다. 순수한 일정은 없습니다. `main`에서 성공한 비봇 push CI 실행이 이를 트리거할 수 있지만, 다른 workflow-run 호출이 해당 UTC 날짜에 이미 실행되었거나 실행 중이면 건너뜁니다. 수동 디스패치는 일일 활동 게이트를 우회합니다. 이 레인은 전체 스위트 그룹화 Vitest 성능 보고서를 빌드하고, Codex가 광범위한 리팩터링 대신 커버리지를 보존하는 작은 테스트 성능 수정만 수행하도록 한 뒤, 전체 스위트 보고서를 다시 실행하고 통과 기준 테스트 수를 줄이는 변경 사항을 거부합니다. 기준선에 실패하는 테스트가 있으면 Codex는 명백한 실패만 수정할 수 있으며, 에이전트 이후 전체 스위트 보고서가 통과해야만 커밋할 수 있습니다. 봇 push가 병합되기 전에 `main`이 전진하면, 이 레인은 검증된 패치를 rebase하고 `pnpm check:changed`를 다시 실행한 뒤 push를 재시도합니다. 충돌하는 오래된 패치는 건너뜁니다. GitHub 호스팅 Ubuntu를 사용하므로 Codex 액션은 문서 에이전트와 동일한 drop-sudo 안전 세를 유지할 수 있습니다.
`Test Performance Agent` 워크플로는 느린 테스트를 위한 이벤트 기반 Codex 유지 관리 레인입니다. 순수한 일정은 없습니다. `main`에서 봇이 아닌 성공한 푸시 CI 실행이 이를 트리거할 수 있지만, 다른 워크플로 실행 호출이 해당 UTC 날짜에 이미 실행되었거나 실행 중이면 건너뜁니다. 수동 디스패치는 해당 일일 활동 게이트를 우회합니다. 이 레인은 전체 스위트 그룹화 Vitest 성능 보고서를 빌드하고, Codex가 광범위한 리팩터링 대신 커버리지를 보존하는 작은 테스트 성능 수정만 수행하게 한 다음, 전체 스위트 보고서를 다시 실행하고 통과 기준 테스트 수를 줄이는 변경을 거부합니다. 기준선에 실패 테스트가 있으면 Codex는 명백한 실패만 수정할 수 있으며, 에이전트 이후 전체 스위트 보고서는 커밋 전에 통과해야 합니다. 봇 푸시가 랜딩되기 전에 `main`이 앞으로 이동하면, 레인은 검증된 패치를 리베이스하고 `pnpm check:changed`를 다시 실행한 뒤 푸시를 재시도합니다. 충돌하는 오래된 패치는 건너뜁니다. GitHub 호스팅 Ubuntu를 사용하므로 Codex 액션은 문서 에이전트와 동일한 drop-sudo 안전 세를 유지할 수 있습니다.
### 병합 후 중복 PR
`Duplicate PRs After Merge` 워크플로는 병합 후 중복 정리를 위한 수동 유지 관리자 워크플로입니다. 기본값은 dry-run이며 `apply=true`일 때 명시적으로 나열된 PR만 닫습니다. GitHub를 변경하기 전에, 병합된 PR이 실제로 병합되었고 각 중복 항목에 공유된 참조 이슈나 겹치는 변경 hunk가 있는지 확인합니다.
`Duplicate PRs After Merge` 워크플로는 랜딩 후 중복 정리를 위한 수동 유지 관리자 워크플로입니다. 기본값은 드라이런이며 `apply=true`일 때만 명시적으로 나열된 PR을 닫습니다. GitHub를 변경하기 전에, 랜딩된 PR이 병합되었고 각 중복 항목에 공유 참조 이슈 또는 겹치는 변경 헝크가 있는지 확인합니다.
```bash
gh workflow run duplicate-after-merge.yml \
@ -394,25 +394,25 @@ gh workflow run duplicate-after-merge.yml \
## 로컬 검사 게이트와 변경 라우팅
로컬 변경 레인 로직은 `scripts/changed-lanes.mjs`에 있으며 `scripts/check-changed.mjs`가 실행합니다. 해당 로컬 검사 게이트는 넓은 CI 플랫폼 범위보다 아키텍처 경계에 대해 더 엄격합니다.
로컬 변경 레인 로직은 `scripts/changed-lanes.mjs`에 있으며 `scripts/check-changed.mjs`가 실행합니다. 해당 로컬 검사 게이트는 광범위한 CI 플랫폼 범위보다 아키텍처 경계에 더 엄격합니다.
- 코어 프로덕션 변경은 코어 prod 및 코어 테스트 typecheck와 코어 lint/guard를 실행합니다.
- 코어 테스트 전용 변경은 코어 테스트 typecheck와 코어 lint만 실행합니다.
- 확장 프로덕션 변경은 확장 prod 및 확장 테스트 typecheck와 확장 lint를 실행합니다.
- 확장 테스트 전용 변경은 확장 테스트 typecheck와 확장 lint를 실행합니다.
- 공개 Plugin SDK 또는 Plugin 계약 변경은 확장이 해당 코어 계약에 의존하므로 확장 typecheck로 확장됩니다. Vitest 확장 sweep은 명시적 테스트 작업으로 남습니다.
- 릴리스 메타데이터 전용 버전 bump는 대상 지정 버전/config/root-dependency 검사를 실행합니다.
- 알 수 없는 루트/config 변경은 안전하게 모든 검사 레인으로 실패 처리됩니다.
- 핵심 프로덕션 변경은 핵심 prod와 핵심 test typecheck 및 핵심 lint/guard를 실행합니다.
- 핵심 테스트 전용 변경은 핵심 test typecheck와 핵심 lint만 실행합니다.
- 확장 프로덕션 변경은 확장 prod와 확장 test typecheck 및 확장 lint를 실행합니다.
- 확장 테스트 전용 변경은 확장 test typecheck와 확장 lint를 실행합니다.
- 공개 Plugin SDK 또는 플러그인 계약 변경은 확장이 해당 핵심 계약에 의존하므로 확장 typecheck로 확장됩니다(Vitest 확장 스윕은 명시적인 테스트 작업으로 유지됩니다).
- 릴리스 메타데이터 전용 버전 범프는 대상 버전/구성/루트 의존성 검사를 실행합니다.
- 알 수 없는 루트/구성 변경은 안전하게 모든 검사 레인으로 실패 처리됩니다.
로컬 변경 테스트 라우팅은 `scripts/test-projects.test-support.mjs`에 있으며 의도적으로 `check:changed`보다 저렴합니다. 직접 테스트 편집은 해당 테스트 자체를 실행하고, 소스 편집은 명시적 매핑을 우선한 뒤 형제 테스트와 import 그래프 의존 항목을 사용합니다. 공유 그룹룸 전달 config는 명시적 매핑 중 하나입니다. 그룹 visible-reply config, 소스 응답 전달 모드 또는 message-tool 시스템 프롬프트 변경은 코어 응답 테스트와 Discord 및 Slack 전달 회귀를 통과하므로, 공유 기본값 변경은 첫 PR push 전에 실패합니다. 변경이 하네스 전체에 영향을 줄 만큼 넓어서 저렴한 매핑 세트를 신뢰할 수 있는 대리 지표로 볼 수 없을 때`OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 사용하세요.
로컬 변경 테스트 라우팅은 `scripts/test-projects.test-support.mjs`에 있으며 의도적으로 `check:changed`보다 저렴합니다. 직접 테스트 편집은 그 자체를 실행하고, 소스 편집은 명시적 매핑을 우선한 다음 형제 테스트와 import 그래프 의존 항목을 따릅니다. 공유 그룹룸 전달 구성은 명시적 매핑 중 하나입니다. 그룹 표시 응답 구성, 소스 응답 전달 모드 또는 메시지 도구 시스템 프롬프트 변경은 핵심 응답 테스트와 Discord 및 Slack 전달 회귀를 거치므로, 공유 기본값 변경은 첫 PR 푸시 전에 실패합니다. 변경이 하네스 전반에 걸쳐 있어 저렴한 매핑 집합을 신뢰할 수 있는 프록시로 볼 수 없는 경우에`OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 사용하세요.
## Testbox 검증
Testbox는 repo root에서 실행하고, 넓은 증거에는 새로 예열한 박스를 선호하세요. 재사용되었거나 만료되었거나 방금 예상보다 큰 동기화를 보고한 박스에서 느린 게이트를 실행하기 전에, 먼저 박스 안에서 `pnpm testbox:sanity`를 실행하세요.
레포 루트에서 Testbox를 실행하고, 광범위한 증명에는 새로 워밍된 박스를 선호하세요. 재사용되었거나 만료되었거나 예상보다 큰 동기화를 방금 보고한 박스에서 느린 게이트를 쓰기 전에, 먼저 박스 안에서 `pnpm testbox:sanity`를 실행하세요.
sanity 검사는 `pnpm-lock.yaml` 같은 필수 루트 파일이 사라졌거나 `git status --short`에 추적되는 삭제가 200개 이상 표시되면 빠르게 실패합니다. 이는 보통 원격 동기화 상태가 PR의 신뢰할 수 있는 복사본이 아니라는 뜻입니다. 제품 테스트 실패를 디버깅하는 대신 해당 박스를 중지하고 새 박스를 예열하세요. 의도적인 대규모 삭제 PR의 경우 해당 sanity 실행에 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`을 설정하세요.
sanity 검사는 `pnpm-lock.yaml` 같은 필수 루트 파일이 사라졌거나 `git status --short`가 추적 파일 삭제를 최소 200개 표시하면 빠르게 실패합니다. 이는 대개 원격 동기화 상태가 PR의 신뢰할 수 있는 복사본이 아니라는 뜻입니다. 제품 테스트 실패를 디버깅하는 대신 해당 박스를 중지하고 새 박스를 워밍하세요. 의도적인 대규모 삭제 PR의 경우 해당 sanity 실행에 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`을 설정하세요.
`pnpm testbox:run`post-sync 출력 없이 5분 넘게 동기화 단계에 머무르는 로컬 Blacksmith CLI 호출도 종료합니다. 이 guard를 비활성화하려면 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0`을 설정하고, 비정상적으로 큰 로컬 diff에는 더 큰 밀리초 값을 사용하세요.
`pnpm testbox:run`동기화 이후 출력 없이 5분 넘게 동기화 단계에 머무르는 로컬 Blacksmith CLI 호출도 종료합니다. 해당 가드를 비활성화하려면 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0`을 설정하거나, 비정상적으로 큰 로컬 diff에는 더 큰 밀리초 값을 사용하세요.
## 관련 항목

View File

@ -1,24 +1,25 @@
---
read_when:
- 에이전트 루프 또는 수명 주기 이벤트에 대한 정확한 단계별 설명이 필요합니다
- 세션 큐잉, 트랜스크립트 쓰기 또는 세션 쓰기 잠금 동작을 변경하는 경우
summary: 에이전트 루프 수명 주기, 스트림 대기 의미 체계
- 세션 대기열 처리, 트랜스크립트 쓰기 작업 또는 세션 쓰기 잠금 동작을 변경하는 경우
summary: 에이전트 루프 수명 주기, 스트림, 대기 의미 체계
title: 에이전트 루프
x-i18n:
generated_at: "2026-04-30T06:25:13Z"
generated_at: "2026-04-30T18:38:34Z"
model: gpt-5.5
provider: openai
source_hash: 902d543bd71dd517a810d825cbe92e244fe89230f47eeada72477c657a2bec32
source_hash: 5466893253e1f82482284ff82db56f4c3fca018bf12e4114fad76d37cad954df
source_path: concepts/agent-loop.md
workflow: 16
---
에이전트 루프는 에이전트의 전체 “실제” 실행입니다: 입력 수신 → 컨텍스트 조립 → 모델 추론 →
도구 실행 → 스트리밍 응답 → 영속화. 이는 메시지를 작업과 최종 응답으로 변환하면서
세션 상태의 일관성을 유지하는 권위 있는 경로입니다.
에이전트 루프는 에이전트의 전체 “실제” 실행입니다: 수신 → 컨텍스트 조립 → 모델 추론 →
도구 실행 → 스트리밍 응답 → 영속화. 이는 메시지를 작업과 최종 응답으로
변환하면서 세션 상태를 일관되게 유지하는 권위 있는 경로입니다.
OpenClaw에서 루프는 모델이 사고하고, 도구를 호출하며, 출력을 스트리밍하는 동안 생명주기 및 스트림 이벤트를 내보내는
세션별 단일 직렬화 실행입니다. 이 문서는 그 실제 루프가 엔드투엔드로 어떻게 연결되는지 설명합니다.
OpenClaw에서 루프는 세션당 하나씩 직렬화되는 단일 실행이며, 모델이 생각하고 도구를 호출하며
출력을 스트리밍하는 동안 수명 주기 및 스트림 이벤트를 내보냅니다. 이 문서는 그 실제 루프가
엔드투엔드로 어떻게 연결되는지 설명합니다.
## 진입점
@ -27,162 +28,164 @@ OpenClaw에서 루프는 모델이 사고하고, 도구를 호출하며, 출력
## 작동 방식(상위 수준)
1. `agent` RPC는 매개변수를 검증하고, 세션(sessionKey/sessionId)을 확인하고, 세션 메타데이터를 영속화한 뒤, 즉시 `{ runId, acceptedAt }`를 반환합니다.
2. `agentCommand` 에이전트를 실행합니다:
- 모델 + 사고/상세/추적 기본값 확인
1. `agent` RPC는 매개변수를 검증하고, 세션(sessionKey/sessionId)을 해석하고, 세션 메타데이터를 영속화한 뒤, 즉시 `{ runId, acceptedAt }`를 반환합니다.
2. `agentCommand` 에이전트를 실행합니다:
- 모델 + thinking/verbose/trace 기본값 해석
- Skills 스냅샷 로드
- `runEmbeddedPiAgent` 호출(pi-agent-core 런타임)
- 내장 루프가 생명주기 end/error를 내보내지 않으면 **생명주기 end/error** 내보냄
- 내장 루프가 하나를 내보내지 않으면 **수명 주기 end/error** 내보내기
3. `runEmbeddedPiAgent`:
- 세션별 + 전역 큐를 통해 실행을 직렬화
- 모델 + 인증 프로필을 확인하고 Pi 세션 구성
- Pi 이벤트를 구독하고 assistant/tool 델타 스트리밍
- 타임아웃 강제 -> 초과 시 실행 중단
- 페이로드 + 사용량 메타데이터 반환
4. `subscribeEmbeddedPiSession`은 pi-agent-core 이벤트를 OpenClaw `agent` 스트림으로 연결합니다:
- 세션별 + 전역 큐를 통해 실행을 직렬화합니다
- 모델 + 인증 프로필을 해석하고 Pi 세션을 빌드합니다
- Pi 이벤트를 구독하고 어시스턴트/도구 델타를 스트리밍합니다
- 시간 초과를 강제 적용합니다 -> 초과되면 실행을 중단합니다
- Codex app-server 턴의 경우, 터미널 이벤트 전에 app-server 진행 상태 생성을 멈춘 수락된 턴을 중단합니다
- 페이로드 + 사용량 메타데이터를 반환합니다
4. `subscribeEmbeddedPiSession`은 pi-agent-core 이벤트를 OpenClaw `agent` 스트림으로 브리지합니다:
- 도구 이벤트 => `stream: "tool"`
- assistant 델타 => `stream: "assistant"`
- 생명주기 이벤트 => `stream: "lifecycle"` (`phase: "start" | "end" | "error"`)
- 어시스턴트 델타 => `stream: "assistant"`
- 수명 주기 이벤트 => `stream: "lifecycle"` (`phase: "start" | "end" | "error"`)
5. `agent.wait``waitForAgentRun`을 사용합니다:
- `runId`에 대한 **생명주기 end/error** 대기
- `{ status: ok|error|timeout, startedAt, endedAt, error? }` 반환
- `runId`의 **수명 주기 end/error**를 기다립니다
- `{ status: ok|error|timeout, startedAt, endedAt, error? }` 반환합니다
## 큐잉 + 동시성
- 실행은 세션 키별(세션 레인)로 직렬화되며, 선택적으로 전역 레인을 통과합니다.
- 이는 도구/세션 경합을 방지하고 세션 기록의 일관성을 유지합니다.
- 실행은 세션 키(세션 레인)별로, 그리고 선택적으로 전역 레인을 통해 직렬화됩니다.
- 이는 도구/세션 경합을 방지하고 세션 기록을 일관되게 유지합니다.
- 메시징 채널은 이 레인 시스템에 공급되는 큐 모드(collect/steer/followup)를 선택할 수 있습니다.
[명령 큐](/ko/concepts/queue)를 참하세요.
- 트랜스크립트 쓰기도 세션 파일의 세션 쓰기 잠금으로 보호됩니다. 이 잠금은
프로세스를 인식하고 파일 기반이므로, 프로세스 내 큐를 우회하거나 다른 프로세스에서 온
작성자도 감지합니다.
- 세션 쓰기 잠금은 기본적으로 재진입할 수 없습니다. 헬퍼가 하나의 논리적 작성자를 유지하면서
동일한 잠금 획득을 의도적으로 중첩하는 경우, `allowReentrant: true`
명시적으로 옵트인해야 합니다.
[명령 큐](/ko/concepts/queue)를 참하세요.
- transcript 쓰기도 세션 파일의 세션 쓰기 잠금으로 보호됩니다. 이 잠금은
프로세스를 인식하며 파일 기반이므로, 인프로세스 큐를 우회하거나
다른 프로세스에서 온 작성자를 포착합니다.
- 세션 쓰기 잠금은 기본적으로 재진입 불가입니다. 헬퍼가 하나의 논리적 작성자를 유지하면서
동일한 잠금 획득을 의도적으로 중첩하는 경우, 명시적으
`allowReentrant: true`를 선택해야 합니다.
## 세션 + 워크스페이스 준비
## 세션 + 작업공간 준비
- 워크스페이스를 확인하고 생성합니다. 샌드박스 실행은 샌드박스 워크스페이스 루트로 리디렉션될 수 있습니다.
- Skills를 로드하거나 스냅샷에서 재사용하고, env 및 프롬프트에 주입합니다.
- 부트스트랩/컨텍스트 파일을 확인하고 시스템 프롬프트 보고서에 주입합니다.
- 세션 쓰기 잠금을 획득합니다. 스트리밍 전에 `SessionManager`를 열고 준비합니다. 이후의
트랜스크립트 재작성, Compaction 또는 잘라내기 경로는 트랜스크립트 파일을 열거나
- 작업공간이 해석되고 생성됩니다. 샌드박스 실행은 샌드박스 작업공간 루트로 리디렉션될 수 있습니다.
- Skills가 로드되거나 스냅샷에서 재사용되어 env와 프롬프트에 주입됩니다.
- 부트스트랩/컨텍스트 파일이 해석되어 시스템 프롬프트 보고서에 주입됩니다.
- 세션 쓰기 잠금을 획득합니다. `SessionManager`는 스트리밍 전에 열리고 준비됩니다. 이후의 모든
transcript 재작성, Compaction 또는 잘라내기 경로는 transcript 파일을 열거나
변경하기 전에 동일한 잠금을 획득해야 합니다.
## 프롬프트 조립 + 시스템 프롬프트
- 시스템 프롬프트는 OpenClaw의 기본 프롬프트, Skills 프롬프트, 부트스트랩 컨텍스트, 실행별 오버라이드로 구성됩니다.
- 모델별 제한과 Compaction 예약 토큰이 적용됩니다.
- 모델이 보는 내용은 [시스템 프롬프트](/ko/concepts/system-prompt)를 참하세요.
- 시스템 프롬프트는 OpenClaw의 기본 프롬프트, Skills 프롬프트, 부트스트랩 컨텍스트, 실행별 오버라이드로 빌드됩니다.
- 모델별 제한 및 Compaction 예약 토큰이 강제 적용됩니다.
- 모델이 보는 내용은 [시스템 프롬프트](/ko/concepts/system-prompt)를 참하세요.
## 훅 지점(가로챌 수 있는 위치)
OpenClaw에는 두 가지 훅 시스템이 있습니다:
- **내부 훅**(Gateway 훅): 명령 및 생명주기 이벤트를 위한 이벤트 기반 스크립트입니다.
- **Plugin 훅**: 에이전트/도구 생명주기 및 Gateway 파이프라인 내부의 확장 지점입니다.
- **내부 훅**(Gateway 훅): 명령 및 수명 주기 이벤트를 위한 이벤트 기반 스크립트입니다.
- **Plugin 훅**: 에이전트/도구 수명 주기 및 gateway 파이프라인 내부의 확장 지점입니다.
### 내부 훅(Gateway 훅)
- **`agent:bootstrap`**: 시스템 프롬프트가 확정되기 전에 부트스트랩 파일을 구성하는 동안 실행됩니다.
부트스트랩 컨텍스트 파일을 추가/제거할 때 사용하세요.
- **명령 훅**: `/new`, `/reset`, `/stop` 및 기타 명령 이벤트(Hooks 문서 참).
- **`agent:bootstrap`**: 시스템 프롬프트가 최종 확정되기 전에 부트스트랩 파일을 빌드하는 동안 실행됩니다.
이를 사용해 부트스트랩 컨텍스트 파일을 추가/제거하세요.
- **명령 훅**: `/new`, `/reset`, `/stop` 및 기타 명령 이벤트(Hooks 문서 참).
설정 및 예시는 [Hooks](/ko/automation/hooks)를 참하세요.
설정 및 예시는 [Hooks](/ko/automation/hooks)를 참하세요.
### Plugin 훅(에이전트 + Gateway 생명주기)
### Plugin 훅(에이전트 + gateway 수명 주기)
들은 에이전트 루프 또는 Gateway 파이프라인 내부에서 실행됩니다:
는 에이전트 루프 또는 gateway 파이프라인 내부에서 실행됩니다:
- **`before_model_resolve`**: 모델 확인 전에 제공자/모델을 결정적으로 오버라이드하기 위해 세션 전 단계(`messages` 없음)에 실행됩니다.
- **`before_prompt_build`**: 세션 로드 후(`messages` 포함) 실행되어 프롬프트 제출 전에 `prependContext`, `systemPrompt`, `prependSystemContext` 또는 `appendSystemContext`를 주입니다. 턴별 동적 텍스트에는 `prependContext`를 사용하고, 시스템 프롬프트 공간에 있어야 하는 안정적인 지침에는 시스템 컨텍스트 필드를 사용하세요.
- **`before_model_resolve`**: 모델 해석 전에 공급자/모델을 결정적으로 오버라이드하기 위해 세션 전(`messages` 없음)에 실행됩니다.
- **`before_prompt_build`**: 세션 로드 후(`messages` 포함) 프롬프트 제출 전에 `prependContext`, `systemPrompt`, `prependSystemContext` 또는 `appendSystemContext`를 주입하기 위해 실행됩니다. 턴별 동적 텍스트에는 `prependContext`를 사용하고, 시스템 프롬프트 공간에 있어야 하는 안정적인 지침에는 시스템 컨텍스트 필드를 사용하세요.
- **`before_agent_start`**: 어느 단계에서든 실행될 수 있는 레거시 호환성 훅입니다. 위의 명시적 훅을 선호하세요.
- **`before_agent_reply`**: 인라인 작업 후, LLM 호출 전에 실행되어 Plugin이 해당 턴을 처리하고 합성 응답을 반환하거나 턴을 완전히 침묵시킬 수 있게 합니다.
- **`before_agent_reply`**: 인라인 작업 후 LLM 호출 전에 실행되어, Plugin이 해당 턴을 가져가 합성 응답을 반환하거나 턴을 완전히 무음 처리할 수 있게 합니다.
- **`agent_end`**: 완료 후 최종 메시지 목록과 실행 메타데이터를 검사합니다.
- **`before_compaction` / `after_compaction`**: Compaction 주기를 관찰하거나 주석을 추가합니다.
- **`before_tool_call` / `after_tool_call`**: 도구 매개변수/결과를 가로챕니다.
- **`before_install`**: 기본 제공 스캔 결과를 검사하고 선택적으로 skill 또는 Plugin 설치를 차단합니다.
- **`tool_result_persist`**: 도구 결과가 OpenClaw 소유 세션 트랜스크립트에 기록되기 전에 동기적으로 변환합니다.
- **`message_received` / `message_sending` / `message_sent`**: 인바운드 + 아웃바운드 메시지 훅입니다.
- **`session_start` / `session_end`**: 세션 생명주기 경계입니다.
- **`gateway_start` / `gateway_stop`**: Gateway 생명주기 이벤트입니다.
- **`before_install`**: 내장 스캔 결과를 검사하고 선택적으로 skill 또는 Plugin 설치를 차단합니다.
- **`tool_result_persist`**: 도구 결과가 OpenClaw 소유 세션 transcript에 기록되기 전에 동기적으로 변환합니다.
- **`message_received` / `message_sending` / `message_sent`**: 수신 + 발신 메시지 훅입니다.
- **`session_start` / `session_end`**: 세션 수명 주기 경계입니다.
- **`gateway_start` / `gateway_stop`**: gateway 수명 주기 이벤트입니다.
아웃바운드/도구 가드에 대한 훅 결정 규칙:
발신/도구 가드에 대한 훅 결정 규칙:
- `before_tool_call`: `{ block: true }`종료 상태이며 더 낮은 우선순위의 핸들러를 중지합니다.
- `before_tool_call`: `{ block: false }`아무 작업도 하지 않으며 이전 차단을 해제하지 않습니다.
- `before_install`: `{ block: true }`종료 상태이며 더 낮은 우선순위의 핸들러를 중지합니다.
- `before_install`: `{ block: false }`아무 작업도 하지 않으며 이전 차단을 해제하지 않습니다.
- `message_sending`: `{ cancel: true }`종료 상태이며 더 낮은 우선순위의 핸들러를 중지합니다.
- `message_sending`: `{ cancel: false }`아무 작업도 하지 않으며 이전 취소를 해제하지 않습니다.
- `before_tool_call`: `{ block: true }`터미널이며 낮은 우선순위 핸들러를 중지합니다.
- `before_tool_call`: `{ block: false }`no-op이며 이전 차단을 해제하지 않습니다.
- `before_install`: `{ block: true }`터미널이며 낮은 우선순위 핸들러를 중지합니다.
- `before_install`: `{ block: false }`no-op이며 이전 차단을 해제하지 않습니다.
- `message_sending`: `{ cancel: true }`터미널이며 낮은 우선순위 핸들러를 중지합니다.
- `message_sending`: `{ cancel: false }`no-op이며 이전 취소를 해제하지 않습니다.
훅 API 및 등록 세부 정보는 [Plugin 훅](/ko/plugins/hooks)를 참조하세요.
훅 API 및 등록 세부 정보는 [Plugin 훅](/ko/plugins/hooks)을 참고하세요.
하네스는 이러한 훅을 다르게 조정할 수 있습니다. Codex app-server 하네스는 문서화된 미러링 표면에 대한 호환성 계약으로
OpenClaw Plugin 훅을 유지하는 반면, Codex 네이티브 훅은 별도의 저수준 Codex 메커니즘으로 남아 있습니다.
하네스는 이러한 훅을 다르게 조정할 수 있습니다. Codex app-server 하네스는 문서화된 미러링
표면에 대한 호환성 계약으로 OpenClaw Plugin 훅을 유지하며, Codex 네이티브 훅은 별도의
하위 수준 Codex 메커니즘으로 남습니다.
## 스트리밍 + 부분 응답
- assistant 델타는 pi-agent-core에서 스트리밍되어 `assistant` 이벤트로 내보내집니다.
- 어시스턴트 델타는 pi-agent-core에서 스트리밍되어 `assistant` 이벤트로 내보내집니다.
- 블록 스트리밍은 `text_end` 또는 `message_end`에서 부분 응답을 내보낼 수 있습니다.
- 추론 스트리밍은 별도 스트림 또는 블록 응답으로 내보낼 수 있습니다.
- 청크 처리 및 블록 응답 동작은 [스트리밍](/ko/concepts/streaming)을 참조하세요.
- 추론 스트리밍은 별도 스트림 또는 블록 응답으로 내보낼 수 있습니다.
- 청킹 및 블록 응답 동작은 [스트리밍](/ko/concepts/streaming)을 참고하세요.
## 도구 실행 + 메시징 도구
- 도구 시작/업데이트/종료 이벤트 `tool` 스트림에 내보내집니다.
- 도구 결과는 기록/내보내기 전에 크기 및 이미지 페이로드 기준으로 정리됩니다.
- 메시징 도구 전송은 중복 assistant 확인을 억제하기 위해 추적됩니다.
- 도구 시작/업데이트/종료 이벤트 `tool` 스트림에 내보내집니다.
- 도구 결과는 로깅/내보내기 전에 크기와 이미지 페이로드에 대해 정리됩니다.
- 메시징 도구 전송은 중복 어시스턴트 확인을 억제하기 위해 추적됩니다.
## 응답 성 + 억제
## 응답 성 + 억제
- 최종 페이로드는 다음으로 조립됩니다:
- assistant 텍스트(및 선택적 추론)
- 인라인 도구 요약(상세 모드 + 허용된 경우)
- 모델 오류 시 assistant 오류 텍스트
- 정확한 무응답 토큰 `NO_REPLY` / `no_reply`는 발신
- 최종 페이로드는 다음에서 조립됩니다:
- 어시스턴트 텍스트(및 선택적 추론)
- 인라인 도구 요약(verbose + 허용된 경우)
- 모델 오류 시 어시스턴트 오류 텍스트
- 정확한 무 토큰 `NO_REPLY` / `no_reply`는 발신
페이로드에서 필터링됩니다.
- 메시징 도구 중복 항목은 최종 페이로드 목록에서 제거됩니다.
- 메시징 도구 중복은 최종 페이로드 목록에서 제거됩니다.
- 렌더링 가능한 페이로드가 남아 있지 않고 도구에 오류가 발생한 경우, 대체 도구 오류 응답이 내보내집니다
(메시징 도구가 이미 사용자에게 보이는 응답을 보낸 경우 제외).
(메시징 도구가 이미 사용자에게 보이는 응답을 보낸 경우 제외).
## Compaction + 재시도
- 자동 Compaction은 `compaction` 스트림 이벤트를 내보내며 재시도를 트리거할 수 있습니다.
- 재시도 시 중복 출력을 하기 위해 인메모리 버퍼와 도구 요약이 재설정됩니다.
- Compaction 파이프라인은 [Compaction](/ko/concepts/compaction)을 참하세요.
- 재시도 시 중복 출력을 방지하기 위해 인메모리 버퍼와 도구 요약이 재설정됩니다.
- Compaction 파이프라인은 [Compaction](/ko/concepts/compaction)을 참하세요.
## 이벤트 스트림(현재)
- `lifecycle`: `subscribeEmbeddedPiSession`에서 내보냄(`agentCommand`에서 대체로 내보냄)
- `lifecycle`: `subscribeEmbeddedPiSession`에서 내보냄(그리고 `agentCommand`에서 대체 수단으로 내보냄)
- `assistant`: pi-agent-core의 스트리밍 델타
- `tool`: pi-agent-core의 스트리밍 도구 이벤트
## 채팅 채널 처리
- assistant 델타는 채팅 `delta` 메시지로 버퍼링됩니다.
- 채팅 `final`은 **생명주기 end/error**에서 내보내집니다.
- 어시스턴트 델타는 채팅 `delta` 메시지로 버퍼링됩니다.
- 채팅 `final`은 **수명 주기 end/error**에서 내보내집니다.
## 타임아웃
## 시간 초과
- `agent.wait` 기본값: 30초(대기만). `timeoutMs` 매개변수 오버라이드합니다.
- 에이전트 런타임: `agents.defaults.timeoutSeconds` 기본값 172800초(48시간); `runEmbeddedPiAgent` 중단 타이머에서 강제됩니다.
- Cron 런타임: 격리된 에이전트 턴 `timeoutSeconds`는 cron이 소유합니다. 스케줄러는 실행이 시작될 때 해당 타이머를 시작하고, 구성된 마감 시점에 기본 실행을 중단한 뒤, 타임아웃을 기록하기 전에 제한된 정리를 실행하여 오래된 자식 세션이 레인을 막아두지 못하게 합니다.
- 멈춘 세션 복구: 진단이 활성화된 경우 `diagnostics.stuckSessionWarnMs`가 장시간 `processing` 세션을 감지합니다. 활성 내장 실행, 활성 응답 작업, 활성 세션 레인 작업은 기본적으로 경고 전용으로 유지됩니다. 진단 결과 세션에 활성 작업이 없으면, 워치독이 영향을 받은 세션 레인을 해제하여 큐에 쌓인 시작 작업이 처리되도록 합니다.
- 모델 유휴 타임아웃: 유휴 창 내에 응답 청크가 도착하지 않으면 OpenClaw는 모델 요청을 중단합니다. `models.providers.<id>.timeoutSeconds`는 느린 로컬/셀프 호스팅 제공자에 대해 이 유휴 워치독을 연장합니다. 그렇지 않으면 OpenClaw는 구성된 경우 `agents.defaults.timeoutSeconds`를 사용하며, 기본적으로 120초로 제한됩니다. 명시적 모델 또는 에이전트 타임아웃이 없는 Cron 트리거 실행은 유휴 워치독을 비활성화하고 cron 외부 타임아웃에 의존합니다.
- 제공자 HTTP 요청 타임아웃: `models.providers.<id>.timeoutSeconds`는 연결, 헤더, 본문, SDK 요청 타임아웃, 전체 보호 fetch 중단 처리, 모델 스트림 유휴 워치독을 포함하여 해당 제공자의 모델 HTTP fetch에 적용됩니다. 전체 에이전트 런타임 타임아웃을 늘리기 전에 Ollama와 같은 느린 로컬/셀프 호스팅 제공자에 이 값을 사용하세요.
- `agent.wait` 기본값: 30초(대기만). `timeoutMs` 매개변수 오버라이드합니다.
- 에이전트 런타임: `agents.defaults.timeoutSeconds` 기본값 172800초(48시간); `runEmbeddedPiAgent` 중단 타이머에서 강제 적용됩니다.
- Cron 런타임: 격리된 에이전트 턴 `timeoutSeconds`는 cron이 소유합니다. 스케줄러는 실행이 시작될 때 해당 타이머를 시작하고, 구성된 마감 시점에 기반 실행을 중단한 뒤, 제한된 정리를 실행한 후 시간 초과를 기록하여 오래된 자식 세션이 레인을 막아 두지 못하게 합니다.
- 멈춘 세션 복구: 진단이 활성화되면 `diagnostics.stuckSessionWarnMs`가 오래 지속되는 `processing` 세션을 감지합니다. 활성 내장 실행, 활성 응답 작업, 활성 세션 레인 작업은 기본적으로 경고 전용으로 유지됩니다. 진단에서 해당 세션에 활성 작업이 없는 것으로 나타나면, watchdog이 영향을 받은 세션 레인을 해제하여 대기 중인 시작 작업이 비워질 수 있게 합니다.
- 모델 유휴 시간 초과: OpenClaw는 유휴 창 전에 응답 청크가 도착하지 않으면 모델 요청을 중단합니다. `models.providers.<id>.timeoutSeconds`는 느린 local loopback/자체 호스팅 공급자를 위해 이 유휴 watchdog을 연장합니다. 그렇지 않으면 OpenClaw는 구성된 경우 `agents.defaults.timeoutSeconds`를 사용하며, 기본적으로 120초로 제한됩니다. 명시적 모델 또는 에이전트 시간 초과가 없는 Cron 트리거 실행은 유휴 watchdog을 비활성화하고 Cron 외부 시간 초과에 의존합니다.
- 공급자 HTTP 요청 시간 초과: `models.providers.<id>.timeoutSeconds`는 연결, 헤더, 본문, SDK 요청 시간 초과, 전체 guarded-fetch 중단 처리, 모델 스트림 유휴 watchdog을 포함해 해당 공급자의 모델 HTTP fetch에 적용됩니다. 전체 에이전트 런타임 시간 초과를 올리기 전에 Ollama 같은 느린 local loopback/자체 호스팅 공급자에 이를 사용하세요.
## 조기 종료될 수 있는 위치
- 에이전트 타임아웃(중단)
- 에이전트 시간 초과(중단)
- AbortSignal(취소)
- Gateway 연결 해제 또는 RPC 타임아웃
- `agent.wait` 타임아웃(대기 전용, 에이전트를 중지하지 않음)
- Gateway 연결 해제 또는 RPC 시간 초과
- `agent.wait` 시간 초과(대기 전용, 에이전트를 중지하지 않음)
## 관련 항목
- [도구](/ko/tools) — 사용 가능한 에이전트 도구
- [Hooks](/ko/automation/hooks) — 에이전트 생명주기 이벤트로 트리거되는 이벤트 기반 스크립트
- [Compaction](/ko/concepts/compaction) — 긴 대화를 요약하는 방식
- [Hooks](/ko/automation/hooks) — 에이전트 수명 주기 이벤트에 의해 트리거되는 이벤트 기반 스크립트
- [Compaction](/ko/concepts/compaction) — 긴 대화가 요약되는 방식
- [Exec 승인](/ko/tools/exec-approvals) — 셸 명령에 대한 승인 게이트
- [사고](/ko/tools/thinking) — 사고/추론 수준 구성
- [Thinking](/ko/tools/thinking) — thinking/reasoning 수준 구성

View File

@ -1,60 +1,60 @@
---
read_when:
- 자동 응답 실행 또는 동시성 변경
- /queue 모드 또는 메시지 방향 지정 동작 설명
- /queue 모드 또는 메시지 라우팅 동작 설명
summary: 자동 응답 큐 모드, 기본값 및 세션별 재정의
title: 명령 큐
x-i18n:
generated_at: "2026-04-30T06:28:15Z"
generated_at: "2026-04-30T18:38:27Z"
model: gpt-5.5
provider: openai
source_hash: 2ac0c0ded9558b080714fa4b8be0d552f985911bf19b427020f9654ae4955b2d
source_hash: fbf1bb1ffd4ce06fa138f63e31651b8821226d9c95dd6b93d68326a5fb91fdd0
source_path: concepts/queue.md
workflow: 16
---
인바운드 자동 응답 실행(모든 채널)을 작은 인프로세스 큐를 통해 직렬화하여, 세션 간 안전한 병렬 처리는 허용하면서도 여러 에이전트 실행이 충돌하지 않도록 합니다.
수신 자동 응답 실행(모든 채널)을 작은 프로세스 내 큐를 통해 직렬화하여 여러 에이전트 실행이 충돌하는 것을 방지하면서도, 세션 간의 안전한 병렬 처리는 계속 허용합니다.
## 이유
- 자동 응답 실행은 비용이 클 수 있으며(LLM 호출), 여러 인바운드 메시지가 짧은 간격으로 도착하면 충돌할 수 있습니다.
- 직렬화하면 공유 리소스(세션 파일, 로그, CLI stdin) 경쟁을 피하고 업스트림 속도 제한 가능성을 줄일 수 있습니다.
- 자동 응답 실행은 비용이 클 수 있으며(LLM 호출), 여러 수신 메시지가 짧은 간격으로 도착하면 충돌할 수 있습니다.
- 직렬화는 공유 리소스(세션 파일, 로그, CLI stdin)를 두고 경쟁하는 것을 피하고, 업스트림 속도 제한에 걸릴 가능성을 줄입니다.
## 작동 방식
- 레인 인식 FIFO 큐가 구성 가능한 동시 실행 한도(구성되지 않은 레인의 기본값은 1, main 기본값은 4, subagent 기본값은 8)로 각 레인을 처리합니다.
- 레인 인식 FIFO 큐가 구성 가능한 동시성 상한으로 각 레인을 비웁니다(구성되지 않은 레인의 기본값은 1, main 기본값은 4, subagent는 8).
- `runEmbeddedPiAgent`**세션 키**(레인 `session:<key>`)별로 큐에 넣어 세션당 활성 실행이 하나만 있도록 보장합니다.
- 그런 다음 각 세션 실행은 **전역 레인**(기본값은 `main`)에 큐잉되어 전체 병렬 처리가 `agents.defaults.maxConcurrent`로 제한됩니다.
- 자세한 로깅이 활성화되면, 큐에 들어간 실행은 시작 전 대기 시간이 약 2초를 넘었을 때 짧은 알림을 내보냅니다.
- 입력 중 표시기는 큐에 들어가는 즉시(채널에서 지원하는 경우) 계속 실행되므로, 차례를 기다리는 동안 사용자 경험은 변경되지 않습니다.
- 그런 다음 각 세션 실행은 **전역 레인**(기본값은 `main`)에 큐잉되므로 전체 병렬 처리는 `agents.defaults.maxConcurrent`로 제한됩니다.
- 자세한 로그가 활성화된 경우, 큐에 있던 실행이 시작 전 약 2초 넘게 기다리면 짧은 알림을 출력합니다.
- 입력 표시기는 큐에 넣는 즉시 계속 실행되므로(채널에서 지원하는 경우), 차례를 기다리는 동안에도 사용자 경험은 바뀌지 않습니다.
## 기본값
설정되지 않은 경우 모든 인바운드 채널 표면은 다음을 사용합니다.
설정하지 않으면 모든 수신 채널 표면은 다음을 사용합니다.
- `mode: "steer"`
- `debounceMs: 500`
- `cap: 20`
- `drop: "summarize"`
`steer`는 두 번째 세션 실행을 시작하지 않고도 활성 모델 턴의 응답성을 유지하므로 기본값입니다. 다음 모델 경계 전에 도착한 모든 스티어링 메시지를 처리합니다. 현재 실행이 스티어링을 받을 수 없으면 OpenClaw는 후속 큐 항목으로 폴백합니다.
`steer`가 기본값인 이유는 두 번째 세션 실행을 시작하지 않으면서도 활성 모델 턴의 응답성을 유지하기 때문입니다. 다음 모델 경계 전에 도착한 모든 스티어링 메시지를 비웁니다. 현재 실행이 스티어링을 수락할 수 없으면 OpenClaw는 후속 큐 항목으로 대체합니다.
## 큐 모드
인바운드 메시지는 현재 실행을 스티어링하거나, 후속 턴을 기다리거나, 둘 다 수행할 수 있습니다.
수신 메시지는 현재 실행을 스티어링하거나, 후속 턴을 기다리거나, 둘 다 수행할 수 있습니다.
- `steer`: 스티어링 메시지를 활성 런타임 큐에 넣습니다. Pi는 **현재 어시스턴트 턴이 도구 호출 실행을 마친 뒤**, 다음 LLM 호출 전에 대기 중인 모든 스티어링 메시지를 전달합니다. Codex 앱 서버는 배치`turn/steer` 하나를 받습니다. 실행이 활성 스트리밍 중이 아니거나 스티어링을 사용할 수 없으면 OpenClaw는 후속 큐 항목으로 폴백합니다.
- `queue`(레거시): 전의 한 번에 하나씩 처리하는 스티어링입니다. Pi는 각 모델 경계에서 큐에 있는 스티어링 메시지 하나를 전달합니다. Codex 앱 서버는 별도의 `turn/steer` 요청을 받습니다. 이전 직렬화 동작이 필요한 경우가 아니라면 `steer`를 선호하세요.
- `steer`: 스티어링 메시지를 활성 런타임에 큐잉합니다. Pi는 **현재 어시스턴트 턴이 도구 호출 실행을 마친 후** 다음 LLM 호출 전에 대기 중인 모든 스티어링 메시지를 전달합니다. Codex app-server는 일괄 처리`turn/steer` 하나를 받습니다. 실행이 활성 스트리밍 중이 아니거나 스티어링을 사용할 수 없으면 OpenClaw는 후속 큐 항목으로 대체합니다.
- `queue`(레거시): 전의 한 번에 하나씩 처리하는 스티어링입니다. Pi는 각 모델 경계에서 큐에 있던 스티어링 메시지 하나를 전달합니다. Codex app-server는 별도의 `turn/steer` 요청을 받습니다. 이전 직렬화 동작이 필요한 경우가 아니라면 `steer`를 선호하세요.
- `followup`: 현재 실행이 끝난 뒤 나중의 에이전트 턴을 위해 각 메시지를 큐에 넣습니다.
- `collect`: 조용한 창 이후 큐에 있는 메시지를 **단일** 후속 턴으로 병합합니다. 메시지가 서로 다른 채널/스레드를 대상으로 하면 라우팅을 보존하기 위해 개별적으로 처리됩니다.
- `collect`: 조용한 기간이 지난 뒤 큐에 있는 메시지를 **단일** 후속 턴으로 병합합니다. 메시지가 서로 다른 채널/스레드를 대상으로 하면 라우팅을 보존하기 위해 개별적으로 비웁니다.
- `steer-backlog`(`steer+backlog`라고도 함): 지금 스티어링하고 **동시에** 같은 메시지를 후속 턴용으로 보존합니다.
- `interrupt`(레거시): 해당 세션의 활성 실행을 중단한 다음 최신 메시지를 실행합니다.
- `interrupt`(레거시): 해당 세션의 활성 실행을 중단한 최신 메시지를 실행합니다.
Steer-backlog는 스티어링된 실행 이후 후속 응답을 받을 수 있다는 뜻이므로, 스트리밍 표면에서는 중복처럼 보일 수 있습니다. 인바운드 메시지당 응답 하나를 원한다면 `collect`/`steer`를 선호하세요.
Steer-backlog는 스티어링된 실행 이후 후속 응답을 받을 수 있음을 의미하므로, 스트리밍 표면에서는 중복처럼 보일 수 있습니다. 수신 메시지당 응답 하나를 원한다면 `collect`/`steer`를 선호하세요.
런타임별 타이밍과 종속성 동작은 [스티어링 큐](/ko/concepts/queue-steering)를 참조하세요.
런타임별 타이밍 및 의존성 동작은 [스티어링 큐](/ko/concepts/queue-steering)를 참조하세요.
`messages.queue`를 통해 전역 또는 채널별로 구성하세요.
`messages.queue`를 통해 전역 또는 채널별로 구성합니다.
```json5
{
@ -72,48 +72,49 @@ Steer-backlog는 스티어링된 실행 이후 후속 응답을 받을 수 있
## 큐 옵션
옵션은 `followup`, `collect`, `steer-backlog`에 적용됩니다(스티어링이 후속 처리로 폴백될 때 `steer` 또는 레거시 `queue`에도 적용).
옵션은 `followup`, `collect`, `steer-backlog`에 적용됩니다(`steer` 또는 레거시 `queue`가 후속 처리로 대체되는 경우에도 적용).
- `debounceMs`: 큐에 있는 후속 항목을 처리하기 전의 조용한 창입니다. 단독 숫자는 밀리초이며, `/queue` 옵션에서는 단위 `ms`, `s`, `m`, `h`, `d`가 허용됩니다.
- `debounceMs`: 큐에 있는 후속 항목을 비우기 전 조용한 기간입니다. 단위 없는 숫자는 밀리초이며, `/queue` 옵션에서는 `ms`, `s`, `m`, `h`, `d` 단위를 사용할 수 있습니다.
- `cap`: 세션당 큐에 넣을 수 있는 최대 메시지 수입니다. `1`보다 작은 값은 무시됩니다.
- `drop: "summarize"`: 기본값입니다. 필요에 따라 가장 오래된 큐 항목을 삭제하고, 간결한 요약을 유지한 뒤 이를 합성 후속 프롬프트로 주입합니다.
- `drop: "old"`: 필요에 따라 가장 오래된 큐 항목을 삭제하되, 요약은 보존하지 않습니다.
- `drop: "new"`: 큐가 이미 가득 찬 경우 최신 메시지를 거부합니다.
- `drop: "summarize"`: 기본값입니다. 필요에 따라 가장 오래된 큐 항목을 버리고, 압축된 요약을 보관한 뒤 합성 후속 프롬프트로 주입합니다.
- `drop: "old"`: 필요에 따라 가장 오래된 큐 항목을 버리며, 요약은 보존하지 않습니다.
- `drop: "new"`: 큐가 이미 가득 차 있으면 최신 메시지를 거부합니다.
기본값: `debounceMs: 500`, `cap: 20`, `drop: summarize`.
## 우선순위
모드 선택 시 OpenClaw는 다음 순서로 확인합니다.
모드 선택 시 OpenClaw는 다음 순서로 해석합니다.
1. 인라인 또는 저장된 세션별 `/queue` 오버라이드.
1. 인라인 또는 저장된 세션별 `/queue` 재정의.
2. `messages.queue.byChannel.<channel>`.
3. `messages.queue.mode`.
4. 기본값 `steer`.
옵션의 경우 인라인 또는 저장된 `/queue` 옵션이 구성보다 우선합니다. 그다음 채널별 디바운스(`messages.queue.debounceMsByChannel`), Plugin 디바운스 기본값, 전역 `messages.queue` 옵션, 내장 기본값이 적용됩니다. `cap``drop`채널별 구성 키가 아니라 전역/세션 옵션입니다.
옵션의 경우 인라인 또는 저장된 `/queue` 옵션이 구성보다 우선합니다. 그다음 채널별 디바운스(`messages.queue.debounceMsByChannel`), Plugin 디바운스 기본값, 전역 `messages.queue` 옵션, 내장 기본값이 적용됩니다. `cap``drop`전역/세션 옵션이며, 채널별 구성 키가 아닙니다.
## 세션별 오버라이드
## 세션별 재정의
- 현재 세션의 모드를 저장하려면 `/queue <mode>`를 독립 명령으로 보냅니다.
- 옵션 조합할 수 있습니다: `/queue collect debounce:0.5s cap:25 drop:summarize`
- `/queue default` 또는 `/queue reset`은 세션 오버라이드를 지웁니다.
- 현재 세션의 모드를 저장하려면 `/queue <mode>`를 독립 실행 명령으로 전송합니다.
- 옵션 조합할 수 있습니다: `/queue collect debounce:0.5s cap:25 drop:summarize`
- `/queue default` 또는 `/queue reset`은 세션 재정의를 지웁니다.
## 범위 보장
## 범위 보장
- Gateway 응답 파이프라인을 사용하는 모든 인바운드 채널(WhatsApp 웹, Telegram, Slack, Discord, Signal, iMessage, 웹챗 등)의 자동 응답 에이전트 실행에 적용됩니다.
- 기본 레인(`main`)은 인바운드 및 main Heartbeat에 대해 프로세스 전역입니다. 여러 세션을 병렬로 허용하려면 `agents.defaults.maxConcurrent`를 설정하세요.
- 추가 레인(예: `cron`, `cron-nested`, `nested`, `subagent`)이 있을 수 있으므로 백그라운드 작업은 인바운드 응답을 차단하지 않고 병렬로 실행될 수 있습니다. 격리된 Cron 에이전트 턴은 내부 에이전트 실행이 `cron-nested`를 사용하는 동안 `cron` 슬롯을 보유합니다. 둘 다 `cron.maxConcurrentRuns`를 사용합니다. 공유 비-Cron `nested` 흐름은 자체 레인 동작을 유지합니다. 이러한 분리된 실행은 [백그라운드 작업](/ko/automation/tasks)으로 추적됩니다.
- 세션별 레인은 특정 세션을 동시에 하나의 에이전트 실행만 건드리도록 보장합니다.
- 외부 종속성이나 백그라운드 워커 스레드는 없습니다. 순수 TypeScript와 프로미스만 사용합니다.
- Gateway 응답 파이프라인을 사용하는 모든 수신 채널(WhatsApp web, Telegram, Slack, Discord, Signal, iMessage, webchat 등)의 자동 응답 에이전트 실행에 적용됩니다.
- 기본 레인(`main`)은 수신 + main Heartbeat에 대해 프로세스 전체에 적용됩니다. 여러 세션을 병렬로 허용하려면 `agents.defaults.maxConcurrent`를 설정하세요.
- 추가 레인(예: `cron`, `cron-nested`, `nested`, `subagent`)이 있을 수 있으므로 백그라운드 작업은 수신 응답을 막지 않고 병렬로 실행될 수 있습니다. 격리된 Cron 에이전트 턴은 내부 에이전트 실행이 `cron-nested`를 사용하는 동안 `cron` 슬롯을 보유합니다. 둘 다 `cron.maxConcurrentRuns`를 사용합니다. 공유 비-Cron `nested` 흐름은 자체 레인 동작을 유지합니다. 이러한 분리된 실행은 [백그라운드 작업](/ko/automation/tasks)으로 추적됩니다.
- 세션별 레인은 특정 세션을 한 번에 하나의 에이전트 실행만 건드리도록 보장합니다.
- 외부 의존성이나 백그라운드 워커 스레드가 없으며, 순수 TypeScript + promises입니다.
## 문제 해결
- 명령이 멈춘 것처럼 보이면 자세한 로그를 활성화하고 “queued for …ms” 줄을 찾아 큐가 처리되고 있는지 확인하세요.
- 명령이 멈춘 것처럼 보이면 자세한 로그를 활성화하고 “queued for …ms” 줄을 찾아 큐가 비워지고 있는지 확인하세요.
- 큐 깊이가 필요하면 자세한 로그를 활성화하고 큐 타이밍 줄을 확인하세요.
- 진단이 활성화되면 `diagnostics.stuckSessionWarnMs`를 지나 `processing` 상태로 남아 있는 세션은 멈춘 세션 경고를 기록합니다. 활성 임베디드 실행, 활성 응답 작업, 활성 레인 작업은 기본적으로 경고 전용으로 남습니다. 활성 세션 작업이 없는 오래된 시작 시점 장부 처리는 영향을 받은 세션 레인을 해제해 큐에 있는 작업이 처리되도록 할 수 있습니다.
- 턴을 수락한 뒤 진행 상황 출력을 멈추는 Codex app-server 실행은 Codex 어댑터가 중단하여, 외부 실행 타임아웃을 기다리지 않고 활성 세션 레인이 해제되도록 합니다.
- 진단이 활성화된 경우 `diagnostics.stuckSessionWarnMs`를 지나 `processing` 상태로 남아 있는 세션은 멈춘 세션 경고를 기록합니다. 활성 임베디드 실행, 활성 응답 작업, 활성 레인 작업은 기본적으로 경고만 남깁니다. 활성 세션 작업이 없는 오래된 시작 시점 장부 기록은 영향을 받은 세션 레인을 해제하여 큐에 있는 작업이 비워지도록 할 수 있습니다.
## 관련 항목
## 관련
- [세션 관리](/ko/concepts/session)
- [스티어링 큐](/ko/concepts/queue-steering)

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +1,59 @@
---
read_when:
- 테스트 실행 또는 수정하기
summary: 로컬에서 테스트를 실행하는 방법(vitest) 및 force/coverage 모드를 사용해야 하는 경우
summary: 로컬에서 테스트를 실행하는 방법(vitest)과 강제/커버리지 모드를 사용할 시점
title: 테스트
x-i18n:
generated_at: "2026-04-30T06:50:25Z"
generated_at: "2026-04-30T18:38:26Z"
model: gpt-5.5
provider: openai
source_hash: 9328d6f0383b5067fa8bb5d0f1bf22a3b9048a267908bf85167842ddc3d12e42
source_hash: 131f2bad3b2806d28394213cec38d632d106ddbf8ff04d06345ab8046fb8bcf2
source_path: reference/test.md
workflow: 16
---
- 전체 테스트 키트(스위트, 라이브, Docker): [테스트](/ko/help/testing)
- `pnpm test:force`: 기본 제어 포트를 점유한 남아 있는 Gateway 프로세스를 종료한 다음, 격리된 Gateway 포트로 전체 Vitest 스위트를 실행하여 서버 테스트가 실행 중인 인스턴스와 충돌하지 않게 합니다. 이전 Gateway 실행으로 포트 18789가 점유된 상태로 남아 있을 때 사용하세요.
- `pnpm test:coverage`: V8 커버리지(`vitest.unit.config.ts`를 통해)로 단위 스위트를 실행합니다. 이는 전체 저장소의 모든 파일 커버리지가 아니라, 로드된 파일 단위 커버리지 게이트입니다. 임계값은 줄/함수/문장 70%, 분기 55%입니다. `coverage.all`이 false이므로, 이 게이트는 모든 분할 레인 소스 파일을 미커버 상태로 취급하는 대신 단위 커버리지 스위트가 로드한 파일을 측정합니다.
- `pnpm test:force`: 기본 제어 포트를 점유하고 남아 있는 모든 gateway 프로세스를 종료한 다음, 서버 테스트가 실행 중인 인스턴스와 충돌하지 않도록 격리된 Gateway 포트로 전체 Vitest 제품군을 실행합니다. 이전 Gateway 실행 후 포트 18789가 점유된 상태로 남았을 때 사용하세요.
- `pnpm test:coverage`: `vitest.unit.config.ts`를 통해 V8 커버리지로 단위 제품군을 실행합니다. 이는 전체 저장소의 모든 파일 커버리지가 아니라, 로드된 파일 기준 단위 커버리지 게이트입니다. 임계값은 라인/함수/문장 70%, 브랜치 55%입니다. `coverage.all`이 false이므로 이 게이트는 모든 분할 레인 소스 파일을 미커버 파일로 취급하지 않고, 단위 커버리지 제품군이 로드한 파일을 측정합니다.
- `pnpm test:coverage:changed`: `origin/main` 이후 변경된 파일에 대해서만 단위 커버리지를 실행합니다.
- `pnpm test:changed`: 저렴한 스마트 변경 테스트 실행입니다. 직접 테스트 편집, 형제 `*.test.ts` 파일, 명시적 소스 매핑, 로컬 import 그래프에서 정확한 대상을 실행합니다. 넓은 범위의 config/package 변경은 정확한 테스트로 매핑되지 않는 한 건너뜁니다.
- `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`: 명시적인 넓은 범위 변경 테스트 실행입니다. 테스트 하네스/config/package 편집이 Vitest의 더 넓은 changed-test 동작으로 폴백해야 할 때 사용하세요.
- `pnpm changed:lanes`: `origin/main` 대비 diff가 트리거하는 아키텍처 레인을 표시합니다.
- `pnpm check:changed`: `origin/main` 대비 diff에 대해 스마트 변경 체크 게이트를 실행합니다. 영향을 받는 아키텍처 레인에 대해 typecheck, lint, guard 명령을 실행하지만 Vitest 테스트는 실행하지 않습니다. 테스트 증명에는 `pnpm test:changed` 또는 명시적 `pnpm test <target>`을 사용하세요.
- `pnpm test`: 명시적 파일/디렉터리 대상을 범위가 지정된 Vitest 레인으로 라우팅합니다. 대상이 없는 실행은 고정 shard 그룹을 사용하고 로컬 병렬 실행을 위해 leaf config로 확장합니다. extension 그룹은 하나의 거대한 root-project 프로세스 대신 항상 extension별 shard config로 확장됩니다.
- 테스트 래퍼 실행은 짧은 `[test] passed|failed|skipped ... in ...` 요약으로 끝납니다. Vitest 자체 duration 은 shard별 세부 정보로 유지됩니다.
- 공유 OpenClaw 테스트 상태: 테스트에 격리된 `HOME`, `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH`, config fixture, workspace, agent dir, auth-profile store가 필요할 때 Vitest에서 `src/test-utils/openclaw-test-state.ts`를 사용하세요.
- 프로세스 E2E 헬퍼: Vitest 프로세스 수준 E2E 테스트에 실행 중인 Gateway, CLI env, 로그 캡처, 정리가 한곳에 필요할 때 `test/helpers/openclaw-test-instance.ts`를 사용하세요.
- Docker/Bash E2E 헬퍼: `scripts/lib/docker-e2e-image.sh`를 source하는 레인은 `docker_e2e_test_state_shell_b64 <label> <scenario>`를 컨테이너에 전달하고 `scripts/lib/openclaw-e2e-instance.sh`로 디코드할 수 있습니다. multi-home 스크립트는 `docker_e2e_test_state_function_b64`를 전달하고 각 flow에서 `openclaw_test_state_create <label> <scenario>`를 호출할 수 있습니다. 더 낮은 수준의 호출자는 컨테이너 내부 shell snippet에는 `scripts/lib/openclaw-test-state.mjs shell --label <name> --scenario <name>`를, source 가능한 호스트 env 파일에는 `node scripts/lib/openclaw-test-state.mjs -- create --label <name> --scenario <name> --env-file <path> --json`을 사용할 수 있습니다. `create` 앞의 `--`최신 Node 런타임이 `--env-file`을 Node flag로 처리하지 않게 합니다. Gateway를 시작하는 Docker/Bash 레인은 컨테이너 내부에서 `scripts/lib/openclaw-e2e-instance.sh`를 source하여 entrypoint 해석, mock OpenAI 시작, Gateway foreground/background 실행, readiness probe, 상태 env export, 로그 dump, 프로세스 정리를 수행할 수 있습니다.
- 전체, extension, include-pattern shard 실행은 `.artifacts/vitest-shard-timings.json`의 로컬 timing 데이터를 업데이트합니다. 이후 whole-config 실행은 이 timing을 사용해 느린 shard와 빠른 shard의 균형을 맞춥니다. Include-pattern CI shard는 timing key에 shard 이름을 덧붙여, whole-config timing 데이터를 대체하지 않고 필터링된 shard timing이 보이도록 유지합니다. 로컬 timing artifact를 무시하려면 `OPENCLAW_TEST_PROJECTS_TIMINGS=0`을 설정하세요.
- 선택된 `plugin-sdk``commands` 테스트 파일은 이제 전용 경량 레인을 통해 라우팅되`test/setup.ts`만 유지하고, 런타임이 무거운 케이스는 기존 레인에 남겨 둡니다.
- 형제 테스트가 있는 소스 파일은 더 넓은 디렉터리 glob으로 폴백하기 전에 해당 형제 테스트에 매핑됩니다. `src/channels/plugins/contracts/test-helpers`, `src/plugin-sdk/test-helpers`, `src/plugins/contracts` 아래의 헬퍼 편집은 dependency path가 정확할 때 모든 shard를 넓게 실행하는 대신 로컬 import 그래프를 사용해 import하는 테스트를 실행합니다.
- `auto-reply`는 이제 세 개의 전용 config(`core`, `top-level`, `reply`)로도 분할되어 reply 하네스가 더 가벼운 top-level status/token/helper 테스트를 지배하지 않게 합니다.
- 기본 Vitest config는 이제 `pool: "threads"` `isolate: false`를 기본값으로 사용하며, 공유 non-isolated runner가 저장소 config 전반에서 활성화됩니다.
- `pnpm test:changed`: 저비용 스마트 변경 테스트 실행입니다. 직접 테스트 편집, 형제 `*.test.ts` 파일, 명시적 소스 매핑, 로컬 import 그래프에서 정확한 대상을 실행합니다. 광범위한/config/package 변경은 정확한 테스트로 매핑되지 않는 한 건너뜁니다.
- `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`: 명시적 광범위 변경 테스트 실행입니다. 테스트 하니스/config/package 편집이 Vitest의 더 넓은 변경 테스트 동작으로 폴백해야 할 때 사용하세요.
- `pnpm changed:lanes`: `origin/main`과의 diff로 트리거된 아키텍처 레인을 표시합니다.
- `pnpm check:changed`: `origin/main`과의 diff에 대해 스마트 변경 체크 게이트를 실행합니다. 영향을 받는 아키텍처 레인에 대해 typecheck, lint, guard 명령을 실행하지만 Vitest 테스트는 실행하지 않습니다. 테스트 증명에는 `pnpm test:changed` 또는 명시적 `pnpm test <target>`을 사용하세요.
- `pnpm test`: 명시적 파일/디렉터리 대상을 범위가 지정된 Vitest 레인으로 라우팅합니다. 대상이 없는 실행은 고정 shard 그룹을 사용하고 로컬 병렬 실행을 위해 leaf config로 확장됩니다. 확장 그룹은 항상 하나의 거대한 루트 프로젝트 프로세스 대신 확장별 shard config로 확장됩니다.
- 테스트 래퍼 실행은 짧은 `[test] passed|failed|skipped ... in ...` 요약으로 끝납니다. Vitest 자체 duration 라인은 shard별 세부 정보로 유지됩니다.
- 공유 OpenClaw 테스트 상태: 테스트에 격리된 `HOME`, `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH`, config fixture, workspace, agent dir 또는 auth-profile store가 필요할 때 Vitest에서 `src/test-utils/openclaw-test-state.ts`를 사용하세요.
- 프로세스 E2E 헬퍼: Vitest 프로세스 수준 E2E 테스트에 실행 중인 Gateway, CLI env, 로그 캡처, 정리가 한곳에 필요할 때 `test/helpers/openclaw-test-instance.ts`를 사용하세요.
- Docker/Bash E2E 헬퍼: `scripts/lib/docker-e2e-image.sh`를 source하는 레인은 `docker_e2e_test_state_shell_b64 <label> <scenario>`를 컨테이너로 전달하고 `scripts/lib/openclaw-e2e-instance.sh`로 디코드할 수 있습니다. 다중 홈 스크립트는 `docker_e2e_test_state_function_b64`를 전달하고 각 흐름에서 `openclaw_test_state_create <label> <scenario>`를 호출할 수 있습니다. 더 낮은 수준의 호출자는 컨테이너 내부 shell snippet에는 `scripts/lib/openclaw-test-state.mjs shell --label <name> --scenario <name>` 사용할 수 있고, source 가능한 호스트 env 파일에는 `node scripts/lib/openclaw-test-state.mjs -- create --label <name> --scenario <name> --env-file <path> --json`을 사용할 수 있습니다. `create` 앞의 `--`더 새로운 Node 런타임이 `--env-file`을 Node 플래그로 취급하지 않게 합니다. Gateway를 시작하는 Docker/Bash 레인은 컨테이너 안에서 `scripts/lib/openclaw-e2e-instance.sh`를 source하여 entrypoint 해석, mock OpenAI 시작, Gateway foreground/background 시작, readiness probe, 상태 env export, 로그 dump, 프로세스 정리를 수행할 수 있습니다.
- 전체, 확장, include-pattern shard 실행은 `.artifacts/vitest-shard-timings.json`의 로컬 timing 데이터를 갱신합니다. 이후 whole-config 실행은 이 timing을 사용해 느린 shard와 빠른 shard의 균형을 맞춥니다. include-pattern CI shard는 timing key에 shard 이름을 추가하여, whole-config timing 데이터를 대체하지 않고 필터링된 shard timing이 보이도록 유지합니다. 로컬 timing artifact를 무시하려면 `OPENCLAW_TEST_PROJECTS_TIMINGS=0`을 설정하세요.
- 선택된 `plugin-sdk``commands` 테스트 파일은 이제 전용 경량 레인을 통해 라우팅되며, 해당 레인은 `test/setup.ts`만 유지하고 runtime-heavy case는 기존 레인에 남깁니다.
- 형제 테스트가 있는 소스 파일은 더 넓은 디렉터리 glob로 폴백하기 전에 해당 형제 테스트로 매핑됩니다. `src/channels/plugins/contracts/test-helpers`, `src/plugin-sdk/test-helpers`, `src/plugins/contracts` 아래의 헬퍼 편집은 dependency 경로가 정확할 때 모든 shard를 광범위하게 실행하는 대신 로컬 import 그래프를 사용해 import하는 테스트를 실행합니다.
- `auto-reply`는 이제 세 개의 전용 config(`core`, `top-level`, `reply`)로도 분할되어 reply 하니스가 더 가벼운 top-level status/token/helper 테스트를 지배하지 않도록 합니다.
- 기본 Vitest config는 이제 `pool: "threads"` `isolate: false`를 기본값으로 사용하며, 공유 non-isolated runner가 저장소 config 전반에서 활성화됩니다.
- `pnpm test:channels``vitest.channels.config.ts`를 실행합니다.
- `pnpm test:extensions``pnpm test extensions`는 모든 extension/Plugin shard를 실행합니다. 무거운 채널 Plugin, 브라우저 Plugin, OpenAI는 전용 shard로 실행되고, 다른 Plugin 그룹은 batched 상태로 유지됩니다. 번들 Plugin 레인 하나에는 `pnpm test extensions/<id>`를 사용하세요.
- `pnpm test:perf:imports`: 명시적 파일/디렉터리 대상에는 여전히 범위 지정 레인 라우팅을 사용하면서 Vitest import-duration 및 import-breakdown 보고를 활성화합니다.
- `pnpm test:perf:imports:changed`: 동일한 import profiling이지만 `origin/main` 이후 변경된 파일에 대해서만 행합니다.
- `pnpm test:extensions``pnpm test extensions`는 모든 확장/Plugin shard를 실행합니다. 무거운 채널 Plugin, 브라우저 Plugin, OpenAI는 전용 shard로 실행되고, 다른 Plugin 그룹은 batched 상태를 유지합니다. 번들 Plugin 레인 하나에는 `pnpm test extensions/<id>`를 사용하세요.
- `pnpm test:perf:imports`: Vitest import-duration 및 import-breakdown 보고를 활성화하면서도, 명시적 파일/디렉터리 대상에는 범위 지정 레인 라우팅을 계속 사용합니다.
- `pnpm test:perf:imports:changed`: 동일한 import profiling이지만 `origin/main` 이후 변경된 파일에 대해서만 행합니다.
- `pnpm test:perf:changed:bench -- --ref <git-ref>`는 동일한 커밋된 git diff에 대해 라우팅된 changed-mode 경로를 네이티브 root-project 실행과 비교해 벤치마크합니다.
- `pnpm test:perf:changed:bench -- --worktree`는 먼저 커밋하지 않고 현재 worktree 변경 세트를 벤치마크합니다.
- `pnpm test:perf:profile:main`: Vitest main thread의 CPU profile을 씁니다(`.artifacts/vitest-main-profile`).
- `pnpm test:perf:profile:runner`: unit runner의 CPU 및 heap profile을 씁니다(`.artifacts/vitest-runner-profile`).
- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`: 모든 full-suite Vitest leaf config를 직렬로 실행하고 grouped duration 데이터와 config별 JSON/log artifact를 씁니다. Test Performance Agent는 느린 테스트 수정을 시도하기 전 이를 baseline으로 사용합니다.
- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`: 성능 중심 변경 이후 grouped report를 비교합니다.
- `pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json`: 모든 full-suite Vitest leaf config를 직렬로 실행하고, per-config JSON/log artifact와 함께 그룹화된 duration 데이터를 씁니다. Test Performance Agent는 느린 테스트 수정을 시도하기 전 이를 baseline으로 사용합니다.
- `pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json`: 성능 중심 변경 후 그룹화된 report를 비교합니다.
- Gateway 통합: `OPENCLAW_TEST_INCLUDE_GATEWAY=1 pnpm test` 또는 `pnpm test:gateway`로 opt-in합니다.
- `pnpm test:e2e`: Gateway end-to-end smoke test(multi-instance WS/HTTP/node pairing)를 실행합니다. `vitest.e2e.config.ts`에서 adaptive worker와 함께 `threads` + `isolate: false`가 기본값입니다. `OPENCLAW_E2E_WORKERS=<n>`로 조정하고 자세한 로그에는 `OPENCLAW_E2E_VERBOSE=1`을 설정하세요.
- `pnpm test:live`: provider live test(minimax/zai)를 실행합니다. 건너뛰기를 해제하려면 API key와 `LIVE=1`(또는 provider별 `*_LIVE_TEST=1`)이 필요합니다.
- `pnpm test:docker:all`: 공유 live-test 이미지를 빌드하고, OpenClaw를 npm tarball로 한 번 pack하고, bare Node/Git runner 이미지와 해당 tarball을 `/app`에 설치하는 functional 이미지를 빌드/재사용한 다음, weighted scheduler를 통해 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 Docker smoke 레인을 실행합니다. bare 이미지(`OPENCLAW_DOCKER_E2E_BARE_IMAGE`)는 installer/update/plugin-dependency 레인에 사용되며, 이 레인들은 복사된 저장소 소스를 사용하는 대신 prebuilt tarball을 mount합니다. functional 이미지(`OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`)는 일반 built-app 기능 레인에 사용됩니다. `scripts/package-openclaw-for-docker.mjs`는 단일 local/CI package packer이며 Docker가 사용하기 전에 tarball과 `dist/postinstall-inventory.json`을 검증합니다. Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, planner 로직은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, `scripts/test-docker-all.mjs`가 선택된 plan을 실행합니다. `node scripts/test-docker-all.mjs --plan-json`은 Docker를 빌드하거나 실행하지 않고 선택된 레인, 이미지 종류, package/live-image 필요성, 상태 scenario, credential check에 대한 scheduler 소유 CI plan을 출력합니다. `OPENCLAW_DOCKER_ALL_PARALLELISM=<n>`은 프로세스 slot을 제어하며 기본값은 10입니다. `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>`은 provider-sensitive tail pool을 제어하며 기본값은 10입니다. 무거운 레인 cap 기본값은 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10`, `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`이고, provider cap 기본값은 `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4`를 통해 provider당 하나의 무거운 레인입니다. 더 큰 호스트에는 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 또는 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`를 사용하세요. 저병렬 host에서 하나의 레인이 effective weight 또는 resource cap을 초과해도, 빈 pool에서 시작할 수 있으며 capacity를 release할 때까지 단독으로 실행됩니다. 레인 시작은 로컬 Docker daemon create storm을 피하기 위해 기본적으로 2초 간격으로 stagger됩니다. `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>`로 override하세요. runner는 기본적으로 Docker를 preflight하고, 오래된 OpenClaw E2E container를 정리하고, 30초마다 active-lane status를 출력하고, 호환되는 레인 간 provider CLI tool cache를 공유하고, transient live-provider failure를 기본적으로 한 번 retry하며(`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=<n>`), 이후 실행에서 longest-first ordering을 위해 lane timing을 `.artifacts/docker-tests/lane-timings.json`에 저장합니다. Docker를 실행하지 않고 레인 manifest를 출력하려면 `OPENCLAW_DOCKER_ALL_DRY_RUN=1`을, status 출력 조정에는 `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>`를, timing 재사용 비활성화에는 `OPENCLAW_DOCKER_ALL_TIMINGS=0`을 사용하세요. 결정적/local 레인만 실행하려면 `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip`을, live-provider 레인만 실행하려면 `OPENCLAW_DOCKER_ALL_LIVE_MODE=only`를 사용하세요. package alias는 `pnpm test:docker:local:all``pnpm test:docker:live:all`입니다. Live-only mode는 main 및 tail live 레인을 하나의 longest-first pool로 병합하여 provider bucket이 Claude, Codex, Gemini 작업을 함께 pack할 수 있게 합니다. runner는 `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`이 설정되지 않은 한 첫 failure 이후 새 pooled lane scheduling을 중단하며, 각 레인은 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`로 override 가능한 120분 fallback timeout을 갖습니다. 선택된 live/tail 레인은 더 엄격한 레인별 cap을 사용합니다. CLI backend Docker setup 명령에는 `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS`를 통한 자체 timeout이 있습니다(기본값 180). 레인별 로그, `summary.json`, `failures.json`, phase timing은 `.artifacts/docker-tests/<run-id>/` 아래에 기록됩니다. 느린 레인을 검사하려면 `pnpm test:docker:timings <summary.json>`를, 저렴한 targeted rerun 명령을 출력하려면 `pnpm test:docker:rerun <run-id|summary.json|failures.json>`을 사용하세요.
- `pnpm test:docker:browser-cdp-snapshot`: Chromium 기반 source E2E container를 빌드하고, raw CDP와 격리된 Gateway를 시작하고, `browser doctor --deep`를 실행한 다음, CDP role snapshot에 link URL, cursor-promoted clickable, iframe ref, frame metadata가 포함되는지 검증합니다.
- CLI backend live Docker probe는 focused lane으로 실행할 수 있습니다. 예: `pnpm test:docker:live-cli-backend:codex`, `pnpm test:docker:live-cli-backend:codex:resume`, `pnpm test:docker:live-cli-backend:codex:mcp`. Claude와 Gemini에는 일치하는 `:resume``:mcp` alias가 있습니다.
- `pnpm test:docker:openwebui`: Dockerized OpenClaw + Open WebUI를 시작하고, Open WebUI를 통해 sign in하고, `/api/models`를 확인한 다음, `/api/chat/completions`를 통해 실제 proxied chat을 실행합니다. 사용 가능한 live model key(예: `~/.profile`의 OpenAI)가 필요하고, 외부 Open WebUI 이미지를 pull하며, 일반 unit/e2e suite처럼 CI에서 안정적일 것으로 기대되지는 않습니다.
- `pnpm test:docker:mcp-channels`: seeded Gateway container와 `openclaw mcp serve`를 spawn하는 두 번째 client container를 시작한 다음, 실제 stdio bridge를 통해 routed conversation discovery, transcript read, attachment metadata, live event queue behavior, outbound send routing, Claude-style channel 및 permission notification을 검증합니다. Claude notification assertion은 raw stdio MCP frame을 직접 읽기 때문에 smoke는 bridge가 실제로 내보내는 내용을 반영합니다.
- `pnpm test:e2e`: Gateway end-to-end smoke test를 실행합니다(다중 인스턴스 WS/HTTP/node pairing). `vitest.e2e.config.ts`에서 adaptive worker와 함께 기본값은 `threads` + `isolate: false`입니다. `OPENCLAW_E2E_WORKERS=<n>`로 조정하고 자세한 로그에는 `OPENCLAW_E2E_VERBOSE=1`을 설정하세요.
- `pnpm test:live`: provider live test를 실행합니다(minimax/zai). 건너뛰기를 해제하려면 API key와 `LIVE=1` 또는 provider별 `*_LIVE_TEST=1`이 필요합니다.
- `pnpm test:docker:all`: 공유 live-test 이미지를 빌드하고, OpenClaw를 한 번 npm tarball로 패킹하며, bare Node/Git runner 이미지와 해당 tarball을 `/app`에 설치하는 functional 이미지를 빌드/재사용한 다음, `OPENCLAW_SKIP_DOCKER_BUILD=1`로 weighted scheduler를 통해 Docker smoke 레인을 실행합니다. bare 이미지(`OPENCLAW_DOCKER_E2E_BARE_IMAGE`)는 installer/update/plugin-dependency 레인에 사용되며, 해당 레인은 복사된 저장소 소스 대신 미리 빌드된 tarball을 마운트합니다. functional 이미지(`OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE`)는 일반 built-app 기능 레인에 사용됩니다. `scripts/package-openclaw-for-docker.mjs`는 단일 local/CI package packer이며, Docker가 사용하기 전에 tarball과 `dist/postinstall-inventory.json`을 검증합니다. Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, planner logic은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, `scripts/test-docker-all.mjs`가 선택된 plan을 실행합니다. `node scripts/test-docker-all.mjs --plan-json`은 Docker를 빌드하거나 실행하지 않고, 선택된 레인, 이미지 종류, package/live-image 필요 여부, 상태 scenario, credential check에 대한 scheduler 소유 CI plan을 출력합니다. `OPENCLAW_DOCKER_ALL_PARALLELISM=<n>`은 프로세스 슬롯을 제어하며 기본값은 10입니다. `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM=<n>`은 provider-sensitive tail pool을 제어하며 기본값은 10입니다. 무거운 레인 cap의 기본값은 `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10`, `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`이고, provider cap은 `OPENCLAW_DOCKER_ALL_LIVE_CLAUDE_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_CODEX_LIMIT=4`, `OPENCLAW_DOCKER_ALL_LIVE_GEMINI_LIMIT=4`를 통해 provider당 무거운 레인 하나가 기본값입니다. 더 큰 호스트에는 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 또는 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`를 사용하세요. 낮은 병렬성 호스트에서 한 레인이 effective weight 또는 resource cap을 초과해도, 빈 pool에서 시작하여 capacity를 해제할 때까지 단독으로 실행될 수 있습니다. 레인 시작은 로컬 Docker daemon create storm을 피하기 위해 기본적으로 2초씩 엇갈리게 진행됩니다. `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=<ms>`로 재정의하세요. runner는 기본적으로 Docker를 preflight하고, 오래된 OpenClaw E2E 컨테이너를 정리하며, 30초마다 active-lane 상태를 출력하고, 호환되는 레인 간 provider CLI tool cache를 공유하며, 일시적 live-provider 실패를 기본적으로 한 번 재시도하고(`OPENCLAW_DOCKER_ALL_LIVE_RETRIES=<n>`), 이후 실행에서 longest-first ordering을 위해 `.artifacts/docker-tests/lane-timings.json`에 레인 timing을 저장합니다. Docker를 실행하지 않고 레인 manifest를 출력하려면 `OPENCLAW_DOCKER_ALL_DRY_RUN=1`을 사용하고, 상태 출력을 조정하려면 `OPENCLAW_DOCKER_ALL_STATUS_INTERVAL_MS=<ms>`를 사용하며, timing 재사용을 비활성화하려면 `OPENCLAW_DOCKER_ALL_TIMINGS=0`을 사용하세요. 결정적/로컬 레인만 실행하려면 `OPENCLAW_DOCKER_ALL_LIVE_MODE=skip`을 사용하고, live-provider 레인만 실행하려면 `OPENCLAW_DOCKER_ALL_LIVE_MODE=only`를 사용하세요. package alias는 `pnpm test:docker:local:all``pnpm test:docker:live:all`입니다. live-only 모드는 main 및 tail live 레인을 하나의 longest-first pool로 병합하여 provider bucket이 Claude, Codex, Gemini 작업을 함께 pack할 수 있게 합니다. runner는 `OPENCLAW_DOCKER_ALL_FAIL_FAST=0`이 설정되지 않는 한 첫 번째 실패 후 새 pooled 레인 scheduling을 중지하며, 각 레인은 `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`로 재정의 가능한 120분 fallback timeout을 갖습니다. 선택된 live/tail 레인은 더 엄격한 per-lane cap을 사용합니다. CLI backend Docker setup 명령에는 `OPENCLAW_LIVE_CLI_BACKEND_SETUP_TIMEOUT_SECONDS`를 통한 자체 timeout이 있습니다(기본값 180). 레인별 로그, `summary.json`, `failures.json`, phase timing은 `.artifacts/docker-tests/<run-id>/` 아래에 기록됩니다. 느린 레인을 검사하려면 `pnpm test:docker:timings <summary.json>`를 사용하고, 저비용 targeted rerun 명령을 출력하려면 `pnpm test:docker:rerun <run-id|summary.json|failures.json>`을 사용하세요.
- `pnpm test:docker:browser-cdp-snapshot`: Chromium 기반 source E2E 컨테이너를 빌드하고, raw CDP와 격리된 Gateway를 시작하며, `browser doctor --deep`을 실행하고, CDP role snapshot에 link URL, cursor-promoted clickable, iframe ref, frame metadata가 포함되는지 검증합니다.
- CLI backend live Docker probe는 focused lane으로 실행할 수 있습니다. 예를 들어 `pnpm test:docker:live-cli-backend:codex`, `pnpm test:docker:live-cli-backend:codex:resume`, `pnpm test:docker:live-cli-backend:codex:mcp`입니다. Claude와 Gemini에도 일치하는 `:resume``:mcp` alias가 있습니다.
- `pnpm test:docker:openwebui`: Dockerized OpenClaw + Open WebUI를 시작하고, Open WebUI를 통해 sign in하고, `/api/models`를 확인한 다음, `/api/chat/completions`를 통해 실제 proxied chat을 실행합니다. 사용 가능한 live model key가 필요하며(예: `~/.profile`의 OpenAI), 외부 Open WebUI 이미지를 pull하고, 일반 unit/e2e 제품군처럼 CI-stable할 것으로 기대되지 않습니다.
- `pnpm test:docker:mcp-channels`: seeded Gateway 컨테이너와 `openclaw mcp serve`를 spawn하는 두 번째 client 컨테이너를 시작한 다음, routed conversation discovery, transcript read, attachment metadata, live event queue 동작, outbound send routing, 그리고 실제 stdio bridge를 통한 Claude 스타일 channel + permission notification을 검증합니다. Claude notification assertion은 raw stdio MCP frame을 직접 읽으므로 smoke가 bridge가 실제로 emit하는 내용을 반영합니다.
- `pnpm test:docker:upgrade-survivor`: 더티한 이전 사용자 fixture 위에 패키징된 OpenClaw tarball을 설치하고, 라이브 제공자 또는 채널 키 없이 패키지 업데이트와 비대화형 doctor를 실행한 다음, 루프백 Gateway를 시작하고 에이전트, 채널 구성, Plugin 허용 목록, 워크스페이스/세션 파일, 오래된 Plugin `runtime-deps` 상태, 시작, RPC 상태가 유지되는지 확인합니다.
## 로컬 PR 게이트
로컬 PR 랜딩/게이트 검사의 경우 다음을 실행하세요.
로컬 PR 랜딩/게이트 검사를 위해 다음을 실행하세요:
- `pnpm check:changed`
- `pnpm check`
@ -61,27 +62,27 @@ x-i18n:
- `pnpm test`
- `pnpm check:docs`
부하가 걸린 호스트에서 `pnpm test`가 불안정하게 실패하면 회귀로 간주하기 전에 한 번 다시 실행한 다음, `pnpm test <path/to/test>`로 격리하세요. 메모리가 제한된 호스트에서는 다음을 사용하세요.
부하가 걸린 호스트에서 `pnpm test`가 불안정하게 실패하면 회귀로 취급하기 전에 한 번 다시 실행한 다음, `pnpm test <path/to/test>`로 격리하세요. 메모리가 제한된 호스트에서는 다음을 사용하세요:
- `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`
- `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/tmp/openclaw-vitest-cache pnpm test:changed`
## 모델 지연 시간 벤치마크(로컬 키)
## 모델 지연 시간 벤치(로컬 키)
스크립트: [`scripts/bench-model.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/bench-model.ts)
사용법:
- `source ~/.profile && pnpm tsx scripts/bench-model.ts --runs 10`
- 선택적 환경 변수: `MINIMAX_API_KEY`, `MINIMAX_BASE_URL`, `MINIMAX_MODEL`, `ANTHROPIC_API_KEY`
- 기본 프롬프트: “단어 하나로만 답하세요: ok. 문장 부호나 추가 텍스트는 넣지 마세요.”
- 선택적 env: `MINIMAX_API_KEY`, `MINIMAX_BASE_URL`, `MINIMAX_MODEL`, `ANTHROPIC_API_KEY`
- 기본 프롬프트: “단어 하나로만 답하세요: ok. 구두점이나 추가 텍스트는 넣지 마세요.”
마지막 실행(2025-12-31, 20회 실행):
- minimax 중앙값 1279ms(최소 1114, 최대 2431)
- opus 중앙값 2454ms(최소 1224, 최대 3170)
## CLI 시작 벤치마크
## CLI 시작 벤치
스크립트: [`scripts/bench-cli-startup.ts`](https://github.com/openclaw/openclaw/blob/main/scripts/bench-cli-startup.ts)
@ -109,41 +110,41 @@ x-i18n:
- `real`: `health`, `status`, `status --json`, `sessions`, `sessions --json`, `tasks --json`, `tasks list --json`, `tasks audit --json`, `agents list --json`, `gateway status`, `gateway status --json`, `gateway health --json`, `config get gateway.port`
- `all`: 두 프리셋 모두
출력에는 각 명령의 `sampleCount`, 평균, p50, p95, 최소/최대, 종료 코드/시그널 분포, 최대 RSS 요약이 포함됩니다. 선택적 `--cpu-prof-dir` / `--heap-prof-dir`는 실행별 V8 프로필을 기록하므로 타이밍과 프로필 캡처가 같은 하네스를 사용합니다.
출력에는 각 명령의 `sampleCount`, 평균, p50, p95, 최소/최대, 종료 코드/시그널 분포, 최대 RSS 요약이 포함됩니다. 선택적 `--cpu-prof-dir` / `--heap-prof-dir`는 실행마다 V8 프로필을 작성하므로 타이밍과 프로필 캡처가 동일한 하네스를 사용합니다.
저장된 출력 규칙:
- `pnpm test:startup:bench:smoke`는 대상 스모크 아티팩트를 `.artifacts/cli-startup-bench-smoke.json`기록합니다.
- `pnpm test:startup:bench:save``runs=5``warmup=1`을 사용해 전체 제품군 아티팩트를 `.artifacts/cli-startup-bench-all.json`에 기록합니다.
- `pnpm test:startup:bench:update``runs=5``warmup=1`을 사용해 체크인된 기준 픽스처를 `test/fixtures/cli-startup-bench.json`에서 새로 고칩니다.
- `pnpm test:startup:bench:smoke`는 대상 스모크 아티팩트를 `.artifacts/cli-startup-bench-smoke.json`작성합니다
- `pnpm test:startup:bench:save``runs=5``warmup=1`을 사용해 전체 스위트 아티팩트를 `.artifacts/cli-startup-bench-all.json`에 작성합니다
- `pnpm test:startup:bench:update``runs=5``warmup=1`을 사용해 체크인된 기준 픽스처를 `test/fixtures/cli-startup-bench.json`에서 새로 고칩니다
체크인된 픽스처:
- `test/fixtures/cli-startup-bench.json`
- `pnpm test:startup:bench:update`로 새로 고치세요.
- `pnpm test:startup:bench:check`로 현재 결과를 픽스처와 비교하세요.
- `pnpm test:startup:bench:update`로 새로 고치세요
- `pnpm test:startup:bench:check`로 현재 결과를 픽스처와 비교하세요
## 온보딩 E2E(Docker)
Docker는 선택 사항입니다. 컨테이너화된 온보딩 스모크 테스트에만 필요합니다.
Docker는 선택 사항입니다. 이는 컨테이너화된 온보딩 스모크 테스트에만 필요합니다.
깨끗한 Linux 컨테이너에서 전체 콜드 스타트 흐름:
깨끗한 Linux 컨테이너에서 전체 콜드 스타트 흐름:
```bash
scripts/e2e/onboard-docker.sh
```
이 스크립트는 의사 tty를 통해 대화형 마법사를 구동하고, config/workspace/session 파일을 검증한 다음 Gateway를 시작하고 `openclaw health`를 실행합니다.
이 스크립트는 pseudo-tty를 통해 대화형 마법사를 구동하고, config/workspace/session 파일을 확인한 다음, Gateway를 시작하고 `openclaw health`를 실행합니다.
## QR 가져오기 스모크(Docker)
지원되는 Docker Node 런타임(Node 24 기본값, Node 22 호환)에서 유지 관리되는 QR 런타임 헬퍼가 로드되는지 확인합니다.
유지 관리되는 QR 런타임 헬퍼가 지원되는 Docker Node 런타임(Node 24 기본값, Node 22 호환)에서 로드되는지 확인합니다:
```bash
pnpm test:docker:qr
```
## 관련 문서
## 관련 항목
- [테스트](/ko/help/testing)
- [라이브 테스트](/ko/help/testing-live)