feat(ui-automation): Add rs/1 runtime automation parity #416
5 issues
find-bugs: Found 5 issues (5 low)
Low
Runtime-snapshot next-steps branch ignores `result.didError`, unlike the fallback path - `src/mcp/tools/ui-automation/shared/domain-result.ts:215-222`
When result.capture is a RuntimeSnapshotV1 the new branch immediately calls createRuntimeSnapshotNextSteps and returns without checking result.didError, so a failed action result that carries a runtime-snapshot capture would still emit actionable tap/scroll next steps. The fallback path createUiActionSuccessNextSteps correctly guards with if (result.didError) return [], but the new early-return branch skips that guard entirely.
tapElement ref duplicated across batch and tap next-step suggestions - `src/mcp/tools/ui-automation/shared/runtime-next-steps.ts:352-402`
When the highest-priority tap element (tapElement = tapElements[0]) is not content-rich, screen-changing, or low-priority, it passes into batchElements and its ref appears in both the batch step (batchElements.slice(0, 2)) and the standalone tap step. An agent that executes both steps would tap the same element twice.
`readState` can never return `undefined`, making the guard in `normalizeNode` dead code - `src/mcp/tools/ui-automation/shared/runtime-snapshot.ts:220-239`
The state object is always initialized with enabled and visible, so Object.keys(state).length > 0 is always >= 2 and the function never returns undefined. The conditional spread ...(state ? { state } : {}) in normalizeNode is therefore always truthy, meaning every element in the snapshot unconditionally receives a state field — the optional omission path is unreachable.
Recursive `flattenHierarchy` has no depth guard and can stack overflow on deep trees - `src/mcp/tools/ui-automation/shared/runtime-snapshot.ts:492-499`
The inner visit function in flattenHierarchy recurses without a depth limit; a malformed or unusually deep accessibility tree response could exhaust the call stack.
Wrong fallback error message when `isRuntimeSnapshotUnchanged` is true but `isRuntimeSnapshot` is false in the `didError` branch - `src/utils/renderers/domain-result-text.ts:1477-1485`
When capture.type is 'runtime-snapshot-unchanged', the didError block falls through to else if (isUiHierarchy) (which is true because isUiHierarchy was broadened to include isRuntimeSnapshotUnchanged) and produces the misleading fallback 'Failed to get accessibility hierarchy.' instead of a runtime-snapshot-appropriate message.
⏱ 36m 31s · 11.4M in / 559.5k out · $19.46