@deeeed/metamask-harness 0.2.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 (158) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +140 -0
  3. package/bin/mm-harness +99 -0
  4. package/docs/CHEATSHEET.md +61 -0
  5. package/docs/CLI-SPEC.md +915 -0
  6. package/docs/MENTAL-MODEL.md +295 -0
  7. package/docs/architecture.md +367 -0
  8. package/docs/extension-runtime-commands.md +60 -0
  9. package/docs/harness-cli.md +43 -0
  10. package/docs/live-adapter-contract.md +188 -0
  11. package/docs/package-boundaries.md +47 -0
  12. package/docs/perps-flow-catalog.md +235 -0
  13. package/docs/recipe-libraries.md +95 -0
  14. package/docs/runtime-file-conventions.md +36 -0
  15. package/library/actions/core/perps/_controller.mjs +727 -0
  16. package/library/actions/core/perps/assert_orders.mjs +53 -0
  17. package/library/actions/core/perps/assert_positions.mjs +52 -0
  18. package/library/actions/core/perps/close_orders.mjs +97 -0
  19. package/library/actions/core/perps/close_positions.mjs +118 -0
  20. package/library/actions/core/perps/ensure_orders.mjs +40 -0
  21. package/library/actions/core/perps/ensure_positions.mjs +37 -0
  22. package/library/actions/core/perps/place_order.mjs +201 -0
  23. package/library/actions/core/perps/read_account.mjs +30 -0
  24. package/library/actions/core/perps/read_orders.mjs +27 -0
  25. package/library/actions/core/perps/read_positions.mjs +27 -0
  26. package/library/actions/core/perps/start_state.mjs +92 -0
  27. package/library/actions/core/perps/teardown_state.mjs +86 -0
  28. package/library/actions/extension/perps/assert_orders.mjs +11 -0
  29. package/library/actions/extension/perps/assert_positions.mjs +11 -0
  30. package/library/actions/extension/perps/close_orders.mjs +8 -0
  31. package/library/actions/extension/perps/close_positions.mjs +8 -0
  32. package/library/actions/extension/perps/ensure_orders.mjs +4 -0
  33. package/library/actions/extension/perps/ensure_positions.mjs +4 -0
  34. package/library/actions/extension/perps/perps.mjs +730 -0
  35. package/library/actions/extension/perps/place_order.mjs +7 -0
  36. package/library/actions/extension/perps/read_orders.mjs +4 -0
  37. package/library/actions/extension/perps/read_positions.mjs +3 -0
  38. package/library/actions/extension/platform/cdp.mjs +541 -0
  39. package/library/actions/extension/ui/navigate.mjs +44 -0
  40. package/library/actions/extension/wallet/ensure_unlocked.mjs +36 -0
  41. package/library/actions/extension/wallet/read_state.mjs +27 -0
  42. package/library/actions/extension/wallet/select_account.mjs +48 -0
  43. package/library/actions/extension/wallet/setup.mjs +35 -0
  44. package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +185 -0
  45. package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +1662 -0
  46. package/library/actions/mobile/bridge-runtime/cdp-bridge.cjs +686 -0
  47. package/library/actions/mobile/bridge-runtime/lib/cdp-eval.cjs +110 -0
  48. package/library/actions/mobile/bridge-runtime/lib/config.cjs +39 -0
  49. package/library/actions/mobile/bridge-runtime/lib/issue-capture.cjs +446 -0
  50. package/library/actions/mobile/bridge-runtime/lib/target-discovery.cjs +204 -0
  51. package/library/actions/mobile/bridge-runtime/lib/ws-client.cjs +108 -0
  52. package/library/actions/mobile/bridge-runtime/setup-wallet.sh +442 -0
  53. package/library/actions/mobile/perps/assert_orders.mjs +11 -0
  54. package/library/actions/mobile/perps/assert_positions.mjs +11 -0
  55. package/library/actions/mobile/perps/close_orders.mjs +8 -0
  56. package/library/actions/mobile/perps/close_positions.mjs +8 -0
  57. package/library/actions/mobile/perps/ensure_orders.mjs +4 -0
  58. package/library/actions/mobile/perps/ensure_positions.mjs +4 -0
  59. package/library/actions/mobile/perps/perps.mjs +709 -0
  60. package/library/actions/mobile/perps/place_order.mjs +7 -0
  61. package/library/actions/mobile/perps/read_orders.mjs +4 -0
  62. package/library/actions/mobile/perps/read_positions.mjs +3 -0
  63. package/library/actions/mobile/platform/bridge.mjs +283 -0
  64. package/library/actions/mobile/ui/navigate.mjs +38 -0
  65. package/library/actions/mobile/wallet/ensure_unlocked.mjs +107 -0
  66. package/library/actions/mobile/wallet/home.mjs +35 -0
  67. package/library/actions/mobile/wallet/read_state.mjs +40 -0
  68. package/library/actions/mobile/wallet/select_account.mjs +48 -0
  69. package/library/actions/mobile/wallet/setup.mjs +220 -0
  70. package/library/flows/perps.flows.json +64 -0
  71. package/library/library.json +7 -0
  72. package/library/manifests/core.action-manifest.json +1282 -0
  73. package/library/manifests/extension.action-manifest.json +1749 -0
  74. package/library/manifests/mobile.action-manifest.json +1753 -0
  75. package/library/recipes/action-validation.extension.recipe.json +417 -0
  76. package/library/recipes/action-validation.mobile.recipe.json +422 -0
  77. package/library/recipes/order-lifecycle.core.recipe.json +78 -0
  78. package/library/recipes/perps-lifecycle.recipe.json +194 -0
  79. package/library/recipes/read-markets.core.recipe.json +38 -0
  80. package/library/recipes/smoke.extension.recipe.json +31 -0
  81. package/library/recipes/smoke.mobile.recipe.json +31 -0
  82. package/library/recipes/trading-lifecycle.core.recipe.json +76 -0
  83. package/orchestration/compat-overlays/README.md +19 -0
  84. package/orchestration/compat-overlays/mobile/README.md +13 -0
  85. package/orchestration/compat-overlays/mobile/rn81-message-event-source.patch +42 -0
  86. package/orchestration/core/cleanup.sh +37 -0
  87. package/orchestration/core/inject.sh +154 -0
  88. package/orchestration/doctor.mjs +72 -0
  89. package/orchestration/extension/cleanup.mjs +60 -0
  90. package/orchestration/extension/console-tail.mjs +228 -0
  91. package/orchestration/extension/ensure-browser.sh +416 -0
  92. package/orchestration/extension/ensure-ready.ts +185 -0
  93. package/orchestration/extension/extension-id.ts +107 -0
  94. package/orchestration/extension/inject.mjs +266 -0
  95. package/orchestration/extension/launch-browser.cjs +216 -0
  96. package/orchestration/extension/launch.sh +175 -0
  97. package/orchestration/extension/live.sh +320 -0
  98. package/orchestration/extension/pin-remote-flags.cjs +45 -0
  99. package/orchestration/extension/readiness.mjs +414 -0
  100. package/orchestration/extension/refresh-build.sh +190 -0
  101. package/orchestration/extension/runtime-decision.ts +445 -0
  102. package/orchestration/extension/runtime.ts +407 -0
  103. package/orchestration/extension/seed-fixture.sh +177 -0
  104. package/orchestration/extension/sidepanel-toggle.sh +291 -0
  105. package/orchestration/extension/snapshot-dist.sh +84 -0
  106. package/orchestration/extension/start-watch.sh +339 -0
  107. package/orchestration/extension/wallet-fixture-state.cjs +1086 -0
  108. package/orchestration/lib/activate-repo-node.sh +144 -0
  109. package/orchestration/lib/cli-color.mjs +84 -0
  110. package/orchestration/lib/cli-commands.mjs +243 -0
  111. package/orchestration/lib/cli-home.mjs +354 -0
  112. package/orchestration/lib/cli-ux.sh +252 -0
  113. package/orchestration/lib/cli-version.mjs +123 -0
  114. package/orchestration/lib/ensure-runner-deps.sh +56 -0
  115. package/orchestration/lib/harness-path.sh +55 -0
  116. package/orchestration/lib/hash-helpers.sh +44 -0
  117. package/orchestration/lib/json-field.sh +23 -0
  118. package/orchestration/lib/log-tui.mjs +304 -0
  119. package/orchestration/lib/open-debug.mjs +317 -0
  120. package/orchestration/lib/path-defaults.json +4 -0
  121. package/orchestration/lib/progress.mjs +107 -0
  122. package/orchestration/lib/recipe-paths.mjs +26 -0
  123. package/orchestration/lib/resolve-farmslot-ports.sh +144 -0
  124. package/orchestration/manifest.json +358 -0
  125. package/orchestration/mobile/cleanup.sh +192 -0
  126. package/orchestration/mobile/deps-markers.ts +21 -0
  127. package/orchestration/mobile/inject.sh +681 -0
  128. package/orchestration/mobile/launch.sh +137 -0
  129. package/orchestration/mobile/live.sh +125 -0
  130. package/orchestration/mobile/runtime-decision.ts +292 -0
  131. package/orchestration/porcelain/metamask-recipe +99 -0
  132. package/orchestration/porcelain/mm-recipe +1591 -0
  133. package/orchestration/porcelain/mme-recipe +1181 -0
  134. package/package.json +59 -0
  135. package/runner/extension/verify.sh +511 -0
  136. package/runner/mobile/verify.sh +501 -0
  137. package/runner/src/adapters.ts +601 -0
  138. package/runner/src/cli.ts +1820 -0
  139. package/runner/src/commands/debug.ts +44 -0
  140. package/runner/src/commands/fixtures.ts +99 -0
  141. package/runner/src/commands/launch.ts +397 -0
  142. package/runner/src/commands/logs.ts +60 -0
  143. package/runner/src/commands/shared.ts +138 -0
  144. package/runner/src/completions-cache.ts +86 -0
  145. package/runner/src/doctor.ts +203 -0
  146. package/runner/src/harness.ts +516 -0
  147. package/runner/src/heal-bounds.ts +179 -0
  148. package/runner/src/index.ts +6 -0
  149. package/runner/src/live-adapter-contract.ts +274 -0
  150. package/runner/src/manifest.ts +47 -0
  151. package/runner/src/mm-harness-cli.ts +488 -0
  152. package/runner/src/paths.ts +198 -0
  153. package/runner/src/recording-target.ts +147 -0
  154. package/runner/src/run-recording.ts +329 -0
  155. package/runner/src/runner.ts +108 -0
  156. package/runner/src/types.ts +57 -0
  157. package/scripts/completions.sh +125 -0
  158. package/scripts/install-completions.sh +62 -0
