swe-marathon-five-arm
Migrate historical SWE-Marathon agent configurations to the shared Codex runtime.
在 Terminal-Bench 4.0 上做 codex harness 五臂对照(裸 codex / 原生 /goal / LoopX 三模式)。复用 SWE-Marathon 那套驱动,靠 WEN_BENCH 切换。重点是 TB4 相对 SWE-Marathon 的四处结构性差异——每一处踩错都**退出码 0、有轨迹、有分数**,只是分数不对。
$ npx -y skills add loopx-project/loopx --skill tb4-five-arm --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/tb4-five-armContext preview
The summary Claude sees to decide when to auto-load this skill.
在 Terminal-Bench 4.0 上做 codex harness 五臂对照(裸 codex / 原生 /goal / LoopX 三模式)。复用 SWE-Marathon 那套驱动,靠 WEN_BENCH 切换。重点是 TB4 相对 SWE-Marathon 的四处结构性差异——每一处踩错都**退出码 0、有轨迹、有分数**,只是分数不对。
name: tb4-five-arm description: 在 Terminal-Bench 4.0 上做 codex harness 五臂对照(裸 codex / 原生 /goal / LoopX 三模式)。复用 SWE-Marathon 那套驱动,靠 WEN_BENCH 切换。重点是 TB4 相对 SWE-Marathon 的四处结构性差异——每一处踩错都**退出码 0、有轨迹、有分数**,只是分数不对。
五臂定义、LoopX profile 装配、agent 类、监控工具全部与 [[swe-marathon-five-arm]] 相同,**先读那一份**。这里只写 TB4 特有的部分。
对照维度仍是 **harness 不是模型**:五臂的模型、effort、工具面、沙箱、容器一致。
export WEN_BENCH=tb4 # 必须 export,见下面「最毒的一个坑」 source env.sh ./scripts/prebuild_images.sh music-harmony # 应建 2 个镜像,不是 1 个 ./scripts/verify_envs.sh music-harmony # install-only,不烧 token ./scripts/canary_timeout.sh # 五臂 × 短死线 ./scripts/marathon_all.sh --dry # 63 任务 × 5 臂 = 315 trial
benchmark 相关的量全在 `scripts/bench/tb4.sh`,驱动脚本里没有任何 TB4 常量。 `WEN_BENCH` 不设时默认 `swe-marathon`,行为与引入 bench 层之前逐字一致 (已用 `bash -x` 逐参数 diff 验证过)。
`terminal-bench/` 是 `harbor-framework/terminal-bench` 的 **tag v4.0.0** (commit `452bf305c6`),66 个任务,见 `terminal-bench/VERSION`。
`dataset` 表)里只有 `terminal-bench@2.0`,实测查 4.0 返回 `null`。
跟 main 跑出来的结果不可复现。
一个字节都不能改。要注入环境变量走 harbor 的 `--ve` / `--ae`。
| 项 | SWE-Marathon | TB4.0 | |---|---|---| | `agent.timeout_sec` | 3600–36000 各异 | **全部 28800(统一 8h)** | | `verifier.environment_mode` | 无(shared) | **全部 `separate`** | | `network_mode` | 三态,逐任务 | **一个都没声明** → harbor 默认 public | | 每任务镜像数 | 1(`environment/`) | **2(`environment/` + `tests/`)** | | 连续分 | `metrics.json` 有 | **没有**,只有二值 reward |
排除 3 个要 H100 的任务(`fp8-rmsnorm-gemm` / `jax-speedrun-gpu` / `math-eval-grader`),本机是 4090D。剩 63 个,其中 11 个是多容器 (`environment/docker-compose.yaml`),1 个(`medical-claims-processing`) 还要 MCP server(playwright,sse `http://playwright-mcp:3080/sse`)。
WEN_BENCH=tb4 source env.sh # ✗ 错 export WEN_BENCH=tb4; source env.sh # ✓ 对
bash 在 `source` 返回后会把前缀赋值的变量**还原成未设置**,但 `WEN_TASKS_DIR` 是 export 的、留了下来。于是后续任何脚本自己 source env.sh 时:`WEN_BENCH` 空 → 回退 swe-marathon profile,却继承着 TB4 的任务目录 —— 拿 **TB4 的任务**、套 **marathon 的网络策略**(`from-task` 找不到 `network_mode` 就断网)、 开着判官注入、写进 `marathon-full/`。退出码 0,全程无警告。
`env.sh` 里有个一致性闸门专门拦这个(`WEN_TASKS_DIR_BENCH` 与当前 bench 不符 就丢弃继承值),但闸门只保证**状态自洽**,不保证是你想要的那个 bench。 开跑前看一眼各脚本打印的 `bench:` 那一行。
TB4 的 66 个 `task.toml` **一个都没有声明 `network_mode` / `allow_internet`**, 而 harbor 0.20.0 的 `NetworkPolicy.network_mode` 默认是 `PUBLIC` —— 上游的标定条件是联网。
而 `marathon_run.sh` 原本的做法是 grep `task.toml` 的 `network_mode`、 **找不到就回退 `no-network`**。直接套用会把 66 个任务全跑成断网: 退出码 0、有轨迹、有分数,只是分数偏低,看着像"模型不行"。
`bench/tb4.sh` 里 `BENCH_NET_POLICY=public` 显式钉死,不走那条 grep。
**另注:`--allow-agent-host` 在 public 下是空操作。** 实测 harbor 会打印
UserWarning: Run-specific allowlist host(s) ['<model-gateway>', '<container-gateway>'] are ignored because the effective network policy is public.
模型端点的可达性靠代理环境变量和宿主机路由,不靠这个参数,别以为加了就生效。
**再注:本机实测容器不穿代理也能出网**(`docker run` 里直连 pypi.org 得 200)。 代理注入是沿用 marathon 对 public 任务的既有做法、属冗余保险; `no_proxy` 已包含模型网关,不会劫持 codex 的调用。
全部 66 个任务都是 separate。harbor 0.20.0 的实际时序 (`harbor/trial/single_step.py:38-55`、`trial/trial.py:610-680`):
跑 agent → 上传 agent 日志 → 收 artifacts → **停掉 agent 环境**
→ 起一个从 tests/ 构建的独立 verifier 环境 → 验证 → 停三个后果:
1. **每个任务两个镜像**(66 × 2 = 132)。`prebuild_images.sh` 原来只扫 `environment/`,漏掉 `tests/`。漏了的话 verifier 镜像会在**运行期**首次构建, 而运行期没有代理(那是刻意的,代理进运行时容器会破坏隔离),dockerd 自己钉的 `<dead-dockerd-proxy>` 又是死的 → `apt-get` 超时 → verifier 起不来记 errored。 **症状极像"任务没做出来"**:agent 阶段完全正常、有轨迹、有 token 消耗。 现在由 `BENCH_IMAGE_DIRS=(environment tests)` 覆盖,且跳过会计数。
2. **只有声明在 `artifacts` 里的文件能跨到 verifier**(66 个全声明了)。 agent 把活干在别处、没写到声明路径 → verifier 看到空目录 → reward 0, 而 agent 轨迹完全正常。这是 shared 模式下不存在的失败模式。
3. 串行,所以每 trial 的容器/网段**峰值**不翻倍,但多一次构建、 多一个 compose project。
SWE-Marathon 靠任务自写的 `metrics.json`(`partial_score` / `pass_rate` / `pytest` / `gates_*`)补救;**TB4 不写这个文件**,只有 harbor 的二值 reward。
`bench/tb4.sh` 设 `BENCH_HAS_PARTIAL=0`,于是:
(一列 0.0 会被读成"全都没得分",比不显示更坏)
marathon 那轮实测:撞死线的 23 条 trial 无一得分,自己收尾的 14 条中 11 条得分 ——决定分数的是"能不能在预算内做完"。TB4 统一 8h 预算而我们的死线远短于此, 这个问题只会更严重。**唯一还能分辨的信号是终止原因**(自己收工 vs 撞死线), `_receipts.py` 有这个数据,报表必须并排给出。
marathon 用的是 build 6× / setup 3× / verifier 4×,那是为**未做资源标定**的 Dockerfile 定的。TB 4.0 的卖点恰恰是"重新标定了 time/CPU/memory" (`build_timeout_sec` 中位数 900、`verifier.timeout_sec` 中位数 600), 照抄 6× 等于把上游的标定压掉。`bench/tb4.sh` 用 4 / 3 / 2。
`canary_timeout.sh` 的 `CANARY_TIMEOUT_MULT=0.05` 是按 8h 声明预算定的 (8h × 0.05 = 24 分钟 > `GOAL_TIMEOUT_SEC` 5 分钟,保证**我们先到**)。 TB4 恰好也统一 8h,所以同一个值仍成立。换到声明预算短的 benchmark 上, harbor 侧可能反而先到,冒烟就白做了 —— 而那是**静默**的: 五臂照样出 result.json,只是走的是另一条超时路径。
63 任务 × 5 臂 = **315 trial**,外加 126 个镜像构建。 `MARATHON_AGENT_TIMEOUT_MULT` 沿用 marathon 的 0.3 得 8640s(2.4h)/trial。 **先拿冒烟的真实单 trial 墙钟再算总时长**,别直接开全量。
网段池是硬约束:默认约 32 个 bridge 网络,机器共用。起跑前确认池子有余量 (`marathon_all.sh` 有 `MARATHON_NET_CAP` 闸门),清理容器时**连 compose 网络 一起清**(`docker rm -f` 不删网络)。
冒烟只覆盖单容器路径。`ctr-optimization` `cumulative-layout-shift` `freight-dispatch-shift` `heat-pump-warranty` `intrastat-meldung` `kv-live-surgery` `legacy-utility-triage` `live-database-cutover` `medical-claims-processing` `nextjs-performance` `payments-pipeline-fix` 容器数与内存压力显著更高;`medical-claims-processing` 还要 MCP server 起得来。全量前单独验这 11 个。
tb4-full/<task>/<arm>/<stamp>/<arm>/result.json job 级,含 stats
/<trial>/verifier/ reward.txt
/agent/ trA control plane with a durable state kernel for long-horizon agents and teams. Keep work moving and improving across sessions, with less human attention.
Repo: loopx-project/loopx
Migrate historical SWE-Marathon agent configurations to the shared Codex runtime.
Inspect authorized LoopX Goals, Todos and deliveries to explain progress, identify owner…
Use when acting as the operator or post-run analyst of a LoopX-managed benchmark experiment…
Qualify the exact final diff for a LoopX-managed goal. Use when goal policy enables…
Use when a connected LoopX project is asked to read, remember, record, index, register, or…
Operate an explicitly activated LoopX Material Lifecycle for a connected project. Use for…