@swmansion/argent 0.32.0 → 0.32.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/bin/argent-android-devtools-0.3.0.apk +0 -0
  2. package/bin/darwin/ax-service +0 -0
  3. package/bin/darwin/tvos-ax-service +0 -0
  4. package/bin/darwin/tvos-hid-daemon +0 -0
  5. package/bin/network-inspector/network-inspector.jar +0 -0
  6. package/bin/tcp/ax-service +0 -0
  7. package/dist/cli-cmds.mjs +1 -1
  8. package/dist/installer.mjs +7 -7
  9. package/dist/mcp-server.mjs +1 -1
  10. package/dist/tool-args.generated.d.ts +178 -178
  11. package/dist/tool-server.cjs +1281 -1459
  12. package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
  13. package/dylibs/libKeyboardPatch.dylib +0 -0
  14. package/dylibs/libNativeDevtoolsIos.dylib +0 -0
  15. package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
  16. package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
  17. package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
  18. package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
  19. package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
  20. package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
  21. package/package.json +1 -1
  22. package/rules/argent.md +19 -183
  23. package/skills/argent-android-emulator-setup/SKILL.md +5 -13
  24. package/skills/argent-create-e2e/SKILL.md +1 -1
  25. package/skills/argent-create-e2e/references/e2e-yaml.md +12 -17
  26. package/skills/argent-create-e2e/references/live-authoring.md +25 -65
  27. package/skills/argent-create-e2e/references/reliability-and-recovery.md +8 -8
  28. package/skills/argent-device-interact/SKILL.md +65 -367
  29. package/skills/argent-device-interact/references/chromium.md +4 -19
  30. package/skills/argent-device-interact/references/foldables.md +8 -0
  31. package/skills/argent-device-interact/references/harmonyos.md +13 -50
  32. package/skills/argent-ios-device-interact/SKILL.md +0 -1
  33. package/skills/argent-ios-device-setup/SKILL.md +1 -1
  34. package/skills/argent-ios-simulator-setup/SKILL.md +3 -9
  35. package/skills/argent-lens/SKILL.md +20 -75
  36. package/skills/argent-metro-debugger/SKILL.md +35 -101
  37. package/skills/argent-native-profiler/SKILL.md +23 -92
  38. package/skills/argent-qa-e2e/SKILL.md +5 -5
  39. package/skills/argent-react-native-app-workflow/SKILL.md +34 -203
  40. package/skills/argent-react-native-optimization/SKILL.md +10 -26
  41. package/skills/argent-react-native-optimization/references/fix-reference.md +11 -11
  42. package/skills/argent-react-native-optimization/references/lint-rules.md +4 -5
  43. package/skills/argent-react-native-optimization/references/semantic-checklist.md +2 -2
  44. package/skills/argent-react-native-profiler/SKILL.md +46 -110
  45. package/skills/argent-screen-recording/SKILL.md +18 -37
  46. package/skills/argent-screenshot-diff/SKILL.md +8 -52
  47. package/skills/argent-settings-permissions/SKILL.md +15 -117
  48. package/skills/argent-test-ui-flow/SKILL.md +20 -90
  49. package/skills/argent-tv-interact/SKILL.md +9 -34
  50. package/skills/argent-tv-interact/references/vega.md +23 -0
  51. package/agents/argent-environment-inspector.md +0 -107
  52. package/agents/references/quality-control-checklist.md +0 -45
  53. package/skills/argent-device-interact/references/gesture-examples.md +0 -114
  54. package/skills/argent-device-interact/references/secrets.md +0 -23
  55. package/skills/argent-metro-debugger/references/failure-scenarios.md +0 -14
  56. package/skills/argent-metro-debugger/references/source-maps.md +0 -27
  57. package/skills/argent-react-native-profiler/references/diagnostic-tools.md +0 -101
@@ -23,28 +23,17 @@ Read this file before creating or changing an e2e test. Exercise the saved path
23
23
 
24
24
  ## Recorder contract
25
25
 
