本地检查与 Testbox
本地等价命令¶
完整的 channels 测试通道会在启动测试进程前准备好其原生 worker 构件。因此,冷编译不会消耗测试输出看门狗的截止时间。聚焦的 channel 选择仍保留惰性准备;看门狗与编译器清理规则保持不变。
lint 包装器为当前 CI 管理 Go 资源限制。它在可用 CPU 少于八个或内存小于 24 GiB 的主机上应用这些限制,但不会将 lint 默认值应用于声明准备。显式设置的 Go 配置仍然会被继承。冻结的修订版本保留工作流限制,因为其包装器可能早于该策略。
在 Linux CI 上,有界 core 分片和八目录插件 lint 分片可使用两个 lint 线程、四个 Go CPU、GOGC=100 以及 8-GiB 的 Go 软堆目标。批处理所有者必须在至少四个 CPU 和 15 GiB 已验证容量上接纳一个子进程;每个子进程还需要 14 GiB 可用内存用于 core,或 10 GiB 用于插件。子进程会验证其参数与已接纳的分片匹配。更大的插件块、无界命令、并行子进程以及未知内存情况将保持原有限制。显式线程与 Go 设置仍然会被继承。更大的堆目标能减少重复垃圾回收,而不会改变 lint 规则、目标文件或声明准备。
运行时拓扑 CI 任务还向 pnpm check:architecture 提供 GOGC=30 和 GOMEMLIMIT=3GiB 默认值,同时保留调用方的覆盖设置。导入循环检查与其余架构检查都继承这些设置。内存目标为软性:在 Node 24.21.0 上使用四 CPU、15.42-GiB Testbox 的对比测试中,未使用默认值时峰值 checker/compiler 进程组 RSS 为 14.24 GiB,使用默认值时为 11.31 GiB;峰值交换使用量从 4.74 GiB 降至零。两台托管运行器在原生 Madge 检查期间关闭,但其日志并未确认是内核 OOM。这些测量结果支持降低内存压力,而非设定 3-GiB RSS 硬上限或确认这些关闭的原因。
在内存小于 24 GiB 的串行主机上,完整 lint 运行会以五个不相交批次执行 core 目标,并以更小的块执行插件。这些运行保留相同的类型感知规则和 TypeScript 配置,同时限制 checker 缓存。至少四个 CPU 和 15 GiB 已验证内存容量的自动 Linux CI 使用十六目录插件块来分摊类型图启动开销。容量包括物理 RAM 和祖先 cgroup 限制。较小或未知容量、本地运行、Windows、显式插件条带以及显式串行选择则保持八目录块。显式拆分 core 和并行执行选择保持不变。
Oxlint 的类型感知后端会分别发现 src/tsconfig.json 和 ui/tsconfig.json。二者都继承根编译器选项、包含共享的环境声明,并跟随导入的依赖。所有现有的 lint 目标和规则仍会运行,包括源码 CommonJS 测试预加载。CLI 的 --tsconfig 选项控制导入解析;它不会替代这些发现项目。
当前 CI 的 core-test 行会将配对的条带合并为一个由全新编译器进程组成的队列,并保持相同的两子进程限制。每个独立图都以增量项目模式运行:解决方案构建模式可能会遗漏添加的根节点,如果其时间戳早于已恢复的构建信息。冻结目标保留其原有的条带调用。每个图的耗时出现在任务日志中。
test-type 任务会在各次运行之间恢复其自身的 .artifacts/tsgo-cache 状态。精确的缓存键会区分编译器/依赖/配置版本与 CI 行。只有当这些输入匹配时,行才会跨源码修订重用增量状态。编译器、依赖或配置变更会从空缓存开始:更新旧状态的成本可能远高于全新检查。编译器在恢复后仍会验证当前的根、选项、源码和依赖内容。集中式变更图队列还会恢复完整运行所发布的五个 core 条带缓存。即使缓存命中,每个选中的图仍会运行。拉取请求只恢复状态,而现有的受信任缓存写入策略控制成功检查后的发布。关闭缓存和冻结目标的运行保留其原有行为。lint 程序不共享这些编译器缓存。
Oxlint 会对 JavaScript 保持启用 eslint/no-redeclare。对于 .ts、.tsx、.mts 和 .cts,tsgo 负责声明有效性,包括同名且有意为之的类型/值配对。eslint/no-var 对所有源码格式保持启用;编译器并不会拒绝所有 var 重复声明。
eslint/no-eval 默认拒绝直接和间接求值。只有 extensions/qa-lab/src/web-runtime.ts 允许间接求值,因为 QA 场景脚本需要页面全局声明语义,而 Playwright 的表达式求值无法保留这些语义。在那里,直接求值仍然是错误。执行所生成浏览器脚本的测试使用隔离的 node:vm 上下文,而非进程全局求值。
pnpm changed:lanes # inspect the local changed-lane classifier for origin/main...HEAD
pnpm check:changed # smart local check gate: changed formatting/typecheck/lint/guards by boundary lane
pnpm check # fast local gate: prod tsgo + sharded lint + parallel fast guards
pnpm check:test-types
pnpm check:timed # same gate with per-stage timings
pnpm build:strict-smoke
pnpm check:architecture
pnpm test:gateway:watch-regression
OPENCLAW_TUI_PTY_INCLUDE_LOCAL=1 node scripts/run-vitest.mjs run --config test/vitest/vitest.tui-pty.config.ts
pnpm test # vitest tests
pnpm test:changed # cheap smart changed Vitest targets
pnpm test:ui # Control UI unit/browser suite
pnpm ui:i18n:check # generated Control UI locale parity (release gate)
pnpm native:i18n:baseline # update source-owned native extraction inventory
pnpm native:i18n:verify # source inventory + Android/Apple localization safety
pnpm native:i18n:check # strict local translated/platform-generated parity
pnpm test:channels
pnpm test:contracts:channels
pnpm check:docs # docs format + lint + broken links
pnpm build # build dist when CI artifact/smoke checks matter
pnpm ios:build # generate and build the iOS app project
pnpm ci:timings # summarize the latest origin/main push CI run
pnpm ci:timings:recent # compare recent successful main CI runs
pnpm ci:timings:trend # 72h main baseline; latest 12h versus prior 12h
node scripts/ci-run-timings.mjs <run-id> # summarize wall time, queue time, and slowest jobs
node scripts/ci-run-timings.mjs --latest-main # ignore issue/comment noise and choose origin/main push CI
node scripts/ci-run-timings.mjs --recent 10 # compare recent successful main CI runs
node scripts/ci-run-timings.mjs --trend-hours 72 --compare-hours 12 --detail-runs 100 --output .artifacts/ci-timings/trend.json
pnpm test:perf:groups --full-suite --allow-failures --output .artifacts/test-perf/baseline-before.json
pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifacts/test-perf/after-agent.json
pnpm test:startup:memory
pnpm test:extensions:memory -- --json .artifacts/openclaw-performance/source/mock-provider/extension-memory.json
pnpm perf:kova:summary --report .artifacts/kova/reports/mock-provider/report.json --output .artifacts/kova/summary.md
本地原生语言环境检查在本地仍保持严格。当设置 CI=true 或 CI=1 时,原生检查会警告过时的翻译 ID、Android 生成行,以及等待序列化语言环境刷新的 Apple 目录行。Android 警告要求这些行是规范的、未被引用的、非插值的过时行,并且删除它们后其他所有字节保持不变。Apple 警告要求这些行是规范的普通生成器行,并且不存在于活动清单中;删除这些行后必须保留完全相同的生成目录,包括元数据。过时行对于 Xcode 仍需要有效的字典和字符串单元结构,但不需要活动语言环境或已翻译/非空文本。不支持的元数据和变体形状仍保留严格的一致性检查。
缺失的活动翻译或资源、活动占位符漂移、无效工件语法以及其他生成输出差异仍会阻断。生成器同步以及独立的 Android 和 Apple 检查保留其严格行为。
可选编译器证据¶
保留 pnpm check:timed(或 check:changed --timed)用于阶段计时,并保留 pnpm tsgo:profile <graph> --deep 用于有意的多遍 graph/pprof 分析。
对于来自你已经在运行的编译器调用的证据,请设置 OPENCLAW_TSGO_METRICS_DIR=.artifacts/tsgo-metrics。在普通本地开发机器上,每次 run-tsgo 调用都会写入一个单独的 JSON 工件;指标和 OPENCLAW_TSGO_PPROF_DIR 均不需要 OPENCLAW_LOCAL_CHECK_MODE=throttled、CI 或服务器特定配置。未设置或空白的指标意味着在正常路径上不会导入指标、探针、文件或产生额外输出。这也适用于通过计时检查包装器到达的测试分片和编译器阶段。它不会添加编译器调用,也不会更改编译器参数、限制、截止时间、信号或清理策略。指标写入失败会发出警告,但不会替换编译器结果。
工件会记录有效命令和退出/错误/信号、受管理的实际时间(包括清理,排除证据 I/O 和工件所有权准入)、修订版本、受跟踪脏状态、已安装的原生编译器/Node 版本、lockfile 摘要、操作系统以及有效 Go 限制。未知来源为 null;受跟踪脏状态不考虑未跟踪输入。命令和路径可能包含私有本地信息:在共享之前,请检查并脱敏工件。
在 Linux 上,可选采样会每 100 ms 读取编译器进程的 /proc CPU 计数器(所有线程)和 RSS 高水位。CPU 和峰值 RSS 明确是采样下界,而不是进程结束时的精确总计或进程树内存。它们可能错过最后一个区间;非常短暂的运行或受限的 procfs 可能没有可用样本。缺失的统计值会带有原因并设为 null,绝不会填充为零。macOS 和 Windows 会报告不支持资源采样;实际时间和来源仍然可用。包装器进程不会更改信号所有权。
显式 --tsBuildInfoFile 会提供前后 SHA-256 证据。它的存在并不表示缓存命中:hit 保持为 unknown,操作系统页缓存为 uncontrolled。已更改且可读的 JSON 构建元数据会提供总文件数、根文件数和非根/传递文件数,包括库/声明输入。未更改、缺失、过大(超过 32 MiB)或不支持的元数据会使计数不可用,而不是将陈旧图归因于本次运行。不会推断隐式缓存路径和 solution-build 缓存。不会启动 --listFiles、--showConfig 或诊断遍来填充缺失字段。当你确实需要这些额外遍时,请使用现有的 tsgo:profile 工具。
mkdir -p .artifacts
benchmark_dir=$(mktemp -d .artifacts/tsgo-benchmark.XXXXXX)
for repeat in 1 2 3; do
pair="$benchmark_dir/$repeat"
mkdir -p "$pair"
OPENCLAW_TSGO_METRICS_DIR="$pair/cold" node scripts/run-tsgo.mjs \
-p tsconfig.ui.json --incremental --tsBuildInfoFile "$pair/cache.tsbuildinfo" || break
OPENCLAW_TSGO_METRICS_DIR="$pair/warm" node scripts/run-tsgo.mjs \
-p tsconfig.ui.json --incremental --tsBuildInfoFile "$pair/cache.tsbuildinfo" || break
done
在此命令树周围遵守主机现有的构建锁和资源策略;不要并发运行这些配对。在解释计时之前,请停止并调查任何非零编译器退出码。此处的“Cold”仅表示该配对的 build-info 文件缺失;它并不意味着操作系统/依赖缓存处于冷状态。“Warm”表示已尝试使用相同输入进行复用,而不是已证明的缓存命中。比较中位数和范围,报告所有退出状态和缺失字段,并将前后修订版本以及 lockfile/工具链摘要与结果放在一起。不要删除共享缓存、丢弃操作系统缓存或放宽资源上限以制造有利的比较。该配方仅创建一个新的基准目录,并保持正常缓存不变。
对于 CPU/堆调查,请复用 OPENCLAW_TSGO_PPROF_DIR,并为每次被测调用使用不同的目录,或使用 tsgo:profile --deep。性能分析会改变测量开销:请为比较的两侧都启用它,或将其置于计时配对之外。证据会记录有效的 --pprofDir;它不会管理或删除这些性能分析文件。这些测量是开发者证据,而不是 CI 通过/失败阈值。
Gateway watch 回归检查只有在就绪和稳定期之后才开始其空闲 CPU 窗口。启动和提前退出失败仍会使检查失败。否则有效窗口中缺失的 CPU 样本会使测量失败;整个运行的 CPU 会单独报告,并且从不与空闲阈值比较。
该检查会在获取运行后快照或删除其私有 HOME 之前,连接计时 watch 进程及其输出。如果无法确认清理,则检查失败并保留该 HOME 以供检查;输出目录中的 watch.home.txt 会记录其路径。
原生源代码门控覆盖目录拥有的 macOS、iOS 和共享 Apple 源代码根目录。可在 Linux 上运行的源代码提取要求使用显式类型化本地化格式(例如,对于 Int 使用 String(format: String(localized: "Expires in %lld minutes"), minutes)),而不是任意 Swift 插值。受限的屈折计数资源在两个平台上都受支持。对于用户、系统或已本地化数据,请使用显式逐字文本。
对于暂存检查,pnpm check:changed --staged 将索引与 HEAD 进行比较。
使用 pnpm check:changed --staged --base <commit> 将索引与显式提交进行比较,包括在待处理合并期间。路径选择、包分类和暂存棘轮使用相同的基准。如果不使用 --staged,默认比较基准仍为 origin/main。
委托的暂存检查会将所选路径和比较基准传递给远程检查器。Crabbox 同步工作树文件,而不是本地 Git 索引,因此远程结果描述的是这些已物化的文件,而不是暂存快照的精确副本。在使用该路径之前,请保持预期证明文件的一致性。
工作流 lint 工具¶
pnpm check:workflows 要求使用在 scripts/check-workflows.mts 和 .pre-commit-config.yaml 中固定的修订版构建的 actionlint。已发布和未知的构建会在每个平台上有意使用固定的回退版本。安装 Go 以便包装器获取该修订版,或使用固定的 pre-commit 钩子。
zizmor 检查还要求 pre-commit、Python pre_commit 模块,或支持 venv 的 Python 3.10+,以便包装器可以安装其固定的 pre-commit 运行时。已安装的匹配 actionlint 不会移除此要求。
用于离线使用时,请缓存 pre-commit 运行时及其 zizmor 钩子,并缓存匹配的已安装 actionlint 或固定的 actionlint 钩子。在已安装 pre-commit 的情况下,在线时预热两个钩子环境:
表面棘轮¶
大小、长度、计数和实测性能限制在本地是错误,在 GitHub Actions 中是警告。scripts/lib/check-limits.mts 使用 GitHub 的 GITHUB_ACTIONS=true 信号负责此决策。仅设置 CI=1 不会放宽检查:本地测试运行器和委托的本地检查也会设置它。每个 CI 违规都会发出一个关联到文件的 GitHub 警告,位于第 0 列,并生成一个作业摘要条目。Docker 证明包装器会携带该信号,并将其摘要转发到运行器。
Oxlint 保留已配置的行长上限和排除项:普通 TypeScript 为 700 个计行数,JavaScript 模块为 800,测试为 1,000,并保留现有的显式覆盖。独立的本地 lint 会报告错误。在 check:changed 中,lint 会为所选的已更改文件报告 max-lines 错误,并为更宽泛 lint 通道包含的未触及文件报告警告。广泛扫描仍会在其运行的所有位置报告语义错误。空或过大的变更范围、对 lint 配置或依赖项的更改,以及具有继承限制的配置会保持严格的本地执行。CI 使用一个临时配置,仅将已启用大小规则的严重级别更改为警告。SwiftLint 同样会将原生长度、嵌套、复杂度和计数限制报告为 CI 警告;语义 lint 错误仍会阻止。
pnpm check、pnpm check:changed 和 pnpm check:line-cap-ratchet --base <commit> 在本地拒绝新的超限文件以及超过继承超限债务的增长。PR 的 checks-fast-baseline-ratchets 作业会将此增长报告为警告。重命名会针对旧路径进行比较;未更改或缩小的超限文件会通过棘轮。测量使用 oxlint 的实际上限和注释/空行排除项,并仅在临时测量副本中使抑制指令失效。主分支推送 CI 不会运行 PR 增长比较;普通 lint 仍会报告所有未抑制的超限文件。
max-lines 抑制清单和环境变量计数预算使用相同的严重级别策略。移除抑制后,请从 config/max-lines-baseline.txt 中删除其过期条目,或运行 pnpm check:max-lines-ratchet --prune。保持清单持续缩减;警告状态不会授权新的抑制或更高的上限。环境预算统计生产 src/、packages/ 和 extensions/ 源码中不同的 OPENCLAW_* 名称,排除测试和 QA Lab。当清理减少该计数时,更新 config/env-var-count-budget.txt。
该策略还涵盖数值 bundle、声明、包、启动内存、CPU、计时和测试根预算。测量值和阈值保持不变。当文件或产物超过上限时,请提取一个连贯的模块或调查新增成本。不要仅为了消除警告而削减覆盖率、禁用规则或提高阈值。
正确性检查保持阻止状态,包括类型、语义 lint、全面 lint 禁用、断言安全性、测试超时竞争棘轮、缺失或格式错误的证据、失败命令、禁止的急切导入以及恰好一次所有权。公共 SDK 清单和生成的配置模式基线仍然是契约守卫。Runner 矩阵上限保护共享 runner 注册容量,并保持阻止状态。显式基准测试资格判定保留其请求的验收标准。
test/scripts/ci-workflow-guards.test.ts 中的工作流文件大小守卫也保持阻止状态。GitHub 会拒绝任何超过 512,000 字节(500 KiB)的工作流文件,并产生一个没有作业的运行,因此每个 PR 和 main CI 运行都会停止,而没有失败的检查。该守卫在 480,000 字节时失败,而 CI 仍可以报告它。在提高限制之前先缩小文件;例如,通过 YAML 锚点和别名共享字节相同的 runner 表达式、步骤和脚本。
本地检查门控与变更路由¶
配置基线计数棘轮¶
pnpm config:docs:check 拒绝未记录的配置表面增长以及损坏或过期的计数快照。当经过审查的产品更改有意添加模式路径时,运行 pnpm config:docs:gen,检查 core/channel/plugin 计数差异和生成的 SHA-256 文件,并将有意识的基线提升与模式、帮助、标签、迁移和测试一起提交。不要手动编辑计数文件以绕过棘轮。
配置作者还必须为 Settings 的新叶子进行分层。在叶子处添加 advanced: false 或 advanced: true,或将键放置在某个祖先之下,其所有后代都应继承该祖先的层级。未分类的根会因复制粘贴的存根而让模式质量测试失败;没有祖先的路径默认是 advanced。经过整理的常见叶子快照使有意的层级更改在审查中可见。
本地变更车道逻辑位于 scripts/changed-lanes.mjs,并由 scripts/check-changed.mjs 执行。该本地检查门针对架构边界的约束比广泛的 CI 平台范围更严格:
- 核心生产变更会运行核心生产类型检查和核心测试类型检查,以及核心 lint/guards;
- 仅核心测试变更只运行核心测试类型检查以及核心 lint;
- 根 TypeScript 测试和支持文件会运行根测试类型检查,以及在
test/tsconfig/tsconfig.test.root.json内的目标类型感知 lint;可发现的test/tsconfig.json继承该仅源代码程序。它包含.ts、.tsx、.d.mts和.d.cts,不包含普通.mts/.cts;测试夹具和构建产物 Docker 客户端保持在目标根 lint 之外; - 扩展生产变更会运行扩展生产类型检查和扩展测试类型检查,以及扩展 lint;
- 仅扩展测试变更会运行扩展测试类型检查以及扩展 lint;
- 捆绑频道清单、包元数据、配置模式、UI 提示和生成器所有者也会运行捆绑频道配置元数据漂移检查;
- 配置模式/帮助、捆绑插件元数据、源模式条目的相对导入依赖、生成器/选择器所有者,以及受跟踪的配置基线变更会运行
pnpm config:docs:check,包括与普通文档混合的基线文件;全车道和发布元数据计划只包含一次; - 公共 Plugin SDK 或插件契约变更会扩展到扩展类型检查,因为扩展依赖这些核心契约(Vitest 扩展扫描仍保持为显式测试工作);
- 仅发布元数据的版本提升会运行目标版本/配置/根依赖检查;
- 未知的根/配置变更会安全地回退到所有检查车道。
src/、extensions/、ui/、packages/、scripts/ 和 test/ 下的 JavaScript 和 TypeScript 变更也会运行现有的完整未使用导出审计。仅导入的编辑以及删除的源文件或测试文件可能使未变更文件中的导出成为孤儿。
模式依赖选择会复用本地相对导入图,包括再导出以及仍被幸存源引用的已删除叶路径。共享 SDK 频道 UI 提示和秘密输入模式所有者,加上工作区敏感 URL 提示所有者,是跨越别名边界的显式根。对其 SDK 外观的编辑也会被选择,而无需遍历无关的外观运行时依赖。这不是通用的别名或计算导入解析。
本地变更测试路由位于 scripts/test-projects.test-support.mts,并且有意比 check:changed 更廉价:直接测试编辑会运行自身,源编辑优先使用显式映射,然后是同级测试和导入图依赖项。共享群聊房间投递配置是显式映射之一:对群组可见回复配置、源回复投递模式或消息工具系统提示的变更会路由到核心回复测试以及 Discord 和 Slack 投递回归,以便共享默认值变更在首次 PR 推送之前失败。仅当变更足够影响整个测试框架,以至于廉价的映射集不是可靠代理时,才使用 OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed。
Testbox 验证¶
Crabbox 是仓库拥有的远程盒子包装器,用于维护者 Linux 证明。Agent 会话默认在本地运行受信任的开发测试、变更门、类型检查/lint 和构建。当环境是证明的一部分时,它们使用 Crabbox:干净机器、安装/打包、Docker、E2E、实时、桌面、跨操作系统或 CI 一致性工作,或者当操作者明确要求远程证明时。Crabbox 不是通用的计算卸载。.crabbox.yaml 将远程证明默认设置为 blacksmith-testbox。其配置的工作流会注入提供者和 Agent 凭据,因此不受信任的贡献者或 fork 代码必须改用无密钥 fork CI 或经过净化的直接 AWS Crabbox。
该包装器使用捆绑的 Crabbox 插件的二进制管理器。所有提供者和云工作器配置文件都需要 Crabbox 0.69.0 或更高版本。这包括任务拥有的 Testbox SSH 拆除,可防止持久 SSH 主进程让空闲 Testbox 保持存活。缺失或较旧的二进制文件会在提供者发现或租约工作之前使用经过验证的受管 0.69.0 发布版本。原始二进制文件保持不变。提供者就绪状态和 broker 身份验证仍决定哪个已配置后端可以运行证明。
检查工作流以深度 1 检出注入其固定的 dispatch 提交;变更门随后重建确切的合并基和同步后的最终树。已分派的检查租约请求 blacksmith-32vcpu-ubuntu-2404。原生容量探针在该类上测得 8 个 CPU 和 30.95 GiB 内存,而之前的 16 类为 15.42 GiB。这为隔离运行时验证提供了余量,而无需增加作业或工作器数量。工作负载仍根据观察到的资源接纳工作;runner 标签不是容量保证。PR 水合检查仍保留在 ubuntu-24.04 上。
其外层 GitHub 作业默认为 240 分钟。手动分派可以覆盖 timeout_minutes。Testbox 空闲超时和单个测试截止时间仍保持为独立限制。
经过净化的 AWS 运行会设置 CRABBOX_ENV_ALLOW=CI,传递 --no-hydrate,并使用全新的临时远程 HOME;这可防止仓库 OPENCLAW_* 允许列表和现有身份验证配置文件到达不受信任的代码。它们使用专门用于该不受信任源的新预热租约,绝不使用受信任或先前已水合的租约。从干净的受信任 main 检出启动已安装的受信任 Crabbox 二进制文件,并使用 --fresh-pr 仅获取远程 PR;绝不在本地执行不受信任检出的包装器或配置。
取消设置 CRABBOX_AWS_INSTANCE_PROFILE,除非解析后的 aws.instanceProfile 为空,否则失败关闭。在任何安装/测试之前,使用受信任的绝对路径工具要求 IMDSv2 令牌,证明 IAM 凭据端点返回 404,并将远程 git rev-parse HEAD 与完整的已审查 PR head SHA 进行比较。将租约绑定到该 SHA,并在 head 变更时停止/重新预热。
从干净的 main 上传受信任的 scripts/crabbox-untrusted-bootstrap.sh,并与 --fresh-pr 一起使用;它会安装固定的 Node/pnpm,验证 SHA 和包管理器固定版本,隔离 HOME,安装依赖项,然后执行请求的测试。
当镜像提供 /opt/crabbox/toolchain-archives 时,引导程序会将匹配的 Node、pnpm 包装器和 pnpm 原生归档复制到私有临时存储,并根据受信任脚本中的摘要验证复制的字节。它仍会在每次调用时提取全新的 Node 和 Corepack 安装;现有可执行文件、相邻校验和和完成标记不是信任锚点。缺失或无效的缓存归档会使用经过身份验证的下载路径。
候选项不能推进包管理器固定版本;在推进工具链时,更新受信任的引导程序及其摘要锚点。
受信任的 Linux 水合使用共享的 Node 兼容性选择器,并可以从相同的已认证 pnpm 归档为作业私有的 Corepack home 播种。共享的 setup 操作也在其预热存储中携带已认证的 pnpm 归档,因此托管和 Blacksmith 作业可以在依赖安装之前引导,而无需再次下载 pnpm。这些归档不会替代冻结锁文件依赖安装。
当 install-bun: "true" 时,setup-node-env 在 Linux glibc x64 上还可以复用 /opt/crabbox/toolchain-archives 中原始固定的 Bun 1.4.2 ZIP 文件。它会先认证一个私有副本,然后提取新的作业私有 bun 和 bunx,再在 Node PATH 条目之后发布其目录。基线归档是默认值;优化版 x64 归档要求每个可见的来宾 CPU 都有 AVX 和 AVX2 证据。缺少 CPU 证据时使用基线。缺少匹配的归档或不支持的平台会保持固定的 npm 安装路径。存在但损坏或格式错误的归档会使 setup 失败,而不是回退到现有 Bun。install-bun: "false" 会跳过这两条路径;它不会移除 runner 已提供的 Bun。此复用不覆盖 ARM、musl 或不受信任的 bootstrap。
取消所有 CRABBOX_TAILSCALE* 覆盖,强制 --network public
--tailscale=false,清除 exit-node/LAN 标志,并在上传任何脚本之前要求 crabbox inspect 报告公共网络且没有 Tailscale 状态。自有的 AWS/Hetzner 容量也仍然是 Blacksmith 故障、配额问题或显式自有容量测试的回退。
对于显式授权的仅限管理员的 PR 落地回退,在 scripts/pr prepare-gates 之前设置 OPENCLAW_PR_GATES_REMOTE=crabbox-aws。该模式不会替代默认的托管聚合 gate。在精确的 prep head 被推送后,wrapper 同步分发 protected-main publisher。该受信任工作流通过校验和安装 Crabbox v0.46,通过 /v1/whoami 解析其服务主体,然后以 umask 022 运行经过净化的 brokered AWS、规范的 untrusted bootstrap、pnpm build、pnpm check,以及一个 fail-closed 的 PR 派生测试计划。现有 changed-test owner 独立评估每个可执行变更路径,并且必须将每个路径解析为具体匹配到的测试文件;宽泛回退、跳过路径、配置目标、已删除的可执行路径和部分计划会被拒绝。显式文档以及 AGENTS.md/CLAUDE.md 指令表面可能产生零测试计划。精确的 PR base SHA、head SHA、bootstrap 哈希和确定性计划摘要绑定到规范命令。publisher 通过 Crabbox 的 --script-stdin 流式传输 launcher。简短 broker 参数绑定 head SHA 以及 bootstrap、规范命令和 launcher 哈希。AWS 租约使用 90 分钟空闲超时和 240 分钟 TTL。pr-crabbox-gate-publisher.yml 工作流接受一个打开的草稿,因为证明在 prepare-push 期间运行;然后使用具有 Members(read) 的仓库原生 GitHub App token 重新读取同一仓库中的实时 PR 以及精确的活跃组织管理员成员资格对象(仓库范围的 workflow token 不被视为组织权限),在相同服务 token 下验证其新创建的已认证 broker 运行、有序的 complete 事件、独立重建的规范命令和 launcher 上传哈希,并仅为精确证明的 base/head/plan 绑定发布独立的 openclaw/crabbox-gate。publisher 还证明 PR base 是其不可变 protected-main workflow SHA 的 merge base,并将该 workflow SHA 添加到严格 check 摘要中。在远程运行之前和之后,它证明候选的实时 main 与该 workflow SHA 相同或派生自该 workflow SHA,然后重新读取 ref 并要求候选保持不变。在长时间远程运行期间允许后代前进;任一比较并重新读取窗口内的移动都会 fail closed。保留的 broker 日志在非空时会被验证,但它们是可选的,因为已发布的 Crabbox v0.46 在成功运行后可以报告零保留日志字节。只有在 publisher 和精确 head 检查成功后,本地 wrapper 才会从受信任摘要中派生 .local/gates.env 的 provider/run/lease/URL 恢复元数据;这些字段不是发布权限。
该回退永远不会替代或重新发布 openclaw/ci-gate。原生 merge 验证仍然拒绝草稿 PR,并且仅当 Crabbox check 由 GitHub Actions 在准备好的 SHA 上成功完成、其绑定的 workflow SHA 是稳定的最终实时 protected-main 快照的祖先、已认证操作者仍然是活跃组织管理员,且唯一未满足的必需 check 是正常 CI gate,并具有由 GitHub 拥有的 job 元数据表示的已识别 hosted-runner 基础设施故障(没有已执行的 workflow 步骤且没有分配 runner_name)时,才允许服务器 ruleset 绕过。Job 日志永远不是权威,因为 PR 代码控制其文本。缺失或不匹配的 check、取消、action-required 或 stale 结论、已分配 runner、任何失败或已执行的 workflow 步骤、未知 runner 后端、pending 上下文以及额外必需 check 失败仍然保持阻塞。只有 workflow startup_failure 或一个未获取的零步骤 hosted job 具有 failure/timed_out 才符合条件。原生流程在管理员 squash 请求之前立即重复完整的绕过验证,并使用 --match-head-commit 固定准备好的 head。GitHub 不暴露 expected-base-OID merge 前置条件,因此最终 main 读取可以最小化但不能原子地消除 base 移动竞态。落地证明必须将 squash parent 与该最终 main 快照进行比较,而不是与较旧的 workflow SHA 比较。Crabbox merge 路径将此比较存储在 .local/merge-crabbox-parent-audit.json 中,将其包含在完成评论中,并报告在已完成 merge 之后任何介入的 main 移动,而不声称原子预防。
代理不为预期工作预热。当第一个环境敏感命令就绪时,惰性获取 Testbox,将返回的 tbx_... id 复用于后续远程命令,在每次运行时同步当前 checkout,并在交接前停止它。
Crabbox 支持的 Blacksmith 运行会预热、申领、同步、运行、报告并清理一次性 Testbox。原生 Blacksmith 负责同步;Crabbox 的直接 SSH 同步控制和批量删除健全性检查不会在此委托路径上运行。
Crabbox 还会终止在同步阶段停留超过五分钟且没有同步后输出的本地 Blacksmith CLI 调用。设置
CRABBOX_BLACKSMITH_SYNC_TIMEOUT_MS=0 以禁用该保护,或对于异常大的本地差异使用更大的
毫秒值。
首次运行前,从仓库根目录检查 wrapper:
仓库 wrapper 会在运行前验证所选的 Crabbox 二进制文件和 provider。在 Codex worktree 或 linked/sparse checkout 中,避免使用本地 pnpm crabbox:run 脚本,因为 pnpm 可能在 Crabbox 启动前协调依赖;请改为直接调用 node wrapper:
node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox --timing-json --shell -- "pnpm test <path-or-filter>"
受支持的 sibling 或 PATH 中的二进制文件可以直接运行。wrapper 会自动
将过时的选择替换为插件管理的二进制文件;重新构建
sibling checkout 不再是证明的前置条件。
.crabbox.yaml 中的 blacksmith: 块已经固定了 org、workflow、job 和 ref 默认值,因此下面的显式标志是可选的。显式干净机器的 changed-gate 一致性:
pnpm crabbox:run -- --provider blacksmith-testbox \
--blacksmith-org openclaw \
--blacksmith-workflow .github/workflows/ci-check-testbox.yml \
--blacksmith-job check \
--blacksmith-ref main \
--idle-timeout 90m \
--ttl 240m \
--timing-json \
--shell -- \
"corepack pnpm check:changed"
当干净机器行为是证明的一部分时,进行聚焦测试重跑:
pnpm crabbox:run -- --provider blacksmith-testbox \
--idle-timeout 90m \
--ttl 240m \
--timing-json \
--shell -- \
"corepack pnpm test <path-or-filter>"
在显式请求的干净机器上运行完整测试套件:
pnpm crabbox:run -- --provider blacksmith-testbox \
--idle-timeout 90m \
--ttl 240m \
--timing-json \
--shell -- \
"corepack pnpm test"
读取最终 JSON 摘要。有用字段是 provider、leaseId、
syncDelegated、exitCode、commandMs 和 totalMs。对于委托的
Blacksmith Testbox 运行,Crabbox wrapper 的退出码和 JSON 摘要即为命令结果。关联的 GitHub Actions 运行负责 hydration 和 keepalive;当 SSH
命令已经返回后 Testbox 被外部停止时,它可能以 cancelled 结束。除非
wrapper exitCode 非零或命令输出显示测试失败,否则将其视为清理/状态产物。
一次性 Blacksmith 支持的 Crabbox 运行应自动停止 Testbox;
如果运行被中断或清理情况不明确,请检查活动 boxes,并只停止你创建的 boxes:
blacksmith testbox list --all
blacksmith testbox status --id <tbx_id>
blacksmith testbox stop --id <tbx_id>
对于同一任务中的多个命令,在第一个命令上分配,并复用其报告的 leaseId。使用唯一的任务标签。在最后一个命令之后停止 lease:
node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox --keep --label <unique-task-name> -- corepack pnpm test <first-file>
node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox --id <tbx_id> --label <unique-task-name> -- corepack pnpm test <next-file>
node scripts/crabbox-wrapper.mjs stop --provider blacksmith-testbox <tbx_id>
wrapper 会在 .crabbox/testbox-leases 下记录分配溯源。
复用要求相同的物理 checkout、HEAD、merge base、依赖输入、
准备输入、调用方 session 和标签。停止较旧或未记录的 leases,
并通过 wrapper 分配。OPENCLAW_TESTBOX_ALLOW_STALE 不再绕过这些检查。
Codex 和 Claude Code session 会自动提供 session 身份。
GitHub Actions 身份包括 workflow attempt 和 job。
这些身份标识的是 session,而不是单个请求。当一个 session 处理多个任务时,使用不同的标签。
人工 shell 对保留的 leases 需要标签。
session 拥有的 warmup --timing-json 也会记录分配溯源。
原生 Crabbox 会在拥有的 lease 上串行化命令。不要在任务之间共享 lease。
wrapper 会发出 testbox-admission 和 testbox-completion JSON 记录。
它们标识调用方类型、哈希后的 session/task 和 checkout、HEAD、命令
摘要、请求的超时、lease ID 以及调用时长。
Session ID、checkout 路径和命令内容不会被复制到这些记录中。
通过 lease ID 将它们与原生 timing 输出关联,以找到 Actions 运行。
这些是本地诊断信息,不是 Blacksmith dashboard 标签或计费生命周期测量。
委托 provider 不强制执行 --ttl。workflow job 超时和
Testbox 空闲超时仍然是有效的生命周期限制。
复用 lease,而不是过时的来源。Blacksmith Testbox 负责同步,包括
复用的 --id 运行。不要传递 --no-sync:wrapper 会在
lease 处理或委托之前拒绝它。指纹缓存命中不是 no-sync 保证。
同步成功不是来源身份的证明。在精确候选证明之前,验证已物化的 Git tree。 将 QA 证据保留在同步的 checkout 之外,并在另一次运行前下载它。不要绕过安全排除项、接受不匹配的 tree,或静默切换 provider。
不受信任的 contributor/fork 代码必须对每个命令使用
CRABBOX_ENV_ALLOW=CI、--provider aws --no-hydrate 以及全新的临时远程 HOME;在该净化命令内部安装依赖后再测试。只复用为同一不受信任来源专门新预热的 lease;绝不使用受信任或之前已 hydration 的 lease。绝不在本地执行不受信任 checkout 的 wrapper 或 config:从干净且受信任的 main 启动已安装的受信任 Crabbox 二进制文件,并在每次运行时传递 --fresh-pr。保持 CRABBOX_AWS_INSTANCE_PROFILE 未设置,拒绝非空的已解析 instance profile,要求受信任的远程 IMDS no-role 证明,并在 install/test 前验证已审查的 head SHA。将 lease 绑定到该 SHA;在任何 head 变化后停止并重新预热。如果不存在远程 PR,请使用无 secret 的 fork CI。对于不受信任来源,绝不选择 hydrate-github 或凭据 hydration 的 Blacksmith workflow。
如果 Crabbox 是故障层,但 Blacksmith 本身可以工作,则仅将直接 Blacksmith 用于诊断,例如 list、status 和清理。在将直接 Blacksmith 运行视为维护者证明之前,先修复 Crabbox 路径。
如果 blacksmith testbox list --all 和 blacksmith testbox status 可以工作,但新的预热实例在几分钟后仍处于 queued 状态,且没有 IP 或 Actions 运行 URL,则将其视为 Blacksmith 提供商、队列、计费或组织限制压力。停止你创建的排队 id,避免启动更多 Testboxes,并在有人检查 Blacksmith 仪表板、计费和组织限制时,将证明转移到下方的自有 Crabbox 容量路径。
仅在 Blacksmith 宕机、受配额限制、缺少所需环境,或明确以自有容量为目标时,才升级到自有 Crabbox 容量:
CRABBOX_CAPACITY_REGIONS=eu-west-1,eu-west-2,eu-central-1,us-east-1,us-west-2 \
pnpm crabbox:warmup -- --provider aws --class standard --market on-demand --idle-timeout 90m
pnpm crabbox:hydrate -- --provider aws --id <cbx_id-or-slug>
pnpm crabbox:run -- --provider aws --id <cbx_id-or-slug> --timing-json --shell -- "pnpm check:changed"
pnpm crabbox:stop -- --provider aws <cbx_id-or-slug>
在 AWS 压力下,除非任务确实需要 48xlarge 级别 CPU,否则避免使用 class=beast。beast 请求从 192 vCPUs 开始,并且是最容易触发区域 EC2 Spot 或 On-Demand Standard 配额的方式。仓库拥有的 .crabbox.yaml 默认为 class: standard、按需市场和 capacity.hints: true,以便代理的 AWS 租约打印所选区域/市场、配额压力、Spot 回退以及高压 class 警告。对更重的广泛检查使用 fast,仅在 standard/fast 不够时使用 large,并且仅在异常 CPU 密集型通道中使用 beast,例如完整套件或全插件 Docker 矩阵、明确的发布/阻塞验证或高核心性能分析。不要对 pnpm check:changed、聚焦测试、仅文档工作、普通 lint/typecheck、小型 E2E 复现或 Blacksmith 故障排查使用 beast。容量诊断时使用 --market on-demand,以免 Spot 市场波动混入信号。
.crabbox.yaml 负责提供商、同步和 GitHub Actions 水合默认值。Crabbox 同步从不传输 .git,因此已水合的 Actions checkout 保留其自身的远程 Git 元数据,而不是同步维护者本地 remotes 和对象存储,并且仓库配置还额外排除本地运行时/构建产物(例如 .artifacts 和测试报告),这些内容绝不应被传输。.github/workflows/crabbox-hydrate.yml 负责 checkout、Node/pnpm 设置、origin/main fetch,以及自有云 crabbox run --id <cbx_id> 命令的非机密环境交接。
Linux 水合保留物理工作区 node_modules 目录和 pnpm 的默认 .pnpm 虚拟存储。只有包内容存储使用持久 /var/cache/crabbox/pnpm/store 卷;其回退位于工作区依赖旁边的 .cache/openclaw-pnpm-store。普通 POSIX 同步会保留这些被忽略的目录,因此冻结重装和后续构建命令使用相同的自有安装。水合在将租约标记为就绪之前会检查工具加载器。当重新水合较旧的租约时,工作流在安装物理工作区依赖之前,仅退役其先前指向 /var/tmp/openclaw-pnpm/node_modules 或 ${XDG_CACHE_HOME:-$RUNNER_TEMP/cache}/openclaw/pnpm/install/node_modules 的根链接,包括那些 runner 缓存已被清除的链接。它保留外部包缓存和无关依赖链接。
原生 Windows 守护进程水合保留其外部依赖 junction,因为已发布的 Crabbox 原生 Windows delete-sync 会替换工作区内容。只有在使用保留生成依赖目录的 Crabbox 同步版本时,才将该路径迁移到物理工作区依赖。
相关¶
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw