Summary
A recorded tool: flow-execute step replays as status: "pass" regardless of what the composed flow actually did. The enclosing run then reports a top-level ok: true for a composition that failed every step, or that ran no steps at all.
Found while verifying #574. It is not caused by that PR — it reproduces byte-identically on main (eea6c27c), and the relevant code is untouched by it. Filing separately as agreed on that PR.
Where
packages/tool-server/src/tools/flows/flow-run.ts — case "tool": only isUnmetUiWaitResult is inspected; every other non-throwing result becomes status: "pass". flow-execute returns { ok: false, ... } or { notice: ... } without throwing, so neither is noticed.
- The step is produced by the "kept the raw flow-execute step" fallback in
packages/tool-server/src/tools/flows/flow-add-step.ts — reached when the target is not a sibling of the recording (cross-project composition) and, in client/remote persist mode, always.
run: composition does not have this problem; only the raw tool: form does.
Reproduction
Real iOS simulator (iPhone 16, D72CC5CA-FF01-4976-8211-50713576D3DA), real app com.apple.Preferences, tool-server driven over HTTP.
mkdir -p projA projB/.argent/flows
cat > projB/.argent/flows/b-prereq.yaml <<'YAML'
executionPrerequisite: Settings must be open on the root Settings page
steps:
- echo: this never runs
YAML
t() { curl -s -X POST "http://127.0.0.1:$PORT/tools/$1" -H 'content-type: application/json' -d "$2"; }
t flow-start-recording '{"name":"raw-prereq","project_root":"'$PWD'/projA"}'
# projB/b-prereq is not a sibling of projA -> the raw flow-execute step is kept
t flow-add-step '{"name":"raw-prereq","project_root":"'$PWD'/projA","command":"flow-execute","args":"{\"name\":\"b-prereq\",\"project_root\":\"'$PWD'/projB\",\"device\":\"'$UDID'\"}"}'
t flow-finish-recording '{"name":"raw-prereq","project_root":"'$PWD'/projA"}'
t flow-execute '{"name":"raw-prereq","project_root":"'$PWD'/projA","device":"'$UDID'"}'
Observed
Recorded YAML:
steps:
- tool: flow-execute
args:
name: b-prereq
project_root: /.../projB
device: D72CC5CA-FF01-4976-8211-50713576D3DA
Replay — the sub-call returned a prerequisite notice and executed zero steps:
top-level ok=True passed=1 failed=0
step status: pass | sub-result: {"flow": "b-prereq", "notice": "This flow has an execution prerequisite that must be fulfilled before it can run. ..."}
The same shape with a sub-flow that genuinely fails (a target whose await-ui-element cannot match):
"flow": "cross-raw", "ok": true, "passed": 1, "failed": 0,
"steps": [ { "kind": "tool", "status": "pass", "tool": "flow-execute",
"result": { "flow": "b-only", "ok": false, "passed": 0, "failed": 1,
"steps": [ { "status": "fail", "tool": "await-ui-element",
"reason": "await-ui-element condition not met: no element matched the selector before timeout" } ] } } ]
Expected
A tool: flow-execute step whose sub-report carries ok: false — or a notice instead of a report — should fail or error the enclosing step and hard-stop the run, as run: composition does. A green top-level result for a composition that failed everything, or ran nothing, is a silent false pass.
Not the known recursion issue
This is unrelated to the tool: flow-execute self-reference recursion also noted on #574: no recursion is involved and the target is a different flow.
Summary
A recorded
tool: flow-executestep replays asstatus: "pass"regardless of what the composed flow actually did. The enclosing run then reports a top-levelok: truefor a composition that failed every step, or that ran no steps at all.Found while verifying #574. It is not caused by that PR — it reproduces byte-identically on
main(eea6c27c), and the relevant code is untouched by it. Filing separately as agreed on that PR.Where
packages/tool-server/src/tools/flows/flow-run.ts—case "tool": onlyisUnmetUiWaitResultis inspected; every other non-throwing result becomesstatus: "pass".flow-executereturns{ ok: false, ... }or{ notice: ... }without throwing, so neither is noticed.packages/tool-server/src/tools/flows/flow-add-step.ts— reached when the target is not a sibling of the recording (cross-project composition) and, in client/remote persist mode, always.run:composition does not have this problem; only the rawtool:form does.Reproduction
Real iOS simulator (iPhone 16,
D72CC5CA-FF01-4976-8211-50713576D3DA), real appcom.apple.Preferences, tool-server driven over HTTP.Observed
Recorded YAML:
Replay — the sub-call returned a prerequisite notice and executed zero steps:
The same shape with a sub-flow that genuinely fails (a target whose
await-ui-elementcannot match):Expected
A
tool: flow-executestep whose sub-report carriesok: false— or anoticeinstead of a report — should fail or error the enclosing step and hard-stop the run, asrun:composition does. A green top-level result for a composition that failed everything, or ran nothing, is a silent false pass.Not the known recursion issue
This is unrelated to the
tool: flow-executeself-reference recursion also noted on #574: no recursion is involved and the target is a different flow.