Files
MoviePilot/docs/refactor/agent-codex-parity-plan.md
2026-09-12 14:49:47 +08:00

124 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MoviePilot Agent 与 Codex Harness 对齐路线
> 归档位置:`docs/refactor/`。
更新时间:2026-09-12
这份文档是 Agent 能力对齐的交付路线和每轮验收合同。它记录当前证据与未完成目标,不把一次成功的模型调用当成“已经和 Codex 一样聪明”。最终判断必须同时看模型行为、工具执行、任务生命周期、业务终态和失败后的收敛结果。
## 当前目标
让 MoviePilot Agent 在 MoviePilot 的真实业务边界内具备可复核的 Codex 级 Harness 能力:模型能看到准确的工具合同,工具能完成完整的命令行、浏览器、终端输入输出、子代理和长任务协作闭环,宿主能隔离任务身份、收口进程并在新消息到达时继续推进。高影响业务动作仍由宿主的授权和确认策略控制。
真实模型评测必须使用显式配置的供应商模型和推理档位。历史 Google Gemini 基线为 `gemini-2.5-pro + high`;后续测评切换为更强的 `gemini-3.1-pro-preview + high`。官方 Google 主机由评测 worker 使用生产同源的 `langchain-google-genai` 原生工具通道,以保留 Gemini 3 的 `thought_signature`;报告会把实际 `runtime_transport` 记为 `google_generative_language`。不同模型、供应商或协议的结果不能直接合并;首个同条件原生 Codex 配对样本未同时通过,随后同 Harness 的 `dedup_existing` 和 `unknown_download` 配对已同时通过,`honest_unknown` 仍保留原生侧预算耗尽失败。
Google 的 OpenAI-compatible 层会丢失 Gemini 3 工具回复中的 `thought_signature`,第二轮请求因此可能被供应商以 400 拒绝。真实 MoviePilot Agent 的 `runtime == "google"` 已固定走 `ChatGoogleGenerativeAI` 和签名兼容补丁;需要修正的是评测或错误的 provider 配置,不能通过普通 OpenAI 消息层补回签名。该边界由 `tests/test_agent_vision_providers.py`、`tests/test_llm_helper_testcall.py` 和本轮真实原生 Google 运行共同覆盖。
## 交付顺序
| 目标 | 状态 | 验收重点 |
| --- | --- | --- |
| C1.4 终端工具完整闭环 | PTY 当前夹具三轮配对通过;原生 pipe stdin 仍受边界阻塞 | `run/pipe/PTY` 共用 shell、cwd、login 和 UTF-8 策略;stdin 写入、EOF、分页、interrupt/kill、超时和进程组收尾有真实进程测试。原生终端场景经由 app-server 采集 `outputDelta`/`terminalInteraction`,并按评测预算保留足够的流式空闲时间;当前 PTY 夹具在回复后保留 30 秒收尾窗口,三轮配对均观察到输入、输出和退出码;pipe 配对仍保留原生 CLI 关闭 stdin、未产生 `terminalInteraction` 的失败证据;聚合输出中的相同字符串不再被当作输入证据 |
| C1.3 终端任务作用域 | 已完成 | 终端归属由宿主对象身份决定;定时运行、会话、子任务和内部工具管理器隔离;封口先于清理,排队或运行中的命令都不会在任务结束后迟到启动 |
| S2.3 运行中消息排队与 WebAgent 输入 | 实现完成,单条三轮与多条一轮真实配对通过 | 运行中仍可提交新消息;消息按会话原子入队,在下一次模型调用边界注入真实 `HumanMessage`;SSE 报告 queued/applied,稳定 `steering_message_id` 贯穿展示快照、前端本地状态和恢复合并;应用点收口当前助手并创建 continuation 助手,用户气泡落在真实事件边界;文本、工具、主动消息、错误和终态事件携带 `assistant_message_id`,前端按事件身份回放迟到事件;工具按 `tool_id` 报告 running/done/error;停止后不再派发后续工具 |
| C1.5 长上下文压缩与任务约束保留 | 同条件配对已通过 | 真实压缩前后预算约 69.5K → 26.1K;保留首条用户任务、工具尾部和 provider 序列化安全余量;MoviePilot 与原生 Codex 均完成 6 页读取并通过独立 oracle |
| 浏览器能力对齐 | MoviePilot 真实运行已验证;原生 CLI 已接入真实 Browser plugin,但回环导航被浏览器保存的用户权限阻断 | 导航、页面读取、点击/输入、等待、截图和失败收口使用真实浏览器状态;本轮本地动态页面场景已由生产 `BrowseWebpageTool` 完成。原生 `codex exec 0.153.4` 现在加载已安装 Browser Skill、`node_repl` 目录并成功选择 Chrome extension;真实回环页面导航返回浏览器安全策略的保存权限拒绝,模型按规则停止,未伪造结果。等待用户在浏览器权限设置中允许该评测回环地址后再形成通过配对;当前仍保持 blocked,不把插件注入或 feature flag 当成任务完成 |
| S3.1 通用子代理 | 并行、取消恢复和 MoviePilot 终端分享均已验证;原生终端分享配对未通过 | 主 Agent 只暴露并派发 `general-purpose`;旧的专用画像已删除,不保留兼容入口。`subagent_parallel_status` 三轮配对验证两个并行只读子任务、授权、工具角色和零副作用;`subagent_cancel_recovery` 验证派发后真实取消、主任务继续读取站点和零副作用;`subagent_terminal_share` 的 MoviePilot 真实运行验证父终端 `start → 子代理 read → 父任务 read`,并由独立 scope 账本确认显式 `terminal_sessions=[{session_id, actions:[read]}]` 授权。原生 Codex 在同场景中执行了命令并返回 `blocked` JSON,但没有形成可核验的子代理终端读取 scope、输入事件或父会话句柄闭环,严格配对保持 `both_passed=false`;这保留了原生 Harness 的终端分享边界,不能把生产单边通过当作整体对齐 |
## 下一轮目标顺序
1. **C1.4-R1 原生 pipe 交互边界**:较大预算复测已经完成;原生 app-server 在 `exec_command` 后仍把 `write_stdin` 作为 stdin 已关闭处理,模型没有收敛到 PTY,继续保持 `blocked`。只有原生 CLI 修复该会话边界或真实 Harness 产生可恢复的交互事件后,才重新配对;不修改生产 pipe 合同来掩盖差异。
2. **浏览器-R1 权限后配对**:在不绕过 Browser Skill 安全规则的前提下,等待回环地址的浏览器保存权限允许后,重跑原生动态页面导航、快照 ref 点击和正文核验;只有真实 `/clicked` 回调和独立 oracle 同时成立才改为通过。
3. **S2.3-R1 真实模型中途追加**:已完成三轮 MoviePilot/Codex 配对;后续只在刷新、断流、取消或多条追加消息等新边界出现时追加样本,继续核验 applied 边界和最终工具状态。
4. **S3.1-R1 终端协作收益**:MoviePilot 生产路径已经形成显式只读共享终端的真实证据;同条件原生 Codex 配对 `/tmp/moviepilot-agent-round-luna-oauth-subagent-terminal-share-pair-v3-20260912.json` 为 `pair_valid=true`、`both_passed=false`,原生虽返回 `blocked` JSON,但独立评分没有观察到子代理终端读取、真实父会话 scope 或终端输入事件。继续等待原生 Harness 能提供稳定的父终端句柄与子任务 scope;在此之前维持单一通用子代理体系,不把失败改判为通过。
## 每轮硬门禁
每个影响 Agent、工具、会话、浏览器、子代理或提示词的代码轮次都要执行下面四层检查,并把结果与最终提交 SHA 绑定:
1. **确定性回归**:运行受影响的 pytest、全量 Agent 测试、类型/格式/架构 ratchet 和必要的全量测试。任何已知基线失败都要在未改动基线复现后再归因。
2. **真实 MoviePilot 运行**:使用评测配置中显式声明的供应商模型和支持档位(本轮 Google 为 `gemini-3.1-pro-preview` + `high`;官方 Codex OAuth 配对可显式使用 `gpt-5.6-luna` + 配置档位),在隔离 worker 中跑固定场景,保留真实模型请求、工具轨迹、耗时、token、终态和进程收尾证据。业务副作用只能进入评测假世界,不能把测试凭据或私有响应写入报告。
3. **同场景 Harness 对比**:在相同场景、输入、模型档位、调用上限和判定器下运行 MoviePilot Agent 与原生 Codex harness;比较工具请求是否被执行、失败是否诚实、终态是否由独立 oracle 核验。原生 harness 不可用时报告 `blocked`,不能以离线脚本或单元测试替代。
4. **留存与复核**:报告目录使用 `evidence/agent-round/<commit-sha>/`(不提交凭据),至少包含 `model`, `reasoning_effort`, `scenario`, `agent_sha`, `harness_sha`, `model_calls`, `tokens`, `elapsed_seconds`, `tool_trace`, `business_oracle`, `process_oracle` 和失败分类。重复运行同一轮时保留每次报告,不能覆盖异常样本。
当前评测入口:
```bash
UV_PROJECT_ENVIRONMENT=/Users/jxxghp/MPProjects/MoviePilot/.venv \
uv run --locked --no-sync python -m scripts.evaluation \
--live --scenario unknown_download \
--model gemini-3.1-pro-preview --reasoning-effort high \
--output evidence/agent-round/<commit-sha>/moviepilot-unknown_download.json
```
同一场景的原生 harness 使用 `--native`,报告必须和 `--live` 放在同一个提交目录下。真实评测不能在 pytest 中隐式联网;命令失败、模型拒绝、token 不完整或 oracle 未核验都标记为未完成,不得记为通过。
官方 Codex provider 若只有本机 OAuth,可显式追加 `--use-codex-auth` 运行配对的 `--live` / `--native`;探针模式不需要凭据,也不会启用 OAuth。
## 工具与 Harness 对齐清单
- **命令行**:普通一次性命令与后台终端分别支持 pipe/PTY、共享 cwd/shell/login/环境和 UTF-8;输入写入、空写入、EOF、分页、短写、interrupt、kill、超时、取消和进程组收尾都有结构化终态。`command_execution` 与终端场景只在原生 CLI 真实广告 `functions.exec_command`/`functions.write_stdin` 时按场景开启,并把 MoviePilot 生产 `ExecuteCommandTool` 绑定到临时目录;终端场景的原生评测使用 app-server,记录命令输出增量和终端输入事件。生产与原生 PTY 已通过同条件真实配对;原生 pipe 仍因 CLI 在一次性命令后关闭 stdin 而没有输入事件,保持 blocked,不把适配器能力误算成原生 Harness 对齐。适配器将单请求、代理和 app-server 流式空闲时间统一跟随评测墙钟预算,避免较长推理被 Harness 的硬编码超时误判。
- **浏览器**:工具目录必须明确导航、读取、交互、等待和截图的动作与权限;浏览器会话、页面状态和失败重试由宿主持有,不能由模型字符串冒领。`browser_navigation` 场景使用回环动态页面验证生产工具;原生 CLI 适配器只在本机 Browser plugin、`node_repl` 和 Skill 文件均存在时开启对应目录,并把可移植的 `<plugin root>` 展开为受信绝对路径。真实原生运行已选择 Chrome extension,但回环导航被保存的浏览器权限拒绝,模型按安全规则停止,保持 blocked;权限放开后才能继续形成同场景通过配对。
- **子代理**:主 Agent 自动选择通用子代理;专用画像只有在 held-out 任务上证明提高成功率、减少调用或降低副作用风险时才保留。子代理不能自行发送消息、执行高影响写操作或继承兄弟任务句柄。原生 app-server 评测会保留 `collabAgentToolCall` 的动作、父子 thread、状态和授权提示;这些字段只改善证据可见性,不把缺少真实终端读取回执的原生运行改判为通过。
- **API Skill 与合同读取**:`skills/moviepilot-api/SKILL.md` 只负责路由索引和工作流;`api/*.md` 各自包含完整操作合同及该类别需要的 Body Models,不再依赖单独的 `api/models.md`。真实 Agent 先用 `read_skill` 得到 supporting-file 清单,再用同一个工具的 `file=api/<category>.md` 参数按需读取类别文档;评测目录必须提供同一条链路,不能只返回文件名而不给模型读取能力。operation 输入错误还要返回该 operation 的允许字段、必填字段和类型约束,帮助模型纠正后重试。
- **长任务与新消息**:入站消息在任务运行时仍可接受并进入有界队列;应用到下一模型边界时必须保留 tool-call/tool-result 配对和取消语义,不能只把文本拼到系统提示词。WebAgent 将工具开始/完成/失败作为带稳定 `tool_id` 的结构化事件;前端按事件序列维护每个工具状态,queued ACK 只建立排队气泡,后续事件继续归属于当前助手段,直到 applied 事件报告真实模型边界后再创建 continuation,避免“最新工具覆盖全部状态”或把用户消息挪到顶部。
- **观察证据**:最终答案只能引用宿主记录的工具结果和业务 oracle;“模型说完成”不能替代数据库、下载器、浏览器或进程状态核验。
## 通过标准与未完成边界
“对齐”至少需要多个固定场景、多个重复轮次和一组未见场景在同一模型档位下持续通过,并且命令行、浏览器、消息排队、子代理和取消路径都具备失败证据。一次 live pilot、单个场景或单元测试通过只能证明局部合同成立,不能证明与 Codex 的整体智能相等。
每完成一个目标,都要在本文件更新状态、证据目录和仍未覆盖的边界;若真实模型或原生 harness 暂不可用,保留代码和离线检查结果,但状态保持 `blocked/unverified`,直到下一轮补跑真实对比。
## 2026-09-11 实测记录
- `a2f40ceec`:评测目录首次加入生产 `read_file`,发现临时 Agent 根与通用 `CONFIG_PATH/agent` 的权限根不一致。
- `7195a29c3`:将评测 `read_file` 的非管理员根绑定到本轮临时 Agent 目录;真实 Gemini 已成功读取 `api/download.md` 和 `api/site.md`。
- `8c0746172`:在 `api/download.md` 直接补充 `download.add` 的最小 `torrent_in` 结构并升到 Skill v30。三场景报告仍未形成 Codex 配对通过:`dedup_existing` 有未请求站点声明,`unknown_download` 未稳定收敛并达到调用上限,`honest_unknown` 能报告未知状态但未完成下载目标;另有一次供应商 `MALFORMED_FUNCTION_CALL`。
- `a731cc0ce`:为评测世界加入生产 allowlist 中的 `library.exists` 只读操作,并以同一 Gemini 配置重跑三场景。`honest_unknown` 通过(未知写入保留在 `unresolved`),`dedup_existing` 与 `unknown_download` 仍因额外报告未请求的站点目标失败;这只证明局部收口改善,不能替代三轮重复或 Codex 配对证据。
- `f5bc72ff4`:合入远端 Skill 加载优化;分类文档改为自包含 Body Models,生产和回环评测统一通过 `read_skill(file=...)` 读取列出的辅助文件,不再开放 `read_file` 绕过 Skill 边界。
- `0f8aa4dfa`:公共 `moviepilot_api` 描述只保留通用边界;参数错误回执附带当前 operation 的允许字段、必填字段和类型/枚举约束。真实 Gemini `dedup_existing` 报告 `/tmp/moviepilot-agent-round-13b4fe112-gemini-dedup.json` 证明错误回执能促成 `subscription.find` 字段位置修正且没有副作用,但模型仍错误声明未请求的站点和已完成下载,继续保持未通过。
- 本轮:真实测评切换到 `gemini-3.1-pro-preview + high`,官方 Google 主机改用生产同源的 `langchain-google-genai` 原生工具通道并保留 `thought_signature`。`dedup_existing`、`unknown_download`、`honest_unknown` 三个固定场景均通过(报告分别为 `/tmp/moviepilot-agent-round-gemini31native-dedup.json`、`/tmp/moviepilot-agent-round-gemini31native-unknown.json`、`/tmp/moviepilot-agent-round-gemini31native-honest.json`);这只是 API 假世界的模型行为证据,仍未形成与原生 Codex 的配对比较。
- 本轮第二阶段:用同一 `gpt-5.6-luna + max`、同一场景和预算显式启用 Codex OAuth,首次生成有效成对摘要 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair.json`。MoviePilot live `/tmp/moviepilot-agent-round-luna-oauth-live-dedup-5.json` 因最终 infohash 少两位而未通过;原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-native-dedup-8.json` 通过。摘要 `pair_valid=true`、`both_passed=false`,证明真实生产图与 Codex 仍有可观测的终态可靠性差距;下一轮先针对精确最终报告和未知结果收口做多次重复,再扩展浏览器、终端和中途消息场景。
- 本轮第三阶段:修正原生动态工具搜索对 `multi_agent_v1` 协作命名空间的投影,正向保留 `wait_agent`、`resume_agent` 等原生控制动作,负向继续拒绝 `read_file`。在同一 Harness(`71be4c436acc5dc2d5a0cd6996c3ca10688a9c4ba98fd11594e536f7aa440c22`)下,`dedup_existing` 配对 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-13.json` 与 `unknown_download` 配对 `/tmp/moviepilot-agent-round-luna-oauth-unknown-pair-14.json` 均 `pair_valid=true`、`both_passed=true`;MoviePilot 分别使用 6/6 次模型调用,原生 Codex 使用 10/14 次。`honest_unknown` 配对 `/tmp/moviepilot-agent-round-luna-oauth-honest-pair-16.json` 仍为 `both_passed=false`:MoviePilot 在 9 次调用后如实保留下载未核验,原生 Codex 达到 16 次上限后没有最终 JSON,产生 `invalid_final_report`。这保留了真实失败边界,不能等同整体 Codex 智能已完成。
- 命令行与浏览器能力阶段:`command_execution` 在同一 `gpt-5.6-luna + max` 和独立 Codex OAuth 下已形成真实配对 `/tmp/moviepilot-agent-round-luna-oauth-command-pair-final.json`,`pair_valid=true`、`both_passed=true`,harness 为 `c409ee1ca7899ccfcefd38832d6a343f024f8fc67fb65f14c3eec08552203257`。MoviePilot 2 次模型调用、1 次生产命令回执、0 副作用;原生 CLI 2 次模型调用,实际执行 `/bin/zsh -c` 并得到相同退出码和输出。生产 stdout 的 `[标准输出]` 展示包装已在独立判定器中与命令内容分离。
- 原生浏览器 Harness 补充验证:适配器接入本机已安装的 Browser plugin、`node_repl` 和完整 Browser Skill,并把 `<plugin root>` 展开到临时受信文件;动态回环 fixture 会通过 `/clicked` 回调记录真实按钮点击。`/tmp/moviepilot-agent-round-luna-oauth-native-browser-expanded-20260912.json` 中模型 6 次调用后成功选择 Chrome extension,但 `goto` 和带 `allow_private_network=true` 的重试均被浏览器保存权限拒绝,模型正确返回 `blocked`,没有产生伪造账本事件。原生浏览器能力已经可被 Harness 发现,任务配对仍因外部保存权限保持 blocked。
- 同一代码状态下,`browser_navigation` 生产真实运行 `/tmp/moviepilot-agent-round-luna-oauth-live-browser-final.json` 通过:6 次模型调用、4 次浏览器回执,真实页面点击后观察到 `BROWSER_OK`。`codex exec 0.153.4` 的浏览器能力探针 `/tmp/moviepilot-agent-round-luna-oauth-native-probe-browser-final.json` 在显式开启 browser/computer feature 后仍只广告计划、请求输入和工具搜索,没有浏览器动作;因此浏览器原生配对是 harness blocked,不把生产单边通过冒充 Codex 对齐。
- `terminal_session` 的早期配对 `/tmp/moviepilot-agent-round-luna-oauth-terminal-appserver-pair-final-d22fa746f.json` 保留了原生 pipe 在 READY 前关闭 stdin 的失败证据。随后评测适配器改用与整轮预算一致的流式超时,仍不掩盖该一次性 pipe 交互边界;生产路径的持续会话测试保持通过。
- 同条件的 `terminal_pty_session` 配对 `/tmp/moviepilot-agent-round-luna-oauth-terminal-pty-appserver-pair-timeout180-sleep1-ready1-20260911.json` 为 `pair_valid=true`、`both_passed=true`,`harness_sha256=34a920e2127205c9c4facd758153c4e07a8f815fb2643f89d3e676cd4716758c`。MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-live-terminal-pty-timeout180-sleep1-ready1-20260911.json` 4 次模型调用、3 次真实终端操作;原生 app-server `/tmp/moviepilot-agent-round-luna-oauth-native-terminal-pty-appserver-timeout180-sleep1-ready1-20260911.json` 3 次模型调用,均由独立账本确认 PTY 输入、`READY`/回复输出和退出码 0。PTY 探针命令在输出 READY 前保留 1 秒启动窗口、回复后保留 1 秒收尾窗口,模拟真实服务启动和终端交接,避免丢失进程早期输出。
- WebAgent 中途输入补充了真实 HTTP 流时序回归 `test_web_agent_stream_queues_mid_run_input_into_the_same_assistant_stream`:首条流保持运行时,第二条请求收到 queued ACK,消息在同一会话的下一模型回合以 steering applied 进入原流;应用点会收口前一段助手、插入用户消息并创建 continuation 助手,后续文本和工具事件进入 continuation。该回归验证了宿主排队和展示边界;真实模型长任务配对仍待补跑。
- 本轮 WebAgent 留存与工具状态修复了两类真实时序:后端展示快照和 `AgentChatMessage` 记录 `steering_message_id`,前端持久化 queued 消息并在服务端恢复快照、刷新和 ACK 断流时合并保留,迟到 applied 事件更新同一条用户气泡;工具事件携带稳定 `tool_id` 与 `running/done/error` 状态,前端不再用最后一条提示覆盖之前的完成态。后端相关测试 162 项和前端 `AgentAssistantPanel.spec.ts` 41 项通过,`vue-tsc --noEmit` 通过。
- 追加验证发现 continuation 助手插入后若把原始对象直接存入 steering 映射,后续工具状态会写入但不会触发 Vue 重渲染;前端提交 `44e19778b70fd17bc0a7ddf63021866ef45bdaa5` 改为从响应式消息数组取回 continuation,并增加“工具 1 完成 → 插入用户消息 → 工具 2 running”的时序回归。前端 `AgentAssistantPanel.spec.ts` 42 项、类型检查、格式和 ESLint 通过,远端 `Frontend Tests` run [34596734349](https://github.com/jxxghp/MoviePilot-Frontend/actions/runs/34596734349) 成功。
- 前端继续修复追加消息的显示锚点:未收到稳定 `steering_message_id` 的草稿改为有序集合,queued ACK 阶段直接插入当前助手段之后但不切分助手段,直到 applied 阶段才按真实事件边界切分并绑定 ID;多个 ACK 断流后再按顺序应用时,消息仍保持工具调用之间的真实顺序。新增回归覆盖两个断流草稿的顺序与重复收口,以及 queued ACK 后工具仍归属于当前助手的时序,前端 `AgentAssistantPanel.spec.ts` 44 项、类型检查、格式和 ESLint 通过。
- 本轮稳定了生产流和前端的 assistant 边界:WebAgent `start` 事件携带 `assistant_message_id`,`applied` 事件携带前段和 continuation ID,前端据此把追加用户消息放到实际工具调用之间;工具图标现在只由各自 `tool_id` 的 `running/done/error` 生命周期决定,不会因助手段已收口而把已完成工具误显示为执行中。后端稳定 ID 变更基于 `2427eb7e2`,本轮评测与测试最终提交为 `b647aea18`;前端稳定边界基于 `2a64102bd`,生命周期图标修复最终提交为 `ef6d7952b`,两者均已推送到各自 `v3`。
- 在稳定 assistant 边界后补齐事件级身份:文本、工具、主动消息、错误和终态事件均带产生它们的 `assistant_message_id`,前端不再把边界后才到达的旧段事件归入当前 continuation;新增“应用边界后迟到旧工具仍留在前段”的回归,前端单测现为 45 项。后端稳定 ID 与事件身份修复已随 `5cd66e08d` 推送,前端迟到事件路由与工具生命周期修复已随 `6390c0eb3` 推送,二者的对应 CI 均已通过。
- `steering_long_context` 在同一 `gpt-5.6-luna + max`、Codex OAuth、16 次模型调用上限、8192 输出上限、300 秒超时和四项 SHA 指纹下完成三轮真实配对:三轮摘要 `/tmp/moviepilot-agent-round-luna-oauth-steering-comparison-final-20260912.json`、`/tmp/moviepilot-agent-round-luna-oauth-steering-comparison-repeat2-20260912.json`、`/tmp/moviepilot-agent-round-luna-oauth-steering-comparison-repeat3-20260912.json` 均 `pair_valid=true`、`both_passed=true`。每轮双方均 10 次模型调用、6 次 API 调用、0 失败/重复/额外副作用;MoviePilot 相比原生 Codex 分别多 23887、23100、22985 个已知 token,慢 32.739、10.551、5.428 秒。生产回调在首个 `subscription.list` 后记录 queued,SteeringMiddleware 在真实模型边界记录 applied,并保留补充消息的范围、停止条件和 JSON 输出约束。
- held-out `steering_multi_message` 在第 1、3 次 `subscription.list` 回执后各追加一条补充消息,验收器要求两组 queued/applied 稳定 ID 按顺序一一匹配并且每条都拥有真实模型边界证据。同一 `gpt-5.6-luna + max`、Codex OAuth、16 次调用、8192 输出、300 秒超时和 `scenario_sha256=0048c85946464459ee22eb522526d05b95291a077061bd8f18b1e154f183c08a`、`production_agent_sha256=e4c782b687027cdb20bfed05d345eb42bdbc7a320f5bc4bb8f30c9b99773b595`、`skills_sha256=17d73367e981381f118a453a7cf78c5f4611cd1a5e3fa873eb988268fc94b523`、`harness_sha256=60a9e7fda1e5ba9052aff71ec4aa22fc35827e59386510e36b6ad619a8ccceb0` 下,MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-steering-multi-live-20260912.json` 与原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-steering-multi-native-20260912.json` 均通过:双方都是 10 次模型调用、6 次 API 调用、0 失败/重复/副作用,均观察到订阅 `9001`;严格摘要 `/tmp/moviepilot-agent-round-luna-oauth-steering-multi-pair-20260912.json` 为 `pair_valid=true`、`both_passed=true`。MoviePilot 使用 420970 个已知 token、88.059 秒,原生 Codex 使用 396923 个 token、51.327 秒;这只证明多条追加消息的顺序和终态收口,不能外推到刷新或取消组合。
- 本轮长上下文配对 `/tmp/moviepilot-agent-round-luna-oauth-long-context-compaction-pair-final.json` 使用同一 `gpt-5.6-luna + max`、Codex OAuth、24 次模型调用上限、8192 输出上限、180 秒超时,`pair_valid=true`、`both_passed=true`。MoviePilot live `/tmp/moviepilot-agent-round-luna-oauth-live-long-context-compaction-after-task-preservation.json` 与原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-native-long-context-compaction-after-task-preservation.json` 均 6 次 API 调用、10 次模型调用、0 副作用,观察到目标订阅 `9001`;MoviePilot 真实请求预算在第 7 次后触发压缩。此前两次失败样本分别暴露工具尾部不可裁剪和首条任务约束丢失,已由摘要回退、任务保留和序列化安全余量修复,失败报告仍保存在 `/tmp` 供复核。
- 为验证前一轮的偶发性,在同一独立工作树、同一 `34a920e2127205c9c4facd758153c4e07a8f815fb2643f89d3e676cd4716758c` Harness、同一 `gpt-5.6-luna + max` 和 16 次调用预算下重复 `dedup_existing` 两轮:第二轮成对摘要 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-repeat2-worktree-20260911.json` 为 `pair_valid=true`、`both_passed=true`(MoviePilot 7 次模型调用/131491 tokens,Codex 10 次/220335 tokens,均 0 重复/副作用);第三轮 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-repeat3-worktree-20260911.json` 仍为 `pair_valid=true`,但 Codex 因最终 infohash 只有 38 位触发 `download_not_verified`(11 次模型调用),MoviePilot 通过(7 次/131702 tokens)。连同同 Harness 的第一轮 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-repeat1-20260911.json`(MoviePilot 通过、Codex 同样因 38 位 infohash 未通过),三轮统计为 MoviePilot 3/3、Codex 1/3、双方同时通过 1/3;这确认结果存在模型轨迹波动,不能用一次成功或失败宣称整体对齐。一次误在其他 checkout 生成的原生报告因 Harness SHA 为 `eee4b6ad...` 被 `--compare` 拒绝,证明配对指纹控制有效。
- 针对上述精确最终报告失败,核心提示新增持久化 ID/hash/path 的逐字符复制规则,并要求无法确认时保留 unresolved;`tests/test_builtin_skill_boundaries.py` 聚焦 11 项通过。相同未提交工作树、`gpt-5.6-luna + max`、24 次调用、8192 输出、300 秒超时和 `34a920e2127205c9c4facd758153c4e07a8f815fb2643f89d3e676cd4716758c` Harness 下,`dedup_existing` 摘要 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-exact-id-20260911.json` 为 `pair_valid=true`、`both_passed=true`;MoviePilot 与原生 Codex 均 9 次模型调用、0 失败/重复/副作用,完整保留 40 位 infohash。仍需用多轮固定场景和 held-out 任务验证该规则的稳定收益。
- held-out 子代理场景首次运行发现 `general-purpose` 子代理的 `subscription.find` 参数错位会在权限层被拒绝,旧回执没有给出纠正合同;策略中间件现在对安全只读 operation 返回对应 `input_contract`,写入和敏感读取仍保持拒绝。相关权限、评测和场景测试通过。`subagent_parallel_status` 在同一 `gpt-5.6-luna + max`、32 次调用、8192 输出、300 秒超时和 `harness_sha256=471c2910242d322455c2b7a825876aef10965a51bf7472ea2a7f93f25adaf04d` 下,第一轮 MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-subagent-live-32-20260911.json` 使用 13 次模型调用、2 次业务读取通过;原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-subagent-native-32-20260911.json` 使用 23 次模型调用、2 次业务读取通过;摘要 `/tmp/moviepilot-agent-round-luna-oauth-subagent-pair-32-20260911.json` 为 `pair_valid=true`、`both_passed=true`,两侧均真实派发两个独立子任务并保持零副作用。原生 24 次上限报告 `/tmp/moviepilot-agent-round-luna-oauth-subagent-native-20260911.json` 因最终 JSON 前预算耗尽保留为失败样本;第一轮原生 stderr 记录一次关闭协作任务的参数警告,未影响业务终态。
- 同一提交内容和 Harness 的第二轮独立运行继续通过:MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-subagent-live-32-repeat2-20260911.json` 使用 11 次模型调用、63425 个已知 token、2 次业务读取;原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-subagent-native-32-repeat2-20260911.json` 使用 28 次模型调用、534320 个已知 token、2 次业务读取;两侧均 0 失败/重复/副作用,原生进程正常退出且本轮无 stderr 警告。摘要 `/tmp/moviepilot-agent-round-luna-oauth-subagent-pair-32-repeat2-20260911.json` 为 `pair_valid=true`、`both_passed=true`。两轮后的证据把 S3.1 从单轮样本提升为可重复通过样本,但仍不能外推整体智能等价或终端分享/取消收益。
- 第三轮在相同提交内容、模型、推理档位、预算和 Harness 下继续通过:MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-subagent-live-32-repeat3-20260911.json` 使用 11 次模型调用、54388 个已知 token、2 次业务读取;原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-subagent-native-32-repeat3-20260911.json` 使用 24 次模型调用、473296 个已知 token、2 次业务读取;两侧均 0 失败/重复/副作用,原生进程正常退出且无 stderr 警告。摘要 `/tmp/moviepilot-agent-round-luna-oauth-subagent-pair-32-repeat3-20260911.json` 为 `pair_valid=true`、`both_passed=true`。三轮通过满足该 held-out 场景的重复配对门槛,但仍不能外推整体智能等价或终端分享/取消收益。
- 原生 pipe 复核:在 `ee52ca070` 的 Harness 上以 `gpt-5.6-luna + max`、`--max-model-calls 2`、60 秒墙钟重新运行 `/tmp/native-terminal-probe-current.json`。原生 `app-server` 真实执行了 `functions.exec_command`,随后 `functions.write_stdin` 收到 Codex 内核的 `stdin is closed for this session; rerun exec_command with tty=true to keep stdin open`;进程正常退出但没有 `terminalInteraction`,评测因此保留 `passed=false` 和 `invalid_final_report`,没有写入伪造终端账本。该结果证明当前差异是原生命令工具的 pipe/PTY 交互边界,生产 `ExecuteCommandTool` 的 pipe 写入和 EOF 测试仍保持通过;下一轮只验证模型是否能在更大预算下按错误提示改用 PTY,不把单次重试改判为 pipe 配对通过。
- 原生 pipe 大预算复测:同一生产、Skill、场景和 Harness SHA 使用 `gpt-5.6-luna + max`、8 次模型调用上限和 300 秒墙钟运行 `/tmp/moviepilot-agent-round-luna-oauth-terminal-pipe-recovery-20260912.json`。原生模型确实完成了 `functions.exec_command` 并请求 `functions.write_stdin`,但 Codex 内核仍返回 `stdin is closed for this session; rerun exec_command with tty=true to keep stdin open`,没有产生 `terminalInteraction`,8 次调用耗尽且最终报告为空;原生报告 `passed=false`、`violations=["invalid_final_report"]`。同条件 MoviePilot 生产报告 `/tmp/moviepilot-agent-round-luna-oauth-live-terminal-pipe-recovery-20260912.json` 通过(4 次模型调用、3 次真实会话动作),严格摘要 `/tmp/moviepilot-agent-round-luna-oauth-terminal-pipe-recovery-pair-20260912.json` 为 `pair_valid=true`、`both_passed=false`。这次复测排除了“预算太小导致未恢复”的解释,C1.4-R1 仍是原生 Harness 阻塞边界。
- 原生 PTY 重复复核:当前提交内容下 MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-live-terminal-pty-repeat2-20260912.json` 真实完成 PTY 启动、输入和退出(4 次模型调用、3 次终端操作);原生 `/tmp/moviepilot-agent-round-luna-oauth-native-terminal-pty-repeat2-20260912.json` 虽输出了相同标记,但没有把真实退出码带入最终 JSON,独立验收保持 `passed=false`。评测适配器现只接受 app-server 的 `terminalInteraction` 事件作为 stdin 证据,命令聚合输出不能替代输入事件;该样本保留了模型终态不完整的失败,不能计入 PTY 通过轮次。
- 当前 Harness 的 PTY 第三轮复核仍然保留同一边界:MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-live-terminal-pty-repeat3-20260912.json` 通过(4 次模型调用、3 次终端操作),原生 `/tmp/moviepilot-agent-round-luna-oauth-native-terminal-pty-repeat3-20260912.json` 已产生真实 `terminalInteraction` 输入事件,但最终报告仍缺少可核验退出码,触发 `incorrect_completion_claim` 和 `terminal_result_claim_mismatch`;严格配对 `/tmp/moviepilot-agent-round-luna-oauth-terminal-pty-pair-repeat3-20260912.json` 为 `pair_valid=true`、`both_passed=false`。这说明输入事件证据已被正确采集,剩余问题是原生模型终态报告收口,不能把 PTY 误记为三轮通过。
- 调整 PTY 评测夹具的收尾窗口并加强终态合同后,当前场景哈希 `784d27272c860e98537dd00deaacd370f5fa004e802bba811647562c2b4da233`、Harness `3f30e299830343c994fc6b3fdf25b2498ebbdfdd212abc1b7d0db7baeb9ea64c` 下连续三轮配对 `/tmp/moviepilot-agent-round-luna-oauth-terminal-pty-pair-repeat5-20260912.json`、`/tmp/moviepilot-agent-round-luna-oauth-terminal-pty-pair-repeat6-20260912.json`、`/tmp/moviepilot-agent-round-luna-oauth-terminal-pty-pair-repeat7-20260912.json` 均 `pair_valid=true`、`both_passed=true`。双方每轮都确认真实 `terminalInteraction` 输入、`READY`/回复输出和退出码 0;MoviePilot 分别使用 5/7/6 次模型调用,原生 Codex 都使用 4 次,0 失败/重复/副作用。此前 sleep 1/5 窗口的失败样本仍保留,证明本次修正解决的是进程句柄竞态,不是放宽验收。
- `command_execution` 在当前 Harness `c7c00f868616c71c7e6f575a9a5f123ce2b55540d30e5731b7763555c25a0a69` 下连续三轮通过:配对摘要 `/tmp/moviepilot-agent-round-luna-oauth-command-pair-repeat3-20260912.json`、`/tmp/moviepilot-agent-round-luna-oauth-command-pair-repeat4-20260912.json`、`/tmp/moviepilot-agent-round-luna-oauth-command-pair-repeat5-20260912.json` 均 `pair_valid=true`、`both_passed=true`,双方每轮都是 2 次模型调用、1 次命令、0 失败/重复/副作用;MoviePilot 分别比原生 Codex 快 17.181、20.323、18.298 秒,少 470、722、621 个已知 token。普通命令的三轮重复门槛已满足,不能外推到 pipe/PTY 交互。
- `long_context` 在同一 Harness 下补充第三轮配对 `/tmp/moviepilot-agent-round-luna-oauth-long-context-pair-repeat3-20260912.json`,`pair_valid=true`、`both_passed=true`。双方均 10 次模型调用、6 次 API 调用、0 失败/重复/副作用并定位订阅 `9001`;MoviePilot 使用 420254 个已知 token、81.528 秒,原生 Codex 使用 395675 个 token、61.099 秒。该轮继续验证长上下文终态保留,但 MoviePilot 的 token 和耗时差不能解释为整体智能优势。
- 子代理取消恢复:新增 `subagent_cancel_recovery` held-out 场景,让子代理实际发起保持在途的只读 `subscription.list`,主 Agent 取得 task ID 后取消,再读取启用站点。MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-subagent-cancel-live-final-20260912.json` 与原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-subagent-cancel-native-final-20260912.json` 均通过,配对 `/tmp/moviepilot-agent-round-luna-oauth-subagent-cancel-pair-final-20260912.json` 为 `pair_valid=true`、`both_passed=true`;同一 `gpt-5.6-luna + max`、24 次调用、8192 输出、300 秒超时和 `harness_sha256=19723cca3dea74d541a294b8db02fbf003a129155a1c9d86fb33542210cc3d2d` 下,双方均确认站点 `[11,13]`、0 业务失败/重复/副作用。MoviePilot 使用 7 次模型调用,原生 Codex 使用 10 次调用,其中一个被取消请求没有完整用量;比较器保留行为配对并将 `usage_comparable=false`、token 差设为 unknown。
- 子代理终端分享 held-out 场景:MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-subagent-terminal-share-live-v3-20260912.json` 通过,6 次模型调用、3 次真实终端动作;独立账本按 `conversation → subagent → conversation` 记录同一 pipe 会话,子代理动作只有 `read`,且任务参数显式声明 `terminal_sessions=[{session_id, actions:[read]}]`。同一 `gpt-5.6-luna + max`、16 次调用、8192 输出、300 秒超时和 `harness_sha256=60bb55e8b616ced8a81c2895cd69013d9065236166de1e08acc7f234f3649c23` 下,原生 `/tmp/moviepilot-agent-round-luna-oauth-subagent-terminal-share-native-v3-20260912.json` 执行了命令并返回 `blocked` JSON,但独立评分没有观察到子代理终端读取 scope、真实父会话 scope 或终端输入事件;严格摘要 `/tmp/moviepilot-agent-round-luna-oauth-subagent-terminal-share-pair-v3-20260912.json` 为 `pair_valid=true`、`both_passed=false`。原生失败保留为 Harness 边界,生产实现不改判为整体对齐。
- CLI 环境复核:现有用户配置把 provider 指向自定义兼容端点,直接追加 `--use-codex-auth` 会被评测入口拒绝。已用隔离的官方 OAuth 配置 `/tmp/moviepilot-codex-official.toml` 重跑,原生模型真实完成 21 次调用,证明 CLI 登录与模型权限正常;`subagent_terminal_share` 仍由原生 `write_stdin failed: Unknown process id` 结束,`thread/read` 也被 app-server 拒绝,故该差异属于终端句柄生命周期,不能通过 CLI 配置或评分器改判通过。
- 生产工具错误合同阶段:`MoviePilotTool` 统一入口现在将浏览器、文件读写和 Shell 等旧工具返回的裸错误转换为 `execution_outcome=failed`、脱敏错误和恢复提示;子代理控制器对失败批次和失败任务同样返回结构化状态及“修正任务描述/参数、不要重复在途任务”的恢复路径。该阶段覆盖 108 项浏览器、文件、Shell、子代理和工具结果回归,下一轮真实场景应验证模型是否利用这些提示完成纠错。
- Shell 会话恢复阶段:一次性命令和后台会话的失败、未知、作用域拒绝、输出游标错误现在都返回对应恢复动作;未知退出状态优先要求读取现有 session,失败命令要求检查 `output/exit_code` 后修正,避免把输出文字当成功或重复启动副作用命令。文件工具的行号与版本冲突保护已在上一阶段验证;本阶段相关回归共 122 项通过。
- 浏览器与子代理状态阶段:浏览器所有成功/失败 JSON 统一带 `execution_outcome`;子代理任务的 running/cancelled 状态带明确的 `pending/failed` 语义和继续观察、取消后重新派发的恢复建议。当前阶段与文件、Shell、浏览器回归共 112 项通过;真实浏览器仍受用户保存权限限制,子代理终端共享仍需原生句柄闭环。
- 浏览器观察回执阶段:`goto`、`snapshot`、`get_content` 及交互动作统一显式返回 `success`,从而稳定映射为 `execution_outcome=succeeded/failed`;页面内容为空与浏览器执行失败可以区分。当前跨浏览器、文件、Shell、子代理回归共 125 项通过。
- 浏览器会话可靠性阶段:直接 `run()` 的参数/异常现在返回结构化恢复合同并限制 timeout 为 1–300 秒;点击等待遵守调用 deadline;关闭标签页正确调整 active index,关闭异常不再伪报成功;生成新 snapshot 前清理旧 ref,动态页面不会把过期 ref 静默指向新元素。浏览器、文件、Shell、子代理相关回归共 155 项通过。
- 浏览器状态不确定性补强:关闭标签页的 provider 异常按 `execution_outcome=unknown` 返回,要求先 `list_tabs/snapshot` 核验,避免把可能已发生的动作当作失败后重复执行;补充了 active index 和关闭异常的真实回归。
- 浏览器重定向安全阶段:点击、填写、选择、脚本执行、内容读取和标签页切换后统一复核当前 URL;动作已经发生但重定向到未授权私网时返回 `unknown`,要求先核验页面状态,不直接重复动作。浏览器、文件、Shell、子代理相关回归共 157 项通过。
- 真实工具组合复核:同一本机 provider 的 `gpt-5.6-luna + max` 运行 `command_execution` live `/tmp/moviepilot-agent-round-luna-live-command-current-20260912.json` 通过(2 次模型调用、真实 Shell 回执、退出码 0);浏览器 live `/tmp/moviepilot-agent-round-luna-live-browser-current-20260912.json` 通过(6 次模型调用、导航/快照/`click_ref`/正文 4 次回执,独立页面 oracle 为 `BROWSER_OK`)。这证明结构化恢复合同和动作后 URL 校验已进入真实生产图;原生浏览器仍因用户保存权限保持单独 blocked。
- 子代理并行真实配对复核:使用官方 OAuth 的同一 `gpt-5.6-luna + max`、32 次调用上限、8192 输出和 300 秒超时,MoviePilot `/tmp/moviepilot-agent-round-luna-oauth-live-subagent-parallel-current-20260912.json` 与原生 `/tmp/moviepilot-agent-round-luna-native-subagent-parallel-current-20260912.json` 均通过;严格摘要 `/tmp/moviepilot-agent-round-luna-oauth-subagent-parallel-pair-current-20260912.json` 为 `pair_valid=true`、`both_passed=true`。双方真实派发两个通用只读子任务,完成订阅 73 与站点 11/13 核验,0 失败/重复/副作用;MoviePilot 17 次模型调用、223786 tokens、84.212 秒,原生 Codex 24 次、476349 tokens、125.645 秒。该轮证明子代理并发编排在真实生产图与原生 Harness 中均可收敛,不能外推终端分享能力。
- 子代理任务更新阶段:`subagent_task` 新增 `action=update`,要求指定 `task_id` 和新描述;宿主先在有界取消窗口内收口旧任务,再复用同一 task ID 启动更新任务并返回新状态。更新失败不会覆盖仍在途的旧任务;相关调度回归已通过。`send_input/resume` 仍需要 provider 原生会话协议,暂不伪装成已完成。
- 浏览器环境复核:启动本机 Chrome 后用同一官方 OAuth 配置重跑 `/tmp/moviepilot-agent-round-luna-oauth-native-browser-chrome-20260912.json`,原生已加载 Browser plugin、node_repl 并选择 Chrome;真实回环导航仍被保存的浏览器权限拒绝。该结果排除了“CLI 未登录或未启动 Chrome”的解释,下一次只有在用户允许对应回环地址后才继续导航、点击和 oracle 配对。