From 4b9fa9cdffe4e8821c73bad310b37b43f9eb75d2 Mon Sep 17 00:00:00 2001 From: "openclaw-docs-i18n[bot]" Date: Thu, 30 Apr 2026 18:41:40 +0000 Subject: [PATCH] chore(i18n): refresh ko translations --- docs/ko/ci.md | 330 +++++++------- docs/ko/concepts/agent-loop.md | 201 ++++---- docs/ko/concepts/queue.md | 83 ++-- docs/ko/help/testing.md | 808 +++++++++++++++++---------------- docs/ko/reference/test.md | 97 ++-- 5 files changed, 764 insertions(+), 755 deletions(-) diff --git a/docs/ko/ci.md b/docs/ko/ci.md index d2ef91034..a30622dfe 100644 --- a/docs/ko/ci.md +++ b/docs/ko/ci.md @@ -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= -f include_andro gh workflow run full-release-validation.yml --ref main -f ref= ``` -## 실행기 +## 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:` 이미지를 사용합니다. live 릴리스 워크플로는 해당 이미지를 한 번 빌드하고 푸시한 다음, Docker live 모델, Gateway, CLI 백엔드, ACP bind, Codex harness 샤드가 `OPENCLAW_SKIP_DOCKER_BUILD=1`로 실행됩니다. 이러한 샤드가 전체 소스 Docker 대상을 독립적으로 다시 빌드한다면 릴리스 실행이 잘못 구성된 것이며 중복 이미지 빌드로 벽시계 시간을 낭비하게 됩니다. +Docker 기반 라이브 모델/백엔드 샤드는 선택된 커밋마다 별도의 공유 `ghcr.io/openclaw/openclaw-live-test:` 이미지를 사용합니다. 라이브 릴리스 워크플로는 해당 이미지를 한 번 빌드하고 푸시한 다음, 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=`, `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=`, `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 # Docker 아티팩트를 다운로드하고 결합/레인별 대상 재실행 명령을 출력합니다 -pnpm test:docker:timings # 느린 레인 및 단계 중요 경로 요약 +pnpm test:docker:rerun # download Docker artifacts and print combined/per-lane targeted rerun commands +pnpm test:docker:timings # 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에는 더 큰 밀리초 값을 사용하세요. ## 관련 항목 diff --git a/docs/ko/concepts/agent-loop.md b/docs/ko/concepts/agent-loop.md index 7db235274..87ceade28 100644 --- a/docs/ko/concepts/agent-loop.md +++ b/docs/ko/concepts/agent-loop.md @@ -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..timeoutSeconds`는 느린 로컬/셀프 호스팅 제공자에 대해 이 유휴 워치독을 연장합니다. 그렇지 않으면 OpenClaw는 구성된 경우 `agents.defaults.timeoutSeconds`를 사용하며, 기본적으로 120초로 제한됩니다. 명시적 모델 또는 에이전트 타임아웃이 없는 Cron 트리거 실행은 유휴 워치독을 비활성화하고 cron 외부 타임아웃에 의존합니다. -- 제공자 HTTP 요청 타임아웃: `models.providers..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..timeoutSeconds`는 느린 local loopback/자체 호스팅 공급자를 위해 이 유휴 watchdog을 연장합니다. 그렇지 않으면 OpenClaw는 구성된 경우 `agents.defaults.timeoutSeconds`를 사용하며, 기본적으로 120초로 제한됩니다. 명시적 모델 또는 에이전트 시간 초과가 없는 Cron 트리거 실행은 유휴 watchdog을 비활성화하고 Cron 외부 시간 초과에 의존합니다. +- 공급자 HTTP 요청 시간 초과: `models.providers..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 수준 구성 diff --git a/docs/ko/concepts/queue.md b/docs/ko/concepts/queue.md index aa13d1e36..fbec35bbb 100644 --- a/docs/ko/concepts/queue.md +++ b/docs/ko/concepts/queue.md @@ -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:`)별로 큐에 넣어 세션당 활성 실행이 하나만 있도록 보장합니다. -- 그런 다음 각 세션 실행은 **전역 레인**(기본값은 `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.`. 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 `를 독립 명령으로 보냅니다. -- 옵션을 조합할 수 있습니다: `/queue collect debounce:0.5s cap:25 drop:summarize` -- `/queue default` 또는 `/queue reset`은 세션 오버라이드를 지웁니다. +- 현재 세션의 모드를 저장하려면 `/queue `를 독립 실행 명령으로 전송합니다. +- 옵션은 조합할 수 있습니다: `/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) diff --git a/docs/ko/help/testing.md b/docs/ko/help/testing.md index 00b5faded..0bb51dee7 100644 --- a/docs/ko/help/testing.md +++ b/docs/ko/help/testing.md @@ -1,198 +1,196 @@ --- read_when: - 로컬 또는 CI에서 테스트 실행 - - 모델/프로바이더 버그에 대한 회귀 테스트 추가 + - 모델/제공자 버그에 대한 회귀 테스트 추가 - Gateway + 에이전트 동작 디버깅 -summary: '테스트 키트: 단위/e2e/라이브 스위트, Docker 러너, 각 테스트의 적용 범위' +summary: '테스트 키트: 단위/e2e/라이브 스위트, Docker 러너, 각 테스트가 다루는 범위' title: 테스트 x-i18n: - generated_at: "2026-04-30T06:35:50Z" + generated_at: "2026-04-30T18:38:38Z" model: gpt-5.5 provider: openai - source_hash: c7b506350f11431195cb55c84cb10e99efb5f43b934079528b982627024d1ffc + source_hash: 470a96c6b47c2708950d05adc4a4efba5fe290f0675a131e2888d2d0032d5953 source_path: help/testing.md workflow: 16 --- -OpenClaw에는 세 가지 Vitest 제품군(unit/integration, e2e, live)과 소수의 Docker 러너가 있습니다. 이 문서는 "테스트 방식" 가이드입니다. +OpenClaw에는 세 가지 Vitest 스위트(unit/integration, e2e, live)와 소수의 Docker 러너가 있습니다. 이 문서는 "테스트 방식" 가이드입니다. -- 각 제품군이 다루는 범위(그리고 의도적으로 다루지 _않는_ 범위). +- 각 스위트가 다루는 범위와 의도적으로 다루지 _않는_ 범위. - 일반적인 워크플로(local, pre-push, debugging)에서 실행할 명령. - live 테스트가 자격 증명을 찾고 모델/제공자를 선택하는 방식. -- 실제 모델/제공자 문제에 대한 회귀 테스트를 추가하는 방식. +- 실제 모델/제공자 문제에 대한 회귀 테스트를 추가하는 방법. **QA 스택(qa-lab, qa-channel, live transport lanes)**은 별도로 문서화되어 있습니다. - [QA 개요](/ko/concepts/qa-e2e-automation) — 아키텍처, 명령 표면, 시나리오 작성. -- [Matrix QA](/ko/concepts/qa-matrix) — `pnpm openclaw qa matrix` 참조. -- [QA 채널](/ko/channels/qa-channel) — repo 기반 시나리오에서 사용하는 합성 transport Plugin. +- [Matrix QA](/ko/concepts/qa-matrix) — `pnpm openclaw qa matrix`에 대한 참조. +- [QA channel](/ko/channels/qa-channel) — 저장소 기반 시나리오에서 사용하는 합성 전송 Plugin. -이 페이지는 일반 테스트 제품군과 Docker/Parallels 러너 실행을 다룹니다. 아래의 QA 전용 러너 섹션([QA 전용 러너](#qa-specific-runners))은 구체적인 `qa` 호출을 나열하고 위의 참조로 다시 안내합니다. +이 페이지는 일반 테스트 스위트와 Docker/Parallels 러너 실행을 다룹니다. 아래 QA 전용 러너 섹션([QA-specific runners](#qa-specific-runners))에는 구체적인 `qa` 호출이 나열되어 있으며 위 참조로 다시 안내합니다. ## 빠른 시작 대부분의 날에는: -- 전체 게이트(push 전 예상): `pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- 여유 있는 머신에서 더 빠른 local 전체 제품군 실행: `pnpm test:max` -- 직접 Vitest watch 루프: `pnpm test:watch` -- 직접 파일 타기팅은 이제 extension/channel 경로도 라우팅합니다: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- 단일 실패를 반복 작업 중이라면 먼저 타깃 실행을 선호하세요. +- 전체 게이트(push 전에 필요): `pnpm build && pnpm check && pnpm check:test-types && pnpm test` +- 여유 있는 머신에서 더 빠른 local 전체 스위트 실행: `pnpm test:max` +- 직접 Vitest 감시 루프: `pnpm test:watch` +- 직접 파일 지정은 이제 확장/채널 경로도 라우팅합니다: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- 단일 실패를 반복 수정 중이라면 먼저 대상 실행을 선호하세요. - Docker 기반 QA 사이트: `pnpm qa:lab:up` - Linux VM 기반 QA lane: `pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -테스트를 건드렸거나 추가 확신이 필요할 때: +테스트를 수정했거나 추가 확신이 필요할 때: -- Coverage 게이트: `pnpm test:coverage` -- E2E 제품군: `pnpm test:e2e` +- 커버리지 게이트: `pnpm test:coverage` +- E2E 스위트: `pnpm test:e2e` 실제 제공자/모델을 디버깅할 때(실제 자격 증명 필요): -- Live 제품군(모델 + Gateway 도구/이미지 프로브): `pnpm test:live` -- live 파일 하나를 조용히 타깃: `pnpm test:live -- src/agents/models.profiles.live.test.ts` -- Docker live 모델 스윕: `pnpm test:docker:live-models` +- live 스위트(모델 + gateway tool/image 프로브): `pnpm test:live` +- 하나의 live 파일을 조용히 대상으로 지정: `pnpm test:live -- src/agents/models.profiles.live.test.ts` +- Docker live 모델 스위프: `pnpm test:docker:live-models` - 선택된 각 모델은 이제 텍스트 턴과 작은 파일 읽기 스타일 프로브를 실행합니다. 메타데이터가 `image` 입력을 알리는 모델은 작은 이미지 턴도 실행합니다. - 제공자 실패를 격리할 때는 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 또는 - `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0`로 추가 프로브를 비활성화하세요. - - CI 범위: 일일 `OpenClaw Scheduled Live And E2E Checks`와 수동 - `OpenClaw Release Checks`는 모두 reusable live/E2E workflow를 - `include_live_suites: true`로 호출하며, 여기에는 제공자별로 샤딩된 별도의 Docker live 모델 - matrix jobs가 포함됩니다. + 제공자 실패를 격리할 때 추가 프로브를 비활성화하려면 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 또는 + `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0`을 사용하세요. + - CI 커버리지: 일일 `OpenClaw Scheduled Live And E2E Checks`와 수동 + `OpenClaw Release Checks`는 모두 `include_live_suites: true`로 재사용 가능한 live/E2E 워크플로를 호출하며, + 여기에는 제공자별로 샤딩된 별도 Docker live 모델 matrix 작업이 포함됩니다. - 집중 CI 재실행의 경우 `include_live_suites: true` 및 `live_models_only: true`로 `OpenClaw Live And E2E Checks (Reusable)`를 dispatch하세요. - - 새 high-signal 제공자 secret은 `scripts/ci-hydrate-live-auth.sh`와 - `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 및 그 - scheduled/release caller에 추가하세요. -- Native Codex bound-chat smoke: `pnpm test:docker:live-codex-bind` - - Codex app-server 경로를 대상으로 Docker live lane을 실행하고, `/codex bind`로 합성 - Slack DM을 바인딩하며, `/codex fast`와 - `/codex permissions`를 실행한 뒤 일반 답장과 이미지 첨부가 - ACP 대신 native Plugin binding을 통해 라우팅되는지 확인합니다. -- Codex app-server harness smoke: `pnpm test:docker:live-codex-harness` - - Plugin 소유 Codex app-server harness를 통해 Gateway agent 턴을 실행하고, - `/codex status`와 `/codex models`를 확인하며, 기본적으로 이미지, + - 새로운 고신호 제공자 secret은 `scripts/ci-hydrate-live-auth.sh`와 + `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 및 해당 + scheduled/release 호출자에 추가하세요. +- 네이티브 Codex bound-chat smoke: `pnpm test:docker:live-codex-bind` + - Codex app-server 경로를 대상으로 Docker live lane을 실행하고, 합성 + Slack DM을 `/codex bind`로 바인딩하며, `/codex fast`와 + `/codex permissions`를 실행한 다음, 일반 응답과 이미지 첨부가 + ACP 대신 네이티브 Plugin 바인딩을 통해 라우팅되는지 확인합니다. +- Codex app-server 하네스 smoke: `pnpm test:docker:live-codex-harness` + - Plugin 소유 Codex app-server 하네스를 통해 gateway agent 턴을 실행하고, + `/codex status`와 `/codex models`를 확인하며, 기본적으로 image, cron MCP, sub-agent, Guardian 프로브를 실행합니다. 다른 Codex - app-server 실패를 격리할 때는 `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0`로 sub-agent 프로브를 비활성화하세요. 집중 sub-agent 확인에는 다른 프로브를 비활성화하세요: + app-server 실패를 격리할 때 sub-agent 프로브를 비활성화하려면 + `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0`을 사용하세요. 집중 sub-agent 확인을 위해 다른 프로브를 비활성화하세요: `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness`. - `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`이 설정되지 않은 한 + `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`이 설정되어 있지 않으면 sub-agent 프로브 후 종료됩니다. -- Crestodian rescue command smoke: `pnpm test:live:crestodian-rescue-channel` - - message-channel rescue command - 표면에 대한 opt-in belt-and-suspenders 확인입니다. `/crestodian status`를 실행하고, 영구 모델 - 변경을 큐에 넣고, `/crestodian yes`에 응답하며, audit/config 쓰기 경로를 확인합니다. +- Crestodian rescue 명령 smoke: `pnpm test:live:crestodian-rescue-channel` + - 메시지 채널 rescue 명령 표면에 대한 선택적 이중 확인입니다. + `/crestodian status`를 실행하고, 지속 모델 변경을 큐에 넣고, + `/crestodian yes`에 응답하며, audit/config 쓰기 경로를 확인합니다. - Crestodian planner Docker smoke: `pnpm test:docker:crestodian-planner` - - `PATH`의 가짜 Claude CLI가 있는 configless 컨테이너에서 Crestodian을 실행하고 - fuzzy planner fallback이 audit된 typed - config 쓰기로 변환되는지 확인합니다. + - `PATH`에 가짜 Claude CLI가 있는 configless 컨테이너에서 Crestodian을 실행하고, + fuzzy planner fallback이 감사되는 typed config 쓰기로 변환되는지 확인합니다. - Crestodian first-run Docker smoke: `pnpm test:docker:crestodian-first-run` - - 빈 OpenClaw state dir에서 시작해 bare `openclaw`를 - Crestodian으로 라우팅하고, setup/model/agent/Discord Plugin + SecretRef 쓰기를 적용하며, - config를 검증하고 audit entry를 확인합니다. 동일한 Ring 0 setup 경로는 - QA Lab에서도 - `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup`으로 다룹니다. -- Moonshot/Kimi cost smoke: `MOONSHOT_API_KEY`가 설정된 상태에서 - `openclaw models list --provider moonshot --json`을 실행한 다음, 격리된 - `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`을 - `moonshot/kimi-k2.6` 대상으로 실행하세요. JSON이 Moonshot/K2.6을 보고하고 - assistant transcript가 정규화된 `usage.cost`를 저장하는지 확인하세요. + - 빈 OpenClaw 상태 디렉터리에서 시작하고, bare `openclaw`를 + Crestodian으로 라우팅하며, setup/model/agent/Discord Plugin + SecretRef 쓰기를 적용하고, + config를 검증하며 audit 항목을 확인합니다. 동일한 Ring 0 setup 경로는 + `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup`로 QA Lab에서도 다룹니다. +- Moonshot/Kimi 비용 smoke: `MOONSHOT_API_KEY`가 설정된 상태에서 + `openclaw models list --provider moonshot --json`을 실행한 다음, + `moonshot/kimi-k2.6`을 대상으로 격리된 + `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json` + 를 실행합니다. JSON이 Moonshot/K2.6을 보고하고 assistant transcript가 정규화된 `usage.cost`를 저장하는지 확인하세요. -실패 사례 하나만 필요할 때는 아래에 설명된 allowlist env var로 live 테스트를 좁히는 방식을 선호하세요. +실패 사례 하나만 필요하다면 아래에 설명된 allowlist env var로 live 테스트를 좁히는 것을 선호하세요. ## QA 전용 러너 -QA-lab의 현실성이 필요할 때 이 명령들은 주요 테스트 제품군 옆에 놓입니다. +QA-lab의 현실성이 필요할 때 이 명령들은 기본 테스트 스위트 옆에 있습니다. -CI는 전용 workflow에서 QA Lab을 실행합니다. `Parity gate`는 매칭되는 PR과 -mock 제공자를 사용하는 수동 dispatch에서 실행됩니다. `QA-Lab - All Lanes`는 -`main`에서 매일 밤 실행되며, mock parity gate, live Matrix lane, +CI는 전용 워크플로에서 QA Lab을 실행합니다. `Parity gate`는 일치하는 PR과 +mock 제공자를 사용한 수동 dispatch에서 실행됩니다. `QA-Lab - All Lanes`는 매일 밤 +`main`과 수동 dispatch에서 mock parity gate, live Matrix lane, Convex 관리 live Telegram lane, Convex 관리 live Discord lane을 -병렬 job으로 사용하는 수동 dispatch에서도 실행됩니다. Scheduled QA와 release checks는 Matrix `--profile fast`를 -명시적으로 전달하는 반면, Matrix CLI와 수동 workflow 입력의 기본값은 +병렬 작업으로 실행합니다. 예정된 QA 및 release checks는 Matrix `--profile fast`를 +명시적으로 전달하며, Matrix CLI와 수동 워크플로 입력 기본값은 `all`로 유지됩니다. 수동 dispatch는 `all`을 `transport`, `media`, `e2ee-smoke`, -`e2ee-deep`, `e2ee-cli` job으로 샤딩할 수 있습니다. `OpenClaw Release Checks`는 release approval 전에 parity와 -fast Matrix 및 Telegram lane을 실행하며, release transport checks에는 -`mock-openai/gpt-5.5`를 사용해 결정적으로 유지하고 일반 provider-plugin startup을 피합니다. -이 live transport Gateway들은 memory search를 비활성화합니다. memory 동작은 QA parity 제품군에서 계속 다룹니다. +`e2ee-deep`, `e2ee-cli` 작업으로 샤딩할 수 있습니다. `OpenClaw Release Checks`는 +release approval 전에 parity와 fast Matrix 및 Telegram lane을 실행하며, +release transport checks에는 `mock-openai/gpt-5.5`를 사용하여 결정성을 유지하고 +일반 제공자 Plugin 시작을 피합니다. 이러한 live transport gateway는 +memory search를 비활성화하며, memory 동작은 QA parity 스위트에서 계속 다룹니다. -Full release live media shard는 +전체 release live media 샤드는 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`를 사용하며, 여기에는 이미 -`ffmpeg`와 `ffprobe`가 있습니다. Docker live model/backend shard는 선택된 -commit마다 한 번 빌드된 공유 -`ghcr.io/openclaw/openclaw-live-test:` 이미지를 사용한 다음, 각 shard 내부에서 다시 빌드하는 대신 -`OPENCLAW_SKIP_DOCKER_BUILD=1`로 pull합니다. +`ffmpeg`와 `ffprobe`가 포함되어 있습니다. Docker live model/backend 샤드는 선택된 +커밋마다 한 번 빌드되는 공유 +`ghcr.io/openclaw/openclaw-live-test:` 이미지를 사용한 다음, 각 샤드 안에서 재빌드하는 대신 +`OPENCLAW_SKIP_DOCKER_BUILD=1`로 가져옵니다. - `pnpm openclaw qa suite` - - host에서 repo 기반 QA 시나리오를 직접 실행합니다. - - 기본적으로 격리된 Gateway worker로 선택된 여러 시나리오를 병렬 실행합니다. - `qa-channel`은 concurrency 4가 기본값입니다(선택된 시나리오 수로 제한). + - 저장소 기반 QA 시나리오를 호스트에서 직접 실행합니다. + - 기본적으로 격리된 gateway worker로 여러 선택된 시나리오를 병렬 실행합니다. + `qa-channel`은 동시성 4가 기본값입니다(선택된 시나리오 수에 의해 제한됨). worker 수를 조정하려면 `--concurrency `를 사용하거나, 이전 serial lane에는 `--concurrency 1`을 사용하세요. - - 어떤 시나리오든 실패하면 0이 아닌 코드로 종료합니다. 실패 exit code 없이 - artifact만 원할 때는 `--allow-failures`를 사용하세요. + - 어떤 시나리오라도 실패하면 non-zero로 종료합니다. 실패 exit code 없이 artifact를 원할 때는 + `--allow-failures`를 사용하세요. - 제공자 모드 `live-frontier`, `mock-openai`, `aimock`을 지원합니다. `aimock`은 시나리오 인식 - `mock-openai` lane을 대체하지 않고 experimental - fixture 및 protocol-mock 범위를 위해 local AIMock 기반 제공자 서버를 시작합니다. + `mock-openai` lane을 대체하지 않고도 실험적 + fixture 및 protocol-mock 커버리지를 위해 local AIMock 기반 제공자 서버를 시작합니다. - `pnpm test:gateway:cpu-scenarios` - - Gateway startup bench와 작은 mock QA Lab 시나리오 팩 + - gateway startup bench와 작은 mock QA Lab 시나리오 팩 (`channel-chat-baseline`, `memory-failure-fallback`, - `gateway-restart-inflight-run`)을 실행하고 결합된 CPU observation - summary를 `.artifacts/gateway-cpu-scenarios/` 아래에 씁니다. - - 기본적으로 sustained hot CPU observation만 flag합니다(`--cpu-core-warn` - 및 `--hot-wall-warn-ms`). 따라서 짧은 startup burst는 minutes-long Gateway peg regression처럼 보이지 않고 metric으로 기록됩니다. - - 빌드된 `dist` artifact를 사용합니다. checkout에 최신 runtime output이 아직 없으면 먼저 build를 실행하세요. + `gateway-restart-inflight-run`)을 실행하고, 결합된 CPU 관찰 + 요약을 `.artifacts/gateway-cpu-scenarios/` 아래에 작성합니다. + - 기본적으로 지속적인 hot CPU 관찰만 플래그합니다(`--cpu-core-warn` + 및 `--hot-wall-warn-ms`). 따라서 짧은 startup burst는 몇 분 길이의 gateway peg 회귀처럼 보이지 않고 + metric으로 기록됩니다. + - 빌드된 `dist` artifact를 사용합니다. 체크아웃에 이미 최신 runtime output이 없는 경우 먼저 빌드하세요. - `pnpm openclaw qa suite --runner multipass` - - disposable Multipass Linux VM 안에서 동일한 QA 제품군을 실행합니다. - - host의 `qa suite`와 동일한 scenario-selection 동작을 유지합니다. - - `qa suite`와 동일한 제공자/모델 선택 flag를 재사용합니다. - - Live 실행은 guest에 실용적인 지원 QA auth input을 전달합니다: - env 기반 제공자 key, QA live provider config path, 그리고 존재하는 경우 `CODEX_HOME`. - - Output dir는 guest가 mounted workspace를 통해 다시 쓸 수 있도록 repo root 아래에 있어야 합니다. - - 일반 QA report + summary와 Multipass log를 - `.artifacts/qa-e2e/...` 아래에 씁니다. + - 동일한 QA 스위트를 일회용 Multipass Linux VM 안에서 실행합니다. + - 호스트의 `qa suite`와 동일한 시나리오 선택 동작을 유지합니다. + - `qa suite`와 동일한 제공자/모델 선택 플래그를 재사용합니다. + - live 실행은 게스트에 실용적인 지원 QA auth 입력을 전달합니다: + env 기반 제공자 키, QA live 제공자 config 경로, 그리고 존재하는 경우 `CODEX_HOME`. + - 출력 디렉터리는 repo 루트 아래에 유지되어야 게스트가 마운트된 workspace를 통해 다시 쓸 수 있습니다. + - 일반 QA report + summary와 Multipass 로그를 + `.artifacts/qa-e2e/...` 아래에 작성합니다. - `pnpm qa:lab:up` - operator 스타일 QA 작업을 위한 Docker 기반 QA 사이트를 시작합니다. - `pnpm test:docker:npm-onboard-channel-agent` - - 현재 checkout에서 npm tarball을 빌드하고 Docker에 전역 설치한 뒤, - non-interactive OpenAI API-key onboarding을 실행하고, 기본적으로 Telegram을 구성하며, - Plugin 활성화가 필요 시 runtime dependency를 설치하는지 확인하고, - doctor를 실행한 다음 mocked OpenAI - endpoint를 대상으로 local agent 턴 하나를 실행합니다. + - 현재 체크아웃에서 npm tarball을 빌드하고, Docker에 전역 설치하며, + 비대화형 OpenAI API-key onboarding을 실행하고, 기본적으로 Telegram을 구성하고, + Plugin 활성화가 필요한 runtime dependency를 온디맨드로 설치하는지 확인하며, + doctor를 실행하고, mocked OpenAI endpoint를 대상으로 local agent 턴 하나를 실행합니다. - Discord로 동일한 packaged-install lane을 실행하려면 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`를 사용하세요. - `pnpm test:docker:session-runtime-context` - - embedded runtime context transcript에 대한 deterministic built-app Docker smoke를 실행합니다. - 숨겨진 OpenClaw runtime context가 보이는 user turn으로 누출되지 않고 - non-display custom message로 persisted되는지 확인한 다음, - 영향을 받은 broken session JSONL을 seed하고 + - embedded runtime context transcript에 대한 결정적 built-app Docker smoke를 실행합니다. + 숨겨진 OpenClaw runtime context가 보이는 사용자 턴으로 누출되지 않고 + non-display custom message로 지속되는지 확인한 다음, 영향을 받은 broken session JSONL을 seed하고 `openclaw doctor --fix`가 backup과 함께 active branch로 다시 쓰는지 확인합니다. - `pnpm test:docker:npm-telegram-live` - - Docker에 OpenClaw package candidate를 설치하고 installed-package - onboarding을 실행하며, installed CLI를 통해 Telegram을 구성한 다음 - 해당 installed package를 SUT Gateway로 사용해 live Telegram QA lane을 재사용합니다. + - Docker에 OpenClaw package candidate를 설치하고, installed-package onboarding을 실행하고, + 설치된 CLI를 통해 Telegram을 구성한 다음, 해당 installed package를 SUT Gateway로 사용하여 + live Telegram QA lane을 재사용합니다. - 기본값은 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`입니다. registry에서 설치하는 대신 - resolved local tarball을 테스트하려면 + 확인된 local tarball을 테스트하려면 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 또는 `OPENCLAW_CURRENT_PACKAGE_TGZ`를 설정하세요. - - `pnpm openclaw qa telegram`과 동일한 Telegram env credential 또는 Convex credential source를 사용합니다. CI/release automation의 경우 - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`와 - `OPENCLAW_QA_CONVEX_SITE_URL` 및 role secret을 설정하세요. CI에 - `OPENCLAW_QA_CONVEX_SITE_URL`과 Convex role secret이 있으면 + - `pnpm openclaw qa telegram`과 동일한 Telegram env 자격 증명 또는 Convex 자격 증명 소스를 사용합니다. + CI/release 자동화의 경우 `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`와 + `OPENCLAW_QA_CONVEX_SITE_URL` 및 role secret을 설정하세요. + `OPENCLAW_QA_CONVEX_SITE_URL`과 Convex role secret이 CI에 있으면 Docker wrapper가 Convex를 자동으로 선택합니다. - - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer`는 이 lane에만 공유 - `OPENCLAW_QA_CREDENTIAL_ROLE`을 override합니다. - - GitHub Actions는 이 lane을 수동 maintainer workflow - `NPM Telegram Beta E2E`로 노출합니다. merge 시에는 실행되지 않습니다. workflow는 + - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer`는 이 lane에 대해서만 공유 + `OPENCLAW_QA_CREDENTIAL_ROLE`을 재정의합니다. + - GitHub Actions는 이 lane을 수동 maintainer 워크플로 + `NPM Telegram Beta E2E`로 노출합니다. merge에서는 실행되지 않습니다. 이 워크플로는 `qa-live-shared` environment와 Convex CI credential lease를 사용합니다. -- GitHub Actions는 또한 side-run product proof를 위해 하나의 candidate package를 대상으로 - `Package Acceptance`를 노출합니다. trusted ref, published npm spec, - HTTPS tarball URL과 SHA-256, 또는 다른 run의 tarball artifact를 허용하고, - 정규화된 `openclaw-current.tgz`를 `package-under-test`로 upload한 다음, - smoke, package, product, full, custom - lane profile로 기존 Docker E2E scheduler를 실행합니다. 동일한 `package-under-test` artifact를 대상으로 +- GitHub Actions는 하나의 candidate package에 대한 side-run product proof를 위해 + `Package Acceptance`도 노출합니다. 신뢰할 수 있는 ref, published npm spec, + HTTPS tarball URL 및 SHA-256, 또는 다른 실행의 tarball artifact를 받고, + 정규화된 `openclaw-current.tgz`를 `package-under-test`로 업로드한 다음, + 기존 Docker E2E scheduler를 smoke, package, product, full 또는 custom + lane profile로 실행합니다. 동일한 `package-under-test` artifact를 대상으로 Telegram QA workflow를 실행하려면 `telegram_mode=mock-openai` 또는 `live-frontier`를 설정하세요. - 최신 beta product proof: @@ -225,74 +223,74 @@ gh workflow run package-acceptance.yml --ref main \ ``` - `pnpm test:docker:bundled-channel-deps` - - Docker에서 현재 OpenClaw 빌드를 패키징하고 설치한 뒤, OpenAI가 구성된 Gateway를 시작하고 config 편집을 통해 번들 채널/plugins를 활성화합니다. - - 설정 탐색에서 구성되지 않은 plugin 런타임 의존성이 없는 상태로 남는지, 처음 구성된 Gateway 또는 doctor 실행이 각 번들 plugin의 런타임 의존성을 필요할 때 설치하는지, 두 번째 재시작에서 이미 활성화된 의존성을 다시 설치하지 않는지 확인합니다. - - 또한 알려진 이전 npm 기준선을 설치하고, `openclaw update --tag `를 실행하기 전에 Telegram을 활성화한 뒤, 후보 버전의 업데이트 후 doctor가 하네스 측 postinstall 복구 없이 번들 채널 런타임 의존성을 복구하는지 확인합니다. + - Docker에서 현재 OpenClaw 빌드를 패킹하고 설치한 뒤, OpenAI가 구성된 상태로 Gateway를 시작하고, config 편집을 통해 번들 채널/plugins를 활성화합니다. + - setup discovery가 구성되지 않은 plugin 런타임 의존성을 남기지 않는지, 처음 구성된 Gateway 또는 doctor 실행이 각 번들 plugin의 런타임 의존성을 필요 시 설치하는지, 두 번째 재시작이 이미 활성화된 의존성을 다시 설치하지 않는지 확인합니다. + - 또한 알려진 이전 npm 기준 버전을 설치하고, `openclaw update --tag `를 실행하기 전에 Telegram을 활성화한 뒤, 후보 버전의 업데이트 후 doctor가 harness 측 postinstall 복구 없이 번들 채널 런타임 의존성을 복구하는지 확인합니다. - `pnpm test:parallels:npm-update` - - Parallels 게스트 전반에서 네이티브 패키지 설치 업데이트 smoke를 실행합니다. 선택된 각 플랫폼은 먼저 요청된 기준선 패키지를 설치한 다음, 동일한 게스트에서 설치된 `openclaw update` 명령을 실행하고 설치된 버전, 업데이트 상태, Gateway 준비 상태, 로컬 에이전트 턴 하나를 확인합니다. - - 한 게스트에서 반복 작업할 때는 `--platform macos`, `--platform windows` 또는 `--platform linux`를 사용하세요. 요약 아티팩트 경로와 레인별 상태에는 `--json`을 사용하세요. + - Parallels 게스트 전반에서 네이티브 패키지 설치 업데이트 smoke를 실행합니다. 선택된 각 플랫폼은 먼저 요청된 기준 패키지를 설치한 다음, 같은 게스트에서 설치된 `openclaw update` 명령을 실행하고 설치된 버전, 업데이트 상태, Gateway 준비 상태, 로컬 에이전트 턴 하나를 확인합니다. + - 한 게스트를 반복 작업할 때는 `--platform macos`, `--platform windows` 또는 `--platform linux`를 사용하세요. 요약 아티팩트 경로와 레인별 상태에는 `--json`을 사용하세요. - OpenAI 레인은 기본적으로 라이브 에이전트 턴 증명에 `openai/gpt-5.5`를 사용합니다. 다른 OpenAI 모델을 의도적으로 검증할 때는 `--model `을 전달하거나 `OPENCLAW_PARALLELS_OPENAI_MODEL`을 설정하세요. - - Parallels 전송 정체가 남은 테스트 시간을 소모하지 않도록 긴 로컬 실행을 호스트 timeout으로 감싸세요. + - Parallels 전송 정체가 나머지 테스트 시간을 소모하지 않도록 긴 로컬 실행을 호스트 timeout으로 감싸세요. ```bash timeout --foreground 150m pnpm test:parallels:npm-update -- --json timeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json ``` - - 스크립트는 중첩된 레인 로그를 `/tmp/openclaw-parallels-npm-update.*` 아래에 작성합니다. 외부 래퍼가 멈췄다고 가정하기 전에 `windows-update.log`, `macos-update.log` 또는 `linux-update.log`를 확인하세요. - - Windows 업데이트는 콜드 게스트에서 업데이트 후 doctor/런타임 의존성 복구에 10분에서 15분을 쓸 수 있습니다. 중첩된 npm 디버그 로그가 진행 중이면 여전히 정상입니다. + - 스크립트는 `/tmp/openclaw-parallels-npm-update.*` 아래에 중첩 레인 로그를 씁니다. 외부 래퍼가 멈췄다고 가정하기 전에 `windows-update.log`, `macos-update.log` 또는 `linux-update.log`를 확인하세요. + - Windows 업데이트는 콜드 게스트에서 업데이트 후 doctor/런타임 의존성 복구에 10~15분을 쓸 수 있습니다. 중첩 npm 디버그 로그가 진행 중이라면 여전히 정상입니다. - 이 집계 래퍼를 개별 Parallels macOS, Windows 또는 Linux smoke 레인과 병렬로 실행하지 마세요. 이들은 VM 상태를 공유하며 스냅샷 복원, 패키지 제공 또는 게스트 Gateway 상태에서 충돌할 수 있습니다. - - 업데이트 후 증명은 일반 번들 plugin 표면을 실행합니다. 음성, 이미지 생성, 미디어 이해 같은 capability facade는 에이전트 턴 자체가 단순 텍스트 응답만 확인하더라도 번들 런타임 API를 통해 로드되기 때문입니다. + - 업데이트 후 증명은 일반 번들 plugin 표면을 실행합니다. agent turn 자체가 단순한 텍스트 응답만 확인하더라도 음성, 이미지 생성, 미디어 이해 같은 capability facade가 번들 런타임 API를 통해 로드되기 때문입니다. - `pnpm openclaw qa aimock` - - 직접 프로토콜 smoke 테스트를 위해 로컬 AIMock provider 서버만 시작합니다. + - 직접 프로토콜 smoke 테스트를 위해 로컬 AIMock 제공자 서버만 시작합니다. - `pnpm openclaw qa matrix` - 일회용 Docker 기반 Tuwunel homeserver를 대상으로 Matrix 라이브 QA 레인을 실행합니다. 소스 체크아웃 전용입니다. 패키지 설치에는 `qa-lab`이 포함되지 않습니다. - - 전체 CLI, 프로필/시나리오 카탈로그, env var, 아티팩트 레이아웃: [Matrix QA](/ko/concepts/qa-matrix). + - 전체 CLI, 프로필/시나리오 카탈로그, 환경 변수, 아티팩트 레이아웃: [Matrix QA](/ko/concepts/qa-matrix). - `pnpm openclaw qa telegram` - - env의 드라이버 및 SUT bot 토큰을 사용하여 실제 비공개 그룹을 대상으로 Telegram 라이브 QA 레인을 실행합니다. + - 환경의 드라이버 및 SUT 봇 토큰을 사용해 실제 비공개 그룹을 대상으로 Telegram 라이브 QA 레인을 실행합니다. - `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`, `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`이 필요합니다. 그룹 id는 숫자 Telegram 채팅 id여야 합니다. - - 공유 풀링 자격 증명에는 `--credential-source convex`를 지원합니다. 기본적으로 env 모드를 사용하거나, 풀링된 lease를 사용하려면 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`를 설정하세요. - - 어떤 시나리오라도 실패하면 0이 아닌 값으로 종료합니다. 실패 종료 코드 없이 아티팩트를 원할 때는 `--allow-failures`를 사용하세요. - - 동일한 비공개 그룹에 서로 다른 두 bot이 필요하며, SUT bot은 Telegram 사용자 이름을 노출해야 합니다. - - 안정적인 bot 간 관찰을 위해 두 bot 모두 `@BotFather`에서 Bot-to-Bot Communication Mode를 활성화하고 드라이버 bot이 그룹 bot 트래픽을 관찰할 수 있는지 확인하세요. - - `.artifacts/qa-e2e/...` 아래에 Telegram QA 보고서, 요약, 관찰된 메시지 아티팩트를 작성합니다. 응답 시나리오에는 드라이버 전송 요청부터 관찰된 SUT 응답까지의 RTT가 포함됩니다. + - 공유 풀 자격 증명에는 `--credential-source convex`를 지원합니다. 기본적으로 env 모드를 사용하거나, 풀 리스 사용을 선택하려면 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`를 설정하세요. + - 어떤 시나리오든 실패하면 0이 아닌 코드로 종료합니다. 실패 종료 코드 없이 아티팩트를 원할 때는 `--allow-failures`를 사용하세요. + - 같은 비공개 그룹에 있는 서로 다른 두 봇이 필요하며, SUT 봇은 Telegram 사용자 이름을 노출해야 합니다. + - 안정적인 봇 간 관찰을 위해 두 봇 모두에서 `@BotFather`의 Bot-to-Bot Communication Mode를 활성화하고, 드라이버 봇이 그룹 봇 트래픽을 관찰할 수 있는지 확인하세요. + - `.artifacts/qa-e2e/...` 아래에 Telegram QA 보고서, 요약, 관찰된 메시지 아티팩트를 씁니다. 응답 시나리오는 드라이버 전송 요청부터 관찰된 SUT 응답까지의 RTT를 포함합니다. -라이브 전송 레인은 새 전송이 어긋나지 않도록 하나의 표준 계약을 공유합니다. 레인별 커버리지 매트릭스는 [QA 개요 → 라이브 전송 커버리지](/ko/concepts/qa-e2e-automation#live-transport-coverage)에 있습니다. `qa-channel`은 광범위한 합성 스위트이며 이 매트릭스의 일부가 아닙니다. +라이브 전송 레인은 새 전송이 어긋나지 않도록 하나의 표준 계약을 공유합니다. 레인별 범위 행렬은 [QA 개요 → 라이브 전송 범위](/ko/concepts/qa-e2e-automation#live-transport-coverage)에 있습니다. `qa-channel`은 광범위한 합성 스위트이며 이 행렬의 일부가 아닙니다. ### Convex를 통한 공유 Telegram 자격 증명(v1) -`openclaw qa telegram`에 `--credential-source convex`(또는 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)가 활성화되면, QA lab은 Convex 기반 풀에서 독점 lease를 획득하고, 레인이 실행되는 동안 해당 lease에 Heartbeat를 보내며, 종료 시 lease를 해제합니다. +`openclaw qa telegram`에 대해 `--credential-source convex`(또는 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)가 활성화되면, QA lab은 Convex 기반 풀에서 독점 리스를 획득하고, 레인이 실행되는 동안 해당 리스에 Heartbeat를 보내며, 종료 시 리스를 해제합니다. 참조 Convex 프로젝트 스캐폴드: - `qa/convex-credential-broker/` -필수 env var: +필수 환경 변수: - `OPENCLAW_QA_CONVEX_SITE_URL`(예: `https://your-deployment.convex.site`) -- 선택한 역할에 대한 secret 하나: - - `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`는 `maintainer`용 - - `OPENCLAW_QA_CONVEX_SECRET_CI`는 `ci`용 +- 선택된 역할에 대한 비밀 하나: + - `maintainer`용 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` + - `ci`용 `OPENCLAW_QA_CONVEX_SECRET_CI` - 자격 증명 역할 선택: - CLI: `--credential-role maintainer|ci` - - Env 기본값: `OPENCLAW_QA_CREDENTIAL_ROLE`(CI에서는 기본값 `ci`, 그 외에는 `maintainer`) + - 환경 기본값: `OPENCLAW_QA_CREDENTIAL_ROLE`(CI에서는 기본값 `ci`, 그 외에는 `maintainer`) -선택적 env var: +선택적 환경 변수: - `OPENCLAW_QA_CREDENTIAL_LEASE_TTL_MS`(기본값 `1200000`) - `OPENCLAW_QA_CREDENTIAL_HEARTBEAT_INTERVAL_MS`(기본값 `30000`) - `OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS`(기본값 `90000`) - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS`(기본값 `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX`(기본값 `/qa-credentials/v1`) -- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(선택적 trace id) +- `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(선택적 추적 id) - `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1`은 로컬 전용 개발을 위해 loopback `http://` Convex URL을 허용합니다. -일반 작업에서는 `OPENCLAW_QA_CONVEX_SITE_URL`이 `https://`를 사용해야 합니다. +`OPENCLAW_QA_CONVEX_SITE_URL`은 일반 작업에서 `https://`를 사용해야 합니다. -Maintainer 관리자 명령(풀 추가/제거/목록)은 특히 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`가 필요합니다. +메인테이너 관리자 명령(풀 추가/제거/목록)은 특히 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`가 필요합니다. -maintainer용 CLI 헬퍼: +메인테이너용 CLI 헬퍼: ```bash pnpm openclaw qa credentials doctor @@ -301,263 +299,264 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -라이브 실행 전에 `doctor`를 사용하여 secret 값을 출력하지 않고 Convex 사이트 URL, 브로커 secret, endpoint prefix, HTTP timeout, 관리자/목록 도달 가능성을 확인하세요. 스크립트와 CI 유틸리티에서 기계가 읽을 수 있는 출력에는 `--json`을 사용하세요. +라이브 실행 전에 `doctor`를 사용해 비밀 값을 출력하지 않고 Convex 사이트 URL, 브로커 비밀, 엔드포인트 접두사, HTTP timeout, admin/list 도달 가능성을 확인하세요. 스크립트 및 CI 유틸리티에서 기계 판독 가능한 출력에는 `--json`을 사용하세요. -기본 endpoint 계약(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): +기본 엔드포인트 계약(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): - `POST /acquire` - 요청: `{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs }` - 성공: `{ status: "ok", credentialId, leaseToken, payload, leaseTtlMs?, heartbeatIntervalMs? }` - - 소진/재시도 가능: `{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` + - 소진됨/재시도 가능: `{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` - `POST /heartbeat` - 요청: `{ kind, ownerId, actorRole, credentialId, leaseToken, leaseTtlMs }` - 성공: `{ status: "ok" }`(또는 빈 `2xx`) - `POST /release` - 요청: `{ kind, ownerId, actorRole, credentialId, leaseToken }` - 성공: `{ status: "ok" }`(또는 빈 `2xx`) -- `POST /admin/add`(maintainer secret 전용) +- `POST /admin/add`(메인테이너 비밀 전용) - 요청: `{ kind, actorId, payload, note?, status? }` - 성공: `{ status: "ok", credential }` -- `POST /admin/remove`(maintainer secret 전용) +- `POST /admin/remove`(메인테이너 비밀 전용) - 요청: `{ credentialId, actorId }` - 성공: `{ status: "ok", changed, credential }` - - 활성 lease 가드: `{ status: "error", code: "LEASE_ACTIVE", ... }` -- `POST /admin/list`(maintainer secret 전용) + - 활성 리스 가드: `{ status: "error", code: "LEASE_ACTIVE", ... }` +- `POST /admin/list`(메인테이너 비밀 전용) - 요청: `{ kind?, status?, includePayload?, limit? }` - 성공: `{ status: "ok", credentials, count }` -Telegram 종류의 페이로드 형태: +Telegram 종류의 payload 형태: - `{ groupId: string, driverToken: string, sutToken: string }` - `groupId`는 숫자 Telegram 채팅 id 문자열이어야 합니다. -- `admin/add`는 `kind: "telegram"`에 대해 이 형태를 검증하고 잘못된 페이로드를 거부합니다. +- `admin/add`는 `kind: "telegram"`에 대해 이 형태를 검증하고 잘못된 payload를 거부합니다. -### QA에 채널 추가하기 +### QA에 채널 추가 -새 채널 어댑터의 아키텍처와 시나리오 헬퍼 이름은 [QA 개요 → 채널 추가하기](/ko/concepts/qa-e2e-automation#adding-a-channel)에 있습니다. 최소 기준은 공유 `qa-lab` 호스트 seam에서 전송 runner를 구현하고, plugin 매니페스트에 `qaRunners`를 선언하고, `openclaw qa `로 마운트하고, `qa/scenarios/` 아래에 시나리오를 작성하는 것입니다. +새 채널 어댑터의 아키텍처와 시나리오 헬퍼 이름은 [QA 개요 → 채널 추가](/ko/concepts/qa-e2e-automation#adding-a-channel)에 있습니다. 최소 기준: 공유 `qa-lab` 호스트 seam에 전송 runner를 구현하고, plugin manifest에 `qaRunners`를 선언하고, `openclaw qa `로 마운트하고, `qa/scenarios/` 아래에 시나리오를 작성하세요. -## 테스트 스위트(어디서 무엇이 실행되는가) +## 테스트 스위트(무엇이 어디서 실행되는가) -스위트를 "현실성 증가"(그리고 flakiness/비용 증가)로 생각하세요. +스위트를 “현실성 증가”(그리고 불안정성/비용 증가)로 생각하세요. -### Unit / 통합(기본값) +### 단위 / 통합(기본) - 명령: `pnpm test` -- 구성: 타깃이 없는 실행은 `vitest.full-*.config.ts` shard 세트를 사용하며 병렬 스케줄링을 위해 다중 프로젝트 shard를 프로젝트별 config로 확장할 수 있습니다. -- 파일: `src/**/*.test.ts`, `packages/**/*.test.ts`, `test/**/*.test.ts` 아래의 core/unit 인벤토리. UI unit 테스트는 전용 `unit-ui` shard에서 실행됩니다. +- Config: 대상이 지정되지 않은 실행은 `vitest.full-*.config.ts` shard 세트를 사용하며, 병렬 스케줄링을 위해 multi-project shard를 프로젝트별 config로 확장할 수 있습니다. +- 파일: `src/**/*.test.ts`, `packages/**/*.test.ts`, `test/**/*.test.ts` 아래의 코어/단위 인벤토리. UI 단위 테스트는 전용 `unit-ui` shard에서 실행됩니다. - 범위: - - 순수 unit 테스트 - - 인프로세스 통합 테스트(Gateway 인증, 라우팅, tooling, 파싱, config) + - 순수 단위 테스트 + - 프로세스 내 통합 테스트(Gateway 인증, 라우팅, 도구, 파싱, config) - 알려진 버그에 대한 결정적 회귀 테스트 - 기대 사항: - - CI에서 실행됩니다. - - 실제 키가 필요하지 않습니다. - - 빠르고 안정적이어야 합니다. - - Resolver와 public-surface loader 테스트는 실제 번들 plugin 소스 API가 아니라 생성된 작은 plugin fixture로 광범위한 `api.js` 및 `runtime-api.js` fallback 동작을 증명해야 합니다. 실제 plugin API 로드는 plugin 소유 계약/통합 스위트에 속합니다. + - CI에서 실행 + - 실제 키 필요 없음 + - 빠르고 안정적이어야 함 + - resolver 및 public-surface loader 테스트는 실제 번들 plugin 소스 API가 아니라 생성된 작은 plugin fixture로 광범위한 `api.js` 및 `runtime-api.js` fallback 동작을 증명해야 합니다. 실제 plugin API 로드는 plugin 소유 계약/통합 스위트에 속합니다. - + - - 대상이 지정되지 않은 `pnpm test`는 거대한 단일 네이티브 루트 프로젝트 프로세스 대신 열두 개의 더 작은 샤드 구성(`core-unit-fast`, `core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`)을 실행합니다. 이렇게 하면 부하가 있는 머신에서 최대 RSS를 줄이고 auto-reply/extension 작업이 관련 없는 스위트를 굶주리게 하는 일을 방지합니다. - - `pnpm test --watch`는 여전히 네이티브 루트 `vitest.config.ts` 프로젝트 그래프를 사용합니다. 다중 샤드 watch 루프는 실용적이지 않기 때문입니다. - - `pnpm test`, `pnpm test:watch`, `pnpm test:perf:imports`는 명시적 파일/디렉터리 대상을 먼저 범위 지정된 레인으로 라우팅하므로, `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts`는 전체 루트 프로젝트 시작 비용을 치르지 않습니다. - - `pnpm test:changed`는 변경된 git 경로를 기본적으로 저렴한 범위 지정 레인으로 확장합니다. 직접 테스트 편집, 형제 `*.test.ts` 파일, 명시적 소스 매핑, 로컬 import 그래프 의존 대상이 포함됩니다. config/setup/package 편집은 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 명시적으로 사용하지 않는 한 테스트를 광범위하게 실행하지 않습니다. - - `pnpm check:changed`는 좁은 범위 작업을 위한 일반적인 스마트 로컬 검사 게이트입니다. diff를 core, core tests, extensions, extension tests, apps, docs, release metadata, live Docker tooling, tooling으로 분류한 다음, 일치하는 typecheck, lint, guard 명령을 실행합니다. Vitest 테스트는 실행하지 않습니다. 테스트 증거가 필요하면 `pnpm test:changed` 또는 명시적 `pnpm test `을 호출하세요. release metadata 전용 버전 범프는 대상 지정 version/config/root-dependency 검사를 실행하며, 최상위 version 필드 밖의 package 변경을 거부하는 guard가 포함됩니다. - - Live Docker ACP 하네스 편집은 집중 검사를 실행합니다. live Docker auth 스크립트의 shell 구문 검사와 live Docker scheduler dry-run입니다. `package.json` 변경은 diff가 `scripts["test:docker:live-*"]`로 제한될 때만 포함됩니다. dependency, export, version 및 기타 package 표면 편집은 여전히 더 넓은 guard를 사용합니다. - - agents, commands, plugins, auto-reply helper, `plugin-sdk` 및 유사한 순수 utility 영역의 import-light unit test는 `unit-fast` 레인을 통해 라우팅되며, 이 레인은 `test/setup-openclaw-runtime.ts`를 건너뜁니다. stateful/runtime-heavy 파일은 기존 레인에 유지됩니다. - - 선택된 `plugin-sdk` 및 `commands` helper 소스 파일도 changed-mode 실행을 이러한 light lane의 명시적 형제 테스트에 매핑하므로, helper 편집 시 해당 디렉터리의 전체 heavy suite를 다시 실행하지 않아도 됩니다. - - `auto-reply`에는 최상위 core helper, 최상위 `reply.*` integration test, `src/auto-reply/reply/**` 하위 트리를 위한 전용 버킷이 있습니다. CI는 reply 하위 트리를 agent-runner, dispatch, commands/state-routing 샤드로 더 분할하여 하나의 import-heavy 버킷이 전체 Node tail을 독점하지 않도록 합니다. - - 일반 PR/main CI는 의도적으로 extension batch sweep과 release-only `agentic-plugins` 샤드를 건너뜁니다. Full Release Validation은 release candidate에서 plugin/extension-heavy suite를 위해 별도의 `Plugin Prerelease` child workflow를 디스패치합니다. + - 대상이 지정되지 않은 `pnpm test`는 하나의 거대한 네이티브 루트 프로젝트 프로세스 대신 열두 개의 더 작은 샤드 설정(`core-unit-fast`, `core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`)을 실행합니다. 이렇게 하면 부하가 걸린 머신에서 최대 RSS를 줄이고 auto-reply/extension 작업이 관련 없는 스위트를 굶주리게 하는 일을 피할 수 있습니다. + - `pnpm test --watch`는 여전히 네이티브 루트 `vitest.config.ts` 프로젝트 그래프를 사용합니다. 멀티 샤드 watch 루프는 실용적이지 않기 때문입니다. + - `pnpm test`, `pnpm test:watch`, `pnpm test:perf:imports`는 명시적 파일/디렉터리 대상을 먼저 범위 지정된 레인을 통해 라우팅하므로, `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts`는 전체 루트 프로젝트 시작 비용을 치르지 않아도 됩니다. + - `pnpm test:changed`는 기본적으로 변경된 git 경로를 저렴한 범위 지정 레인으로 확장합니다. 직접 테스트 편집, 형제 `*.test.ts` 파일, 명시적 소스 매핑, 로컬 import 그래프 의존 항목이 해당됩니다. Config/setup/package 편집은 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 명시적으로 사용하지 않는 한 테스트를 넓게 실행하지 않습니다. + - `pnpm check:changed`는 좁은 작업에 대한 일반적인 스마트 로컬 검사 게이트입니다. diff를 core, core tests, extensions, extension tests, apps, docs, release metadata, live Docker tooling, tooling으로 분류한 뒤 일치하는 typecheck, lint, guard 명령을 실행합니다. Vitest 테스트는 실행하지 않습니다. 테스트 증명이 필요하면 `pnpm test:changed` 또는 명시적 `pnpm test `을 호출하세요. 릴리스 메타데이터만 변경하는 버전 범프는 대상 버전/config/root-dependency 검사를 실행하며, 최상위 version 필드 밖의 package 변경을 거부하는 guard가 있습니다. + - Live Docker ACP 하네스 편집은 집중 검사를 실행합니다. live Docker auth 스크립트의 셸 문법과 live Docker 스케줄러 dry-run입니다. `package.json` 변경은 diff가 `scripts["test:docker:live-*"]`로 제한될 때만 포함됩니다. dependency, export, version, 기타 package 표면 편집은 여전히 더 넓은 guard를 사용합니다. + - agents, commands, plugins, auto-reply helpers, `plugin-sdk`와 유사한 순수 유틸리티 영역의 import가 가벼운 단위 테스트는 `unit-fast` 레인을 통해 라우팅되며, 이 레인은 `test/setup-openclaw-runtime.ts`를 건너뜁니다. 상태가 있거나 런타임이 무거운 파일은 기존 레인에 남습니다. + - 선택된 `plugin-sdk` 및 `commands` helper 소스 파일도 changed 모드 실행을 해당 가벼운 레인의 명시적 형제 테스트로 매핑하므로, helper 편집은 해당 디렉터리의 전체 무거운 스위트를 다시 실행하지 않아도 됩니다. + - `auto-reply`에는 최상위 core helper, 최상위 `reply.*` 통합 테스트, `src/auto-reply/reply/**` 하위 트리에 대한 전용 버킷이 있습니다. CI는 reply 하위 트리를 agent-runner, dispatch, commands/state-routing 샤드로 추가 분할하여 import가 무거운 하나의 버킷이 전체 Node 꼬리 시간을 독점하지 않게 합니다. + - 일반 PR/main CI는 의도적으로 extension 배치 스윕과 릴리스 전용 `agentic-plugins` 샤드를 건너뜁니다. Full Release Validation은 릴리스 후보에서 이러한 plugin/extension이 무거운 스위트를 위해 별도의 `Plugin Prerelease` 자식 워크플로를 디스패치합니다. - + - - message-tool discovery 입력 또는 compaction runtime context를 변경할 때는 두 수준의 커버리지를 모두 유지하세요. - - 순수 routing 및 normalization 경계에 대해 집중 helper regression을 추가하세요. - - embedded runner integration suite를 건강하게 유지하세요: + - 메시지 도구 탐색 입력 또는 compaction 런타임 컨텍스트를 변경할 때는 두 수준의 커버리지를 모두 유지하세요. + - 순수 라우팅 및 정규화 경계에 대한 집중 helper 회귀 테스트를 추가하세요. + - 내장 러너 통합 스위트를 정상 상태로 유지하세요: `src/agents/pi-embedded-runner/compact.hooks.test.ts`, - `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, 그리고 + `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, 및 `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`. - - 이러한 suite는 scoped id와 compaction 동작이 실제 `run.ts` / `compact.ts` 경로를 통해 계속 흐르는지 검증합니다. helper 전용 테스트는 이러한 integration path의 충분한 대체물이 아닙니다. + - 이러한 스위트는 범위 지정 id와 compaction 동작이 실제 `run.ts` / `compact.ts` 경로를 계속 통과하는지 검증합니다. helper 전용 테스트는 이러한 통합 경로를 충분히 대체하지 못합니다. - + - 기본 Vitest config는 `threads`를 기본값으로 사용합니다. - - 공유 Vitest config는 `isolate: false`를 고정하고 root project, e2e, live config 전반에서 non-isolated runner를 사용합니다. - - 루트 UI 레인은 `jsdom` setup과 optimizer를 유지하지만, 공유 non-isolated runner에서도 실행됩니다. + - 공유 Vitest config는 `isolate: false`를 고정하고 루트 프로젝트, e2e, live config 전반에서 비격리 러너를 사용합니다. + - 루트 UI 레인은 `jsdom` 설정과 optimizer를 유지하지만, 역시 공유 비격리 러너에서 실행됩니다. - 각 `pnpm test` 샤드는 공유 Vitest config에서 동일한 `threads` + `isolate: false` 기본값을 상속합니다. - - `scripts/run-vitest.mjs`는 대규모 로컬 실행 중 V8 compile churn을 줄이기 위해 기본적으로 Vitest child Node 프로세스에 `--no-maglev`를 추가합니다. + - `scripts/run-vitest.mjs`는 대규모 로컬 실행 중 V8 컴파일 churn을 줄이기 위해 기본적으로 Vitest 자식 Node 프로세스에 `--no-maglev`를 추가합니다. 기본 V8 동작과 비교하려면 `OPENCLAW_VITEST_ENABLE_MAGLEV=1`을 설정하세요. - - `pnpm changed:lanes`는 diff가 트리거하는 architecture lane을 보여줍니다. - - pre-commit hook은 formatting 전용입니다. format된 파일을 다시 stage하며 lint, typecheck, test를 실행하지 않습니다. - - 스마트 로컬 검사 게이트가 필요할 때는 handoff 또는 push 전에 `pnpm check:changed`를 명시적으로 실행하세요. - - `pnpm test:changed`는 기본적으로 저렴한 범위 지정 레인을 통해 라우팅됩니다. agent가 harness, config, package 또는 contract 편집에 더 넓은 Vitest 커버리지가 정말 필요하다고 판단할 때만 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 사용하세요. - - `pnpm test:max`와 `pnpm test:changed:max`는 동일한 라우팅 동작을 유지하며, worker cap만 더 높습니다. - - 로컬 worker auto-scaling은 의도적으로 보수적이며 host load average가 이미 높을 때 물러나므로, 여러 동시 Vitest 실행이 기본적으로 더 적은 피해를 줍니다. - - 기본 Vitest config는 project/config 파일을 `forceRerunTriggers`로 표시하므로 test wiring이 변경될 때 changed-mode 재실행이 올바르게 유지됩니다. - - config는 지원되는 host에서 `OPENCLAW_VITEST_FS_MODULE_CACHE`를 활성화한 상태로 유지합니다. 직접 profiling을 위해 명시적인 cache 위치 하나를 원하면 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`를 설정하세요. + - `pnpm changed:lanes`는 diff가 어떤 아키텍처 레인을 트리거하는지 보여줍니다. + - pre-commit hook은 formatting 전용입니다. 포맷된 파일을 다시 stage하며 lint, typecheck, 테스트는 실행하지 않습니다. + - handoff 또는 push 전에 스마트 로컬 검사 게이트가 필요하면 `pnpm check:changed`를 명시적으로 실행하세요. + - `pnpm test:changed`는 기본적으로 저렴한 범위 지정 레인을 통해 라우팅합니다. 에이전트가 harness, config, package, contract 편집에 더 넓은 Vitest 커버리지가 정말 필요하다고 판단한 경우에만 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`를 사용하세요. + - `pnpm test:max`와 `pnpm test:changed:max`는 동일한 라우팅 동작을 유지하되 worker 상한만 더 높입니다. + - 로컬 worker 자동 스케일링은 의도적으로 보수적이며, 호스트 load average가 이미 높을 때 물러나므로 여러 동시 Vitest 실행이 기본적으로 피해를 덜 줍니다. + - 기본 Vitest config는 프로젝트/config 파일을 `forceRerunTriggers`로 표시하여 테스트 wiring이 변경될 때 changed 모드 재실행이 올바르게 유지되도록 합니다. + - config는 지원되는 호스트에서 `OPENCLAW_VITEST_FS_MODULE_CACHE`를 활성화된 상태로 유지합니다. 직접 profiling을 위해 명시적 cache 위치 하나를 원하면 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`를 설정하세요. - - `pnpm test:perf:imports`는 Vitest import-duration reporting과 import-breakdown 출력을 활성화합니다. - - `pnpm test:perf:imports:changed`는 동일한 profiling view를 `origin/main` 이후 변경된 파일로 범위 지정합니다. - - 샤드 timing data는 `.artifacts/vitest-shard-timings.json`에 기록됩니다. - whole-config 실행은 config path를 key로 사용합니다. include-pattern CI shard는 shard 이름을 덧붙여 filtered shard를 별도로 추적할 수 있게 합니다. - - 하나의 hot test가 여전히 대부분의 시간을 startup import에 쓰는 경우, heavy dependency를 좁은 로컬 `*.runtime.ts` seam 뒤에 두고, runtime helper를 단지 `vi.mock(...)`에 넘기기 위해 deep-import하는 대신 그 seam을 직접 mock하세요. - - `pnpm test:perf:changed:bench -- --ref `는 해당 committed diff에 대해 라우팅된 `test:changed`를 네이티브 root-project 경로와 비교하고 wall time 및 macOS max RSS를 출력합니다. - - `pnpm test:perf:changed:bench -- --worktree`는 변경된 파일 목록을 `scripts/test-projects.mjs`와 루트 Vitest config로 라우팅하여 현재 dirty tree를 벤치마크합니다. - - `pnpm test:perf:profile:main`은 Vitest/Vite startup 및 transform overhead에 대한 main-thread CPU profile을 기록합니다. - - `pnpm test:perf:profile:runner`는 file parallelism을 비활성화한 unit suite의 runner CPU+heap profile을 기록합니다. + - `pnpm test:perf:imports`는 Vitest import duration 보고와 import breakdown 출력을 활성화합니다. + - `pnpm test:perf:imports:changed`는 동일한 profiling 뷰를 `origin/main` 이후 변경된 파일로 범위 지정합니다. + - 샤드 타이밍 데이터는 `.artifacts/vitest-shard-timings.json`에 기록됩니다. + 전체 config 실행은 config 경로를 key로 사용합니다. include-pattern CI 샤드는 샤드 이름을 덧붙여 필터링된 샤드를 별도로 추적할 수 있게 합니다. + - 하나의 뜨거운 테스트가 여전히 대부분의 시간을 시작 import에 소비한다면, 무거운 dependency를 좁은 로컬 `*.runtime.ts` seam 뒤에 두고, 단순히 `vi.mock(...)`에 통과시키기 위해 런타임 helper를 deep import하는 대신 해당 seam을 직접 mock하세요. + - `pnpm test:perf:changed:bench -- --ref `는 커밋된 해당 diff에 대해 라우팅된 `test:changed`를 네이티브 루트 프로젝트 경로와 비교하고 wall time과 macOS 최대 RSS를 출력합니다. + - `pnpm test:perf:changed:bench -- --worktree`는 변경된 파일 목록을 `scripts/test-projects.mjs`와 루트 Vitest config를 통해 라우팅하여 현재 dirty tree를 벤치마크합니다. + - `pnpm test:perf:profile:main`은 Vitest/Vite 시작 및 transform overhead에 대한 main thread CPU profile을 작성합니다. + - `pnpm test:perf:profile:runner`는 파일 병렬 처리를 비활성화한 단위 스위트에 대한 runner CPU+heap profile을 작성합니다. -### 안정성 (gateway) +### 안정성(gateway) - 명령: `pnpm test:stability:gateway` - Config: `vitest.gateway.config.ts`, worker 하나로 강제 - 범위: - - diagnostics가 기본적으로 활성화된 실제 loopback Gateway를 시작합니다. - - diagnostic event path를 통해 synthetic gateway message, memory, large-payload churn을 구동합니다. - - Gateway WS RPC를 통해 `diagnostics.stability`를 쿼리합니다. - - diagnostic stability bundle persistence helper를 커버합니다. - - recorder가 bounded 상태를 유지하고, synthetic RSS sample이 pressure budget 아래에 머무르며, session별 queue depth가 다시 0으로 drain되는지 assertion합니다. + - 기본적으로 diagnostics가 활성화된 실제 loopback Gateway를 시작합니다 + - diagnostic event 경로를 통해 synthetic gateway message, memory, large-payload churn을 구동합니다 + - Gateway WS RPC를 통해 `diagnostics.stability`를 쿼리합니다 + - diagnostic stability bundle 영속성 helper를 다룹니다 + - recorder가 bounded 상태를 유지하고, synthetic RSS sample이 pressure budget 아래에 머물며, session별 queue depth가 다시 0으로 drain되는지 assert합니다 - 기대 사항: - - CI-safe 및 keyless - - stability-regression follow-up을 위한 좁은 레인이며, 전체 Gateway suite의 대체물이 아닙니다. + - CI에서 안전하고 key가 필요 없습니다 + - stability regression 후속 조치를 위한 좁은 레인이며, 전체 Gateway 스위트를 대체하지 않습니다 -### E2E (gateway smoke) +### E2E(gateway smoke) - 명령: `pnpm test:e2e` - Config: `vitest.e2e.config.ts` -- 파일: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts`, 그리고 `extensions/` 아래 bundled-plugin E2E test -- Runtime 기본값: - - repo의 나머지 부분과 일치하도록 Vitest `threads`와 `isolate: false`를 사용합니다. - - adaptive worker를 사용합니다(CI: 최대 2개, local: 기본 1개). - - console I/O overhead를 줄이기 위해 기본적으로 silent mode로 실행됩니다. +- 파일: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts`, 및 `extensions/` 아래 bundled-plugin E2E 테스트 +- 런타임 기본값: + - 저장소의 나머지 부분과 일치하도록 Vitest `threads`와 `isolate: false`를 사용합니다. + - adaptive worker를 사용합니다(CI: 최대 2, 로컬: 기본값 1). + - console I/O overhead를 줄이기 위해 기본적으로 silent mode로 실행합니다. - 유용한 override: - - worker 수를 강제하려면 `OPENCLAW_E2E_WORKERS=`을 사용하세요(최대 16으로 capped). - - 자세한 console 출력을 다시 활성화하려면 `OPENCLAW_E2E_VERBOSE=1`을 사용하세요. + - worker 수를 강제하려면 `OPENCLAW_E2E_WORKERS=`(최대 16으로 제한). + - 자세한 console 출력을 다시 활성화하려면 `OPENCLAW_E2E_VERBOSE=1`. - 범위: - - multi-instance gateway end-to-end 동작 + - 다중 인스턴스 gateway end-to-end 동작 - WebSocket/HTTP 표면, node pairing, 더 무거운 networking - 기대 사항: - - CI에서 실행됩니다(pipeline에서 활성화된 경우). - - 실제 key가 필요하지 않습니다. - - unit test보다 moving part가 더 많습니다(느릴 수 있음). + - CI에서 실행됩니다(pipeline에서 활성화된 경우) + - 실제 key가 필요 없습니다 + - 단위 테스트보다 움직이는 부분이 더 많습니다(더 느릴 수 있음) -### E2E: OpenShell backend smoke +### E2E: OpenShell 백엔드 smoke - 명령: `pnpm test:e2e:openshell` - 파일: `extensions/openshell/src/backend.e2e.test.ts` - 범위: - - Docker를 통해 host에서 격리된 OpenShell gateway를 시작합니다. - - 임시 로컬 Dockerfile에서 sandbox를 생성합니다. - - 실제 `sandbox ssh-config` + SSH exec를 통해 OpenClaw의 OpenShell backend를 실행합니다. - - sandbox fs bridge를 통해 remote-canonical filesystem 동작을 검증합니다. + - Docker를 통해 호스트에서 격리된 OpenShell gateway를 시작합니다 + - 임시 로컬 Dockerfile에서 sandbox를 생성합니다 + - 실제 `sandbox ssh-config` + SSH exec를 통해 OpenClaw의 OpenShell 백엔드를 실행합니다 + - sandbox fs bridge를 통해 remote-canonical filesystem 동작을 검증합니다 - 기대 사항: - - opt-in 전용이며 기본 `pnpm test:e2e` 실행의 일부가 아닙니다. - - 로컬 `openshell` CLI와 작동 중인 Docker daemon이 필요합니다. - - 격리된 `HOME` / `XDG_CONFIG_HOME`을 사용한 다음 test gateway와 sandbox를 제거합니다. + - opt-in 전용이며 기본 `pnpm test:e2e` 실행의 일부가 아닙니다 + - 로컬 `openshell` CLI와 작동하는 Docker daemon이 필요합니다 + - 격리된 `HOME` / `XDG_CONFIG_HOME`을 사용한 뒤 테스트 gateway와 sandbox를 삭제합니다 - 유용한 override: - - 더 넓은 e2e suite를 수동으로 실행할 때 테스트를 활성화하려면 `OPENCLAW_E2E_OPENSHELL=1`을 사용하세요. - - 기본값이 아닌 CLI binary 또는 wrapper script를 가리키려면 `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`을 사용하세요. + - 더 넓은 e2e 스위트를 수동으로 실행할 때 테스트를 활성화하려면 `OPENCLAW_E2E_OPENSHELL=1` + - 기본값이 아닌 CLI binary 또는 wrapper script를 가리키려면 `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` -### Live (실제 provider + 실제 model) +### Live(실제 provider + 실제 model) - 명령: `pnpm test:live` - Config: `vitest.live.config.ts` -- 파일: `src/**/*.live.test.ts`, `test/**/*.live.test.ts`, 그리고 `extensions/` 아래 bundled-plugin live test -- 기본값: `pnpm test:live`에 의해 **enabled** (`OPENCLAW_LIVE_TEST=1` 설정) +- 파일: `src/**/*.live.test.ts`, `test/**/*.live.test.ts`, 및 `extensions/` 아래 bundled-plugin live 테스트 +- 기본값: `pnpm test:live`에 의해 **활성화됨**(`OPENCLAW_LIVE_TEST=1` 설정) - 범위: - - “이 provider/model이 실제 creds로 _오늘_ 실제로 동작하는가?” - - provider format 변경, tool-calling quirks, auth issue, rate limit 동작을 포착합니다. + - “이 provider/model이 실제 credential로 _오늘_ 정말 동작하는가?” + - provider format 변경, tool-calling quirks, auth 문제, rate limit 동작을 잡아냅니다 - 기대 사항: - - 설계상 CI-stable이 아닙니다(실제 network, 실제 provider policy, quota, outage). - - 비용이 발생하거나 rate limit을 사용합니다. - - “everything” 대신 범위를 좁힌 subset 실행을 선호하세요. + - 설계상 CI 안정적이지 않습니다(실제 network, 실제 provider 정책, quota, outage) + - 비용이 들거나 rate limit을 사용합니다 + - “everything” 대신 좁혀진 subset 실행을 선호하세요 - Live 실행은 누락된 API key를 가져오기 위해 `~/.profile`을 source합니다. -- 기본적으로 live 실행은 여전히 `HOME`을 격리하고 config/auth material을 임시 test home으로 복사하므로 unit fixture가 실제 `~/.openclaw`를 변경할 수 없습니다. -- live test가 실제 home directory를 사용해야 한다는 의도가 있을 때만 `OPENCLAW_LIVE_USE_REAL_HOME=1`을 설정하세요. -- `pnpm test:live`는 이제 더 조용한 mode를 기본값으로 사용합니다. `[live] ...` progress output은 유지하지만, 추가 `~/.profile` notice를 숨기고 gateway bootstrap log/Bonjour chatter를 mute합니다. 전체 startup log를 다시 원하면 `OPENCLAW_LIVE_TEST_QUIET=0`을 설정하세요. -- API key rotation(provider별): comma/semicolon format의 `*_API_KEYS` 또는 `*_API_KEY_1`, `*_API_KEY_2`(예: `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`)를 설정하거나, `OPENCLAW_LIVE_*_KEY`를 통해 per-live override를 설정하세요. test는 rate limit response에서 retry합니다. -- Progress/heartbeat output: - - Live suite는 이제 stderr로 progress line을 emit하므로 Vitest console capture가 조용해도 긴 provider call이 눈에 띄게 active 상태임을 볼 수 있습니다. - - `vitest.live.config.ts`는 Vitest console interception을 비활성화하여 provider/gateway progress line이 live 실행 중 즉시 stream되도록 합니다. +- 기본적으로 live 실행은 여전히 `HOME`을 격리하고 config/auth 자료를 임시 test home으로 복사하므로 단위 fixture가 실제 `~/.openclaw`를 변경할 수 없습니다. +- live 테스트가 실제 home directory를 사용해야 한다는 의도가 있을 때만 `OPENCLAW_LIVE_USE_REAL_HOME=1`을 설정하세요. +- `pnpm test:live`는 이제 더 조용한 모드를 기본값으로 사용합니다. `[live] ...` progress output은 유지하지만, 추가 `~/.profile` notice를 억제하고 gateway bootstrap logs/Bonjour chatter를 mute합니다. 전체 startup logs를 다시 원하면 `OPENCLAW_LIVE_TEST_QUIET=0`을 설정하세요. +- API key rotation(provider별): comma/semicolon 형식의 `*_API_KEYS` 또는 `*_API_KEY_1`, `*_API_KEY_2`(예: `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`)를 설정하거나 `OPENCLAW_LIVE_*_KEY`를 통해 live별 override를 설정하세요. 테스트는 rate limit response에서 재시도합니다. +- Progress/Heartbeat 출력: + - Live suite는 이제 stderr에 progress line을 내보내므로 Vitest console capture가 조용해도 긴 provider call이 visibly active임을 볼 수 있습니다. + - `vitest.live.config.ts`는 Vitest console interception을 비활성화하여 live 실행 중 provider/gateway progress line이 즉시 stream되도록 합니다. - direct-model heartbeat는 `OPENCLAW_LIVE_HEARTBEAT_MS`로 조정하세요. - gateway/probe heartbeat는 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS`로 조정하세요. -## 어떤 suite를 실행해야 하나요? +## 어떤 스위트를 실행해야 하나요? -다음 decision table을 사용하세요: +이 결정 표를 사용하세요: -- 편집 로직/테스트: `pnpm test`를 실행합니다(많이 변경했다면 `pnpm test:coverage`도 실행) -- Gateway 네트워킹 / WS 프로토콜 / 페어링을 건드리는 경우: `pnpm test:e2e`를 추가합니다 -- “내 봇이 다운됨” / 공급자별 실패 / 도구 호출을 디버깅하는 경우: 범위를 좁힌 `pnpm test:live`를 실행합니다 +- 편집 로직/테스트: `pnpm test` 실행(많이 변경했다면 `pnpm test:coverage`도 실행) +- Gateway 네트워킹 / WS 프로토콜 / 페어링을 건드리는 경우: `pnpm test:e2e` 추가 +- “내 봇이 내려감” / 제공자별 실패 / 도구 호출을 디버깅하는 경우: 범위를 좁힌 `pnpm test:live` 실행 ## 라이브(네트워크 접촉) 테스트 -라이브 모델 매트릭스, CLI 백엔드 스모크, ACP 스모크, Codex 앱 서버 -하네스, 모든 미디어 공급자 라이브 테스트(Deepgram, BytePlus, ComfyUI, 이미지, -음악, 비디오, 미디어 하네스) 및 라이브 실행을 위한 자격 증명 처리에 대해서는 -[테스트 — 라이브 스위트](/ko/help/testing-live)를 참조하세요. +라이브 모델 매트릭스, CLI 백엔드 스모크 테스트, ACP 스모크 테스트, Codex 앱 서버 +하네스, 모든 미디어 제공자 라이브 테스트(Deepgram, BytePlus, ComfyUI, 이미지, +음악, 비디오, 미디어 하네스) 및 라이브 실행을 위한 자격 증명 처리는 +[테스트 — 라이브 제품군](/ko/help/testing-live)을 참조하세요. -## Docker 러너(선택 사항인 "Linux에서 작동" 확인) +## Docker 러너(선택적 "Linux에서 작동함" 검사) -이 Docker 러너들은 두 버킷으로 나뉩니다. +이 Docker 러너들은 두 범주로 나뉩니다. -- 라이브 모델 러너: `test:docker:live-models` 및 `test:docker:live-gateway`는 repo Docker 이미지 안에서 각각 일치하는 프로필 키 라이브 파일(`src/agents/models.profiles.live.test.ts` 및 `src/gateway/gateway-models.profiles.live.test.ts`)만 실행하며, 로컬 config 디렉터리와 워크스페이스를 마운트합니다(마운트된 경우 `~/.profile`도 소싱). 일치하는 로컬 엔트리포인트는 `test:live:models-profiles` 및 `test:live:gateway-profiles`입니다. -- Docker 라이브 러너는 전체 Docker 스윕이 현실적으로 유지되도록 기본적으로 더 작은 스모크 상한을 사용합니다. +- 라이브 모델 러너: `test:docker:live-models` 및 `test:docker:live-gateway`는 repo Docker 이미지 안에서 일치하는 profile-key 라이브 파일(`src/agents/models.profiles.live.test.ts` 및 `src/gateway/gateway-models.profiles.live.test.ts`)만 실행하며, 로컬 config 디렉터리와 workspace를 마운트합니다(마운트된 경우 `~/.profile`도 소싱). 일치하는 로컬 진입점은 `test:live:models-profiles` 및 `test:live:gateway-profiles`입니다. +- Docker 라이브 러너는 전체 Docker 스윕을 실용적으로 유지하기 위해 기본적으로 더 작은 스모크 상한을 사용합니다. `test:docker:live-models`의 기본값은 `OPENCLAW_LIVE_MAX_MODELS=12`이고, `test:docker:live-gateway`의 기본값은 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`, `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`, `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`, 및 - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`입니다. 더 큰 전체 스캔을 명시적으로 원할 때는 이러한 env var를 재정의하세요. -- `test:docker:all`은 `test:docker:live-build`를 통해 라이브 Docker 이미지를 한 번 빌드하고, `scripts/package-openclaw-for-docker.mjs`를 통해 OpenClaw를 npm tarball로 한 번 패키징한 다음, 두 개의 `scripts/e2e/Dockerfile` 이미지를 빌드/재사용합니다. 기본 이미지는 install/update/plugin-dependency 레인을 위한 Node/Git 러너일 뿐이며, 이러한 레인은 미리 빌드된 tarball을 마운트합니다. 기능 이미지는 built-app 기능 레인을 위해 동일한 tarball을 `/app`에 설치합니다. Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, 플래너 로직은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, `scripts/test-docker-all.mjs`가 선택된 계획을 실행합니다. 집계는 가중 로컬 스케줄러를 사용합니다. `OPENCLAW_DOCKER_ALL_PARALLELISM`은 프로세스 슬롯을 제어하고, 리소스 상한은 무거운 라이브, npm-install, 멀티 서비스 레인이 한꺼번에 시작되지 않도록 합니다. 단일 레인이 활성 상한보다 무거워도, 풀이 비어 있으면 스케줄러가 해당 레인을 시작한 다음 다시 용량을 사용할 수 있을 때까지 단독으로 계속 실행합니다. 기본값은 슬롯 10개, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10`, `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`입니다. Docker 호스트에 더 많은 여유가 있을 때만 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 또는 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`를 조정하세요. 러너는 기본적으로 Docker 사전 검사를 수행하고, 오래된 OpenClaw E2E 컨테이너를 제거하며, 30초마다 상태를 출력하고, 성공한 레인 타이밍을 `.artifacts/docker-tests/lane-timings.json`에 저장하며, 이후 실행에서 더 오래 걸리는 레인을 먼저 시작하는 데 이 타이밍을 사용합니다. 빌드하거나 Docker를 실행하지 않고 가중 레인 매니페스트를 출력하려면 `OPENCLAW_DOCKER_ALL_DRY_RUN=1`을 사용하거나, 선택된 레인의 CI 계획, 패키지/이미지 필요 사항, 자격 증명을 출력하려면 `node scripts/test-docker-all.mjs --plan-json`를 사용하세요. -- `Package Acceptance`는 "이 설치 가능한 tarball이 제품으로서 작동하는가?"를 확인하는 GitHub 네이티브 패키지 게이트입니다. `source=npm`, `source=ref`, `source=url`, 또는 `source=artifact`에서 하나의 후보 패키지를 해석하고, 이를 `package-under-test`로 업로드한 다음, 선택된 ref를 다시 패키징하는 대신 정확히 그 tarball에 대해 재사용 가능한 Docker E2E 레인을 실행합니다. `workflow_ref`는 신뢰할 수 있는 워크플로/하네스 스크립트를 선택하고, `package_ref`는 `source=ref`일 때 패키징할 소스 커밋/브랜치/태그를 선택합니다. 이를 통해 현재 acceptance 로직으로 이전의 신뢰할 수 있는 커밋을 검증할 수 있습니다. 프로필은 범위가 넓어지는 순서로 정렬됩니다. `smoke`는 빠른 설치/채널/에이전트와 Gateway/config이고, `package`는 패키지/update/Plugin 계약이며 대부분의 Parallels 패키지/update 커버리지를 대체하는 기본 네이티브 항목이고, `product`는 MCP 채널, Cron/subagent 정리, OpenAI 웹 검색, OpenWebUI를 추가하며, `full`은 OpenWebUI와 함께 릴리스 경로 Docker 청크를 실행합니다. 릴리스 검증은 릴리스 경로 Docker 청크가 겹치는 패키지/update/Plugin 레인을 이미 커버하기 때문에 Telegram 패키지 QA와 함께 사용자 지정 패키지 델타(`bundled-channel-deps-compat plugins-offline`)를 실행합니다. 아티팩트에서 생성된 대상 지정 GitHub Docker 재실행 명령은 사용 가능할 때 이전 패키지 아티팩트와 준비된 이미지 입력을 포함하므로, 실패한 레인이 패키지와 이미지를 다시 빌드하지 않아도 됩니다. -- 빌드 및 릴리스 확인은 tsdown 이후 `scripts/check-cli-bootstrap-imports.mjs`를 실행합니다. 이 가드는 `dist/entry.js` 및 `dist/cli/run-main.js`에서 정적 빌드 그래프를 따라가며, 명령 디스패치 전의 사전 디스패치 시작 단계에서 Commander, 프롬프트 UI, undici, 로깅 같은 패키지 의존성을 가져오면 실패합니다. 또한 번들된 Gateway 실행 청크를 예산 이내로 유지하고, 알려진 콜드 Gateway 경로의 정적 import를 거부합니다. 패키징된 CLI 스모크는 root 도움말, onboard 도움말, doctor 도움말, status, config schema, model-list 명령도 커버합니다. -- Package Acceptance 레거시 호환성은 `2026.4.25`(`2026.4.25-beta.*` 포함)까지로 제한됩니다. 이 기준일까지 하네스는 배송된 패키지 메타데이터 공백만 허용합니다. 생략된 비공개 QA 인벤터리 항목, 누락된 `gateway install --wrapper`, tarball 파생 git fixture의 누락된 패치 파일, 누락된 지속 `update.channel`, 레거시 Plugin install-record 위치, 누락된 marketplace install-record 지속성, 그리고 `plugins update` 중 config 메타데이터 마이그레이션이 이에 해당합니다. `2026.4.25` 이후 패키지에서는 이러한 경로가 엄격한 실패입니다. -- 컨테이너 스모크 러너: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:npm-onboard-channel-agent`, `test:docker:update-channel-switch`, `test:docker:session-runtime-context`, `test:docker:agents-delete-shared-workspace`, `test:docker:gateway-network`, `test:docker:browser-cdp-snapshot`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools`, `test:docker:cron-mcp-cleanup`, `test:docker:plugins`, `test:docker:plugin-update`, 및 `test:docker:config-reload`는 하나 이상의 실제 컨테이너를 부팅하고 더 높은 수준의 통합 경로를 검증합니다. + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`입니다. 더 큰 전체 스캔을 명시적으로 원할 때 해당 env vars를 재정의하세요. +- `test:docker:all`은 `test:docker:live-build`를 통해 라이브 Docker 이미지를 한 번 빌드하고, `scripts/package-openclaw-for-docker.mjs`를 통해 OpenClaw를 npm tarball로 한 번 패킹한 다음, 두 개의 `scripts/e2e/Dockerfile` 이미지를 빌드/재사용합니다. bare 이미지는 install/update/plugin-dependency 레인을 위한 Node/Git 러너일 뿐이며, 해당 레인들은 미리 빌드된 tarball을 마운트합니다. functional 이미지는 built-app 기능 레인을 위해 같은 tarball을 `/app`에 설치합니다. Docker 레인 정의는 `scripts/lib/docker-e2e-scenarios.mjs`에 있고, planner 로직은 `scripts/lib/docker-e2e-plan.mjs`에 있으며, `scripts/test-docker-all.mjs`가 선택된 plan을 실행합니다. 집계는 가중치 기반 로컬 스케줄러를 사용합니다. `OPENCLAW_DOCKER_ALL_PARALLELISM`은 프로세스 슬롯을 제어하고, 리소스 상한은 무거운 live, npm-install, multi-service 레인이 모두 동시에 시작되지 않도록 합니다. 단일 레인이 활성 상한보다 무거운 경우에도, 풀(pool)이 비어 있으면 스케줄러가 이를 시작할 수 있으며, 이후 용량을 다시 사용할 수 있을 때까지 단독으로 계속 실행합니다. 기본값은 슬롯 10개, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=10`, `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`입니다. Docker 호스트에 여유가 더 있을 때만 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 또는 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`를 조정하세요. 러너는 기본적으로 Docker 사전 검사를 수행하고, 오래된 OpenClaw E2E 컨테이너를 제거하며, 30초마다 상태를 출력하고, 성공한 레인 타이밍을 `.artifacts/docker-tests/lane-timings.json`에 저장하며, 이후 실행에서 더 긴 레인을 먼저 시작하는 데 이 타이밍을 사용합니다. 빌드하거나 Docker를 실행하지 않고 가중치 적용 레인 manifest를 출력하려면 `OPENCLAW_DOCKER_ALL_DRY_RUN=1`을 사용하거나, 선택된 레인, 패키지/이미지 요구 사항, 자격 증명에 대한 CI plan을 출력하려면 `node scripts/test-docker-all.mjs --plan-json`을 사용하세요. +- `Package Acceptance`는 "이 설치 가능한 tarball이 제품으로 작동하는가?"를 확인하는 GitHub 네이티브 패키지 게이트입니다. `source=npm`, `source=ref`, `source=url`, 또는 `source=artifact`에서 후보 패키지 하나를 해석해 `package-under-test`로 업로드한 다음, 선택된 ref를 다시 패킹하는 대신 그 정확한 tarball에 대해 재사용 가능한 Docker E2E 레인을 실행합니다. `workflow_ref`는 신뢰할 수 있는 workflow/harness 스크립트를 선택하고, `package_ref`는 `source=ref`일 때 패킹할 소스 commit/branch/tag를 선택합니다. 이를 통해 현재 acceptance 로직으로 더 오래된 신뢰할 수 있는 commit을 검증할 수 있습니다. Profile은 범위가 좁은 순서에서 넓은 순서로 정렬됩니다. `smoke`는 빠른 install/channel/agent에 gateway/config를 더한 것이고, `package`는 package/update/plugin 계약에 keyless upgrade-survivor fixture를 더한 것이며 대부분의 Parallels package/update 커버리지를 대체하는 기본 네이티브 항목입니다. `product`는 MCP 채널, cron/subagent 정리, OpenAI 웹 검색, OpenWebUI를 추가하고, `full`은 OpenWebUI와 함께 release-path Docker 청크를 실행합니다. 릴리스 검증은 release-path Docker 청크가 겹치는 package/update/plugin 레인을 이미 다루므로, 커스텀 패키지 델타(`bundled-channel-deps-compat plugins-offline`)와 Telegram 패키지 QA를 실행합니다. artifacts에서 생성된 대상 지정 GitHub Docker 재실행 명령에는 사용 가능한 경우 이전 패키지 artifact와 준비된 이미지 입력이 포함되므로, 실패한 레인이 패키지와 이미지를 다시 빌드하지 않아도 됩니다. +- 빌드 및 릴리스 검사는 tsdown 이후 `scripts/check-cli-bootstrap-imports.mjs`를 실행합니다. guard는 `dist/entry.js` 및 `dist/cli/run-main.js`에서 정적 빌드 그래프를 따라가며, pre-dispatch startup이 command dispatch 전에 Commander, prompt UI, undici, logging 같은 패키지 의존성을 import하면 실패합니다. 또한 번들된 Gateway run chunk가 예산 안에 있도록 유지하고, 알려진 cold Gateway 경로의 정적 import를 거부합니다. 패키징된 CLI 스모크 테스트는 root help, onboard help, doctor help, status, config schema, model-list 명령도 다룹니다. +- Package Acceptance 레거시 호환성은 `2026.4.25`(`2026.4.25-beta.*` 포함)로 제한됩니다. 해당 기준일까지 하네스는 출시된 패키지 메타데이터 공백만 허용합니다. 생략된 private QA inventory 항목, 누락된 `gateway install --wrapper`, tarball에서 파생된 git fixture의 누락된 patch 파일, 누락된 지속 `update.channel`, 레거시 Plugin install-record 위치, 누락된 marketplace install-record 지속성, `plugins update` 중 config metadata migration이 여기에 포함됩니다. `2026.4.25` 이후 패키지에서는 이러한 경로가 엄격한 실패입니다. +- 컨테이너 스모크 러너: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:npm-onboard-channel-agent`, `test:docker:update-channel-switch`, `test:docker:upgrade-survivor`, `test:docker:session-runtime-context`, `test:docker:agents-delete-shared-workspace`, `test:docker:gateway-network`, `test:docker:browser-cdp-snapshot`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools`, `test:docker:cron-mcp-cleanup`, `test:docker:plugins`, `test:docker:plugin-update`, 및 `test:docker:config-reload`는 하나 이상의 실제 컨테이너를 부팅하고 더 높은 수준의 통합 경로를 검증합니다. -라이브 모델 Docker 러너는 필요한 CLI auth 홈만(또는 실행 범위가 좁혀지지 않은 경우 지원되는 모든 홈) 바인드 마운트한 다음, 실행 전에 컨테이너 홈으로 복사하여 외부 CLI OAuth가 호스트 auth 저장소를 변경하지 않고 토큰을 갱신할 수 있도록 합니다: +라이브 모델 Docker 러너는 필요한 CLI auth home만 bind-mount하거나(실행 범위가 좁혀지지 않은 경우 지원되는 모든 항목), 실행 전에 이를 컨테이너 home으로 복사하여 external-CLI OAuth가 호스트 auth 저장소를 변경하지 않고 토큰을 새로 고칠 수 있게 합니다: - 직접 모델: `pnpm test:docker:live-models` (스크립트: `scripts/test-live-models-docker.sh`) -- ACP 바인드 스모크 테스트: `pnpm test:docker:live-acp-bind` (스크립트: `scripts/test-live-acp-bind-docker.sh`; 기본적으로 Claude, Codex, Gemini를 다루며, `pnpm test:docker:live-acp-bind:droid` 및 `pnpm test:docker:live-acp-bind:opencode`를 통해 Droid/OpenCode의 엄격한 커버리지를 포함) -- CLI 백엔드 스모크 테스트: `pnpm test:docker:live-cli-backend` (스크립트: `scripts/test-live-cli-backend-docker.sh`) -- Codex 앱 서버 하니스 스모크 테스트: `pnpm test:docker:live-codex-harness` (스크립트: `scripts/test-live-codex-harness-docker.sh`) +- ACP 바인드 스모크: `pnpm test:docker:live-acp-bind` (스크립트: `scripts/test-live-acp-bind-docker.sh`; 기본적으로 Claude, Codex, Gemini를 다루며, `pnpm test:docker:live-acp-bind:droid` 및 `pnpm test:docker:live-acp-bind:opencode`를 통해 Droid/OpenCode 엄격 적용 범위를 포함) +- CLI 백엔드 스모크: `pnpm test:docker:live-cli-backend` (스크립트: `scripts/test-live-cli-backend-docker.sh`) +- Codex 앱 서버 하네스 스모크: `pnpm test:docker:live-codex-harness` (스크립트: `scripts/test-live-codex-harness-docker.sh`) - Gateway + 개발 에이전트: `pnpm test:docker:live-gateway` (스크립트: `scripts/test-live-gateway-models-docker.sh`) -- 관측성 스모크 테스트: `pnpm qa:otel:smoke`는 비공개 QA 소스 체크아웃 레인입니다. npm 타르볼에는 QA Lab이 포함되지 않으므로, 의도적으로 패키지 Docker 릴리스 레인에는 포함하지 않습니다. -- Open WebUI 라이브 스모크 테스트: `pnpm test:docker:openwebui` (스크립트: `scripts/e2e/openwebui-docker.sh`) +- 관측성 스모크: `pnpm qa:otel:smoke`는 비공개 QA 소스 체크아웃 레인입니다. npm tarball은 QA Lab을 생략하므로 의도적으로 패키지 Docker 릴리스 레인에 포함하지 않습니다. +- Open WebUI 라이브 스모크: `pnpm test:docker:openwebui` (스크립트: `scripts/e2e/openwebui-docker.sh`) - 온보딩 마법사(TTY, 전체 스캐폴딩): `pnpm test:docker:onboard` (스크립트: `scripts/e2e/onboard-docker.sh`) -- Npm 타르볼 온보딩/채널/에이전트 스모크 테스트: `pnpm test:docker:npm-onboard-channel-agent`는 패키징된 OpenClaw 타르볼을 Docker에 전역 설치하고, env-ref 온보딩을 통해 OpenAI를 구성하며 기본적으로 Telegram도 구성하고, doctor가 활성화된 Plugin 런타임 의존성을 복구했는지 확인한 뒤, 모의 OpenAI 에이전트 턴 하나를 실행합니다. `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz`로 미리 빌드된 타르볼을 재사용하거나, `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0`으로 호스트 재빌드를 건너뛰거나, `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`로 채널을 전환하세요. -- 업데이트 채널 전환 스모크 테스트: `pnpm test:docker:update-channel-switch`는 패키징된 OpenClaw 타르볼을 Docker에 전역 설치하고, 패키지 `stable`에서 git `dev`로 전환하고, 저장된 채널과 Plugin 업데이트 후 작업을 검증한 다음, 다시 패키지 `stable`로 전환하고 업데이트 상태를 확인합니다. -- 세션 런타임 컨텍스트 스모크 테스트: `pnpm test:docker:session-runtime-context`는 숨겨진 런타임 컨텍스트 transcript 지속성과 영향을 받은 중복 프롬프트 재작성 브랜치의 doctor 복구를 검증합니다. -- Bun 전역 설치 스모크 테스트: `bash scripts/e2e/bun-global-install-smoke.sh`는 현재 트리를 패키징하고, 격리된 홈에서 `bun install -g`로 설치한 뒤, `openclaw infer image providers --json`이 멈추지 않고 번들된 이미지 제공자를 반환하는지 확인합니다. `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`로 미리 빌드된 타르볼을 재사용하거나, `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0`으로 호스트 빌드를 건너뛰거나, `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local`로 빌드된 Docker 이미지에서 `dist/`를 복사하세요. -- 설치 프로그램 Docker 스모크 테스트: `bash scripts/test-install-sh-docker.sh`는 root, update, direct-npm 컨테이너 간에 하나의 npm 캐시를 공유합니다. 업데이트 스모크 테스트는 후보 타르볼로 업그레이드하기 전 안정 기준선으로 기본적으로 npm `latest`를 사용합니다. 로컬에서는 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22`로, GitHub에서는 Install Smoke 워크플로의 `update_baseline_version` 입력으로 재정의하세요. non-root 설치 프로그램 검사는 root 소유 캐시 항목이 사용자 로컬 설치 동작을 가리지 않도록 격리된 npm 캐시를 유지합니다. 로컬 재실행 간에 root/update/direct-npm 캐시를 재사용하려면 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache`를 설정하세요. -- Install Smoke CI는 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1`로 중복 direct-npm 전역 업데이트를 건너뜁니다. 직접 `npm install -g` 커버리지가 필요하면 해당 env 없이 스크립트를 로컬에서 실행하세요. -- 에이전트 공유 작업 영역 삭제 CLI 스모크 테스트: `pnpm test:docker:agents-delete-shared-workspace` (스크립트: `scripts/e2e/agents-delete-shared-workspace-docker.sh`)는 기본적으로 루트 Dockerfile 이미지를 빌드하고, 격리된 컨테이너 홈에 하나의 작업 영역을 가진 두 에이전트를 시드하고, `agents delete --json`을 실행한 뒤, 유효한 JSON과 유지된 작업 영역 동작을 검증합니다. `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1`로 install-smoke 이미지를 재사용하세요. -- Gateway 네트워킹(컨테이너 2개, WS 인증 + 상태 확인): `pnpm test:docker:gateway-network` (스크립트: `scripts/e2e/gateway-network-docker.sh`) -- 브라우저 CDP 스냅샷 스모크 테스트: `pnpm test:docker:browser-cdp-snapshot` (스크립트: `scripts/e2e/browser-cdp-snapshot-docker.sh`)는 소스 E2E 이미지와 Chromium 레이어를 빌드하고, 원시 CDP로 Chromium을 시작하고, `browser doctor --deep`를 실행한 뒤, CDP 역할 스냅샷이 링크 URL, 커서로 승격된 클릭 가능 항목, iframe 참조, 프레임 메타데이터를 포함하는지 검증합니다. -- OpenAI Responses web_search 최소 reasoning 회귀 테스트: `pnpm test:docker:openai-web-search-minimal` (스크립트: `scripts/e2e/openai-web-search-minimal-docker.sh`)는 모의 OpenAI 서버를 Gateway를 통해 실행하고, `web_search`가 `reasoning.effort`를 `minimal`에서 `low`로 올리는지 검증한 다음, 제공자 스키마 거부를 강제하고 원시 세부 정보가 Gateway 로그에 나타나는지 확인합니다. -- MCP 채널 브리지(시드된 Gateway + stdio 브리지 + 원시 Claude 알림 프레임 스모크 테스트): `pnpm test:docker:mcp-channels` (스크립트: `scripts/e2e/mcp-channels-docker.sh`) -- Pi 번들 MCP 도구(실제 stdio MCP 서버 + 내장 Pi 프로필 허용/거부 스모크 테스트): `pnpm test:docker:pi-bundle-mcp-tools` (스크립트: `scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- Cron/서브에이전트 MCP 정리(실제 Gateway + 격리된 cron 및 일회성 서브에이전트 실행 후 stdio MCP 자식 종료): `pnpm test:docker:cron-mcp-cleanup` (스크립트: `scripts/e2e/cron-mcp-cleanup-docker.sh`) -- Plugins(설치 스모크 테스트, ClawHub kitchen-sink 설치/제거, 마켓플레이스 업데이트, Claude 번들 활성화/검사): `pnpm test:docker:plugins` (스크립트: `scripts/e2e/plugins-docker.sh`) - ClawHub 블록을 건너뛰려면 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0`을 설정하거나, 기본 kitchen-sink 패키지/런타임 쌍을 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 및 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID`로 재정의하세요. `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL`이 없으면 테스트는 hermetic 로컬 ClawHub fixture 서버를 사용합니다. -- Plugin 업데이트 변경 없음 스모크 테스트: `pnpm test:docker:plugin-update` (스크립트: `scripts/e2e/plugin-update-unchanged-docker.sh`) -- 구성 다시 로드 메타데이터 스모크 테스트: `pnpm test:docker:config-reload` (스크립트: `scripts/e2e/config-reload-source-docker.sh`) -- 번들된 Plugin 런타임 의존성: `pnpm test:docker:bundled-channel-deps`는 기본적으로 작은 Docker 러너 이미지를 빌드하고, 호스트에서 OpenClaw를 한 번 빌드 및 패키징한 다음, 해당 타르볼을 각 Linux 설치 시나리오에 마운트합니다. `OPENCLAW_SKIP_DOCKER_BUILD=1`로 이미지를 재사용하거나, 새 로컬 빌드 후 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0`으로 호스트 재빌드를 건너뛰거나, `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz`로 기존 타르볼을 지정하세요. 전체 Docker 집계와 릴리스 경로 번들 채널 청크는 이 타르볼을 한 번 미리 패키징한 다음, Telegram, Discord, Slack, Feishu, memory-lancedb, ACPX에 대한 별도 업데이트 레인을 포함해 번들 채널 검사를 독립 레인으로 샤딩합니다. 릴리스 청크는 채널 스모크 테스트, 업데이트 대상, setup/runtime 계약을 `bundled-channels-core`, `bundled-channels-update-a`, `bundled-channels-update-b`, `bundled-channels-contracts`로 나눕니다. 집계 `bundled-channels` 청크는 수동 재실행용으로 계속 사용할 수 있습니다. 릴리스 워크플로는 제공자 설치 프로그램 청크와 번들된 Plugin 설치/제거 청크도 분할합니다. 기존 `package-update`, `plugins-runtime`, `plugins-integrations` 청크는 수동 재실행을 위한 집계 별칭으로 유지됩니다. 번들 레인을 직접 실행할 때 채널 매트릭스를 좁히려면 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack`을 사용하거나, 업데이트 시나리오를 좁히려면 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx`를 사용하세요. 시나리오별 Docker 실행의 기본값은 `OPENCLAW_BUNDLED_CHANNEL_DOCKER_RUN_TIMEOUT=900s`입니다. 다중 대상 업데이트 시나리오의 기본값은 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_DOCKER_RUN_TIMEOUT=2400s`입니다. 이 레인은 `channels..enabled=false` 및 `plugins.entries..enabled=false`가 doctor/runtime 의존성 복구를 억제하는지도 검증합니다. -- 반복 작업 중 관련 없는 시나리오를 비활성화하여 번들된 Plugin 런타임 의존성을 좁히세요. 예: +- Npm tarball 온보딩/채널/에이전트 스모크: `pnpm test:docker:npm-onboard-channel-agent`는 패키징된 OpenClaw tarball을 Docker에 전역 설치하고, env-ref 온보딩과 기본 Telegram을 통해 OpenAI를 구성하고, doctor 수리가 활성화된 Plugin 런타임 의존성을 확인한 뒤 모의 OpenAI 에이전트 턴 하나를 실행합니다. `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz`로 미리 빌드된 tarball을 재사용하거나, `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0`으로 호스트 재빌드를 건너뛰거나, `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`로 채널을 전환하세요. +- 업데이트 채널 전환 스모크: `pnpm test:docker:update-channel-switch`는 패키징된 OpenClaw tarball을 Docker에 전역 설치하고, 패키지 `stable`에서 git `dev`로 전환하고, 지속된 채널 및 Plugin 업데이트 후 동작을 확인한 다음, 다시 패키지 `stable`로 전환하고 업데이트 상태를 확인합니다. +- 업그레이드 생존자 스모크: `pnpm test:docker:upgrade-survivor`는 에이전트, 채널 구성, Plugin 허용 목록, 오래된 Plugin 런타임 의존성 상태, 기존 워크스페이스/세션 파일이 있는 지저분한 이전 사용자 픽스처 위에 패키징된 OpenClaw tarball을 설치합니다. 라이브 제공자나 채널 키 없이 패키지 업데이트와 비대화형 doctor를 실행한 다음, loopback Gateway를 시작하고 시작/상태 예산과 함께 구성/상태 보존을 확인합니다. +- 세션 런타임 컨텍스트 스모크: `pnpm test:docker:session-runtime-context`는 숨겨진 런타임 컨텍스트 트랜스크립트 지속성과 영향을 받은 중복 프롬프트 재작성 브랜치의 doctor 수리를 확인합니다. +- Bun 전역 설치 스모크: `bash scripts/e2e/bun-global-install-smoke.sh`는 현재 트리를 패키징하고 격리된 홈에 `bun install -g`로 설치한 뒤, `openclaw infer image providers --json`이 멈추는 대신 번들 이미지 제공자를 반환하는지 확인합니다. `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`로 미리 빌드된 tarball을 재사용하거나, `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0`으로 호스트 빌드를 건너뛰거나, `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local`로 빌드된 Docker 이미지에서 `dist/`를 복사하세요. +- 설치 프로그램 Docker 스모크: `bash scripts/test-install-sh-docker.sh`는 root, update, direct-npm 컨테이너 간에 하나의 npm 캐시를 공유합니다. 업데이트 스모크는 후보 tarball로 업그레이드하기 전 안정 기준선으로 기본 npm `latest`를 사용합니다. 로컬에서는 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22`로, GitHub에서는 Install Smoke 워크플로의 `update_baseline_version` 입력으로 재정의하세요. 비루트 설치 프로그램 검사는 루트 소유 캐시 항목이 사용자 로컬 설치 동작을 가리지 않도록 격리된 npm 캐시를 유지합니다. 로컬 재실행에서 root/update/direct-npm 캐시를 재사용하려면 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache`를 설정하세요. +- Install Smoke CI는 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1`로 중복 direct-npm 전역 업데이트를 건너뜁니다. 직접 `npm install -g` 적용 범위가 필요하면 해당 env 없이 스크립트를 로컬에서 실행하세요. +- 에이전트 공유 워크스페이스 삭제 CLI 스모크: `pnpm test:docker:agents-delete-shared-workspace` (스크립트: `scripts/e2e/agents-delete-shared-workspace-docker.sh`)는 기본적으로 루트 Dockerfile 이미지를 빌드하고, 격리된 컨테이너 홈에 워크스페이스 하나를 가진 에이전트 둘을 시드하고, `agents delete --json`을 실행한 뒤, 유효한 JSON과 보존된 워크스페이스 동작을 확인합니다. `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1`로 install-smoke 이미지를 재사용하세요. +- Gateway 네트워킹(두 컨테이너, WS 인증 + 상태): `pnpm test:docker:gateway-network` (스크립트: `scripts/e2e/gateway-network-docker.sh`) +- 브라우저 CDP 스냅샷 스모크: `pnpm test:docker:browser-cdp-snapshot` (스크립트: `scripts/e2e/browser-cdp-snapshot-docker.sh`)는 소스 E2E 이미지와 Chromium 레이어를 빌드하고, 원시 CDP로 Chromium을 시작하고, `browser doctor --deep`을 실행한 뒤, CDP 역할 스냅샷이 링크 URL, 커서 승격 클릭 가능 요소, iframe 참조, 프레임 메타데이터를 포함하는지 확인합니다. +- OpenAI Responses web_search 최소 reasoning 회귀: `pnpm test:docker:openai-web-search-minimal` (스크립트: `scripts/e2e/openai-web-search-minimal-docker.sh`)는 모의 OpenAI 서버를 Gateway를 통해 실행하고, `web_search`가 `reasoning.effort`를 `minimal`에서 `low`로 올리는지 확인한 다음, 제공자 스키마 거부를 강제하고 원시 상세 정보가 Gateway 로그에 나타나는지 확인합니다. +- MCP 채널 브리지(시드된 Gateway + stdio 브리지 + 원시 Claude 알림 프레임 스모크): `pnpm test:docker:mcp-channels` (스크립트: `scripts/e2e/mcp-channels-docker.sh`) +- Pi 번들 MCP 도구(실제 stdio MCP 서버 + 내장 Pi 프로필 허용/거부 스모크): `pnpm test:docker:pi-bundle-mcp-tools` (스크립트: `scripts/e2e/pi-bundle-mcp-tools-docker.sh`) +- Cron/하위 에이전트 MCP 정리(실제 Gateway + 격리된 cron 및 일회성 하위 에이전트 실행 후 stdio MCP 자식 종료): `pnpm test:docker:cron-mcp-cleanup` (스크립트: `scripts/e2e/cron-mcp-cleanup-docker.sh`) +- Plugin(설치 스모크, ClawHub kitchen-sink 설치/제거, 마켓플레이스 업데이트, Claude 번들 활성화/검사): `pnpm test:docker:plugins` (스크립트: `scripts/e2e/plugins-docker.sh`) + ClawHub 블록을 건너뛰려면 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0`을 설정하거나, 기본 kitchen-sink 패키지/런타임 쌍을 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 및 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID`로 재정의하세요. `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL`이 없으면 테스트는 완전히 격리된 로컬 ClawHub 픽스처 서버를 사용합니다. +- Plugin 업데이트 변경 없음 스모크: `pnpm test:docker:plugin-update` (스크립트: `scripts/e2e/plugin-update-unchanged-docker.sh`) +- 구성 리로드 메타데이터 스모크: `pnpm test:docker:config-reload` (스크립트: `scripts/e2e/config-reload-source-docker.sh`) +- 번들 Plugin 런타임 의존성: `pnpm test:docker:bundled-channel-deps`는 기본적으로 작은 Docker 러너 이미지를 빌드하고, 호스트에서 OpenClaw를 한 번 빌드 및 패키징한 다음, 해당 tarball을 각 Linux 설치 시나리오에 마운트합니다. `OPENCLAW_SKIP_DOCKER_BUILD=1`로 이미지를 재사용하거나, 최신 로컬 빌드 후 `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0`으로 호스트 재빌드를 건너뛰거나, `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz`로 기존 tarball을 지정하세요. 전체 Docker 집계와 릴리스 경로 번들 채널 청크는 이 tarball을 한 번 미리 패키징한 다음, Telegram, Discord, Slack, Feishu, memory-lancedb, ACPX의 별도 업데이트 레인을 포함해 번들 채널 검사를 독립 레인으로 샤딩합니다. 릴리스 청크는 채널 스모크, 업데이트 대상, 설정/런타임 계약을 `bundled-channels-core`, `bundled-channels-update-a`, `bundled-channels-update-b`, `bundled-channels-contracts`로 나눕니다. 집계 `bundled-channels` 청크는 수동 재실행용으로 계속 사용할 수 있습니다. 릴리스 워크플로는 제공자 설치 프로그램 청크와 번들 Plugin 설치/제거 청크도 나눕니다. 기존 `package-update`, `plugins-runtime`, `plugins-integrations` 청크는 수동 재실행용 집계 별칭으로 유지됩니다. 번들 레인을 직접 실행할 때 채널 매트릭스를 좁히려면 `OPENCLAW_BUNDLED_CHANNELS=telegram,slack`을 사용하거나, 업데이트 시나리오를 좁히려면 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx`를 사용하세요. 시나리오별 Docker 실행의 기본값은 `OPENCLAW_BUNDLED_CHANNEL_DOCKER_RUN_TIMEOUT=900s`입니다. 다중 대상 업데이트 시나리오의 기본값은 `OPENCLAW_BUNDLED_CHANNEL_UPDATE_DOCKER_RUN_TIMEOUT=2400s`입니다. 이 레인은 `channels..enabled=false`와 `plugins.entries..enabled=false`가 doctor/런타임 의존성 수리를 억제하는지도 확인합니다. +- 반복 작업 중 관련 없는 시나리오를 비활성화하여 번들 Plugin 런타임 의존성을 좁힙니다. 예: `OPENCLAW_BUNDLED_CHANNEL_SCENARIOS=0 OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO=0 pnpm test:docker:bundled-channel-deps`. 공유 기능 이미지를 수동으로 미리 빌드하고 재사용하려면: @@ -567,130 +566,135 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local pnpm test:docker: OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels ``` -`OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 같은 제품군별 이미지 재정의는 설정되어 있으면 여전히 우선합니다. `OPENCLAW_SKIP_DOCKER_BUILD=1`이 원격 공유 이미지를 가리키면, 스크립트는 해당 이미지가 아직 로컬에 없을 때 가져옵니다. QR 및 설치 프로그램 Docker 테스트는 공유 빌드 앱 런타임이 아니라 패키지/설치 동작을 검증하므로 자체 Dockerfile을 유지합니다. +`OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE` 같은 스위트별 이미지 재정의가 설정되어 있으면 여전히 우선합니다. `OPENCLAW_SKIP_DOCKER_BUILD=1`이 원격 공유 이미지를 가리키면, 스크립트는 해당 이미지가 이미 로컬에 없을 때 가져옵니다. QR 및 설치 프로그램 Docker 테스트는 공유 빌드 앱 런타임이 아니라 패키지/설치 동작을 검증하므로 자체 Dockerfile을 유지합니다. -라이브 모델 Docker 러너는 현재 체크아웃도 읽기 전용으로 바인드 마운트하고 -컨테이너 내부의 임시 작업 디렉터리에 스테이징합니다. 이렇게 하면 런타임 -이미지를 작게 유지하면서도 정확한 로컬 소스/구성에 대해 Vitest를 실행할 수 있습니다. -스테이징 단계는 `.pnpm-store`, `.worktrees`, `__openclaw_vitest__`, 앱 로컬 `.build` 또는 -Gradle 출력 디렉터리 같은 큰 로컬 전용 캐시와 앱 빌드 출력을 건너뛰므로 Docker 라이브 실행이 -머신별 아티팩트를 복사하느라 몇 분을 쓰지 않습니다. -또한 컨테이너 안에서 Gateway 라이브 프로브가 실제 Telegram/Discord 등 채널 워커를 -시작하지 않도록 `OPENCLAW_SKIP_CHANNELS=1`을 설정합니다. -`test:docker:live-models`는 여전히 `pnpm test:live`를 실행하므로, 해당 Docker 레인에서 -Gateway 라이브 커버리지를 좁히거나 제외해야 할 때는 `OPENCLAW_LIVE_GATEWAY_*`도 전달하세요. -`test:docker:openwebui`는 더 높은 수준의 호환성 스모크 테스트입니다. OpenAI 호환 HTTP 엔드포인트가 -활성화된 OpenClaw Gateway 컨테이너를 시작하고, 해당 Gateway를 대상으로 고정된 Open WebUI 컨테이너를 시작하고, +라이브 모델 Docker 러너는 현재 checkout도 읽기 전용으로 bind-mount하고 +컨테이너 내부의 임시 workdir에 stage합니다. 이렇게 하면 runtime +이미지를 작게 유지하면서도 정확히 사용자의 로컬 소스/config에 대해 Vitest를 실행할 수 있습니다. +staging 단계는 Docker 라이브 실행이 머신별 artifact를 복사하느라 몇 분을 쓰지 않도록 +`.pnpm-store`, `.worktrees`, `__openclaw_vitest__`, 그리고 app-local `.build` 또는 +Gradle 출력 디렉터리 같은 큰 로컬 전용 캐시와 앱 빌드 출력을 건너뜁니다. +또한 `OPENCLAW_SKIP_CHANNELS=1`을 설정하므로 Gateway 라이브 probe가 컨테이너 내부에서 +실제 Telegram/Discord 등 채널 워커를 시작하지 않습니다. +`test:docker:live-models`는 여전히 `pnpm test:live`를 실행하므로, 해당 Docker lane에서 +Gateway 라이브 coverage를 좁히거나 제외해야 할 때는 +`OPENCLAW_LIVE_GATEWAY_*`도 함께 전달하세요. +`test:docker:openwebui`는 더 높은 수준의 호환성 smoke입니다. OpenAI 호환 HTTP endpoint가 활성화된 +OpenClaw Gateway 컨테이너를 시작하고, 해당 Gateway를 대상으로 고정된 Open WebUI 컨테이너를 시작한 뒤, Open WebUI를 통해 로그인하고, `/api/models`가 `openclaw/default`를 노출하는지 확인한 다음, -Open WebUI의 `/api/chat/completions` 프록시를 통해 실제 채팅 요청을 보냅니다. -첫 실행은 Docker가 Open WebUI 이미지를 가져와야 하거나 Open WebUI가 자체 콜드 스타트 설정을 -마쳐야 할 수 있어 눈에 띄게 느릴 수 있습니다. -이 레인은 사용 가능한 라이브 모델 키를 기대하며, Docker화된 실행에서 이를 제공하는 기본 방법은 +Open WebUI의 `/api/chat/completions` proxy를 통해 실제 chat 요청을 보냅니다. +첫 실행은 Docker가 Open WebUI 이미지를 pull해야 하거나 Open WebUI가 자체 cold-start 설정을 +완료해야 할 수 있어 눈에 띄게 느릴 수 있습니다. +이 lane에는 사용 가능한 라이브 모델 키가 필요하며, Docker화된 실행에서 이를 제공하는 기본 방법은 `OPENCLAW_PROFILE_FILE`(`~/.profile`이 기본값)입니다. 성공한 실행은 `{ "ok": true, "model": -"openclaw/default", ... }` 같은 작은 JSON 페이로드를 출력합니다. -`test:docker:mcp-channels`는 의도적으로 결정적이며 실제 Telegram, Discord 또는 iMessage 계정이 -필요하지 않습니다. 시드된 Gateway 컨테이너를 부팅하고, `openclaw mcp serve`를 생성하는 두 번째 컨테이너를 -시작한 다음, 실제 stdio MCP 브리지를 통해 라우팅된 대화 발견, transcript 읽기, 첨부 파일 메타데이터, -라이브 이벤트 큐 동작, 아웃바운드 전송 라우팅, Claude 스타일 채널 + 권한 알림을 검증합니다. 알림 검사는 -원시 stdio MCP 프레임을 직접 검사하므로, 스모크 테스트는 특정 클라이언트 SDK가 우연히 노출하는 것만이 아니라 -브리지가 실제로 내보내는 내용을 검증합니다. -`test:docker:pi-bundle-mcp-tools`는 결정적이며 라이브 모델 키가 필요하지 않습니다. repo Docker 이미지를 빌드하고, -컨테이너 안에서 실제 stdio MCP 프로브 서버를 시작하고, 내장 Pi 번들 MCP 런타임을 통해 해당 서버를 구체화하고, -도구를 실행한 다음, `coding` 및 `messaging`은 `bundle-mcp` 도구를 유지하는 반면 `minimal` 및 -`tools.deny: ["bundle-mcp"]`는 이를 필터링하는지 검증합니다. -`test:docker:cron-mcp-cleanup`은 결정적이며 라이브 모델 키가 필요하지 않습니다. 실제 stdio MCP 프로브 서버가 있는 -시드된 Gateway를 시작하고, 격리된 cron 턴과 `/subagents spawn` 일회성 자식 턴을 실행한 다음, -각 실행 후 MCP 자식 프로세스가 종료되는지 검증합니다. +"openclaw/default", ... }` 같은 작은 JSON payload를 출력합니다. +`test:docker:mcp-channels`는 의도적으로 결정적이며 실제 Telegram, Discord, iMessage 계정이 +필요하지 않습니다. seed된 Gateway 컨테이너를 부팅하고, `openclaw mcp serve`를 spawn하는 두 번째 +컨테이너를 시작한 다음, 실제 stdio MCP bridge를 통해 routed conversation discovery, transcript read, +attachment metadata, live event queue 동작, outbound send routing, Claude 스타일 channel + +permission notification을 검증합니다. notification check는 raw stdio MCP frame을 직접 검사하므로, +smoke는 특정 client SDK가 우연히 표면화하는 내용만이 아니라 bridge가 실제로 emit하는 내용을 검증합니다. +`test:docker:pi-bundle-mcp-tools`는 결정적이며 라이브 모델 키가 필요하지 않습니다. +repo Docker 이미지를 빌드하고, 컨테이너 내부에서 실제 stdio MCP probe server를 시작하고, +embedded Pi bundle MCP runtime을 통해 해당 server를 materialize하고, tool을 실행한 뒤, +`coding`과 `messaging`은 `bundle-mcp` tool을 유지하고 `minimal` 및 `tools.deny: ["bundle-mcp"]`는 +이를 filter하는지 검증합니다. +`test:docker:cron-mcp-cleanup`은 결정적이며 라이브 모델 키가 필요하지 않습니다. +실제 stdio MCP probe server가 있는 seed된 Gateway를 시작하고, 격리된 Cron turn과 +`/subagents spawn` one-shot child turn을 실행한 다음, 각 실행 후 MCP child process가 종료되는지 검증합니다. -수동 ACP 일반 언어 스레드 스모크 테스트(CI 아님): +수동 ACP 평문 thread smoke(CI 아님): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- 회귀/디버그 워크플로를 위해 이 스크립트를 유지하세요. ACP 스레드 라우팅 검증에 다시 필요할 수 있으므로 삭제하지 마세요. +- 이 script는 regression/debug workflow를 위해 유지하세요. ACP thread routing 검증에 다시 필요할 수 있으므로 삭제하지 마세요. -유용한 env vars: +유용한 env var: -- `OPENCLAW_CONFIG_DIR=...` (기본값: `~/.openclaw`)는 `/home/node/.openclaw`에 마운트됨 -- `OPENCLAW_WORKSPACE_DIR=...` (기본값: `~/.openclaw/workspace`)는 `/home/node/.openclaw/workspace`에 마운트됨 -- `OPENCLAW_PROFILE_FILE=...` (기본값: `~/.profile`)는 `/home/node/.profile`에 마운트되며 테스트 실행 전에 source됨 -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1`은 임시 config/workspace 디렉터리를 사용하고 외부 CLI auth 마운트 없이 `OPENCLAW_PROFILE_FILE`에서 source된 env vars만 검증함 -- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...` (기본값: `~/.cache/openclaw/docker-cli-tools`)는 Docker 내부의 캐시된 CLI 설치를 위해 `/home/node/.npm-global`에 마운트됨 -- `$HOME` 아래의 외부 CLI auth 디렉터리/파일은 `/host-auth...` 아래에 읽기 전용으로 마운트된 다음, 테스트 시작 전에 `/home/node/...`로 복사됨 - - 기본 디렉터리: `.minimax` - - 기본 파일: `~/.codex/auth.json`, `~/.codex/config.toml`, `.claude.json`, `~/.claude/.credentials.json`, `~/.claude/settings.json`, `~/.claude/settings.local.json` - - 범위를 좁힌 provider 실행은 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS`에서 추론한 필요한 디렉터리/파일만 마운트함 - - `OPENCLAW_DOCKER_AUTH_DIRS=all`, `OPENCLAW_DOCKER_AUTH_DIRS=none` 또는 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 같은 쉼표 목록으로 수동 재정의 -- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...`로 실행 범위를 좁힘 -- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...`로 컨테이너 내부의 provider를 필터링함 -- `OPENCLAW_SKIP_DOCKER_BUILD=1`은 재빌드가 필요 없는 재실행에서 기존 `openclaw:local-live` 이미지를 재사용함 -- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`은 자격 증명이 env가 아니라 profile store에서 오는지 보장함 -- `OPENCLAW_OPENWEBUI_MODEL=...`은 Open WebUI 스모크를 위해 Gateway가 노출하는 모델을 선택함 -- `OPENCLAW_OPENWEBUI_PROMPT=...`은 Open WebUI 스모크가 사용하는 nonce-check 프롬프트를 재정의함 -- `OPENWEBUI_IMAGE=...`는 고정된 Open WebUI 이미지 태그를 재정의함 +- `OPENCLAW_CONFIG_DIR=...` (기본값: `~/.openclaw`) `/home/node/.openclaw`에 mount됨 +- `OPENCLAW_WORKSPACE_DIR=...` (기본값: `~/.openclaw/workspace`) `/home/node/.openclaw/workspace`에 mount됨 +- `OPENCLAW_PROFILE_FILE=...` (기본값: `~/.profile`) `/home/node/.profile`에 mount되고 test 실행 전에 source됨 +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1`: 임시 config/workspace dir를 사용하고 외부 CLI auth mount 없이 `OPENCLAW_PROFILE_FILE`에서 source된 env var만 검증 +- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...` (기본값: `~/.cache/openclaw/docker-cli-tools`) Docker 내부의 cached CLI install을 위해 `/home/node/.npm-global`에 mount됨 +- `$HOME` 아래의 외부 CLI auth dir/file은 `/host-auth...` 아래에 읽기 전용으로 mount된 다음 test 시작 전에 `/home/node/...`로 복사됨 + - 기본 dir: `.minimax` + - 기본 file: `~/.codex/auth.json`, `~/.codex/config.toml`, `.claude.json`, `~/.claude/.credentials.json`, `~/.claude/settings.json`, `~/.claude/settings.local.json` + - 좁혀진 provider 실행은 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS`에서 추론된 필요한 dir/file만 mount함 + - `OPENCLAW_DOCKER_AUTH_DIRS=all`, `OPENCLAW_DOCKER_AUTH_DIRS=none` 또는 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 같은 comma list로 수동 override +- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...`: 실행 범위 좁히기 +- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...`: 컨테이너 내부 provider filter +- `OPENCLAW_SKIP_DOCKER_BUILD=1`: rebuild가 필요 없는 재실행에서 기존 `openclaw:local-live` 이미지 재사용 +- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`: credential이 env가 아닌 profile store에서 오도록 보장 +- `OPENCLAW_OPENWEBUI_MODEL=...`: Open WebUI smoke를 위해 Gateway가 노출하는 모델 선택 +- `OPENCLAW_OPENWEBUI_PROMPT=...`: Open WebUI smoke에서 사용하는 nonce-check prompt override +- `OPENWEBUI_IMAGE=...`: 고정된 Open WebUI image tag override ## Docs sanity -문서 수정 후 docs 검사를 실행하세요: `pnpm check:docs`. -페이지 내부 heading 검사까지 필요할 때는 전체 Mintlify 앵커 검증을 실행하세요: `pnpm docs:check-links:anchors`. +문서 수정 후 docs check를 실행하세요: `pnpm check:docs`. +in-page heading check까지 필요할 때는 전체 Mintlify anchor validation을 실행하세요: `pnpm docs:check-links:anchors`. -## 오프라인 회귀 (CI 안전) +## 오프라인 regression(CI-safe) -다음은 실제 provider 없이 수행하는 “실제 pipeline” 회귀입니다. +다음은 실제 provider 없이 수행하는 “real pipeline” regression입니다: -- Gateway tool calling (mock OpenAI, 실제 gateway + agent loop): `src/gateway/gateway.test.ts` (케이스: "runs a mock OpenAI tool call end-to-end via gateway agent loop") -- Gateway wizard (WS `wizard.start`/`wizard.next`, config 작성 + auth 강제 적용): `src/gateway/gateway.test.ts` (케이스: "runs wizard over ws and writes auth token config") +- Gateway tool calling(mock OpenAI, 실제 Gateway + agent loop): `src/gateway/gateway.test.ts` (case: "Gateway agent loop를 통해 mock OpenAI tool call을 end-to-end로 실행") +- Gateway wizard(WS `wizard.start`/`wizard.next`, config 작성 + auth 적용): `src/gateway/gateway.test.ts` (case: "ws를 통해 wizard를 실행하고 auth token config 작성") -## 에이전트 안정성 평가 (Skills) +## Agent reliability evals (Skills) -이미 “에이전트 안정성 평가”처럼 동작하는 몇 가지 CI 안전 테스트가 있습니다. +이미 “agent reliability evals”처럼 동작하는 CI-safe test가 몇 가지 있습니다: -- 실제 Gateway + 에이전트 루프를 통한 mock tool-calling (`src/gateway/gateway.test.ts`). -- 세션 연결과 config 효과를 검증하는 end-to-end wizard 흐름 (`src/gateway/gateway.test.ts`). +- 실제 Gateway + agent loop를 통한 mock tool-calling(`src/gateway/gateway.test.ts`). +- session wiring과 config effect를 검증하는 end-to-end wizard flow(`src/gateway/gateway.test.ts`). -Skills에 아직 부족한 것([Skills](/ko/tools/skills) 참조): +Skills에 아직 빠져 있는 항목([Skills](/ko/tools/skills) 참조): -- **의사결정:** Skills가 프롬프트에 나열되었을 때 에이전트가 올바른 skill을 선택하는가(또는 관련 없는 skill을 피하는가)? -- **준수:** 에이전트가 사용 전에 `SKILL.md`를 읽고 필요한 단계/인자를 따르는가? -- **워크플로 계약:** tool 순서, 세션 기록 carryover, sandbox 경계를 assert하는 multi-turn 시나리오. +- **Decisioning:** prompt에 Skills가 나열되어 있을 때 agent가 올바른 skill을 선택하는가(또는 관련 없는 것을 피하는가)? +- **Compliance:** agent가 사용 전에 `SKILL.md`를 읽고 필요한 step/arg를 따르는가? +- **Workflow contract:** tool order, session history carryover, sandbox boundary를 assert하는 multi-turn scenario. -향후 평가는 먼저 deterministic하게 유지해야 합니다. +향후 eval은 먼저 결정적으로 유지해야 합니다: -- tool calls + 순서, skill 파일 읽기, 세션 연결을 assert하기 위해 mock provider를 사용하는 scenario runner. -- skill 중심 시나리오의 작은 suite (사용 vs 회피, gating, prompt injection). -- CI 안전 suite가 마련된 뒤에만 선택적 live evals (opt-in, env-gated). +- mock provider를 사용해 tool call + order, skill file read, session wiring을 assert하는 scenario runner. +- skill 중심 scenario의 작은 suite(use vs avoid, gating, prompt injection). +- 선택적 live eval(opt-in, env-gated)은 CI-safe suite가 준비된 후에만 추가. -## Contract tests (Plugin 및 channel 형태) +## Contract test(Plugin 및 channel shape) -Contract tests는 등록된 모든 Plugin과 채널이 해당 interface contract를 준수하는지 검증합니다. 발견된 모든 Plugin을 순회하며 형태 및 동작 assertions suite를 실행합니다. 기본 `pnpm test` unit lane은 이러한 shared seam 및 smoke 파일을 의도적으로 건너뜁니다. shared channel 또는 provider surface를 건드릴 때는 contract commands를 명시적으로 실행하세요. +Contract test는 등록된 모든 Plugin과 channel이 해당 interface contract를 준수하는지 검증합니다. +발견된 모든 Plugin을 순회하며 shape 및 behavior assertion suite를 실행합니다. +기본 `pnpm test` unit lane은 이러한 shared seam 및 smoke file을 의도적으로 건너뜁니다. +shared channel 또는 provider surface를 수정할 때는 contract command를 명시적으로 실행하세요. -### 명령 +### Command -- 모든 contracts: `pnpm test:contracts` -- Channel contracts만: `pnpm test:contracts:channels` -- Provider contracts만: `pnpm test:contracts:plugins` +- 모든 contract: `pnpm test:contracts` +- Channel contract만: `pnpm test:contracts:channels` +- Provider contract만: `pnpm test:contracts:plugins` -### Channel contracts +### Channel contract `src/channels/plugins/contracts/*.contract.test.ts`에 위치: -- **plugin** - 기본 Plugin 형태 (id, name, capabilities) -- **setup** - 설정 wizard contract -- **session-binding** - 세션 바인딩 동작 -- **outbound-payload** - 메시지 payload 구조 -- **inbound** - inbound 메시지 처리 -- **actions** - 채널 action handlers -- **threading** - 스레드 ID 처리 +- **plugin** - 기본 Plugin shape(id, name, capability) +- **setup** - Setup wizard contract +- **session-binding** - Session binding 동작 +- **outbound-payload** - Message payload 구조 +- **inbound** - Inbound message 처리 +- **actions** - Channel action handler +- **threading** - Thread ID 처리 - **directory** - Directory/roster API -- **group-policy** - 그룹 정책 강제 적용 +- **group-policy** - Group policy 적용 -### Provider status contracts +### Provider status contract `src/plugins/contracts/*.contract.test.ts`에 위치. -- **status** - Channel status probes -- **registry** - Plugin registry 형태 +- **status** - Channel status probe +- **registry** - Plugin registry shape -### Provider contracts +### Provider contract `src/plugins/contracts/*.contract.test.ts`에 위치: @@ -701,30 +705,30 @@ Contract tests는 등록된 모든 Plugin과 채널이 해당 interface contract - **loader** - Plugin loading - **runtime** - Provider runtime - **shape** - Plugin shape/interface -- **wizard** - 설정 wizard +- **wizard** - Setup wizard ### 실행 시점 -- plugin-sdk exports 또는 subpaths를 변경한 후 -- channel 또는 provider Plugin을 추가하거나 수정한 후 -- Plugin registration 또는 discovery를 리팩터링한 후 +- plugin-sdk export 또는 subpath 변경 후 +- channel 또는 provider Plugin 추가/수정 후 +- Plugin registration 또는 discovery refactor 후 -Contract tests는 CI에서 실행되며 실제 API keys가 필요하지 않습니다. +Contract test는 CI에서 실행되며 실제 API key가 필요하지 않습니다. -## 회귀 추가 (가이드) +## Regression 추가(guidance) -live에서 발견된 provider/model 문제를 수정할 때: +라이브에서 발견된 provider/model issue를 수정할 때: -- 가능하면 CI 안전 회귀를 추가하세요 (mock/stub provider, 또는 정확한 request-shape transformation 캡처) -- 본질적으로 live 전용이라면 (rate limits, auth policies), live test를 좁게 유지하고 env vars를 통해 opt-in으로 만드세요 -- 버그를 잡아내는 가장 작은 layer를 대상으로 삼는 것을 선호하세요: - - provider request conversion/replay 버그 → 직접 models test - - gateway session/history/tool pipeline 버그 → Gateway live smoke 또는 CI 안전 Gateway mock test +- 가능하면 CI-safe regression을 추가하세요(mock/stub provider 또는 정확한 request-shape transformation capture) +- 본질적으로 live-only라면(rate limit, auth policy) live test를 좁게 유지하고 env var를 통한 opt-in으로 두세요 +- 버그를 잡는 가장 작은 layer를 target하는 것을 선호하세요: + - provider request conversion/replay bug → direct models test + - Gateway session/history/tool pipeline bug → Gateway live smoke 또는 CI-safe Gateway mock test - SecretRef traversal guardrail: - - `src/secrets/exec-secret-ref-id-parity.test.ts`는 registry metadata (`listSecretTargetRegistryEntries()`)에서 SecretRef class당 하나의 sampled target을 도출한 다음, traversal-segment exec ids가 거부되는지 assert합니다. - - `src/secrets/target-registry-data.ts`에 새 `includeInPlan` SecretRef target family를 추가하면 해당 테스트의 `classifyTargetClass`를 업데이트하세요. 새 classes가 조용히 건너뛰어지지 않도록, 이 테스트는 분류되지 않은 target ids에서 의도적으로 실패합니다. + - `src/secrets/exec-secret-ref-id-parity.test.ts`는 registry metadata(`listSecretTargetRegistryEntries()`)에서 SecretRef class별 sampled target 하나를 derive한 다음, traversal-segment exec id가 reject되는지 assert합니다. + - `src/secrets/target-registry-data.ts`에 새로운 `includeInPlan` SecretRef target family를 추가하면 해당 test의 `classifyTargetClass`를 업데이트하세요. 이 test는 unclassified target id에서 의도적으로 실패하므로 새 class가 조용히 skip될 수 없습니다. ## 관련 항목 -- [Live 테스트](/ko/help/testing-live) +- [Testing live](/ko/help/testing-live) - [CI](/ko/ci) diff --git a/docs/ko/reference/test.md b/docs/ko/reference/test.md index efdaddbd2..f7da306a6 100644 --- a/docs/ko/reference/test.md +++ b/docs/ko/reference/test.md @@ -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 `을 사용하세요. -- `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