From 6fc828a9ce84f3cc18057386e85c13e74ad4ba9d Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 24 Sep 2026 04:36:06 +0000 Subject: [PATCH] docs(tooling): record PI executor acceptance and operating guide --- .doc/README.md | 2 +- .../2026-09-24-pi-executor-boundaries.md | 39 +++ .../2026-09-24-subagent-workflow-research.md | 4 + .doc/audit/ISSUES.md | 4 +- .doc/ops/2026-09-21-policy-registry.md | 2 +- .../2026-09-24-pi-executor-implementation.md | 47 ++++ .doc/ops/2026-09-24-pi-subagent-executor.md | 80 ++++++ .doc/ops/2026-09-24-subagent-model-config.md | 8 +- .../2026-09-24-subagent-workflow-standard.md | 10 +- .doc/ops/CURRENT.md | 1 + .../lessons/2026-09-24-pi-tool-boundaries.md | 26 ++ .doc/ops/lessons/INDEX.md | 1 + .../2026-09-24-subagent-workflow-standard.md | 23 +- .../2026-09-24-pi-executor-test-report.md | 54 ++++ .../pi-executor-2026-09-24/arch-check.txt | 5 + .../committed-focused.txt | 88 ++++++ .../cursor-dispatch.json | 64 +++++ .../engineering-tests.txt | 250 ++++++++++++++++++ .../pi-executor-2026-09-24/guard-review.json | 10 + .../pi-executor-2026-09-24/live-mcp.json | 152 +++++++++++ .../cursor-auto-research-01/receipt.json | 83 ++++++ .../cursor-auto-research-01/report.md | 44 +++ .../cursor-auto-research-02/receipt.json | 63 +++++ .../cursor-auto-research-02/report.md | 32 +++ .../real-mcp-plan-01/receipt.json | 63 +++++ .../real-mcp-plan-01/report.md | 63 +++++ .../real-mcp-research-02/receipt.json | 63 +++++ .../real-mcp-research-02/report.md | 28 ++ .../command-evidence/00-stderr.txt | 0 .../command-evidence/00-stdout.txt | 1 + .../real-mcp-test-01/receipt.json | 102 +++++++ .../real-mcp-test-01/report.md | 44 +++ .../real-research-01/receipt.json | 39 +++ .../real-research-01/report.md | 29 ++ 34 files changed, 1509 insertions(+), 15 deletions(-) create mode 100644 .doc/audit/2026-09-24-pi-executor-boundaries.md create mode 100644 .doc/ops/2026-09-24-pi-executor-implementation.md create mode 100644 .doc/ops/2026-09-24-pi-subagent-executor.md create mode 100644 .doc/ops/lessons/2026-09-24-pi-tool-boundaries.md create mode 100644 .doc/test-reports/2026-09-24-pi-executor-test-report.md create mode 100644 .doc/test-reports/assets/pi-executor-2026-09-24/arch-check.txt create mode 100644 .doc/test-reports/assets/pi-executor-2026-09-24/committed-focused.txt create mode 100644 .doc/test-reports/assets/pi-executor-2026-09-24/cursor-dispatch.json create mode 100644 .doc/test-reports/assets/pi-executor-2026-09-24/engineering-tests.txt create mode 100644 .doc/test-reports/assets/pi-executor-2026-09-24/guard-review.json create mode 100644 .doc/test-reports/assets/pi-executor-2026-09-24/live-mcp.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/receipt.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/report.md create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/receipt.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/report.md create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/receipt.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/report.md create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/receipt.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/report.md create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stderr.txt create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stdout.txt create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/receipt.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/report.md create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/receipt.json create mode 100644 .doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/report.md diff --git a/.doc/README.md b/.doc/README.md index bd3e97d7..156adf6f 100644 --- a/.doc/README.md +++ b/.doc/README.md @@ -33,7 +33,7 @@ | 我要… | 读这里 | |--------|--------| -| Subagent 模型配置 / 流程 | [可调整模型配置](ops/2026-09-24-subagent-model-config.md) · [流程草案](ops/2026-09-24-subagent-workflow-standard.md) · [研究依据](audit/2026-09-24-subagent-workflow-research.md) | +| Subagent 模型配置 / 流程 | [可调整模型配置](ops/2026-09-24-subagent-model-config.md) · [PI 执行器](ops/2026-09-24-pi-subagent-executor.md) · [流程草案](ops/2026-09-24-subagent-workflow-standard.md) · [研究依据](audit/2026-09-24-subagent-workflow-research.md) | | 规则来源/生效版本 | [规范登记](ops/2026-09-21-policy-registry.md) | | 选择测试/报告范围 | [验证契约](ops/2026-09-21-validation-contract.md) | | 任务模板与会话收口 | [任务模板](ops/templates/short-term-task.md) · [收口清单](ops/templates/session-close-checklist.md) | diff --git a/.doc/audit/2026-09-24-pi-executor-boundaries.md b/.doc/audit/2026-09-24-pi-executor-boundaries.md new file mode 100644 index 00000000..b5ab8ad7 --- /dev/null +++ b/.doc/audit/2026-09-24-pi-executor-boundaries.md @@ -0,0 +1,39 @@ +# PI Subagent 执行器初版边界审查 + +task_id:subagent-workflow-standard-2026-09-24;issue_id:ISSUE-20260924-pi-executor-boundaries。 +owner:Cursor(修复)/ Codex(复核);issue_state:resolved;severity:high。 +本记录针对尚未发布的执行器初版,不表示 dev 或产品 Runner 存在这些实现。 + +## 事实与机制 + +1. 独立验证发现 PI 内置工具的路径规范化与扩展守卫不一致。安装版本 0.85.1 的 tools/path-utils.js 中 resolveToCwd 使用 stripAtPrefix 并展开 home;初版守卫使用 path.resolve(root,input)。 +2. 以专门创建的 /tmp/pi-guard-audit-* 临时目录及 outside.txt 假文件测试 @绝对路径,实际结果为 guard_blocked=false、actual_tool_path_escapes=true。没有读取真实密钥或业务文件。 +3. 同类范围:@ 前缀、~ 前缀、相对父路径、符号链接、Unicode/读取路径规范化;MCP 的同仓/工作区验证和临时文件写入;报告幂等与损坏收据;进程树/输出上限/环境变量隔离。 +4. 初版静态阅读另发现:跨仓 MCP 可能执行目标仓脚本;输出仅在 communicate 完成后截断;只回收仍存活 leader 的进程组;测试环境黑名单不足;模型报告用关键词推导 PASS。上述需要实现修复和负例,不以本行代替实测。 +5. 初版测试夹具存在 eager stderr.read(),在 MCP 仍存活时阻塞。host 两次仅终止 /tmp/pi-subagent-test-* 的假 MCP 子进程以释放测试,未终止产品或用户进程。 + +## 复现与迭代 + +- 初次 RED:19 项,7 failures / 11 errors,主实现未创建;存在性/调用失败为已缺失功能,不当作实现通过。 +- 初版回归:19 项,4 failures / 7 errors;耗时含夹具死锁处理。后续错误数不作为发布质量结论,待主机完整重跑。 +- Cursor 首轮 supervisor 已由 host 为明确的修复交接发送 TERM,退出143;源文件保留。没有未知写副作用后盲目重派,第二轮是带具体修复清单的新执行。 +- 本机 Qwen3.8-Flash、GLM-5.3-Flash 无工具短请求连通通过,实际 provider/model 与配置一致,正常 stop + agent_end/agent_settled。仅连接证据。 +- GLM-5.3 对初版整包快照的只读审查 300 秒超时,无完整结论;不报审查 PASS。进程由 subprocess 超时处理结束,未授予工具,无仓库写入。 + +## 修复与验收要求 + +Cursor 修复清单已交接:统一/拒绝路径规范化;MCP 同仓注册验证和无租约写入;有界双向进程通信/整体回收;测试环境白名单;严格请求/配置与冻结 SHA;损坏收据禁止重派;报告完成与审查通过分离;最终事件完整性;禁用 PI 隐式重试;相关真实 Git/进程/MCP 回归。 + +关闭条件:静态发现均落实对应修复或有证据排除;原例与同类负例通过;真实 PI 调用经新执行器完成;审查与测试报告保存。修复中,不新增 validated 经验;验证后再总结。 + +## 2026-09-24 修复关闭 + +issue_state=resolved 仅针对未发布初版的约定缺陷;代码提交 69ffaa677e23a1dd9aa0528bb09b3acfcd38b119,主机完整工程回归 173 项通过,提交后专项 34 项通过;最终 Cursor CLI→MCP→PI 中 ls/read 全通过。实际覆盖、早期失败和独立 GLM 审查边界见[报告](../test-reports/2026-09-24-pi-executor-test-report.md)。 +新增[经验](../ops/lessons/2026-09-24-pi-tool-boundaries.md)。本文件前面的“修复中/待验证”为初版历史,当前结论以本节为准。dev 集成/客户端 IDE 验收不由本问题关闭状态推导。 + +## cursor-cli-mcp-path + +issue_id:ISSUE-20260924-cursor-cli-mcp-path;issue_state:deferred;severity:medium;owner:工程维护;日期:2026-09-24。 +本机 Cursor CLI 2026.09.18 在项目 MCP args 中未展开 workspaceFolder 变量,原样传给 Node。pi-subagents 新入口已改工作区相对路径并实测通过。 +同类只读检查:agent mcp list 也显示既有 agentctl / jev Connection failed,它们仍使用相同变量写法;codegraph ready。未进一步修改/验收这两个既有服务,也未断言 IDE 同样失败。官方支持声明与本机观测须分开。 +此残差不阻塞 PI MCP(其内部直接调用主仓治理 CLI),不构成本轮产品发布结论;后续由工程维护在 Cursor CLI 升级或这两项 MCP 接入验收时检查路径/stdio 协议,形成独立修复与实际客户端证据。仅保留问题,不宣称已修复。 diff --git a/.doc/audit/2026-09-24-subagent-workflow-research.md b/.doc/audit/2026-09-24-subagent-workflow-research.md index ae1c0bac..1dd0740e 100644 --- a/.doc/audit/2026-09-24-subagent-workflow-research.md +++ b/.doc/audit/2026-09-24-subagent-workflow-research.md @@ -105,3 +105,7 @@ issue_state:open;严重度:medium;owner:Codex(研究);evidence_b 这些用户决策取代本报告前文 r1 中 Cursor 原生 .cursor/agents/inherit 的接入建议;前文保留为研究历史,不再作为当前实现方向。现行模型映射唯一来源为[模型配置](../ops/2026-09-24-subagent-model-config.md),流程草案同步到 r2。没有改变 Herdr 或产品 Runner。 2026-09-24 再次执行 pi --offline --no-extensions --no-skills --no-prompt-templates --no-themes --no-context-files --no-approve --list-models,exit 0;精确五个 provider/model 均存在。此命令没有模型推理,不证明各角色能力或连接状态。配置字段由主 Agent 人工读取,当前不含执行器/热加载/自动校验实现。 + +## 9. 执行器已接入(后续实现) + +用户进一步授权接入自动调用 PI 的执行器。代码提交 69ffaa677e23a1dd9aa0528bb09b3acfcd38b119,真实 Cursor CLI→MCP→PI 和 173 项工程回归通过,详情见[验证报告](../test-reports/2026-09-24-pi-executor-test-report.md)及[运行说明](../ops/2026-09-24-pi-subagent-executor.md)。前文关于未接入/未调用的说明属于当时研究阶段;当前交付范围与未覆盖项以上述新报告为准。完整流程草案审批、dev 集成和远端同步分别记录。 diff --git a/.doc/audit/ISSUES.md b/.doc/audit/ISSUES.md index 44d2a541..96dc60c7 100644 --- a/.doc/audit/ISSUES.md +++ b/.doc/audit/ISSUES.md @@ -2,7 +2,7 @@ 维护规则:[问题记录与开发经验闭环](../ops/2026-09-23-issue-learning-workflow.md)。每个问题一个稳定 ID;主记录是事实与状态来源,本表为可检索投影。新发现及时登记,修复后保留记录;发布 blocker 仍见 [gap-matrix](../remediation/gap-matrix.md)。 -更新:2026-09-23。本轮为初始建库,仅补录两个历史案例;下列历史 resolved 不表示本日运行回归通过。 +更新:2026-09-24。历史 resolved 不表示本日系统完整回归通过;各项范围与证据以唯一主记录为准。 | issue_id | 模块 / 检索词 | 问题 | 严重度 | issue_state | owner | 证据日期 / 范围 | 唯一主记录 | 经验 | |---|---|---|---|---|---|---|---|---| @@ -11,3 +11,5 @@ | ISSUE-20260923-coordination-authority | agentctl / claim / SQLite / CAS / CURRENT / FEATURE-MATRIX | 本地副本 CAS 与任务许可不能表达跨主机全局权威认领 | high | investigating | Codex(研究) | 2026-09-23;源码/只读状态,未复现具体丢写 | [主记录](../ops/short-term/2026-09-23-coordination-db-daemon-research.md#issue-20260923-coordination-authority) | 沿用 content-hash 投影经验;跨机结论待实施验证 | | ISSUE-20260923-matrix-status-regression | FEATURE-MATRIX / module-batches-ag / merge / docs-apply | 矩阵行 done 被 closeout 合并冲突手解回退为 planned | high | resolved | Cursor | 2026-09-23;本机 dev tip 与 git 考古;docs apply 已恢复 | [主记录](2026-09-23-matrix-status-regression.md) | [LESSON-20260923-matrix-status-cas](../ops/lessons/2026-09-23-matrix-status-cas.md) | | ISSUE-20260924-cursor-test-rule-drift | Cursor / test-reports / 固定模型 / 规则副本 | Cursor 测试规则与验证契约存在固定模型及范围冲突 | medium | open | Codex(研究) | 2026-09-24;静态规则比对,客户端行为未复现 | [主记录](2026-09-24-subagent-workflow-research.md#4-issue-20260924-cursor-test-rule-drift) | 未修复验证,不新增 validated 经验 | +| ISSUE-20260924-pi-executor-boundaries | PI executor / 路径规范化 / MCP / 子进程 / 幂等 | 未发布初版只读边界与执行可靠性缺陷 | high | resolved | Cursor/Codex | 2026-09-24;173 工程回归与真实 Cursor CLI/MCP/PI | [主记录](2026-09-24-pi-executor-boundaries.md) | [工具路径与输入隔离](../ops/lessons/2026-09-24-pi-tool-boundaries.md) | +| ISSUE-20260924-cursor-cli-mcp-path | Cursor CLI / MCP / workspaceFolder | 既有 agentctl/jev 项目 MCP 入口在本机 CLI 连接失败 | medium | deferred | 工程维护 | 2026-09-24;CLI list/list-tools,PI 入口已修复 | [主记录](2026-09-24-pi-executor-boundaries.md#cursor-cli-mcp-path) | 沿用工具路径经验 | diff --git a/.doc/ops/2026-09-21-policy-registry.md b/.doc/ops/2026-09-21-policy-registry.md index c6a2813b..9dae7728 100644 --- a/.doc/ops/2026-09-21-policy-registry.md +++ b/.doc/ops/2026-09-21-policy-registry.md @@ -50,4 +50,4 @@ CURRENT 是带时间的活跃协调快照;Git/机器状态用于核验实际 修订 ID:`subagent-workflow-2026-09-24-r2`;owner:Codex;state:`proposed`;能力:`manual`;effective_commit:无。 用户要求研究 Cursor Auto 下的 subagent 分工、阶段流程及报告,授权与本次验收见[任务](short-term/2026-09-24-subagent-workflow-standard.md)。[规范草案](2026-09-24-subagent-workflow-standard.md)为拟议行为的唯一来源,[研究报告](../audit/2026-09-24-subagent-workflow-research.md)给出事实和待修冲突,[模板](templates/subagent-stage-record.md)承载交接。 -用户后续明确采用 Cursor Auto 实施 + gmktec 本机 PI 子任务,并批准默认模型分工及可调整文档。[模型配置](2026-09-24-subagent-model-config.md)为模型路由唯一来源,decision_state=approved;流程整体仍 proposed,未合入 dev。原 Cursor 原生角色/inherit 方案被替代。当前为文档人工读取,尚未实现自动调度或验证真实派发;受控集成、客户端接入和机器执行能力分别验收。 +用户后续明确采用 Cursor Auto 实施 + gmktec 本机 PI 子任务,并批准默认模型分工及可调整文档。[模型配置](2026-09-24-subagent-model-config.md)为模型路由唯一来源,decision_state=approved;流程整体仍 proposed,未合入 dev。原 Cursor 原生角色/inherit 方案被替代。执行器已在任务分支实现并验证 Cursor CLI→MCP→PI,代码 69ffaa677e23a1dd9aa0528bb09b3acfcd38b119;[运行说明](2026-09-24-pi-subagent-executor.md)与[验证报告](../test-reports/2026-09-24-pi-executor-test-report.md)限定已验证的机器边界。dev 集成/完整流程审批仍独立记录;不以派发器可用宣称全阶段自动门禁。 diff --git a/.doc/ops/2026-09-24-pi-executor-implementation.md b/.doc/ops/2026-09-24-pi-executor-implementation.md new file mode 100644 index 00000000..33543112 --- /dev/null +++ b/.doc/ops/2026-09-24-pi-executor-implementation.md @@ -0,0 +1,47 @@ +# 本机 PI Subagent 执行器接入方案与实施记录 + +task_id:subagent-workflow-standard-2026-09-24;operation_task_id:subagent-workflow-standard-2026-09-24-executor。 +用户授权:“接入自动调用 pi 的执行器”;既有约束:Cursor Auto 实施,PI 模型限[配置](2026-09-24-subagent-model-config.md),M3 默认停用。本次是同任务的实现续作。 + +## 目标与边界 + +Cursor 能通过项目 MCP 自动按角色调用 gmktec 本机 PI,读取配置,提供冻结输入,获得持久报告和可核验状态。CLI 同步提供可复现入口。 +不修改产品服务/Runner、不操作真实业务数据、不安装 daemon、不 push。代码只在原登记 worktree 修改,当前 main 有其他任务的未跟踪 promotion receipt,保留不动。 +本次复核 local dev=6858e21d477571696a8458032e2c884449e773fd;原任务 HEAD=52462b45e985f596b2a503fc70ac12c3bd5fe571;新增 dev 差异为 internal/squad,与本次脚本无交叉。没有重新建场或切换主目录分支。 + +## 分工与执行方式 + +- Cursor Auto:编写执行器、MCP 接口、权限限制与测试。host Codex:需求/契约、文档、证据核验、审查与受控提交。 +- Cursor CLI 在已登记原任务 worktree、agentctl with 监督和精确路径租约内执行;不授予提交/合并/推送/环境操作权限。模型请求 Auto;实际底层模型不可见时记录 unknown。 +- 本次使用 ce-work 的执行/验证思路、CodeGraph 定位、test-driven-development 和 writing-for-agents。仓库 AGENTS 的原任务 worktree/agentctl 规则优先于技能中 detached 临时工作区机制;使用仓库 supervisor 派发 Cursor,代码路径单写者,外层核对差异。该隔离不是 OS 沙箱。 +- 范围:scripts/pi_subagents.py、scripts/pi-subagent-readonly.ts、scripts/mcp/pi-subagents-mcp.mjs、scripts/tests/test_pi_subagents.py、scripts/mcp/README.md、.cursor/mcp.json、.cursor/rules/pi-subagents.mdc,以及本任务相关 .doc 文档。 +- 认领能力仅 docs:publish;不注册 env:* 或 git:dev。后续集成另按受控候选流程处理。 + +## 设计契约 + +1. 配置文档是唯一模型来源,每次派发解析严格表格,记录 revision/hash 和实际 provider/model。禁用、未知、循环、M3 关键职责路由失败关闭;没有静默备用。 +2. 新鲜 PI 会话;冻结 source SHA 与显式 tracked 输入文件(拒绝秘密/业务 data/路径穿越/符号链接),上限限制。模型只得到选定输入与允许的只读工具,无任意 shell、源码写入或递归派发。 +3. 测试角色仅运行主 Agent 显式提供、带来源的 argv 计划;独立源码副本、净化环境、超时和输出限制,模型不生成可执行命令。共享业务环境本版不接入,返回明确限制。 +4. MCP 提供角色预览、运行、结果查询;跨 worktree 调用核对同仓与 task 注册;运行由权威 agentctl with 包裹,并由执行器校验继承租约。 +5. 每个 request_id 绑定输入摘要;同请求重放只查询,变更载荷拒绝,running/unknown 不重派。每请求独立短范围 report 路径锁,跨调用者统一并发上限。 +6. 运行前保存 running;完成保存 receipt.json/report.md,含命令、版本、输入摘要、配置摘要、状态/结论、报告来源。结果未知/失败不冒充通过,进程退出0不替代模型最终事件和必需测试结果。 +7. timeout/cancel 处理进程组并回收;未知副作用保留现场。凭证仅由 PI 客户端读取,绝不进入模型输入/报告;测试子进程不继承模型密钥或租约身份。 +8. MCP 用标准 stdio JSON-RPC,查询不被运行调用阻塞。项目规则告诉 Cursor 何时选择哪种 role_id,具体模型仍从配置读取。 +9. 实施与修复始终交给 Cursor;PI 负责分析/审查/验证。模型结论和 acceptance_owner 的最终验收分开。 + +## 验证计划 + +- 隔离真实 Git/agentctl:注册/租约负例、路径范围、报告落盘、请求幂等、并发与异常退出。 +- 本地假 PI 仅作为协议传输夹具:模型参数、权限开关、JSON 事件、错误/空响应/超时/子进程清理;不得当作真实模型能力验收。 +- MCP 实进程:initialize、tools/list、roles、run、result;错误必须 isError。 +- 实际本机 PI:至少一条真实分析请求与独立代码审查;模型/权限/配置/源码身份可追溯。不得把 CLI/MCP 接口实测写成 Cursor IDE 页面已实测。 +- 主机核验聚焦测试与工程脚本套件,按失败证据补回归;无需运行无关产品全量 Go、重建服务或产品 PI。 +- 收口保留运行结果和剩余条件,分别记录 local commit / integration / deployment / remote_sync / cleanup。 + +## 当前进度 + +2026-09-24:Cursor Auto 已在 agentctl supervisor 内启动;本轮尚未宣称实现完成。机器租约身份和终端输出由 host 核验,待实施结果后补测试与审查。 + +## 已验证结果 + +执行器代码已提交为 69ffaa677e23a1dd9aa0528bb09b3acfcd38b119。完整工程回归 173 项、提交后专项 34 项、真实 Cursor CLI→MCP→PI 自动路由与最终 ls/read 均通过,详见[报告](../test-reports/2026-09-24-pi-executor-test-report.md)。文档配置已改为程序读取;完整审批状态机仍人工/Agent 遵约。当前交付限本地任务分支,dev 集成等待共享环境验收锁释放,未推送。 diff --git a/.doc/ops/2026-09-24-pi-subagent-executor.md b/.doc/ops/2026-09-24-pi-subagent-executor.md new file mode 100644 index 00000000..ec9a6b59 --- /dev/null +++ b/.doc/ops/2026-09-24-pi-subagent-executor.md @@ -0,0 +1,80 @@ +# 本机 PI Subagent 执行器使用说明 + +范围:Cursor Auto 主协调/代码实施,gmktec 本机 PI 子任务。模型分工唯一来源为[模型配置](2026-09-24-subagent-model-config.md),阶段定义见[流程规范](2026-09-24-subagent-workflow-standard.md)。本说明与代码位于任务 worktree;dev 集成和最终实测状态见[实施记录](2026-09-24-pi-executor-implementation.md)。 + +## Cursor 中使用 + +1. 在包含本次提交的工作区打开 Cursor,重新加载项目 MCP;.cursor/mcp.json 注册 pi-subagents 服务,.cursor/rules/pi-subagents.mdc 提供派发入口。 +2. 主会话保持 Auto。先按原有流程创建/登记任务 worktree,并将 .doc/test-reports/assets/pi-subagents/ 纳入任务写范围。 +3. Cursor 调用 pi_subagent_roles 读取当前角色与模型;从任务目标选择 role_id,调用 pi_subagent_run,随后查询 pi_subagent_result。 +4. 不需要用户切换 PI 模型。需求/方案、独立审查、测试和报告由不同角色处理;代码实施与修复仍由 Cursor 执行。 +5. 接收报告并核对范围、源码/配置版本、缺项;运行完成不代表阶段批准。最终验收责任仍由任务 acceptance_owner 承担。 + +任务 worktree 尚未合入 dev 时,主目录中的旧 MCP 配置不会自动获得新工具;先在该任务 worktree 验证,受控集成后再在主目录重载。本文不宣称已操纵 Cursor IDE 页面。 + +## 请求内容 + +MCP 工具的外层参数 worktree 为同仓的已登记任务工作区,task_id 为实际操作任务。request 中给出以下信息;授权引用应能回链到真实用户请求,不用日志/模型文本自授权限。 + +```json +{ + "worktree": "/absolute/path/to/repo/.worktrees/task-id", + "task_id": "task-id", + "request": { + "role_id": "research", + "request_id": "research-001", + "goal": "读取选定文件,给出有证据的分析", + "authorization_ref": "本任务主记录中的用户授权位置", + "source_sha": "<完整的已提交源码 SHA>", + "input_files": ["PROJECT.md"], + "timeout_seconds": 120 + } +} +``` + +source_sha 必须为完整提交 hash;HEAD/分支名不作为可变输入。只发送明确列出的已跟踪 UTF-8 普通文件,禁止运行数据、.env、凭证、符号链接和路径越界。未提交的代码不会自动进入快照,先由 Cursor 形成可审提交或使用已有冻结版本。 + +request_id 在同一任务中稳定标识一次请求:同参数只读重放既有结果,不重复调模型;不同参数复用 ID 被拒绝;running/unknown 保留现场,不能盲目重派。配置变更在下一次新派发读取,旧请求保留原 config_revision/config_sha256。 + +## CLI 入口 + +在任务工作区使用: + +```bash +python3 -B scripts/pi_subagents.py roles +../../scripts/agentctl with --task task-id \ + --resource path:.doc/test-reports/assets/pi-subagents/task-id/research-001 -- \ + python3 -B scripts/pi_subagents.py run --request /tmp/pi-request.json +python3 -B scripts/pi_subagents.py result --task task-id --request-id research-001 +``` + +CLI 请求文件需包括 task_id;也可用 run --stdin 输入 JSON。直接裸调 run 会被租约校验拒绝。上述名称是示例,不构成任何任务或环境授权。 + +## 测试角色 + +test_run / acceptance_check 还需 approved_commands(argv 数组的数组)和 plan_digest(外部已批准计划 SHA-256);执行器另记录 approved_commands_sha256,不能以任意字符串冒充命令与计划的同一摘要。 + +命令在独立测试快照中运行,使用净化环境和私有 HOME/cache/tmp,标准输入关闭。PI 模型根据收到的命令摘要、退出码和日志引用分析,不生成或修改被执行命令;完整日志由主 Agent 核验并在需要时补充上下文。模型分析快照保持原始源码内容,与测试可写副本分离。必要的 stdout/stderr 保存到本请求报告目录以便核对,不仅保留一段摘要。 + +依赖未安装、用例缺失或命令失败须如实记录。本版不自动安装依赖,不直接连接共享 dev/test/main 或操作真实业务数据;相关检查继续由主 Agent 通过现有环境授权/租约流程执行。命令退出 0 只证明命令层执行成功;必需用例是否执行、SKIP、持久性/UI 和业务验收仍按验证契约核对。 + +## 证据与状态 + +输出位置:.doc/test-reports/assets/pi-subagents///。 + +- receipt.json:请求摘要、配置摘要、源码/输入文件摘要、配置与观察到的模型、运行状态、命令结果、工具调用摘要。 +- report.md:可读报告;模型分析是审查输入,主 Agent 核对后再推进阶段。 +- 命令日志:按收据记录的位置查询;报告目录受对应 path 租约保护。 +- 模型私有 thinking 不作为归档材料。错误输出与日志按敏感信息规则处理;不保存凭证。 + +run_status 与 verdict 分开:模型正常结束可以是 succeeded,但非测试报告仍为 review_state=pending / verdict=not_applicable。测试报告的 commands_passed/pass 只针对提交的命令,不能直接赋值到任务的 review_state 或 acceptance。失败、取消、结果未知不能换成 PASS。 + +超时、取消和输出超限处理整个受控进程组。只读结果查询可推断 orphan 为 unknown,但不能通过查询无租约改写收据。错误前置检查未形成业务收据时,MCP 返回可核对的执行拒绝,不能让主 Agent 一直等待不存在的结果。 + +## 调整与边界 + +角色默认模型、enabled、升级角色和并发上限在模型配置文档维护。禁用角色前同步处理指向它的升级关系。程序仅接受当前明确批准的五个 provider/model 组合;扩大模型池还需用户授权并更新硬边界校验,不是任意改一行即放宽权限。 + +本工具提供配置解析、模型启动、有限工具/输入范围、租约、进程监督和证据保存;没有把全部 S0–S9 的审批实现成不可跳过的状态机。Cursor 通过规则决定何时调用;模型失败不会触发隐式换 provider 或降级到 M3。 + +进程组和工具权限限制不是 OS 沙箱。批准的测试代码与本机工程工具属于可信执行面;外部不可信项目/代码不能因使用本工具就获得运行授权。普通 Cursor/PI 配置与 Herdr、产品 PI Runner 各自独立。 diff --git a/.doc/ops/2026-09-24-subagent-model-config.md b/.doc/ops/2026-09-24-subagent-model-config.md index 91edcc72..30f77a67 100644 --- a/.doc/ops/2026-09-24-subagent-model-config.md +++ b/.doc/ops/2026-09-24-subagent-model-config.md @@ -4,9 +4,9 @@ config_revision:`subagent-models-2026-09-24-r1` owner:用户;维护执行者:当前任务主 Agent。 -decision_state:`approved`(本会话确认);integration_state:`pending`;execution:`manual`。 +decision_state:`approved`(本会话确认);integration_state:`pending`;execution:`enforced`(本执行器已验证的配置/租约/工具/进程边界);阶段审批仍为 manual。 -**这是模型分配的唯一配置文档。** 用户调整下列表格;主 Agent 每次派发前读取,并把解析结果写入[派发记录](templates/subagent-stage-record.md)。当前没有程序自动解析、热加载或启动 PI;不能仅凭此文件声称执行器已接入。完整流程见[协作规范](2026-09-24-subagent-workflow-standard.md)。 +**这是模型分配的唯一配置文档。** 用户调整下列表格;主 Agent 每次派发前读取,并把解析结果写入[派发记录](templates/subagent-stage-record.md)。`scripts/pi_subagents.py` 已直接解析本文件,Cursor MCP 提供角色预览、派发与结果查询;每次新派发读取配置,旧请求保留旧摘要。实测与边界见[运行说明](2026-09-24-pi-subagent-executor.md)和[报告](../test-reports/2026-09-24-pi-executor-test-report.md)。完整流程见[协作规范](2026-09-24-subagent-workflow-standard.md)。 ## 1. 日常调整入口 @@ -14,8 +14,8 @@ decision_state:`approved`(本会话确认);integration_state:`pending` |---|---|---| | 某角色的默认模型 | §3 对应角色的“默认模型”列 | 修改后递增 config_revision;下一次派发读取 | | 复杂任务的升级去向 | §3 “升级角色”列 | 升级时保留原报告与原因;以目标角色重新派发 | -| 启停某角色 | §3 enabled 列 | false 时不自动派发;必需职责暂停或显式重新分配,不能跳过门禁 | -| 允许使用的 provider/model | §2 模型池 | 使用本机精确 ID;新增模型需用户明确调整授权范围 | +| 启停某角色 | §3 enabled 列 | false 时不自动派发;引用该角色的升级关系须同时调整;必需职责暂停或显式重新分配,不能跳过门禁 | +| 允许使用的 provider/model | §2 模型池 | 使用本机精确 ID;新增模型需用户明确调整授权范围并更新程序硬边界校验 | | 并发量、失败处理 | §4 | 主 Agent 按配置与任务实际资源取更严格边界 | | 只改本次任务 | 在任务主记录写 override | 记录用户指令、角色、原值/新值、期限;不改全局默认 | diff --git a/.doc/ops/2026-09-24-subagent-workflow-standard.md b/.doc/ops/2026-09-24-subagent-workflow-standard.md index eb888c45..54034080 100644 --- a/.doc/ops/2026-09-24-subagent-workflow-standard.md +++ b/.doc/ops/2026-09-24-subagent-workflow-standard.md @@ -91,7 +91,7 @@ S7 候选需执行该范围的真实检查,不能用分支自测替代合并 - 先画依赖再并行;有先后依赖的任务等待前置证据。有相同文件、公共 lockfile、路由、迁移号或共享环境的写任务不能同时认领。 - 同一任务 worktree 的源码写者为 Cursor,PI 只读任务读取冻结快照;只读报告由 Cursor 持锁保存。PI 验证涉及产物/环境写入必须在有效 agentctl supervisor 下运行;无法保证时停止执行并报告条件缺失。 - 若另行开展多 Cursor 并行实施,仍须独立登记 worktree,各自从明确 dev SHA 创建;父子关系用 parent_task_id/subtask_id 关联。此条不授权 PI 实施代码。 -- 父任务只承担汇总。写子任务登记独立操作 ID/路径;只读子审查复用父任务文档,不重复创建任务链。子分支结果通过现行候选集成流程交付;不能由 Cursor 的自动隔离/自动合并绕过本仓注册和准入。 +- 父任务汇总子任务成果,源码仍由 Cursor 实施。涉及测试产物写入的子任务登记独立操作 ID/路径;只读子审查复用父任务文档,不重复创建任务链。子分支结果通过现行候选集成流程交付;不能由 Cursor 的自动隔离/自动合并绕过本仓注册和准入。 - 有后台任务时,主 Agent 可继续独立工作,但不得在结果未回收时发布依赖它的 PASS、合并或清理。各子任务的工具可用性不代表授权可用性。 ## 6. 派发、回传与失败处理 @@ -129,11 +129,11 @@ S7 候选需执行该范围的真实检查,不能用分支自测替代合并 任务 status 继续只有 planned/in_progress/blocked/done/cancelled;phase 与 review_state、integration_state、deployment、cleanup、remote_sync、acceptance 独立记录。done 取决于授权交付终点。清理待办不扩充任务状态,但必须有人接管。需求验收 pending 时,若验收属于授权交付终点,任务不能 done。 -## 8. Cursor → 本机 PI 接入(执行器尚未实现) +## 8. Cursor → 本机 PI 接入(任务分支已实现) ### 配置与能力边界 -用户已明确选择 Cursor Auto 主协调和实施、gmktec 本机 PI 承担子任务;原 r1 的 Cursor 原生 .cursor/agents + inherit 方案废止,历史研究保留说明。当前[模型配置](2026-09-24-subagent-model-config.md)可人工调整,由主 Agent 读取;不是 PI 原生配置格式,不会自动改变 ~/.pi/agent/settings.json。 +用户已明确选择 Cursor Auto 主协调和实施、gmktec 本机 PI 承担子任务;原 r1 的 Cursor 原生 .cursor/agents + inherit 方案废止,历史研究保留说明。当前[模型配置](2026-09-24-subagent-model-config.md)可人工调整,由执行器每次派发读取;不是 PI 原生配置格式,不改变 PI 全局模型设置。CLI/MCP 接入与限制见[运行说明](2026-09-24-pi-subagent-executor.md),实际验证见[报告](../test-reports/2026-09-24-pi-executor-test-report.md)。 PI 模型和角色路由以配置文档为唯一来源。主 Agent 根据任务读取 role_id,显式传入 provider/model、独立会话、输入版本、工作目录与工具范围,收取结果后按本规范形成阶段记录。不能把主会话可用工具全部自动授予子任务。 @@ -149,12 +149,12 @@ PI 模型和角色路由以配置文档为唯一来源。主 Agent 根据任务 |---|---|---| | A 文档配置 | 已确认分工,维护模型配置/派发模板;流程整体另按规范登记 | 默认值与用户选择一致;修改可追溯;未合入前不称全仓 active | | B 消除旧规则冲突 | 修订 Cursor 测试规则副本为验证契约指针 | 相关 ISSUE 单独修复验证;本次不改变 Runner | -| C 实现派发入口 | Cursor 读取配置,启动本机 PI,限制工具、传入任务包、收取报告 | 配置校验、精确模型、独立上下文、权限拒绝、超时处理;需后续实现 | +| C 实现派发入口 | 已实现 CLI + 项目 MCP;本地任务分支代码 69ffaa67 | 配置/租约/模型/快照/结果校验与异常回归已验证;dev 集成另记 | | D 实机试运行 | 小型文档任务和受控代码任务(代码由 Cursor 写) | Auto 不需手动切模型;PI 角色/模型/run_id/证据可追溯;不冒充真实产品 PI | | E 异常演练 | 同路径写冲突、PI 失联、必需测试缺项、dev 变化、验收失败、清理拒绝 | 正确暂停/升级;保留失败证据 | | F 工具门禁 | 据试运行决定是否增加阶段校验/hook | 实现和真实负例验收后才将相应能力标 enforced | -接入验收 V1–V10:V1 Cursor Auto 与配置指定 PI provider/model;V2 授权/需求上下文传递;V3 独立只读审查与报告转存;V4 租约内测试;V5 输入 SHA 变化后复核;V6 写冲突拒绝;V7 缺项不合并;V8 验收失败保留现场;V9 清理拒绝有 owner;V10 中断后恢复。新增 V11:修改配置只影响下一次派发、记录 hash;V12:M3 停用/越权路由及未知 alias 被拒绝。以上均为后续实机验收项,本次仅文档静态检查。 +接入验收 V1–V10:V1 Cursor Auto 与配置指定 PI provider/model;V2 授权/需求上下文传递;V3 独立只读审查与报告转存;V4 租约内测试;V5 输入 SHA 变化后复核;V6 写冲突拒绝;V7 缺项不合并;V8 验收失败保留现场;V9 清理拒绝有 owner;V10 中断后恢复。新增 V11:修改配置只影响下一次派发、记录 hash;V12:M3 停用/越权路由及未知 alias 被拒绝。本轮执行器已完成 173 项工程回归与真实 Cursor CLI→MCP→PI 验证,覆盖及未覆盖项以测试报告为准;这不是宣称全部 S0–S9 审批、产品 UI/共享环境或清理已自动执行。 ### 日常使用与调整 diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index 3a25786e..97d8f9ce 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -18,6 +18,7 @@ | owner | task | branch | worktree | mutex | status | |---|---|---|---|---|---| +| Cursor/Codex | subagent-workflow-standard-2026-09-24-executor | feature/subagent-workflow-standard-2026-09-24 | .worktrees/subagent-workflow-standard-2026-09-24 | pi-subagent-executor | done | | Codex | subagent-workflow-standard-2026-09-24-config-r2 | feature/subagent-workflow-standard-2026-09-24 | .worktrees/subagent-workflow-standard-2026-09-24 | subagent-workflow-docs | done | | Codex | subagent-workflow-standard-2026-09-24 | feature/subagent-workflow-standard-2026-09-24 | .worktrees/subagent-workflow-standard-2026-09-24 | subagent-workflow-docs | done | | Cursor | fix-fav-staging-uuid-2026-09-24 | fix/fix-fav-staging-uuid-2026-09-24 | .worktrees/fix-fav-staging-uuid-2026-09-24 | artifactvault | done | diff --git a/.doc/ops/lessons/2026-09-24-pi-tool-boundaries.md b/.doc/ops/lessons/2026-09-24-pi-tool-boundaries.md new file mode 100644 index 00000000..9033ee6b --- /dev/null +++ b/.doc/ops/lessons/2026-09-24-pi-tool-boundaries.md @@ -0,0 +1,26 @@ +--- +lesson_id: LESSON-20260924-pi-tool-boundaries +lesson_state: validated +owner: Cursor/Codex +reviewer: Codex +last_reviewed: 2026-09-24 +reviewed_revision: 69ffaa677e23a1dd9aa0528bb09b3acfcd38b119 +source_issues: [ISSUE-20260924-pi-executor-boundaries] +keywords: [PI, MCP, readonly, path, snapshot, process-group] +--- + +# 文件工具的路径检查须匹配实际客户端语义 + +触发:为第三方 Agent 包装只读文件工具、复制输入快照或监督子进程。 + +机制:PI 0.85.1 工具会展开 @/~,初版守卫只做 path.resolve,检查对象与实际打开对象不同;另有 exact-root 空相对路径误拒、内部扩展复制进模型快照导致合法枚举被白名单拒绝。见[问题](../../audit/2026-09-24-pi-executor-boundaries.md)与[验证](../../test-reports/2026-09-24-pi-executor-test-report.md)。 + +实施前检查: + +1. 读实际工具的路径规范化实现;拒绝不支持的前缀/参数,核对 canonical realpath、符号链接与选定文件。不能仅假设安全的相对拼接等于最终访问路径。 +2. 模型输入、测试可写副本、客户端内部配置/扩展分开;允许清单只包含模型该读的材料。内部文件不要塞进源码快照。 +3. 同时验证拒绝路径和合法根目录/子目录、默认 path;只有负例通过不足以证明工具可用。 +4. MCP 直接协议实测和真实客户端派发都要做。官方文档支持变量不证明本机 CLI 已展开;真实路径错误用版本/命令留证。 +5. 进程完成与验收通过分开,leader 退出不证明整个进程组退出。保留报告和失败证据,再按实际运行身份回收。 + +范围:本次 gmktec/Linux、PI 0.85.1、Cursor CLI 的工程工具;客户端升级和其它系统需复核。这里的工具/进程守卫不是 OS 沙箱。 diff --git a/.doc/ops/lessons/INDEX.md b/.doc/ops/lessons/INDEX.md index 2e05973c..f59e3b52 100644 --- a/.doc/ops/lessons/INDEX.md +++ b/.doc/ops/lessons/INDEX.md @@ -9,3 +9,4 @@ | LESSON-20260923-matrix-status-cas | FEATURE-MATRIX、docs-apply、record_id、merge conflict、CAS | 矩阵/CURRENT 行变更走 docs apply;合并后核验状态列未被回退 | validated | [矩阵状态 CAS](2026-09-23-matrix-status-cas.md);2026-09-23 | validated 的证据范围见各条目;本日复核为历史材料和源码阅读,未重跑产品回归。后续按机制补充,过时条目标 superseded/retired 并保留替代链接。 +| LESSON-20260924-pi-tool-boundaries | PI、MCP、readonly、path、snapshot、process-group | 路径语义与快照边界一致,合法路径和拒绝路径都验收 | validated | [文件工具边界](2026-09-24-pi-tool-boundaries.md);2026-09-24 | diff --git a/.doc/ops/short-term/2026-09-24-subagent-workflow-standard.md b/.doc/ops/short-term/2026-09-24-subagent-workflow-standard.md index 325733ba..db8d1aec 100644 --- a/.doc/ops/short-term/2026-09-24-subagent-workflow-standard.md +++ b/.doc/ops/short-term/2026-09-24-subagent-workflow-standard.md @@ -5,16 +5,16 @@ status: done created: 2026-09-24 updated: 2026-09-24 owner: Codex -task_type: research +task_type: implementation task_tier: multi_stage policy_revision: "agent-governance-2026-09-21-r1 + issue-learning-2026-09-23-r1 + systemic-issue-analysis-2026-09-23-r1 + codegraph-governance-2026-09-24-r1; dev@5423b261f97f371bdf7fa5066e9305f9eddaef42" branch: feature/subagent-workflow-standard-2026-09-24 worktree: .worktrees/subagent-workflow-standard-2026-09-24 base_dev_sha: 5423b261f97f371bdf7fa5066e9305f9eddaef42 -write_scope: [".doc/ops/2026-09-24-subagent-model-config.md", ".doc/ops/2026-09-24-subagent-workflow-standard.md", ".doc/ops/short-term/2026-09-24-subagent-workflow-standard.md", ".doc/audit/2026-09-24-subagent-workflow-research.md", ".doc/ops/templates/subagent-stage-record.md", ".doc/ops/2026-09-21-policy-registry.md", ".doc/README.md", ".doc/audit/ISSUES.md", ".doc/ops/CURRENT.md"] +write_scope: ["scripts/pi_subagents.py", "scripts/pi-subagent-readonly.ts", "scripts/mcp/pi-subagents-mcp.mjs", "scripts/mcp/README.md", "scripts/tests/test_pi_subagents.py", ".cursor/mcp.json", ".cursor/rules/pi-subagents.mdc", ".doc", ".doc/ops/2026-09-24-subagent-model-config.md", ".doc/ops/2026-09-24-subagent-workflow-standard.md", ".doc/ops/short-term/2026-09-24-subagent-workflow-standard.md", ".doc/audit/2026-09-24-subagent-workflow-research.md", ".doc/ops/templates/subagent-stage-record.md", ".doc/ops/2026-09-21-policy-registry.md", ".doc/README.md", ".doc/audit/ISSUES.md", ".doc/ops/CURRENT.md"] allowed_environments: [] mutex: subagent-workflow-docs -review_state: pending +review_state: approved integration_state: pending deployment: not_required cleanup: retained-with-reason @@ -107,3 +107,20 @@ remote_sync: not_requested 本轮交付已完成;逻辑任务恢复 done,模型分工已获用户确认。新增配置与配套文档保存于本地任务分支;未合入 dev、未 push,主目录与 PI 全局设置均未修改。自动调用 PI 的执行器、角色工具限制实测、流程整体采纳和相关旧规则修复作为后续工作,不因配置文档存在视为已完成。 提交前检查记录:首次 git diff --cached --check 检出新配置头部两处 Markdown 行末双空格,提交未执行。已改为段落分隔并重跑检查;此前 git diff --check 不包含未跟踪新文件,最终以暂存区检查为准。 + +## 执行器实现续作 + +用户授权“接入自动调用 pi 的执行器”。继续原逻辑 task_id;操作登记 subagent-workflow-standard-2026-09-24-executor,Cursor Auto 负责代码,Codex 主协调。[实施契约与验证计划](../2026-09-24-pi-executor-implementation.md)。阶段 in_progress,原文“尚未实现”为此前交付历史,当前结果以本节后续报告为准。 + +## 执行器收口 + +- 实施与验证完成:代码由 Cursor Auto 编写,代码提交 69ffaa677e23a1dd9aa0528bb09b3acfcd38b119;Codex 主机复核与验收,本机 GLM-5.3 独立审查守卫候选。模型配置默认值按用户已确认方案。 +- [使用说明](../2026-09-24-pi-subagent-executor.md) · [完整报告](../../test-reports/2026-09-24-pi-executor-test-report.md)。实际 Cursor CLI 调用 roles/run/result,无 model_override、无 shell PI 替代;最终 ls/read 成功。 +- 完整工程 suite 173 项 PASS;提交后专项 34 项 PASS;node 检查、arch-check block、文档与证据核对通过。产品 Go/前端/PG/真实产品 Runner 无改动,未冒充验收。 +- 本轮授权交付终点:执行器源码与 Cursor CLI 本地接入验证。全套阶段审批状态机和 IDE 页面验证不在本次完成声明中。 +- integration_state=pending:本地 dev 已前进至 3de5bc5c396fc21887f0f19e6e3baa8784347f99(新增 nightly/测试修复),主目录干净;但 dev-full-gate-test-promo-2026-09-24 持 env:dev 真实验收租约,同锁还有别人的候选排队,不能抢占。未向 dev 写入本任务成果,未 push,未重建服务。 +- 接管:环境槽位释放后,从届时最新 dev 创建受控候选,重读规则并验证,再集成本任务分支。不得复用旧 expected-dev 或抢占别人队列。 +- cleanup 保留:未合入 dev,当前 worktree 用于配置审阅与运行;唯一报告/日志已纳入本任务文档提交,CodeGraph 为可再生缓存。由 owner 退出后的独立维护者按祖先/进程/证据条件复查,不强删。 +- ISSUE-20260924-pi-executor-boundaries 已按本地范围验证关闭;新增 LESSON-20260924-pi-tool-boundaries。既有测试规则漂移仍 open;其它 Cursor MCP 入口兼容性残差单独 deferred。研究/代码完成不自动关闭这些问题。 + +本轮临时操作登记为 subagent-workflow-standard-2026-09-24-executor;逻辑 task_id 保持原值。最终头部状态仅表示上述源码/本地验收完成,integration/deployment/remote_sync/cleanup 各自独立。 diff --git a/.doc/test-reports/2026-09-24-pi-executor-test-report.md b/.doc/test-reports/2026-09-24-pi-executor-test-report.md new file mode 100644 index 00000000..dce362e7 --- /dev/null +++ b/.doc/test-reports/2026-09-24-pi-executor-test-report.md @@ -0,0 +1,54 @@ +# 本机 PI Subagent 执行器验证报告 + +日期:2026-09-24。task_id:subagent-workflow-standard-2026-09-24;操作任务:subagent-workflow-standard-2026-09-24-executor。 +代码提交:`69ffaa677e23a1dd9aa0528bb09b3acfcd38b119`。真实模型请求的材料来自 `52462b45e985f596b2a503fc70ac12c3bd5fe571`;输入材料提交与执行器版本分开。测试期间执行器文件冻结,随后原样提交,代码摘要见客户端证据。 + +## 范围与结论 + +Cursor Auto 经项目 MCP 自动读取模型配置、派发本机 PI、取回持久报告的 CLI 链路通过。代码实施/修复由 Cursor 承担,PI 工具与输入范围受限,M3 默认禁用且未调用。 +这是个人工程工具验收,不代表产品 PI Agent Runner、产品 UI、PG 持久性或发布门禁通过。未重建服务、修改产品模型或 push。 + +## 环境 + +gmktec / Linux;PI 0.85.1;Cursor CLI 2026.09.18-9a7762b;Node v26.9.0;Python 3.14。 +入口:scripts/pi_subagents.py、scripts/mcp/pi-subagents-mcp.mjs、scripts/pi-subagent-readonly.ts。 +[配置](../ops/2026-09-24-subagent-model-config.md) · [运行说明](../ops/2026-09-24-pi-subagent-executor.md)。 +模型身份来自 PI 结构化消息与调用参数的比对,不是服务商内部路由的独立证明。 + +## 实际执行结果 + +| 检查 | 命令 / 输入 | 结果 | 证据 | +|---|---|---|---| +| 完整工程回归 | python3 -B -m unittest discover -s scripts/tests -p 'test_*.py' -v | 173 tests / OK / exit 0;111.229 秒 | [日志](assets/pi-executor-2026-09-24/engineering-tests.txt) | +| 提交后专项回归 | python3 -B -m unittest discover -s scripts/tests -p 'test_pi_subagents.py' -v | 34 tests / OK / exit 0;38.229 秒;HEAD=69ffaa67 | [日志](assets/pi-executor-2026-09-24/committed-focused.txt) | +| 架构门禁 | ./scripts/arch-check.sh --mode block | exit 0;archtest 两组通过 | [日志](assets/pi-executor-2026-09-24/arch-check.txt) | +| JS / 差异 | node --check scripts/mcp/pi-subagents-mcp.mjs;git diff --check | exit 0 | 本报告及最终检查 | +| Cursor 工具发现 | agent mcp list-tools pi-subagents | 3 个工具可发现 | [客户端证据](assets/pi-executor-2026-09-24/cursor-dispatch.json) | +| MCP 研究 | real-mcp-research-02 | Qwen3.8-Flash 返回目录声明及标记;早期 ls 误拒已保留并在最终链路重验 | [收据](assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/receipt.json) | +| MCP 测试 | real-mcp-test-01;Python 检查文件及 env 隔离 | GLM-5.3-Flash;命令 exit 0,PI_ISOLATED_TEST_PASS;非产品测试 | [收据](assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/receipt.json) | +| MCP 规划 | real-mcp-plan-01 | Qwen3.8-Max 正确总结 Cursor/M3/升级规则并返回 MODEL_PLAN_OK | [收据](assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/receipt.json) | +| 禁用角色 | real-mcp-disabled-01 / auxiliary | ROLE_DISABLED、isError=true,未调用 M3 | [汇总](assets/pi-executor-2026-09-24/live-mcp.json) | +| Cursor Auto 完整派发 | roles → run → result;cursor-auto-research-02;无 model_override 或 shell PI 替代 | succeeded;Qwen3.8-Flash;ls/read 均 isError=false;CURSOR_PI_AUTOMATION_OK | [报告](assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/report.md) · [工具调用](assets/pi-executor-2026-09-24/cursor-dispatch.json) | + +PI 单测使用明确的假传输;Git/锁/进程/MCP 为隔离实测,真实模型请求另列。未操作 Cursor IDE 页面。 + +## 覆盖与审查 + +回归覆盖配置/角色/循环校验、M3 越权拒绝、注册/租约/伪造身份、冻结 SHA、路径穿越/秘密/符号链接、TS 守卫合法根目录和负例、输出上限/超时/存活子进程、终止事件、PID 身份/只读查询、幂等/损坏收据/配置重载、环境白名单、测试与模型快照隔离、命令失败不可被模型叙事升级、MCP 主仓入口及拒绝原因。 +命令 pass/commands_passed 只表示显式命令结果;必需用例、任务验收与人工批准另判。non-test 模型完成仍为 pending/not_applicable。 + +Cursor Auto 实施,Codex 主机复核完整差异和测试;本机 GLM-5.3 独立审查只读守卫:[原审查](assets/pi-executor-2026-09-24/guard-review.json)。有效目录/默认路径候选已通过隔离与 inventory 检查落实;paths[] 不属于实际 PI 内置 schema,其假设不当作已证实漏洞,接口另外拒绝未知路径载体。最终修复由主机与回归确认,未声称 GLM 对整套最终代码出具通过结论。 + +## 失败过程及修复 + +- 初版路径规范化问题用假文件复现并修复,没有读取真实敏感文件;其它进程、环境、幂等和判定问题见[主记录](../audit/2026-09-24-pi-executor-boundaries.md)。 +- 第一次 GLM 整包审查 300 秒超时,无完整结果,不记 PASS;改为有完整返回的分段审查与主机复核。 +- 第一次 Cursor 会话未挂载工具。list-tools 证明本机 CLI 未展开 ${workspaceFolder};本次新入口改为相对路径并启用本工作区 pi-subagents 后通过。[官方 CLI MCP 文档](https://cursor.com/docs/cli/mcp)描述共用配置,本机行为以实际命令为准。 +- 合法目录枚举的两次失败分别来自 exact-root 判断和内部扩展污染模型快照;修复、新回归和最终 Cursor 调用证明 ls/read 正常,旧收据保留。 +- 部分 Cursor 编码客户端退出后留下语言服务子进程,agentctl 正确保留 recovery_required;host 仅核对/终止本任务记录的进程组后 recover,没有删锁或杀他人进程。 + +## 交付边界 + +dev 集成以任务和机器收据为准;共享 dev 正由另一任务持 env:dev 验收租约,不能抢占或绕过集成。模型分工已确认,流程整体草案未因此自动全仓生效。 +执行器不是全套 S0–S9 审批状态机,也不是 OS 沙箱;批准测试代码属于可信执行面。本版不直接操作共享环境或自动安装依赖。PI 获得命令摘要/日志引用,完整日志由主 Agent 核验并按需补充上下文,不能用预览证明所有必需用例。 +原始 Cursor 会话、模型 thinking 不入 Git;只留必要工具调用/结果/摘要。未归档凭证、业务正文或敏感截图。 diff --git a/.doc/test-reports/assets/pi-executor-2026-09-24/arch-check.txt b/.doc/test-reports/assets/pi-executor-2026-09-24/arch-check.txt new file mode 100644 index 00000000..d6825916 --- /dev/null +++ b/.doc/test-reports/assets/pi-executor-2026-09-24/arch-check.txt @@ -0,0 +1,5 @@ +arch-check mode=block +boundaries=/home/weichen/projects/Agent-System/.worktrees/subagent-workflow-standard-2026-09-24/.doc/system-design/module-boundaries.yaml +ok chat-agent-system/internal/archtest 0.222s +ok chat-agent-system/internal/archtest 0.193s +arch-check block: production gate passed diff --git a/.doc/test-reports/assets/pi-executor-2026-09-24/committed-focused.txt b/.doc/test-reports/assets/pi-executor-2026-09-24/committed-focused.txt new file mode 100644 index 00000000..79936e9a --- /dev/null +++ b/.doc/test-reports/assets/pi-executor-2026-09-24/committed-focused.txt @@ -0,0 +1,88 @@ +test_00_executor_module_present (test_pi_subagents.PiSubagentsTests.test_00_executor_module_present) ... ok +test_approved_commands_do_not_mutate_model_snapshot (test_pi_subagents.PiSubagentsTests.test_approved_commands_do_not_mutate_model_snapshot) ... ok +test_config_catalog_parses_known_pool_and_roles (test_pi_subagents.PiSubagentsTests.test_config_catalog_parses_known_pool_and_roles) ... ok +test_config_rejects_unknown_alias_and_cycle (test_pi_subagents.PiSubagentsTests.test_config_rejects_unknown_alias_and_cycle) ... ok +test_config_reload_snapshot_on_dispatch (test_pi_subagents.PiSubagentsTests.test_config_reload_snapshot_on_dispatch) ... ok +test_corrupt_receipt_fail_closed (test_pi_subagents.PiSubagentsTests.test_corrupt_receipt_fail_closed) ... ok +test_crash_before_receipt_terminal_is_unknown_on_status (test_pi_subagents.PiSubagentsTests.test_crash_before_receipt_terminal_is_unknown_on_status) ... ok +test_disabled_auxiliary_and_m3_critical_remap_denied (test_pi_subagents.PiSubagentsTests.test_disabled_auxiliary_and_m3_critical_remap_denied) ... ok +test_extension_outside_model_snapshot_inventory (test_pi_subagents.PiSubagentsTests.test_extension_outside_model_snapshot_inventory) +Model snapshot must contain only declared inputs; -e guard lives outside it. ... ok +test_failed_replay_stays_failure (test_pi_subagents.PiSubagentsTests.test_failed_replay_stays_failure) ... ok +test_forged_lease_env_refused (test_pi_subagents.PiSubagentsTests.test_forged_lease_env_refused) ... ok +test_global_concurrency_limit (test_pi_subagents.PiSubagentsTests.test_global_concurrency_limit) ... ok +test_idempotent_replay_and_digest_mismatch (test_pi_subagents.PiSubagentsTests.test_idempotent_replay_and_digest_mismatch) ... ok +test_input_path_traversal_symlink_secret_refusal (test_pi_subagents.PiSubagentsTests.test_input_path_traversal_symlink_secret_refusal) ... ok +test_leader_exit_reaps_orphan_child (test_pi_subagents.PiSubagentsTests.test_leader_exit_reaps_orphan_child) ... ok +test_malformed_and_empty_outputs_fail (test_pi_subagents.PiSubagentsTests.test_malformed_and_empty_outputs_fail) ... ok +test_mcp_from_worktree_uses_main_agentctl (test_pi_subagents.PiSubagentsTests.test_mcp_from_worktree_uses_main_agentctl) +Server INSTALL_ROOT may be a linked worktree; agentctl must resolve from main. ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_mcp_initialize_list_run_result (test_pi_subagents.PiSubagentsTests.test_mcp_initialize_list_run_result) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_mcp_running_poll_is_not_error (test_pi_subagents.PiSubagentsTests.test_mcp_running_poll_is_not_error) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_mcp_surfaces_role_disabled_and_scope_refusal (test_pi_subagents.PiSubagentsTests.test_mcp_surfaces_role_disabled_and_scope_refusal) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=10 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=6 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=8 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_model_mismatch_fails (test_pi_subagents.PiSubagentsTests.test_model_mismatch_fails) ... ok +test_naked_run_without_lease_refused (test_pi_subagents.PiSubagentsTests.test_naked_run_without_lease_refused) ... ok +test_orphan_result_is_readonly (test_pi_subagents.PiSubagentsTests.test_orphan_result_is_readonly) ... ok +test_output_cap_on_stdout_flood (test_pi_subagents.PiSubagentsTests.test_output_cap_on_stdout_flood) ... ok +test_readonly_guard_allows_exact_root_listing (test_pi_subagents.PiSubagentsTests.test_readonly_guard_allows_exact_root_listing) +Exact-root ls/grep must pass when snapshot inventory is allowlisted-only. ... ok +test_readonly_guard_rejects_at_prefix (test_pi_subagents.PiSubagentsTests.test_readonly_guard_rejects_at_prefix) +Exercise extension path policy via Node strip-types if available. ... ok +test_replay_keeps_old_config_after_disable (test_pi_subagents.PiSubagentsTests.test_replay_keeps_old_config_after_disable) ... ok +test_roles_does_not_invoke_pi (test_pi_subagents.PiSubagentsTests.test_roles_does_not_invoke_pi) ... ok +test_run_emits_exact_pi_flags_and_receipt (test_pi_subagents.PiSubagentsTests.test_run_emits_exact_pi_flags_and_receipt) ... ok +test_scope_refusal_outside_report_path (test_pi_subagents.PiSubagentsTests.test_scope_refusal_outside_report_path) ... ok +test_scrub_env_drops_pi_dir_for_tests (test_pi_subagents.PiSubagentsTests.test_scrub_env_drops_pi_dir_for_tests) ... ok +test_source_sha_rejects_symbolic_refs (test_pi_subagents.PiSubagentsTests.test_source_sha_rejects_symbolic_refs) ... ok +test_test_run_requires_approved_commands_and_records_failure (test_pi_subagents.PiSubagentsTests.test_test_run_requires_approved_commands_and_records_failure) ... ok +test_timeout_kills_process_group (test_pi_subagents.PiSubagentsTests.test_timeout_kills_process_group) ... ok + +---------------------------------------------------------------------- +Ran 34 tests in 38.229s + +OK diff --git a/.doc/test-reports/assets/pi-executor-2026-09-24/cursor-dispatch.json b/.doc/test-reports/assets/pi-executor-2026-09-24/cursor-dispatch.json new file mode 100644 index 00000000..9d28cb1e --- /dev/null +++ b/.doc/test-reports/assets/pi-executor-2026-09-24/cursor-dispatch.json @@ -0,0 +1,64 @@ +{ + "client": { + "session_id": "ef25c056-edb9-4902-bf4e-dcafb255e9f9", + "model": "Auto" + }, + "tools": [ + { + "tool": "pi_subagent_roles", + "server": "pi-subagents", + "arguments": { + "worktree": "/home/weichen/projects/Agent-System/.worktrees/subagent-workflow-standard-2026-09-24", + "task_id": "subagent-workflow-standard-2026-09-24-executor" + } + }, + { + "tool": "pi_subagent_run", + "server": "pi-subagents", + "arguments": { + "worktree": "/home/weichen/projects/Agent-System/.worktrees/subagent-workflow-standard-2026-09-24", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "request": { + "role_id": "research", + "request_id": "cursor-auto-research-02", + "goal": "call ls(path='.') and confirm the snapshot contains PROJECT.md; call read on PROJECT.md; quote two directory names declared in its repository map; finish CURSOR_PI_AUTOMATION_OK. Report any tool failure truthfully; do not call failed ls/read success.", + "authorization_ref": "user requested PI executor isolated acceptance", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "input_files": [ + "PROJECT.md" + ], + "timeout_seconds": 90 + } + } + }, + { + "tool": "pi_subagent_result", + "server": "pi-subagents", + "arguments": { + "request_id": "cursor-auto-research-02", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "worktree": "/home/weichen/projects/Agent-System/.worktrees/subagent-workflow-standard-2026-09-24" + } + }, + { + "tool": "pi_subagent_result", + "server": "pi-subagents", + "arguments": { + "request_id": "cursor-auto-research-02", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "worktree": "/home/weichen/projects/Agent-System/.worktrees/subagent-workflow-standard-2026-09-24" + } + } + ], + "implementation_commit": "69ffaa677e23a1dd9aa0528bb09b3acfcd38b119", + "code_sha256": { + "scripts/pi_subagents.py": "5a656ee93d8effb1ae347d113a4e2b579bdc78a795d848dc6bbf9057c0d2a0df", + "scripts/pi-subagent-readonly.ts": "8d818dccb3c2f3bff9de0fcfae1ace110a50b1e3055afd21179171320c334284", + "scripts/mcp/pi-subagents-mcp.mjs": "9a3a2d2b8793e0dbbc19110af4ba42352661b791e72987136aa1f3a13a59c143", + "scripts/mcp/README.md": "37a25cb07e4405e199074b3c4714792269cba562f134e7652bd0598a642e9b96", + "scripts/tests/test_pi_subagents.py": "4276c56ab42abca268f4807f3814741fe06341eb56adc1b215debbd8452e374a", + ".cursor/mcp.json": "690815b2fe5ec9b48d39c9c1600fa0d7a39f343917bb1e187c89d4dfbcce8f88", + ".cursor/rules/pi-subagents.mdc": "560682ba89daab2be100be68983eba0b9fcb7cfca73d99747a5fb54352feb2c7" + }, + "scope": "Real Cursor CLI via MCP, not IDE UI; no model override; no shell substitute" +} diff --git a/.doc/test-reports/assets/pi-executor-2026-09-24/engineering-tests.txt b/.doc/test-reports/assets/pi-executor-2026-09-24/engineering-tests.txt new file mode 100644 index 00000000..2d58f7ce --- /dev/null +++ b/.doc/test-reports/assets/pi-executor-2026-09-24/engineering-tests.txt @@ -0,0 +1,250 @@ +test_linux_permission_error_path_remains_fail_closed (test_agent_worktree.ProcessVisibilityTest.test_linux_permission_error_path_remains_fail_closed) ... ok +test_unknown_same_uid_inaccessible_cwd_is_not_skipped (test_agent_worktree.ProcessVisibilityTest.test_unknown_same_uid_inaccessible_cwd_is_not_skipped) ... ok +test_branch_delete_refusal_preserves_branch_without_force_with_visibility_fixture (test_agent_worktree.WorktreeTest.test_branch_delete_refusal_preserves_branch_without_force_with_visibility_fixture) ... ok +test_cleanup_actual_branch_mapping_with_visibility_fixture (test_agent_worktree.WorktreeTest.test_cleanup_actual_branch_mapping_with_visibility_fixture) ... ok +test_cleanup_legacy_mapping_and_nonforced_branch_delete_with_visibility_fixture (test_agent_worktree.WorktreeTest.test_cleanup_legacy_mapping_and_nonforced_branch_delete_with_visibility_fixture) ... ok +test_cleanup_lifecycle_lock_prevents_a_new_run (test_agent_worktree.WorktreeTest.test_cleanup_lifecycle_lock_prevents_a_new_run) ... ok +test_cleanup_refuses_active_registry_operation_even_with_other_cwd (test_agent_worktree.WorktreeTest.test_cleanup_refuses_active_registry_operation_even_with_other_cwd) ... ok +test_cleanup_refuses_live_process_cwd (test_agent_worktree.WorktreeTest.test_cleanup_refuses_live_process_cwd) ... ok +test_cleanup_refuses_tracked_untracked_and_ignored_evidence (test_agent_worktree.WorktreeTest.test_cleanup_refuses_tracked_untracked_and_ignored_evidence) ... ok +test_cleanup_refuses_unfinished_git_operation (test_agent_worktree.WorktreeTest.test_cleanup_refuses_unfinished_git_operation) ... ok +test_cleanup_refuses_unmerged_commit (test_agent_worktree.WorktreeTest.test_cleanup_refuses_unmerged_commit) ... ok +test_create_from_feature_uses_current_dev_and_canonical_main (test_agent_worktree.WorktreeTest.test_create_from_feature_uses_current_dev_and_canonical_main) ... ok +test_create_with_main_on_unrelated_branch_uses_dev (test_agent_worktree.WorktreeTest.test_create_with_main_on_unrelated_branch_uses_dev) ... ok +test_forged_inherited_lease_is_refused (test_agent_worktree.WorktreeTest.test_forged_inherited_lease_is_refused) ... ok +test_inherited_worktree_lease_does_not_double_lock (test_agent_worktree.WorktreeTest.test_inherited_worktree_lease_does_not_double_lock) ... ok +test_list_is_read_only_without_init (test_agent_worktree.WorktreeTest.test_list_is_read_only_without_init) ... ok +test_rejects_traversal_nested_and_protected_branches (test_agent_worktree.WorktreeTest.test_rejects_traversal_nested_and_protected_branches) ... ok +test_same_task_id_and_existing_branch_do_not_collide (test_agent_worktree.WorktreeTest.test_same_task_id_and_existing_branch_do_not_collide) ... ok +test_stable_lock_refuses_concurrent_writer (test_agent_worktree.WorktreeTest.test_stable_lock_refuses_concurrent_writer) ... ok +test_symlink_parent_or_target_is_refused (test_agent_worktree.WorktreeTest.test_symlink_parent_or_target_is_refused) ... ok +test_write_requires_explicit_init (test_agent_worktree.WorktreeTest.test_write_requires_explicit_init) ... ok +test_admin_document_cannot_bypass_done_with_compact_cells (test_agentctl.AgentctlTests.test_admin_document_cannot_bypass_done_with_compact_cells) ... ok +test_admin_document_cannot_overwrite_human_sections (test_agentctl.AgentctlTests.test_admin_document_cannot_overwrite_human_sections) ... ok +test_admin_document_cannot_overwrite_integration_slot (test_agentctl.AgentctlTests.test_admin_document_cannot_overwrite_integration_slot) ... ok +test_admin_document_cas_preserves_slot_and_needs_capability (test_agentctl.AgentctlTests.test_admin_document_cas_preserves_slot_and_needs_capability) ... ok +test_admin_full_document_requires_explicit_admin_capability (test_agentctl.AgentctlTests.test_admin_full_document_requires_explicit_admin_capability) ... ok +test_claim_blocks_task_close_until_released (test_agentctl.AgentctlTests.test_claim_blocks_task_close_until_released) ... ok +test_claim_concurrent_twenty_exactly_one_held (test_agentctl.AgentctlTests.test_claim_concurrent_twenty_exactly_one_held) ... ok +test_claim_frozen_rejects_even_holder (test_agentctl.AgentctlTests.test_claim_frozen_rejects_even_holder) ... ok +test_claim_parent_child_overlap_and_sibling_ok (test_agentctl.AgentctlTests.test_claim_parent_child_overlap_and_sibling_ok) ... ok +test_claim_request_id_idempotent_and_reuse_guard (test_agentctl.AgentctlTests.test_claim_request_id_idempotent_and_reuse_guard) ... ok +test_claim_unrelated_resources_parallel_ok (test_agentctl.AgentctlTests.test_claim_unrelated_resources_parallel_ok) ... ok +test_commit_lease_must_cover_staged_files_not_only_task_scope (test_agentctl.AgentctlTests.test_commit_lease_must_cover_staged_files_not_only_task_scope) ... ok +test_daemon_does_not_grant_register_or_docs_apply (test_agentctl.AgentctlTests.test_daemon_does_not_grant_register_or_docs_apply) ... ok +test_daemon_single_instance_lock_busy_with_holder_pid (test_agentctl.AgentctlTests.test_daemon_single_instance_lock_busy_with_holder_pid) ... ok +test_daemon_stop_leaves_pending_queue_untouched (test_agentctl.AgentctlTests.test_daemon_stop_leaves_pending_queue_untouched) ... ok +test_descendant_resource_guard_accepts_only_held_resource (test_agentctl.AgentctlTests.test_descendant_resource_guard_accepts_only_held_resource) ... ok +test_docs_cannot_launder_unmanaged_other_task_changes (test_agentctl.AgentctlTests.test_docs_cannot_launder_unmanaged_other_task_changes) ... ok +test_docs_foreign_current_row_is_rejected (test_agentctl.AgentctlTests.test_docs_foreign_current_row_is_rejected) ... ok +test_docs_multi_file_preflight_failure_has_no_partial_writes (test_agentctl.AgentctlTests.test_docs_multi_file_preflight_failure_has_no_partial_writes) ... ok +test_docs_project_parallel_apply_keeps_both_rows (test_agentctl.AgentctlTests.test_docs_project_parallel_apply_keeps_both_rows) ... ok +test_docs_project_preview_apply_receipts_and_projections (test_agentctl.AgentctlTests.test_docs_project_preview_apply_receipts_and_projections) ... ok +test_docs_project_same_row_race_base_changed_no_partial (test_agentctl.AgentctlTests.test_docs_project_same_row_race_base_changed_no_partial) ... ok +test_docs_row_cas_preserves_unrelated_rows_and_is_idempotent (test_agentctl.AgentctlTests.test_docs_row_cas_preserves_unrelated_rows_and_is_idempotent) ... ok +test_env_guard_accepts_clean_main_and_requires_all_target_leases (test_agentctl.AgentctlTests.test_env_guard_accepts_clean_main_and_requires_all_target_leases) ... ok +test_env_guard_refuses_linked_worktree_even_with_capability (test_agentctl.AgentctlTests.test_env_guard_refuses_linked_worktree_even_with_capability) ... ok +test_failed_child_releases_lease_and_preserves_failure (test_agentctl.AgentctlTests.test_failed_child_releases_lease_and_preserves_failure) ... ok +test_failed_revalidation_revokes_old_success_receipt (test_agentctl.AgentctlTests.test_failed_revalidation_revokes_old_success_receipt) ... ok +test_guard_build_requires_exact_clean_commit (test_agentctl.AgentctlTests.test_guard_build_requires_exact_clean_commit) ... ok +test_hook_checks_reject_out_of_scope_and_secret_paths (test_agentctl.AgentctlTests.test_hook_checks_reject_out_of_scope_and_secret_paths) ... ok +test_hook_rejects_shared_document_without_publish_receipt (test_agentctl.AgentctlTests.test_hook_rejects_shared_document_without_publish_receipt) ... ok +test_hooks_allow_published_shared_document_receipt (test_agentctl.AgentctlTests.test_hooks_allow_published_shared_document_receipt) ... ok +test_hooks_allow_scoped_task_commit_under_live_lease (test_agentctl.AgentctlTests.test_hooks_allow_scoped_task_commit_under_live_lease) ... ok +test_hooks_refuse_overwriting_foreign_hook (test_agentctl.AgentctlTests.test_hooks_refuse_overwriting_foreign_hook) ... ok +test_init_cannot_steal_live_legacy_lock (test_agentctl.AgentctlTests.test_init_cannot_steal_live_legacy_lock) ... ok +test_init_preserves_existing_legacy_lock_inode (test_agentctl.AgentctlTests.test_init_preserves_existing_legacy_lock_inode) ... ok +test_installed_hooks_reject_direct_dev_commit (test_agentctl.AgentctlTests.test_installed_hooks_reject_direct_dev_commit) ... ok +test_interrupted_validation_stops_child_before_releasing_scope (test_agentctl.AgentctlTests.test_interrupted_validation_stops_child_before_releasing_scope) ... ok +test_invalid_document_request_shape_has_no_write_side_effects (test_agentctl.AgentctlTests.test_invalid_document_request_shape_has_no_write_side_effects) ... ok +test_linked_worktree_uses_only_main_coordination_root (test_agentctl.AgentctlTests.test_linked_worktree_uses_only_main_coordination_root) ... ok +test_live_and_stale_credentials_cannot_be_spoofed (test_agentctl.AgentctlTests.test_live_and_stale_credentials_cannot_be_spoofed) ... ok +test_live_run_cannot_be_recovered_or_task_closed (test_agentctl.AgentctlTests.test_live_run_cannot_be_recovered_or_task_closed) ... ok +test_matrix_done_without_evidence_refused (test_agentctl.AgentctlTests.test_matrix_done_without_evidence_refused) ... ok +test_matrix_duplicate_or_rename_record_id_rejected (test_agentctl.AgentctlTests.test_matrix_duplicate_or_rename_record_id_rejected) ... ok +test_matrix_record_id_layout_migration_without_new_dones (test_agentctl.AgentctlTests.test_matrix_record_id_layout_migration_without_new_dones) +Additive record_id column must not trip EVIDENCE_REQUIRED when statuses unchanged. ... ok +test_matrix_unknown_columns_and_lineage_preserved (test_agentctl.AgentctlTests.test_matrix_unknown_columns_and_lineage_preserved) ... ok +test_multi_resource_acquisition_is_atomic (test_agentctl.AgentctlTests.test_multi_resource_acquisition_is_atomic) ... ok +test_parent_child_path_conflict_and_disjoint_coexistence (test_agentctl.AgentctlTests.test_parent_child_path_conflict_and_disjoint_coexistence) ... ok +test_path_scope_and_capability_are_enforced (test_agentctl.AgentctlTests.test_path_scope_and_capability_are_enforced) ... ok +test_policy_invalid_json_rejects_write (test_agentctl.AgentctlTests.test_policy_invalid_json_rejects_write) ... ok +test_policy_missing_rejects_write_but_status_stays_readonly (test_agentctl.AgentctlTests.test_policy_missing_rejects_write_but_status_stays_readonly) ... ok +test_policy_protocol_too_low_rejects_write (test_agentctl.AgentctlTests.test_policy_protocol_too_low_rejects_write) ... ok +test_quarantine_sweep_keeps_live_child_and_release_refuses (test_agentctl.AgentctlTests.test_quarantine_sweep_keeps_live_child_and_release_refuses) ... ok +test_quarantine_ttl_demotes_never_auto_completes (test_agentctl.AgentctlTests.test_quarantine_ttl_demotes_never_auto_completes) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/email/errors.py:12: ResourceWarning: unclosed database in + class MessageParseError(MessageError): +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/email/errors.py:12: ResourceWarning: unclosed database in + class MessageParseError(MessageError): +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/email/errors.py:12: ResourceWarning: unclosed database in + class MessageParseError(MessageError): +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/email/errors.py:12: ResourceWarning: unclosed database in + class MessageParseError(MessageError): +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/email/errors.py:12: ResourceWarning: unclosed database in + class MessageParseError(MessageError): +ResourceWarning: Enable tracemalloc to get the object allocation traceback +{"demoted": [{"from": "running", "run_id": "hb-stale", "to": "suspect"}, {"from": "suspect", "run_id": "sus-stale", "to": "quarantine"}], "heartbeat_ttl_seconds": 300, "status": "ok", "suspect_ttl_seconds": 600} +ok +test_quarantine_unreadable_proc_stops_at_suspect (test_agentctl.AgentctlTests.test_quarantine_unreadable_proc_stops_at_suspect) ... {"demoted": [{"from": "running", "run_id": "run-unknown", "to": "suspect"}], "heartbeat_ttl_seconds": 300, "status": "ok", "suspect_ttl_seconds": 600} +ok +test_queue_enqueue_list_cancel_roundtrip (test_agentctl.AgentctlTests.test_queue_enqueue_list_cancel_roundtrip) ... ok +test_queue_schedule_promotes_validated_candidate (test_agentctl.AgentctlTests.test_queue_schedule_promotes_validated_candidate) ... ok +test_queue_subparser_registered_once (test_agentctl.AgentctlTests.test_queue_subparser_registered_once) +Duplicate queue registration must not shadow handler-compatible flags. ... usage: python3.14 -m unittest [-h] [--repo REPO] + {init,status,doctor,task,with,guard,worktree-check,docs,queue,cleanup,recover,operation,freeze,unfreeze,hooks,validate,integrate,deploy,claim,quarantine,daemon} ... +python3.14 -m unittest: error: unrecognized arguments: --head-sha deadbeef +ok +test_recover_git_dev_requires_verification_marker (test_agentctl.AgentctlTests.test_recover_git_dev_requires_verification_marker) ... ok +test_recovery_refuses_dead_supervisor_with_live_child (test_agentctl.AgentctlTests.test_recovery_refuses_dead_supervisor_with_live_child) ... ok +test_registered_active_task_must_close_before_cleanup (test_agentctl.AgentctlTests.test_registered_active_task_must_close_before_cleanup) ... ok +test_replaced_compatibility_inode_is_not_a_new_free_lock (test_agentctl.AgentctlTests.test_replaced_compatibility_inode_is_not_a_new_free_lock) ... ok +test_shared_lease_does_not_satisfy_write_guard (test_agentctl.AgentctlTests.test_shared_lease_does_not_satisfy_write_guard) ... ok +test_stale_fence_env_is_stale_generation (test_agentctl.AgentctlTests.test_stale_fence_env_is_stale_generation) ... ok +test_task_close_does_not_auto_promote_matrix_done (test_agentctl.AgentctlTests.test_task_close_does_not_auto_promote_matrix_done) ... ok +test_task_index_lease_serializes_index_but_not_disjoint_work (test_agentctl.AgentctlTests.test_task_index_lease_serializes_index_but_not_disjoint_work) ... ok +test_task_registration_rejects_protected_branch_and_invalid_scopes (test_agentctl.AgentctlTests.test_task_registration_rejects_protected_branch_and_invalid_scopes) ... ok +test_uninitialized_status_and_doctor_do_not_create_state (test_agentctl.AgentctlTests.test_uninitialized_status_and_doctor_do_not_create_state) ... ok +test_unset_fence_env_matches_default_zero (test_agentctl.AgentctlTests.test_unset_fence_env_matches_default_zero) +Self-bootstrap: hooks re-exec updated agentctl without AGENTCTL_FENCE set. ... ok +test_validated_linear_commit_cannot_bypass_candidate_entrypoint (test_agentctl.AgentctlTests.test_validated_linear_commit_cannot_bypass_candidate_entrypoint) ... ok +test_validated_merge_candidate_is_exactly_promoted_to_dev (test_agentctl.AgentctlTests.test_validated_merge_candidate_is_exactly_promoted_to_dev) ... ok +test_boot_and_self_proc_are_observable (test_agentctl.ProcessPlatformTests.test_boot_and_self_proc_are_observable) ... ok +test_descent_unreadable_is_unknown (test_agentctl.ProcessPlatformTests.test_descent_unreadable_is_unknown) ... ok +test_gone_pid_is_dead (test_agentctl.ProcessPlatformTests.test_gone_pid_is_dead) ... ok +test_lease_denies_when_supervisor_proc_unreadable (test_agentctl.ProcessPlatformTests.test_lease_denies_when_supervisor_proc_unreadable) ... ok +test_unreadable_proc_is_unknown_not_dead (test_agentctl.ProcessPlatformTests.test_unreadable_proc_is_unknown_not_dead) ... ok +test_zombie_is_not_alive (test_agentctl.ProcessPlatformTests.test_zombie_is_not_alive) ... ok +test_build_projection_row_canonical (test_agentctl_w4.AgentctlW4Tests.test_build_projection_row_canonical) ... ok +test_deploy_recover_loop_failure_sets_recovery_required (test_agentctl_w4.AgentctlW4Tests.test_deploy_recover_loop_failure_sets_recovery_required) ... ok +test_deploy_recover_loop_success_with_fake_command (test_agentctl_w4.AgentctlW4Tests.test_deploy_recover_loop_success_with_fake_command) ... ok +test_document_projection_cas_mismatch_refuses (test_agentctl_w4.AgentctlW4Tests.test_document_projection_cas_mismatch_refuses) ... ok +test_project_cleanup_markdown_header_is_report_only (test_agentctl_w4.AgentctlW4Tests.test_project_cleanup_markdown_header_is_report_only) ... ok +test_recover_deploy_from_recovery_required (test_agentctl_w4.AgentctlW4Tests.test_recover_deploy_from_recovery_required) ... ok +test_row_projection_ambiguous_record_refuses (test_agentctl_w4.AgentctlW4Tests.test_row_projection_ambiguous_record_refuses) ... ok +test_row_projection_cas_and_insert (test_agentctl_w4.AgentctlW4Tests.test_row_projection_cas_and_insert) ... ok +test_cwd_visibility_structured_on_host (test_agentctl_w4.DarwinCwdVisibilityTests.test_cwd_visibility_structured_on_host) ... ok +test_cleanup_report_never_deletes (test_codegraph_governance.CodegraphGovernanceTest.test_cleanup_report_never_deletes) ... ok +test_codegraph_sync_fail_open_without_binary (test_codegraph_governance.CodegraphGovernanceTest.test_codegraph_sync_fail_open_without_binary) ... ok +test_create_skips_codegraph_when_missing (test_codegraph_governance.CodegraphGovernanceTest.test_create_skips_codegraph_when_missing) ... ok +test_docs_drift_detects_done_regression (test_codegraph_governance.CodegraphGovernanceTest.test_docs_drift_detects_done_regression) ... ok +test_hooks_install_includes_codegraph_sync_hooks (test_codegraph_governance.CodegraphGovernanceTest.test_hooks_install_includes_codegraph_sync_hooks) ... ok +test_both_expected_tests_pass (test_go_test_evidence.TestEvidence.test_both_expected_tests_pass) ... ok +test_missing_partial_skip_failure_and_duplicate_are_not_pass (test_go_test_evidence.TestEvidence.test_missing_partial_skip_failure_and_duplicate_are_not_pass) ... ok +test_subtests_and_case_mismatches_do_not_prove_parent_execution (test_go_test_evidence.TestEvidence.test_subtests_and_case_mismatches_do_not_prove_parent_execution) ... ok +test_all_profiles_have_noninteractive_flags_and_explicit_pi_routes (test_herdr_agents.HerdrTests.test_all_profiles_have_noninteractive_flags_and_explicit_pi_routes) ... ok +test_explicit_prewrite_retry_reaches_flash (test_herdr_agents.HerdrTests.test_explicit_prewrite_retry_reaches_flash) ... ok +test_implementation_fallback_is_explicit (test_herdr_agents.HerdrTests.test_implementation_fallback_is_explicit) ... ok +test_kimi_atomic_limit_across_eight_processes (test_herdr_agents.HerdrTests.test_kimi_atomic_limit_across_eight_processes) ... ok +test_kimi_reason_disabled_marker_and_cross_lane_budget (test_herdr_agents.HerdrTests.test_kimi_reason_disabled_marker_and_cross_lane_budget) ... ok +test_kimi_uncertain_send_consumes_budget (test_herdr_agents.HerdrTests.test_kimi_uncertain_send_consumes_budget) ... ok +test_main_or_wrong_target_pane_cannot_start (test_herdr_agents.HerdrTests.test_main_or_wrong_target_pane_cannot_start) ... ok +test_outside_herdr_and_wrong_task_cwd_never_contact_transport (test_herdr_agents.HerdrTests.test_outside_herdr_and_wrong_task_cwd_never_contact_transport) ... ok +test_report_routes_to_max_not_kimi_or_minimax (test_herdr_agents.HerdrTests.test_report_routes_to_max_not_kimi_or_minimax) ... ok +test_same_role_ambiguity_and_foreign_cwd_do_not_dispatch (test_herdr_agents.HerdrTests.test_same_role_ambiguity_and_foreign_cwd_do_not_dispatch) ... ok +test_uncertain_transport_error_and_blocked_do_not_fallback (test_herdr_agents.HerdrTests.test_uncertain_transport_error_and_blocked_do_not_fallback) ... ok +test_authorized_pinned_rebuild_preserves_no_build (test_ops_guards.OpsGuardsTest.test_authorized_pinned_rebuild_preserves_no_build) ... ok +test_build_accepts_nightly_evidence_excluded_from_build_context (test_ops_guards.OpsGuardsTest.test_build_accepts_nightly_evidence_excluded_from_build_context) ... ok +test_build_context_is_frozen_when_managed_source_changes (test_ops_guards.OpsGuardsTest.test_build_context_is_frozen_when_managed_source_changes) ... ok +test_build_dirty_source_refuses_before_docker_or_receipts (test_ops_guards.OpsGuardsTest.test_build_dirty_source_refuses_before_docker_or_receipts) ... ok +test_build_mismatched_commit_refuses_before_docker_or_receipts (test_ops_guards.OpsGuardsTest.test_build_mismatched_commit_refuses_before_docker_or_receipts) ... ok +test_build_untracked_source_refuses_before_docker_or_receipts (test_ops_guards.OpsGuardsTest.test_build_untracked_source_refuses_before_docker_or_receipts) ... ok +test_clean_build_records_exact_source_commit (test_ops_guards.OpsGuardsTest.test_clean_build_records_exact_source_commit) ... ok +test_environment_lease_cannot_deploy_dirty_main_source (test_ops_guards.OpsGuardsTest.test_environment_lease_cannot_deploy_dirty_main_source) ... ok +test_invalid_action_does_not_initialize_environment (test_ops_guards.OpsGuardsTest.test_invalid_action_does_not_initialize_environment) ... ok +test_linked_worktree_writes_refuse_and_queries_remain_read_only (test_ops_guards.OpsGuardsTest.test_linked_worktree_writes_refuse_and_queries_remain_read_only) ... ok +test_one_environment_lease_does_not_authorize_all (test_ops_guards.OpsGuardsTest.test_one_environment_lease_does_not_authorize_all) ... ok +test_queries_never_initialize_environment (test_ops_guards.OpsGuardsTest.test_queries_never_initialize_environment) ... ok +test_service_writes_without_lease_refuse_before_any_side_effect (test_ops_guards.OpsGuardsTest.test_service_writes_without_lease_refuse_before_any_side_effect) ... ok +test_valid_lease_cannot_hide_linked_caller_or_linked_script (test_ops_guards.OpsGuardsTest.test_valid_lease_cannot_hide_linked_caller_or_linked_script) ... ok +test_00_executor_module_present (test_pi_subagents.PiSubagentsTests.test_00_executor_module_present) ... ok +test_approved_commands_do_not_mutate_model_snapshot (test_pi_subagents.PiSubagentsTests.test_approved_commands_do_not_mutate_model_snapshot) ... ok +test_config_catalog_parses_known_pool_and_roles (test_pi_subagents.PiSubagentsTests.test_config_catalog_parses_known_pool_and_roles) ... ok +test_config_rejects_unknown_alias_and_cycle (test_pi_subagents.PiSubagentsTests.test_config_rejects_unknown_alias_and_cycle) ... ok +test_config_reload_snapshot_on_dispatch (test_pi_subagents.PiSubagentsTests.test_config_reload_snapshot_on_dispatch) ... ok +test_corrupt_receipt_fail_closed (test_pi_subagents.PiSubagentsTests.test_corrupt_receipt_fail_closed) ... ok +test_crash_before_receipt_terminal_is_unknown_on_status (test_pi_subagents.PiSubagentsTests.test_crash_before_receipt_terminal_is_unknown_on_status) ... ok +test_disabled_auxiliary_and_m3_critical_remap_denied (test_pi_subagents.PiSubagentsTests.test_disabled_auxiliary_and_m3_critical_remap_denied) ... ok +test_extension_outside_model_snapshot_inventory (test_pi_subagents.PiSubagentsTests.test_extension_outside_model_snapshot_inventory) +Model snapshot must contain only declared inputs; -e guard lives outside it. ... ok +test_failed_replay_stays_failure (test_pi_subagents.PiSubagentsTests.test_failed_replay_stays_failure) ... ok +test_forged_lease_env_refused (test_pi_subagents.PiSubagentsTests.test_forged_lease_env_refused) ... ok +test_global_concurrency_limit (test_pi_subagents.PiSubagentsTests.test_global_concurrency_limit) ... ok +test_idempotent_replay_and_digest_mismatch (test_pi_subagents.PiSubagentsTests.test_idempotent_replay_and_digest_mismatch) ... ok +test_input_path_traversal_symlink_secret_refusal (test_pi_subagents.PiSubagentsTests.test_input_path_traversal_symlink_secret_refusal) ... ok +test_leader_exit_reaps_orphan_child (test_pi_subagents.PiSubagentsTests.test_leader_exit_reaps_orphan_child) ... ok +test_malformed_and_empty_outputs_fail (test_pi_subagents.PiSubagentsTests.test_malformed_and_empty_outputs_fail) ... ok +test_mcp_from_worktree_uses_main_agentctl (test_pi_subagents.PiSubagentsTests.test_mcp_from_worktree_uses_main_agentctl) +Server INSTALL_ROOT may be a linked worktree; agentctl must resolve from main. ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_mcp_initialize_list_run_result (test_pi_subagents.PiSubagentsTests.test_mcp_initialize_list_run_result) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_mcp_running_poll_is_not_error (test_pi_subagents.PiSubagentsTests.test_mcp_running_poll_is_not_error) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_mcp_surfaces_role_disabled_and_scope_refusal (test_pi_subagents.PiSubagentsTests.test_mcp_surfaces_role_disabled_and_scope_refusal) ... /home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=10 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=6 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=8 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=7 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=4 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +/home/linuxbrew/.linuxbrew/Cellar/python@3.14/3.14.7/lib/python3.14/unittest/case.py:615: ResourceWarning: unclosed file <_io.TextIOWrapper name=5 encoding='UTF-8'> + result = method() +ResourceWarning: Enable tracemalloc to get the object allocation traceback +ok +test_model_mismatch_fails (test_pi_subagents.PiSubagentsTests.test_model_mismatch_fails) ... ok +test_naked_run_without_lease_refused (test_pi_subagents.PiSubagentsTests.test_naked_run_without_lease_refused) ... ok +test_orphan_result_is_readonly (test_pi_subagents.PiSubagentsTests.test_orphan_result_is_readonly) ... ok +test_output_cap_on_stdout_flood (test_pi_subagents.PiSubagentsTests.test_output_cap_on_stdout_flood) ... ok +test_readonly_guard_allows_exact_root_listing (test_pi_subagents.PiSubagentsTests.test_readonly_guard_allows_exact_root_listing) +Exact-root ls/grep must pass when snapshot inventory is allowlisted-only. ... ok +test_readonly_guard_rejects_at_prefix (test_pi_subagents.PiSubagentsTests.test_readonly_guard_rejects_at_prefix) +Exercise extension path policy via Node strip-types if available. ... ok +test_replay_keeps_old_config_after_disable (test_pi_subagents.PiSubagentsTests.test_replay_keeps_old_config_after_disable) ... ok +test_roles_does_not_invoke_pi (test_pi_subagents.PiSubagentsTests.test_roles_does_not_invoke_pi) ... ok +test_run_emits_exact_pi_flags_and_receipt (test_pi_subagents.PiSubagentsTests.test_run_emits_exact_pi_flags_and_receipt) ... ok +test_scope_refusal_outside_report_path (test_pi_subagents.PiSubagentsTests.test_scope_refusal_outside_report_path) ... ok +test_scrub_env_drops_pi_dir_for_tests (test_pi_subagents.PiSubagentsTests.test_scrub_env_drops_pi_dir_for_tests) ... ok +test_source_sha_rejects_symbolic_refs (test_pi_subagents.PiSubagentsTests.test_source_sha_rejects_symbolic_refs) ... ok +test_test_run_requires_approved_commands_and_records_failure (test_pi_subagents.PiSubagentsTests.test_test_run_requires_approved_commands_and_records_failure) ... ok +test_timeout_kills_process_group (test_pi_subagents.PiSubagentsTests.test_timeout_kills_process_group) ... ok + +---------------------------------------------------------------------- +Ran 173 tests in 111.229s + +OK diff --git a/.doc/test-reports/assets/pi-executor-2026-09-24/guard-review.json b/.doc/test-reports/assets/pi-executor-2026-09-24/guard-review.json new file mode 100644 index 00000000..40ca3789 --- /dev/null +++ b/.doc/test-reports/assets/pi-executor-2026-09-24/guard-review.json @@ -0,0 +1,10 @@ +{ + "exit_code": 0, + "provider": "zai-coding-cn", + "model": "glm-5.3", + "stopReason": "stop", + "settled": true, + "seconds": 67.6, + "source_sha256": "b1743d0f632c0719d56a39214a419163c195ed11ef53b16d48015ad6dd794ae3", + "review": "## 审查结论:发现 3 项可实际触发的缺陷\n\n### 1. 祖先目录规则使 grep/find 递归读取白名单之外的文件\n\n`allowlistOk()` 中:当 `resolved` 是目录且是某个白名单文件的祖先(`rel.startsWith(f + path.sep)` 分支)时直接放行。但 guard 并不区分工具类型——对 `grep`/`find` 这类递归工具,传入白名单文件的任一祖先目录(包括 snapshot root 本身)即满足该条件,工具会递归扫描目录下**所有**文件,包括未列入 `PI_SUBAGENT_ALLOWED_FILES` 的文件。\n\n**触发**:白名单为 `[\"sub/a.txt\"]`,调用 `grep { pattern: \"secret\", path: \"\" }`(或 `path: \"sub\"`)。`allowlistOk` 因 root 是 `sub/a.txt` 的祖先目录而返回 true,grep 读取整个快照内全部文件内容。\n\n### 2. 未提供路径时完全跳过白名单检查\n\n`paths.length === 0` 分支只检查 `process.cwd()` 是否在 root 内,通过即直接 `return undefined`,`allowlistOk` 从未被调用。依赖默认 cwd 的 `grep`/`find`/`ls` 调用因此绕过白名单。\n\n**触发**:设置 `PI_SUBAGENT_ALLOWED_FILES=[\"a.txt\"]`,进程 cwd 位于 snapshot root 内,调用 `grep { pattern: \"x\" }`(无 path 字段)。guard 仅验证 cwd 在 root 内即放行,grep 递归扫描 cwd 下所有文件(如 `b.txt`、`.env` 以外的任意敏感文件),白名单被完全绕过。(且此分支连 `.env`/`.git` 的 basename 黑名单也不执行。)\n\n### 3. 相对路径按 root 校验、但按 cwd 解析,且 `paths` 数组从不回写\n\n- `contained()` 对相对路径用 `path.resolve(root, candidate)` 校验;\n- 但回写(canonicalize)只覆盖 `path/file/filename/directory/dir` 五个单值键,`paths` 数组、`root`、`cwd` 键只校验不回写;\n- 给出路径时 guard 从不检查 `process.cwd()` 是否在 root 内。\n\n因此对 `paths` 数组中的相对条目(或 `root`/`cwd` 键),guard 验证的是「相对 root」的路径,而下游工具按 pi 的 resolveToCwd 语义相对实际 cwd 打开——校验对象与实际打开对象可以是两个不同文件。\n\n**触发**:`PI_SUBAGENT_SNAPSHOT_ROOT=/tmp/snap`,进程 cwd 为 `/home/user`(root 外)。`/tmp/snap/notes.txt` 在白名单中,同时 `/home/user/notes.txt` 是要窃读的目标。调用 `grep { pattern: \".\", paths: [\"notes.txt\"] }`:guard 校验通过 `/tmp/snap/notes.txt`(存在、在白名单),但 `paths` 未回写,builtin 相对 cwd 打开 `/home/user/notes.txt`——快照与白名单之外的内容被读取。\n\n(次要相关点:即便单值键,也只有 `input.path === p` 精确相等才回写,若输入含前后空白,校验与回写也会脱节,属同一缺陷族的变体。)" +} \ No newline at end of file diff --git a/.doc/test-reports/assets/pi-executor-2026-09-24/live-mcp.json b/.doc/test-reports/assets/pi-executor-2026-09-24/live-mcp.json new file mode 100644 index 00000000..b5a80fc7 --- /dev/null +++ b/.doc/test-reports/assets/pi-executor-2026-09-24/live-mcp.json @@ -0,0 +1,152 @@ +{ + "initialize": "PASS", + "tools": 3, + "cases": [ + { + "request_id": "real-mcp-research-02", + "role_id": "research", + "run_status": "succeeded", + "verdict": "not_applicable", + "review_state": "pending", + "configured_provider": "qwen-token-plan-cn", + "configured_model": "qwen3.8-flash", + "observed_provider": "qwen-token-plan-cn", + "observed_model": "qwen3.8-flash", + "tool_calls": [ + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_end" + } + ], + "isError": false + }, + { + "request_id": "real-mcp-test-01", + "role_id": "test_run", + "run_status": "succeeded", + "verdict": "pass", + "review_state": "commands_passed", + "configured_provider": "zai-coding-cn", + "configured_model": "glm-5.3-flash", + "observed_provider": "zai-coding-cn", + "observed_model": "glm-5.3-flash", + "tool_calls": [ + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "read", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "read", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_end" + } + ], + "test_outcomes": [ + { + "argv": [ + "python3", + "-c", + "import os,pathlib; assert pathlib.Path('PROJECT.md').is_file(); assert 'AGENTCTL_RUN_ID' not in os.environ; assert 'PI_CODING_AGENT_DIR' not in os.environ; print('PI_ISOLATED_TEST_PASS')" + ], + "cwd": "/tmp/pi-subagent-test-snap-t52sfrdr", + "duration_seconds": 0.086, + "exit_code": 0, + "status": "ok", + "stderr_path": "command-evidence/00-stderr.txt", + "stderr_preview": "", + "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "stdout_path": "command-evidence/00-stdout.txt", + "stdout_preview": "PI_ISOLATED_TEST_PASS\n", + "stdout_sha256": "960dc8f2b47ab4a6214cc9358d79fcd36909f181034664405bc5440d7420b7ec" + } + ], + "isError": false + }, + { + "request_id": "real-mcp-plan-01", + "role_id": "planning", + "run_status": "succeeded", + "verdict": "not_applicable", + "review_state": "pending", + "configured_provider": "qwen-token-plan-cn", + "configured_model": "qwen3.8-max", + "observed_provider": "qwen-token-plan-cn", + "observed_model": "qwen3.8-max", + "tool_calls": [ + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "find", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "find", + "type": "tool_execution_end" + } + ], + "isError": false + }, + { + "code": "ROLE_DISABLED", + "request_id": "real-mcp-disabled-01", + "isError": true + } + ] +} \ No newline at end of file diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/receipt.json b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/receipt.json new file mode 100644 index 00000000..94974837 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/receipt.json @@ -0,0 +1,83 @@ +{ + "approved_commands_sha256": null, + "authorization_ref": "user requested automatic PI executor isolated acceptance", + "config_revision": "subagent-models-2026-09-24-r1", + "config_sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0", + "configured_alias": "qwen_flash", + "configured_model": "qwen3.8-flash", + "configured_provider": "qwen-token-plan-cn", + "errors": [], + "final_text": "## Result\n\n**ls on snapshot root: blocked.** Every enumeration call returned `directory contains non-allowlisted file`:\n- `ls .` → blocked\n- `ls /tmp/pi-subagent-snap-t4436jt2` → blocked\n- `find * -path /tmp/pi-subagent-snap-t4436jt2` → blocked\n\nSo I could not get a ground-truth directory listing of the snapshot. Single-file reads do work (`PROJECT.md` was read successfully). Notably, the only evidence in the packet is `PROJECT.md` itself — no `AGENTS.md`, `.doc/*`, `cmd/`, `web/`, etc. were provided, and I did not attempt to fetch files outside the allowlist.\n\n**Two repository directories** (from the `PROJECT.md` 仓库地图 table, i.e. documented rather than filesystem-verified):\n\n| 路径 | 用途 |\n|---|---|\n| `cmd/`、`internal/` | 服务入口与 Go 模块 |\n| `web/` | React/Vite 前端 |\n\n**Caveats / scope notes:**\n- The directory names above are *claims from PROJECT.md*, not confirmed to exist in this snapshot — the read-only probe was blocked, so they are unverified.\n- PROJECT.md references credentials at `${HOME}/.secrets/gitea` (`ACCESS_TOKEN`, `URL_PREFIX`). That is outside the snapshot and is a secret store: I did not read, list, or reference it, and the caller goal did not authorize doing so.\n- `PROJECT.md` is only an entry-point doc; it explicitly says it does not cache \"no blocker\" status or current schema, and that env topology (ports 8080/8081/8000/5432-5435, compose names) is convention only, to be verified against target-environment receipts. Any follow-up wanting authoritative state would need `.doc/ops/CURRENT.md`, `.doc/status/FEATURE-MATRIX.md`, `.doc/remediation/gap-matrix.md` — none of which are in this packet.\n- No modifications made; nothing beyond the snapshot was accessed.\n\nCURSOR_PI_AUTOMATION_OK", + "finished_at": 1790222226.6835754, + "goal": "use ls for current snapshot and read PROJECT.md, report two repository directories, finish CURSOR_PI_AUTOMATION_OK", + "input_files": [ + { + "bytes": 4183, + "path": "PROJECT.md", + "sha256": "91d148876a9457e646b8adab69670a1a85ac7d067268568ff8db084c0c0801d8" + } + ], + "observed_model": "qwen3.8-flash", + "observed_provider": "qwen-token-plan-cn", + "ok": true, + "pi_exit_code": 0, + "plan_digest": null, + "request_digest": "7c7b17d5183cf0fc0dd149cbd9ddcead76e1f78532c8ada9d69d517a16b47c3a", + "request_id": "cursor-auto-research-01", + "retry_disabled": true, + "review_state": "pending", + "role_id": "research", + "run_status": "succeeded", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "started_at": 1790222209.62396, + "stderr_preview": "", + "stream_error": null, + "supervisor_boot_id": "a37fa29f-4cbd-4c8a-89d2-d5d31b20615b", + "supervisor_pgid": 2834994, + "supervisor_pid": 2834994, + "supervisor_start": "109360920", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "tool_calls": [ + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "find", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "find", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_end" + } + ], + "verdict": "not_applicable" +} diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/report.md b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/report.md new file mode 100644 index 00000000..b36750e1 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-01/report.md @@ -0,0 +1,44 @@ +# PI subagent report — `cursor-auto-research-01` + +- task_id: `subagent-workflow-standard-2026-09-24-executor` +- role_id: `research` +- run_status: `succeeded` +- verdict: `not_applicable` +- config_revision: `subagent-models-2026-09-24-r1` +- config_sha256: `0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0` +- source_sha: `52462b45e985f596b2a503fc70ac12c3bd5fe571` +- configured: `qwen-token-plan-cn/qwen3.8-flash` +- observed: `qwen-token-plan-cn/qwen3.8-flash` + +## Goal + +use ls for current snapshot and read PROJECT.md, report two repository directories, finish CURSOR_PI_AUTOMATION_OK + +## Model output + +## Result + +**ls on snapshot root: blocked.** Every enumeration call returned `directory contains non-allowlisted file`: +- `ls .` → blocked +- `ls /tmp/pi-subagent-snap-t4436jt2` → blocked +- `find * -path /tmp/pi-subagent-snap-t4436jt2` → blocked + +So I could not get a ground-truth directory listing of the snapshot. Single-file reads do work (`PROJECT.md` was read successfully). Notably, the only evidence in the packet is `PROJECT.md` itself — no `AGENTS.md`, `.doc/*`, `cmd/`, `web/`, etc. were provided, and I did not attempt to fetch files outside the allowlist. + +**Two repository directories** (from the `PROJECT.md` 仓库地图 table, i.e. documented rather than filesystem-verified): + +| 路径 | 用途 | +|---|---| +| `cmd/`、`internal/` | 服务入口与 Go 模块 | +| `web/` | React/Vite 前端 | + +**Caveats / scope notes:** +- The directory names above are *claims from PROJECT.md*, not confirmed to exist in this snapshot — the read-only probe was blocked, so they are unverified. +- PROJECT.md references credentials at `${HOME}/.secrets/gitea` (`ACCESS_TOKEN`, `URL_PREFIX`). That is outside the snapshot and is a secret store: I did not read, list, or reference it, and the caller goal did not authorize doing so. +- `PROJECT.md` is only an entry-point doc; it explicitly says it does not cache "no blocker" status or current schema, and that env topology (ports 8080/8081/8000/5432-5435, compose names) is convention only, to be verified against target-environment receipts. Any follow-up wanting authoritative state would need `.doc/ops/CURRENT.md`, `.doc/status/FEATURE-MATRIX.md`, `.doc/remediation/gap-matrix.md` — none of which are in this packet. +- No modifications made; nothing beyond the snapshot was accessed. + +CURSOR_PI_AUTOMATION_OK + + +_Note: model narrative is not an approved review verdict; run_status and verdict are separate._ diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/receipt.json b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/receipt.json new file mode 100644 index 00000000..8d7f47ad --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/receipt.json @@ -0,0 +1,63 @@ +{ + "approved_commands_sha256": null, + "authorization_ref": "user requested PI executor isolated acceptance", + "config_revision": "subagent-models-2026-09-24-r1", + "config_sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0", + "configured_alias": "qwen_flash", + "configured_model": "qwen3.8-flash", + "configured_provider": "qwen-token-plan-cn", + "errors": [], + "final_text": "**Tool results (truthful report):**\n\n1. `ls(path='.')` — **succeeded**. Output: `PROJECT.md`. Confirms the snapshot contains PROJECT.md (and no other entries).\n2. `read(path='PROJECT.md')` — **succeeded**. Content is verbatim identical to the evidence packet (no discrepancies observed). No `.git`, `.env`, or out-of-snapshot paths were accessed; no tool failures occurred.\n\n**Two directory names from the repository map (仓库地图):**\n\n- \"`cmd/`、`internal/` | 服务入口与 Go 模块\" → **`cmd/`**\n- \"`web/` | React/Vite 前端\" → **`web/`**\n\nCURSOR_PI_AUTOMATION_OK", + "finished_at": 1790222752.7294602, + "goal": "call ls(path='.') and confirm the snapshot contains PROJECT.md; call read on PROJECT.md; quote two directory names declared in its repository map; finish CURSOR_PI_AUTOMATION_OK. Report any tool failure truthfully; do not call failed ls/read success.", + "input_files": [ + { + "bytes": 4183, + "path": "PROJECT.md", + "sha256": "91d148876a9457e646b8adab69670a1a85ac7d067268568ff8db084c0c0801d8" + } + ], + "observed_model": "qwen3.8-flash", + "observed_provider": "qwen-token-plan-cn", + "ok": true, + "pi_exit_code": 0, + "plan_digest": null, + "request_digest": "a83155fc059c23e884be38339c8e442f71d30e49e913966848289ae7d4d107eb", + "request_id": "cursor-auto-research-02", + "retry_disabled": true, + "review_state": "pending", + "role_id": "research", + "run_status": "succeeded", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "started_at": 1790222746.4985802, + "stderr_preview": "", + "stream_error": null, + "supervisor_boot_id": "a37fa29f-4cbd-4c8a-89d2-d5d31b20615b", + "supervisor_pgid": 2883592, + "supervisor_pid": 2883592, + "supervisor_start": "109414606", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "tool_calls": [ + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_end" + } + ], + "verdict": "not_applicable" +} diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/report.md b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/report.md new file mode 100644 index 00000000..62197da2 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/cursor-auto-research-02/report.md @@ -0,0 +1,32 @@ +# PI subagent report — `cursor-auto-research-02` + +- task_id: `subagent-workflow-standard-2026-09-24-executor` +- role_id: `research` +- run_status: `succeeded` +- verdict: `not_applicable` +- config_revision: `subagent-models-2026-09-24-r1` +- config_sha256: `0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0` +- source_sha: `52462b45e985f596b2a503fc70ac12c3bd5fe571` +- configured: `qwen-token-plan-cn/qwen3.8-flash` +- observed: `qwen-token-plan-cn/qwen3.8-flash` + +## Goal + +call ls(path='.') and confirm the snapshot contains PROJECT.md; call read on PROJECT.md; quote two directory names declared in its repository map; finish CURSOR_PI_AUTOMATION_OK. Report any tool failure truthfully; do not call failed ls/read success. + +## Model output + +**Tool results (truthful report):** + +1. `ls(path='.')` — **succeeded**. Output: `PROJECT.md`. Confirms the snapshot contains PROJECT.md (and no other entries). +2. `read(path='PROJECT.md')` — **succeeded**. Content is verbatim identical to the evidence packet (no discrepancies observed). No `.git`, `.env`, or out-of-snapshot paths were accessed; no tool failures occurred. + +**Two directory names from the repository map (仓库地图):** + +- "`cmd/`、`internal/` | 服务入口与 Go 模块" → **`cmd/`** +- "`web/` | React/Vite 前端" → **`web/`** + +CURSOR_PI_AUTOMATION_OK + + +_Note: model narrative is not an approved review verdict; run_status and verdict are separate._ diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/receipt.json b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/receipt.json new file mode 100644 index 00000000..aebf7d50 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/receipt.json @@ -0,0 +1,63 @@ +{ + "approved_commands_sha256": null, + "authorization_ref": "user:接入自动调用pi的执行器; isolated engineering acceptance", + "config_revision": "subagent-models-2026-09-24-r1", + "config_sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0", + "configured_alias": "qwen_max", + "configured_model": "qwen3.8-max", + "configured_provider": "qwen-token-plan-cn", + "errors": [], + "final_text": "快照目录不可列举,以下仅依据证据包中提供的 `.doc/ops/2026-09-24-subagent-model-config.md`(config_revision `subagent-models-2026-09-24-r1`)内容整理。\n\n## 1. Cursor 职责\n\n- **代码实施与修复固定由 Cursor Auto 承担**(§2 模型池说明 + §3 表头前置说明 + §4 `implementation_executor = cursor_auto`)。\n- §3 角色路由表**只路由 PI 子任务**;PI 不修改产品代码或测试源码,所需修复/新增测试一律**交回 Cursor**。\n- 主会话为 Cursor(模型选择 Auto),工程子任务为本机 gmktec PI CLI;该配置不改变 Cursor UI 模型开关、PI 全局默认设置或产品 PI Agent Runner。\n- 修改 `implementation_executor` 这一边界**需要用户明确授权**。\n\n## 2. M3 限制(alias `minimax_aux`,provider `minimax-cn`,model `MiniMax-M3`)\n\n- **默认停用**:§3 中 `auxiliary` 角色 `enabled = false`,仅在明确启用后才派发;false 时不自动派发,必需职责暂停或显式重新分配,**不能跳过门禁**。\n- **只能用于易核验辅助任务**(格式整理、清单提取等),且**不能承担关键判断**;派发后需保留来源供核验。\n- **不得进入**:规划、代码审查、根因裁决、最终验收,以及**主力自动备用链**。\n- §4 `automatic_fallback = none`:**不因超时或故障降级到 M3**,也不静默换模型/换 provider;`unavailable_action = pause_role`。\n- 初始决策依据记录为“M3 能力有限 → 移出默认流程、仅可选辅助”;改变这些限制须由**用户明确修订 §2**。\n\n## 3. Flash 升级规则\n\n**两个 Flash 角色的升级去向(§3 “升级角色”列):**\n\n| 角色 | 默认模型 | 升级角色 |\n|---|---|---|\n| research | qwen_flash | planning(qwen_max) |\n| test_run | glm_flash | diagnosis(glm_full) |\n| acceptance_check | glm_flash | diagnosis(glm_full) |\n| stage_notes | qwen_flash | report(qwen_max) |\n\n**触发条件(§4 升级触发):**\n- Flash 无法解释失败;\n- 证据互相矛盾;\n- 涉及跨模块机制;\n- 超出已批准验证计划。\n\n**规则约束:**\n- 升级**只用于质量不足,不是网络故障重试**;结果未知时先核对副作用,流程遵循协作规范。\n- 升级时**保留原报告与升级原因**,以目标角色重新派发(§1)。\n- 字段规则:升级角色引用 §3 的 `role_id` 或 `none`;出现**缺字段、未知 alias、循环升级、角色越权**时**停止该派发并报告错误,不自行猜测模型**。\n- 边界不因升级而放宽:`test_run` 仅执行已批准命令/测试产物/环境,不改源码,复现操作由其在授权环境执行,`diagnosis` 只做只读分析;`acceptance_check` **不代签最终验收**,业务取舍交 `acceptance_owner`,最终验收责任仍归任务声明的 acceptance_owner。\n- `reload_boundary = next_dispatch`、`recursive_delegation = false`:升级派发在下一次派发时读取配置,PI 子任务不得自行再派发,需要协作者时只返回建议。\n\nMODEL_PLAN_OK", + "finished_at": 1790221229.1172304, + "goal": "根据配置只列出 Cursor 职责、M3 限制、Flash 升级规则三点,最后输出 MODEL_PLAN_OK。不要评价执行器是否已经实现。", + "input_files": [ + { + "bytes": 7876, + "path": ".doc/ops/2026-09-24-subagent-model-config.md", + "sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0" + } + ], + "observed_model": "qwen3.8-max", + "observed_provider": "qwen-token-plan-cn", + "ok": true, + "pi_exit_code": 0, + "plan_digest": null, + "request_digest": "5a5ce640778270c8f3cd718ac665f85d9e118096455cd893928dd26fc0c74b0e", + "request_id": "real-mcp-plan-01", + "retry_disabled": true, + "review_state": "pending", + "role_id": "planning", + "run_status": "succeeded", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "started_at": 1790221203.9798584, + "stderr_preview": "", + "stream_error": null, + "supervisor_boot_id": "a37fa29f-4cbd-4c8a-89d2-d5d31b20615b", + "supervisor_pgid": 2750675, + "supervisor_pid": 2750675, + "supervisor_start": "109260353", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "tool_calls": [ + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "find", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "find", + "type": "tool_execution_end" + } + ], + "verdict": "not_applicable" +} diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/report.md b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/report.md new file mode 100644 index 00000000..368e1ca0 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-plan-01/report.md @@ -0,0 +1,63 @@ +# PI subagent report — `real-mcp-plan-01` + +- task_id: `subagent-workflow-standard-2026-09-24-executor` +- role_id: `planning` +- run_status: `succeeded` +- verdict: `not_applicable` +- config_revision: `subagent-models-2026-09-24-r1` +- config_sha256: `0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0` +- source_sha: `52462b45e985f596b2a503fc70ac12c3bd5fe571` +- configured: `qwen-token-plan-cn/qwen3.8-max` +- observed: `qwen-token-plan-cn/qwen3.8-max` + +## Goal + +根据配置只列出 Cursor 职责、M3 限制、Flash 升级规则三点,最后输出 MODEL_PLAN_OK。不要评价执行器是否已经实现。 + +## Model output + +快照目录不可列举,以下仅依据证据包中提供的 `.doc/ops/2026-09-24-subagent-model-config.md`(config_revision `subagent-models-2026-09-24-r1`)内容整理。 + +## 1. Cursor 职责 + +- **代码实施与修复固定由 Cursor Auto 承担**(§2 模型池说明 + §3 表头前置说明 + §4 `implementation_executor = cursor_auto`)。 +- §3 角色路由表**只路由 PI 子任务**;PI 不修改产品代码或测试源码,所需修复/新增测试一律**交回 Cursor**。 +- 主会话为 Cursor(模型选择 Auto),工程子任务为本机 gmktec PI CLI;该配置不改变 Cursor UI 模型开关、PI 全局默认设置或产品 PI Agent Runner。 +- 修改 `implementation_executor` 这一边界**需要用户明确授权**。 + +## 2. M3 限制(alias `minimax_aux`,provider `minimax-cn`,model `MiniMax-M3`) + +- **默认停用**:§3 中 `auxiliary` 角色 `enabled = false`,仅在明确启用后才派发;false 时不自动派发,必需职责暂停或显式重新分配,**不能跳过门禁**。 +- **只能用于易核验辅助任务**(格式整理、清单提取等),且**不能承担关键判断**;派发后需保留来源供核验。 +- **不得进入**:规划、代码审查、根因裁决、最终验收,以及**主力自动备用链**。 +- §4 `automatic_fallback = none`:**不因超时或故障降级到 M3**,也不静默换模型/换 provider;`unavailable_action = pause_role`。 +- 初始决策依据记录为“M3 能力有限 → 移出默认流程、仅可选辅助”;改变这些限制须由**用户明确修订 §2**。 + +## 3. Flash 升级规则 + +**两个 Flash 角色的升级去向(§3 “升级角色”列):** + +| 角色 | 默认模型 | 升级角色 | +|---|---|---| +| research | qwen_flash | planning(qwen_max) | +| test_run | glm_flash | diagnosis(glm_full) | +| acceptance_check | glm_flash | diagnosis(glm_full) | +| stage_notes | qwen_flash | report(qwen_max) | + +**触发条件(§4 升级触发):** +- Flash 无法解释失败; +- 证据互相矛盾; +- 涉及跨模块机制; +- 超出已批准验证计划。 + +**规则约束:** +- 升级**只用于质量不足,不是网络故障重试**;结果未知时先核对副作用,流程遵循协作规范。 +- 升级时**保留原报告与升级原因**,以目标角色重新派发(§1)。 +- 字段规则:升级角色引用 §3 的 `role_id` 或 `none`;出现**缺字段、未知 alias、循环升级、角色越权**时**停止该派发并报告错误,不自行猜测模型**。 +- 边界不因升级而放宽:`test_run` 仅执行已批准命令/测试产物/环境,不改源码,复现操作由其在授权环境执行,`diagnosis` 只做只读分析;`acceptance_check` **不代签最终验收**,业务取舍交 `acceptance_owner`,最终验收责任仍归任务声明的 acceptance_owner。 +- `reload_boundary = next_dispatch`、`recursive_delegation = false`:升级派发在下一次派发时读取配置,PI 子任务不得自行再派发,需要协作者时只返回建议。 + +MODEL_PLAN_OK + + +_Note: model narrative is not an approved review verdict; run_status and verdict are separate._ diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/receipt.json b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/receipt.json new file mode 100644 index 00000000..93bcfefa --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/receipt.json @@ -0,0 +1,63 @@ +{ + "approved_commands_sha256": null, + "authorization_ref": "user:接入自动调用pi的执行器; isolated engineering acceptance", + "config_revision": "subagent-models-2026-09-24-r1", + "config_sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0", + "configured_alias": "qwen_flash", + "configured_model": "qwen3.8-flash", + "configured_provider": "qwen-token-plan-cn", + "errors": [], + "final_text": "已读取快照文件 `PROJECT.md`(仅读取该文件,未访问 `.env`/`.git`/凭证或快照外路径)。\n\n**两个仓库目录名(来自「仓库地图」):**\n1. `cmd/` — 服务入口(Go)\n2. `web/` — React/Vite 前端\n\nPI_EXECUTOR_REAL_OK", + "finished_at": 1790221154.765425, + "goal": "Call read on PROJECT.md; report two repository directory names and finish PI_EXECUTOR_REAL_OK.", + "input_files": [ + { + "bytes": 4183, + "path": "PROJECT.md", + "sha256": "91d148876a9457e646b8adab69670a1a85ac7d067268568ff8db084c0c0801d8" + } + ], + "observed_model": "qwen3.8-flash", + "observed_provider": "qwen-token-plan-cn", + "ok": true, + "pi_exit_code": 0, + "plan_digest": null, + "request_digest": "5752326f01bedcee6832987ebf723cbf14334fee3bb82dda1238e5be5b4b5be1", + "request_id": "real-mcp-research-02", + "retry_disabled": true, + "review_state": "pending", + "role_id": "research", + "run_status": "succeeded", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "started_at": 1790221148.1277544, + "stderr_preview": "", + "stream_error": null, + "supervisor_boot_id": "a37fa29f-4cbd-4c8a-89d2-d5d31b20615b", + "supervisor_pgid": 2740655, + "supervisor_pid": 2740655, + "supervisor_start": "109254769", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "tool_calls": [ + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_end" + } + ], + "verdict": "not_applicable" +} diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/report.md b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/report.md new file mode 100644 index 00000000..d62bee9a --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-research-02/report.md @@ -0,0 +1,28 @@ +# PI subagent report — `real-mcp-research-02` + +- task_id: `subagent-workflow-standard-2026-09-24-executor` +- role_id: `research` +- run_status: `succeeded` +- verdict: `not_applicable` +- config_revision: `subagent-models-2026-09-24-r1` +- config_sha256: `0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0` +- source_sha: `52462b45e985f596b2a503fc70ac12c3bd5fe571` +- configured: `qwen-token-plan-cn/qwen3.8-flash` +- observed: `qwen-token-plan-cn/qwen3.8-flash` + +## Goal + +Call read on PROJECT.md; report two repository directory names and finish PI_EXECUTOR_REAL_OK. + +## Model output + +已读取快照文件 `PROJECT.md`(仅读取该文件,未访问 `.env`/`.git`/凭证或快照外路径)。 + +**两个仓库目录名(来自「仓库地图」):** +1. `cmd/` — 服务入口(Go) +2. `web/` — React/Vite 前端 + +PI_EXECUTOR_REAL_OK + + +_Note: model narrative is not an approved review verdict; run_status and verdict are separate._ diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stderr.txt b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stderr.txt new file mode 100644 index 00000000..e69de29b diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stdout.txt b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stdout.txt new file mode 100644 index 00000000..103f43a5 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/command-evidence/00-stdout.txt @@ -0,0 +1 @@ +PI_ISOLATED_TEST_PASS diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/receipt.json b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/receipt.json new file mode 100644 index 00000000..c2743bed --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/receipt.json @@ -0,0 +1,102 @@ +{ + "approved_commands_sha256": "73d15c48485e02f893dd6cac36b04f8cb3dfd63d166849f2369dbd5c5c4748f6", + "authorization_ref": "user:接入自动调用pi的执行器; isolated engineering acceptance", + "config_revision": "subagent-models-2026-09-24-r1", + "config_sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0", + "configured_alias": "glm_flash", + "configured_model": "glm-5.3-flash", + "configured_provider": "zai-coding-cn", + "errors": [], + "final_text": "## Analysis of approved command output\n\n**Was `PI_ISOLATED_TEST_PASS` printed? — Yes.**\n\nPer the authoritative evidence packet (single approved command, `status: \"ok\"`, `exit_code: 0`):\n\n- `stdout_preview` is exactly `PI_ISOLATED_TEST_PASS\\n` — the marker was printed.\n- `exit_code: 0` is consistent with the command's logic: all three asserts passed (`PROJECT.md` is a file; `AGENTCTL_RUN_ID` and `PI_CODING_AGENT_DIR` are absent from the environment), so the final `print()` executed.\n- `stderr_sha256` (`e3b0c442...b855`) is the well-known SHA-256 of the empty string, matching the empty `stderr_preview` — no error output.\n- `duration_seconds: 0.086` is plausible for a one-shot `python3 -c` run.\n\n### Verification notes (from this snapshot, read-only)\n\n- `PROJECT.md` in this snapshot (`/tmp/pi-subagent-snap-a1uvxn50`) matches the packet's content, consistent with the assert that it exists as a file.\n- The `command-evidence/00-stdout.txt` / `00-stderr.txt` artifacts referenced by `stdout_path`/`stderr_path` are **not present** in this snapshot, and the command's `cwd` was `/tmp/pi-subagent-test-snap-t52sfrdr` (a different snapshot directory than this one). So corroboration rests on the packet's preview and recorded hashes, which are declared authoritative; I cannot independently re-hash them here.\n\n### Scope caveat\n\nThis marker evidences only that the **isolation/environment precondition check** passed (snapshot file present; the two orchestrator env vars absent). It is **not** evidence that any product tests (Go, frontend, or real PI Agent Runner workflow acceptance) were run or passed.", + "finished_at": 1790221203.5930333, + "goal": "Analyze only the approved command output. State whether PI_ISOLATED_TEST_PASS was printed. Do not infer product tests passed.", + "input_files": [ + { + "bytes": 4183, + "path": "PROJECT.md", + "sha256": "91d148876a9457e646b8adab69670a1a85ac7d067268568ff8db084c0c0801d8" + } + ], + "observed_model": "glm-5.3-flash", + "observed_provider": "zai-coding-cn", + "ok": true, + "pi_exit_code": 0, + "plan_digest": "63e5a1fa27f2cf9f8b905531a3ab17f852d1f4000361d65b14a472ad24dc920b", + "request_digest": "37c2925cf846df8ad240371be4c994b8be4c68cbf442620d8ac59ab33d51cbb9", + "request_id": "real-mcp-test-01", + "retry_disabled": true, + "review_state": "commands_passed", + "role_id": "test_run", + "run_status": "succeeded", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "started_at": 1790221155.0332568, + "stderr_preview": "", + "stream_error": null, + "supervisor_boot_id": "a37fa29f-4cbd-4c8a-89d2-d5d31b20615b", + "supervisor_pgid": 2742005, + "supervisor_pid": 2742005, + "supervisor_start": "109255459", + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "test_outcomes": [ + { + "argv": [ + "python3", + "-c", + "import os,pathlib; assert pathlib.Path('PROJECT.md').is_file(); assert 'AGENTCTL_RUN_ID' not in os.environ; assert 'PI_CODING_AGENT_DIR' not in os.environ; print('PI_ISOLATED_TEST_PASS')" + ], + "cwd": "/tmp/pi-subagent-test-snap-t52sfrdr", + "duration_seconds": 0.086, + "exit_code": 0, + "status": "ok", + "stderr_path": "command-evidence/00-stderr.txt", + "stderr_preview": "", + "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "stdout_path": "command-evidence/00-stdout.txt", + "stdout_preview": "PI_ISOLATED_TEST_PASS\n", + "stdout_sha256": "960dc8f2b47ab4a6214cc9358d79fcd36909f181034664405bc5440d7420b7ec" + } + ], + "tool_calls": [ + { + "isError": false, + "toolName": "ls", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "ls", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "read", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": true, + "toolName": "read", + "type": "tool_execution_end" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_start" + }, + { + "isError": false, + "toolName": "read", + "type": "tool_execution_end" + } + ], + "verdict": "pass" +} diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/report.md b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/report.md new file mode 100644 index 00000000..0518e4d7 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-mcp-test-01/report.md @@ -0,0 +1,44 @@ +# PI subagent report — `real-mcp-test-01` + +- task_id: `subagent-workflow-standard-2026-09-24-executor` +- role_id: `test_run` +- run_status: `succeeded` +- verdict: `pass` +- config_revision: `subagent-models-2026-09-24-r1` +- config_sha256: `0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0` +- source_sha: `52462b45e985f596b2a503fc70ac12c3bd5fe571` +- configured: `zai-coding-cn/glm-5.3-flash` +- observed: `zai-coding-cn/glm-5.3-flash` + +## Goal + +Analyze only the approved command output. State whether PI_ISOLATED_TEST_PASS was printed. Do not infer product tests passed. + +## Model output + +## Analysis of approved command output + +**Was `PI_ISOLATED_TEST_PASS` printed? — Yes.** + +Per the authoritative evidence packet (single approved command, `status: "ok"`, `exit_code: 0`): + +- `stdout_preview` is exactly `PI_ISOLATED_TEST_PASS\n` — the marker was printed. +- `exit_code: 0` is consistent with the command's logic: all three asserts passed (`PROJECT.md` is a file; `AGENTCTL_RUN_ID` and `PI_CODING_AGENT_DIR` are absent from the environment), so the final `print()` executed. +- `stderr_sha256` (`e3b0c442...b855`) is the well-known SHA-256 of the empty string, matching the empty `stderr_preview` — no error output. +- `duration_seconds: 0.086` is plausible for a one-shot `python3 -c` run. + +### Verification notes (from this snapshot, read-only) + +- `PROJECT.md` in this snapshot (`/tmp/pi-subagent-snap-a1uvxn50`) matches the packet's content, consistent with the assert that it exists as a file. +- The `command-evidence/00-stdout.txt` / `00-stderr.txt` artifacts referenced by `stdout_path`/`stderr_path` are **not present** in this snapshot, and the command's `cwd` was `/tmp/pi-subagent-test-snap-t52sfrdr` (a different snapshot directory than this one). So corroboration rests on the packet's preview and recorded hashes, which are declared authoritative; I cannot independently re-hash them here. + +### Scope caveat + +This marker evidences only that the **isolation/environment precondition check** passed (snapshot file present; the two orchestrator env vars absent). It is **not** evidence that any product tests (Go, frontend, or real PI Agent Runner workflow acceptance) were run or passed. + +## Approved test command outcomes + +- argv=`['python3', '-c', "import os,pathlib; assert pathlib.Path('PROJECT.md').is_file(); assert 'AGENTCTL_RUN_ID' not in os.environ; assert 'PI_CODING_AGENT_DIR' not in os.environ; print('PI_ISOLATED_TEST_PASS')"]` exit=0 status=ok + + +_Note: model narrative is not an approved review verdict; run_status and verdict are separate._ diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/receipt.json b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/receipt.json new file mode 100644 index 00000000..1a3f33c0 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/receipt.json @@ -0,0 +1,39 @@ +{ + "approved_commands_sha256": null, + "authorization_ref": "user:接入自动调用pi的执行器; bounded engineering smoke", + "config_revision": "subagent-models-2026-09-24-r1", + "config_sha256": "0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0", + "configured_alias": "qwen_flash", + "configured_model": "qwen3.8-flash", + "configured_provider": "qwen-token-plan-cn", + "errors": [], + "final_text": "Read `PROJECT.md` (read-only; no files written, no tests run or inferred).\n\nTwo repository directory names from the 仓库地图 in PROJECT.md:\n\n1. `cmd/` — 服务入口 (Go modules, together with `internal/`)\n2. `web/` — React/Vite 前端\n\nPI_EXECUTOR_REAL_OK", + "finished_at": 1790219576.5912876, + "goal": "Use the read tool on PROJECT.md, then provide two repository directory names and finish with PI_EXECUTOR_REAL_OK. Do not write files or infer test results.", + "input_files": [ + { + "bytes": 4183, + "path": "PROJECT.md", + "sha256": "91d148876a9457e646b8adab69670a1a85ac7d067268568ff8db084c0c0801d8" + } + ], + "observed_model": "qwen3.8-flash", + "observed_provider": "qwen-token-plan-cn", + "ok": true, + "pi_exit_code": 0, + "plan_digest": null, + "request_digest": "12939b982d796ab0c1e5c22b536474c505ddf3a4e925ce37fa551afeb86275ba", + "request_id": "real-research-01", + "retry_disabled": true, + "review_state": "pending", + "role_id": "research", + "run_status": "succeeded", + "source_sha": "52462b45e985f596b2a503fc70ac12c3bd5fe571", + "started_at": 1790219569.6384125, + "stderr_preview": "", + "stream_error": null, + "supervisor_boot_id": "a37fa29f-4cbd-4c8a-89d2-d5d31b20615b", + "supervisor_pid": 2588429, + "task_id": "subagent-workflow-standard-2026-09-24-executor", + "verdict": "not_applicable" +} diff --git a/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/report.md b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/report.md new file mode 100644 index 00000000..35c8c060 --- /dev/null +++ b/.doc/test-reports/assets/pi-subagents/subagent-workflow-standard-2026-09-24-executor/real-research-01/report.md @@ -0,0 +1,29 @@ +# PI subagent report — `real-research-01` + +- task_id: `subagent-workflow-standard-2026-09-24-executor` +- role_id: `research` +- run_status: `succeeded` +- verdict: `not_applicable` +- config_revision: `subagent-models-2026-09-24-r1` +- config_sha256: `0cd96bbdb6b4204dac32058989a3adaf176c5775a3d323353103cc23e2414ca0` +- source_sha: `52462b45e985f596b2a503fc70ac12c3bd5fe571` +- configured: `qwen-token-plan-cn/qwen3.8-flash` +- observed: `qwen-token-plan-cn/qwen3.8-flash` + +## Goal + +Use the read tool on PROJECT.md, then provide two repository directory names and finish with PI_EXECUTOR_REAL_OK. Do not write files or infer test results. + +## Model output + +Read `PROJECT.md` (read-only; no files written, no tests run or inferred). + +Two repository directory names from the 仓库地图 in PROJECT.md: + +1. `cmd/` — 服务入口 (Go modules, together with `internal/`) +2. `web/` — React/Vite 前端 + +PI_EXECUTOR_REAL_OK + + +_Note: model narrative is not an approved review verdict; run_status and verdict are separate._