@deeeed/metamask-harness 0.17.5 → 0.19.0

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 (169) hide show
  1. package/CHANGELOG.md +1059 -0
  2. package/README.md +91 -140
  3. package/adapters/core/inject.sh +1 -6
  4. package/adapters/extension/console-tail.mjs +55 -24
  5. package/adapters/extension/ensure-browser.sh +6 -1
  6. package/adapters/extension/inject.mjs +7 -13
  7. package/adapters/extension/launch-browser.cjs +7 -1
  8. package/adapters/extension/launch-webpack.cjs +83 -0
  9. package/adapters/extension/launch.sh +8 -11
  10. package/adapters/extension/lib/chrome-args.cjs +8 -1
  11. package/adapters/extension/lib/macos-focus.cjs +32 -0
  12. package/adapters/extension/live.sh +12 -21
  13. package/adapters/extension/reattach.sh +1 -0
  14. package/adapters/extension/seed-fixture.sh +4 -12
  15. package/adapters/extension/sidepanel-toggle.sh +4 -1
  16. package/adapters/extension/stamp-runtime-title.cjs +58 -0
  17. package/adapters/extension/start-watch.sh +17 -4
  18. package/adapters/extension/stop-viewers.sh +1 -1
  19. package/adapters/extension/sync-webpack-dist.cjs +107 -0
  20. package/adapters/extension/verify.sh +2 -2
  21. package/adapters/manifest.json +53 -37
  22. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +16 -0
  23. package/adapters/mobile/bridge-runtime/console-forwarder.cjs +1 -1
  24. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
  25. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +2 -3
  26. package/adapters/mobile/cleanup.sh +16 -176
  27. package/adapters/mobile/inject.sh +91 -671
  28. package/adapters/mobile/launch-console-forwarder.cjs +39 -0
  29. package/adapters/mobile/open-device.sh +45 -7
  30. package/adapters/mobile/start-console-forwarder.sh +70 -0
  31. package/adapters/mobile/start-metro.sh +0 -41
  32. package/adapters/mobile/verify.sh +34 -83
  33. package/adapters/mobile/wait-for-bridge.sh +22 -8
  34. package/adapters/shared/harness-source-fingerprint.mjs +14 -12
  35. package/adapters/shared/resolve-slot-ports-core.mjs +17 -6
  36. package/adapters/shared/resolve-slot-ports.sh +17 -5
  37. package/adapters/shared/update-check-worker.mjs +43 -0
  38. package/bin/mm-harness +21 -2
  39. package/dist/adapters/core/surface.js +4 -1
  40. package/dist/adapters/extension/console-capture.js +95 -0
  41. package/dist/adapters/extension/product-config.js +110 -0
  42. package/dist/adapters/extension/runtime-decision.js +20 -2
  43. package/dist/adapters/extension/surface.js +22 -3
  44. package/dist/adapters/harness-freshness.js +49 -0
  45. package/dist/adapters/mobile/perps-env.js +43 -3
  46. package/dist/adapters/mobile/prepare.js +39 -7
  47. package/dist/adapters/mobile/surface.js +5 -2
  48. package/dist/adapters/resolve-slot-ports.js +2 -2
  49. package/dist/adapters/slot-ports.js +13 -16
  50. package/dist/adapters.js +56 -16
  51. package/dist/checkout-lock.js +27 -2
  52. package/dist/cli-color.js +19 -0
  53. package/dist/cli-commands.js +1 -1
  54. package/dist/cli.js +7 -18
  55. package/dist/command-contract.js +462 -0
  56. package/dist/command-journal.js +263 -0
  57. package/dist/commands/call.js +252 -57
  58. package/dist/commands/check.js +10 -4
  59. package/dist/commands/completion-candidates.js +17 -22
  60. package/dist/commands/device-target.js +27 -12
  61. package/dist/commands/doctor.js +106 -25
  62. package/dist/commands/fixtures.js +142 -35
  63. package/dist/commands/last.js +60 -0
  64. package/dist/commands/launch/extension.js +40 -17
  65. package/dist/commands/launch/index.js +207 -63
  66. package/dist/commands/launch/mobile.js +2 -0
  67. package/dist/commands/list-executables.js +187 -29
  68. package/dist/commands/logs.js +8 -6
  69. package/dist/commands/manifest.js +286 -35
  70. package/dist/commands/parse-args.js +68 -4
  71. package/dist/commands/provision.js +10 -4
  72. package/dist/commands/run-engine.js +772 -264
  73. package/dist/commands/run-report.js +12 -3
  74. package/dist/commands/run.js +378 -85
  75. package/dist/commands/shared.js +76 -4
  76. package/dist/commands/status-probe.js +4 -1
  77. package/dist/commands/status.js +2 -1
  78. package/dist/commands/stop.js +7 -2
  79. package/dist/commands/update.js +16 -28
  80. package/dist/completions-cache.js +1 -1
  81. package/dist/doctor.js +57 -10
  82. package/dist/harness.js +47 -137
  83. package/dist/heal-bounds.js +7 -2
  84. package/dist/json-stream.js +57 -0
  85. package/dist/live-adapter-contract.js +138 -32
  86. package/dist/manifest.js +161 -1
  87. package/dist/mm-harness-cli.js +146 -73
  88. package/dist/paths.js +2 -5
  89. package/dist/recipe-security.js +178 -0
  90. package/dist/run-diagnostics.js +261 -0
  91. package/dist/run-recording.js +1 -1
  92. package/dist/runner.js +140 -9
  93. package/docs/CONTRIBUTING.md +136 -0
  94. package/docs/QA.md +184 -0
  95. package/docs/RECIPES.md +122 -0
  96. package/docs/SECURITY.md +88 -0
  97. package/library/README.md +7 -3
  98. package/library/actions/core/perps/_controller.mjs +43 -56
  99. package/library/actions/core/perps/assert_orders.mjs +6 -7
  100. package/library/actions/core/perps/assert_positions.mjs +6 -7
  101. package/library/actions/core/perps/close_orders.mjs +2 -0
  102. package/library/actions/core/perps/close_positions.mjs +2 -0
  103. package/library/actions/core/perps/ensure_orders.mjs +4 -2
  104. package/library/actions/core/perps/ensure_positions.mjs +4 -2
  105. package/library/actions/core/perps/place_order.mjs +7 -3
  106. package/library/actions/core/perps/read_account.mjs +2 -2
  107. package/library/actions/core/perps/read_orders.mjs +2 -1
  108. package/library/actions/core/perps/read_positions.mjs +2 -1
  109. package/library/actions/core/wallet/list_accounts.mjs +95 -0
  110. package/library/actions/extension/perps/assert_orders.mjs +2 -1
  111. package/library/actions/extension/perps/assert_positions.mjs +2 -1
  112. package/library/actions/extension/perps/perps.mjs +43 -14
  113. package/library/actions/extension/platform/cdp.mjs +1 -0
  114. package/library/actions/extension/wallet/list_accounts.mjs +41 -0
  115. package/library/actions/mobile/perps/assert_orders.mjs +2 -1
  116. package/library/actions/mobile/perps/assert_positions.mjs +2 -1
  117. package/library/actions/mobile/perps/perps.mjs +40 -12
  118. package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
  119. package/library/library.json +1 -1
  120. package/library/manifests/core.action-manifest.json +1214 -396
  121. package/library/manifests/extension.action-manifest.json +1635 -728
  122. package/library/manifests/mobile.action-manifest.json +1740 -727
  123. package/library/recipes/app/lifecycle.android-smoke.mobile.recipe.json +63 -81
  124. package/library/recipes/perps/clean-market-testnet.core.recipe.json +44 -0
  125. package/library/recipes/perps/clean-market-testnet.recipe.json +49 -0
  126. package/library/recipes/perps/lifecycle.recipe.json +136 -180
  127. package/library/recipes/perps/order-lifecycle.core.recipe.json +71 -67
  128. package/library/recipes/perps/performance.background-resume.mobile.recipe.json +51 -67
  129. package/library/recipes/perps/performance.cold-start.mobile.recipe.json +51 -67
  130. package/library/recipes/perps/performance.mobile.recipe.json +37 -51
  131. package/library/recipes/perps/performance.warm-start.mobile.recipe.json +44 -59
  132. package/library/recipes/perps/read-markets.core.recipe.json +29 -31
  133. package/library/recipes/perps/smoke.core.recipe.json +29 -32
  134. package/library/recipes/perps/smoke.extension.recipe.json +41 -44
  135. package/library/recipes/perps/smoke.mobile.recipe.json +42 -44
  136. package/library/recipes/perps/trading-lifecycle.core.recipe.json +69 -65
  137. package/library/recipes/runner/action-validation.extension.recipe.json +312 -398
  138. package/library/recipes/runner/action-validation.mobile.recipe.json +316 -402
  139. package/library/recipes/runner/smoke.core.recipe.json +25 -0
  140. package/library/recipes/runner/smoke.extension.recipe.json +23 -24
  141. package/library/recipes/runner/smoke.mobile.recipe.json +23 -24
  142. package/library/recipes/wallet/smoke.extension.recipe.json +40 -0
  143. package/library/recipes/wallet/smoke.mobile.recipe.json +40 -0
  144. package/package.json +12 -5
  145. package/scripts/completions.sh +8 -11
  146. package/scripts/validate-human-outcomes.mjs +169 -0
  147. package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -185
  148. package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -1662
  149. package/adapters/mobile/overlay/compat/README.md +0 -28
  150. package/adapters/mobile/overlay/compat/rn81-message-event-source.patch +0 -42
  151. package/adapters/shared/resolve-farmslot-ports-core.mjs +0 -3
  152. package/adapters/shared/resolve-farmslot-ports.mjs +0 -5
  153. package/adapters/shared/resolve-farmslot-ports.sh +0 -7
  154. package/dist/adapters/extension/harness-freshness.js +0 -39
  155. package/dist/commands/flows.js +0 -62
  156. package/docs/ADAPTER-SURFACE.md +0 -119
  157. package/docs/CHEATSHEET.md +0 -61
  158. package/docs/CLI-SPEC.md +0 -1098
  159. package/docs/CODE-MAP.md +0 -62
  160. package/docs/DEBUG-HANDOVER.md +0 -36
  161. package/docs/MENTAL-MODEL.md +0 -295
  162. package/docs/UX-PRINCIPLES.md +0 -64
  163. package/docs/architecture.md +0 -398
  164. package/docs/live-adapter-contract.md +0 -188
  165. package/docs/package-boundaries.md +0 -47
  166. package/docs/perps-flow-catalog.md +0 -235
  167. package/docs/recipe-libraries.md +0 -301
  168. package/docs/runtime-file-conventions.md +0 -36
  169. package/library/flows/perps.flows.json +0 -64
