fix(replay): escape recorded interpolation, run scripts off the event loop, harden Maestro and test flows
Merged
TH
4h ago+1687+1687+0123456789012345678901234567890123456789-535-535-012345678901234567890123456789
Summary
Fixes 12 audit findings in replay, Maestro and the test runner. REPLAY-8 is dropped: upstream Maestro's repeat while is also unbounded, and the real gap is a missing default test timeout (REPLAY-19).
- Placeholder escaping: literal
${ā¦}text in a recorded script is escaped when the script is written. The only placeholder left live is the one in the fill that--record-asparameterized, tracked per action. - runScript: runs in a child process (
internal/run-script-child) that the daemon can cancel and time out. The 8 MiB HTTP response cap and the 30 s timeout now apply to both paths. - Input limits:
eraseTextis capped at 10000 characters. Maestro-ekeys andAD_VAR_*accept mixed case and dots, and__proto__is rejected. The key grammar is chosen by the input's resolved format. - iOS launch arguments: map-form keys get a leading
-, matching Maestro. Android is unchanged. replay export: handleswait stable, rejects@refand malformed waits, and keeps multi-token text and selectors whole.- Refs and classification: divergence refs stay within the published scope. Test-infrastructure classification uses typed details only.
- Companion process lock: companion ensure and stop run under a process lock.
- Cleanup: the unused
actionSourcePathsis removed, and plan digests are unchanged.
About 60 files touched.
Validation
- Tested
df9d76dwithcheck:affected(exactCommit=true):- Format, lint, typecheck, layering, Fallow, build and package passed.
integration-nodefails 2smoke-daemon-cleantests, which fail the same way on base093341ain this container. Checks after it did not run locally.
- The installed-package test runs the packed
run-script-child. Focused coverage on the runScript files is 90ā98%. - CI must confirm unit, Coverage, maestro-conformance and provider-integration.
- Risks:
- The iOS launch-argument change needs a device check.
replay exportkeeps its own copy of the wait grammar, so it can drift from command-registry. It can't import that parser without breaking the eager-closure budget.
š¤ Generated with Claude Code