26
- `e2e-add-step.command` is an MCP tool name. `args` is a JSON string, not an object. Omit `args` for a no-argument tool.
27
-
28
- ```text
29
- command: "gesture-tap"
30
- args: "{\"udid\":\"DEVICE\",\"x\":0.5,\"y\":0.35}"
31
- ```
32
-
33
26
  A recorded `e2e-execute` has two names. The top-level `name` identifies the recording. `args.name` identifies the sibling test captured as `run:`.
34
27
 
35
- When the user requests a script, call `e2e-add-script` at the point where it must run. Read [E2E YAML: Local scripts](e2e-yaml.md#local-scripts) first. If the call fails, check its changes before you retry.
36
-
37
28
  Over a link, `e2e-add-step` refuses a call whose step a replay over the same link rejects, and runs nothing. It also refuses an `e2e-execute` call whose test does not pass. That test can have changed the device before it stopped. In both cases the recorder records no step. See [Replay](#replay) for the steps that a replay over a link rejects.
38
29
 
39
30
  Obey these lifecycle rules:
40
31
 
41
- 1. Pass the same `name` and absolute `project_root` to every recording tool.
42
- 2. Choose a name unique to the task. Another caller can take over the same pair without an ownership check. The pair is keyed by the file the filesystem resolves to, not the spelling you passed, so a differently-cased name or a symlinked `.argent/e2e` collides too. That collision is reported: the second start says `restarted`, and the first recording's next call fails naming both spellings.
43
- 3. Give concurrent recordings separate devices. Their files are isolated, but their live device actions are not.
44
- 4. Treat `e2e-start-recording` as destructive. It always truncates the named YAML, including a finished or committed test. `restarted` reports only a displaced live take.
45
- 5. If a call says the recording is inactive, do not restart under that name. The completed take can still be on disk. Copy it aside or record under a fresh name.
46
- 6. Inspect `toolResult`, `message`, and `recorded` after each call. A call that errors records nothing, but a call that returns normally while reporting an unmet condition **does** append the step, and `message` says the step was added either way. A failed `e2e-add-script` call appends nothing. `await-ui-element` is the case that turns up in practice (see [Live waits and checks](#live-waits-and-checks)). Only `e2e-start-recording` and `e2e-finish-recording` return the whole YAML as `e2eTestFile`. A step call returns `recorded` (one summary line for the step it appended) plus a running `stepCount`. Read `recorded`: the recorder does not always store the tool call you made, and that line is where a rewrite shows up. To see the whole file mid-recording, read it at `savedTo`. A `savedTo` that comes back `null` means the write failed on your side. The step is still in the recording, so continue: the next step rewrites the whole file, and `e2e-finish-recording` returns `e2eTestFile` regardless.
47
- 7. Edit or reorder the YAML only after `e2e-finish-recording`. A recording over a link, also to 127.0.0.1, overwrites edits made during the recording.
32
+ 1. Choose a name unique to the task: another caller can take over the same `name` + `project_root` pair without an ownership check. The pair is keyed by the file the filesystem resolves to, not the spelling you passed, so a differently-cased name or a symlinked `.argent/e2e` collides too. That collision is reported: the second start says `restarted`, and the first recording's next call fails naming both spellings.
33
+ 2. Treat `e2e-start-recording` as destructive. It truncates the named YAML even when it holds a finished or committed test. `restarted` reports only a displaced live take.
34
+ 3. If a call says the recording is inactive, do not restart under that name. The completed take can still be on disk. Copy it aside or record under a fresh name.
35
+ 4. Read `recorded` after each call. The recorder does not always store the tool call you made, and that line is where a rewrite shows up. A call that returns normally while reporting an unmet condition **does** append the step; `await-ui-element` is the case that turns up in practice (see [Live waits and checks](#live-waits-and-checks)). To see the whole file mid-recording, read it at `savedTo`. A `null` `savedTo` means only the write on your side failed: the step is still in the recording, the next step rewrites the whole file, and `e2e-finish-recording` returns `e2eTestFile` regardless.
36
+ 5. Edit or reorder the YAML only after `e2e-finish-recording`.
48
37
 
49
38
  ## Start in the correct order
50
39
 
@@ -64,7 +53,7 @@ On iOS, only `restart-app` guarantees an instrumented launch. `launch-app` can f
64
53
 
65
54
  **The app sets the window size; no boot argument overrides it.** Electron ignores `--window-size`: the size comes from the app's own `BrowserWindow` options, and Argent never resizes the window. Boot a fresh target with `boot-device` and `electronAppPath`, then take one `screenshot` and record its pixel dimensions: that capture size is the snapshot device class ([E2E YAML: Snapshots](e2e-yaml.md#snapshots-and-cli-runs)) and must match when CI replays. If the app sizes its window from host or session state, say so in the report.
66
55
 
67
- After boot, start the recorder before the first in-app action. Record the first-screen wait. `restart-app` has no Chromium support, so the call errors and records nothing, and a recorded Chromium test is always a fragment: its launch is written in during polish rather than captured, and any `executionPrerequisite` the recording declared must go with it. A launch-first test must not carry one. During polish, add the matching launch:
56
+ After boot, start the recorder before the first in-app action. Record the first-screen wait. `restart-app` has no Chromium support, so a recorded Chromium test is a fragment until polish writes its launch in (and removes any `executionPrerequisite` the recording declared). During polish, add the matching launch:
68
57
 
69
58
  ```yaml
70
59
  steps:
@@ -74,7 +63,7 @@ steps:
74
63
  args: ["--enable-feature-flag"]
75
64
  ```
76
65
 
77
- The path is relative to `.argent/e2e/`. Copy the live boot arguments verbatim, and omit `args` when the boot passed none. This packaging exception represents the boot already exercised live. It does not permit a rehearsed UI path.
66
+ A relative path resolves from the folder of the test being run. Copy the live boot arguments verbatim, and omit `args` when the boot passed none. This packaging exception represents the boot already exercised live. It does not permit a rehearsed UI path.
78
67
 
79
68
  ### Fragments
80
69
 
@@ -88,8 +77,8 @@ Reach each screen through the app's UI. Do not replace tested navigation with `o
88
77
 
89
78
  For every action:
90
79
 
91
- 1. **Discover without mutation.** Use `describe`, iOS native discovery, `debugger-component-tree`, or `screenshot`. Do not record discovery or `debugger-*` calls: `port` is not a device-bind key, so a recorded one replays against whatever Metro owns that port.
92
- 2. **Choose a durable target.** Prefer a stable id, then stable text or an accessibility label. On iOS, use native discovery for ids that trimmed accessibility output omits.
80
+ 1. **Discover without mutation.** Use `describe`, iOS native discovery, or `screenshot`. Do not record discovery or `debugger-*` calls: `port` is not a device-bind key, so a recorded one replays against whatever Metro owns that port.
81
+ 2. **Choose a durable target.** Prefer a stable id, then stable text or an accessibility label. On iOS, use native discovery for ids that trimmed accessibility output omits; on Android React Native, `debugger-component-tree`.
93
82
  3. **Add an echo.** Name the current state, action, and expected outcome before the action can fail.
94
83
  4. **Execute through `e2e-add-step`.** Inspect the result and the `recorded` line immediately.
95
84
  5. **Verify immediately.** Record outcome checks when their states first appear. After navigation, prove identity then readiness: record the identity check live, and add the readiness gate during polish.
@@ -114,10 +103,10 @@ Without step 1, `hidden` also passes for a typo or an element that never existed
114
103
 
115
104
  ### Taps
116
105
 
117
- `e2e-add-step` cannot receive a YAML selector directly. Discover the element first, then record `gesture-tap` at its frame center; the live coordinates are transport for the gesture, not a final locator. The recorder reads the pre-tap tree and derives the selector in a fixed order (`id`, then `text`, then `role`), giving three outcomes. Read the `recorded` line after every tap, because only two of them warn. It names the derived form (a selector map, or the kept point):
106
+ `e2e-add-step` cannot receive a YAML selector directly. Discover the element first, then record `gesture-tap` at its frame center; the live coordinates are transport for the gesture, not a final locator. The recorder reads the pre-tap tree and derives the selector in a fixed order (`id`, then `text`, then `role`), giving three outcomes. Read the `recorded` line after every tap. It names the derived form (a selector map, or the kept point):
118
107
 
119
108
  1. **`tap: { id: ... }` or `tap: { text: ... }`**: the good case.
120
- 2. **`tap: { role: ... }`, appended with no warning.** An icon-only button with neither id nor visible label lands here. `role` matches as a case-insensitive substring, so a replay screen holding a second control of that role can win the [ranking](e2e-yaml.md#the-runner-tree-is-not-the-discovery-tree) and the tap reports a pass on the wrong control.
109
+ 2. **`tap: { role: ... }`, with a warning.** An icon-only button with neither id nor visible label lands here. `role` matches as a case-insensitive substring, so a replay screen holding a second control of that role can win the [ranking](e2e-yaml.md#the-runner-tree-is-not-the-discovery-tree) and the tap reports a pass on the wrong control.
121
110
  3. **A kept raw point**, with a warning naming the reason and the retarget.
122
111
 
123
112
  Treat outcomes 2 and 3 alike. Restore the source screen with direct MCP calls, record a corrected tap, then remove the weak step after finishing. Keep a point or a bare role only through the [coordinate fallback gate](reliability-and-recovery.md#coordinate-fallback-gate).
@@ -126,11 +115,11 @@ Never tap the on-screen keyboard through the recorder. Some platforms expose it
126
115
 
127
116
  ### Typing
128
117
 
129
- Record the focus tap, then record `keyboard` with `text`. A `keyboard` call carries `text` or `key`, never both. To submit, record a second `keyboard` step with `key: "enter"`. Verify the complete value with `describe` or an app validation marker.
118
+ Record the focus tap, then record `keyboard` with `text`. To submit, record a second `keyboard` step with `key: "enter"`. Verify the complete value with `describe` or an app validation marker.
130
119
 
131
120
  **Never `describe` or `screenshot` a non-secure field you just filled from `{{secret:…}}`.** Only a password field is redacted; a plain text input hands the resolved value back into your context, and an API key or token typed into one is the ordinary case. Submit or navigate away first, then verify the resulting screen.
132
121
 
133
- **`describe` reports focus on Chromium only.** iOS and Android leave it unset (it is a Vega/D-pad signal there), so those platforms have no live pre-typing focus check, and the value check afterwards is what proves the keys landed. On Chromium, read `focused` before recording `keyboard`.
122
+ **`describe` marks the field being typed into as `focused` on Chromium and the iOS simulator.** There, read it before recording `keyboard`. Elsewhere, the value check afterwards is what proves the keys landed.
134
123
 
135
124
  If characters are lost, restore the field with direct calls. Do not record a duplicate typing step. Polish the valid pair into `type:`. Its replay focus wait reads the runner's own tree, which does report focus on iOS, Android, and Chromium, but an unconfirmed poll falls through to typing rather than failing, so retain the committed-value check. Store credentials as `{{secret:NAME}}`. Never record a literal credential.
136
125
 
@@ -146,27 +135,13 @@ For every retained raw gesture, add an echo and a recorded result check.
146
135
 
147
136
  ### Live waits and checks
148
137
 
149
- Record `await-ui-element` through `e2e-add-step`. The recorder writes the step even when `toolResult.success` is false. Read `success` and `cause` after each check:
150
-
151
- - `unmet`: The tree was readable, but the condition was false. Restore the expected state or correct the selector or timeout. Record the check again, then delete the failed step after `e2e-finish-recording`.
152
- - `unreadable`: The wait ended without a trustworthy read. Restore the tree source and record the check again. Keep the failed step: the condition is unknown, not false.
153
- - `cancelled`: The caller stopped the wait. Record the check again. Keep the failed step: the condition is unknown, not false.
154
-
155
- Only `unmet` disproves the condition. Never delete a step during the recording.
156
-
157
- A stale `hidden` whose selector matches nothing replays as a silent pass: the unfalsifiable gate that [Record absence in three steps](#record-absence-in-three-steps) exists to prevent. Never proceed as though the gate passed. See the `await-ui-element` section of `argent-device-interact` for the full live condition and selector reference.
138
+ Record `await-ui-element` through `e2e-add-step`. The recorder writes the step even when `toolResult.success` is false, and its warning names the cause and what to do. Delete a failed wait only when the cause is `unmet`, after `e2e-finish-recording`; never during the recording.
158
139
 
159
- A wait inside `run-sequence` gets no recorder warning. Inspect the nested result. Any `success: false` fails the sequence during replay.
140
+ A stale `hidden` whose selector matches nothing replays as a silent pass: the unfalsifiable gate that [Record absence in three steps](#record-absence-in-three-steps) exists to prevent. Never proceed as though the gate passed.
160
141
 
161
- The live tool and e2e runner use [different trees](e2e-yaml.md#the-runner-tree-is-not-the-discovery-tree). After a successful wait, the recorder checks the same condition on the runner tree:
142
+ The live tool and e2e runner use [different trees](e2e-yaml.md#the-runner-tree-is-not-the-discovery-tree). After a successful wait, the recorder checks the same condition on the runner tree and warns when it does not hold there or could not be checked; the warning says what to rule out. If the trees really differ, keep the raw `await-ui-element` step: it replays on the tree it passed on.
162
143
 
163
- - No warning: The condition holds on both trees.
164
- - Mismatch: For `text`, first rule out a selector that matches more than one element. Then rule out a changed screen. If the trees really differ, keep the raw `await-ui-element` step: it replays on the tree it passed on.
165
- - Unreadable, slow, or cancelled check: The conversion is unknown. Restore the source or re-record before conversion.
166
-
167
- A warning does not reject the step. `e2e-finish-recording` repeats each warning below its step and reports dropped warnings.
168
-
169
- Do not edit YAML before finishing because edits can drop recorded verdicts. If the finish reports drops, record the waits again. Replay every conversion. Keep a raw tool only for `pollIntervalMs`, `bundleId`, or a cross-tree mismatch.
144
+ A warning does not reject the step. If `e2e-finish-recording` reports dropped warnings, record those waits again. Replay every conversion. Keep a raw tool only for `pollIntervalMs`, `bundleId`, or a cross-tree mismatch.
170
145
 
171
146
  ### Wrong turns
172
147
 
@@ -253,7 +228,7 @@ The condition grep matches a condition key with a scalar after it (`visible: Sav
253
228
  Resolve every hit and confirm:
254
229
 
255
230
  - Every element action uses a stable selector unless the fallback gate cleared and documented it.
256
- - **No `role:` stands as the only key under a `tap:`/`long-press:`.** That is the recorder's silent fallback, which warned about nothing. Replace it, or clear it through the fallback gate. A `role:` beside another field or a scope (`within`, `after`, `next`) is deliberate and needs no defence.
231
+ - **No `role:` stands as the only key under a `tap:`/`long-press:`.** It comes from the recorder's last-resort fallback or a hand edit. Replace it, or clear it through the fallback gate. A `role:` beside another field or a scope (`within`, `after`, `next`) is deliberate and needs no defence.
257
232
  - Every element-seeking gesture became `scroll-to`.
258
233
  - No device id or literal credential remains.
259
234
  - Every selector-bearing condition uses an explicit selector map without positional or data-derived values.
@@ -268,30 +243,15 @@ Resolve every hit and confirm:
268
243
 
269
244
  Run `e2e-execute` on the complete YAML with the absolute project root. For a fragment, verify its prerequisite before setting `prerequisiteAcknowledged: true`.
270
245
 
271
- `e2e-execute` takes exactly one test source: `name`, for a test saved under `.argent/e2e/` (or the legacy `.argent/flows/`), or `e2e_test_path`, an absolute path to any test `.yaml`.
272
-
273
- Over `argent link` or `ARGENT_TOOLS_URL`, the client sends the test file, its `run:` fragments, the tests that its `tool: e2e-execute` steps name, the snapshot baselines of each run and the file arguments of its `tool:` steps with the call. These steps work over a link:
274
-
275
- - `run:` fragments and the tests that `tool: e2e-execute` steps name, when they are under `project_root`, under its `.argent/e2e/` or `.argent/flows/`, or beside the test file. Keep them there.
276
- - `snapshot:` steps in the test and in its fragments. The baselines stay in the project. With `updateBaselines: true`, the client writes each new baseline when the run ends. A `baseline not written` line in the report means that the client did not save that baseline: fix the reason in the line and run again.
277
- - A `tool:` step whose file argument is an absolute path to a `.png` or `.yaml` file, such as `baselinePath` of `screenshot-diff`. Keep the real file under the project root or beside the test file, not behind a symlink to another place. Otherwise the step reports `error` when it runs, after the earlier steps acted.
278
- - A `tool: e2e-execute` step that names its test with `name` and an absolute `project_root` without a `..` segment. Keep the test that the step names under the project on the client, and spell `name` in the letter case of its file. That test uses its own baselines. A replay with `updateBaselines` also updates them, unless the step sets `updateBaselines` itself.
246
+ Over `argent link` or `ARGENT_TOOLS_URL`, the client uploads the test and the files its steps need. `e2e-execute`'s description lists what travels and which steps a linked run rejects (`script:`, recording tools, directory, app or output-directory arguments such as `reinstall-app`'s, relative or non-`.png`/`.yaml` file arguments, file paths built from several arguments). Beyond that list:
279
247
 
280
- These steps do not work over a link, in the test or in a fragment or test that it runs:
281
-
282
- - `script:`
283
- - a `tool:` step that takes a directory, an app or an output directory, such as `reinstall-app`, `gather-workspace-data`, or `screenshot-diff` with `outputDir`
284
- - a `tool:` step with a relative file path, or a file other than `.png` or `.yaml`
285
- - a `tool:` step whose tool builds the file path from several arguments, such as `e2e-read-prerequisite` with `name`
286
- - a `tool: e2e-execute` step with `e2e_test_path`, or with `name` and a relative `project_root` or one with a `..` segment
287
- - a `tool:` step that records an e2e test
288
-
289
- The tool-server checks the test, its fragments and the tests that it runs before the first step. The error lists each step that does not work over a link, and each `run:` or `tool: e2e-execute` step whose test the client could not send, with the reason. A fragment or a test that does not exist fails its step when the step runs. Run a test that needs these steps with no link and no `ARGENT_TOOLS_URL`, on the computer that runs the tool-server.
248
+ - Keep every file a step needs (`run:` fragments, tests named by `tool: e2e-execute`, `.png`/`.yaml` arguments such as `screenshot-diff`'s `baselinePath`) as a real file under `project_root`, its `.argent/e2e/` or `.argent/flows/`, or beside the test file, not behind a symlink to another place. Otherwise the step reports `error` when it runs, after the earlier steps acted.
249
+ - A `tool: e2e-execute` step works over a link only with `name` and an absolute `project_root` without a `..` segment. Spell `name` in the letter case of its file.
250
+ - A `baseline not written` line in the report means that the client did not save that baseline: fix the reason in the line and run again.
251
+ - The tool-server rejects unsupported steps before the first step, listing each with the reason; a fragment or test that does not exist fails only when its step runs. Run a test that needs a rejected step with no link and no `ARGENT_TOOLS_URL`, on the computer that runs the tool-server.
290
252
 
291
253
  Manual rescue invalidates the pass. An `errored` step was never evaluated: an `idle` wait whose tree source could not be read, a step that threw, an unresolvable `run:` target, or a `launch:` that did not start the app. Read the reason: most name the environment, but a failed `launch:` is a verdict about the app. Unconfirmed focus is not in this class at all: the replay focus poll has no failure return, so a `type:` step whose focus was never confirmed is scored a **pass**, and only the value check after typing catches it.
292
254
 
293
- **A passing step that carries a `warning` is a finding, not noise.** `await: { idle: true }` raises [six different warnings](e2e-yaml.md#idle-readiness) and they do not share one meaning. Two say the screen was moving; one says the wait ran out mid-hold and is repaired by raising the step's `timeout:`; one says the tree stayed empty; one says the tree did hold still and only the screenshot pairs were missing, so the capture path is what to check; one says the step ended with no evidence either way. No report separates intended motion from a load that never finished. Read which one it is, look at that screen, disclose what you found, and confirm the following step targets a stable element rather than stillness.
294
-
295
- A [selector-less gesture](e2e-yaml.md#directives) raises a warning of a different shape, not one of those six: a tree-source outage left it unsettled, so it dispatched blind and the green says only that the gesture was sent. Restore the source, usually by relaunching the app so the instrumentation loads. Accept it only where the app serves no tree at all, such as the [injection-free iOS form](reliability-and-recovery.md#terminally-non-injectable-ios-apps).
255
+ **A passing step that carries a `warning` is a finding, not noise.** `await: { idle: true }` raises [six different warnings](e2e-yaml.md#idle-readiness) and they do not share one meaning or one repair. No report separates intended motion from a load that never finished. Read which one it is, look at that screen, disclose what you found, and confirm the following step targets a stable element rather than stillness.
296
256
 
297
- One uninterrupted full pass completes a normal e2e test. `argent-qa-e2e` requires two consecutive passes of unchanged YAML. For CI, use `argent e2e run <name> [--platform ...]`; it exits non-zero on failure.
257
+ A [selector-less gesture](e2e-yaml.md#directives) warns in a different shape: it dispatched blind during a tree-source outage, so the green says only that the gesture was sent. Restore the source, usually by relaunching the app. Accept it only where the app serves no tree at all, such as the [injection-free iOS form](reliability-and-recovery.md#terminally-non-injectable-ios-apps).
@@ -24,10 +24,10 @@ Convert element-seeking swipes to `scroll-to`. Keep a coordinate swipe only when
24
24
 
25
25
  ### Run the gate when capture warns
26
26
 
27
- Work this gate as soon as capture warns that it kept a raw point, and equally when it silently recorded a role-only selector, which warns about nothing. Keep the source screen available and do these checks:
27
+ Work this gate as soon as capture warns that it kept a raw point or recorded a role-only selector. Keep the source screen available and do these checks:
28
28
 
29
29
  1. **iOS:** query plausible ids or labels with `native-find-views`. If no term is useful, call `native-full-hierarchy` with narrow fields and `maxDepth: 100`. `describe` and `native-describe-screen` are accessibility projections. They cannot prove that no YAML selector exists.
30
- 2. **Other platforms:** use `debugger-component-tree` for React Native; otherwise, use `describe`. Verify Android and Chromium candidates in step 3. Their discovery trees can omit runner elements.
30
+ 2. **Other platforms:** use `describe`; for React Native on Android, also `debugger-component-tree`, for testIDs `describe` omits. Verify Android and Chromium candidates in step 3. Their discovery trees can omit runner elements.
31
31
  3. Test each candidate in a scratch fragment with `assert: { visible: <candidate> }` on the valid screen. Inspect every failure before trying a better id, label, app, or container.
32
32
  4. If source is available, inspect its `testID`, `accessibilityIdentifier`, or `resource-id`. If none exists, report the missing stable id as the real fix.
33
33
 
@@ -39,12 +39,12 @@ QA e2e tests are stricter. They can keep a coordinate only for a genuinely unlab
39
39
 
40
40
  ## iOS selector recovery
41
41
 
42
- The full iOS runner tree exists only for an app launched by Argent with instrumentation.
42
+ On an iOS simulator, the full runner tree exists only for an app launched by Argent with instrumentation.
43
43
 
44
44
  1. If Metro, Expo, Xcode, an icon, or a prior process launched the app, call `restart-app`. Restore the source screen and retry capture. `launch-app` can only foreground the existing process.
45
45
  2. Tap capture does **not** wait for that connection. It makes one tree read and turns any failure straight into the kept-coordinates warning. A recording-time `restart-app` returns before the devtools connection opens, so the first tap after a restart can warn transiently. Re-record that tap once before escalating; only a warning that survives the retry is evidence of a real fault.
46
- 3. If the warning survives, call `native-devtools-status` with the same UDID and bundle id and follow its `message`, which names the one action that helps and says when to stop. `requiresRestart` covers only the states a fresh process fixes: an `unregistered` or `connecting` app reports it false, because it already launched under the terms a restart would recreate.
47
- 4. If an injectable app remains disconnected, call `stop-all-simulator-servers` once, **scoped to `devices: [<this simulator's UDID>]`**. One tool-server serves every agent on this Argent install, so an unscoped call tears down their devices too. This does not change app or account data. Then restart and check status again.
46
+ 3. If the warning survives, call `native-devtools-status` with the same UDID and bundle id and follow its `message`, which names the one action that helps and says when to stop.
47
+ 4. If an injectable app remains disconnected, call `stop-all-simulator-servers` once, **scoped to `devices: [<this simulator's UDID>]`**. This does not change app or account data. Then restart and check status again.
48
48
  5. If it still fails, report an instrumentation blocker. Do not replace selectors with coordinates in a QA e2e test.
49
49
 
50
50
  Use the same explicit UDID throughout. Multiple booted simulators are not an injection fault. Pass `--device <udid>` when CLI device selection is ambiguous.
@@ -60,9 +60,9 @@ Give the test a `launch:` step as usual. On iOS the launch waits the full devtoo
60
60
  - Raw `tool: await-ui-element` accessibility checks.
61
61
  - Point taps or long-presses derived from `describe`, each named by an echo.
62
62
  - A point focus tap plus a raw text-only `keyboard` with `delayMs: 500`, and a second raw `keyboard` with `key: "enter"` to submit.
63
- - Raw swipes with `momentum: false` because `scroll-to` needs the missing runner tree. Momentum-free scrolling keeps later coordinate taps valid. `momentum: false` needs `durationMs` of at least 150 and is rejected below it, so keep the 300 default or raise it.
63
+ - Raw swipes with `momentum: false` because `scroll-to` needs the missing runner tree. Momentum-free scrolling keeps later coordinate taps valid.
64
64
 
65
- Every point tap, long-press or coordinate swipe in such a test passes **carrying a warning** for as long as the app serves no tree: each [selector-less gesture](e2e-yaml.md#directives) dispatches unsettled. Nothing here repairs it. Accept the warnings, read each green as "the gesture was sent, not that it landed", and put an explicit `wait:` or a raw `tool: await-ui-element` before a gesture that follows a transition. Raw `tool:` steps take no settle, so they never carry that warning.
65
+ Every point tap, long-press or coordinate swipe in such a test passes **carrying the [selector-less gesture](e2e-yaml.md#directives) warning** for as long as the app serves no tree. Nothing here repairs it. Accept the warnings and put an explicit `wait:` or a raw `tool: await-ui-element` before a gesture that follows a transition. Raw `tool:` steps take no settle, so they never carry that warning.
66
66
 
67
67
  A recorded wait carries a different warning: it adds about one second and reports that the runner tree is unavailable. That warning is expected too. Keep the wait as a raw `tool:` step.
68
68
 
@@ -120,7 +120,7 @@ Classify before editing:
120
120
  Then:
121
121
 
122
122
  1. Record the first failure or divergence index and message.
123
- 2. Capture `screenshot` and `describe`. Use native or React Native discovery when needed.
123
+ 2. Look at the failed step's `screen` capture, then `describe` the current screen. Use native or React Native discovery when needed. After a `{{secret:…}}` step there is no capture: move off the field that holds the secret before you `describe` or take a `screenshot`.
124
124
  3. Compare actual state with the preceding echo and expected destination.
125
125
  4. Classify the cause: selector, screen, missing element, readiness, stale data, optional interstitial, or product behavior.
126
126
  5. State the diagnosis in one sentence before correcting it.