@@ -0,0 +1,417 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask Extension action E2E validation",
4
+ "description": "Exercises every Extension manifest-declared action against mme-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-action-validation && printf 'E2E_ACTION_VALIDATION extension\\n' > temp/recipe-action-validation/probe.txt && printf '{\"platform\":\"extension\",\"ok\":true}\n' > temp/recipe-action-validation/probe.json && printf 'extension log E2E_ACTION_VALIDATION\\n' > temp/recipe-action-validation/validation.log && echo E2E_ACTION_VALIDATION extension",
12
+ "next": "assert-command-exit",
13
+ "intent": "Prepare 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 extension",
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-action-validation/probe.txt",
39
+ "contains": "E2E_ACTION_VALIDATION extension",
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-action-validation/probe.json",
48
+ "assert": {
49
+ "path": "$.platform",
50
+ "operator": "eq",
51
+ "value": "extension"
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-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-action-validation/probe.txt",
72
+ "type": "log",
73
+ "category": "debug",
74
+ "label": "Extension 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": "wallet-unlock",
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": "cdp-probe",
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": "extension-account-list",
129
+ "intent": "Read wallet state for proof",
130
+ "detail": "Capture selected account and network state without mutating UI.",
131
+ "flow": "wallet"
132
+ },
133
+ "app-navigate-wallet": {
134
+ "action": "ui.navigate",
135
+ "next": "app-navigate-perps",
136
+ "intent": "Navigate to wallet home",
137
+ "detail": "Use the raw extension home hash route.",
138
+ "flow": "wallet",
139
+ "hash": "#/"
140
+ },
141
+ "app-navigate-perps": {
142
+ "action": "ui.navigate",
143
+ "next": "ui-wait-perps",
144
+ "intent": "Open the Perps tab",
145
+ "detail": "Use the raw extension Perps tab hash route.",
146
+ "flow": "ui",
147
+ "hash": "#/?tab=perps"
148
+ },
149
+ "ui-wait-perps": {
150
+ "action": "ui.wait_for",
151
+ "text": "Perps",
152
+ "expected": "visible",
153
+ "next": "ui-press",
154
+ "intent": "Wait for Perps UI to be visible",
155
+ "detail": "Use the generic UI wait action.",
156
+ "flow": "ui"
157
+ },
158
+ "ui-press": {
159
+ "action": "ui.press",
160
+ "selector": "body",
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
+ "offset": 120,
169
+ "next": "ui-scroll-into-view",
170
+ "intent": "Verify generic scroll works",
171
+ "detail": "Scroll the visible app surface through the platform adapter.",
172
+ "flow": "ui"
173
+ },
174
+ "ui-screenshot-perps": {
175
+ "action": "ui.screenshot",
176
+ "path": "screenshots/extension-perps-action-validation.png",
177
+ "timeout_ms": 5000,
178
+ "next": "wallet-navigate-perps",
179
+ "intent": "Capture Perps 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 extension hash",
187
+ "detail": "Use the raw extension Perps tab hash route.",
188
+ "flow": "ui",
189
+ "hash": "#/?tab=perps"
190
+ },
191
+ "perps-navigate-home": {
192
+ "action": "ui.navigate",
193
+ "next": "perps-navigate-market",
194
+ "intent": "Open Perps home with a raw extension hash",
195
+ "detail": "Use the raw extension Perps tab hash route.",
196
+ "flow": "perps",
197
+ "hash": "#/?tab=perps"
198
+ },
199
+ "perps-navigate-market": {
200
+ "action": "ui.navigate",
201
+ "next": "start-state",
202
+ "intent": "Open the ETH Perps market with a raw extension hash",
203
+ "detail": "Use the raw extension Perps market hash route.",
204
+ "flow": "perps",
205
+ "hash": "#/perps/market/ETH"
206
+ },
207
+ "ensure-clean": {
208
+ "action": "metamask.perps.ensure_positions",
209
+ "market": "ETH",
210
+ "next": "ensure-orders-clean",
211
+ "state": "none",
212
+ "intent": "Ensure no positions are open",
213
+ "detail": "Use the reusable Perps position precondition in selected-market cleanup mode.",
214
+ "flow": "perps setup",
215
+ "mode": "matching"
216
+ },
217
+ "assert-no-position": {
218
+ "action": "metamask.perps.assert_positions",
219
+ "market": "ETH",
220
+ "next": "read-orders-empty",
221
+ "state": "none",
222
+ "intent": "Confirm selected ETH position state is clean",
223
+ "detail": "Assert no position exists before placing a validation order.",
224
+ "flow": "perps setup",
225
+ "mode": "matching"
226
+ },
227
+ "read-orders-empty": {
228
+ "action": "metamask.perps.read_orders",
229
+ "market": "ETH",
230
+ "next": "assert-no-orders",
231
+ "intent": "Read order state after cleanup",
232
+ "detail": "Collect current ETH order state for proof.",
233
+ "flow": "perps setup"
234
+ },
235
+ "place-order": {
236
+ "action": "metamask.perps.place_order",
237
+ "market": "ETH",
238
+ "side": "long",
239
+ "amount": "11",
240
+ "leverage": 3,
241
+ "next": "read-positions",
242
+ "intent": "Place a small ETH 3x long validation order",
243
+ "detail": "Create an approximately $11 real Perps position through the runner action.",
244
+ "flow": "perps validation"
245
+ },
246
+ "read-positions": {
247
+ "action": "metamask.perps.read_positions",
248
+ "market": "ETH",
249
+ "next": "assert-position",
250
+ "intent": "Read ETH position after order placement",
251
+ "detail": "Collect current ETH position state for proof.",
252
+ "flow": "perps validation"
253
+ },
254
+ "assert-position": {
255
+ "action": "metamask.perps.assert_positions",
256
+ "market": "ETH",
257
+ "next": "read-orders-open",
258
+ "state": "open",
259
+ "intent": "Confirm the ETH validation position opened",
260
+ "detail": "Assert the order produced an open ETH position.",
261
+ "flow": "perps validation"
262
+ },
263
+ "read-orders-open": {
264
+ "action": "metamask.perps.read_orders",
265
+ "market": "ETH",
266
+ "next": "close-orders",
267
+ "intent": "Read ETH orders before cleanup",
268
+ "detail": "Collect order state before closing validation artifacts.",
269
+ "flow": "perps validation"
270
+ },
271
+ "assert-closed": {
272
+ "action": "metamask.perps.assert_positions",
273
+ "market": "ETH",
274
+ "next": "teardown-state",
275
+ "state": "none",
276
+ "intent": "Confirm global position cleanup completed",
277
+ "detail": "Assert no selected ETH position remains after cleanup.",
278
+ "flow": "perps teardown",
279
+ "mode": "matching"
280
+ },
281
+ "done": {
282
+ "action": "end",
283
+ "status": "pass",
284
+ "intent": "Finish action validation successfully",
285
+ "detail": "Mark the recipe run as passed after all checks complete.",
286
+ "flow": "teardown"
287
+ },
288
+ "ensure-orders-clean": {
289
+ "action": "metamask.perps.ensure_orders",
290
+ "market": "ETH",
291
+ "state": "none",
292
+ "next": "assert-no-position",
293
+ "intent": "Ensure no orders are open",
294
+ "detail": "Use the reusable Perps order precondition in selected-market cleanup mode.",
295
+ "flow": "perps setup",
296
+ "mode": "matching"
297
+ },
298
+ "assert-no-orders": {
299
+ "action": "metamask.perps.assert_orders",
300
+ "market": "ETH",
301
+ "state": "none",
302
+ "next": "place-order",
303
+ "intent": "Confirm selected ETH order state is clean",
304
+ "detail": "Assert no orders exist before placing a validation order.",
305
+ "flow": "perps setup",
306
+ "mode": "matching"
307
+ },
308
+ "close-orders": {
309
+ "action": "metamask.perps.close_orders",
310
+ "market": "ETH",
311
+ "next": "close-positions",
312
+ "intent": "Close ETH orders created by validation",
313
+ "detail": "Clean up any open ETH orders selected by the recipe parameters.",
314
+ "flow": "perps teardown"
315
+ },
316
+ "close-positions": {
317
+ "action": "metamask.perps.close_positions",
318
+ "market": "ETH",
319
+ "next": "assert-closed",
320
+ "intent": "Close the ETH validation position",
321
+ "detail": "Clean up the ETH position selected by the recipe parameters.",
322
+ "flow": "perps teardown"
323
+ },
324
+ "start-state": {
325
+ "action": "metamask.perps.start_state",
326
+ "profile": "clean_market_testnet",
327
+ "market": "ETH",
328
+ "positions": {
329
+ "state": "none",
330
+ "mode": "matching"
331
+ },
332
+ "orders": {
333
+ "state": "none",
334
+ "mode": "matching"
335
+ },
336
+ "page": "market",
337
+ "next": "ensure-clean",
338
+ "intent": "Prepare selected-market clean testnet Perps validation state",
339
+ "detail": "Close existing ETH testnet positions and orders before validation so unrelated leftovers cannot produce false confidence.",
340
+ "flow": "perps setup",
341
+ "mode": "matching"
342
+ },
343
+ "teardown-state": {
344
+ "action": "metamask.perps.teardown_state",
345
+ "market": "ETH",
346
+ "positions": {
347
+ "state": "none",
348
+ "mode": "matching"
349
+ },
350
+ "orders": {
351
+ "state": "none",
352
+ "mode": "matching"
353
+ },
354
+ "page": "home",
355
+ "next": "done",
356
+ "intent": "Return Perps to a selected-market clean home state",
357
+ "detail": "Close remaining ETH positions and orders so the account ends selected-market clean.",
358
+ "flow": "perps teardown",
359
+ "mode": "matching"
360
+ },
361
+ "app-hud": {
362
+ "action": "app.hud",
363
+ "text": "extension action parity validation",
364
+ "status": "running",
365
+ "next": "fixture",
366
+ "intent": "Start visible recipe progress HUD",
367
+ "detail": "Show the human reviewer what this validation is doing.",
368
+ "flow": "setup"
369
+ },
370
+ "select-account": {
371
+ "action": "metamask.wallet.select_account",
372
+ "address": "0x8dc623e964475d4d669da601fd15ea9125469003",
373
+ "next": "app-navigate-wallet",
374
+ "intent": "Select the validation account",
375
+ "detail": "Ensure the run uses the configured deterministic account.",
376
+ "flow": "wallet"
377
+ },
378
+ "ui-scroll-into-view": {
379
+ "action": "ui.scroll",
380
+ "selector": "body",
381
+ "scroll_into_view": true,
382
+ "next": "ui-screenshot-perps",
383
+ "intent": "Bring the extension page into view for proof",
384
+ "detail": "Exercise the Recipe v1 scroll_into_view contract over CDP.",
385
+ "flow": "ui"
386
+ },
387
+ "extension-account-list": {
388
+ "action": "ui.navigate",
389
+ "hash": "/account-list",
390
+ "next": "extension-account-search-visible",
391
+ "intent": "Open a harmless extension text input surface",
392
+ "detail": "Navigate to the account list so Recipe v1 can validate generic text input through a real DOM input.",
393
+ "flow": "ui"
394
+ },
395
+ "extension-account-search-visible": {
396
+ "action": "ui.wait_for",
397
+ "selector": "[data-testid=multichain-account-list-search] input",
398
+ "visible": true,
399
+ "timeout_ms": 10000,
400
+ "next": "ui-set-input-account-search",
401
+ "intent": "Wait for the account search input",
402
+ "detail": "Ensure the DOM input exists before setting text.",
403
+ "flow": "ui"
404
+ },
405
+ "ui-set-input-account-search": {
406
+ "action": "ui.set_input",
407
+ "selector": "[data-testid=multichain-account-list-search] input",
408
+ "value": "Account",
409
+ "next": "select-account",
410
+ "intent": "Set a visible account search value",
411
+ "detail": "Exercise ui.set_input on a harmless search field without changing wallet or Perps state.",
412
+ "flow": "ui"
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }