# 执行与结果 > [返回文档中心](README.md) · [动作目录](actions/README.md) · [任务协议](protocol.md) ## 1. 当前执行流程 **[已实现]** 当前 `TaskExecutor` 按以下方式执行每一步: 1. 计算步骤截止时间。 2. 等待 `packageName` 和可选 `activityName` 匹配。 3. BACK 直接调用全局返回;其他动作查询 selector。 4. 没有目标时继续等待,多个目标立即失败。 5. 执行动作;成功后立即结束本步并进入下一步。 6. 每次尝试结束后判定截止时间:到达超时时 optional 步骤跳过,其他步骤停止任务。 超时判定在每轮尝试之后进行,因此轮询唤醒晚于截止时间不会让失败的步骤被记为成功。多目标(`TARGET_AMBIGUOUS`)立即停止任务,不受 `optional` 影响。 当前结果: ~~~json { "successful": true, "code": "OK", "message": "任务执行完成", "extracted": { "status": ["准备完成"] } } ~~~ 结果码见[结果码总表](actions/README.md#结果码总表)。当前执行器会产生 `OK`、`PACKAGE_MISMATCH`、`ACTIVITY_MISMATCH`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS` 和 `ACTION_FAILED`。 是否成功只看 `successful`,成功时 `code` 恒为 `OK`;`message` 只用于排障,不参与流程判断。 ## 2. 简单步骤结果 **[提案]** 为了便于排查,可将每一步记录为简单结构: ~~~json { "stepId": "click-submit", "action": "CLICK", "success": false, "code": "ACTION_FAILED", "message": "点击未成功", "output": {}, "elapsedMs": 1200 } ~~~ 建议只保留: - `stepId`、`action`:定位步骤。 - `success`、`code`:供程序判断。 - `message`:供排障,不参与流程判断。 - `output`:动作输出,没有输出时为空对象。 - `elapsedMs`:步骤耗时。 暂不引入 phase、effect、transition 和独立结果协议版本。以后确实需要断点恢复或复杂流程审计时再扩展。 结果码的取值与新增规则统一见[结果码总表](actions/README.md#结果码总表)。 ## 3. 动作执行规则 - `timeoutMs` 是整个步骤的总时间,包括等待和验证。 - 每轮查询都读取当前页面,不长期保存旧节点。 - WAIT 和只读提取可以轮询。 - CLICK、INPUT、BACK、OPEN 等有副作用动作默认只分发一次。 - 提供 `after` 时,动作后重新读取页面并验证。 - 动作失败不会自动回到初始页面;需要返回或重新打开时由任务显式增加步骤。 ## 4. 并发与幂等 当前 SQLite 以 `taskId + revision` 防止同一版本重复入库,但自动执行尚未实现,`TaskExecutionMutex` 也尚未接入。 简单目标: - 同一时刻只执行一个任务。 - 已成功执行的相同 `taskId + revision` 不自动重复。 - 更高 revision 是否替代旧版本,等调度需求明确后决定。 - 暂不实现抢占、租约、断点恢复和自动回滚。 ## 5. 测试 至少覆盖: - 每个失败原因得到稳定 code。 - optional 只跳过约定的失败。 - 多目标不会执行动作。 - 有副作用动作在一个步骤内最多调用一次。 - after 使用动作后的新页面状态。 - 失败结果仍保留此前已经完成的提取输出。