octopus-rpa-app-runner 技能升级技术方案 v2

原始文件:wecom_e0c326ea_octopus-rpa-app-runner_技能升级技术方案_v2.md

octopus-rpa-app-runner 技能升级技术方案 v2

基于 octopus-rpa-app-runner_技能升级PRD_20260806.mdoctopus-rpa-app-runner_技能升级需求_v2.md 与当前技能代码形成。本文是增量实施方案,不包含代码修改。

1. 文档目标与实施原则

1.1 目标

本方案用于指导多个开发 Agent 并行完成以下升级:

  1. 将参数弹窗“不填参数直接运行”收敛为正式、安全、可审计的 CLI 能力。
  2. 将“先尝试停止,再关闭运行浮窗并恢复 Studio”收敛为正式 CLI 能力,同时不把“窗口关闭”误报为“任务停止”。
  3. 为所有主动作建立统一结果对象、文本/JSON 输出、错误码和退出码。
  4. 在不重写现有 runner 的前提下补齐参数策略、状态机、PowerShell fallback、自动化测试和迁移文档。

1.2 实施原则

2. 现有架构与调用链

2.1 文件与职责

文件当前职责主要问题
skills/octopus-rpa-app-runner/SKILL.mdAgent 使用说明、安全边界、命令示例未描述 v2 direct/close 正式能力和统一结果契约;内部类说明不足
scripts/run_pywinauto.cmd定位技能本地 .venv,调用 Python runner,透传参数和退出码venv 缺失仅自由文本 + exit 2,与 v2 环境错误 exit 7 不一致
scripts/OctopusRpaAppRunner.py默认实现;CLI、业务决策、pywinauto UI、确认、配置、进程查询均在单文件结果/异常无统一模型;动作不互斥;参数弹窗策略单一;direct/close 无正式入口
scripts/OctopusRpaAppRunner.ps1UIAutomation fallback,能力大体对应 Python参数、退出码、stop 行为与 Python 漂移;无 JSON/统一结果;direct/close 无正式入口
scripts/click_run_app_direct.py临时绕过:直接点击既有参数弹窗“运行应用”无专用确认、无快照复核、无统一输出,非安全正式入口
scripts/close_run_window_direct.py临时绕过:调用 close_run_window_if_present无专用确认;布尔返回混淆“窗口关闭”和“任务停止”
tests_static.py纯函数断言和源码字符串检查覆盖有限、行为 mock 不足、无法验证调用顺序和零副作用
config.json(运行时)记忆 DataDirectory无 schema 版本;非原子写入

2.2 Python 当前调用链

run_pywinauto.cmd
  -> .venv\Scripts\python.exe OctopusRpaAppRunner.py <args>
  -> __main__
     -> main(argv)
        -> argparse.parse_args
        -> 部分维护/只读动作提前返回
        -> OctopusPywinautoRunner(...)
        -> 若运行请求且存在浮窗
           -> run_window_snapshot
           -> confirm_restore_existing_run
           -> 快照复核
           -> close_run_window_if_present
              -> stop_run_window
              -> win.close
        -> read_all_apps
           -> open_apps_page -> root -> find_main_window
           -> get_flow_grid -> visible_apps -> scroll
        -> exact/latest/interactive_picker 选择目标
        -> confirm_run
        -> run_app_by_name
           -> bring_app_into_view
           -> invoke 列表 running 按钮
           -> handle_run_parameter_dialog
              -> find_run_parameter_dialog_root
              -> find_editable_input
              -> confirm_run_parameter_dialog
              -> 填目录 -> 点击“运行应用”
        -> 自由文本 Done / int 退出码

关键现状:

2.3 PowerShell 当前调用链

powershell -File OctopusRpaAppRunner.ps1 <params>
  -> param + StrictMode + UIAutomation 初始化
  -> 顶层 try
     -> Restart/Stop/ReadOnly 等分支
     -> 浮窗检测与 Confirm-RestoreExistingRunWindowForRun
     -> Close-OctopusRunWindowIfPresent
        -> Stop-OctopusRunWindowIfPresent
        -> WindowPattern.Close / WM_CLOSE
        -> Restore-OctopusMainWindow
     -> Read-AllApps
     -> 目标选择 + Confirm-RunSelection
     -> Run-AppByName
     -> Invoke-RunParameterDialogIfPresent
  -> Write-RunLog + exit 0/1/2

