@deeeed/metamask-harness 0.47.4 → 0.48.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 (146) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +3 -2
  3. package/adapters/extension/lib/macos-focus.cjs +2 -2
  4. package/adapters/extension/live.sh +6 -8
  5. package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +1 -0
  6. package/adapters/shared/ensure-runner-deps.sh +6 -0
  7. package/dist/adapters/extension/runtime-decision.js +18 -1
  8. package/dist/adapters/extension/runtime.js +5 -5
  9. package/dist/adapters/extension/surface.js +1 -0
  10. package/dist/app-lifecycle.js +3 -1
  11. package/dist/command-contract.js +2 -0
  12. package/dist/commands/call.js +1 -8
  13. package/dist/commands/device-target.js +12 -3
  14. package/dist/commands/doctor.js +7 -5
  15. package/dist/commands/fixtures.js +1 -1
  16. package/dist/commands/launch/index.js +10 -0
  17. package/dist/commands/manifest.js +3 -1
  18. package/dist/commands/mobile-device-view.js +13 -3
  19. package/dist/commands/parse-args.js +2 -0
  20. package/dist/commands/run-engine.js +29 -4
  21. package/dist/commands/run.js +1 -1
  22. package/dist/commands/runtime-launch.js +10 -1
  23. package/dist/commands/status.js +8 -4
  24. package/dist/devices.js +31 -9
  25. package/dist/execution-provenance.js +8 -7
  26. package/dist/funding-execution-context.js +43 -13
  27. package/dist/heal-bounds.js +3 -3
  28. package/dist/live-adapter-contract.js +4 -0
  29. package/dist/manifest.js +2 -13
  30. package/dist/mm-harness-cli.js +2 -1
  31. package/dist/runner.js +14 -3
  32. package/docs/RECIPES.md +133 -22
  33. package/docs/RELEASE-QA-CAPABILITY-MAP.md +3 -2
  34. package/library/actions/core/perps/_controller.mjs +10 -0
  35. package/library/actions/core/perps/close_orders.mjs +13 -17
  36. package/library/actions/extension/assets/home-token-identity.mjs +30 -0
  37. package/library/actions/extension/assets/import_custom_token.mjs +61 -79
  38. package/library/actions/extension/assets/open_details.mjs +18 -7
  39. package/library/actions/extension/assets/read_details.mjs +61 -29
  40. package/library/actions/extension/assets/read_visible_state.mjs +4 -1
  41. package/library/actions/extension/assets/select_network_scope.mjs +16 -9
  42. package/library/actions/extension/assets/set_token_visibility.mjs +84 -17
  43. package/library/actions/extension/assets/verify_sorting.mjs +62 -14
  44. package/library/actions/extension/networks/add_custom.mjs +19 -17
  45. package/library/actions/extension/networks/custom_network.mjs +8 -3
  46. package/library/actions/extension/networks/read_visible_state.mjs +1 -0
  47. package/library/actions/extension/performance/_navigation-memory.mjs +35 -6
  48. package/library/actions/extension/performance/compare_idle_navigation_memory.mjs +3 -2
  49. package/library/actions/extension/performance/measure_detached_dom.mjs +3 -2
  50. package/library/actions/extension/performance/measure_navigation_memory.mjs +3 -2
  51. package/library/actions/extension/perps/assert_visible_consistency.mjs +9 -4
  52. package/library/actions/extension/perps/close_visible_position.mjs +3 -3
  53. package/library/actions/extension/perps/edit_margin.mjs +1 -1
  54. package/library/actions/extension/perps/open_balance_action.mjs +16 -7
  55. package/library/actions/extension/perps/perps.mjs +150 -45
  56. package/library/actions/extension/perps/read_funds_confirmation.mjs +8 -0
  57. package/library/actions/extension/perps/read_snapshot.mjs +2 -1
  58. package/library/actions/extension/perps/read_visible_state.mjs +10 -6
  59. package/library/actions/extension/perps/search_markets.mjs +7 -2
  60. package/library/actions/extension/perps/select_activity_filter.mjs +1 -1
  61. package/library/actions/extension/perps/select_market_filter.mjs +74 -45
  62. package/library/actions/extension/perps/set_market_favorite.mjs +6 -3
  63. package/library/actions/extension/perps/state.mjs +1 -0
  64. package/library/actions/extension/perps/update_position_tpsl.mjs +1 -1
  65. package/library/actions/extension/perps/visible-mutation-identity.mjs +4 -2
  66. package/library/actions/extension/platform/cdp.mjs +23 -142
  67. package/library/actions/extension/swap_bridge/quote-state.mjs +54 -0
  68. package/library/actions/extension/swap_bridge/read_visible_state.mjs +4 -1
  69. package/library/actions/extension/swap_bridge/select_assets.mjs +11 -1
  70. package/library/actions/extension/swap_bridge/set_amount.mjs +10 -8
  71. package/library/actions/extension/swap_bridge/set_max_amount.mjs +17 -18
  72. package/library/actions/extension/swap_bridge/set_slippage.mjs +0 -9
  73. package/library/actions/extension/ui/navigate.mjs +58 -14
  74. package/library/actions/extension/wallet/lock.mjs +2 -1
  75. package/library/actions/mobile/assets/import_custom_token.mjs +1 -0
  76. package/library/actions/mobile/assets/read_visible_state.mjs +3 -1
  77. package/library/actions/mobile/assets/set_token_visibility.mjs +13 -9
  78. package/library/actions/mobile/networks/network-management.mjs +22 -15
  79. package/library/actions/mobile/networks/remove_custom.mjs +6 -2
  80. package/library/actions/mobile/perps/perps.mjs +3 -0
  81. package/library/actions/mobile/perps/read-visible-state-loop.mjs +1 -0
  82. package/library/actions/mobile/perps/set_market_favorite.mjs +15 -19
  83. package/library/actions/mobile/platform/native-session.mjs +26 -17
  84. package/library/actions/mobile/platform/observe-ui.mjs +2 -2
  85. package/library/actions/mobile/ui/navigate.mjs +1 -1
  86. package/library/actions/shared/perps/visible-state.mjs +14 -3
  87. package/library/manifests/core.action-manifest.json +14 -2
  88. package/library/manifests/extension.action-manifest.json +49 -16
  89. package/library/manifests/mobile.action-manifest.json +8 -7
  90. package/library/recipes/core/perps/smoke.recipe.json +23 -0
  91. package/library/recipes/core/perps/snapshot.recipe.json +26 -1
  92. package/library/recipes/extension/assets/release-custom-network-token-persistence.recipe.json +25 -8
  93. package/library/recipes/extension/performance/navigation-memory-suite.recipe.json +219 -0
  94. package/library/recipes/extension/performance/navigation-memory.recipe.json +61 -156
  95. package/library/recipes/extension/wallet/smoke.recipe.json +17 -8
  96. package/library/recipes/mobile/app/lifecycle.android-smoke.recipe.json +23 -4
  97. package/library/recipes/mobile/networks/release-custom-network-persistence.recipe.json +31 -6
  98. package/library/recipes/mobile/networks/release-multichain-visibility.recipe.json +5 -4
  99. package/library/recipes/mobile/wallet/smoke.recipe.json +17 -8
  100. package/library/recipes/{assets → shared/assets}/release-token-address-import.recipe.json +7 -0
  101. package/library/recipes/{assets → shared/assets}/release-token-details.recipe.json +2 -2
  102. package/library/recipes/shared/assets/release-token-hide-readd.recipe.json +91 -0
  103. package/library/recipes/{assets → shared/assets}/release-token-persistence.recipe.json +3 -0
  104. package/library/recipes/{assets → shared/assets}/release-token-search-import.recipe.json +4 -1
  105. package/library/recipes/{assets → shared/assets}/release-token-sorting.recipe.json +13 -2
  106. package/library/recipes/{swap-bridge → shared/swap-bridge}/release-quote.recipe.json +29 -3
  107. package/package.json +3 -3
  108. package/site/assets/help-recipes.json +63 -23
  109. package/library/recipes/assets/release-token-hide-readd.recipe.json +0 -57
  110. package/library/recipes/core/perps/clean-market-testnet.recipe.json +0 -44
  111. package/library/recipes/core/perps/order-lifecycle.recipe.json +0 -82
  112. package/library/recipes/core/perps/read-markets.recipe.json +0 -36
  113. package/library/recipes/core/perps/trading-lifecycle.recipe.json +0 -80
  114. package/library/recipes/extension/perps/release-activity-filters.recipe.json +0 -51
  115. package/library/recipes/extension/perps/release-funds-flows.recipe.json +0 -76
  116. package/library/recipes/extension/perps/release-live-limit-order.recipe.json +0 -109
  117. package/library/recipes/extension/perps/release-market-filters.recipe.json +0 -97
  118. package/library/recipes/extension/perps/release-order-entry.recipe.json +0 -158
  119. package/library/recipes/extension/perps/release-order-validation.recipe.json +0 -259
  120. package/library/recipes/extension/perps/release-visible-consistency.recipe.json +0 -47
  121. package/library/recipes/extension/perps/source-dev-snapshot-consistency.recipe.json +0 -76
  122. package/library/recipes/mobile/perps/chase-assert-running.recipe.json +0 -110
  123. package/library/recipes/mobile/perps/chase-place.recipe.json +0 -145
  124. package/library/recipes/mobile/perps/chase-terminate.recipe.json +0 -98
  125. package/library/recipes/mobile/perps/performance.recipe.json +0 -722
  126. package/library/recipes/mobile/perps/pro-order-setup.recipe.json +0 -111
  127. package/library/recipes/mobile/perps/pro-order-start-state.recipe.json +0 -53
  128. package/library/recipes/mobile/perps/scale-assert-orders.recipe.json +0 -126
  129. package/library/recipes/mobile/perps/scale-place.recipe.json +0 -186
  130. package/library/recipes/mobile/perps/twap-assert-active.recipe.json +0 -97
  131. package/library/recipes/mobile/perps/twap-place.recipe.json +0 -146
  132. package/library/recipes/mobile/runner/action-validation.recipe.json +0 -336
  133. package/library/recipes/perps/clean-market-testnet.recipe.json +0 -49
  134. package/library/recipes/perps/lifecycle.recipe.json +0 -144
  135. package/library/recipes/perps/release-live-market-order.recipe.json +0 -139
  136. package/library/recipes/perps/release-watchlist.recipe.json +0 -111
  137. package/library/recipes/swap-bridge/release-max-quote.recipe.json +0 -72
  138. /package/library/recipes/{assets → shared/assets}/release-token-list.recipe.json +0 -0
  139. /package/library/recipes/{perps → shared/perps}/release-market-details.recipe.json +0 -0
  140. /package/library/recipes/{perps → shared/perps}/release-market-search.recipe.json +0 -0
  141. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-custom-slippage.recipe.json +0 -0
  142. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-max-swap.recipe.json +0 -0
  143. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-swap.recipe.json +0 -0
  144. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-surface.recipe.json +0 -0
  145. /package/library/recipes/{wallet → shared/wallet}/import.recipe.json +0 -0
  146. /package/library/recipes/{wallet → shared/wallet}/reset-import.recipe.json +0 -0
