octopus-rpa-app-runner 修复记录(第5轮)
原始文件:wecom_2146645b_octopus-rpa-app-runner_修复记录_第5轮.md
octopus-rpa-app-runner 修复记录(第5轮)
1. 范围与结论
本轮对照原始 PRD、需求 v2、技术方案 v2、第5轮质检报告与当前代码逐项复现。全程未调用真实 Octopus RPA,未枚举或操作真实 UI,未执行运行、停止、关闭或重启动作;验证仅限纯函数、mock、参数前置黑盒、编译与 PowerShell AST。
并发修改处置结论:保留公开 raw-argument launcher scripts/OctopusRpaAppRunner.ps1 与强类型实现 scripts/OctopusRpaAppRunner.impl.ps1 的拆分架构,不回滚。launcher 只负责原始参数扫描、动作推断、捕获 impl 参数绑定异常、生成 v2 单一结果并透传 impl 退出码;业务逻辑、参数校验和 UI 实现继续位于 impl。测试与 SKILL 文档继续明确引用 impl。
第5轮报告的 C-01/C-02/C-03、H-01/H-02/H-03/H-04、L-01 均采纳并修复。M-01 采纳并收敛文档口径;M-02 采纳为非阻断能力缺口,未虚构已实现的运行列表/进程启动证据;M-03 按技术方案 4.4 的明确 wrapper preflight 例外保留,并在 SKILL 中说明。
2. 逐项处理
| 质检项 | 处理结果 | 修复与证据 |
|---|---|---|
| C-01 restart 部分副作用低报 | 已修复 | Python dispatch() 和 PowerShell Restart-OctopusStudioClean 均在进入首个进程/UI副作用边界前标记 changed;异常携带 restart_attempted/effect_unknown。mock 失败注入断言 changed=true。 |
| C-02 mkdir 部分创建失败低报 | 已修复 | Python 与 PowerShell 均在 mkdir/New-Item 前标记副作用;Python稳定映射 DIRECTORY_CREATE_FAILED,记录路径指纹而非原值,并报告 directory_create_attempted/effect_unknown。 |
| C-03 PowerShell 宿主绑定错误绕过契约 | 已修复 | 公开 launcher 接收 $args,在 try 内调用强类型 impl。未知参数和整数转换失败均输出一次 v2 JSON/text、exit 3;impl 正常退出码由 $LASTEXITCODE 透传。修复了 launcher 扫描后又把 requestedAction 重置为 interactive 的并发残留,并补 -Output:json 识别。 |
| H-01 PowerShell 参数弹窗唯一性/TOCTOU | 已修复 | 正式路径统一使用 Get-RunParameterDialogCandidates/Get-SingleRunParameterDialogSnapshot;候选限定 Studio 进程、可见窗口、唯一 enabled 按钮和参数标识。确认/写入/提交前重枚举,比较 pid、handle、按钮和输入结构指纹;多候选阻断。 |
| H-02 Python disabled 按钮 | 已修复 | 候选、snapshot 和点击前均要求 enabled;明确 disabled 时不进入 invoke/坐标 fallback。行为测试断言 invoke 次数为 0。 |
| H-03 leave stage | 已修复 | Python 和 PowerShell 不再用无信息 bool 表示弹窗结果;唯一弹窗出现且 policy=leave 时返回 partial、initial_clicked、parameter_dialog_found=true、start_verified=false。无弹窗超时仍为 start_unverified。 |
| H-04 空 run 参数 | 已修复 | Python 用 is not None 判断参数是否出现;PowerShell 用 $PSBoundParameters.ContainsKey。显式空/空白 exact/latest 均在 UI 初始化前返回 ARG_REQUIRED/exit 3,并保留正确 action。 |
| M-01 list 滚动口径 | 已收敛契约 | 原 PRD只禁止启动/停止/关闭/清理业务动作,并未明确禁止只读 DataGrid 导航。当前虚拟化列表必须 UIA scroll 才能完整枚举,因此不伪称绝对零 UI 状态变化;SKILL 明确 list/current 可能导航/滚动,要求绝对零 UI 状态变化时只用 process snapshot。未执行真实 list。 |
| M-02 启动证据层级 | 采纳,未伪修 | 当前 Python可信强证据仍以新运行浮窗为主,PowerShell fallback 对启动固定保守返回 unverified。未用弱进程证据证明具体应用;文档能力表保持保守。后续若补运行列表目标证据,应以独立 adapter/mock 工作包实现。 |
| M-03 cmd venv preflight | 保留技术方案例外 | 技术方案 4.4 推荐并允许 wrapper 启动失败 stderr + exit 7,正式 JSON 契约从 Python 启动成功后生效。继续避免在 cmd 中脆弱拼 JSON;SKILL 已明确该例外。 |
| L-01 legacy skip 冲突 | 已修复 | PowerShell 使用 $PSBoundParameters.ContainsKey('ParameterDialogPolicy') 区分显式策略;skip 与非 leave 显式策略返回 ARG_CONFLICT。 |
额外核查发现并修复:配置写入和 stop/close 编排的脚本级副作用边界前移,避免未预期异常落入顶层 catch 时低报 changed;launcher 对所有已公开主动作统一推断,冲突保持 action=interactive,不把冲突误归到任一动作。
3. 行为级无 UI 测试
新增/扩展 tests/test_round5_regressions.py,覆盖:
- restart 进入副作用边界后失败的 changed/effect_unknown。
- mkdir 部分失败、稳定错误码、证据脱敏和禁止提交。
- disabled 参数按钮零 invoke。
- leave 有弹窗时的
initial_clicked。 - Python exact/latest 显式空值在 UI 初始化前失败。
- 公开 PowerShell launcher 未知参数、整数绑定失败、空值、动作推断、主动作冲突、
-Output:json和 exit 3。 - PowerShell impl 的候选集合、结构指纹、leave outcome、restart/config 副作用边界静态行为门禁。
已有 acceptance/fake 测试继续覆盖 direct/close 的确认前零副作用、一次点击、stale window、stop 优先、替换窗口不关闭、partial/verified 状态与兼容 wrapper 退出码透传。
4. 验证记录
最终门禁以本记录生成后的最后一次执行为准:
- 全量无 UI unittest:70/70 通过。
tests_static.py:输出STATIC_TESTS_PASSED。- 全部项目 Python 文件:12 个文件通过
py_compile。 - PowerShell launcher + impl:输出
POWERSHELL_AST_OK。 - 公开 launcher 安全黑盒:未知参数、类型转换、空 exact/latest、冲突、process snapshot unsupported 共 6 组通过;均为 v2 单对象、exit 3,且不初始化 UI。
- 技能目录
config.json:测试后确认不存在。 - 真实 RPA/UI:未触发。
5. 残余边界
- M-02 的多层启动证据仍是后续增强项;当前实现选择保守 partial,而不是错误宣称成功,因此不构成本轮安全发布阻断。
- list/current 的完整虚拟化枚举可能改变可见滚动位置;这是已文档化的只读导航例外,不属于业务启动/停止副作用。要求桌面像素/UI状态完全不变时只使用 process snapshot。
- cmd venv 缺失仍是技术方案明确的 preflight 契约例外:stderr 提示并 exit 7;调用方必须先按退出码处理。