PowerShell 已有多数 UI 基元,但存在三项关键漂移:-StopRunWindow 找不到按钮仍 exit 0;无 direct/close 专用授权;无稳定结果对象和 JSON 输出。

2.4 当前安全调用边界

3. 目标架构(最小增量)

3.1 分层

CLI/参数层
  - argparse / PowerShell param
  - 主动作互斥、组合校验、弃用别名归一化
  - 输出模式选择
        |
编排与状态层
  - OperationContext / ActionResult / RunnerError
  - run/direct/stop/close/list 等动作编排
  - 确认范围、状态转换、后置验证
        |
现有 UI 适配层(保留 OctopusPywinautoRunner)
  - 窗口、控件、列表、弹窗枚举/快照
  - invoke/set value/close 等单步原语
        |
系统适配层
  - config、PowerShell 进程查询、时间、stdout/stderr

3.2 建议的最小文件调整

该结构只新增一个小型共享契约模块,不试图让 PowerShell 导入 Python,也不把所有 UI 方法抽象成完整接口,避免过度重构。

3.3 核心对象

Python 建议定义:

OperationContext
- operation_id: UUID
- action: Action
- output: text|json
- interactive: bool
- confirmation_scopes: set[str]
- started_at / phase timings
- side_effect_started: bool

ActionResult
- contract_version: 2
- operation_id, action
- result: success|partial|cancelled|failed|already_satisfied
- stage
- changed, verified
- error: {code, message} | null
- evidence: dict[str, JSON scalar/list/object]
- warnings: list[str]

RunnerError
- code
- exit_code
- message
- stage
- evidence

约束:动作函数返回 ActionResult;预期业务错误抛 RunnerError,顶层统一转换;仅编程错误走 INTERNAL_ERROR/exit 1。PowerShell 的 PSCustomObject 字段和值域必须一致。

4. CLI 参数与兼容策略

4.1 主动作

所有主动作必须互斥,并在初始化 pywinauto、读取/写入配置、访问 UI 前校验:

规范动作Python 参数PowerShell 参数说明
list_apps--list-only-ListOnly只读
run_exact--run-exact-name NAME-RunExactName NAME严格全名唯一匹配
run_latest--run-latest-by-prefix KEY-RunLatestByPrefix KEY保留旧名,增加歧义阻断
interactive无主动作参数无主动作参数默认动作;本次仅单选
current_running--current-running / --check-run-list-CheckRunList,可加 alias同一规范动作,两个 alias 不视为冲突
process_snapshot--process-snapshot建议补 -ProcessSnapshot只读
stop_run_window--stop-run-window-StopRunWindow只 stop,不 close
close_run_window--close-run-window-CloseRunWindow专用确认后 stop -> close -> verify
direct_parameter_run--click-run-app-direct-ClickRunAppDirect仅接管已存在参数弹窗
restart_clean--restart-studio-clean-RestartStudioClean保持独立维护动作
set_default_only--set-default-data-directory --data-directory PATH对应现有参数组合归一为独立主动作

--remember-data-directory 不是主动作,只能附着于 run exact/latest/interactive;set-default-only 不得同时运行应用。

4.2 新增/调整参数

--parameter-dialog-policy auto|map|direct|leave   默认 auto
--parameter KEY=VALUE                            可重复,仅 map
--create-missing-directories                     仅 auto/map
--yes-direct-run                                 仅独立 direct
--yes-close-run-window                           仅独立 close
--output text|json                               默认 text
--parameter-dialog-timeout-seconds N             默认 12,上限建议 60
--verification-timeout-seconds N                 默认 15,上限建议 120

PowerShell 使用对应 PascalCase 参数;若本版本不实现 map,必须在解析阶段返回 UNSUPPORTED_IN_FALLBACK/exit 3,不能忽略 -Parameter 或改用 direct。

4.3 参数组合校验

4.4 兼容策略

旧参数/行为v2 行为
--yes / -SkipConfirm保留一个小版本,归一为 yes_run,stderr 输出弃用警告;权限绝不扩大
--skip-run-parameter-dialog / -SkipRunParameterDialog归一为 policy=leave;若同时显式给其他 policy 则 ARG_CONFLICT
--check-run-list保留为 --current-running alias
--stop-run-window名称保留;PowerShell 修正为未点击时非成功,属于安全收紧
默认无参数互动模式保留,但多编号改为 BATCH_RUN_UNSUPPORTED 提示后重输
临时两个 Python 脚本保留一个迁移版本,只打印弃用提示并 subprocess 转发正式 CLI;不得直接 import 后点击
旧调用方只认 0/1发布说明要求升级;所有非 0 一律先视为未成功,逐步识别 2~7

run_pywinauto.cmd 应保持参数原样透传;venv 缺失时输出同契约的最小文本结果并 exit 7。JSON 参数检测在 cmd 中脆弱,不建议由 wrapper 手工生成 JSON;可以增加一个极小 Python bootstrap,或明确 wrapper 自身失败仍写 stderr + exit 7,而正式 runner 的 JSON 契约从 Python 启动成功后生效。推荐后者以避免批处理过度复杂化。

5. direct 与 close 的独立确认和安全语义

5.1 独立 direct

定义:只接管已经存在的合法 Octopus 参数弹窗;不查应用列表、不点击列表 running、不启动/恢复 Studio、不写参数、不创建目录、不写配置。

流程:

  1. 枚举所有属于 OctopusRPA.Studio 的顶层候选。
  2. 仅接受具有参数区域标识、唯一可用“运行应用”按钮的弹窗;0 个报 PARAM_DIALOG_NOT_FOUND,多个报 PARAM_DIALOG_AMBIGUOUS
  3. 建立弹窗快照/指纹,输出输入框总数、可写数、empty/non-empty 数,不输出值。
  4. --yes-direct-run 存在则确认 direct_parameter_continue scope;否则展示风险并交互确认;非交互 stdin 不可用则 CONFIRMATION_REQUIRED/exit 4。
  5. 确认后重新枚举并比较 pid、handle、按钮标识、输入摘要指纹。
  6. 指纹一致才点击一次。调用返回后即标记副作用已发生,验证超时也不得重试。
  7. 观测新浮窗/运行列表/进程差异,得到 start_observedstart_unverified

集成 policy=direct 与独立 direct 不同:它在运行计划开始前已声明,--yes-run 可授权 initial_run,direct_parameter_continue;最终结果必须输出 CONFIRM_SCOPE。运行过程中绝不允许从 auto 动态降级到 direct。

5.2 独立 close

定义:恢复 Studio 的显式动作;计划为“快照确认 -> 尝试 stop -> 若浮窗仍在则 close -> 验证”,但关闭窗口不等于证明任务停止

流程:

  1. 若无浮窗且 Studio 可访问,返回 already_satisfiedchanged=false、exit 0,不点击。
  2. 若浮窗和 Studio 都无法识别,返回 RUN_WINDOW_NOT_FOUND 或状态未知;不得启动 Studio。
  3. 获取浮窗快照并展示完整降级风险。独立动作仅接受 --yes-close-run-window 或交互肯定;其他 yes 标志无效。
  4. 确认后复核 title/pid/handle;变化返回 STALE_CONFIRMATION
  5. 尝试一次 stop;找不到按钮时记录 STOP_BUTTON_NOT_FOUND 证据,但因为 close 专用确认已覆盖降级风险,可以继续 close。
  6. stop 后轮询;浮窗已消失则不得再操作旧 handle,直接验证 Studio。
  7. 浮窗仍在才重新查询当前对象并 close;不得杀进程。
  8. 重新枚举浮窗与 Studio,再在 Studio 可访问时查询运行列表。
  9. 仅可信 empty 可令 RUN_STOP_VERIFIED=trueunknown 或无法查询为 partial/exit 2;active 为 failed 或 partial/exit 2/6,且不得输出“停止成功”。

必须分别输出:STOP_ATTEMPTEDSTOP_CLICKEDWINDOW_CLOSE_ATTEMPTEDWINDOW_CLOSEDSTUDIO_RESTOREDRUN_STOP_VERIFIED

5.3 运行新应用时恢复旧浮窗

继续使用 --yes-restore-existing-run,但复用 close 编排的“受控恢复子流程”,确认 scope 为 restore_existing_run,而不是独立 close_run_window。它只授权处理确认快照中的旧浮窗;新应用首击仍需 --yes-run。建议共用内部 restore_run_window(snapshot, authorization, verify=True),外层根据动作产生不同确认文案和结果。

