Sandbox 测试
一个可复现的、基于证据的回答,用于回应这个问题:
Archon 的 install / update / sync / uninstall 协议在每一个支持的 IDE 与语言上,是否真的能在真实项目中端到端工作?
每个 sandbox 测试都会取一个干净的 fixture 项目(没有 .archon/, 也没有 binding 目录),运行一条 Archon 生命周期命令(通过 agent 或 CLI),并将生成的目录树与预期结果进行比对。每一次 run 都会记录日期、 manifest 版本、runner 与结果,让你可以审计真实情况,而不是承诺。
与 Contract 测试 的区别
| 层级 | 关心的问题 | 位于 |
|---|---|---|
| Contract 测试 | "框架文件之间是否内部一致?"(文件形态、交叉引用、行数上限、禁用子串) | scripts/archon-check.py,针对 .archon/contracts/governance-contract.yaml 运行 |
| Sandbox 测试(本节) | "在某个 IDE / 语言下,install 协议是否能在一个真实的全新项目上生成有效的目录树?" | /zh/testing/sandbox/scenarios/ 下的 scenario 页面 —— 每个都由 fixtures/ 中的 fixture 支撑 |
两层都是必须的。Contract 测试是静态的,每次提交都会运行;sandbox 测试 则是 scenario 驱动的,每次发布都会运行(在新增 IDE / 语言目标时也会 按需运行)。
12 个 scenario 矩阵
第一版矩阵覆盖 生命周期阶段 × IDE × 语言,并在最常见的技术栈 (Cursor + Node + TS)上有意保留重叠,以便 update / sync / uninstall scenario 可以在 install scenario 之上链式执行。
| # | test-id | 阶段 | IDE | 语言 |
|---|---|---|---|---|
| 01 | install-cursor-node | install | Cursor | Node + TS |
| 02 | install-claude-python | install | Claude Code | Python |
| 03 | install-codex-go | install | Codex CLI | Go |
| 04 | install-aider-rust | install | Aider | Rust |
| 05 | boot-cursor-node | boot | Cursor | Node + TS |
| 06 | boot-claude-python | boot | Claude Code | Python |
| 07 | update-cursor-node | update | Cursor | Node + TS |
| 08 | update-cli-without-cli | update + --without=cli | Cursor | Node + TS |
| 09 | sync-clean | sync(无 drift) | Cursor | Node + TS |
| 10 | sync-modified | sync(检测到 drift) | Cursor | Node + TS |
| 11 | uninstall-preserve | uninstall(保留 ledger) | Claude Code | Python |
| 12 | uninstall-archive | uninstall(归档 ledger) | Cursor | Node + TS |
完整网格(含 fixture / 状态列)请见 Test Matrix 页面, 或跳转到 Test Fixtures 查看每个 scenario 安装目标所使用的 项目骨架。
最近一次 run 的概要
下方表格是判断 "Archon 是否可发布" 的唯一事实来源。在每一行的 最近一次 run 都对候选 manifest 版本 passing 之前,本次发布不会上线。
它由 runs/index.json 实时渲染,该文件会在每次调用 scripts/sandbox-run.mjs 时(本地 + GitHub Actions)重新生成。修改某个 scenario 后,运行下面的 命令即可刷新:
node scripts/sandbox-run.mjs --runnable=cli # CLI scenarios
node scripts/sandbox-run.mjs --runnable=agent # agent scenarios (currently → manual)| Scenario | Stage | Latest result | Manifest | Runner | Duration | Recorded |
|---|---|---|---|---|---|---|
| install-cursor-node | install | ✅ passing | v0.1.0 | cli | 231 ms | 2026-05-06 10:24:35 |
| install-claude-python | install | ⏳ manual | v0.1.0 | manualclaude | 2 ms | 2026-05-06 10:24:38 |
| install-codex-go | install | ⏳ manual | v0.1.0 | manualcodex | 1 ms | 2026-05-06 10:24:38 |
| install-aider-rust | install | ⏳ manual | v0.1.0 | manualaider | 1 ms | 2026-05-06 10:24:38 |
| boot-cursor-node | boot | ⏳ manual | v0.1.0 | manualcursor | 224 ms | 2026-05-06 10:24:38 |
| boot-claude-python | boot | ⏳ manual | v0.1.0 | manualclaude | 222 ms | 2026-05-06 10:24:38 |
| update-cursor-node | update | ✅ passing | v0.1.0 | cli | 353 ms | 2026-05-06 10:24:37 |
| update-cli-without-cli | update | ❌ failing | v0.1.0 | cli | 345 ms | 2026-05-06 10:24:37 |
| sync-clean | sync | ✅ passing | v0.1.0 | cli | 372 ms | 2026-05-06 10:24:35 |
| sync-modified | sync | ✅ passing | v0.1.0 | cli | 386 ms | 2026-05-06 10:24:36 |
| uninstall-preserve | uninstall | ✅ passing | v0.1.0 | cli | 367 ms | 2026-05-06 10:24:36 |
| uninstall-archive | uninstall | ✅ passing | v0.1.0 | cli | 357 ms | 2026-05-06 10:24:36 |
状态图例:✅ passing · ❌ failing · ⏳ manual(尚无 SDK adapter, 详见 KNOWN-003) · · pending(暂无 run 记录)。
failing行不是 runner 噪声 —— 要么是真实的 CLI 回归,要么 是某个 scenario 的断言需要更新。无论哪种情况,在解决之前它都会 阻塞发布。
如何新增一个 scenario
- 找到缺口:尚未覆盖的 阶段 / IDE / 语言 组合。
- 在
fixtures/下选择(或新增)一个 fixture —— 约定参见fixtures/README.md。 - 将
template.md拷贝到scenarios/<test-id>.md, 填写 front-matter + steps + 预期结果。 - 把这一行加入 Test Matrix 以及上面的 最近一次 run 的概要 表格(状态填
pending)。 - (在你真正执行它之后)录制 mp4 + cast,上传到
docs/public/videos/<test-id>.mp4与docs/public/asciinema/<test-id>.cast,并在同一 commit 里把状态 翻成passing。
为什么我们要让 pending 行始终可见
一个被搁置在 "我之后会写这个测试" 状态下的 scenario 页面会很快腐坏。 通过在 run 之前就把页面(包含 pending 状态、预期步骤、空的录制 位)提交进来,可以发生三件事:
- 矩阵能诚实地反映覆盖率缺口。
- 预期结果在 run 之前就被固定下来,避免了让测试去迁就实际发生情况 的偏差。
- 任何人(包括未来的维护者)都可以接手一个
pendingscenario 并执行 它,而不必从零去构思它。