@@ -0,0 +1,219 @@
1
+ {
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
+ "title": "Extension multi-screen retained-memory suite",
4
+ "description": "Broad maintainer suite: retain all eight screen slopes, detached-DOM checks, and equal-duration idle attribution. Use performance.navigation-memory for one screen. Verify these reference screen markers against the tested build.",
5
+ "proofTargets": [
6
+ {
7
+ "id": "screen-slopes",
8
+ "claim": "Eight representative Extension screens remain within separate post-GC retained-node and listener growth bounds during navigation churn."
9
+ },
10
+ {
11
+ "id": "detached-dom",
12
+ "claim": "Detached DOM retained after forced garbage collection does not grow beyond the declared bound."
13
+ },
14
+ {
15
+ "id": "idle-control",
16
+ "claim": "Navigation-attributable listener growth remains within its declared bound after subtracting an equal-duration idle control."
17
+ }
18
+ ],
19
+ "workflow": {
20
+ "entry": "require-cdp",
21
+ "nodes": {
22
+ "require-cdp": {
23
+ "action": "cdp.target",
24
+ "required": true,
25
+ "require_reachable": true,
26
+ "intent": "Confirm the live Extension CDP target is reachable before measuring retained memory.",
27
+ "next": "ensure-unlocked"
28
+ },
29
+ "ensure-unlocked": {
30
+ "action": "metamask.wallet.ensure_unlocked",
31
+ "intent": "Ensure the representative screens are reachable from an unlocked wallet.",
32
+ "next": "market-detail"
33
+ },
34
+ "market-detail": {
35
+ "action": "call",
36
+ "ref": "performance.navigation-memory",
37
+ "params": {
38
+ "screen_hash": "#/perps/market/ETH",
39
+ "screen_test_id": "parent-selector-perps-market-detail",
40
+ "return_hash": "#/",
41
+ "cycles": 8,
42
+ "timeout_ms": 400000,
43
+ "max_nodes_per_cycle": 2,
44
+ "max_listeners_per_cycle": 4
45
+ },
46
+ "intent": "Measure the post-GC navigation slope for Perps market detail.",
47
+ "proves": [
48
+ "screen-slopes"
49
+ ],
50
+ "next": "order-entry"
51
+ },
52
+ "order-entry": {
53
+ "action": "call",
54
+ "ref": "performance.navigation-memory",
55
+ "params": {
56
+ "screen_hash": "#/perps/trade/ETH?direction=long&mode=new",
57
+ "screen_test_id": "parent-selector-perps-order-entry",
58
+ "return_hash": "#/",
59
+ "cycles": 6,
60
+ "timeout_ms": 400000,
61
+ "max_nodes_per_cycle": 2,
62
+ "max_listeners_per_cycle": 4
63
+ },
64
+ "intent": "Measure the post-GC navigation slope for Perps order entry.",
65
+ "proves": [
66
+ "screen-slopes"
67
+ ],
68
+ "next": "perps-home"
69
+ },
70
+ "perps-home": {
71
+ "action": "call",
72
+ "ref": "performance.navigation-memory",
73
+ "params": {
74
+ "screen_hash": "#/perps-home",
75
+ "screen_test_id": "perps-home-page",
76
+ "return_hash": "#/",
77
+ "cycles": 6,
78
+ "timeout_ms": 400000,
79
+ "max_nodes_per_cycle": 2,
80
+ "max_listeners_per_cycle": 4
81
+ },
82
+ "intent": "Measure the post-GC navigation slope for Perps home.",
83
+ "proves": [
84
+ "screen-slopes"
85
+ ],
86
+ "next": "market-list"
87
+ },
88
+ "market-list": {
89
+ "action": "call",
90
+ "ref": "performance.navigation-memory",
91
+ "params": {
92
+ "screen_hash": "#/perps/market-list",
93
+ "screen_test_id": "parent-selector-perps-market-list",
94
+ "return_hash": "#/",
95
+ "cycles": 6,
96
+ "timeout_ms": 400000,
97
+ "max_nodes_per_cycle": 2,
98
+ "max_listeners_per_cycle": 4
99
+ },
100
+ "intent": "Measure the post-GC navigation slope for the Perps market list.",
101
+ "proves": [
102
+ "screen-slopes"
103
+ ],
104
+ "next": "perps-activity"
105
+ },
106
+ "perps-activity": {
107
+ "action": "call",
108
+ "ref": "performance.navigation-memory",
109
+ "params": {
110
+ "screen_hash": "#/perps/activity",
111
+ "screen_test_id": "parent-selector-perps-activity",
112
+ "return_hash": "#/",
113
+ "cycles": 6,
114
+ "timeout_ms": 400000,
115
+ "max_nodes_per_cycle": 2,
116
+ "max_listeners_per_cycle": 4
117
+ },
118
+ "intent": "Measure the post-GC navigation slope for Perps activity.",
119
+ "proves": [
120
+ "screen-slopes"
121
+ ],
122
+ "next": "asset-details"
123
+ },
124
+ "asset-details": {
125
+ "action": "call",
126
+ "ref": "performance.navigation-memory",
127
+ "params": {
128
+ "screen_hash": "#/asset/0x1/",
129
+ "screen_test_id": "asset-price-chart",
130
+ "return_hash": "#/",
131
+ "cycles": 6,
132
+ "timeout_ms": 400000,
133
+ "max_nodes_per_cycle": 2,
134
+ "max_listeners_per_cycle": 4
135
+ },
136
+ "intent": "Measure the post-GC navigation slope for asset details.",
137
+ "proves": [
138
+ "screen-slopes"
139
+ ],
140
+ "next": "swaps-bridge"
141
+ },
142
+ "swaps-bridge": {
143
+ "action": "call",
144
+ "ref": "performance.navigation-memory",
145
+ "params": {
146
+ "screen_hash": "#/cross-chain/swaps/prepare-bridge-page",
147
+ "screen_test_id": "bridge-source-button",
148
+ "return_hash": "#/",
149
+ "cycles": 6,
150
+ "timeout_ms": 400000,
151
+ "max_nodes_per_cycle": 2,
152
+ "max_listeners_per_cycle": 4
153
+ },
154
+ "intent": "Measure the post-GC navigation slope for Swaps and Bridge.",
155
+ "proves": [
156
+ "screen-slopes"
157
+ ],
158
+ "next": "settings-control"
159
+ },
160
+ "settings-control": {
161
+ "action": "call",
162
+ "ref": "performance.navigation-memory",
163
+ "params": {
164
+ "screen_hash": "#/settings",
165
+ "screen_test_id": "settings-tab-bar-grouped",
166
+ "return_hash": "#/",
167
+ "cycles": 6,
168
+ "timeout_ms": 400000,
169
+ "max_nodes_per_cycle": 2,
170
+ "max_listeners_per_cycle": 4
171
+ },
172
+ "intent": "Measure a non-Perps control screen with the same retained-memory gate.",
173
+ "proves": [
174
+ "screen-slopes"
175
+ ],
176
+ "next": "detached-market-detail"
177
+ },
178
+ "detached-market-detail": {
179
+ "action": "metamask.performance.measure_detached_dom",
180
+ "screen_hash": "#/perps/market/ETH",
181
+ "screen_test_id": "parent-selector-perps-market-detail",
182
+ "return_hash": "#/",
183
+ "cycles": 5,
184
+ "timeout_ms": 400000,
185
+ "max_detached_growth": 50,
186
+ "intent": "Compare retained detached DOM before and after market-detail navigation churn.",
187
+ "proves": [
188
+ "detached-dom"
189
+ ],
190
+ "next": "idle-control-market-detail"
191
+ },
192
+ "idle-control-market-detail": {
193
+ "action": "metamask.performance.compare_idle_navigation_memory",
194
+ "screen_hash": "#/perps/market/ETH",
195
+ "screen_test_id": "parent-selector-perps-market-detail",
196
+ "return_hash": "#/",
197
+ "rounds": 8,
198
+ "round_duration_ms": 10000,
199
+ "timeout_ms": 400000,
200
+ "max_attributable_listeners_per_cycle": 2,
201
+ "intent": "Subtract equal-duration idle growth from the market-detail navigation slope.",
202
+ "proves": [
203
+ "idle-control"
204
+ ],
205
+ "next": "return-home"
206
+ },
207
+ "return-home": {
208
+ "action": "ui.navigate",
209
+ "page": "home",
210
+ "intent": "Leave the Extension on a known screen after the audit.",
211
+ "next": "done"
212
+ },
213
+ "done": {
214
+ "action": "end",
215
+ "status": "pass"
216
+ }
217
+ }
218
+ }
219
+ }
@@ -1,169 +1,74 @@
1
1
  {
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "Extension navigation retained-memory audit",
4
- "description": "Measures post-GC retained nodes and listeners across eight representative Extension screens, verifies detached DOM does not grow, and separates navigation-attributable listener growth from an equal-duration idle control.",
5
- "proofTargets": [
6
- {
7
- "id": "screen-slopes",
8
- "claim": "Eight representative Extension screens remain within separate post-GC retained-node and listener growth bounds during navigation churn."
9
- },
10
- {
11
- "id": "detached-dom",
12
- "claim": "Detached DOM retained after forced garbage collection does not grow beyond the declared bound."
13
- },
14
- {
15
- "id": "idle-control",
16
- "claim": "Navigation-attributable listener growth remains within its declared bound after subtracting an equal-duration idle control."
17
- }
18
- ],
19
- "workflow": {
20
- "entry": "require-cdp",
21
- "nodes": {
22
- "require-cdp": {
23
- "action": "cdp.target",
24
- "required": true,
25
- "require_reachable": true,
26
- "intent": "Confirm the live Extension CDP target is reachable before measuring retained memory.",
27
- "next": "ensure-unlocked"
3
+ "title": "Extension one-screen retained-memory measurement",
4
+ "description": "Measure retained DOM-node and listener growth for one screen in an already-unlocked runtime. This does not prove detached-DOM or idle attribution; use performance.navigation-memory-suite for those checks. Run with --hud hide for a consistent measurement condition.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "screen_hash",
10
+ "screen_test_id"
11
+ ],
12
+ "properties": {
13
+ "screen_hash": {
14
+ "type": "string",
15
+ "description": "Exact in-app hash route to measure."
28
16
  },
29
- "ensure-unlocked": {
30
- "action": "metamask.wallet.ensure_unlocked",
31
- "intent": "Ensure the representative screens are reachable from an unlocked wallet.",
32
- "next": "market-detail"
33
- },
34
- "market-detail": {
35
- "action": "metamask.performance.measure_navigation_memory",
36
- "screen_hash": "#/perps/market/ETH",
37
- "screen_test_id": "perps-market-detail-page",
38
- "return_hash": "#/",
39
- "cycles": 8,
40
- "timeout_ms": 400000,
41
- "max_nodes_per_cycle": 2,
42
- "max_listeners_per_cycle": 4,
43
- "intent": "Measure the post-GC navigation slope for Perps market detail.",
44
- "proves": ["screen-slopes"],
45
- "next": "order-entry"
17
+ "screen_test_id": {
18
+ "type": "string",
19
+ "description": "Current screen marker that must appear before each sample."
46
20
  },
47
- "order-entry": {
48
- "action": "metamask.performance.measure_navigation_memory",
49
- "screen_hash": "#/perps/trade/ETH?direction=long&mode=new",
50
- "screen_test_id": "perps-order-entry-page",
51
- "return_hash": "#/",
52
- "cycles": 6,
53
- "timeout_ms": 400000,
54
- "max_nodes_per_cycle": 2,
55
- "max_listeners_per_cycle": 4,
56
- "intent": "Measure the post-GC navigation slope for Perps order entry.",
57
- "proves": ["screen-slopes"],
58
- "next": "perps-home"
21
+ "return_hash": {
22
+ "type": "string",
23
+ "default": "#/",
24
+ "description": "Route to visit between measured-screen entries."
59
25
  },
60
- "perps-home": {
61
- "action": "metamask.performance.measure_navigation_memory",
62
- "screen_hash": "#/perps-home",
63
- "screen_test_id": "perps-home-page",
64
- "return_hash": "#/",
65
- "cycles": 6,
66
- "timeout_ms": 400000,
67
- "max_nodes_per_cycle": 2,
68
- "max_listeners_per_cycle": 4,
69
- "intent": "Measure the post-GC navigation slope for Perps home.",
70
- "proves": ["screen-slopes"],
71
- "next": "market-list"
26
+ "cycles": {
27
+ "type": "integer",
28
+ "minimum": 2,
29
+ "default": 8,
30
+ "description": "Post-GC samples; choose the count before measuring."
72
31
  },
73
- "market-list": {
74
- "action": "metamask.performance.measure_navigation_memory",
75
- "screen_hash": "#/perps/market-list",
76
- "screen_test_id": "market-list-view",
77
- "return_hash": "#/",
78
- "cycles": 6,
79
- "timeout_ms": 400000,
80
- "max_nodes_per_cycle": 2,
81
- "max_listeners_per_cycle": 4,
82
- "intent": "Measure the post-GC navigation slope for the Perps market list.",
83
- "proves": ["screen-slopes"],
84
- "next": "perps-activity"
32
+ "max_nodes_per_cycle": {
33
+ "type": "number",
34
+ "minimum": 0,
35
+ "default": 2,
36
+ "description": "Declared retained DOM-node growth budget per cycle."
85
37
  },
86
- "perps-activity": {
87
- "action": "metamask.performance.measure_navigation_memory",
88
- "screen_hash": "#/perps/activity",
89
- "screen_test_id": "perps-activity-page",
90
- "return_hash": "#/",
91
- "cycles": 6,
92
- "timeout_ms": 400000,
93
- "max_nodes_per_cycle": 2,
94
- "max_listeners_per_cycle": 4,
95
- "intent": "Measure the post-GC navigation slope for Perps activity.",
96
- "proves": ["screen-slopes"],
97
- "next": "asset-details"
38
+ "max_listeners_per_cycle": {
39
+ "type": "number",
40
+ "minimum": 0,
41
+ "default": 4,
42
+ "description": "Declared retained listener growth budget per cycle."
98
43
  },
99
- "asset-details": {
100
- "action": "metamask.performance.measure_navigation_memory",
101
- "screen_hash": "#/asset/0x1/",
102
- "screen_test_id": "asset-price-chart",
103
- "return_hash": "#/",
104
- "cycles": 6,
105
- "timeout_ms": 400000,
106
- "max_nodes_per_cycle": 2,
107
- "max_listeners_per_cycle": 4,
108
- "intent": "Measure the post-GC navigation slope for asset details.",
109
- "proves": ["screen-slopes"],
110
- "next": "swaps-bridge"
44
+ "screen_timeout_ms": {
45
+ "type": "integer",
46
+ "minimum": 1,
47
+ "default": 15000,
48
+ "description": "Maximum wait for each screen marker."
111
49
  },
112
- "swaps-bridge": {
113
- "action": "metamask.performance.measure_navigation_memory",
114
- "screen_hash": "#/cross-chain/swaps/prepare-bridge-page",
115
- "screen_test_id": "bridge-source-button",
116
- "return_hash": "#/",
117
- "cycles": 6,
118
- "timeout_ms": 400000,
119
- "max_nodes_per_cycle": 2,
120
- "max_listeners_per_cycle": 4,
121
- "intent": "Measure the post-GC navigation slope for Swaps and Bridge.",
122
- "proves": ["screen-slopes"],
123
- "next": "settings-control"
124
- },
125
- "settings-control": {
50
+ "timeout_ms": {
51
+ "type": "integer",
52
+ "minimum": 1,
53
+ "default": 120000,
54
+ "description": "Total bound for this one-screen measurement."
55
+ }
56
+ }
57
+ },
58
+ "workflow": {
59
+ "entry": "measure",
60
+ "nodes": {
61
+ "measure": {
126
62
  "action": "metamask.performance.measure_navigation_memory",
127
- "screen_hash": "#/settings",
128
- "screen_test_id": "settings-tab-bar-grouped",
129
- "return_hash": "#/",
130
- "cycles": 6,
131
- "timeout_ms": 400000,
132
- "max_nodes_per_cycle": 2,
133
- "max_listeners_per_cycle": 4,
134
- "intent": "Measure a non-Perps control screen with the same retained-memory gate.",
135
- "proves": ["screen-slopes"],
136
- "next": "detached-market-detail"
137
- },
138
- "detached-market-detail": {
139
- "action": "metamask.performance.measure_detached_dom",
140
- "screen_hash": "#/perps/market/ETH",
141
- "screen_test_id": "perps-market-detail-page",
142
- "return_hash": "#/",
143
- "cycles": 5,
144
- "timeout_ms": 400000,
145
- "max_detached_growth": 50,
146
- "intent": "Compare retained detached DOM before and after market-detail navigation churn.",
147
- "proves": ["detached-dom"],
148
- "next": "idle-control-market-detail"
149
- },
150
- "idle-control-market-detail": {
151
- "action": "metamask.performance.compare_idle_navigation_memory",
152
- "screen_hash": "#/perps/market/ETH",
153
- "screen_test_id": "perps-market-detail-page",
154
- "return_hash": "#/",
155
- "rounds": 8,
156
- "round_duration_ms": 10000,
157
- "timeout_ms": 400000,
158
- "max_attributable_listeners_per_cycle": 2,
159
- "intent": "Subtract equal-duration idle growth from the market-detail navigation slope.",
160
- "proves": ["idle-control"],
161
- "next": "return-home"
162
- },
163
- "return-home": {
164
- "action": "ui.navigate",
165
- "page": "home",
166
- "intent": "Leave the Extension on a known screen after the audit.",
63
+ "screen_hash": "{{params.screen_hash}}",
64
+ "screen_test_id": "{{params.screen_test_id}}",
65
+ "return_hash": "{{params.return_hash}}",
66
+ "cycles": "{{params.cycles}}",
67
+ "max_nodes_per_cycle": "{{params.max_nodes_per_cycle}}",
68
+ "max_listeners_per_cycle": "{{params.max_listeners_per_cycle}}",
69
+ "screen_timeout_ms": "{{params.screen_timeout_ms}}",
70
+ "timeout_ms": "{{params.timeout_ms}}",
71
+ "intent": "Measure post-GC retained-node and listener slopes for the requested screen",
167
72
  "next": "done"
168
73
  },
169
74
  "done": {
@@ -2,18 +2,27 @@
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask Extension wallet smoke",
4
4
  "description": "Fixture-backed proof that the Extension wallet is reachable, unlocked, readable, and visually capturable without depending on a product feature domain.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "capture_path": { "type": "string", "default": "screenshots/wallet-smoke.png" }
10
+ }
11
+ },
5
12
  "workflow": {
6
- "entry": "status",
13
+ "entry": "fixture",
7
14
  "nodes": {
8
- "status": {
9
- "action": "app.status",
10
- "next": "fixture",
11
- "intent": "Confirm the Extension runtime is reachable"
12
- },
13
15
  "fixture": {
14
16
  "action": "metamask.wallet.fixture_status",
17
+ "next": "require-fixture",
18
+ "intent": "Read the checkout's wallet fixture readiness without changing it"
19
+ },
20
+ "require-fixture": {
21
+ "action": "assert_output",
22
+ "source": "fixture",
23
+ "assert": { "path": "$.status", "operator": "eq", "value": "ready" },
15
24
  "next": "unlock",
16
- "intent": "Confirm the checkout wallet fixture is ready"
25
+ "intent": "Require a ready on-disk fixture before interacting with the wallet; this does not prove imported account identity"
17
26
  },
18
27
  "unlock": {
19
28
  "action": "metamask.wallet.ensure_unlocked",
@@ -27,7 +36,7 @@
27
36
  },
28
37
  "screenshot": {
29
38
  "action": "ui.screenshot",
30
- "path": "screenshots/wallet-smoke.png",
39
+ "path": "{{params.capture_path}}",
31
40
  "next": "done",
32
41
  "intent": "Record the visible wallet state as evidence"
33
42
  },
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask Mobile Android lifecycle smoke",
4
- "description": "Isolated on-device proof for the standard app.lifecycle action on Android. The graph cold-relaunches the installed app without rebuilding, proves the React Native bridge is reachable, backgrounds and foregrounds the app, proves bridge recovery, and captures a screenshot.",
4
+ "description": "Cold-launch the installed Android dev client, verify its bridge, unlock the fixture-backed wallet, then prove same-process background/foreground recovery and capture the final app state. Requires a source-dev runtime; does not rebuild or reset wallet data.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "runtime_ready_timeout_ms": {
10
+ "type": "integer",
11
+ "minimum": 1000,
12
+ "default": 60000,
13
+ "description": "Bound the selected bridge/route readiness check after each launch or foreground operation."
14
+ }
15
+ }
16
+ },
5
17
  "workflow": {
6
18
  "entry": "terminate-before",
7
19
  "nodes": {
@@ -10,6 +22,7 @@
10
22
  "platform": "android",
11
23
  "command": "background",
12
24
  "settle_ms": 1000,
25
+ "require_process_continuity": true,
13
26
  "intent": "Put the selected Android device on the launcher",
14
27
  "next": "foreground-app"
15
28
  },
@@ -17,8 +30,9 @@
17
30
  "action": "app.lifecycle",
18
31
  "platform": "android",
19
32
  "command": "foreground",
20
- "settle_ms": 15000,
21
- "intent": "Foreground the installed Android app through the Expo dev-client deep link",
33
+ "runtime_ready_timeout_ms": "{{params.runtime_ready_timeout_ms}}",
34
+ "require_process_continuity": true,
35
+ "intent": "Resume the installed Android app in the same process and await its selected bridge",
22
36
  "next": "bridge-after"
23
37
  },
24
38
  "bridge-after": {
@@ -46,13 +60,18 @@
46
60
  "action": "cdp.target",
47
61
  "require_reachable": true,
48
62
  "intent": "Confirm the mobile React Native debug bridge is reachable after setup relaunch",
63
+ "next": "ensure-unlocked"
64
+ },
65
+ "ensure-unlocked": {
66
+ "action": "metamask.wallet.ensure_unlocked",
67
+ "intent": "Unlock the fixture-backed wallet before the background/foreground proof and protected-screen capture boundary",
49
68
  "next": "start-state"
50
69
  },
51
70
  "launch-before": {
52
71
  "action": "app.lifecycle",
53
72
  "platform": "android",
54
73
  "command": "launch",
55
- "settle_ms": 15000,
74
+ "runtime_ready_timeout_ms": "{{params.runtime_ready_timeout_ms}}",
56
75
  "intent": "Launch the installed Android app through the Expo dev-client deep link from a cold process",
57
76
  "next": "bridge-before"
58
77
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "Mobile release custom-network persistence",
4
- "description": "Adds a custom network through native settings, proves it survives lock/unlock, and removes it.",
4
+ "description": "Adds a previously absent custom network through native settings, proves it survives lock/unlock, and removes only the network this run confirmed adding. Existing networks are preserved and refused as proof setup.",
5
5
  "paramsSchema": {
6
6
  "type": "object",
7
7
  "additionalProperties": false,
@@ -11,11 +11,14 @@
11
11
  "chain_id": { "type": "integer", "minimum": 1, "default": 369 },
12
12
  "symbol": { "type": "string", "default": "PLS" },
13
13
  "explorer_url": { "type": "string", "default": "https://scan.pulsechain.com" },
14
+ "before_capture_path": { "type": "string", "default": "screenshots/custom-network-before-lock.png" },
15
+ "after_capture_path": { "type": "string", "default": "screenshots/custom-network-after-unlock.png" },
14
16
  "timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
15
17
  }
16
18
  },
17
19
  "workflow": {
18
20
  "entry": "open-wallet",
21
+ "teardown": "require-owned-network",
19
22
  "nodes": {
20
23
  "open-wallet": {
21
24
  "action": "ui.navigate",
@@ -32,6 +35,14 @@
32
35
  "explorer_url": "{{params.explorer_url}}",
33
36
  "timeout_ms": "{{params.timeout_ms}}",
34
37
  "intent": "Add the custom network through visible settings",
38
+ "next": "require-added"
39
+ },
40
+ "require-added": {
41
+ "action": "assert_output",
42
+ "source": "add-network",
43
+ "stream": "added",
44
+ "match": "^true$",
45
+ "intent": "Refuse persistence proof when the requested network already existed",
35
46
  "next": "assert-added"
36
47
  },
37
48
  "assert-added": {
@@ -45,7 +56,7 @@
45
56
  },
46
57
  "capture-before": {
47
58
  "action": "ui.screenshot",
48
- "path": "screenshots/custom-network-before-lock.png",
59
+ "path": "{{params.before_capture_path}}",
49
60
  "label": "Custom network before lock",
50
61
  "intent": "Preserve pre-lock network evidence",
51
62
  "next": "lock-wallet"
@@ -71,9 +82,22 @@
71
82
  },
72
83
  "capture-after": {
73
84
  "action": "ui.screenshot",
74
- "path": "screenshots/custom-network-after-unlock.png",
85
+ "path": "{{params.after_capture_path}}",
75
86
  "label": "Custom network after unlock",
76
87
  "intent": "Preserve post-unlock network evidence",
88
+ "next": "done"
89
+ },
90
+ "require-owned-network": {
91
+ "action": "assert_output",
92
+ "source": "add-network",
93
+ "stream": "added",
94
+ "match": "^true$",
95
+ "intent": "Refuse deletion without completed evidence that this run added the network",
96
+ "next": "unlock-cleanup"
97
+ },
98
+ "unlock-cleanup": {
99
+ "action": "metamask.wallet.ensure_unlocked",
100
+ "intent": "Reach the task-owned network settings even if the lock-cycle proof failed",
77
101
  "next": "remove-network"
78
102
  },
79
103
  "remove-network": {
@@ -81,10 +105,11 @@
81
105
  "network": "{{params.network}}",
82
106
  "chain_id": "{{params.chain_id}}",
83
107
  "timeout_ms": "{{params.timeout_ms}}",
84
- "intent": "Remove the custom network and prove it is absent",
85
- "next": "done"
108
+ "intent": "Remove only the custom network this run confirmed adding and prove it is absent",
109
+ "next": "cleanup-done"
86
110
  },
87
- "done": { "action": "end", "status": "pass" }
111
+ "done": { "action": "end", "status": "pass" },
112
+ "cleanup-done": { "action": "end", "status": "pass" }
88
113
  }
89
114
  }
90
115
  }