@deeeed/metamask-harness 0.20.0 → 0.22.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.
@@ -1,39 +1,14 @@
1
1
  {
2
- "runner_protocol_version": 1,
3
- "action_registry_version": 1,
4
- "supported_official_actions": [
5
- "command",
6
- "wait",
7
- "assert_file",
8
- "assert_json",
9
- "assert_exit_code",
10
- "assert_output",
11
- "watch_logs",
12
- "index_artifacts",
13
- "end",
14
- "call",
15
- "switch",
16
- "ui.navigate",
17
- "ui.press",
18
- "ui.key_press",
19
- "ui.set_input",
20
- "ui.scroll",
21
- "ui.wait_for",
22
- "ui.screenshot",
23
- "app.status",
24
- "app.hud",
25
- "cdp.target"
26
- ],
27
- "action_metadata": {
2
+ "$schema": "https://farmslot.io/schemas/action-manifest-v1.schema.json",
3
+ "actions": {
28
4
  "command": {
29
5
  "description": "Run a shell command from the project root.",
30
6
  "examples": [
31
7
  {
32
- "node": {
33
- "action": "command",
34
- "cmd": "pwd",
35
- "intent": "Run a shell command from the project root"
36
- }
8
+ "action": "command",
9
+ "cmd": "pwd",
10
+ "intent": "Prepare the project state needed for this proof.",
11
+ "next": "done"
37
12
  }
38
13
  ],
39
14
  "schema": {
@@ -62,11 +37,10 @@
62
37
  "description": "Base wait action.",
63
38
  "examples": [
64
39
  {
65
- "node": {
66
- "action": "wait",
67
- "duration_ms": 1,
68
- "intent": "Base wait action"
69
- }
40
+ "action": "wait",
41
+ "duration_ms": 1,
42
+ "intent": "Allow the requested asynchronous state to settle.",
43
+ "next": "done"
70
44
  }
71
45
  ],
72
46
  "schema": {
@@ -82,40 +56,229 @@
82
56
  "additionalProperties": false
83
57
  }
84
58
  },
85
- "switch": {
86
- "description": "Choose a graph branch when one resolved string equals another.",
59
+ "assert_file": {
60
+ "description": "Assert that a project file exists and optionally contains text.",
61
+ "examples": [
62
+ {
63
+ "action": "assert_file",
64
+ "path": "reports/result.txt",
65
+ "contains": "ok",
66
+ "intent": "Confirm the requested project file state.",
67
+ "next": "done"
68
+ }
69
+ ],
70
+ "schema": {
71
+ "type": "object",
72
+ "properties": {
73
+ "path": {
74
+ "type": "string"
75
+ },
76
+ "contains": {
77
+ "type": "string"
78
+ }
79
+ },
80
+ "required": [
81
+ "path"
82
+ ],
83
+ "additionalProperties": false
84
+ }
85
+ },
86
+ "assert_json": {
87
+ "description": "Assert a JSON file value with a JSONPath-style selector.",
88
+ "examples": [
89
+ {
90
+ "action": "assert_json",
91
+ "path": "reports/result.json",
92
+ "assert": {
93
+ "path": "$.status",
94
+ "operator": "eq",
95
+ "value": "ok"
96
+ },
97
+ "intent": "Confirm the recorded data satisfies the requested condition.",
98
+ "next": "done"
99
+ }
100
+ ],
101
+ "schema": {
102
+ "type": "object",
103
+ "properties": {
104
+ "path": {
105
+ "type": "string"
106
+ },
107
+ "assert": {
108
+ "type": "object",
109
+ "properties": {
110
+ "path": {
111
+ "type": "string"
112
+ },
113
+ "operator": {
114
+ "type": "string"
115
+ },
116
+ "value": {
117
+ "type": [
118
+ "string",
119
+ "number",
120
+ "integer",
121
+ "boolean",
122
+ "object",
123
+ "array"
124
+ ],
125
+ "items": {
126
+ "type": [
127
+ "string",
128
+ "number",
129
+ "integer",
130
+ "boolean",
131
+ "object"
132
+ ]
133
+ }
134
+ },
135
+ "all": {
136
+ "type": "array",
137
+ "items": {
138
+ "type": "object"
139
+ }
140
+ },
141
+ "any": {
142
+ "type": "array",
143
+ "items": {
144
+ "type": "object"
145
+ }
146
+ },
147
+ "none": {
148
+ "type": "array",
149
+ "items": {
150
+ "type": "object"
151
+ }
152
+ }
153
+ },
154
+ "additionalProperties": false
155
+ }
156
+ },
157
+ "required": [
158
+ "path",
159
+ "assert"
160
+ ],
161
+ "additionalProperties": false
162
+ }
163
+ },
164
+ "assert_exit_code": {
165
+ "description": "Assert the exit code captured from a command node output.",
87
166
  "examples": [
88
167
  {
168
+ "action": "assert_exit_code",
169
+ "source": "run-tests",
170
+ "expected": 0,
171
+ "intent": "Confirm the project command completed with the expected result.",
172
+ "next": "done"
173
+ }
174
+ ],
175
+ "schema": {
176
+ "type": "object",
177
+ "properties": {
178
+ "source": {
179
+ "type": "string"
180
+ },
89
181
  "node": {
90
- "action": "switch",
91
- "value": "{{params.mode}}",
92
- "equals": "background_resume",
93
- "cases": { "match": "background" },
94
- "default": "warm",
95
- "intent": "Choose the requested lifecycle preparation path"
182
+ "type": "string"
183
+ },
184
+ "expected": {
185
+ "type": "number"
96
186
  }
187
+ },
188
+ "additionalProperties": false
189
+ }
190
+ },
191
+ "assert_output": {
192
+ "description": "Assert stdout or stderr captured from a command node output.",
193
+ "examples": [
194
+ {
195
+ "action": "assert_output",
196
+ "source": "run-tests",
197
+ "stream": "stdout",
198
+ "contains": "PASS",
199
+ "intent": "Confirm the recorded output satisfies the requested condition.",
200
+ "next": "done"
97
201
  }
98
202
  ],
99
203
  "schema": {
100
204
  "type": "object",
101
205
  "properties": {
102
- "value": { "type": "string" },
103
- "equals": { "type": "string" }
206
+ "source": {
207
+ "type": "string"
208
+ },
209
+ "node": {
210
+ "type": "string"
211
+ },
212
+ "stream": {
213
+ "type": "string"
214
+ },
215
+ "contains": {
216
+ "type": "string"
217
+ },
218
+ "match": {
219
+ "type": "string"
220
+ },
221
+ "assert": {
222
+ "type": "object",
223
+ "properties": {
224
+ "path": {
225
+ "type": "string"
226
+ },
227
+ "operator": {
228
+ "type": "string"
229
+ },
230
+ "value": {
231
+ "type": [
232
+ "string",
233
+ "number",
234
+ "integer",
235
+ "boolean",
236
+ "object",
237
+ "array"
238
+ ],
239
+ "items": {
240
+ "type": [
241
+ "string",
242
+ "number",
243
+ "integer",
244
+ "boolean",
245
+ "object"
246
+ ]
247
+ }
248
+ },
249
+ "all": {
250
+ "type": "array",
251
+ "items": {
252
+ "type": "object"
253
+ }
254
+ },
255
+ "any": {
256
+ "type": "array",
257
+ "items": {
258
+ "type": "object"
259
+ }
260
+ },
261
+ "none": {
262
+ "type": "array",
263
+ "items": {
264
+ "type": "object"
265
+ }
266
+ }
267
+ },
268
+ "additionalProperties": false
269
+ }
104
270
  },
105
- "required": ["value", "equals"],
106
271
  "additionalProperties": false
107
- },
108
- "result_cases": ["match"]
272
+ }
109
273
  },
110
274
  "watch_logs": {
111
275
  "description": "Base log assertion/capture action.",
112
276
  "examples": [
113
277
  {
114
- "node": {
115
- "action": "watch_logs",
116
- "path": "logs/app.log",
117
- "intent": "Base log assertion/capture action"
118
- }
278
+ "action": "watch_logs",
279
+ "path": "logs/app.log",
280
+ "intent": "Observe the runtime behavior needed for this proof.",
281
+ "next": "done"
119
282
  }
120
283
  ],
121
284
  "schema": {
@@ -145,18 +308,17 @@
145
308
  "description": "Index extra recipe-authored artifacts that already exist on disk. Do not use after ui.screenshot; screenshots are registered by the runner.",
146
309
  "examples": [
147
310
  {
148
- "node": {
149
- "action": "index_artifacts",
150
- "artifacts": [
151
- {
152
- "path": "reports/result.json",
153
- "type": "report",
154
- "category": "validation",
155
- "label": "Validation report"
156
- }
157
- ],
158
- "intent": "Register a pre-existing report artifact"
159
- }
311
+ "action": "index_artifacts",
312
+ "artifacts": [
313
+ {
314
+ "path": "reports/result.json",
315
+ "type": "report",
316
+ "category": "validation",
317
+ "label": "Validation report"
318
+ }
319
+ ],
320
+ "intent": "Preserve generated evidence in the review package.",
321
+ "next": "done"
160
322
  }
161
323
  ],
162
324
  "schema": {
@@ -212,11 +374,54 @@
212
374
  "description": "Base terminal action.",
213
375
  "examples": [
214
376
  {
215
- "node": {
216
- "action": "end",
217
- "status": "pass"
218
- }
377
+ "action": "end",
378
+ "status": "pass"
379
+ }
380
+ ]
381
+ },
382
+ "call": {
383
+ "description": "Invoke a named recipe by ref and run its steps inline.",
384
+ "examples": [
385
+ {
386
+ "action": "call",
387
+ "ref": "mydev.open_perps_setup",
388
+ "intent": "Run a personal Perps setup recipe",
389
+ "next": "done"
390
+ }
391
+ ]
392
+ },
393
+ "switch": {
394
+ "description": "Choose a graph branch when one resolved string equals another.",
395
+ "examples": [
396
+ {
397
+ "action": "switch",
398
+ "value": "{{params.mode}}",
399
+ "equals": "background_resume",
400
+ "cases": {
401
+ "match": "background"
402
+ },
403
+ "default": "warm",
404
+ "intent": "Choose the graph path matching the observed state."
219
405
  }
406
+ ],
407
+ "schema": {
408
+ "type": "object",
409
+ "properties": {
410
+ "value": {
411
+ "type": "string"
412
+ },
413
+ "equals": {
414
+ "type": "string"
415
+ }
416
+ },
417
+ "required": [
418
+ "value",
419
+ "equals"
420
+ ],
421
+ "additionalProperties": false
422
+ },
423
+ "result_cases": [
424
+ "match"
220
425
  ]
221
426
  },
222
427
  "ui.navigate": {
@@ -266,29 +471,23 @@
266
471
  },
267
472
  "examples": [
268
473
  {
269
- "description": "Ask the adapter to discover and open the current Perps entry point",
270
- "node": {
271
- "action": "ui.navigate",
272
- "page": "perps",
273
- "intent": "Open Perps"
274
- }
474
+ "action": "ui.navigate",
475
+ "page": "perps",
476
+ "intent": "Open the requested application surface.",
477
+ "next": "done"
275
478
  },
276
479
  {
277
- "description": "Open a Perps market through the current verified adapter path",
278
- "node": {
279
- "action": "ui.navigate",
280
- "page": "perps-market",
281
- "market": "ETH",
282
- "intent": "Open ETH Perps market"
283
- }
480
+ "action": "ui.navigate",
481
+ "page": "perps-market",
482
+ "market": "ETH",
483
+ "intent": "Open the requested application surface.",
484
+ "next": "done"
284
485
  },
285
486
  {
286
- "description": "Use a raw extension hash only after verifying it in the current app",
287
- "node": {
288
- "action": "ui.navigate",
289
- "hash": "#/perps-home",
290
- "intent": "Open a raw extension route"
291
- }
487
+ "action": "ui.navigate",
488
+ "hash": "#/perps-home",
489
+ "intent": "Open the requested application surface.",
490
+ "next": "done"
292
491
  }
293
492
  ]
294
493
  },
@@ -296,11 +495,10 @@
296
495
  "description": "Press/tap/click a UI target through the platform adapter.",
297
496
  "examples": [
298
497
  {
299
- "node": {
300
- "action": "ui.press",
301
- "intent": "Press/tap/click a UI target through the platform adapter",
302
- "text": "Perps"
303
- }
498
+ "action": "ui.press",
499
+ "intent": "Activate the requested visible control.",
500
+ "text": "Perps",
501
+ "next": "done"
304
502
  }
305
503
  ],
306
504
  "schema": {
@@ -331,75 +529,37 @@
331
529
  "additionalProperties": false
332
530
  }
333
531
  },
334
- "ui.scroll": {
335
- "description": "Scroll through the UI through the Farmslot base platform adapter. Supports deltas and scroll_into_view for selector/test-id proof positioning.",
336
- "examples": [
337
- {
338
- "node": {
339
- "action": "ui.scroll",
340
- "delta_y": 300,
341
- "intent": "Scroll through the UI through the Farmslot base platform adapter. Supports deltas and scroll_into_view for selector/test-id proof positioning"
342
- }
343
- },
344
- {
345
- "description": "Bring a web selector into view before screenshot proof",
346
- "node": {
347
- "action": "ui.scroll",
348
- "selector": "[data-testid=\"example\"]",
349
- "scroll_into_view": true,
350
- "intent": "Bring a web selector into view before screenshot proof"
351
- }
352
- }
353
- ],
354
- "proof_effect": "E2E validation must include a passing ui-scroll-into-view trace event with output.intoView=true.",
532
+ "ui.key_press": {
533
+ "description": "Send a trusted keyboard press to the currently focused UI element through the UI transport.",
355
534
  "schema": {
356
535
  "type": "object",
357
536
  "properties": {
358
- "selector": {
359
- "type": "string"
360
- },
361
- "test_id": {
362
- "type": "string"
363
- },
364
- "testID": {
537
+ "key": {
365
538
  "type": "string"
366
539
  },
367
- "delta_x": {
368
- "type": "number"
369
- },
370
- "delta_y": {
371
- "type": "number"
372
- },
373
- "deltaX": {
374
- "type": "number"
375
- },
376
- "deltaY": {
377
- "type": "number"
378
- },
379
- "offset": {
380
- "type": "number"
381
- },
382
- "scroll_into_view": {
383
- "type": "boolean"
384
- },
385
- "into_view": {
386
- "type": "boolean"
387
- },
388
- "animated": {
389
- "type": "boolean"
390
- },
391
- "timeout_ms": {
540
+ "timeout_ms": {
392
541
  "type": "number"
393
542
  },
394
543
  "settle": {
395
544
  "type": "boolean"
396
545
  }
397
546
  },
547
+ "required": [
548
+ "key"
549
+ ],
398
550
  "additionalProperties": false
399
- }
551
+ },
552
+ "examples": [
553
+ {
554
+ "action": "ui.key_press",
555
+ "key": "Enter",
556
+ "intent": "Continue the requested keyboard interaction.",
557
+ "next": "done"
558
+ }
559
+ ]
400
560
  },
401
- "ui.wait_for": {
402
- "description": "Wait for a UI condition through the Extension CDP adapter.",
561
+ "ui.set_input": {
562
+ "description": "Set text on an extension DOM input through the CDP UI transport.",
403
563
  "schema": {
404
564
  "type": "object",
405
565
  "properties": {
@@ -412,312 +572,208 @@
412
572
  "testID": {
413
573
  "type": "string"
414
574
  },
415
- "text": {
416
- "type": "string"
417
- },
418
- "text_match": {
419
- "type": "string"
420
- },
421
- "textMatch": {
422
- "type": "string"
575
+ "value": {
576
+ "type": [
577
+ "string",
578
+ "number"
579
+ ],
580
+ "description": "Text or a typed numeric recipe parameter; numbers are entered as their decimal text."
423
581
  },
424
- "expected": {
582
+ "text": {
425
583
  "type": "string"
426
584
  },
427
- "visible": {
428
- "type": "boolean"
429
- },
430
585
  "timeout_ms": {
431
586
  "type": "number"
587
+ },
588
+ "settle": {
589
+ "type": "boolean"
432
590
  }
433
591
  },
434
592
  "additionalProperties": false
435
593
  },
436
594
  "examples": [
437
595
  {
438
- "node": {
439
- "action": "ui.wait_for",
440
- "text": "Perps",
441
- "intent": "Wait for visible Extension text"
442
- }
443
- },
444
- {
445
- "node": {
446
- "action": "ui.wait_for",
447
- "selector": "[data-testid=example]",
448
- "visible": false,
449
- "timeout_ms": 2000,
450
- "intent": "Prove an Extension element is absent"
451
- }
596
+ "action": "ui.set_input",
597
+ "selector": "[data-testid=multichain-account-list-search] input",
598
+ "value": "Account",
599
+ "intent": "Provide the requested value in the visible form.",
600
+ "next": "done"
452
601
  }
453
602
  ]
454
603
  },
455
- "ui.screenshot": {
456
- "description": "Capture registered visual evidence through capture-helper, bounded Chrome-native capture, or an explicitly labeled computed-style DOM raster fallback. Always read the resulting PNG; artifact metadata records the provider.",
604
+ "ui.scroll": {
605
+ "description": "Scroll through the UI through the Farmslot base platform adapter. Supports deltas and scroll_into_view for selector/test-id proof positioning.",
457
606
  "examples": [
458
607
  {
459
- "node": {
460
- "action": "ui.screenshot",
461
- "path": "screenshots/example.png",
462
- "intent": "Capture visual evidence after a wait/assert step"
463
- }
608
+ "action": "ui.scroll",
609
+ "delta_y": 300,
610
+ "intent": "Expose the requested content for visible review.",
611
+ "next": "done"
612
+ },
613
+ {
614
+ "action": "ui.scroll",
615
+ "selector": "[data-testid=\"example\"]",
616
+ "scroll_into_view": true,
617
+ "intent": "Expose the requested content for visible review.",
618
+ "next": "done"
464
619
  }
465
620
  ],
466
621
  "schema": {
467
622
  "type": "object",
468
623
  "properties": {
469
- "path": {
624
+ "selector": {
470
625
  "type": "string"
471
626
  },
472
- "label": {
627
+ "test_id": {
473
628
  "type": "string"
474
629
  },
475
- "category": {
630
+ "testID": {
476
631
  "type": "string"
477
632
  },
478
- "timeout_ms": {
633
+ "delta_x": {
479
634
  "type": "number"
480
- }
481
- },
482
- "additionalProperties": false
483
- }
484
- },
485
- "assert_file": {
486
- "description": "Assert that a project file exists and optionally contains text.",
487
- "examples": [
488
- {
489
- "node": {
490
- "action": "assert_file",
491
- "path": "reports/result.txt",
492
- "contains": "ok",
493
- "intent": "Assert that a project file exists and optionally contains text"
494
- }
495
- }
496
- ],
497
- "schema": {
498
- "type": "object",
499
- "properties": {
500
- "path": {
501
- "type": "string"
502
635
  },
503
- "contains": {
504
- "type": "string"
505
- }
506
- },
507
- "required": [
508
- "path"
509
- ],
510
- "additionalProperties": false
511
- }
512
- },
513
- "assert_json": {
514
- "description": "Assert a JSON file value with a JSONPath-style selector.",
515
- "examples": [
516
- {
517
- "node": {
518
- "action": "assert_json",
519
- "path": "reports/result.json",
520
- "assert": {
521
- "path": "$.status",
522
- "operator": "eq",
523
- "value": "ok"
524
- },
525
- "intent": "Assert a JSON file value with a JSONPath-style selector"
526
- }
527
- }
528
- ],
529
- "schema": {
530
- "type": "object",
531
- "properties": {
532
- "path": {
533
- "type": "string"
636
+ "delta_y": {
637
+ "type": "number"
534
638
  },
535
- "assert": {
536
- "type": "object",
537
- "properties": {
538
- "path": {
539
- "type": "string"
540
- },
541
- "operator": {
542
- "type": "string"
543
- },
544
- "value": {
545
- "type": [
546
- "string",
547
- "number",
548
- "integer",
549
- "boolean",
550
- "object",
551
- "array"
552
- ],
553
- "items": {
554
- "type": [
555
- "string",
556
- "number",
557
- "integer",
558
- "boolean",
559
- "object"
560
- ]
561
- }
562
- },
563
- "all": {
564
- "type": "array",
565
- "items": {
566
- "type": "object"
567
- }
568
- },
569
- "any": {
570
- "type": "array",
571
- "items": {
572
- "type": "object"
573
- }
574
- },
575
- "none": {
576
- "type": "array",
577
- "items": {
578
- "type": "object"
579
- }
580
- }
581
- },
582
- "additionalProperties": false
583
- }
584
- },
585
- "required": [
586
- "path",
587
- "assert"
588
- ],
589
- "additionalProperties": false
590
- }
591
- },
592
- "assert_exit_code": {
593
- "description": "Assert the exit code captured from a command node output.",
594
- "examples": [
595
- {
596
- "node": {
597
- "action": "assert_exit_code",
598
- "source": "run-tests",
599
- "expected": 0,
600
- "intent": "Assert the exit code captured from a command node output"
601
- }
602
- }
603
- ],
604
- "schema": {
605
- "type": "object",
606
- "properties": {
607
- "source": {
608
- "type": "string"
639
+ "deltaX": {
640
+ "type": "number"
609
641
  },
610
- "node": {
611
- "type": "string"
642
+ "deltaY": {
643
+ "type": "number"
612
644
  },
613
- "expected": {
645
+ "offset": {
646
+ "type": "number"
647
+ },
648
+ "scroll_into_view": {
649
+ "type": "boolean"
650
+ },
651
+ "into_view": {
652
+ "type": "boolean"
653
+ },
654
+ "animated": {
655
+ "type": "boolean"
656
+ },
657
+ "timeout_ms": {
614
658
  "type": "number"
659
+ },
660
+ "settle": {
661
+ "type": "boolean"
615
662
  }
616
663
  },
617
664
  "additionalProperties": false
618
665
  }
619
666
  },
620
- "assert_output": {
621
- "description": "Assert stdout or stderr captured from a command node output.",
622
- "examples": [
623
- {
624
- "node": {
625
- "action": "assert_output",
626
- "source": "run-tests",
627
- "stream": "stdout",
628
- "contains": "PASS",
629
- "intent": "Assert stdout or stderr captured from a command node output"
630
- }
631
- }
632
- ],
667
+ "ui.wait_for": {
668
+ "description": "Wait for a UI condition through the Extension CDP adapter.",
633
669
  "schema": {
634
670
  "type": "object",
635
671
  "properties": {
636
- "source": {
672
+ "selector": {
637
673
  "type": "string"
638
674
  },
639
- "node": {
675
+ "test_id": {
640
676
  "type": "string"
641
677
  },
642
- "stream": {
678
+ "testID": {
643
679
  "type": "string"
644
680
  },
645
- "contains": {
681
+ "text": {
646
682
  "type": "string"
647
683
  },
648
- "match": {
684
+ "text_match": {
649
685
  "type": "string"
650
686
  },
651
- "assert": {
652
- "type": "object",
653
- "properties": {
654
- "path": {
655
- "type": "string"
656
- },
657
- "operator": {
658
- "type": "string"
659
- },
660
- "value": {
661
- "type": [
662
- "string",
663
- "number",
664
- "integer",
665
- "boolean",
666
- "object",
667
- "array"
668
- ],
669
- "items": {
670
- "type": [
671
- "string",
672
- "number",
673
- "integer",
674
- "boolean",
675
- "object"
676
- ]
677
- }
678
- },
679
- "all": {
680
- "type": "array",
681
- "items": {
682
- "type": "object"
683
- }
684
- },
685
- "any": {
686
- "type": "array",
687
- "items": {
688
- "type": "object"
689
- }
690
- },
691
- "none": {
692
- "type": "array",
693
- "items": {
694
- "type": "object"
695
- }
696
- }
697
- },
698
- "additionalProperties": false
687
+ "textMatch": {
688
+ "type": "string"
689
+ },
690
+ "expected": {
691
+ "type": "string"
692
+ },
693
+ "visible": {
694
+ "type": "boolean"
695
+ },
696
+ "timeout_ms": {
697
+ "type": "number"
698
+ }
699
+ },
700
+ "additionalProperties": false
701
+ },
702
+ "examples": [
703
+ {
704
+ "action": "ui.wait_for",
705
+ "text": "Perps",
706
+ "intent": "Confirm the requested application state is visible.",
707
+ "next": "done"
708
+ },
709
+ {
710
+ "action": "ui.wait_for",
711
+ "selector": "[data-testid=example]",
712
+ "visible": false,
713
+ "timeout_ms": 2000,
714
+ "intent": "Confirm the requested application state is visible.",
715
+ "next": "done"
716
+ }
717
+ ]
718
+ },
719
+ "ui.screenshot": {
720
+ "description": "Capture registered visual evidence through capture-helper, bounded Chrome-native capture, or an explicitly labeled computed-style DOM raster fallback. Always read the resulting PNG; artifact metadata records the provider.",
721
+ "examples": [
722
+ {
723
+ "action": "ui.screenshot",
724
+ "path": "screenshots/example.png",
725
+ "intent": "Preserve the visible application state as review evidence.",
726
+ "next": "done"
727
+ }
728
+ ],
729
+ "schema": {
730
+ "type": "object",
731
+ "properties": {
732
+ "path": {
733
+ "type": "string"
734
+ },
735
+ "label": {
736
+ "type": "string"
737
+ },
738
+ "category": {
739
+ "type": "string"
740
+ },
741
+ "timeout_ms": {
742
+ "type": "number"
699
743
  }
700
744
  },
701
745
  "additionalProperties": false
702
746
  }
703
747
  },
748
+ "app.status": {
749
+ "description": "Report the adapter's static status — platform, project root, resolved checkout shape, and headless compatibility mode (no live route or account).",
750
+ "examples": [
751
+ {
752
+ "action": "app.status",
753
+ "intent": "Record the resolved application state before continuing.",
754
+ "next": "done"
755
+ }
756
+ ],
757
+ "schema": {
758
+ "type": "object",
759
+ "properties": {},
760
+ "additionalProperties": false
761
+ }
762
+ },
704
763
  "app.hud": {
705
764
  "description": "Display minimal human-readable recipe progress. The intent must explain the current agent goal; debug metadata and grouping labels are hidden unless explicitly opted in.",
706
765
  "examples": [
707
766
  {
708
- "description": "Default one-intent progress HUD",
709
- "node": {
710
- "action": "app.hud",
711
- "status": "running",
712
- "intent": "Open a small ETH long position",
713
- "progress": {
714
- "current": 12,
715
- "total": 19
716
- }
717
- }
767
+ "action": "app.hud",
768
+ "status": "running",
769
+ "intent": "Show the current goal to the supervising human.",
770
+ "progress": {
771
+ "current": 12,
772
+ "total": 19
773
+ },
774
+ "next": "done"
718
775
  }
719
776
  ],
720
- "safety_notes": "HUD is reviewer feedback only. It must not mutate product state or carry task assertions; trace/artifacts remain authoritative.",
721
777
  "schema": {
722
778
  "type": "object",
723
779
  "properties": {
@@ -769,106 +825,15 @@
769
825
  "additionalProperties": false
770
826
  }
771
827
  },
772
- "ui.set_input": {
773
- "description": "Set text on an extension DOM input through the CDP UI transport.",
774
- "schema": {
775
- "type": "object",
776
- "properties": {
777
- "selector": {
778
- "type": "string"
779
- },
780
- "test_id": {
781
- "type": "string"
782
- },
783
- "testID": {
784
- "type": "string"
785
- },
786
- "value": {
787
- "type": [
788
- "string",
789
- "number"
790
- ],
791
- "description": "Text or a typed numeric recipe parameter; numbers are entered as their decimal text."
792
- },
793
- "text": {
794
- "type": "string"
795
- },
796
- "timeout_ms": {
797
- "type": "number"
798
- },
799
- "settle": {
800
- "type": "boolean"
801
- }
802
- },
803
- "additionalProperties": false
804
- },
805
- "examples": [
806
- {
807
- "node": {
808
- "action": "ui.set_input",
809
- "selector": "[data-testid=multichain-account-list-search] input",
810
- "value": "Account",
811
- "intent": "Set text on an extension DOM input through the CDP UI transport"
812
- }
813
- }
814
- ]
815
- },
816
- "ui.key_press": {
817
- "description": "Send a trusted keyboard press to the currently focused UI element through the UI transport.",
818
- "schema": {
819
- "type": "object",
820
- "properties": {
821
- "key": {
822
- "type": "string"
823
- },
824
- "timeout_ms": {
825
- "type": "number"
826
- },
827
- "settle": {
828
- "type": "boolean"
829
- }
830
- },
831
- "required": [
832
- "key"
833
- ],
834
- "additionalProperties": false
835
- },
836
- "examples": [
837
- {
838
- "node": {
839
- "action": "ui.key_press",
840
- "key": "Enter",
841
- "intent": "Send a trusted Enter key press to the focused UI element"
842
- }
843
- }
844
- ]
845
- },
846
- "app.status": {
847
- "description": "Report the adapter's static status — platform, project root, resolved checkout shape, and headless compatibility mode (no live route or account).",
848
- "examples": [
849
- {
850
- "node": {
851
- "action": "app.status",
852
- "intent": "Report the resolved checkout status"
853
- }
854
- }
855
- ],
856
- "schema": {
857
- "type": "object",
858
- "properties": {},
859
- "additionalProperties": false
860
- }
861
- },
862
828
  "cdp.target": {
863
829
  "description": "Probe the platform debug transport — Chrome CDP for extension, the React Native debug bridge for mobile — and report whether it is reachable.",
864
830
  "examples": [
865
831
  {
866
- "node": {
867
- "action": "cdp.target",
868
- "cdp_port": 9323,
869
- "required": true,
870
- "intent": "Confirm the extension CDP endpoint is reachable"
871
- }
832
+ "action": "cdp.target",
833
+ "cdp_port": 9323,
834
+ "required": true,
835
+ "intent": "Confirm the requested application target is available.",
836
+ "next": "done"
872
837
  }
873
838
  ],
874
839
  "schema": {
@@ -902,23 +867,7 @@
902
867
  "additionalProperties": false
903
868
  }
904
869
  },
905
- "call": {
906
- "description": "Invoke a named recipe by ref and run its steps inline.",
907
- "examples": [
908
- {
909
- "node": {
910
- "action": "call",
911
- "ref": "mydev.open_perps_setup",
912
- "intent": "Run a personal Perps setup recipe"
913
- }
914
- }
915
- ]
916
- }
917
- },
918
- "custom_actions": [
919
- {
920
- "name": "metamask.wallet.fixture_status",
921
- "owner": "metamask",
870
+ "metamask.wallet.fixture_status": {
922
871
  "description": "Report the on-disk wallet fixture status (accounts and password presence) without launching or mutating the app.",
923
872
  "schema": {
924
873
  "type": "object",
@@ -927,20 +876,14 @@
927
876
  },
928
877
  "examples": [
929
878
  {
930
- "description": "Minimal node",
931
- "node": {
932
- "action": "metamask.wallet.fixture_status",
933
- "intent": "Check wallet fixture status"
934
- }
879
+ "action": "metamask.wallet.fixture_status",
880
+ "intent": "Check wallet fixture status",
881
+ "next": "done"
935
882
  }
936
883
  ],
937
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
938
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
939
884
  "execution_capabilities": []
940
885
  },
941
- {
942
- "name": "metamask.wallet.setup",
943
- "owner": "metamask",
886
+ "metamask.wallet.setup": {
944
887
  "description": "Import the wallet fixture accounts and password so the app starts from a known signed-in state.",
945
888
  "schema": {
946
889
  "type": "object",
@@ -949,22 +892,16 @@
949
892
  },
950
893
  "examples": [
951
894
  {
952
- "description": "Minimal node",
953
- "node": {
954
- "action": "metamask.wallet.setup",
955
- "intent": "Prepare the wallet fixture for recipe execution"
956
- }
895
+ "action": "metamask.wallet.setup",
896
+ "intent": "Prepare the wallet fixture for recipe execution",
897
+ "next": "done"
957
898
  }
958
899
  ],
959
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
960
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
961
900
  "execution_capabilities": [
962
901
  "app-mutation"
963
902
  ]
964
903
  },
965
- {
966
- "name": "metamask.wallet.ensure_unlocked",
967
- "owner": "metamask",
904
+ "metamask.wallet.ensure_unlocked": {
968
905
  "description": "Unlock the wallet with the fixture password when it is currently locked.",
969
906
  "schema": {
970
907
  "type": "object",
@@ -977,21 +914,16 @@
977
914
  },
978
915
  "examples": [
979
916
  {
980
- "description": "Minimal node",
981
- "node": {
982
- "action": "metamask.wallet.ensure_unlocked",
983
- "intent": "Ensure the wallet is unlocked before proof steps"
984
- }
917
+ "action": "metamask.wallet.ensure_unlocked",
918
+ "intent": "Ensure the wallet is unlocked before proof steps",
919
+ "next": "done"
985
920
  }
986
921
  ],
987
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
988
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
989
922
  "execution_capabilities": [
990
923
  "app-mutation"
991
924
  ]
992
925
  },
993
- {
994
- "name": "metamask.wallet.select_account",
926
+ "metamask.wallet.select_account": {
995
927
  "description": "extension action to select a wallet account by address, id, or display name.",
996
928
  "schema": {
997
929
  "type": "object",
@@ -1013,30 +945,23 @@
1013
945
  },
1014
946
  "examples": [
1015
947
  {
1016
- "description": "Select by deterministic fixture address",
1017
- "node": {
1018
- "action": "metamask.wallet.select_account",
1019
- "address": "0x8dc623e964475d4d669da601fd15ea9125469003",
1020
- "intent": "Select the requested wallet account"
1021
- }
948
+ "action": "metamask.wallet.select_account",
949
+ "address": "0x8dc623e964475d4d669da601fd15ea9125469003",
950
+ "intent": "Select the requested wallet account",
951
+ "next": "done"
1022
952
  },
1023
953
  {
1024
- "description": "Select by fixture display name",
1025
- "node": {
1026
- "action": "metamask.wallet.select_account",
1027
- "name": "dev1",
1028
- "intent": "Select the requested wallet account"
1029
- }
954
+ "action": "metamask.wallet.select_account",
955
+ "name": "dev1",
956
+ "intent": "Select the requested wallet account",
957
+ "next": "done"
1030
958
  }
1031
959
  ],
1032
- "owner": "metamask",
1033
960
  "execution_capabilities": [
1034
961
  "app-mutation"
1035
962
  ]
1036
963
  },
1037
- {
1038
- "name": "metamask.wallet.list_accounts",
1039
- "owner": "metamask",
964
+ "metamask.wallet.list_accounts": {
1040
965
  "description": "List redacted wallet accounts and identify the selected account without mutating the app.",
1041
966
  "schema": {
1042
967
  "type": "object",
@@ -1057,20 +982,14 @@
1057
982
  },
1058
983
  "examples": [
1059
984
  {
1060
- "description": "List wallet accounts",
1061
- "node": {
1062
- "action": "metamask.wallet.list_accounts",
1063
- "intent": "Discover the available wallet accounts"
1064
- }
985
+ "action": "metamask.wallet.list_accounts",
986
+ "intent": "Discover the available wallet accounts",
987
+ "next": "done"
1065
988
  }
1066
989
  ],
1067
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1068
- "safety_notes": "Read-only account metadata; must never expose keys, mnemonics, vault data, or credentials.",
1069
990
  "execution_capabilities": []
1070
991
  },
1071
- {
1072
- "name": "metamask.wallet.read_state",
1073
- "owner": "metamask",
992
+ "metamask.wallet.read_state": {
1074
993
  "description": "Read the redacted wallet state (selected account, route, and device) from the running app.",
1075
994
  "schema": {
1076
995
  "type": "object",
@@ -1079,20 +998,14 @@
1079
998
  },
1080
999
  "examples": [
1081
1000
  {
1082
- "description": "Minimal node",
1083
- "node": {
1084
- "action": "metamask.wallet.read_state",
1085
- "intent": "Read wallet state needed for the proof"
1086
- }
1001
+ "action": "metamask.wallet.read_state",
1002
+ "intent": "Read wallet state needed for the proof",
1003
+ "next": "done"
1087
1004
  }
1088
1005
  ],
1089
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1090
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1091
1006
  "execution_capabilities": []
1092
1007
  },
1093
- {
1094
- "name": "metamask.perps.read_positions",
1095
- "owner": "metamask",
1008
+ "metamask.perps.read_positions": {
1096
1009
  "description": "extension Read live Perps positions; without a selector, return all live positions.",
1097
1010
  "schema": {
1098
1011
  "type": "object",
@@ -1181,21 +1094,15 @@
1181
1094
  },
1182
1095
  "examples": [
1183
1096
  {
1184
- "description": "Read selected live state",
1185
- "node": {
1186
- "action": "metamask.perps.read_positions",
1187
- "market": "BTC",
1188
- "intent": "Read Perps positions needed for the proof"
1189
- }
1097
+ "action": "metamask.perps.read_positions",
1098
+ "market": "BTC",
1099
+ "intent": "Read Perps positions needed for the proof",
1100
+ "next": "done"
1190
1101
  }
1191
1102
  ],
1192
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1193
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1194
1103
  "execution_capabilities": []
1195
1104
  },
1196
- {
1197
- "name": "metamask.perps.read_orders",
1198
- "owner": "metamask",
1105
+ "metamask.perps.read_orders": {
1199
1106
  "description": "extension Read live Perps open orders; without a selector, return all live orders.",
1200
1107
  "schema": {
1201
1108
  "type": "object",
@@ -1284,21 +1191,15 @@
1284
1191
  },
1285
1192
  "examples": [
1286
1193
  {
1287
- "description": "Read selected live state",
1288
- "node": {
1289
- "action": "metamask.perps.read_orders",
1290
- "market": "BTC",
1291
- "intent": "Read Perps open orders needed for the proof"
1292
- }
1194
+ "action": "metamask.perps.read_orders",
1195
+ "market": "BTC",
1196
+ "intent": "Read Perps open orders needed for the proof",
1197
+ "next": "done"
1293
1198
  }
1294
1199
  ],
1295
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1296
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1297
1200
  "execution_capabilities": []
1298
1201
  },
1299
- {
1300
- "name": "metamask.perps.close_positions",
1301
- "owner": "metamask",
1202
+ "metamask.perps.close_positions": {
1302
1203
  "description": "extension Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested. Close selected live Perps positions. Use selector/mode params to close matching symbols or all positions.",
1303
1204
  "schema": {
1304
1205
  "type": "object",
@@ -1387,35 +1288,27 @@
1387
1288
  },
1388
1289
  "examples": [
1389
1290
  {
1390
- "description": "Close every open position",
1391
- "node": {
1392
- "action": "metamask.perps.close_positions",
1393
- "mode": "all",
1394
- "intent": "Close selected Perps positions before continuing"
1395
- }
1291
+ "action": "metamask.perps.close_positions",
1292
+ "mode": "all",
1293
+ "intent": "Close selected Perps positions before continuing",
1294
+ "next": "done"
1396
1295
  },
1397
1296
  {
1398
- "description": "Close selected BTC/ETH positions",
1399
- "node": {
1400
- "action": "metamask.perps.close_positions",
1401
- "markets": [
1402
- "BTC",
1403
- "ETH"
1404
- ],
1405
- "intent": "Close selected Perps positions before continuing"
1406
- }
1297
+ "action": "metamask.perps.close_positions",
1298
+ "markets": [
1299
+ "BTC",
1300
+ "ETH"
1301
+ ],
1302
+ "intent": "Close selected Perps positions before continuing",
1303
+ "next": "done"
1407
1304
  }
1408
1305
  ],
1409
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1410
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1411
1306
  "execution_capabilities": [
1412
1307
  "app-mutation",
1413
1308
  "external-mutation"
1414
1309
  ]
1415
1310
  },
1416
- {
1417
- "name": "metamask.perps.close_orders",
1418
- "owner": "metamask",
1311
+ "metamask.perps.close_orders": {
1419
1312
  "description": "extension 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.",
1420
1313
  "schema": {
1421
1314
  "type": "object",
@@ -1504,32 +1397,24 @@
1504
1397
  },
1505
1398
  "examples": [
1506
1399
  {
1507
- "description": "Cancel every open order",
1508
- "node": {
1509
- "action": "metamask.perps.close_orders",
1510
- "mode": "all",
1511
- "intent": "Cancel selected Perps orders before continuing"
1512
- }
1400
+ "action": "metamask.perps.close_orders",
1401
+ "mode": "all",
1402
+ "intent": "Cancel selected Perps orders before continuing",
1403
+ "next": "done"
1513
1404
  },
1514
1405
  {
1515
- "description": "Cancel BTC orders only",
1516
- "node": {
1517
- "action": "metamask.perps.close_orders",
1518
- "market": "BTC",
1519
- "intent": "Cancel selected Perps orders before continuing"
1520
- }
1406
+ "action": "metamask.perps.close_orders",
1407
+ "market": "BTC",
1408
+ "intent": "Cancel selected Perps orders before continuing",
1409
+ "next": "done"
1521
1410
  }
1522
1411
  ],
1523
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1524
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1525
1412
  "execution_capabilities": [
1526
1413
  "app-mutation",
1527
1414
  "external-mutation"
1528
1415
  ]
1529
1416
  },
1530
- {
1531
- "name": "metamask.perps.place_order",
1532
- "owner": "metamask",
1417
+ "metamask.perps.place_order": {
1533
1418
  "description": "extension Place a Perps order through a supported app/API path. Default to testnet; mainnet order placement requires an explicit user request.",
1534
1419
  "schema": {
1535
1420
  "type": "object",
@@ -1640,27 +1525,21 @@
1640
1525
  },
1641
1526
  "examples": [
1642
1527
  {
1643
- "description": "Place BTC market order",
1644
- "node": {
1645
- "action": "metamask.perps.place_order",
1646
- "market": "BTC",
1647
- "side": "long",
1648
- "notional": "10",
1649
- "leverage": 2,
1650
- "intent": "Place the requested Perps order"
1651
- }
1528
+ "action": "metamask.perps.place_order",
1529
+ "market": "BTC",
1530
+ "side": "long",
1531
+ "notional": "10",
1532
+ "leverage": 2,
1533
+ "intent": "Place the requested Perps order",
1534
+ "next": "done"
1652
1535
  }
1653
1536
  ],
1654
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1655
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1656
1537
  "execution_capabilities": [
1657
1538
  "app-mutation",
1658
1539
  "external-mutation"
1659
1540
  ]
1660
1541
  },
1661
- {
1662
- "name": "metamask.perps.assert_positions",
1663
- "owner": "metamask",
1542
+ "metamask.perps.assert_positions": {
1664
1543
  "description": "extension Assert live Perps positions are present or absent for an explicit market selection or mode=all.",
1665
1544
  "schema": {
1666
1545
  "type": "object",
@@ -1763,22 +1642,16 @@
1763
1642
  },
1764
1643
  "examples": [
1765
1644
  {
1766
- "description": "Assert BTC position is open",
1767
- "node": {
1768
- "action": "metamask.perps.assert_positions",
1769
- "state": "open",
1770
- "market": "BTC",
1771
- "intent": "Assert the expected Perps position state"
1772
- }
1645
+ "action": "metamask.perps.assert_positions",
1646
+ "state": "open",
1647
+ "market": "BTC",
1648
+ "intent": "Assert the expected Perps position state",
1649
+ "next": "done"
1773
1650
  }
1774
1651
  ],
1775
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1776
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1777
1652
  "execution_capabilities": []
1778
1653
  },
1779
- {
1780
- "name": "metamask.perps.assert_orders",
1781
- "owner": "metamask",
1654
+ "metamask.perps.assert_orders": {
1782
1655
  "description": "extension Assert live Perps open orders are present or absent for an explicit market selection or mode=all.",
1783
1656
  "schema": {
1784
1657
  "type": "object",
@@ -1881,22 +1754,16 @@
1881
1754
  },
1882
1755
  "examples": [
1883
1756
  {
1884
- "description": "Assert no BTC open orders",
1885
- "node": {
1886
- "action": "metamask.perps.assert_orders",
1887
- "state": "none",
1888
- "market": "BTC",
1889
- "intent": "Assert the expected Perps open order state"
1890
- }
1757
+ "action": "metamask.perps.assert_orders",
1758
+ "state": "none",
1759
+ "market": "BTC",
1760
+ "intent": "Assert the expected Perps open order state",
1761
+ "next": "done"
1891
1762
  }
1892
1763
  ],
1893
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
1894
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
1895
1764
  "execution_capabilities": []
1896
1765
  },
1897
- {
1898
- "name": "metamask.perps.ensure_positions",
1899
- "owner": "metamask",
1766
+ "metamask.perps.ensure_positions": {
1900
1767
  "description": "extension Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested. Higher-level wrapper that reads selected positions, closes or places when needed, then asserts final position state.",
1901
1768
  "schema": {
1902
1769
  "type": "object",
@@ -2013,45 +1880,35 @@
2013
1880
  },
2014
1881
  "examples": [
2015
1882
  {
2016
- "description": "Ensure no BTC position before proof window",
2017
- "node": {
2018
- "action": "metamask.perps.ensure_positions",
2019
- "state": "none",
2020
- "market": "BTC",
2021
- "intent": "Converge Perps positions to the requested state"
2022
- }
1883
+ "action": "metamask.perps.ensure_positions",
1884
+ "state": "none",
1885
+ "market": "BTC",
1886
+ "intent": "Converge Perps positions to the requested state",
1887
+ "next": "done"
2023
1888
  },
2024
1889
  {
2025
- "description": "Ensure any existing positions are closed",
2026
- "node": {
2027
- "action": "metamask.perps.ensure_positions",
2028
- "state": "none",
2029
- "mode": "all",
2030
- "intent": "Converge Perps positions to the requested state"
2031
- }
1890
+ "action": "metamask.perps.ensure_positions",
1891
+ "state": "none",
1892
+ "mode": "all",
1893
+ "intent": "Converge Perps positions to the requested state",
1894
+ "next": "done"
2032
1895
  },
2033
1896
  {
2034
- "description": "Ensure one ETH long position exists",
2035
- "node": {
2036
- "action": "metamask.perps.ensure_positions",
2037
- "market": "ETH",
2038
- "side": "long",
2039
- "state": "open",
2040
- "notional": "10",
2041
- "intent": "Converge ETH positions to one explicit testnet precondition"
2042
- }
1897
+ "action": "metamask.perps.ensure_positions",
1898
+ "market": "ETH",
1899
+ "side": "long",
1900
+ "state": "open",
1901
+ "notional": "10",
1902
+ "intent": "Converge ETH positions to one explicit testnet precondition",
1903
+ "next": "done"
2043
1904
  }
2044
1905
  ],
2045
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
2046
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
2047
1906
  "execution_capabilities": [
2048
1907
  "app-mutation",
2049
1908
  "external-mutation"
2050
1909
  ]
2051
1910
  },
2052
- {
2053
- "name": "metamask.perps.ensure_orders",
2054
- "owner": "metamask",
1911
+ "metamask.perps.ensure_orders": {
2055
1912
  "description": "extension Converge selected testnet orders to open or absent, then independently assert the final state. Creating an open state uses a resting limit order.",
2056
1913
  "schema": {
2057
1914
  "type": "object",
@@ -2173,37 +2030,29 @@
2173
2030
  },
2174
2031
  "examples": [
2175
2032
  {
2176
- "description": "Ensure no open orders before proof window",
2177
- "node": {
2178
- "action": "metamask.perps.ensure_orders",
2179
- "state": "none",
2180
- "mode": "all",
2181
- "intent": "Converge Perps orders to the requested state"
2182
- }
2033
+ "action": "metamask.perps.ensure_orders",
2034
+ "state": "none",
2035
+ "mode": "all",
2036
+ "intent": "Converge Perps orders to the requested state",
2037
+ "next": "done"
2183
2038
  },
2184
2039
  {
2185
- "description": "Ensure one small resting ETH short order exists",
2186
- "node": {
2187
- "action": "metamask.perps.ensure_orders",
2188
- "market": "ETH",
2189
- "side": "short",
2190
- "state": "open",
2191
- "notional": 10,
2192
- "leverage": 2,
2193
- "intent": "Converge ETH open orders to one deterministic testnet precondition"
2194
- }
2040
+ "action": "metamask.perps.ensure_orders",
2041
+ "market": "ETH",
2042
+ "side": "short",
2043
+ "state": "open",
2044
+ "notional": 10,
2045
+ "leverage": 2,
2046
+ "intent": "Converge ETH open orders to one deterministic testnet precondition",
2047
+ "next": "done"
2195
2048
  }
2196
2049
  ],
2197
- "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
2198
- "safety_notes": "Must not inject mid-recipe UI/app state to fabricate proof.",
2199
2050
  "execution_capabilities": [
2200
2051
  "app-mutation",
2201
2052
  "external-mutation"
2202
2053
  ]
2203
2054
  },
2204
- {
2205
- "name": "metamask.perps.start_state",
2206
- "owner": "metamask",
2055
+ "metamask.perps.start_state": {
2207
2056
  "description": "extension 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.",
2208
2057
  "schema": {
2209
2058
  "type": "object",
@@ -2527,48 +2376,40 @@
2527
2376
  },
2528
2377
  "examples": [
2529
2378
  {
2530
- "description": "Clean BTC testnet market state",
2531
- "node": {
2532
- "action": "metamask.perps.start_state",
2533
- "profile": "clean_market_testnet",
2534
- "market": "BTC",
2535
- "positions": {
2536
- "state": "none"
2537
- },
2538
- "orders": {
2539
- "state": "none"
2540
- },
2541
- "intent": "Prepare the Perps start state for the proof",
2542
- "network": "testnet"
2543
- }
2379
+ "action": "metamask.perps.start_state",
2380
+ "profile": "clean_market_testnet",
2381
+ "market": "BTC",
2382
+ "positions": {
2383
+ "state": "none"
2384
+ },
2385
+ "orders": {
2386
+ "state": "none"
2387
+ },
2388
+ "intent": "Prepare the Perps start state for the proof",
2389
+ "network": "testnet",
2390
+ "next": "done"
2544
2391
  },
2545
2392
  {
2546
- "description": "Start with an open ETH long position",
2547
- "node": {
2548
- "action": "metamask.perps.start_state",
2549
- "profile": "open_position_testnet",
2550
- "market": "ETH",
2551
- "side": "long",
2552
- "positions": {
2553
- "state": "open",
2554
- "notional": "10",
2555
- "leverage": 2
2556
- },
2557
- "intent": "Prepare the Perps start state for the proof",
2558
- "network": "testnet"
2559
- }
2393
+ "action": "metamask.perps.start_state",
2394
+ "profile": "open_position_testnet",
2395
+ "market": "ETH",
2396
+ "side": "long",
2397
+ "positions": {
2398
+ "state": "open",
2399
+ "notional": "10",
2400
+ "leverage": 2
2401
+ },
2402
+ "intent": "Prepare the Perps start state for the proof",
2403
+ "network": "testnet",
2404
+ "next": "done"
2560
2405
  }
2561
2406
  ],
2562
- "proof_effect": "Runs in setup/teardown phase and must be visible in trace.json; proof videos can keep this as trace-only setup.",
2563
- "safety_notes": "Composes supported app/API paths and must not mutate React/Redux/MobX/DOM/local storage to fabricate proof.",
2564
2407
  "execution_capabilities": [
2565
2408
  "app-mutation",
2566
2409
  "external-mutation"
2567
2410
  ]
2568
2411
  },
2569
- {
2570
- "name": "metamask.perps.teardown_state",
2571
- "owner": "metamask",
2412
+ "metamask.perps.teardown_state": {
2572
2413
  "description": "extension Recommended configurable Perps teardown state that restores the selected environment after proof.",
2573
2414
  "schema": {
2574
2415
  "type": "object",
@@ -2896,181 +2737,29 @@
2896
2737
  },
2897
2738
  "examples": [
2898
2739
  {
2899
- "description": "Return BTC test account to clean state",
2900
- "node": {
2901
- "action": "metamask.perps.teardown_state",
2902
- "market": "BTC",
2903
- "positions": {
2904
- "state": "none"
2905
- },
2906
- "orders": {
2907
- "state": "none"
2908
- },
2909
- "page": "home",
2910
- "intent": "Restore Perps state after the proof"
2911
- }
2740
+ "action": "metamask.perps.teardown_state",
2741
+ "market": "BTC",
2742
+ "positions": {
2743
+ "state": "none"
2744
+ },
2745
+ "orders": {
2746
+ "state": "none"
2747
+ },
2748
+ "page": "home",
2749
+ "intent": "Restore Perps state after the proof",
2750
+ "next": "done"
2912
2751
  },
2913
2752
  {
2914
- "description": "Teardown only state created by selected market",
2915
- "node": {
2916
- "action": "metamask.perps.teardown_state",
2917
- "market": "BTC",
2918
- "intent": "Restore Perps state after the proof"
2919
- }
2753
+ "action": "metamask.perps.teardown_state",
2754
+ "market": "BTC",
2755
+ "intent": "Restore Perps state after the proof",
2756
+ "next": "done"
2920
2757
  }
2921
2758
  ],
2922
- "proof_effect": "Runs in setup/teardown phase and must be visible in trace.json; proof videos can keep this as trace-only setup.",
2923
- "safety_notes": "Composes supported app/API paths and must not mutate React/Redux/MobX/DOM/local storage to fabricate proof.",
2924
2759
  "execution_capabilities": [
2925
2760
  "app-mutation",
2926
2761
  "external-mutation"
2927
2762
  ]
2928
2763
  }
2929
- ],
2930
- "native_bindings": [
2931
- {
2932
- "action": "command",
2933
- "implementation": "@farmslot/recipe-harness/adapters/core"
2934
- },
2935
- {
2936
- "action": "wait",
2937
- "implementation": "@farmslot/recipe-harness/adapters/core"
2938
- },
2939
- {
2940
- "action": "assert_file",
2941
- "implementation": "@farmslot/recipe-harness/adapters/core"
2942
- },
2943
- {
2944
- "action": "assert_json",
2945
- "implementation": "@farmslot/recipe-harness/adapters/core"
2946
- },
2947
- {
2948
- "action": "assert_exit_code",
2949
- "implementation": "@farmslot/recipe-harness/adapters/core"
2950
- },
2951
- {
2952
- "action": "assert_output",
2953
- "implementation": "@farmslot/recipe-harness/adapters/core"
2954
- },
2955
- {
2956
- "action": "watch_logs",
2957
- "implementation": "@farmslot/recipe-harness/adapters/core"
2958
- },
2959
- {
2960
- "action": "index_artifacts",
2961
- "implementation": "@farmslot/recipe-harness/adapters/core"
2962
- },
2963
- {
2964
- "action": "end",
2965
- "implementation": "@farmslot/recipe-harness/adapters/core"
2966
- },
2967
- {
2968
- "action": "ui.navigate",
2969
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
2970
- },
2971
- {
2972
- "action": "ui.press",
2973
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
2974
- },
2975
- {
2976
- "action": "ui.key_press",
2977
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
2978
- },
2979
- {
2980
- "action": "ui.set_input",
2981
- "implementation": "@metamask/recipe-runner/extension/cdp-set-input"
2982
- },
2983
- {
2984
- "action": "ui.scroll",
2985
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
2986
- },
2987
- {
2988
- "action": "ui.wait_for",
2989
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
2990
- },
2991
- {
2992
- "action": "ui.screenshot",
2993
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
2994
- },
2995
- {
2996
- "action": "app.status",
2997
- "implementation": "@metamask/recipe-runner/platform-status"
2998
- },
2999
- {
3000
- "action": "app.hud",
3001
- "implementation": "@farmslot/recipe-harness/runtime/cdp"
3002
- },
3003
- {
3004
- "action": "cdp.target",
3005
- "implementation": "@metamask/recipe-runner/platform-cdp-target"
3006
- },
3007
- {
3008
- "action": "metamask.wallet.fixture_status",
3009
- "implementation": "@metamask/recipe-runner/extension/wallet"
3010
- },
3011
- {
3012
- "action": "metamask.wallet.setup",
3013
- "implementation": "@metamask/recipe-runner/extension/wallet"
3014
- },
3015
- {
3016
- "action": "metamask.wallet.ensure_unlocked",
3017
- "implementation": "@metamask/recipe-runner/extension/wallet"
3018
- },
3019
- {
3020
- "action": "metamask.wallet.select_account",
3021
- "implementation": "@metamask/recipe-runner/extension/wallet"
3022
- },
3023
- {
3024
- "action": "metamask.wallet.list_accounts",
3025
- "implementation": "@metamask/recipe-runner/extension/wallet"
3026
- },
3027
- {
3028
- "action": "metamask.wallet.read_state",
3029
- "implementation": "@metamask/recipe-runner/extension/wallet"
3030
- },
3031
- {
3032
- "action": "metamask.perps.read_positions",
3033
- "implementation": "@metamask/recipe-runner/extension/perps"
3034
- },
3035
- {
3036
- "action": "metamask.perps.read_orders",
3037
- "implementation": "@metamask/recipe-runner/extension/perps"
3038
- },
3039
- {
3040
- "action": "metamask.perps.close_positions",
3041
- "implementation": "@metamask/recipe-runner/extension/perps"
3042
- },
3043
- {
3044
- "action": "metamask.perps.close_orders",
3045
- "implementation": "@metamask/recipe-runner/extension/perps"
3046
- },
3047
- {
3048
- "action": "metamask.perps.place_order",
3049
- "implementation": "@metamask/recipe-runner/extension/perps"
3050
- },
3051
- {
3052
- "action": "metamask.perps.assert_positions",
3053
- "implementation": "@metamask/recipe-runner/extension/perps"
3054
- },
3055
- {
3056
- "action": "metamask.perps.assert_orders",
3057
- "implementation": "@metamask/recipe-runner/extension/perps"
3058
- },
3059
- {
3060
- "action": "metamask.perps.ensure_positions",
3061
- "implementation": "@metamask/recipe-runner/extension/perps"
3062
- },
3063
- {
3064
- "action": "metamask.perps.ensure_orders",
3065
- "implementation": "@metamask/recipe-runner/extension/perps"
3066
- },
3067
- {
3068
- "action": "metamask.perps.start_state",
3069
- "implementation": "@metamask/recipe-runner/extension/perps-domain-dispatcher"
3070
- },
3071
- {
3072
- "action": "metamask.perps.teardown_state",
3073
- "implementation": "@metamask/recipe-runner/extension/perps-domain-dispatcher"
3074
- }
3075
- ]
2764
+ }
3076
2765
  }