@@ -1,421 +1,335 @@
1
1
  {
2
- "schema_version": 1,
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask Mobile action E2E validation",
4
4
  "description": "Exercises every Mobile manifest-declared action against mm-4 and leaves trace output for false-positive checks.",
5
- "validate": {
6
- "workflow": {
7
- "entry": "prepare-files",
8
- "nodes": {
9
- "prepare-files": {
10
- "action": "command",
11
- "cmd": "mkdir -p temp/recipe-runner.action-validation && printf 'E2E_ACTION_VALIDATION mobile\\n' > temp/recipe-runner.action-validation/probe.txt && printf '{\"platform\":\"mobile\",\"ok\":true}\n' > temp/recipe-runner.action-validation/probe.json && printf 'mobile log E2E_ACTION_VALIDATION\\n' > temp/recipe-runner.action-validation/validation.log && echo E2E_ACTION_VALIDATION mobile",
12
- "next": "assert-command-exit",
13
- "intent": "Prepare runner.action-validation probe files",
14
- "detail": "Create local files used to prove command/assert/log/artifact actions.",
15
- "flow": "setup"
16
- },
17
- "assert-command-exit": {
18
- "action": "assert_exit_code",
19
- "source": "prepare-files",
20
- "expected": 0,
21
- "next": "assert-command-output",
22
- "intent": "Verify the probe command exited successfully",
23
- "detail": "Check the previous command exit code.",
24
- "flow": "setup"
25
- },
26
- "assert-command-output": {
27
- "action": "assert_output",
28
- "source": "prepare-files",
29
- "stream": "stdout",
30
- "contains": "E2E_ACTION_VALIDATION mobile",
31
- "next": "assert-file",
32
- "intent": "Verify the probe command produced expected output",
33
- "detail": "Check stdout from the previous command.",
34
- "flow": "setup"
35
- },
36
- "assert-file": {
37
- "action": "assert_file",
38
- "path": "temp/recipe-runner.action-validation/probe.txt",
39
- "contains": "E2E_ACTION_VALIDATION mobile",
40
- "next": "assert-json",
41
- "intent": "Verify file assertions work",
42
- "detail": "Read the probe text file from the project workspace.",
43
- "flow": "setup"
44
- },
45
- "assert-json": {
46
- "action": "assert_json",
47
- "path": "temp/recipe-runner.action-validation/probe.json",
48
- "assert": {
49
- "path": "$.platform",
50
- "operator": "eq",
51
- "value": "mobile"
52
- },
53
- "next": "watch-logs",
54
- "intent": "Verify JSON assertions work",
55
- "detail": "Read the probe JSON file and compare $.platform.",
56
- "flow": "setup"
57
- },
58
- "watch-logs": {
59
- "action": "watch_logs",
60
- "path": "temp/recipe-runner.action-validation/validation.log",
61
- "contains": "E2E_ACTION_VALIDATION",
62
- "next": "index-artifacts",
63
- "intent": "Verify log watching works",
64
- "detail": "Scan the probe log for the validation marker.",
65
- "flow": "setup"
66
- },
67
- "index-artifacts": {
68
- "action": "index_artifacts",
69
- "artifacts": [
70
- {
71
- "path": "temp/recipe-runner.action-validation/probe.txt",
72
- "type": "log",
73
- "category": "debug",
74
- "label": "Mobile action validation probe"
75
- }
76
- ],
77
- "next": "wait",
78
- "intent": "Register the probe file as an artifact",
79
- "detail": "Add the validation probe to the run artifact manifest.",
80
- "flow": "setup"
81
- },
82
- "wait": {
83
- "action": "wait",
84
- "duration_ms": 1,
85
- "next": "status",
86
- "intent": "Verify the base wait action works",
87
- "detail": "Pause briefly before app/runtime checks.",
88
- "flow": "setup"
89
- },
90
- "status": {
91
- "action": "app.status",
92
- "next": "app-hud",
93
- "intent": "Read project runner compatibility status",
94
- "detail": "Confirm the app adapter reports its platform and shape.",
95
- "flow": "setup"
96
- },
97
- "cdp-probe": {
98
- "action": "cdp.target",
99
- "next": "fixture",
100
- "required": true,
101
- "intent": "Verify the automation channel is reachable",
102
- "detail": "Probe CDP/bridge connectivity before UI actions.",
103
- "flow": "setup"
104
- },
105
- "fixture": {
106
- "action": "metamask.wallet.fixture_status",
107
- "next": "wallet-setup",
108
- "intent": "Verify wallet fixture availability",
109
- "detail": "Check the preseeded wallet fixture required by validation.",
110
- "flow": "wallet"
111
- },
112
- "wallet-setup": {
113
- "action": "metamask.wallet.setup",
114
- "next": "wallet-unlock",
115
- "intent": "Verify wallet setup is ready",
116
- "detail": "Confirm onboarding/fixture state before driving the app.",
117
- "flow": "wallet"
118
- },
119
- "wallet-unlock": {
120
- "action": "metamask.wallet.ensure_unlocked",
121
- "next": "wallet-read-state",
122
- "intent": "Ensure the wallet is unlocked",
123
- "detail": "Unlock only if the app is currently locked.",
124
- "flow": "wallet"
125
- },
126
- "wallet-read-state": {
127
- "action": "metamask.wallet.read_state",
128
- "next": "select-account",
129
- "intent": "Read wallet state for proof",
130
- "detail": "Capture selected account and network state without mutating UI.",
131
- "flow": "wallet"
132
- },
133
- "select-account": {
134
- "action": "metamask.wallet.select_account",
135
- "address": "0x8dc623e964475d4d669da601fd15ea9125469003",
136
- "next": "app-navigate-wallet",
137
- "intent": "Select the validation account",
138
- "detail": "Ensure the run uses the configured deterministic account.",
139
- "flow": "wallet"
140
- },
141
- "app-navigate-wallet": {
142
- "action": "ui.navigate",
143
- "next": "ui-wait-wallet",
144
- "intent": "Navigate to wallet home",
145
- "detail": "Use the raw React Navigation WalletView route.",
146
- "flow": "wallet",
147
- "route": "WalletView"
148
- },
149
- "ui-wait-wallet": {
150
- "action": "ui.wait_for",
151
- "test_id": "wallet-screen",
152
- "expected": "present",
153
- "next": "ui-press",
154
- "intent": "Wait for wallet UI to be visible",
155
- "detail": "Use the generic UI wait action.",
156
- "flow": "ui"
157
- },
158
- "ui-press": {
159
- "action": "ui.press",
160
- "test_id": "wallet-account-copy-button",
161
- "next": "ui-scroll",
162
- "intent": "Verify generic press/tap works",
163
- "detail": "Drive a harmless UI press through the platform adapter.",
164
- "flow": "ui"
165
- },
166
- "ui-scroll": {
167
- "action": "ui.scroll",
168
- "test_id": "wallet-screen",
169
- "offset": 1000,
170
- "next": "ui-scroll-into-view",
171
- "intent": "Verify generic scroll works",
172
- "detail": "Scroll the visible app surface through the platform adapter.",
173
- "flow": "ui"
174
- },
175
- "ui-screenshot-wallet": {
176
- "action": "ui.screenshot",
177
- "path": "screenshots/mobile-wallet-runner.action-validation.png",
178
- "next": "wallet-navigate-perps",
179
- "intent": "Capture wallet visual proof",
180
- "detail": "Save a screenshot artifact after generic UI actions.",
181
- "flow": "ui"
182
- },
183
- "wallet-navigate-perps": {
184
- "action": "ui.navigate",
185
- "next": "perps-navigate-home",
186
- "intent": "Navigate to Perps with a raw app route",
187
- "detail": "Use the raw React Navigation PerpsMarketListView route.",
188
- "flow": "ui",
189
- "route": "PerpsMarketListView"
190
- },
191
- "perps-navigate-home": {
192
- "action": "ui.navigate",
193
- "next": "perps-navigate-market",
194
- "intent": "Open Perps home with a raw app route",
195
- "detail": "Use the raw React Navigation PerpsMarketListView route.",
196
- "flow": "perps",
197
- "route": "PerpsMarketListView"
198
- },
199
- "perps-navigate-market": {
200
- "action": "ui.navigate",
201
- "next": "start-state",
202
- "intent": "Open the ETH Perps market with raw route params",
203
- "detail": "Use the raw React Navigation PerpsMarketDetails route and market params.",
204
- "flow": "perps",
205
- "route": "PerpsMarketDetails",
206
- "params": {
207
- "market": {
208
- "symbol": "ETH"
209
- }
5
+ "workflow": {
6
+ "entry": "prepare-files",
7
+ "nodes": {
8
+ "prepare-files": {
9
+ "action": "command",
10
+ "cmd": "mkdir -p temp/recipe-runner.action-validation && printf 'E2E_ACTION_VALIDATION mobile\\n' > temp/recipe-runner.action-validation/probe.txt && printf '{\"platform\":\"mobile\",\"ok\":true}\n' > temp/recipe-runner.action-validation/probe.json && printf 'mobile log E2E_ACTION_VALIDATION\\n' > temp/recipe-runner.action-validation/validation.log && echo E2E_ACTION_VALIDATION mobile",
11
+ "next": "assert-command-exit",
12
+ "intent": "Prepare runner.action-validation probe files"
13
+ },
14
+ "assert-command-exit": {
15
+ "action": "assert_exit_code",
16
+ "source": "prepare-files",
17
+ "expected": 0,
18
+ "next": "assert-command-output",
19
+ "intent": "Verify the probe command exited successfully"
20
+ },
21
+ "assert-command-output": {
22
+ "action": "assert_output",
23
+ "source": "prepare-files",
24
+ "stream": "stdout",
25
+ "contains": "E2E_ACTION_VALIDATION mobile",
26
+ "next": "assert-file",
27
+ "intent": "Verify the probe command produced expected output"
28
+ },
29
+ "assert-file": {
30
+ "action": "assert_file",
31
+ "path": "temp/recipe-runner.action-validation/probe.txt",
32
+ "contains": "E2E_ACTION_VALIDATION mobile",
33
+ "next": "assert-json",
34
+ "intent": "Verify file assertions work"
35
+ },
36
+ "assert-json": {
37
+ "action": "assert_json",
38
+ "path": "temp/recipe-runner.action-validation/probe.json",
39
+ "assert": {
40
+ "path": "$.platform",
41
+ "operator": "eq",
42
+ "value": "mobile"
43
+ },
44
+ "next": "watch-logs",
45
+ "intent": "Verify JSON assertions work"
46
+ },
47
+ "watch-logs": {
48
+ "action": "watch_logs",
49
+ "path": "temp/recipe-runner.action-validation/validation.log",
50
+ "contains": "E2E_ACTION_VALIDATION",
51
+ "next": "index-artifacts",
52
+ "intent": "Verify log watching works"
53
+ },
54
+ "index-artifacts": {
55
+ "action": "index_artifacts",
56
+ "artifacts": [
57
+ {
58
+ "path": "temp/recipe-runner.action-validation/probe.txt",
59
+ "type": "log",
60
+ "category": "debug",
61
+ "label": "Mobile action validation probe"
210
62
  }
211
- },
212
- "ensure-clean": {
213
- "action": "metamask.perps.ensure_positions",
214
- "market": "ETH",
215
- "next": "ensure-orders-clean",
216
- "state": "none",
217
- "intent": "Ensure no positions are open",
218
- "detail": "Use the reusable Perps position precondition in selected-market cleanup mode.",
219
- "flow": "perps setup",
220
- "mode": "matching"
221
- },
222
- "assert-no-position": {
223
- "action": "metamask.perps.assert_positions",
224
- "market": "ETH",
225
- "next": "read-orders-empty",
63
+ ],
64
+ "next": "wait",
65
+ "intent": "Register the probe file as an artifact"
66
+ },
67
+ "wait": {
68
+ "action": "wait",
69
+ "duration_ms": 1,
70
+ "next": "status",
71
+ "intent": "Verify the base wait action works"
72
+ },
73
+ "status": {
74
+ "action": "app.status",
75
+ "next": "app-hud",
76
+ "intent": "Read project runner compatibility status"
77
+ },
78
+ "cdp-probe": {
79
+ "action": "cdp.target",
80
+ "next": "fixture",
81
+ "required": true,
82
+ "intent": "Verify the automation channel is reachable"
83
+ },
84
+ "fixture": {
85
+ "action": "metamask.wallet.fixture_status",
86
+ "next": "wallet-setup",
87
+ "intent": "Verify wallet fixture availability"
88
+ },
89
+ "wallet-setup": {
90
+ "action": "metamask.wallet.setup",
91
+ "next": "wallet-unlock",
92
+ "intent": "Verify wallet setup is ready"
93
+ },
94
+ "wallet-unlock": {
95
+ "action": "metamask.wallet.ensure_unlocked",
96
+ "next": "wallet-read-state",
97
+ "intent": "Ensure the wallet is unlocked"
98
+ },
99
+ "wallet-read-state": {
100
+ "action": "metamask.wallet.read_state",
101
+ "next": "wallet-list-accounts",
102
+ "intent": "Read wallet state for proof"
103
+ },
104
+ "wallet-list-accounts": {
105
+ "action": "metamask.wallet.list_accounts",
106
+ "next": "select-account",
107
+ "intent": "List wallet accounts for proof"
108
+ },
109
+ "select-account": {
110
+ "action": "metamask.wallet.select_account",
111
+ "address": "0x8dc623e964475d4d669da601fd15ea9125469003",
112
+ "next": "app-navigate-wallet",
113
+ "intent": "Select the validation account"
114
+ },
115
+ "app-navigate-wallet": {
116
+ "action": "ui.navigate",
117
+ "next": "ui-wait-wallet",
118
+ "intent": "Show the wallet home surface",
119
+ "route": "WalletView"
120
+ },
121
+ "ui-wait-wallet": {
122
+ "action": "ui.wait_for",
123
+ "test_id": "wallet-screen",
124
+ "expected": "present",
125
+ "next": "ui-press",
126
+ "intent": "Confirm the wallet surface is ready"
127
+ },
128
+ "ui-press": {
129
+ "action": "ui.press",
130
+ "test_id": "wallet-account-copy-button",
131
+ "next": "ui-scroll",
132
+ "intent": "Activate the visible control"
133
+ },
134
+ "ui-scroll": {
135
+ "action": "ui.scroll",
136
+ "test_id": "wallet-screen",
137
+ "offset": 1000,
138
+ "next": "ui-scroll-into-view",
139
+ "intent": "Expose the next visible content"
140
+ },
141
+ "ui-screenshot-wallet": {
142
+ "action": "ui.screenshot",
143
+ "path": "screenshots/mobile-wallet-runner.action-validation.png",
144
+ "next": "wallet-navigate-perps",
145
+ "intent": "Record the visible wallet state as evidence"
146
+ },
147
+ "wallet-navigate-perps": {
148
+ "action": "ui.navigate",
149
+ "next": "perps-navigate-home",
150
+ "intent": "Show the Perps home surface",
151
+ "route": "PerpsMarketListView"
152
+ },
153
+ "perps-navigate-home": {
154
+ "action": "ui.navigate",
155
+ "next": "perps-navigate-market",
156
+ "intent": "Show the Perps home surface",
157
+ "route": "PerpsMarketListView"
158
+ },
159
+ "perps-navigate-market": {
160
+ "action": "ui.navigate",
161
+ "next": "start-state",
162
+ "intent": "Show the ETH Perps market details",
163
+ "route": "PerpsMarketDetails",
164
+ "params": {
165
+ "market": {
166
+ "symbol": "ETH"
167
+ }
168
+ }
169
+ },
170
+ "ensure-clean": {
171
+ "action": "metamask.perps.ensure_positions",
172
+ "market": "ETH",
173
+ "next": "ensure-orders-clean",
174
+ "state": "none",
175
+ "intent": "Ensure no positions are open",
176
+ "mode": "matching"
177
+ },
178
+ "assert-no-position": {
179
+ "action": "metamask.perps.assert_positions",
180
+ "market": "ETH",
181
+ "next": "read-orders-empty",
182
+ "state": "none",
183
+ "intent": "Confirm selected ETH position state is clean",
184
+ "mode": "matching"
185
+ },
186
+ "read-orders-empty": {
187
+ "action": "metamask.perps.read_orders",
188
+ "market": "ETH",
189
+ "next": "assert-no-orders",
190
+ "intent": "Read order state after cleanup"
191
+ },
192
+ "place-order": {
193
+ "action": "metamask.perps.place_order",
194
+ "market": "ETH",
195
+ "side": "long",
196
+ "amount": "11",
197
+ "leverage": 3,
198
+ "next": "read-positions",
199
+ "intent": "Place a small ETH 3x long validation order"
200
+ },
201
+ "read-positions": {
202
+ "action": "metamask.perps.read_positions",
203
+ "market": "ETH",
204
+ "next": "assert-position",
205
+ "intent": "Read ETH position after order placement"
206
+ },
207
+ "assert-position": {
208
+ "action": "metamask.perps.assert_positions",
209
+ "market": "ETH",
210
+ "next": "read-orders-open",
211
+ "state": "open",
212
+ "intent": "Confirm the ETH validation position opened"
213
+ },
214
+ "read-orders-open": {
215
+ "action": "metamask.perps.read_orders",
216
+ "market": "ETH",
217
+ "next": "close-orders",
218
+ "intent": "Read ETH orders before cleanup"
219
+ },
220
+ "assert-closed": {
221
+ "action": "metamask.perps.assert_positions",
222
+ "market": "ETH",
223
+ "next": "teardown-state",
224
+ "state": "none",
225
+ "intent": "Confirm global position cleanup completed",
226
+ "mode": "matching"
227
+ },
228
+ "done": {
229
+ "action": "end",
230
+ "status": "pass"
231
+ },
232
+ "ensure-orders-clean": {
233
+ "action": "metamask.perps.ensure_orders",
234
+ "market": "ETH",
235
+ "state": "none",
236
+ "next": "assert-no-position",
237
+ "intent": "Ensure no orders are open",
238
+ "mode": "matching"
239
+ },
240
+ "assert-no-orders": {
241
+ "action": "metamask.perps.assert_orders",
242
+ "market": "ETH",
243
+ "state": "none",
244
+ "next": "place-order",
245
+ "intent": "Confirm selected ETH order state is clean",
246
+ "mode": "matching"
247
+ },
248
+ "close-orders": {
249
+ "action": "metamask.perps.close_orders",
250
+ "market": "ETH",
251
+ "next": "close-positions",
252
+ "intent": "Close ETH orders created by validation"
253
+ },
254
+ "close-positions": {
255
+ "action": "metamask.perps.close_positions",
256
+ "market": "ETH",
257
+ "next": "assert-closed",
258
+ "intent": "Close the ETH validation position"
259
+ },
260
+ "start-state": {
261
+ "action": "metamask.perps.start_state",
262
+ "profile": "clean_market_testnet",
263
+ "market": "ETH",
264
+ "positions": {
226
265
  "state": "none",
227
- "intent": "Confirm selected ETH position state is clean",
228
- "detail": "Assert no position exists before placing a validation order.",
229
- "flow": "perps setup",
230
266
  "mode": "matching"
231
267
  },
232
- "read-orders-empty": {
233
- "action": "metamask.perps.read_orders",
234
- "market": "ETH",
235
- "next": "assert-no-orders",
236
- "intent": "Read order state after cleanup",
237
- "detail": "Collect current ETH order state for proof.",
238
- "flow": "perps setup"
239
- },
240
- "place-order": {
241
- "action": "metamask.perps.place_order",
242
- "market": "ETH",
243
- "side": "long",
244
- "amount": "11",
245
- "leverage": 3,
246
- "next": "read-positions",
247
- "intent": "Place a small ETH 3x long validation order",
248
- "detail": "Create an approximately $11 real Perps position through the runner action.",
249
- "flow": "perps validation"
250
- },
251
- "read-positions": {
252
- "action": "metamask.perps.read_positions",
253
- "market": "ETH",
254
- "next": "assert-position",
255
- "intent": "Read ETH position after order placement",
256
- "detail": "Collect current ETH position state for proof.",
257
- "flow": "perps validation"
258
- },
259
- "assert-position": {
260
- "action": "metamask.perps.assert_positions",
261
- "market": "ETH",
262
- "next": "read-orders-open",
263
- "state": "open",
264
- "intent": "Confirm the ETH validation position opened",
265
- "detail": "Assert the order produced an open ETH position.",
266
- "flow": "perps validation"
267
- },
268
- "read-orders-open": {
269
- "action": "metamask.perps.read_orders",
270
- "market": "ETH",
271
- "next": "close-orders",
272
- "intent": "Read ETH orders before cleanup",
273
- "detail": "Collect order state before closing validation artifacts.",
274
- "flow": "perps validation"
275
- },
276
- "assert-closed": {
277
- "action": "metamask.perps.assert_positions",
278
- "market": "ETH",
279
- "next": "teardown-state",
268
+ "orders": {
280
269
  "state": "none",
281
- "intent": "Confirm global position cleanup completed",
282
- "detail": "Assert no selected ETH position remains after cleanup.",
283
- "flow": "perps teardown",
284
270
  "mode": "matching"
285
271
  },
286
- "done": {
287
- "action": "end",
288
- "status": "pass",
289
- "intent": "Finish action validation successfully",
290
- "detail": "Mark the recipe run as passed after all checks complete.",
291
- "flow": "teardown"
292
- },
293
- "ensure-orders-clean": {
294
- "action": "metamask.perps.ensure_orders",
295
- "market": "ETH",
272
+ "page": "market",
273
+ "next": "ensure-clean",
274
+ "intent": "Prepare selected-market clean testnet Perps validation state",
275
+ "mode": "matching"
276
+ },
277
+ "teardown-state": {
278
+ "action": "metamask.perps.teardown_state",
279
+ "market": "ETH",
280
+ "positions": {
296
281
  "state": "none",
297
- "next": "assert-no-position",
298
- "intent": "Ensure no orders are open",
299
- "detail": "Use the reusable Perps order precondition in selected-market cleanup mode.",
300
- "flow": "perps setup",
301
282
  "mode": "matching"
302
283
  },
303
- "assert-no-orders": {
304
- "action": "metamask.perps.assert_orders",
305
- "market": "ETH",
284
+ "orders": {
306
285
  "state": "none",
307
- "next": "place-order",
308
- "intent": "Confirm selected ETH order state is clean",
309
- "detail": "Assert no orders exist before placing a validation order.",
310
- "flow": "perps setup",
311
286
  "mode": "matching"
312
287
  },
313
- "close-orders": {
314
- "action": "metamask.perps.close_orders",
315
- "market": "ETH",
316
- "next": "close-positions",
317
- "intent": "Close ETH orders created by validation",
318
- "detail": "Clean up any open ETH orders selected by the recipe parameters.",
319
- "flow": "perps teardown"
320
- },
321
- "close-positions": {
322
- "action": "metamask.perps.close_positions",
323
- "market": "ETH",
324
- "next": "assert-closed",
325
- "intent": "Close the ETH validation position",
326
- "detail": "Clean up the ETH position selected by the recipe parameters.",
327
- "flow": "perps teardown"
328
- },
329
- "start-state": {
330
- "action": "metamask.perps.start_state",
331
- "profile": "clean_market_testnet",
332
- "market": "ETH",
333
- "positions": {
334
- "state": "none",
335
- "mode": "matching"
336
- },
337
- "orders": {
338
- "state": "none",
339
- "mode": "matching"
340
- },
341
- "page": "market",
342
- "next": "ensure-clean",
343
- "intent": "Prepare selected-market clean testnet Perps validation state",
344
- "detail": "Close existing ETH testnet positions and orders before validation so unrelated leftovers cannot produce false confidence.",
345
- "flow": "perps setup",
346
- "mode": "matching"
347
- },
348
- "teardown-state": {
349
- "action": "metamask.perps.teardown_state",
350
- "market": "ETH",
351
- "positions": {
352
- "state": "none",
353
- "mode": "matching"
354
- },
355
- "orders": {
356
- "state": "none",
357
- "mode": "matching"
358
- },
359
- "page": "home",
360
- "next": "done",
361
- "intent": "Return Perps to a selected-market clean home state",
362
- "detail": "Close remaining ETH positions and orders so the account ends selected-market clean.",
363
- "flow": "perps teardown",
364
- "mode": "matching"
365
- },
366
- "app-hud": {
367
- "action": "app.hud",
368
- "text": "mobile action parity validation",
369
- "status": "running",
370
- "next": "cdp-probe",
371
- "intent": "Start visible recipe progress HUD",
372
- "detail": "Show the human reviewer what this validation is doing.",
373
- "flow": "setup"
374
- },
375
- "ui-scroll-into-view": {
376
- "action": "ui.scroll",
377
- "test_id": "wallet-screen",
378
- "scroll_into_view": true,
379
- "offset": 40,
380
- "next": "app-navigate-network-selector",
381
- "intent": "Bring the wallet screen into view for proof",
382
- "detail": "Exercise the Recipe v1 scroll_into_view contract on React Native.",
383
- "flow": "ui"
384
- },
385
- "app-navigate-network-selector": {
386
- "action": "ui.press",
387
- "test_id": "import-token-button",
388
- "next": "wait-token-search-input",
389
- "intent": "Open token search input",
390
- "detail": "Press the wallet Import token button so Recipe v1 can validate generic text input through a real React Native TextInput.",
391
- "flow": "ui"
392
- },
393
- "ui-set-input-network": {
394
- "action": "ui.set_input",
395
- "test_id": "input-search-asset",
396
- "value": "ETH",
397
- "next": "return-wallet-after-input",
398
- "intent": "Set a visible token search value",
399
- "detail": "Exercise ui.set_input on a harmless token search field without changing wallet or Perps state.",
400
- "flow": "ui"
401
- },
402
- "return-wallet-after-input": {
403
- "action": "ui.navigate",
404
- "next": "ui-screenshot-wallet",
405
- "intent": "Return to wallet after input validation",
406
- "detail": "Use the raw React Navigation WalletView route before continuing generic wallet UI proof.",
407
- "flow": "ui",
408
- "route": "WalletView"
409
- },
410
- "wait-token-search-input": {
411
- "action": "ui.wait_for",
412
- "test_id": "input-search-asset",
413
- "expected": "present",
414
- "next": "ui-set-input-network",
415
- "intent": "Wait for token search input",
416
- "detail": "Wait until the Import Token search field is mounted before setting text.",
417
- "flow": "ui"
418
- }
288
+ "page": "home",
289
+ "next": "done",
290
+ "intent": "Return Perps to a selected-market clean home state",
291
+ "mode": "matching"
292
+ },
293
+ "app-hud": {
294
+ "action": "app.hud",
295
+ "text": "mobile action parity validation",
296
+ "status": "running",
297
+ "next": "cdp-probe",
298
+ "intent": "Start visible recipe progress HUD"
299
+ },
300
+ "ui-scroll-into-view": {
301
+ "action": "ui.scroll",
302
+ "test_id": "wallet-screen",
303
+ "scroll_into_view": true,
304
+ "offset": 40,
305
+ "next": "app-navigate-network-selector",
306
+ "intent": "Expose the wallet content needed for proof"
307
+ },
308
+ "app-navigate-network-selector": {
309
+ "action": "ui.press",
310
+ "test_id": "import-token-button",
311
+ "next": "wait-token-search-input",
312
+ "intent": "Open token search input"
313
+ },
314
+ "ui-set-input-network": {
315
+ "action": "ui.set_input",
316
+ "test_id": "input-search-asset",
317
+ "value": "ETH",
318
+ "next": "return-wallet-after-input",
319
+ "intent": "Filter the visible token list"
320
+ },
321
+ "return-wallet-after-input": {
322
+ "action": "ui.navigate",
323
+ "next": "ui-screenshot-wallet",
324
+ "intent": "Return to wallet after input validation",
325
+ "route": "WalletView"
326
+ },
327
+ "wait-token-search-input": {
328
+ "action": "ui.wait_for",
329
+ "test_id": "input-search-asset",
330
+ "expected": "present",
331
+ "next": "ui-set-input-network",
332
+ "intent": "Confirm token search is ready"
419
333
  }
420
334
  }
421
335
  }