@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
@@ -12,6 +12,7 @@
12
12
  "index_artifacts",
13
13
  "end",
14
14
  "call",
15
+ "switch",
15
16
  "app.status"
16
17
  ],
17
18
  "action_metadata": {
@@ -25,7 +26,28 @@
25
26
  "intent": "Run a shell command from the project root"
26
27
  }
27
28
  }
28
- ]
29
+ ],
30
+ "schema": {
31
+ "type": "object",
32
+ "properties": {
33
+ "cmd": {
34
+ "type": "string"
35
+ },
36
+ "command": {
37
+ "type": "string"
38
+ },
39
+ "cwd": {
40
+ "type": "string"
41
+ },
42
+ "timeout_ms": {
43
+ "type": "number"
44
+ },
45
+ "allow_failure": {
46
+ "type": "boolean"
47
+ }
48
+ },
49
+ "additionalProperties": false
50
+ }
29
51
  },
30
52
  "wait": {
31
53
  "description": "Base wait action.",
@@ -37,7 +59,44 @@
37
59
  "intent": "Base wait action"
38
60
  }
39
61
  }
40
- ]
62
+ ],
63
+ "schema": {
64
+ "type": "object",
65
+ "properties": {
66
+ "duration_ms": {
67
+ "type": "integer"
68
+ },
69
+ "ms": {
70
+ "type": "integer"
71
+ }
72
+ },
73
+ "additionalProperties": false
74
+ }
75
+ },
76
+ "switch": {
77
+ "description": "Choose a graph branch when one resolved string equals another.",
78
+ "examples": [
79
+ {
80
+ "node": {
81
+ "action": "switch",
82
+ "value": "{{params.mode}}",
83
+ "equals": "background_resume",
84
+ "cases": { "match": "background" },
85
+ "default": "warm",
86
+ "intent": "Choose the requested lifecycle preparation path"
87
+ }
88
+ }
89
+ ],
90
+ "schema": {
91
+ "type": "object",
92
+ "properties": {
93
+ "value": { "type": "string" },
94
+ "equals": { "type": "string" }
95
+ },
96
+ "required": ["value", "equals"],
97
+ "additionalProperties": false
98
+ },
99
+ "result_cases": ["match"]
41
100
  },
42
101
  "watch_logs": {
43
102
  "description": "Base log assertion/capture action.",
@@ -49,7 +108,29 @@
49
108
  "intent": "Base log assertion/capture action"
50
109
  }
51
110
  }
52
- ]
111
+ ],
112
+ "schema": {
113
+ "type": "object",
114
+ "properties": {
115
+ "path": {
116
+ "type": "string"
117
+ },
118
+ "contains": {
119
+ "type": "string"
120
+ },
121
+ "scope": {
122
+ "type": "string",
123
+ "enum": [
124
+ "run",
125
+ "file"
126
+ ]
127
+ }
128
+ },
129
+ "required": [
130
+ "path"
131
+ ],
132
+ "additionalProperties": false
133
+ }
53
134
  },
54
135
  "index_artifacts": {
55
136
  "description": "Index extra recipe-authored artifacts that already exist on disk.",
@@ -68,7 +149,55 @@
68
149
  "intent": "Register a pre-existing report artifact"
69
150
  }
70
151
  }
71
- ]
152
+ ],
153
+ "schema": {
154
+ "type": "object",
155
+ "properties": {
156
+ "artifacts": {
157
+ "type": "array",
158
+ "items": {
159
+ "type": [
160
+ "string",
161
+ "object"
162
+ ],
163
+ "properties": {
164
+ "path": {
165
+ "type": "string"
166
+ },
167
+ "type": {
168
+ "type": "string"
169
+ },
170
+ "label": {
171
+ "type": "string"
172
+ },
173
+ "nodeId": {
174
+ "type": "string"
175
+ },
176
+ "mimeType": {
177
+ "type": "string"
178
+ },
179
+ "category": {
180
+ "type": "string"
181
+ },
182
+ "proofTarget": {
183
+ "type": "string"
184
+ },
185
+ "covers": {
186
+ "type": "array",
187
+ "items": {
188
+ "type": "string"
189
+ }
190
+ }
191
+ },
192
+ "additionalProperties": false
193
+ }
194
+ }
195
+ },
196
+ "required": [
197
+ "artifacts"
198
+ ],
199
+ "additionalProperties": false
200
+ }
72
201
  },
73
202
  "end": {
74
203
  "description": "Base terminal action.",
@@ -92,7 +221,22 @@
92
221
  "intent": "Assert that a project file exists and optionally contains text"
93
222
  }
94
223
  }
95
- ]
224
+ ],
225
+ "schema": {
226
+ "type": "object",
227
+ "properties": {
228
+ "path": {
229
+ "type": "string"
230
+ },
231
+ "contains": {
232
+ "type": "string"
233
+ }
234
+ },
235
+ "required": [
236
+ "path"
237
+ ],
238
+ "additionalProperties": false
239
+ }
96
240
  },
97
241
  "assert_json": {
98
242
  "description": "Assert a JSON file value with a JSONPath-style selector.",
@@ -109,7 +253,69 @@
109
253
  "intent": "Assert a JSON file value with a JSONPath-style selector"
110
254
  }
111
255
  }
112
- ]
256
+ ],
257
+ "schema": {
258
+ "type": "object",
259
+ "properties": {
260
+ "path": {
261
+ "type": "string"
262
+ },
263
+ "assert": {
264
+ "type": "object",
265
+ "properties": {
266
+ "path": {
267
+ "type": "string"
268
+ },
269
+ "operator": {
270
+ "type": "string"
271
+ },
272
+ "value": {
273
+ "type": [
274
+ "string",
275
+ "number",
276
+ "integer",
277
+ "boolean",
278
+ "object",
279
+ "array"
280
+ ],
281
+ "items": {
282
+ "type": [
283
+ "string",
284
+ "number",
285
+ "integer",
286
+ "boolean",
287
+ "object"
288
+ ]
289
+ }
290
+ },
291
+ "all": {
292
+ "type": "array",
293
+ "items": {
294
+ "type": "object"
295
+ }
296
+ },
297
+ "any": {
298
+ "type": "array",
299
+ "items": {
300
+ "type": "object"
301
+ }
302
+ },
303
+ "none": {
304
+ "type": "array",
305
+ "items": {
306
+ "type": "object"
307
+ }
308
+ }
309
+ },
310
+ "additionalProperties": false
311
+ }
312
+ },
313
+ "required": [
314
+ "path",
315
+ "assert"
316
+ ],
317
+ "additionalProperties": false
318
+ }
113
319
  },
114
320
  "assert_exit_code": {
115
321
  "description": "Assert the exit code captured from a command node output.",
@@ -122,7 +328,22 @@
122
328
  "intent": "Assert the exit code captured from a command node output"
123
329
  }
124
330
  }
125
- ]
331
+ ],
332
+ "schema": {
333
+ "type": "object",
334
+ "properties": {
335
+ "source": {
336
+ "type": "string"
337
+ },
338
+ "node": {
339
+ "type": "string"
340
+ },
341
+ "expected": {
342
+ "type": "number"
343
+ }
344
+ },
345
+ "additionalProperties": false
346
+ }
126
347
  },
127
348
  "assert_output": {
128
349
  "description": "Assert stdout or stderr captured from a command node output.",
@@ -136,7 +357,77 @@
136
357
  "intent": "Assert stdout or stderr captured from a command node output"
137
358
  }
138
359
  }
139
- ]
360
+ ],
361
+ "schema": {
362
+ "type": "object",
363
+ "properties": {
364
+ "source": {
365
+ "type": "string"
366
+ },
367
+ "node": {
368
+ "type": "string"
369
+ },
370
+ "stream": {
371
+ "type": "string"
372
+ },
373
+ "contains": {
374
+ "type": "string"
375
+ },
376
+ "match": {
377
+ "type": "string"
378
+ },
379
+ "assert": {
380
+ "type": "object",
381
+ "properties": {
382
+ "path": {
383
+ "type": "string"
384
+ },
385
+ "operator": {
386
+ "type": "string"
387
+ },
388
+ "value": {
389
+ "type": [
390
+ "string",
391
+ "number",
392
+ "integer",
393
+ "boolean",
394
+ "object",
395
+ "array"
396
+ ],
397
+ "items": {
398
+ "type": [
399
+ "string",
400
+ "number",
401
+ "integer",
402
+ "boolean",
403
+ "object"
404
+ ]
405
+ }
406
+ },
407
+ "all": {
408
+ "type": "array",
409
+ "items": {
410
+ "type": "object"
411
+ }
412
+ },
413
+ "any": {
414
+ "type": "array",
415
+ "items": {
416
+ "type": "object"
417
+ }
418
+ },
419
+ "none": {
420
+ "type": "array",
421
+ "items": {
422
+ "type": "object"
423
+ }
424
+ }
425
+ },
426
+ "additionalProperties": false
427
+ }
428
+ },
429
+ "additionalProperties": false
430
+ }
140
431
  },
141
432
  "app.status": {
142
433
  "description": "Report the core checkout shape and headless compatibility mode for the perps controller.",
@@ -148,260 +439,77 @@
148
439
  "next": "done"
149
440
  }
150
441
  }
151
- ]
442
+ ],
443
+ "schema": {
444
+ "type": "object",
445
+ "properties": {},
446
+ "additionalProperties": false
447
+ }
152
448
  },
153
449
  "call": {
154
- "description": "Invoke a named sub-recipe flow by ref and run its steps inline.",
450
+ "description": "Invoke a named recipe by ref and run its steps inline.",
155
451
  "examples": [
156
452
  {
157
453
  "node": {
158
454
  "action": "call",
159
455
  "ref": "shared/setup",
160
- "intent": "Run a shared sub-recipe flow"
161
- }
162
- }
163
- ]
164
- },
165
- "metamask.perps.read_positions": {
166
- "description": "Read live Perps positions directly from the perps controller (HyperLiquid testnet, HTTP read-only) and return the selected subset.",
167
- "examples": [
168
- {
169
- "description": "Read every live position for the configured account",
170
- "node": {
171
- "action": "metamask.perps.read_positions",
172
- "mode": "all",
173
- "intent": "Read Perps positions from the headless controller"
456
+ "intent": "Run a shared recipe"
174
457
  }
175
458
  }
176
459
  ]
177
- },
178
- "metamask.perps.read_orders": {
179
- "description": "Read live Perps open orders directly from the perps controller (HyperLiquid testnet, HTTP read-only) and return the selected subset.",
180
- "examples": [
181
- {
182
- "description": "Read every live open order for the configured account",
183
- "node": {
184
- "action": "metamask.perps.read_orders",
185
- "mode": "all",
186
- "intent": "Read Perps open orders from the headless controller"
187
- }
188
- }
189
- ]
190
- },
191
- "metamask.perps.read_account": {
192
- "description": "Read live Perps account state (balances, margin) directly from the perps controller (HyperLiquid testnet, HTTP read-only).",
193
- "examples": [
194
- {
195
- "description": "Read account state for the configured account",
196
- "node": {
197
- "action": "metamask.perps.read_account",
198
- "intent": "Read Perps account state from the headless controller"
199
- }
200
- }
201
- ]
202
- },
203
- "metamask.perps.place_order": {
204
- "description": "Place a real Perps order on HyperLiquid testnet by driving the headless perps controller placeOrder() through the full signing/provider path. Testnet only Supports market (default) and resting limit orders (order_type=limit with price/offset_pct). The network field in examples is an authoring convention: only start_state/teardown_state enforce the network (ensureNetwork); the mutation handlers themselves do not read it.",
205
- "examples": [
206
- {
207
- "description": "Place a small BTC long market order on testnet",
208
- "node": {
209
- "action": "metamask.perps.place_order",
210
- "market": "BTC",
211
- "side": "long",
212
- "notional": "11",
213
- "leverage": 2,
214
- "intent": "Place the requested Perps order via the headless controller",
215
- "network": "testnet"
216
- }
217
- },
218
- {
219
- "description": "Place a resting BTC limit BUY 30%% below mid on testnet (does not fill)",
220
- "node": {
221
- "action": "metamask.perps.place_order",
222
- "market": "BTC",
223
- "side": "long",
224
- "order_type": "limit",
225
- "offset_pct": -30,
226
- "notional": "11",
227
- "leverage": 2,
228
- "intent": "Place a resting Perps limit order via the headless controller",
229
- "network": "testnet"
230
- }
231
- }
232
- ]
233
- },
234
- "metamask.perps.close_positions": {
235
- "description": "Close selected live Perps positions on HyperLiquid testnet by driving the headless perps controller closePosition() through the full signing/provider path. Testnet only. The network field in examples is an authoring convention: only start_state/teardown_state enforce the network (ensureNetwork); the mutation handlers themselves do not read it.",
236
- "examples": [
237
- {
238
- "description": "Close the BTC position on testnet",
239
- "node": {
240
- "action": "metamask.perps.close_positions",
241
- "market": "BTC",
242
- "intent": "Close selected Perps positions via the headless controller",
243
- "network": "testnet"
244
- }
245
- }
246
- ]
247
- },
248
- "metamask.perps.assert_positions": {
249
- "description": "Assert selected live Perps positions are present or absent via the headless controller standalone read path. Throws on mismatch.",
250
- "examples": [
251
- {
252
- "description": "Assert BTC position is open",
253
- "node": {
254
- "action": "metamask.perps.assert_positions",
255
- "state": "open",
256
- "market": "BTC",
257
- "intent": "Assert the expected Perps position state via the headless controller"
258
- }
259
- }
260
- ]
261
- },
262
- "metamask.perps.ensure_positions": {
263
- "description": "Higher-level wrapper that reads selected positions, places or closes via the headless controller as needed, then asserts the final position state. Testnet only. The network field in examples is an authoring convention: only start_state/teardown_state enforce the network (ensureNetwork); the mutation handlers themselves do not read it.",
264
- "examples": [
265
- {
266
- "description": "Ensure no BTC position before the proof window",
267
- "node": {
268
- "action": "metamask.perps.ensure_positions",
269
- "state": "none",
270
- "market": "BTC",
271
- "intent": "Converge Perps positions to the requested state via the headless controller",
272
- "network": "testnet"
273
- }
274
- }
275
- ]
276
- },
277
- "metamask.perps.close_orders": {
278
- "description": "Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested. Cancel selected live Perps open orders. Use selector/mode params to cancel matching symbols or all orders. The network field in examples is an authoring convention: only start_state/teardown_state enforce the network (ensureNetwork); the mutation handlers themselves do not read it.",
279
- "examples": [
280
- {
281
- "description": "Cancel every open order",
282
- "node": {
283
- "action": "metamask.perps.close_orders",
284
- "mode": "all",
285
- "intent": "Cancel selected Perps orders before continuing",
286
- "network": "testnet"
287
- }
288
- },
289
- {
290
- "description": "Cancel BTC orders only",
291
- "node": {
292
- "action": "metamask.perps.close_orders",
293
- "market": "BTC",
294
- "intent": "Cancel selected Perps orders before continuing",
295
- "network": "testnet"
296
- }
297
- }
298
- ]
299
- },
300
- "metamask.perps.assert_orders": {
301
- "description": "Assert selected live Perps open orders are present or absent.",
302
- "examples": [
303
- {
304
- "description": "Assert no BTC open orders",
305
- "node": {
306
- "action": "metamask.perps.assert_orders",
307
- "state": "none",
308
- "market": "BTC",
309
- "intent": "Assert the expected Perps open order state"
310
- }
311
- }
312
- ]
313
- },
314
- "metamask.perps.ensure_orders": {
315
- "description": "Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested.Higher-level wrapper that reads selected orders, cancels when needed, then asserts final order state. The network field in examples is an authoring convention: only start_state/teardown_state enforce the network (ensureNetwork); the mutation handlers themselves do not read it.",
316
- "examples": [
317
- {
318
- "description": "Ensure no open orders before proof window",
319
- "node": {
320
- "action": "metamask.perps.ensure_orders",
321
- "state": "none",
322
- "mode": "all",
323
- "intent": "Converge Perps orders to the requested state",
324
- "network": "testnet"
325
- }
326
- }
327
- ]
328
- },
329
- "metamask.perps.start_state": {
330
- "description": "Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested.Recommended configurable Perps start state that composes reusable domain operations before the proof window. Headless: converges POSITION and ORDER baselines on testnet via the controller; no navigation/page/HUD.",
331
- "examples": [
332
- {
333
- "description": "Clean BTC testnet market state",
334
- "node": {
335
- "action": "metamask.perps.start_state",
336
- "profile": "clean_market_testnet",
337
- "market": "BTC",
338
- "positions": {
339
- "state": "none"
340
- },
341
- "orders": {
342
- "state": "none"
343
- },
344
- "intent": "Prepare the Perps start state for the proof",
345
- "network": "testnet"
460
+ }
461
+ },
462
+ "custom_actions": [
463
+ {
464
+ "name": "metamask.wallet.list_accounts",
465
+ "owner": "metamask",
466
+ "description": "List redacted headless fixture accounts available to Core controller actions.",
467
+ "schema": {
468
+ "type": "object",
469
+ "properties": {
470
+ "scope": {
471
+ "type": "string",
472
+ "default": "named",
473
+ "enum": [
474
+ "selected",
475
+ "named",
476
+ "evm",
477
+ "all"
478
+ ],
479
+ "description": "Account scope. Core fixtures are EVM-only today; selected filters to the explicit controller account input."
480
+ },
481
+ "account": {
482
+ "type": "string",
483
+ "default": "dev1",
484
+ "description": "Optional account name to mark as selected for the next controller operation; defaults to dev1."
485
+ },
486
+ "account_name": {
487
+ "type": "string",
488
+ "description": "Alias for account."
346
489
  }
347
490
  },
348
- {
349
- "description": "Start with an open ETH long position",
350
- "node": {
351
- "action": "metamask.perps.start_state",
352
- "profile": "open_position_testnet",
353
- "market": "ETH",
354
- "side": "long",
355
- "positions": {
356
- "state": "open",
357
- "notional": "10",
358
- "leverage": 2
359
- },
360
- "intent": "Prepare the Perps start state for the proof",
361
- "network": "testnet"
362
- }
363
- }
364
- ]
365
- },
366
- "metamask.perps.teardown_state": {
367
- "description": "Recommended configurable Perps teardown state that restores the selected environment after proof. Headless: converges POSITION and ORDER baselines on testnet via the controller; no navigation/page/HUD.",
491
+ "additionalProperties": false
492
+ },
368
493
  "examples": [
369
494
  {
370
- "description": "Return BTC test account to clean state",
371
- "node": {
372
- "action": "metamask.perps.teardown_state",
373
- "market": "BTC",
374
- "positions": {
375
- "state": "none"
376
- },
377
- "orders": {
378
- "state": "none"
379
- },
380
- "intent": "Restore Perps state after the proof"
381
- }
382
- },
383
- {
384
- "description": "Teardown only state created by selected market",
385
- "node": {
386
- "action": "metamask.perps.teardown_state",
387
- "market": "BTC",
388
- "intent": "Restore Perps state after the proof"
495
+ "description": "List configured Core accounts",
496
+ "node": {
497
+ "action": "metamask.wallet.list_accounts",
498
+ "intent": "Discover the accounts available to headless controller actions"
389
499
  }
390
500
  }
391
- ]
392
- }
393
- },
394
- "custom_actions": [
501
+ ],
502
+ "proof_effect": "Records the redacted addresses derived from the same wallet fixture used by headless controller actions.",
503
+ "safety_notes": "Read-only fixture metadata; must never return private keys, mnemonics, passwords, or vault data.",
504
+ "execution_capabilities": []
505
+ },
395
506
  {
396
507
  "name": "metamask.perps.read_positions",
397
508
  "owner": "metamask",
398
- "description": "core Read live Perps positions directly from the perps controller (HyperLiquid testnet, HTTP read-only) and return the selected subset.",
509
+ "description": "core Read live Perps positions directly from the Perps controller; without a selector, return all live positions.",
399
510
  "schema": {
400
511
  "type": "object",
401
512
  "properties": {
402
- "action": {
403
- "const": "metamask.perps.read_positions"
404
- },
405
513
  "market": {
406
514
  "type": "string",
407
515
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -434,7 +542,41 @@
434
542
  },
435
543
  "selector": {
436
544
  "type": "object",
437
- "description": "Optional structured selector with mode, symbols/markets, and side."
545
+ "properties": {
546
+ "mode": {
547
+ "type": "string",
548
+ "enum": [
549
+ "matching",
550
+ "all"
551
+ ]
552
+ },
553
+ "market": {
554
+ "type": "string"
555
+ },
556
+ "symbol": {
557
+ "type": "string"
558
+ },
559
+ "markets": {
560
+ "type": "array",
561
+ "items": {
562
+ "type": "string"
563
+ }
564
+ },
565
+ "symbols": {
566
+ "type": "array",
567
+ "items": {
568
+ "type": "string"
569
+ }
570
+ },
571
+ "side": {
572
+ "type": "string",
573
+ "enum": [
574
+ "long",
575
+ "short"
576
+ ]
577
+ }
578
+ },
579
+ "additionalProperties": false
438
580
  },
439
581
  "side": {
440
582
  "type": "string",
@@ -446,15 +588,13 @@
446
588
  },
447
589
  "account": {
448
590
  "type": "string",
449
- "description": "EVM address to read positions for; defaults to MM_TEST_ACCOUNT_ADDRESS."
591
+ "description": "EVM address to read positions for; defaults to the canonical wallet fixture account."
450
592
  },
451
593
  "timeout_ms": {
452
594
  "type": "number"
453
595
  }
454
596
  },
455
- "required": [
456
- "action"
457
- ]
597
+ "additionalProperties": false
458
598
  },
459
599
  "examples": [
460
600
  {
@@ -467,18 +607,16 @@
467
607
  }
468
608
  ],
469
609
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output.",
470
- "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller/UI state to fabricate proof."
610
+ "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller/UI state to fabricate proof.",
611
+ "execution_capabilities": []
471
612
  },
472
613
  {
473
614
  "name": "metamask.perps.read_orders",
474
615
  "owner": "metamask",
475
- "description": "core Read live Perps open orders directly from the perps controller (HyperLiquid testnet, HTTP read-only) and return the selected subset.",
616
+ "description": "core Read live Perps open orders directly from the Perps controller; without a selector, return all live orders.",
476
617
  "schema": {
477
618
  "type": "object",
478
619
  "properties": {
479
- "action": {
480
- "const": "metamask.perps.read_orders"
481
- },
482
620
  "market": {
483
621
  "type": "string",
484
622
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -511,7 +649,41 @@
511
649
  },
512
650
  "selector": {
513
651
  "type": "object",
514
- "description": "Optional structured selector with mode, symbols/markets, and side."
652
+ "properties": {
653
+ "mode": {
654
+ "type": "string",
655
+ "enum": [
656
+ "matching",
657
+ "all"
658
+ ]
659
+ },
660
+ "market": {
661
+ "type": "string"
662
+ },
663
+ "symbol": {
664
+ "type": "string"
665
+ },
666
+ "markets": {
667
+ "type": "array",
668
+ "items": {
669
+ "type": "string"
670
+ }
671
+ },
672
+ "symbols": {
673
+ "type": "array",
674
+ "items": {
675
+ "type": "string"
676
+ }
677
+ },
678
+ "side": {
679
+ "type": "string",
680
+ "enum": [
681
+ "long",
682
+ "short"
683
+ ]
684
+ }
685
+ },
686
+ "additionalProperties": false
515
687
  },
516
688
  "side": {
517
689
  "type": "string",
@@ -523,15 +695,13 @@
523
695
  },
524
696
  "account": {
525
697
  "type": "string",
526
- "description": "EVM address to read orders for; defaults to MM_TEST_ACCOUNT_ADDRESS."
698
+ "description": "EVM address to read orders for; defaults to the canonical wallet fixture account."
527
699
  },
528
700
  "timeout_ms": {
529
701
  "type": "number"
530
702
  }
531
703
  },
532
- "required": [
533
- "action"
534
- ]
704
+ "additionalProperties": false
535
705
  },
536
706
  "examples": [
537
707
  {
@@ -544,7 +714,8 @@
544
714
  }
545
715
  ],
546
716
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output.",
547
- "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller/UI state to fabricate proof."
717
+ "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller/UI state to fabricate proof.",
718
+ "execution_capabilities": []
548
719
  },
549
720
  {
550
721
  "name": "metamask.perps.read_account",
@@ -553,20 +724,15 @@
553
724
  "schema": {
554
725
  "type": "object",
555
726
  "properties": {
556
- "action": {
557
- "const": "metamask.perps.read_account"
558
- },
559
727
  "account": {
560
728
  "type": "string",
561
- "description": "EVM address to read account state for; defaults to MM_TEST_ACCOUNT_ADDRESS."
729
+ "description": "EVM address to read account state for; defaults to the canonical wallet fixture account."
562
730
  },
563
731
  "timeout_ms": {
564
732
  "type": "number"
565
733
  }
566
734
  },
567
- "required": [
568
- "action"
569
- ]
735
+ "additionalProperties": false
570
736
  },
571
737
  "examples": [
572
738
  {
@@ -578,7 +744,8 @@
578
744
  }
579
745
  ],
580
746
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output.",
581
- "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller/UI state to fabricate proof."
747
+ "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller/UI state to fabricate proof.",
748
+ "execution_capabilities": []
582
749
  },
583
750
  {
584
751
  "name": "metamask.perps.place_order",
@@ -587,9 +754,6 @@
587
754
  "schema": {
588
755
  "type": "object",
589
756
  "properties": {
590
- "action": {
591
- "const": "metamask.perps.place_order"
592
- },
593
757
  "market": {
594
758
  "type": "string",
595
759
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -614,7 +778,41 @@
614
778
  },
615
779
  "selector": {
616
780
  "type": "object",
617
- "description": "Optional structured selector with mode, symbols/markets, and side."
781
+ "properties": {
782
+ "mode": {
783
+ "type": "string",
784
+ "enum": [
785
+ "matching",
786
+ "all"
787
+ ]
788
+ },
789
+ "market": {
790
+ "type": "string"
791
+ },
792
+ "symbol": {
793
+ "type": "string"
794
+ },
795
+ "markets": {
796
+ "type": "array",
797
+ "items": {
798
+ "type": "string"
799
+ }
800
+ },
801
+ "symbols": {
802
+ "type": "array",
803
+ "items": {
804
+ "type": "string"
805
+ }
806
+ },
807
+ "side": {
808
+ "type": "string",
809
+ "enum": [
810
+ "long",
811
+ "short"
812
+ ]
813
+ }
814
+ },
815
+ "additionalProperties": false
618
816
  },
619
817
  "side": {
620
818
  "type": "string",
@@ -649,19 +847,18 @@
649
847
  "description": "USD notional alias."
650
848
  },
651
849
  "leverage": {
652
- "type": "number"
850
+ "type": "number",
851
+ "default": 3
653
852
  },
654
853
  "account": {
655
854
  "type": "string",
656
- "description": "EVM address to trade for; defaults to MM_TEST_ACCOUNT_ADDRESS."
855
+ "description": "EVM address to trade for; defaults to the canonical wallet fixture account."
657
856
  },
658
857
  "timeout_ms": {
659
858
  "type": "number"
660
859
  }
661
860
  },
662
- "required": [
663
- "action"
664
- ]
861
+ "additionalProperties": false
665
862
  },
666
863
  "examples": [
667
864
  {
@@ -672,8 +869,7 @@
672
869
  "side": "long",
673
870
  "notional": "11",
674
871
  "leverage": 2,
675
- "intent": "Place the requested Perps order via the headless controller",
676
- "network": "testnet"
872
+ "intent": "Place the requested Perps order via the headless controller"
677
873
  }
678
874
  },
679
875
  {
@@ -686,13 +882,16 @@
686
882
  "offset_pct": -30,
687
883
  "notional": "11",
688
884
  "leverage": 2,
689
- "intent": "Place a resting Perps limit order via the headless controller",
690
- "network": "testnet"
885
+ "intent": "Place a resting Perps limit order via the headless controller"
691
886
  }
692
887
  }
693
888
  ],
694
889
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output (order id, opened position).",
695
- "safety_notes": "Submits a REAL signed order to HyperLiquid testnet; must not mock the signer/provider or inject controller state to fabricate proof."
890
+ "safety_notes": "Submits a REAL signed order to HyperLiquid testnet; must not mock the signer/provider or inject controller state to fabricate proof.",
891
+ "execution_capabilities": [
892
+ "app-mutation",
893
+ "external-mutation"
894
+ ]
696
895
  },
697
896
  {
698
897
  "name": "metamask.perps.close_positions",
@@ -701,9 +900,6 @@
701
900
  "schema": {
702
901
  "type": "object",
703
902
  "properties": {
704
- "action": {
705
- "const": "metamask.perps.close_positions"
706
- },
707
903
  "market": {
708
904
  "type": "string",
709
905
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -736,7 +932,41 @@
736
932
  },
737
933
  "selector": {
738
934
  "type": "object",
739
- "description": "Optional structured selector with mode, symbols/markets, and side."
935
+ "properties": {
936
+ "mode": {
937
+ "type": "string",
938
+ "enum": [
939
+ "matching",
940
+ "all"
941
+ ]
942
+ },
943
+ "market": {
944
+ "type": "string"
945
+ },
946
+ "symbol": {
947
+ "type": "string"
948
+ },
949
+ "markets": {
950
+ "type": "array",
951
+ "items": {
952
+ "type": "string"
953
+ }
954
+ },
955
+ "symbols": {
956
+ "type": "array",
957
+ "items": {
958
+ "type": "string"
959
+ }
960
+ },
961
+ "side": {
962
+ "type": "string",
963
+ "enum": [
964
+ "long",
965
+ "short"
966
+ ]
967
+ }
968
+ },
969
+ "additionalProperties": false
740
970
  },
741
971
  "side": {
742
972
  "type": "string",
@@ -748,15 +978,13 @@
748
978
  },
749
979
  "account": {
750
980
  "type": "string",
751
- "description": "EVM address to close for; defaults to MM_TEST_ACCOUNT_ADDRESS."
981
+ "description": "EVM address to close for; defaults to the canonical wallet fixture account."
752
982
  },
753
983
  "timeout_ms": {
754
984
  "type": "number"
755
985
  }
756
986
  },
757
- "required": [
758
- "action"
759
- ]
987
+ "additionalProperties": false
760
988
  },
761
989
  "examples": [
762
990
  {
@@ -764,24 +992,24 @@
764
992
  "node": {
765
993
  "action": "metamask.perps.close_positions",
766
994
  "market": "BTC",
767
- "intent": "Close selected Perps positions via the headless controller",
768
- "network": "testnet"
995
+ "intent": "Close selected Perps positions via the headless controller"
769
996
  }
770
997
  }
771
998
  ],
772
999
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output (positions absent after close).",
773
- "safety_notes": "Submits REAL signed close orders to HyperLiquid testnet; must not mock the signer/provider or inject controller state to fabricate proof."
1000
+ "safety_notes": "Submits REAL signed close orders to HyperLiquid testnet; must not mock the signer/provider or inject controller state to fabricate proof.",
1001
+ "execution_capabilities": [
1002
+ "app-mutation",
1003
+ "external-mutation"
1004
+ ]
774
1005
  },
775
1006
  {
776
1007
  "name": "metamask.perps.assert_positions",
777
1008
  "owner": "metamask",
778
- "description": "core Assert selected live Perps positions are present or absent via the headless controller standalone read path. Throws on mismatch.",
1009
+ "description": "core Assert live Perps positions are present or absent for an explicit market selection or mode=all.",
779
1010
  "schema": {
780
1011
  "type": "object",
781
1012
  "properties": {
782
- "action": {
783
- "const": "metamask.perps.assert_positions"
784
- },
785
1013
  "market": {
786
1014
  "type": "string",
787
1015
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -814,7 +1042,41 @@
814
1042
  },
815
1043
  "selector": {
816
1044
  "type": "object",
817
- "description": "Optional structured selector with mode, symbols/markets, and side."
1045
+ "properties": {
1046
+ "mode": {
1047
+ "type": "string",
1048
+ "enum": [
1049
+ "matching",
1050
+ "all"
1051
+ ]
1052
+ },
1053
+ "market": {
1054
+ "type": "string"
1055
+ },
1056
+ "symbol": {
1057
+ "type": "string"
1058
+ },
1059
+ "markets": {
1060
+ "type": "array",
1061
+ "items": {
1062
+ "type": "string"
1063
+ }
1064
+ },
1065
+ "symbols": {
1066
+ "type": "array",
1067
+ "items": {
1068
+ "type": "string"
1069
+ }
1070
+ },
1071
+ "side": {
1072
+ "type": "string",
1073
+ "enum": [
1074
+ "long",
1075
+ "short"
1076
+ ]
1077
+ }
1078
+ },
1079
+ "additionalProperties": false
818
1080
  },
819
1081
  "side": {
820
1082
  "type": "string",
@@ -837,15 +1099,16 @@
837
1099
  },
838
1100
  "account": {
839
1101
  "type": "string",
840
- "description": "EVM address to read for; defaults to MM_TEST_ACCOUNT_ADDRESS."
1102
+ "description": "EVM address to read for; defaults to the canonical wallet fixture account."
841
1103
  },
842
1104
  "timeout_ms": {
843
1105
  "type": "number"
844
1106
  }
845
1107
  },
846
1108
  "required": [
847
- "action"
848
- ]
1109
+ "state"
1110
+ ],
1111
+ "additionalProperties": false
849
1112
  },
850
1113
  "examples": [
851
1114
  {
@@ -859,7 +1122,8 @@
859
1122
  }
860
1123
  ],
861
1124
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output.",
862
- "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller state to fabricate proof."
1125
+ "safety_notes": "Read-only HyperLiquid testnet HTTP query; must not inject controller state to fabricate proof.",
1126
+ "execution_capabilities": []
863
1127
  },
864
1128
  {
865
1129
  "name": "metamask.perps.ensure_positions",
@@ -868,9 +1132,6 @@
868
1132
  "schema": {
869
1133
  "type": "object",
870
1134
  "properties": {
871
- "action": {
872
- "const": "metamask.perps.ensure_positions"
873
- },
874
1135
  "market": {
875
1136
  "type": "string",
876
1137
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -903,7 +1164,41 @@
903
1164
  },
904
1165
  "selector": {
905
1166
  "type": "object",
906
- "description": "Optional structured selector with mode, symbols/markets, and side."
1167
+ "properties": {
1168
+ "mode": {
1169
+ "type": "string",
1170
+ "enum": [
1171
+ "matching",
1172
+ "all"
1173
+ ]
1174
+ },
1175
+ "market": {
1176
+ "type": "string"
1177
+ },
1178
+ "symbol": {
1179
+ "type": "string"
1180
+ },
1181
+ "markets": {
1182
+ "type": "array",
1183
+ "items": {
1184
+ "type": "string"
1185
+ }
1186
+ },
1187
+ "symbols": {
1188
+ "type": "array",
1189
+ "items": {
1190
+ "type": "string"
1191
+ }
1192
+ },
1193
+ "side": {
1194
+ "type": "string",
1195
+ "enum": [
1196
+ "long",
1197
+ "short"
1198
+ ]
1199
+ }
1200
+ },
1201
+ "additionalProperties": false
907
1202
  },
908
1203
  "side": {
909
1204
  "type": "string",
@@ -937,15 +1232,16 @@
937
1232
  },
938
1233
  "account": {
939
1234
  "type": "string",
940
- "description": "EVM address to trade for; defaults to MM_TEST_ACCOUNT_ADDRESS."
1235
+ "description": "EVM address to trade for; defaults to the canonical wallet fixture account."
941
1236
  },
942
1237
  "timeout_ms": {
943
1238
  "type": "number"
944
1239
  }
945
1240
  },
946
1241
  "required": [
947
- "action"
948
- ]
1242
+ "state"
1243
+ ],
1244
+ "additionalProperties": false
949
1245
  },
950
1246
  "examples": [
951
1247
  {
@@ -954,13 +1250,16 @@
954
1250
  "action": "metamask.perps.ensure_positions",
955
1251
  "state": "none",
956
1252
  "market": "BTC",
957
- "intent": "Converge Perps positions to the requested state via the headless controller",
958
- "network": "testnet"
1253
+ "intent": "Converge Perps positions to the requested state via the headless controller"
959
1254
  }
960
1255
  }
961
1256
  ],
962
1257
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or controller output.",
963
- "safety_notes": "May submit REAL signed orders to HyperLiquid testnet; must not mock the signer/provider or inject controller state to fabricate proof."
1258
+ "safety_notes": "May submit REAL signed orders to HyperLiquid testnet; must not mock the signer/provider or inject controller state to fabricate proof.",
1259
+ "execution_capabilities": [
1260
+ "app-mutation",
1261
+ "external-mutation"
1262
+ ]
964
1263
  },
965
1264
  {
966
1265
  "name": "metamask.perps.close_orders",
@@ -969,9 +1268,6 @@
969
1268
  "schema": {
970
1269
  "type": "object",
971
1270
  "properties": {
972
- "action": {
973
- "const": "metamask.perps.close_orders"
974
- },
975
1271
  "market": {
976
1272
  "type": "string",
977
1273
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -1004,7 +1300,41 @@
1004
1300
  },
1005
1301
  "selector": {
1006
1302
  "type": "object",
1007
- "description": "Optional structured selector with mode, symbols/markets, and side."
1303
+ "properties": {
1304
+ "mode": {
1305
+ "type": "string",
1306
+ "enum": [
1307
+ "matching",
1308
+ "all"
1309
+ ]
1310
+ },
1311
+ "market": {
1312
+ "type": "string"
1313
+ },
1314
+ "symbol": {
1315
+ "type": "string"
1316
+ },
1317
+ "markets": {
1318
+ "type": "array",
1319
+ "items": {
1320
+ "type": "string"
1321
+ }
1322
+ },
1323
+ "symbols": {
1324
+ "type": "array",
1325
+ "items": {
1326
+ "type": "string"
1327
+ }
1328
+ },
1329
+ "side": {
1330
+ "type": "string",
1331
+ "enum": [
1332
+ "long",
1333
+ "short"
1334
+ ]
1335
+ }
1336
+ },
1337
+ "additionalProperties": false
1008
1338
  },
1009
1339
  "side": {
1010
1340
  "type": "string",
@@ -1018,9 +1348,7 @@
1018
1348
  "type": "number"
1019
1349
  }
1020
1350
  },
1021
- "required": [
1022
- "action"
1023
- ]
1351
+ "additionalProperties": false
1024
1352
  },
1025
1353
  "examples": [
1026
1354
  {
@@ -1028,8 +1356,7 @@
1028
1356
  "node": {
1029
1357
  "action": "metamask.perps.close_orders",
1030
1358
  "mode": "all",
1031
- "intent": "Cancel selected Perps orders before continuing",
1032
- "network": "testnet"
1359
+ "intent": "Cancel selected Perps orders before continuing"
1033
1360
  }
1034
1361
  },
1035
1362
  {
@@ -1037,24 +1364,24 @@
1037
1364
  "node": {
1038
1365
  "action": "metamask.perps.close_orders",
1039
1366
  "market": "BTC",
1040
- "intent": "Cancel selected Perps orders before continuing",
1041
- "network": "testnet"
1367
+ "intent": "Cancel selected Perps orders before continuing"
1042
1368
  }
1043
1369
  }
1044
1370
  ],
1045
1371
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1046
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof."
1372
+ "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1373
+ "execution_capabilities": [
1374
+ "app-mutation",
1375
+ "external-mutation"
1376
+ ]
1047
1377
  },
1048
1378
  {
1049
1379
  "name": "metamask.perps.assert_orders",
1050
1380
  "owner": "metamask",
1051
- "description": "core Assert selected live Perps open orders are present or absent.",
1381
+ "description": "core Assert live Perps open orders are present or absent for an explicit market selection or mode=all.",
1052
1382
  "schema": {
1053
1383
  "type": "object",
1054
1384
  "properties": {
1055
- "action": {
1056
- "const": "metamask.perps.assert_orders"
1057
- },
1058
1385
  "market": {
1059
1386
  "type": "string",
1060
1387
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -1087,7 +1414,41 @@
1087
1414
  },
1088
1415
  "selector": {
1089
1416
  "type": "object",
1090
- "description": "Optional structured selector with mode, symbols/markets, and side."
1417
+ "properties": {
1418
+ "mode": {
1419
+ "type": "string",
1420
+ "enum": [
1421
+ "matching",
1422
+ "all"
1423
+ ]
1424
+ },
1425
+ "market": {
1426
+ "type": "string"
1427
+ },
1428
+ "symbol": {
1429
+ "type": "string"
1430
+ },
1431
+ "markets": {
1432
+ "type": "array",
1433
+ "items": {
1434
+ "type": "string"
1435
+ }
1436
+ },
1437
+ "symbols": {
1438
+ "type": "array",
1439
+ "items": {
1440
+ "type": "string"
1441
+ }
1442
+ },
1443
+ "side": {
1444
+ "type": "string",
1445
+ "enum": [
1446
+ "long",
1447
+ "short"
1448
+ ]
1449
+ }
1450
+ },
1451
+ "additionalProperties": false
1091
1452
  },
1092
1453
  "side": {
1093
1454
  "type": "string",
@@ -1113,8 +1474,9 @@
1113
1474
  }
1114
1475
  },
1115
1476
  "required": [
1116
- "action"
1117
- ]
1477
+ "state"
1478
+ ],
1479
+ "additionalProperties": false
1118
1480
  },
1119
1481
  "examples": [
1120
1482
  {
@@ -1128,7 +1490,8 @@
1128
1490
  }
1129
1491
  ],
1130
1492
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1131
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof."
1493
+ "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1494
+ "execution_capabilities": []
1132
1495
  },
1133
1496
  {
1134
1497
  "name": "metamask.perps.ensure_orders",
@@ -1137,9 +1500,6 @@
1137
1500
  "schema": {
1138
1501
  "type": "object",
1139
1502
  "properties": {
1140
- "action": {
1141
- "const": "metamask.perps.ensure_orders"
1142
- },
1143
1503
  "market": {
1144
1504
  "type": "string",
1145
1505
  "description": "Single market symbol, e.g. BTC or ETH. Alias: symbol."
@@ -1172,7 +1532,41 @@
1172
1532
  },
1173
1533
  "selector": {
1174
1534
  "type": "object",
1175
- "description": "Optional structured selector with mode, symbols/markets, and side."
1535
+ "properties": {
1536
+ "mode": {
1537
+ "type": "string",
1538
+ "enum": [
1539
+ "matching",
1540
+ "all"
1541
+ ]
1542
+ },
1543
+ "market": {
1544
+ "type": "string"
1545
+ },
1546
+ "symbol": {
1547
+ "type": "string"
1548
+ },
1549
+ "markets": {
1550
+ "type": "array",
1551
+ "items": {
1552
+ "type": "string"
1553
+ }
1554
+ },
1555
+ "symbols": {
1556
+ "type": "array",
1557
+ "items": {
1558
+ "type": "string"
1559
+ }
1560
+ },
1561
+ "side": {
1562
+ "type": "string",
1563
+ "enum": [
1564
+ "long",
1565
+ "short"
1566
+ ]
1567
+ }
1568
+ },
1569
+ "additionalProperties": false
1176
1570
  },
1177
1571
  "side": {
1178
1572
  "type": "string",
@@ -1198,8 +1592,9 @@
1198
1592
  }
1199
1593
  },
1200
1594
  "required": [
1201
- "action"
1202
- ]
1595
+ "state"
1596
+ ],
1597
+ "additionalProperties": false
1203
1598
  },
1204
1599
  "examples": [
1205
1600
  {
@@ -1208,13 +1603,16 @@
1208
1603
  "action": "metamask.perps.ensure_orders",
1209
1604
  "state": "none",
1210
1605
  "mode": "all",
1211
- "intent": "Converge Perps orders to the requested state",
1212
- "network": "testnet"
1606
+ "intent": "Converge Perps orders to the requested state"
1213
1607
  }
1214
1608
  }
1215
1609
  ],
1216
1610
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1217
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof."
1611
+ "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1612
+ "execution_capabilities": [
1613
+ "app-mutation",
1614
+ "external-mutation"
1615
+ ]
1218
1616
  },
1219
1617
  {
1220
1618
  "name": "metamask.perps.start_state",
@@ -1223,9 +1621,6 @@
1223
1621
  "schema": {
1224
1622
  "type": "object",
1225
1623
  "properties": {
1226
- "action": {
1227
- "const": "metamask.perps.start_state"
1228
- },
1229
1624
  "profile": {
1230
1625
  "type": "string",
1231
1626
  "description": "Optional profile such as clean_market_testnet, open_position_testnet, open_order_testnet, or provider_mainnet_readonly."
@@ -1263,34 +1658,249 @@
1263
1658
  }
1264
1659
  },
1265
1660
  "positions": {
1266
- "oneOf": [
1267
- {
1268
- "type": "object"
1661
+ "type": [
1662
+ "object",
1663
+ "boolean"
1664
+ ],
1665
+ "properties": {
1666
+ "mode": {
1667
+ "type": "string",
1668
+ "enum": [
1669
+ "matching",
1670
+ "all"
1671
+ ]
1269
1672
  },
1270
- {
1271
- "const": false
1673
+ "market": {
1674
+ "type": "string"
1675
+ },
1676
+ "symbol": {
1677
+ "type": "string"
1678
+ },
1679
+ "markets": {
1680
+ "type": "array",
1681
+ "items": {
1682
+ "type": "string"
1683
+ }
1684
+ },
1685
+ "symbols": {
1686
+ "type": "array",
1687
+ "items": {
1688
+ "type": "string"
1689
+ }
1690
+ },
1691
+ "side": {
1692
+ "type": "string",
1693
+ "enum": [
1694
+ "long",
1695
+ "short"
1696
+ ]
1697
+ },
1698
+ "state": {
1699
+ "type": "string",
1700
+ "enum": [
1701
+ "none",
1702
+ "closed",
1703
+ "absent",
1704
+ "open",
1705
+ "present"
1706
+ ]
1707
+ },
1708
+ "amount": {
1709
+ "type": [
1710
+ "string",
1711
+ "number"
1712
+ ]
1713
+ },
1714
+ "notional": {
1715
+ "type": [
1716
+ "string",
1717
+ "number"
1718
+ ]
1719
+ },
1720
+ "size": {
1721
+ "type": [
1722
+ "string",
1723
+ "number"
1724
+ ]
1725
+ },
1726
+ "leverage": {
1727
+ "type": "number"
1728
+ },
1729
+ "order_type": {
1730
+ "type": "string"
1731
+ },
1732
+ "orderType": {
1733
+ "type": "string"
1734
+ },
1735
+ "limit_price": {
1736
+ "type": "number"
1737
+ },
1738
+ "limitPrice": {
1739
+ "type": "number"
1740
+ },
1741
+ "offset_pct": {
1742
+ "type": "number"
1743
+ },
1744
+ "offsetPct": {
1745
+ "type": "number"
1746
+ },
1747
+ "current_price": {
1748
+ "type": "number"
1749
+ },
1750
+ "currentPrice": {
1751
+ "type": "number"
1752
+ },
1753
+ "max_slippage_bps": {
1754
+ "type": "number"
1755
+ },
1756
+ "maxSlippageBps": {
1757
+ "type": "number"
1758
+ },
1759
+ "close_attempts": {
1760
+ "type": "integer"
1761
+ },
1762
+ "close_retry_delay_ms": {
1763
+ "type": "integer"
1764
+ },
1765
+ "timeout_ms": {
1766
+ "type": "number"
1272
1767
  }
1273
- ],
1274
- "description": "Desired position baseline or false to skip."
1768
+ },
1769
+ "additionalProperties": false
1275
1770
  },
1276
1771
  "orders": {
1277
- "oneOf": [
1278
- {
1279
- "type": "object"
1772
+ "type": [
1773
+ "object",
1774
+ "boolean"
1775
+ ],
1776
+ "properties": {
1777
+ "mode": {
1778
+ "type": "string",
1779
+ "enum": [
1780
+ "matching",
1781
+ "all"
1782
+ ]
1280
1783
  },
1281
- {
1282
- "const": false
1784
+ "market": {
1785
+ "type": "string"
1786
+ },
1787
+ "symbol": {
1788
+ "type": "string"
1789
+ },
1790
+ "markets": {
1791
+ "type": "array",
1792
+ "items": {
1793
+ "type": "string"
1794
+ }
1795
+ },
1796
+ "symbols": {
1797
+ "type": "array",
1798
+ "items": {
1799
+ "type": "string"
1800
+ }
1801
+ },
1802
+ "side": {
1803
+ "type": "string",
1804
+ "enum": [
1805
+ "long",
1806
+ "short"
1807
+ ]
1808
+ },
1809
+ "state": {
1810
+ "type": "string",
1811
+ "enum": [
1812
+ "none",
1813
+ "closed",
1814
+ "absent",
1815
+ "open",
1816
+ "present"
1817
+ ]
1818
+ },
1819
+ "amount": {
1820
+ "type": [
1821
+ "string",
1822
+ "number"
1823
+ ]
1824
+ },
1825
+ "notional": {
1826
+ "type": [
1827
+ "string",
1828
+ "number"
1829
+ ]
1830
+ },
1831
+ "size": {
1832
+ "type": [
1833
+ "string",
1834
+ "number"
1835
+ ]
1836
+ },
1837
+ "leverage": {
1838
+ "type": "number"
1839
+ },
1840
+ "order_type": {
1841
+ "type": "string"
1842
+ },
1843
+ "orderType": {
1844
+ "type": "string"
1845
+ },
1846
+ "limit_price": {
1847
+ "type": "number"
1848
+ },
1849
+ "limitPrice": {
1850
+ "type": "number"
1851
+ },
1852
+ "offset_pct": {
1853
+ "type": "number"
1854
+ },
1855
+ "offsetPct": {
1856
+ "type": "number"
1857
+ },
1858
+ "current_price": {
1859
+ "type": "number"
1860
+ },
1861
+ "currentPrice": {
1862
+ "type": "number"
1863
+ },
1864
+ "max_slippage_bps": {
1865
+ "type": "number"
1866
+ },
1867
+ "maxSlippageBps": {
1868
+ "type": "number"
1869
+ },
1870
+ "close_attempts": {
1871
+ "type": "integer"
1872
+ },
1873
+ "close_retry_delay_ms": {
1874
+ "type": "integer"
1875
+ },
1876
+ "timeout_ms": {
1877
+ "type": "number"
1283
1878
  }
1284
- ],
1285
- "description": "Desired open-order baseline or false to skip."
1879
+ },
1880
+ "additionalProperties": false
1286
1881
  },
1287
1882
  "timeout_ms": {
1288
1883
  "type": "number"
1884
+ },
1885
+ "side": {
1886
+ "type": "string",
1887
+ "enum": [
1888
+ "long",
1889
+ "short"
1890
+ ]
1891
+ },
1892
+ "account_name": {
1893
+ "type": "string"
1894
+ },
1895
+ "mode": {
1896
+ "type": "string",
1897
+ "enum": [
1898
+ "matching",
1899
+ "all"
1900
+ ]
1289
1901
  }
1290
1902
  },
1291
- "required": [
1292
- "action"
1293
- ]
1903
+ "additionalProperties": false
1294
1904
  },
1295
1905
  "examples": [
1296
1906
  {
@@ -1327,7 +1937,11 @@
1327
1937
  }
1328
1938
  ],
1329
1939
  "proof_effect": "Runs in setup/teardown phase and must be visible in trace.json; proof videos can keep this as trace-only setup.",
1330
- "safety_notes": "Composes supported app/API paths and must not mutate React/Redux/MobX/DOM/local storage to fabricate proof."
1940
+ "safety_notes": "Composes supported app/API paths and must not mutate React/Redux/MobX/DOM/local storage to fabricate proof.",
1941
+ "execution_capabilities": [
1942
+ "app-mutation",
1943
+ "external-mutation"
1944
+ ]
1331
1945
  },
1332
1946
  {
1333
1947
  "name": "metamask.perps.teardown_state",
@@ -1336,9 +1950,6 @@
1336
1950
  "schema": {
1337
1951
  "type": "object",
1338
1952
  "properties": {
1339
- "action": {
1340
- "const": "metamask.perps.teardown_state"
1341
- },
1342
1953
  "profile": {
1343
1954
  "type": "string",
1344
1955
  "description": "Optional profile such as clean_market_testnet, open_position_testnet, open_order_testnet, or provider_mainnet_readonly."
@@ -1376,34 +1987,249 @@
1376
1987
  }
1377
1988
  },
1378
1989
  "positions": {
1379
- "oneOf": [
1380
- {
1381
- "type": "object"
1990
+ "type": [
1991
+ "object",
1992
+ "boolean"
1993
+ ],
1994
+ "properties": {
1995
+ "mode": {
1996
+ "type": "string",
1997
+ "enum": [
1998
+ "matching",
1999
+ "all"
2000
+ ]
1382
2001
  },
1383
- {
1384
- "const": false
2002
+ "market": {
2003
+ "type": "string"
2004
+ },
2005
+ "symbol": {
2006
+ "type": "string"
2007
+ },
2008
+ "markets": {
2009
+ "type": "array",
2010
+ "items": {
2011
+ "type": "string"
2012
+ }
2013
+ },
2014
+ "symbols": {
2015
+ "type": "array",
2016
+ "items": {
2017
+ "type": "string"
2018
+ }
2019
+ },
2020
+ "side": {
2021
+ "type": "string",
2022
+ "enum": [
2023
+ "long",
2024
+ "short"
2025
+ ]
2026
+ },
2027
+ "state": {
2028
+ "type": "string",
2029
+ "enum": [
2030
+ "none",
2031
+ "closed",
2032
+ "absent",
2033
+ "open",
2034
+ "present"
2035
+ ]
2036
+ },
2037
+ "amount": {
2038
+ "type": [
2039
+ "string",
2040
+ "number"
2041
+ ]
2042
+ },
2043
+ "notional": {
2044
+ "type": [
2045
+ "string",
2046
+ "number"
2047
+ ]
2048
+ },
2049
+ "size": {
2050
+ "type": [
2051
+ "string",
2052
+ "number"
2053
+ ]
2054
+ },
2055
+ "leverage": {
2056
+ "type": "number"
2057
+ },
2058
+ "order_type": {
2059
+ "type": "string"
2060
+ },
2061
+ "orderType": {
2062
+ "type": "string"
2063
+ },
2064
+ "limit_price": {
2065
+ "type": "number"
2066
+ },
2067
+ "limitPrice": {
2068
+ "type": "number"
2069
+ },
2070
+ "offset_pct": {
2071
+ "type": "number"
2072
+ },
2073
+ "offsetPct": {
2074
+ "type": "number"
2075
+ },
2076
+ "current_price": {
2077
+ "type": "number"
2078
+ },
2079
+ "currentPrice": {
2080
+ "type": "number"
2081
+ },
2082
+ "max_slippage_bps": {
2083
+ "type": "number"
2084
+ },
2085
+ "maxSlippageBps": {
2086
+ "type": "number"
2087
+ },
2088
+ "close_attempts": {
2089
+ "type": "integer"
2090
+ },
2091
+ "close_retry_delay_ms": {
2092
+ "type": "integer"
2093
+ },
2094
+ "timeout_ms": {
2095
+ "type": "number"
1385
2096
  }
1386
- ],
1387
- "description": "Desired position baseline or false to skip."
2097
+ },
2098
+ "additionalProperties": false
1388
2099
  },
1389
2100
  "orders": {
1390
- "oneOf": [
1391
- {
1392
- "type": "object"
2101
+ "type": [
2102
+ "object",
2103
+ "boolean"
2104
+ ],
2105
+ "properties": {
2106
+ "mode": {
2107
+ "type": "string",
2108
+ "enum": [
2109
+ "matching",
2110
+ "all"
2111
+ ]
1393
2112
  },
1394
- {
1395
- "const": false
2113
+ "market": {
2114
+ "type": "string"
2115
+ },
2116
+ "symbol": {
2117
+ "type": "string"
2118
+ },
2119
+ "markets": {
2120
+ "type": "array",
2121
+ "items": {
2122
+ "type": "string"
2123
+ }
2124
+ },
2125
+ "symbols": {
2126
+ "type": "array",
2127
+ "items": {
2128
+ "type": "string"
2129
+ }
2130
+ },
2131
+ "side": {
2132
+ "type": "string",
2133
+ "enum": [
2134
+ "long",
2135
+ "short"
2136
+ ]
2137
+ },
2138
+ "state": {
2139
+ "type": "string",
2140
+ "enum": [
2141
+ "none",
2142
+ "closed",
2143
+ "absent",
2144
+ "open",
2145
+ "present"
2146
+ ]
2147
+ },
2148
+ "amount": {
2149
+ "type": [
2150
+ "string",
2151
+ "number"
2152
+ ]
2153
+ },
2154
+ "notional": {
2155
+ "type": [
2156
+ "string",
2157
+ "number"
2158
+ ]
2159
+ },
2160
+ "size": {
2161
+ "type": [
2162
+ "string",
2163
+ "number"
2164
+ ]
2165
+ },
2166
+ "leverage": {
2167
+ "type": "number"
2168
+ },
2169
+ "order_type": {
2170
+ "type": "string"
2171
+ },
2172
+ "orderType": {
2173
+ "type": "string"
2174
+ },
2175
+ "limit_price": {
2176
+ "type": "number"
2177
+ },
2178
+ "limitPrice": {
2179
+ "type": "number"
2180
+ },
2181
+ "offset_pct": {
2182
+ "type": "number"
2183
+ },
2184
+ "offsetPct": {
2185
+ "type": "number"
2186
+ },
2187
+ "current_price": {
2188
+ "type": "number"
2189
+ },
2190
+ "currentPrice": {
2191
+ "type": "number"
2192
+ },
2193
+ "max_slippage_bps": {
2194
+ "type": "number"
2195
+ },
2196
+ "maxSlippageBps": {
2197
+ "type": "number"
2198
+ },
2199
+ "close_attempts": {
2200
+ "type": "integer"
2201
+ },
2202
+ "close_retry_delay_ms": {
2203
+ "type": "integer"
2204
+ },
2205
+ "timeout_ms": {
2206
+ "type": "number"
1396
2207
  }
1397
- ],
1398
- "description": "Desired open-order baseline or false to skip."
2208
+ },
2209
+ "additionalProperties": false
1399
2210
  },
1400
2211
  "timeout_ms": {
1401
2212
  "type": "number"
2213
+ },
2214
+ "side": {
2215
+ "type": "string",
2216
+ "enum": [
2217
+ "long",
2218
+ "short"
2219
+ ]
2220
+ },
2221
+ "account_name": {
2222
+ "type": "string"
2223
+ },
2224
+ "mode": {
2225
+ "type": "string",
2226
+ "enum": [
2227
+ "matching",
2228
+ "all"
2229
+ ]
1402
2230
  }
1403
2231
  },
1404
- "required": [
1405
- "action"
1406
- ]
2232
+ "additionalProperties": false
1407
2233
  },
1408
2234
  "examples": [
1409
2235
  {
@@ -1430,19 +2256,11 @@
1430
2256
  }
1431
2257
  ],
1432
2258
  "proof_effect": "Runs in setup/teardown phase and must be visible in trace.json; proof videos can keep this as trace-only setup.",
1433
- "safety_notes": "Composes supported app/API paths and must not mutate React/Redux/MobX/DOM/local storage to fabricate proof."
1434
- }
1435
- ],
1436
- "state_refs": [
1437
- {
1438
- "name": "perps.positions",
1439
- "description": "Normalized Perps position state read from the headless controller."
1440
- }
1441
- ],
1442
- "pre_conditions": [
1443
- {
1444
- "id": "no-mid-recipe-state-injection",
1445
- "description": "Recipes must drive the real perps controller read path for proof state."
2259
+ "safety_notes": "Composes supported app/API paths and must not mutate React/Redux/MobX/DOM/local storage to fabricate proof.",
2260
+ "execution_capabilities": [
2261
+ "app-mutation",
2262
+ "external-mutation"
2263
+ ]
1446
2264
  }
1447
2265
  ],
1448
2266
  "native_bindings": [
@@ -1486,6 +2304,10 @@
1486
2304
  "action": "app.status",
1487
2305
  "implementation": "@metamask/recipe-runner/platform-status"
1488
2306
  },
2307
+ {
2308
+ "action": "metamask.wallet.list_accounts",
2309
+ "implementation": "@metamask/recipe-runner/core/wallet"
2310
+ },
1489
2311
  {
1490
2312
  "action": "metamask.perps.read_positions",
1491
2313
  "implementation": "@metamask/recipe-runner/core/perps"
@@ -1514,9 +2336,5 @@
1514
2336
  "action": "metamask.perps.ensure_positions",
1515
2337
  "implementation": "@metamask/recipe-runner/core/perps"
1516
2338
  }
1517
- ],
1518
- "capability_notes": [
1519
- "core is a headless adapter: it instantiates @metamask/perps-controller against a resolved MetaMask/core checkout and reads HyperLiquid testnet over HTTP. No CDP, bridge, or UI is involved. Slice 1 implements read-only perps actions. Slice 2 adds a default viem signer + write actions (place_order, close_positions, ensure_positions, assert_positions) that submit real signed orders to HyperLiquid testnet via the controller's full provider path."
1520
- ],
1521
- "action_profiles": []
2339
+ ]
1522
2340
  }