6. 参数弹窗策略

6.1 弹窗与输入描述模型

新增轻量只读描述对象:

ParameterDialogSnapshot
- title, pid, handle
- run_button_automation_id/name/enabled
- inputs: [ParameterInputDescriptor]
- fingerprint

ParameterInputDescriptor
- automation_id
- accessible_name
- associated_label(可解析时)
- control_type, class_name
- writable
- empty(只输出布尔)
- index(1-based,仅摘要/显式索引映射使用)

指纹由规范化后的 pid + handle + button descriptor + sorted input descriptors 计算;不得包含输入原值。Python 可用 SHA-256 截断摘要,PowerShell 使用 SHA256;算法和规范化 JSON/连接格式必须写入测试固定向量。

6.2 auto

6.3 map

  1. 解析全部 KEY=VALUE,先构建完整映射计划,任何一项歧义时一项都不写。
  2. key 优先级:AutomationId 精确匹配 > 关联 Label 精确匹配 > accessible name 精确匹配。
  3. 仅显式 index:N 才允许按 1-based 控件序号匹配;不得隐式按顺序填充。
  4. 同层多个候选、同一控件被多个 key 命中、存在未映射的必需性未知输入时均阻断。由于 UIA 无可靠 required 元数据,本版本默认要求调用方明确处理所有可写输入;若允许保留某字段原值,应通过 KEY= 或后续明确的 leave-existing 语法,不在本次暗中推断。
  5. 日志仅输出 key、目标控件摘要及 empty/non-empty,不输出疑似 password/token/secret 字段值;建议所有参数值默认不进入日志。
  6. 逐项写入并回读;任一失败停止,不点击运行应用。
  7. 写入完成后重取快照。由于值的 empty 状态可能改变,点击前指纹比较应区分结构指纹与值状态:授权校验使用结构指纹;写入验证另存 value-state evidence,避免正常写值被误判 stale。

PowerShell P1 若排期不足,可以对 map 明确返回 UNSUPPORTED_IN_FALLBACK;P0 direct/close 不得缺失。

6.4 direct

不读写任何输入,不创建目录。必须输出 input count、empty/non-empty count 和 fingerprint。集成模式由运行计划中的 --parameter-dialog-policy direct + --yes-run 授权;独立模式必须 --yes-direct-run

6.5 leave

完成列表首击后不处理弹窗,也不把流程标记为启动成功。输出:

STAGE=initial_clicked
RUN_STAGE=initial_clicked
START_VERIFIED=false
RESULT=partial
ERROR_CODE=RUN_START_UNVERIFIED

如果已经观测到明确启动证据且没有弹窗,可正常 start_observedleave 只是不等待/处理参数弹窗,不应阻止对立即出现证据的非副作用观测。

7. 状态机设计

7.1 运行主状态机

INIT
 -> VALIDATED
 -> EXISTING_RUN_CHECKED
    -> RESTORE_CONFIRM_REQUIRED -> RESTORING -> RESTORE_VERIFIED
 -> APP_CATALOG_READ
 -> APP_SELECTED
 -> RUN_CONFIRM_REQUIRED
 -> RUN_CONFIRMED
 -> INITIAL_RUN_CLICKED
    -> START_OBSERVED
    -> PARAMETER_WAITING
       -> AUTO_MAPPING -> PARAM_VALUES_VERIFIED -> PARAM_SUBMITTED
       -> EXPLICIT_MAPPING -> PARAM_VALUES_VERIFIED -> PARAM_SUBMITTED
       -> DIRECT_CONFIRM_REQUIRED -> DIRECT_CONFIRMED -> PARAM_SUBMITTED
       -> LEFT_FOR_MANUAL -> START_UNVERIFIED
       -> CANCELLED
    -> START_UNVERIFIED
 -> FAILED

允许的最终 stage:start_observedstart_unverifiedcancelledfailedPARAM_SUBMITTED 后必须验证;点击成功不能直接转 success。

7.2 独立 direct 状态机

INIT -> VALIDATED -> PARAM_DIALOG_DETECTED -> SNAPSHOT_CAPTURED
 -> DIRECT_CONFIRM_REQUIRED -> DIRECT_CONFIRMED -> SNAPSHOT_REVALIDATED
 -> PARAM_SUBMITTED -> START_OBSERVED | START_UNVERIFIED

确认取消:cancelled/exit 0;确认缺失:failed + CONFIRMATION_REQUIRED/exit 4;快照变化:exit 6。

7.3 stop 状态机

INIT -> RUN_WINDOW_DETECTED -> STOP_ATTEMPTED
 -> STOP_CLICKED -> STOP_OBSERVED | STOP_UNVERIFIED
 -> STOP_NOT_AVAILABLE

STOP_NOT_AVAILABLE 不得转 close。无浮窗可返回 already_satisfied(目标“没有可停止浮窗”已满足)或 RUN_WINDOW_NOT_FOUND;为兼容和幂等,建议前者 exit 0、changed=false,但 STOP_CLICKED=false

7.4 close/restore 状态机

INIT
 -> ALREADY_RESTORED
 -> RUN_WINDOW_DETECTED -> CLOSE_CONFIRM_REQUIRED -> CLOSE_CONFIRMED
 -> SNAPSHOT_REVALIDATED -> STOP_ATTEMPTED
    -> STOP_CLICKED -> WAIT_FOR_DISAPPEAR
    -> STOP_NOT_AVAILABLE
 -> WINDOW_ALREADY_GONE -> VERIFY_STUDIO
 -> WINDOW_CLOSE_ATTEMPTED -> WINDOW_CLOSED -> VERIFY_STUDIO
 -> RESTORED_AND_STOP_VERIFIED
 -> RESTORED_BUT_STOP_UNVERIFIED
 -> STILL_ACTIVE
 -> RESTORE_FAILED

关键不变量:确认前零点击;stop 先于 close;旧 handle 消失后不再 close;close 永不触发进程清理。

8. 统一结果、输出与退出码

8.1 结果不变量

8.2 文本模式

日志写 stderr;stdout 最后只输出稳定结果块。为兼容人工阅读,可以在结果块前后使用固定 ASCII 标记,但机器解析只依赖 KEY=VALUE

CONTRACT_VERSION=2
OPERATION_ID=<uuid>
ACTION=close_run_window
RESULT=partial
STAGE=studio_restored
CHANGED=true
VERIFIED=false
ERROR_CODE=RUN_STOP_UNVERIFIED
MESSAGE=Studio restored, but run stop could not be verified.
STOP_ATTEMPTED=true
STOP_CLICKED=false
WINDOW_CLOSE_ATTEMPTED=true
WINDOW_CLOSED=true
STUDIO_RESTORED=true
RUN_STOP_VERIFIED=false
RUN_LIST_STATE=unknown

值中的换行、回车必须替换为空格;复杂 evidence 在文本模式使用稳定的扁平字段。应用列表可用重复 APP_NAME=<name> 行,或 JSON 编码的 APPS_JSON=[...];建议保留现有逐行人类列表到 stderr,并在结果块使用 APPS_JSON,避免裸应用名破坏机器契约。

8.3 JSON 模式

stdout 只输出一个 UTF-8 JSON 对象,ensure_ascii=false;日志、弃用警告和交互提示全部写 stderr:

{
  "contract_version": 2,
  "operation_id": "...",
  "action": "direct_parameter_run",
  "result": "partial",
  "stage": "start_unverified",
  "changed": true,
  "verified": false,
  "error": {"code": "RUN_START_UNVERIFIED", "message": "Run application was clicked, but no start evidence was observed."},
  "evidence": {
    "param_dialog_found": true,
    "param_input_count": 3,
    "direct_run_clicked": true,
    "start_evidence_level": "none"
  },
  "warnings": []
}

PowerShell 5.1 使用 ConvertTo-Json -Depth 8 -Compress。不得让 Write-Host 污染 JSON stdout;统一日志函数在 JSON 模式写 [Console]::Error

8.4 退出码

类别典型情况
0成功、已满足、用户取消verified success、already restored、cancelled
2部分完成/状态未知run list unknown、启动未验证、关闭后停止未验证
3参数/用法错误动作冲突、非法 policy、fallback 不支持的增强参数
4未授权非交互缺少对应 yes 标志
5目标不存在或歧义app/dialog/input 零匹配或多匹配
6UI 动作失败/竞态stale、点击失败、回读失败、close 失败
7环境/依赖失败pywinauto/venv 缺失、桌面不可用
1未分类内部错误编程错误、未映射异常

UNSUPPORTED_IN_FALLBACK 归类 exit 3,因为调用方式对该实现无效;不得回落到 exit 1。

9. 错误码目录

9.1 参数与授权

9.2 应用与运行

9.3 参数弹窗

9.4 浮窗与环境

错误映射表必须集中在 Python runner_contract.py 和 PowerShell 顶部常量区;测试以表驱动校验,不允许各动作自行选择退出码。

10. 启动与停止的验证证据

10.1 启动证据优先级

  1. run_list_target:运行列表显示目标应用,能验证具体目标。
  2. new_run_window:动作后出现新的合法运行浮窗,只证明启动已观测,不能证明目标名称。
  3. new_octopus_process_tree:BrowserBridge/受控 Edge 相比动作前新增,只作为弱证据。
  4. none:点击已发生但未观测证据,start_unverified/exit 2。

独立 direct 未必知道目标应用名,因此最高只能声明“启动已观测”,除非运行列表提供唯一名称;不能将进程变化描述成具体应用成功。

10.2 停止证据

所有验证使用动作前后快照差异,避免把既存窗口/进程当作本次证据。

11. PowerShell fallback 方案

11.1 同版本必须实现(P0)

11.2 可显式不支持(P1)

11.3 禁止自动 fallback 的情况

Python 已发生任意 UI 点击、参数写入、目录/配置写入后,不得自动调用 PowerShell 重做。只有在:

才可以由上层 Agent 明确选择 PowerShell。runner 本身不自动链式回退,避免重复运行。

11.4 PowerShell 实现要点

12. 配置与日志

12.1 配置 schema

建议 schema:

{
  "schema_version": 2,
  "DataDirectory": "C:\\Users\\...\\Documents\\OctopusRPA\\BossResumes",
  "UpdatedAt": "2026-08-06T12:00:00"
}

兼容读取无 schema_version 的旧文件为 v1。写入步骤:同目录临时文件 -> flush/close -> os.replace;PowerShell 使用临时文件后 [System.IO.File]::Replace,目标不存在时 Move。失败保留旧文件并返回 CONFIG_WRITE_FAILED。损坏文件不得被隐式覆盖。

12.2 敏感信息

13. 模块/函数级变更清单

13.1 新增 scripts/runner_contract.py

符号责任
Action, ResultKind, RunStage稳定值域枚举
EXIT_CODES, ERROR_EXIT_MAP错误码到退出码唯一映射
OperationContextoperation id、action、输出模式、确认 scope、side-effect 标志
ActionResult统一结果对象及 evidence/warnings
RunnerError可预期错误对象
validate_cli_plan(normalized_args)无 UI 参数组合校验
render_text(result)单行 KEY=VALUE 结果块
render_json(result)单 JSON 对象
sanitize_message(value)去换行并防止破坏文本协议

该模块不得 import pywinauto,便于跨平台单测。

13.2 修改 OctopusRpaAppRunner.py

CLI/顶层:

弹窗模型与原语:

运行与验证:

浮窗:

配置/日志:

13.3 修改 OctopusRpaAppRunner.ps1

13.4 修改 wrapper 和迁移脚本

13.5 修改文档

SKILL.md 必须更新:

14. 测试设计

14.1 测试目录建议

skills/octopus-rpa-app-runner/
  tests/
    test_contract.py
    test_cli_validation.py
    test_parameter_policy.py
    test_direct_action.py
    test_close_action.py
    test_run_state_machine.py
    test_config.py
    test_selection.py
    test_powershell_contract.py
    fakes.py
  tests_static.py

优先使用标准库 unittest + unittest.mock,避免新增 pytest 依赖;如果仓库已有统一 pytest 再遵循现状。fakes.py 提供可记录调用序列的 Fake UI adapter,而不是模拟 pywinauto 每个底层对象。

14.2 Fake/Mock 边界

不要求彻底抽象现有 runner。测试中可构造不调用 __init__ 的 runner,并 mock 以下边界:

Fake 必须记录 read, confirm, write_value, click_initial, click_direct, click_stop, close_window, create_dir, write_config,用于断言顺序和确认前零副作用。

14.3 单元与契约测试

结果契约:

CLI:

参数策略:

选择与运行:

close/stop:

配置:

14.4 PowerShell 测试

14.5 静态与只读集成

