ancha.

三条路怎么选

目标就三件:make it work,支持 trace,在客户那边跑。三条路用的是同一个世界(twin、人、时钟、checks),差别只在两件事:谁管流程,是 Ancha 还是他们自己的测试;谁写接线,是客户的 Claude Code 还是 Ancha 自己。

2026-11-06 · 依据:Ancha 代码(plan/trace-import 分支)和 Inbox Zero 实验 · 工作量按 session 估,没做过的地方都标了

建议:走第 1 条,顺手借第 3 条的一个点。Ancha 管 trial 和世界;他们的应用一直开着,每个 trial 之前重置一次;流程靠场景里的人和事件触发,需要的时候也可以拿他们自己的测试命令当驱动。

理由:从 trace 拉下来的场景,接一次线就能全部跑起来;它跑在客户的仓库和 CI 里,胶水由客户的 Claude Code 写;要新写的代码最少,因为原来的 endpoint 模式已经有了一半。第 2 条先不做,等接过两三个仓库、看清哪些胶水在重复,再搬进 Ancha。

先澄清一件事:Inbox Zero 那次走的是第 3 条

SPEC-001/002 跑通的那次,世界是我写的脚本在每个 trial 开一次,流程和判分都交给他们的 vitest:看草稿有没有写进那个线程,followUpAppliedAt 有没有值。ancha run 一次都没参与。所以"Ancha 管流程"在真实应用上还没试过,下面第 1 条的工作量就是为这个估的。

三条路放在一起

1 客户迁就我们2 我们迁就客户3 放进他们的测试
谁管流程AnchaAncha他们的测试
谁写接线客户的 Claude CodeAncha,客户只写一份清单客户,每个流程写一个测试
我们新写约 450 行,1–2 session约 2000 行,5–8 session约 600 行,约 2 session
客户仓库多出ancha.yaml 加几个脚本,约 200 行约 30 行清单,加种子数据每个流程一个测试,约 150 行
trace 场景直接跑直接跑每个都要测试来驱动
应用的时钟应用由 Ancha 启动,有办法同左只有测试进程里的调用跟得上
离能用多远约 3 session 能在 Inbox Zero 上跑 ancha run最远最近,SPEC-001 已经是这个形状
像谁原来的 Ancha—Arga、Archal、Hue

三条都还要再加下面的"共同底座":约 1200 行,4–5 session。行数都是估算,不含测试。

不管走哪条,都要先补的世界这边

这些是 Inbox Zero 实验暴露出来的缺口,跟谁管流程无关。

  1. Gmail 推送搬进 twin。SPEC-001 里是 121 行的 bridge 补上的:watch、推送、批量请求、设置。现在世界推出去的事件里没有 Gmail。约 300 行 · 1 session
  2. 人能通过 Gmail 行动。simulated people 现在只会走 Slack 和 GitHub,Tom 没法回邮件;按消息顺序判分的 check 也只看这两种。约 350 行 · 1–1.5 session
  3. 前门。应用一直开着,每个 trial 换一个新世界,但应用看到的地址和 token 不变。SPEC-001 是靠每次重启 bridge 做到的。约 200 行 · 0.5–1 session
  4. 应用的时钟跟上世界。世界的时钟已经能快进(advance),但应用代码里的 new Date() 不会跟着跳。先在 Node 上做。约 100 行 · 1 session · 没试过
  5. trace 支持 Gmail,并且在本地转换。现在的 trace 读取器只认 Slack、GitHub、Datadog、PagerDuty;ancha import 会把文件传到我们的服务器上转换。要在客户那边跑,就得改成在 CLI 本地转换,默认什么都不上传。约 250 行 · 1 session

trace 能重建对面的世界(邮件、人、本该发生什么),重建不了应用自己的数据库(用户的规则、设置),那部分还是要用他们的种子数据。τ² 的 E3 也说明,从失败 trace 推出来的人是最弱的一环。三条路都绕不开这两点。

1 · 客户迁就我们建议

原来的方案基本不动,客户的 Claude Code 写接线,把应用接进 ancha.yaml。下面是 Inbox Zero 用这条路时,仓库里会多出来的配置:

agent:
  # 开数据库和 Redis、迁移、种数据、启动应用
  start: ./ancha/start.sh
  ready_url: http://localhost:3000/api/health
  # 世界往这里推 Gmail 事件
  url: http://localhost:3000/api/google/webhook
  # 新:每个 trial 之前清掉他们的库和 Redis
  reset: ./ancha/reset.sh
  # 新(可选):拿他们自己的测试当驱动
  command: pnpm test-e2e:flows ancha-follow-up
  env:
    GOOGLE_BASE_URL: "{{gmail.url}}"
# 手写的,或者 ancha pull 从 trace 拉下来的
scenes: [ancha/scenes/**/scene.yaml]
trials: 10

橙色是要新加的,其余字段今天就有。

我们要改的

主要改 backend/src/runner/endpoint.ts、run.ts、config.ts 和场景的 schema。约 450 行,1–2 session。

做完之后

风险

2 · 我们迁就客户

第 1 条的基础上,把客户要写的胶水搬进 Ancha:用他们自己的 compose 或脚本开应用,自己给数据库拍快照、每个 trial 还原,自己认出 base-URL 开关,没有开关就拦截网络。

# 整块都是新的
app:
  up: docker compose up -d db redis && pnpm dev
  ready: http://localhost:3000/api/health
  # Ancha 拍快照,每个 trial 还原
  state: [postgres, redis]
  # 认出 GOOGLE_BASE_URL 这类开关,没有就拦截
  routes: auto
  # 可选:用他们自己的测试判分
  test: pnpm test-e2e:flows {{scene}}

我们要改的

约 2000 行,5–8 session。

做完之后

风险

3 · 放进他们的测试里

他们的 vitest 管流程,Ancha 是测试里调用的一个库,提供世界、人、时钟和多次运行。示意:

// 新包
import { world } from '@ancha/test'

test('Tom 第二天回了信,不该再提醒', async () => {
  // 每个测试一个新世界
  const w = await world.up('ancha/scenes/follow-up.yaml')
  // 他们自己的 helper
  await sendTestReply({ to: TOM })
  // 场景里的 Tom 在第 2 天回信
  await w.advance('3d')
  // 只有测试进程里的时间跟得上
  vi.setSystemTime(w.now())
  await processAccountFollowUps({ emailAccount, logger })
  expect(await w.check('no_follow_up_draft')).toBe(true)
})

我们要改的

约 600 行,约 2 session。

做完之后

如果走第 1 条,接下来的顺序

  1. make it work:把 Inbox Zero 那次改成用 ancha run 跑,在 E2B 里跑 10 个 trial。要做底座第 1、3 项,加上第 1 条的生命周期改动。约 3 session。
  2. 人和时钟:Tom 第 2 天回信,就不该提醒;Tom 一直不回,第 3 天要提醒。要做底座第 2、4 项。约 2 session。
  3. trace:用有 bug 的版本造一条失败的 trace,拉成场景,ancha run 能复现出来。要做底座第 5 项。约 1–2 session。
  4. 第二个仓库:用新的文档在 Chatwoot 上跑一次冷启动,量一下接第二个仓库要多少胶水。1 session,最多花 $10。

合计约 7–8 session。顺序和取舍等你定。