发布前命令建议:

python -m py_compile scripts/OctopusRpaAppRunner.py scripts/runner_contract.py
python -m unittest discover -s tests -p "test_*.py"
python tests_static.py
scripts\run_pywinauto.cmd --help
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\OctopusRpaAppRunner.ps1 -Help

在有 Octopus 的受控桌面环境再执行 --list-only--current-running--process-snapshot。只读测试必须审计没有 start/stop/close/create/write/cleanup 调用。

14.6 现场验收

仅由业务负责人指定白名单应用并逐动作确认:

  1. 多输入框 direct:先无确认验证零点击,再专用确认运行,记录 clicked/start evidence,不能宣称业务完成。
  2. 无 stop 按钮 close:确认前零动作;确认后记录 stop=false、window closed、Studio restored、run-list verification。
  3. PowerShell fallback 在 Python P0 通过后抽测;不重复对同一未知状态动作。

15. 并行实现工作包

以下拆分以文件所有权降低冲突。所有 Agent 先读取本方案和 v2 需求,不得自行改变契约值域。

WP-0:契约与测试骨架(先行,短周期)

WP-1:Python CLI、direct 与参数策略

WP-2:Python close/stop 与配置

为避免两个 Agent 同时编辑 OctopusRpaAppRunner.py,不建议与 WP-1 真正并行提交同一文件。可采用二选一:

WP-2 内容:结构化 stop、close/restore 状态机、后置验证、原子配置、tests/test_close_action.pytests/test_config.py。推荐不为并行而强拆,避免过度重构。

WP-3:PowerShell fallback

WP-4:文档、wrapper 与迁移脚本

WP-5:独立验收与回归测试

推荐并行拓扑

WP-0(契约冻结)
   |-- WP-1+WP-2(同一 Agent:Python 核心)
   |-- WP-3(PowerShell)
   |-- WP-4(文档/迁移)
   `-- WP-5(独立测试,先写 fixture)

实际可同时投入 4 个 Agent:Python 核心、PowerShell、文档迁移、独立测试。不要为了增加并行度让两个 Agent 同时编辑 Python 单体文件。

16. 集成顺序与门禁

  1. 合入 WP-0:冻结 contract version、值域、错误码、退出码、JSON schema;未冻结前其他包只可本地开发。
  2. 合入 WP-1+WP-2 Python 核心:先跑 Python 单元/mock,确认参数错误不初始化 UI、direct/close 不重试。
  3. 合入 WP-3 PowerShell:运行跨实现契约 fixture;P0 不一致不得进入文档集成。
  4. 合入 WP-4 文档与迁移:以实际 --help 和测试结果校正文档,确保迁移脚本不自动添加 yes 标志。
  5. 合入 WP-5 黑盒回归:替换脆弱源码字符串断言,保留必要静态 guard;跑全量无副作用测试。
  6. 只读桌面 smoke:Python 必测,PowerShell 抽测;审计无 UI 副作用。
  7. 受控现场验收:direct 与 close 分别单独授权,不在状态未知后自动 fallback 重做。
  8. 发布检查:版本说明列出 exit 码扩展、stop 行为收紧、互动单选、legacy alias 弃用期。

每一步失败只回退当前工作包,不允许以禁用确认、放宽 unknown 或恢复临时直点脚本来“修测试”。

17. 回滚方案

17.1 发布前准备

17.2 代码回滚

若 v2 CLI/输出出现阻断性回归:

  1. 停止发起新的副作用命令。
  2. 仅在确认没有“点击结果未知”的在途操作时,将技能目录切回上一稳定制品。
  3. 保留 v2 config.json;上一版读取 DataDirectory 仍兼容。若上一版解析 schema 字段有问题,使用 v2 自动写入前保留的配置备份恢复,而不是手工截断正在使用的文件。
  4. 临时脚本不得恢复为无确认实现;回滚版本若缺 direct/close,则这些能力应标记不可用,并要求人工操作。
  5. 对已发生 click 但未验证的操作,先人工/只读确认现状,不自动用旧版本重复执行。

17.3 功能降级开关

不建议新增长期 feature flag。必要时可在发布包层面:

不得通过把 direct 改回无确认、把 close 改回布尔成功、把 unknown 当 empty 来降级。

17.4 数据与运行态回滚

18. 完成定义

版本完成必须同时满足: