@deeeed/metamask-harness 0.47.4 → 0.49.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 (261) hide show
  1. package/CHANGELOG.md +12 -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/help.js +17 -5
  17. package/dist/commands/launch/index.js +10 -0
  18. package/dist/commands/manifest.js +3 -1
  19. package/dist/commands/mobile-device-view.js +13 -3
  20. package/dist/commands/parse-args.js +2 -0
  21. package/dist/commands/run-engine.js +29 -4
  22. package/dist/commands/run.js +1 -1
  23. package/dist/commands/runtime-launch.js +10 -1
  24. package/dist/commands/status.js +8 -4
  25. package/dist/devices.js +31 -9
  26. package/dist/execution-provenance.js +8 -7
  27. package/dist/funding-execution-context.js +62 -17
  28. package/dist/heal-bounds.js +3 -3
  29. package/dist/live-adapter-contract.js +4 -0
  30. package/dist/manifest.js +2 -13
  31. package/dist/metamask-action-validation.js +3 -2
  32. package/dist/mm-harness-cli.js +4 -2
  33. package/dist/runner.js +14 -3
  34. package/docs/RECIPES.md +135 -24
  35. package/docs/RELEASE-QA-CAPABILITY-MAP.md +3 -2
  36. package/library/actions/core/perps/_controller.mjs +24 -24
  37. package/library/actions/core/perps/assert_orders.mjs +3 -5
  38. package/library/actions/core/perps/assert_positions.mjs +3 -5
  39. package/library/actions/core/perps/close_orders.mjs +39 -19
  40. package/library/actions/core/perps/close_positions.mjs +53 -12
  41. package/library/actions/core/perps/edit_order.mjs +2 -0
  42. package/library/actions/core/perps/ensure_orders.mjs +3 -4
  43. package/library/actions/core/perps/ensure_positions.mjs +4 -5
  44. package/library/actions/core/perps/place_order.mjs +7 -14
  45. package/library/actions/core/perps/read_account.mjs +2 -0
  46. package/library/actions/core/perps/read_orders.mjs +2 -0
  47. package/library/actions/core/perps/read_positions.mjs +3 -1
  48. package/library/actions/core/perps/read_snapshot.mjs +3 -0
  49. package/library/actions/core/perps/start_state.mjs +3 -14
  50. package/library/actions/core/perps/teardown_state.mjs +3 -14
  51. package/library/actions/core/perps/update_position_tpsl.mjs +13 -19
  52. package/library/actions/core/wallet/list_accounts.mjs +3 -0
  53. package/library/actions/extension/analytics/consent.mjs +2 -0
  54. package/library/actions/extension/analytics/set_consent.mjs +2 -0
  55. package/library/actions/extension/assets/home-token-identity.mjs +31 -0
  56. package/library/actions/extension/assets/import_custom_token.mjs +63 -79
  57. package/library/actions/extension/assets/open_details.mjs +19 -7
  58. package/library/actions/extension/assets/prepare_send.mjs +1 -0
  59. package/library/actions/extension/assets/read_details.mjs +62 -29
  60. package/library/actions/extension/assets/read_visible_state.mjs +5 -1
  61. package/library/actions/extension/assets/review_send.mjs +1 -0
  62. package/library/actions/extension/assets/select_network_scope.mjs +17 -9
  63. package/library/actions/extension/assets/send.mjs +2 -0
  64. package/library/actions/extension/assets/set_custom_gas.mjs +1 -0
  65. package/library/actions/extension/assets/set_token_visibility.mjs +86 -17
  66. package/library/actions/extension/assets/verify_sorting.mjs +63 -14
  67. package/library/actions/extension/deeplink/open.mjs +1 -0
  68. package/library/actions/extension/networks/add_chainlist.mjs +2 -0
  69. package/library/actions/extension/networks/add_custom.mjs +21 -17
  70. package/library/actions/extension/networks/custom_network.mjs +10 -3
  71. package/library/actions/extension/networks/read_visible_state.mjs +2 -0
  72. package/library/actions/extension/networks/remove_custom.mjs +1 -0
  73. package/library/actions/extension/performance/_navigation-memory.mjs +37 -6
  74. package/library/actions/extension/performance/compare_idle_navigation_memory.mjs +5 -2
  75. package/library/actions/extension/performance/measure_detached_dom.mjs +5 -2
  76. package/library/actions/extension/performance/measure_navigation_memory.mjs +5 -2
  77. package/library/actions/extension/perps/assert_orders.mjs +1 -0
  78. package/library/actions/extension/perps/assert_positions.mjs +1 -0
  79. package/library/actions/extension/perps/assert_visible_consistency.mjs +11 -4
  80. package/library/actions/extension/perps/close_orders.mjs +4 -1
  81. package/library/actions/extension/perps/close_positions.mjs +1 -0
  82. package/library/actions/extension/perps/close_visible_position.mjs +160 -11
  83. package/library/actions/extension/perps/compare_provider_market.mjs +2 -0
  84. package/library/actions/extension/perps/edit_margin.mjs +3 -1
  85. package/library/actions/extension/perps/ensure_orders.mjs +1 -0
  86. package/library/actions/extension/perps/ensure_positions.mjs +1 -0
  87. package/library/actions/extension/perps/mutation-receipt.mjs +54 -3
  88. package/library/actions/extension/perps/open_balance_action.mjs +17 -7
  89. package/library/actions/extension/perps/open_position_action.mjs +1 -0
  90. package/library/actions/extension/perps/perps.mjs +550 -69
  91. package/library/actions/extension/perps/place_order.mjs +1 -0
  92. package/library/actions/extension/perps/read_eligibility.mjs +1 -0
  93. package/library/actions/extension/perps/read_funds_confirmation.mjs +10 -0
  94. package/library/actions/extension/perps/read_orders.mjs +1 -0
  95. package/library/actions/extension/perps/read_positions.mjs +1 -0
  96. package/library/actions/extension/perps/read_snapshot.mjs +4 -1
  97. package/library/actions/extension/perps/read_visible_state.mjs +12 -6
  98. package/library/actions/extension/perps/search_markets.mjs +8 -2
  99. package/library/actions/extension/perps/select_activity_filter.mjs +2 -1
  100. package/library/actions/extension/perps/select_market_filter.mjs +75 -45
  101. package/library/actions/extension/perps/set_market_favorite.mjs +7 -3
  102. package/library/actions/extension/perps/state.mjs +2 -0
  103. package/library/actions/extension/perps/update_position_tpsl.mjs +3 -1
  104. package/library/actions/extension/perps/visible-mutation-identity.mjs +6 -2
  105. package/library/actions/extension/platform/cdp.mjs +50 -142
  106. package/library/actions/extension/settings/set_basic_functionality.mjs +1 -0
  107. package/library/actions/extension/swap_bridge/quote-state.mjs +56 -0
  108. package/library/actions/extension/swap_bridge/read_visible_state.mjs +5 -1
  109. package/library/actions/extension/swap_bridge/select_assets.mjs +12 -1
  110. package/library/actions/extension/swap_bridge/set_amount.mjs +11 -8
  111. package/library/actions/extension/swap_bridge/set_max_amount.mjs +18 -18
  112. package/library/actions/extension/swap_bridge/set_slippage.mjs +1 -9
  113. package/library/actions/extension/ui/locators.mjs +1 -0
  114. package/library/actions/extension/ui/navigate.mjs +60 -14
  115. package/library/actions/extension/wallet/ensure_unlocked.mjs +2 -0
  116. package/library/actions/extension/wallet/import.mjs +2 -0
  117. package/library/actions/extension/wallet/list_accounts.mjs +1 -0
  118. package/library/actions/extension/wallet/lock.mjs +4 -1
  119. package/library/actions/extension/wallet/read_state.mjs +1 -0
  120. package/library/actions/extension/wallet/reset.mjs +2 -0
  121. package/library/actions/extension/wallet/secret-input.mjs +2 -0
  122. package/library/actions/extension/wallet/select_account.mjs +2 -0
  123. package/library/actions/extension/wallet/setup.mjs +1 -0
  124. package/library/actions/extension/wallet/state.mjs +2 -0
  125. package/library/actions/extension/wallet/visible-session.mjs +2 -0
  126. package/library/actions/mobile/analytics/consent-settings.mjs +1 -0
  127. package/library/actions/mobile/analytics/set_consent.mjs +1 -0
  128. package/library/actions/mobile/app/network-control.mjs +2 -0
  129. package/library/actions/mobile/app/network.mjs +1 -0
  130. package/library/actions/mobile/app/network_assert.mjs +1 -0
  131. package/library/actions/mobile/app/network_capture.mjs +1 -0
  132. package/library/actions/mobile/assets/import_custom_token.mjs +3 -0
  133. package/library/actions/mobile/assets/open_details.mjs +1 -0
  134. package/library/actions/mobile/assets/read_details.mjs +1 -0
  135. package/library/actions/mobile/assets/read_visible_state.mjs +4 -1
  136. package/library/actions/mobile/assets/set_token_visibility.mjs +15 -9
  137. package/library/actions/mobile/assets/verify_sorting.mjs +90 -7
  138. package/library/actions/mobile/deeplink/open.mjs +1 -0
  139. package/library/actions/mobile/networks/add_custom.mjs +1 -0
  140. package/library/actions/mobile/networks/network-management.mjs +23 -15
  141. package/library/actions/mobile/networks/read_visible_state.mjs +1 -0
  142. package/library/actions/mobile/networks/remove_custom.mjs +7 -2
  143. package/library/actions/mobile/perps/assert_orders.mjs +1 -0
  144. package/library/actions/mobile/perps/assert_positions.mjs +1 -0
  145. package/library/actions/mobile/perps/capture_performance.mjs +1 -0
  146. package/library/actions/mobile/perps/close_orders.mjs +1 -0
  147. package/library/actions/mobile/perps/close_positions.mjs +1 -0
  148. package/library/actions/mobile/perps/ensure_orders.mjs +1 -0
  149. package/library/actions/mobile/perps/ensure_positions.mjs +1 -0
  150. package/library/actions/mobile/perps/measure_homepage_visible.mjs +1 -0
  151. package/library/actions/mobile/perps/performance-capture.mjs +2 -0
  152. package/library/actions/mobile/perps/perps.mjs +8 -1
  153. package/library/actions/mobile/perps/place_order.mjs +1 -0
  154. package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +2 -0
  155. package/library/actions/mobile/perps/read-visible-state-loop.mjs +3 -0
  156. package/library/actions/mobile/perps/read_orders.mjs +1 -0
  157. package/library/actions/mobile/perps/read_positions.mjs +1 -0
  158. package/library/actions/mobile/perps/read_visible_state.mjs +1 -0
  159. package/library/actions/mobile/perps/search_markets.mjs +1 -0
  160. package/library/actions/mobile/perps/set_market_favorite.mjs +17 -19
  161. package/library/actions/mobile/platform/bridge.mjs +16 -4
  162. package/library/actions/mobile/platform/native-session-name.mjs +1 -0
  163. package/library/actions/mobile/platform/native-session.mjs +28 -17
  164. package/library/actions/mobile/platform/observe-ui.mjs +4 -2
  165. package/library/actions/mobile/platform/tool-paths.mjs +1 -0
  166. package/library/actions/mobile/swap_bridge/native-session.mjs +1 -0
  167. package/library/actions/mobile/swap_bridge/read_visible_state.mjs +1 -0
  168. package/library/actions/mobile/swap_bridge/select_assets.mjs +2 -0
  169. package/library/actions/mobile/swap_bridge/set_amount.mjs +1 -0
  170. package/library/actions/mobile/swap_bridge/set_max_amount.mjs +1 -0
  171. package/library/actions/mobile/swap_bridge/set_slippage.mjs +1 -0
  172. package/library/actions/mobile/swap_bridge/submit_transaction.mjs +2 -0
  173. package/library/actions/mobile/ui/locators.mjs +1 -0
  174. package/library/actions/mobile/ui/native-navigation.mjs +2 -0
  175. package/library/actions/mobile/ui/navigate.mjs +3 -1
  176. package/library/actions/mobile/wallet/ensure_unlocked.mjs +2 -0
  177. package/library/actions/mobile/wallet/home.mjs +1 -0
  178. package/library/actions/mobile/wallet/import.mjs +2 -0
  179. package/library/actions/mobile/wallet/list_accounts.mjs +1 -0
  180. package/library/actions/mobile/wallet/lock.mjs +1 -0
  181. package/library/actions/mobile/wallet/native-ui.mjs +2 -0
  182. package/library/actions/mobile/wallet/read_state.mjs +2 -0
  183. package/library/actions/mobile/wallet/reset-helper.mjs +1 -0
  184. package/library/actions/mobile/wallet/reset.mjs +1 -0
  185. package/library/actions/mobile/wallet/select_account.mjs +2 -0
  186. package/library/actions/mobile/wallet/setup.mjs +2 -0
  187. package/library/actions/shared/analytics/assert_events.mjs +3 -0
  188. package/library/actions/shared/analytics/consent.mjs +3 -0
  189. package/library/actions/shared/analytics/read_events.mjs +2 -0
  190. package/library/actions/shared/analytics/start_capture.mjs +3 -0
  191. package/library/actions/shared/app/network-artifact.mjs +2 -0
  192. package/library/actions/shared/app/network-assert.mjs +2 -0
  193. package/library/actions/shared/assets/visible-state.mjs +2 -0
  194. package/library/actions/shared/deeplink/url.mjs +3 -0
  195. package/library/actions/shared/networks/visible-state.mjs +2 -0
  196. package/library/actions/shared/perps/visible-state.mjs +16 -3
  197. package/library/actions/shared/swap-bridge/transaction.mjs +3 -0
  198. package/library/actions/shared/swap-bridge/visible-state.mjs +2 -0
  199. package/library/actions/shared/ui/locators.mjs +2 -0
  200. package/library/actions/shared/wallet/import-source.mjs +3 -0
  201. package/library/manifests/core.action-manifest.json +34 -2
  202. package/library/manifests/extension.action-manifest.json +50 -17
  203. package/library/manifests/mobile.action-manifest.json +11 -10
  204. package/library/recipes/core/perps/smoke.recipe.json +23 -0
  205. package/library/recipes/core/perps/snapshot.recipe.json +26 -1
  206. package/library/recipes/extension/assets/release-custom-network-token-persistence.recipe.json +25 -8
  207. package/library/recipes/extension/performance/navigation-memory-suite.recipe.json +219 -0
  208. package/library/recipes/extension/performance/navigation-memory.recipe.json +61 -156
  209. package/library/recipes/extension/wallet/smoke.recipe.json +17 -8
  210. package/library/recipes/mobile/app/lifecycle-smoke.recipe.json +89 -0
  211. package/library/recipes/mobile/networks/release-custom-network-persistence.recipe.json +31 -6
  212. package/library/recipes/mobile/networks/release-multichain-visibility.recipe.json +5 -4
  213. package/library/recipes/mobile/wallet/smoke.recipe.json +17 -8
  214. package/library/recipes/{assets → shared/assets}/release-token-address-import.recipe.json +7 -0
  215. package/library/recipes/{assets → shared/assets}/release-token-details.recipe.json +2 -2
  216. package/library/recipes/shared/assets/release-token-hide-readd.recipe.json +91 -0
  217. package/library/recipes/{assets → shared/assets}/release-token-persistence.recipe.json +3 -0
  218. package/library/recipes/{assets → shared/assets}/release-token-search-import.recipe.json +4 -1
  219. package/library/recipes/{assets → shared/assets}/release-token-sorting.recipe.json +13 -2
  220. package/library/recipes/{swap-bridge → shared/swap-bridge}/release-quote.recipe.json +29 -3
  221. package/package.json +3 -3
  222. package/site/assets/help-recipes.json +220 -27
  223. package/library/recipes/assets/release-token-hide-readd.recipe.json +0 -57
  224. package/library/recipes/core/perps/clean-market-testnet.recipe.json +0 -44
  225. package/library/recipes/core/perps/order-lifecycle.recipe.json +0 -82
  226. package/library/recipes/core/perps/read-markets.recipe.json +0 -36
  227. package/library/recipes/core/perps/trading-lifecycle.recipe.json +0 -80
  228. package/library/recipes/extension/perps/release-activity-filters.recipe.json +0 -51
  229. package/library/recipes/extension/perps/release-funds-flows.recipe.json +0 -76
  230. package/library/recipes/extension/perps/release-live-limit-order.recipe.json +0 -109
  231. package/library/recipes/extension/perps/release-market-filters.recipe.json +0 -97
  232. package/library/recipes/extension/perps/release-order-entry.recipe.json +0 -158
  233. package/library/recipes/extension/perps/release-order-validation.recipe.json +0 -259
  234. package/library/recipes/extension/perps/release-visible-consistency.recipe.json +0 -47
  235. package/library/recipes/extension/perps/source-dev-snapshot-consistency.recipe.json +0 -76
  236. package/library/recipes/mobile/app/lifecycle.android-smoke.recipe.json +0 -69
  237. package/library/recipes/mobile/perps/chase-assert-running.recipe.json +0 -110
  238. package/library/recipes/mobile/perps/chase-place.recipe.json +0 -145
  239. package/library/recipes/mobile/perps/chase-terminate.recipe.json +0 -98
  240. package/library/recipes/mobile/perps/performance.recipe.json +0 -722
  241. package/library/recipes/mobile/perps/pro-order-setup.recipe.json +0 -111
  242. package/library/recipes/mobile/perps/pro-order-start-state.recipe.json +0 -53
  243. package/library/recipes/mobile/perps/scale-assert-orders.recipe.json +0 -126
  244. package/library/recipes/mobile/perps/scale-place.recipe.json +0 -186
  245. package/library/recipes/mobile/perps/twap-assert-active.recipe.json +0 -97
  246. package/library/recipes/mobile/perps/twap-place.recipe.json +0 -146
  247. package/library/recipes/mobile/runner/action-validation.recipe.json +0 -336
  248. package/library/recipes/perps/clean-market-testnet.recipe.json +0 -49
  249. package/library/recipes/perps/lifecycle.recipe.json +0 -144
  250. package/library/recipes/perps/release-live-market-order.recipe.json +0 -139
  251. package/library/recipes/perps/release-watchlist.recipe.json +0 -111
  252. package/library/recipes/swap-bridge/release-max-quote.recipe.json +0 -72
  253. /package/library/recipes/{assets → shared/assets}/release-token-list.recipe.json +0 -0
  254. /package/library/recipes/{perps → shared/perps}/release-market-details.recipe.json +0 -0
  255. /package/library/recipes/{perps → shared/perps}/release-market-search.recipe.json +0 -0
  256. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-custom-slippage.recipe.json +0 -0
  257. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-max-swap.recipe.json +0 -0
  258. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-swap.recipe.json +0 -0
  259. /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-surface.recipe.json +0 -0
  260. /package/library/recipes/{wallet → shared/wallet}/import.recipe.json +0 -0
  261. /package/library/recipes/{wallet → shared/wallet}/reset-import.recipe.json +0 -0
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "topic": "recipes",
4
4
  "title": "Recipe-backed work",
5
- "summary": "Build an executable proof from the closest installed recipe, adapt it to the exact product version, and leave evidence another agent can replay.",
5
+ "summary": "The harness exposes tools to inspect, interact with, and measure MetaMask. Recipes combine them with starting conditions, branching, and assertions to produce repeatable evidence. Skills organize the task around that proof.",
6
6
  "capabilities": "Recipe uses: functional QA, visual checks, analytics and log assertions, and performance measurements during development, PR review, or release testing.",
7
7
  "scopeNotice": "Current coverage: mm-harness is heavily optimized for Perps. Other teams can use it by adding composable recipes for their key journeys; contact Arthur for help.",
8
8
  "recipeProtocolVersion": "1",
@@ -12,8 +12,21 @@
12
12
  "title": "Freeze the proof target",
13
13
  "instruction": "Work inside one isolated MetaMask checkout. Name the exact product version and acceptance criteria, repair harness-owned state, then verify or launch that checkout.",
14
14
  "details": [
15
- "The tested build and current criteria are authoritative. A prior recipe pass is not current proof.",
16
- "Choose state, visual, log, or mixed evidence for each criterion before authoring the graph."
15
+ "The tested build and current criteria are authoritative. A prior recipe pass is not current proof. Freeze source and installed dependencies during execution. Parallel workers need private dependency trees with matching manifests and lockfiles; installing through a shared node_modules symlink can change another run.",
16
+ "A session helper proves only its declared postcondition, not the selected account, provider, network, or funding; verify those separately before trading. Use account-aware balances: Hyperliquid unified accounts can use spot collateral even when clearinghouseState reports zero margin.",
17
+ "Choose state, visual, log, or performance evidence for each criterion before authoring the graph. A tool returning successfully proves only its own operation, not the task's claim.",
18
+ {
19
+ "text": "Mobile catalog compatibility does not establish both iOS and Android runtime support; validate the selected transport.",
20
+ "adapters": [
21
+ "mobile"
22
+ ]
23
+ },
24
+ {
25
+ "text": "Launching Extension preserves its wallet profile. Applying a fixture or resetting that profile is a separate explicit action.",
26
+ "adapters": [
27
+ "extension"
28
+ ]
29
+ }
17
30
  ],
18
31
  "commands": [
19
32
  "mm-harness doctor --fix",
@@ -25,13 +38,28 @@
25
38
  "title": "Discover the strongest starting point",
26
39
  "instruction": "Search the installed recipe and action catalogs, inspect exact schemas, and select the closest recipe before writing anything new.",
27
40
  "details": [
28
- "A bundled recipe, including a Core recipe, is strong composable vocabulary, not authority for every future product version.",
29
- "Prefer an existing recipe, then existing actions, then read-only CDP or controller inspection. Add shared vocabulary only after repeated need is proven.",
30
- "Before declaring a capability unsupported, inspect both catalogs and the closest recipe's composition. A missing dedicated action may already be composed from UI actions. Read the returned schema before filtering fields; do not treat guessed field names as empty capabilities."
41
+ "A bundled recipe is strong composable vocabulary, not authority for every future product version.",
42
+ "Prefer an existing recipe, then existing actions, then read-only inspection. Add shared vocabulary only after repeated need is proven.",
43
+ "Before declaring a capability unsupported, inspect both catalogs and the closest recipe's composition. A missing dedicated action may already be composed from UI actions. Read the returned schema, examples, and result_cases before authoring; do not treat guessed field names as empty capabilities.",
44
+ "Register a team library with --library team=/path/to/library-root, the directory containing recipes/. Use discovered recipe names in call.ref; the library alias names its source, not a recipe-name prefix. Confirm --describe reports the intended source and platform variant, then plan the complete composition. Discovery alone does not prove that child actions or parameter contracts work on this adapter.",
45
+ {
46
+ "text": "Core actions use isolated controllers: pass account/network into each action instead of adding a no-op initialization node.",
47
+ "adapters": [
48
+ "core"
49
+ ]
50
+ }
31
51
  ],
32
52
  "commands": [
33
53
  "mm-harness actions --json",
34
54
  "mm-harness actions --action app.status --json",
55
+ {
56
+ "text": "mm-harness actions --action ui.screenshot --json",
57
+ "adapters": [
58
+ "mobile",
59
+ "extension"
60
+ ]
61
+ },
62
+ "mm-harness actions performance --json",
35
63
  "mm-harness run --list --json",
36
64
  "mm-harness run runner.smoke --describe --json"
37
65
  ]
@@ -42,29 +70,78 @@
42
70
  "instruction": "Declare genuine caller choices once in paramsSchema and keep invariants required by the postcondition inside the recipe.",
43
71
  "details": [
44
72
  "Parameterize reusable differences such as market, account, provider, network, amount, side, or lifecycle mode.",
45
- "Do not parameterize away safety, assertions, cleanup, or the meaning of success. Never depend on hidden wallet, account, provider, network, page, port, or device state."
73
+ "Use {{params.name}} for declared inputs and {{outputs.nodeId.path}} for a preceding result. Whole-value templates preserve types; embedded templates become strings. Inspect the action's actual output before selecting a field.",
74
+ "CLI values are parsed as JSON when possible. For a numeric-looking string parameter, preserve JSON quotes, for example 'amount=\"15\"'; shell quoting 15 alone still produces a number.",
75
+ "Do not parameterize away safety, assertions, cleanup, or the meaning of success. Never depend on hidden wallet, account, provider, network, page, port, or device state.",
76
+ "A clean-market postcondition must check both sides. Keep side-specific open-state proof separate, and inspect the actual cancellation payload: filtering by side before canceling by symbol does not protect opposite-side orders. Map client receipt IDs to exchange IDs when they differ, checking account and market. Never infer ownership from any new order or widen cleanup to fix a failed assertion.",
77
+ {
78
+ "text": "Asset symbols and test IDs may repeat across networks. Require an unambiguous observed row, or use a contract that accepts network/token identity; never infer chain, funding or ownership from a symbol alone.",
79
+ "adapters": [
80
+ "mobile",
81
+ "extension"
82
+ ]
83
+ },
84
+ "For catalog changes, verify membership and lifecycle flags as well as counts. A smaller list can hide valid delisted entries still needed by callers; distinguish unavailable trading metadata from missing historical identity.",
85
+ "Defaults must agree across callers and children. Keep consent and environment-specific values required when no safe default exists; a missing required input is not recipe drift. The current runtime resolves referenced inputs before branching, so an unselected branch does not hide an undefined parameter. Venue-key registration needs explicit account/key-slot ownership too."
46
86
  ],
47
- "commands": []
87
+ "commands": [
88
+ "mm-harness run ./proof.recipe.json market=ETH --plan --json"
89
+ ]
48
90
  },
49
91
  {
50
92
  "id": "compose",
51
93
  "title": "Compose a readable graph",
52
- "instruction": "Use static call references for unchanged sub-journeys. Keep preparation, action, assertion, evidence, and guaranteed teardown visible as separate nodes with human-facing intent.",
94
+ "instruction": "Use static call references for unchanged sub-journeys. Separate preparation, action, assertions, and evidence; add workflow.teardown when cleanup must run after success or failure.",
53
95
  "details": [
54
- "Use idempotent ensure actions for required start state and independently assert their postconditions.",
96
+ "Starting conditions are ordinary nodes at the beginning of workflow, not a preconditions field. Use idempotent ensure actions and independently assert their postconditions.",
55
97
  "Inspect existing state before creating or cleaning fixtures. Establish only prerequisites required by the claim; a history or display check may already have usable records and need no trade or cleanup. Record the selected records and verify they still satisfy the proof boundary.",
56
- "Actions translate stable UI, CDP, or controller operations. Recipes compose them. Product code owns business rules."
98
+ "Match history-query ranges to the dates of existing visible records before declaring fixtures missing. Sample only sections needed for change detection; fetch one-time corroborating history once, and count background calls as well as graph nodes.",
99
+ "Actions translate UI, CDP, or controller operations. Recipes compose them. Product code owns business rules. Teams own specialized journeys in their libraries; the harness retains shared capabilities and a small set of composable examples.",
100
+ "Put identical cross-adapter graphs in recipes/shared/<domain>/ and platform variants in recipes/<adapter>/<domain>/. Both keep the same domain.recipe name; an adapter variant takes precedence. Keep platform differences in actions when the journey is identical. Verify discovery, execution, and callers before removing duplicates.",
101
+ {
102
+ "text": "Keep lifecycle transitions explicit. Check whether an observation tool activates or foregrounds the app; that behavior can invalidate a lifecycle claim even when the captured screen looks correct.",
103
+ "adapters": [
104
+ "mobile",
105
+ "extension"
106
+ ]
107
+ },
108
+ {
109
+ "text": "On source-dev Mobile, app.lifecycle launch, foreground, and restart already wait for the selected bridge and route. Use runtime_ready_timeout_ms to bound readiness and require_process_continuity for warm-resume claims. settle_ms is an explicit dwell period, not readiness proof. Unlock before a visual proof if the app protects locked-screen capture; never bypass that protection.",
110
+ "adapters": [
111
+ "mobile"
112
+ ]
113
+ },
114
+ "Measure executed nodes and elapsed time across nested calls, including setup and teardown. Include action-internal repetitions such as navigation cycles. Splitting a long graph into child files does not reduce work. Reuse a verified prerequisite within its valid scope, branch around already-satisfied setup, and keep broad coverage suites separate from the small journey a task needs.",
115
+ "Inspect scripts and controller methods before running them. A read, get or stream label does not rule out signing, order placement or collateral settlement. Apply the normal approvals to those effects. Count actual operations and verify assertions; callback counts do not establish transport identity. Use a distinct output path for repeated invocations so one phase cannot overwrite another's evidence.",
116
+ "Merge branch endings when their resolved action inputs and assertions are identical. Preserve the scenario identity in parameters; keep distinct endings when required evidence differs. Compare the selected operation sequences before claiming fewer checks or faster execution.",
117
+ "Use summary.total for executed node count and summary.durationMs for engine duration. Measure CLI wall time separately when assessing speed; preparation and closeout can dominate a short recipe. The trace includes child nodes and their enclosing call; summing both durations double-counts the child work.",
118
+ "Keep repository builds, unit suites, and release bookkeeping outside reusable runtime journeys. Run them separately when required and report both results; a runtime pass does not imply package acceptance.",
119
+ "Main and teardown graphs are disjoint. A cleanup node reached only through next may be skipped on failure. Capture the baseline before mutation, guard restoration on that output, and restore only task-owned state. A missing or ambiguous baseline is unknown, not false. An interaction can complete after timeout or navigation away; check task-owned pending requests during cleanup. Teardown cannot guarantee provider acceptance or survive a killed process.",
120
+ {
121
+ "text": "Reopening a route may preserve filters or search state; establish the required view explicitly before sampling, and validate composition after a different journey changes it.",
122
+ "adapters": [
123
+ "mobile",
124
+ "extension"
125
+ ]
126
+ }
57
127
  ],
58
128
  "commands": []
59
129
  },
60
130
  {
61
131
  "id": "author",
62
132
  "title": "Build and prove one node at a time",
63
- "instruction": "Probe each unfamiliar action with call or a tiny action-to-end recipe. Use read-only CDP inspection only when declared actions cannot reveal the needed authoring detail, then consolidate the final proof from manifest-declared actions.",
133
+ "instruction": "Probe each unfamiliar action with call or a tiny action-to-end recipe. Use read-only inspection only when declared actions cannot reveal the needed authoring detail, then consolidate the final proof from manifest-declared actions.",
64
134
  "details": [
65
135
  "Plan after every structural change and preserve the first failing trace.",
66
136
  "A plan validates structure only. Probe a reused setup boundary against the current build with a short explicit timeout before a full journey; a bundled journey timeout is not a discovery budget.",
67
- "A CDP observation can help find the current route or selector; it is not final evidence unless the recipe records an allowed action and assertion for that signal."
137
+ "A later update cannot repair a failed initial-seed assertion. Preserve the initial sample and stop that wait instead of spending the remaining budget on a proof that cannot pass.",
138
+ {
139
+ "text": "A CDP observation can help find the current route or selector; it is not final evidence unless the recipe records an allowed action and assertion for that signal.",
140
+ "adapters": [
141
+ "mobile",
142
+ "extension"
143
+ ]
144
+ }
68
145
  ],
69
146
  "commands": [
70
147
  "mm-harness call app.status --json",
@@ -74,12 +151,15 @@
74
151
  {
75
152
  "id": "branch",
76
153
  "title": "Branch without hiding decisions",
77
- "instruction": "Use switch for declared parameter choices. For runtime conditions, call an action that returns a finite declared case, then route every case to explicit assertions and a terminal result.",
154
+ "instruction": "Branch on a declared input or a preceding observation. switch compares resolved strings with value and equals: cases.match handles equality and default handles the other path.",
78
155
  "details": [
79
- "Never template a call ref. Pass only declared child parameters and keep child output scoped to the call node.",
80
- "Every success path must prove its postcondition. workflow.teardown must remain reachable after main success or failure."
156
+ "For a runtime decision, value can use {{outputs.inspect.state}} when the preceding inspect node actually returns that string. Actions with result_cases can route directly through cases and default; the recipe supplies destinations, not the action.",
157
+ "Use either next or cases with default. call always uses next and a static ref; only call.params passes child inputs, and child output stays scoped under the call node.",
158
+ "Graphs are acyclic. Put bounded polling inside actions, not backward edges. Each success path must prove its promised outcome. end.status supports pass, fail, or unknown; an unknown result is not proof of success."
81
159
  ],
82
- "commands": []
160
+ "commands": [
161
+ "mm-harness actions --action switch --json"
162
+ ]
83
163
  },
84
164
  {
85
165
  "id": "quality",
@@ -87,11 +167,44 @@
87
167
  "instruction": "Run the complete graph once into an explicit artifact directory, then apply the built-in quality bar before assigning coverage or a verdict.",
88
168
  "details": [
89
169
  "Coverage: every criterion needs an executable path and assertion; manual, untestable, and environment-dependent gaps stay explicit.",
170
+ "Optional proofTargets names claims with id and claim; nodes link evidence with proves: [id]. Coverage labels do not replace assertions.",
90
171
  "A blocked required runtime claim is incomplete proof. Passing static checks or closing a checklist cannot make that claim validated or fixed.",
91
172
  "Graph: no unconditional pass, generic intent, hidden start state, or opaque node that collapses preparation, action, assertion, evidence, and teardown.",
92
- "Evidence: inspect the recipe resolution, summary, trace, manifest, logs, and actual visual evidence. A filename or passing node is not visual proof.",
173
+ "Assertion modes such as require_unchanged must fail before any corrective action. Verify the negative path leaves the inspected state untouched; an assertion must not repair the behavior it is supposed to test.",
174
+ "Reuse structured reads with assert_output instead of adding a new domain action for every comparison: source names the earlier node, and assert can select $.matchingCount with operator eq and the expected parameter. A status-report action can succeed while reporting missing prerequisites; assert required values before the dependent action. Checking three rows exist does not prove there are exactly three, or that they belong to this task.",
175
+ "Evidence: inspect the recipe resolution, summary, trace, manifest, logs, and actual artifacts. Verify the values and state required by the claim.",
176
+ "For a change claim, compare the actual before/after values for the same subject. Two captures alone prove neither an update nor freshness. Preserve unchanged observations as unproven rather than retrying to obtain a pass.",
177
+ {
178
+ "text": "Match capture to the claim. Extension ui.capture_surface records the browser document through Chrome, including below-viewport document content but not hidden nested-scroll contents or native dialogs. Keep viewport assertions separate, inspect every image, and preserve failed captures rather than reconstructing them from HTML.",
179
+ "adapters": [
180
+ "extension"
181
+ ]
182
+ },
183
+ {
184
+ "text": "Screenshots: establish the claimed state, capture it, and inspect the original file. If a displayed preview looks incomplete, verify stored pixels or local OCR before reporting a capture defect or changing code. Preserve genuine failed captures.",
185
+ "adapters": [
186
+ "mobile",
187
+ "extension"
188
+ ]
189
+ },
190
+ "Performance: define a measured window, exclude setup, and compare equivalent builds, devices, and lifecycle conditions; action duration alone is not app latency.",
191
+ "Retain samples and declared limits when a measurement fails. For memory growth, compare an equal-duration idle control before attributing it to navigation; do not raise the budget to make the run pass.",
192
+ "Analytics: verify the collection destination and existing consent before capture. Changing participation or marketing consent requires operator approval and restoration of the prior settings; a recipe's hardcoded opt-in is not permission. Missing collection prerequisites are not missing product events.",
93
193
  "Flake risk: wait on observable state instead of sleeping, keep device and runtime identity explicit, and never overwrite a prior run's artifacts.",
94
- "Mutation: require an independent state assertion, identity-bound receipt, and guaranteed cleanup."
194
+ "Mutation: require an independent state assertion and identity-bound receipt. Bind activity to that operation's accepted ID; an old row or nonzero count is insufficient. Opening and closing orders have different IDs. Schedule authorized cleanup in teardown, verify its result, and report any residue. Testnet cleanup must not cancel another task's orders or close its positions.",
195
+ {
196
+ "text": "An accepted order can fill before the UI updates. Preserve its receipt even when the expected resting-order assertion fails; one empty read does not prove cleanup. Check the read API's cache and freshness options before adding polling. Reconcile returned margin against the pre-placement balance. A successful close does not turn the original failed proof into a pass.",
197
+ "adapters": [
198
+ "extension"
199
+ ]
200
+ },
201
+ {
202
+ "text": "A filename or passing node is not visual proof. A container's presence does not prove its data loaded; tab content does not prove its selection indicator. Inspect the captured image and the values it needs to show.",
203
+ "adapters": [
204
+ "mobile",
205
+ "extension"
206
+ ]
207
+ }
95
208
  ],
96
209
  "commands": [
97
210
  "mm-harness run ./proof.recipe.json --artifacts-dir temp/recipe-proof --json",
@@ -102,18 +215,98 @@
102
215
  {
103
216
  "id": "drift",
104
217
  "title": "Repair drift and promote reusable learning",
105
- "instruction": "When a shared recipe fails, reproduce once and classify product regression, recipe drift, fixture/runtime drift, harness defect, or live dependency before changing anything.",
218
+ "instruction": "Treat saved recipes as starting points, not compatibility guarantees. A failure starts diagnosis, not an automatic task stop. Preserve it, compare the current app with the task's acceptance criteria, and distinguish recipe drift from a product, harness, fixture, or live-dependency failure before repairing anything.",
106
219
  "details": [
107
220
  "The graph and evidence contract can be deterministic while the product, provider, account, or network outcome is not. Honest external rejection remains a valid result, not a reason to seek a green retry.",
108
- "Trace the first failure through the exact action source and test the smallest causal explanation before filing or fixing a harness issue. A selector name does not establish its cause. If a proposed fix outgrows the confirmed cause, preserve it separately and return to the minimal fix.",
109
- "For blocked runtime proof, retain the target identity, build/app state, and first failing command and error. Reconcile later status snapshots with that evidence; they cannot establish that an earlier device was absent.",
110
- "For product-version drift, preserve the failed trace, copy the composed recipe into the task, keep working nodes, and repair the smallest owning node against the tested build.",
111
- "Prove the changed node in isolation, re-plan, then rerun the full task-local recipe and affected callers. Never weaken an assertion or change product code merely to turn stale proof green.",
112
- "Record the source recipe digest, tested product identity, repair, and fresh evidence. If the defect belongs to reusable harness code or bundled vocabulary, prepare a focused experimental-metamask-harness issue and open it when authorized.",
113
- "Promote a repair only after it works on the tested version and current main, or declare and enforce its compatibility boundary."
221
+ "Trace the first failure through the exact action source and test the smallest causal explanation before filing or fixing a harness issue. Check the product runtime too: security shims can change standard JavaScript behavior. Compute expectations independently from the verified contract, not host defaults. If a proposed fix outgrows the confirmed cause, preserve it separately and return to the minimal fix.",
222
+ "For blocked runtime proof, retain the target identity, build/app state, and first failing command and error. Reconcile later status snapshots with that evidence; they cannot establish the earlier runtime state.",
223
+ {
224
+ "text": "A failed discovery probe or native snapshot does not establish a stopped app or unsupported platform. Name the failing observation path. Inspect deviceDiscoveryErrors or DEVICE_DISCOVERY_FAILED and its Next command before restarting. Another supported observer must preserve the required visible identity, selection and ordering assertions.",
225
+ "adapters": [
226
+ "mobile"
227
+ ]
228
+ },
229
+ "An RPC failure is not necessarily a credential or network failure. Distinguish HTTP rejection, JavaScript errors and circuit-breaker cooldowns.",
230
+ {
231
+ "text": "If Chrome blocks an unpacked extension with ERR_BLOCKED_BY_CLIENT, inspect its status in that slot's chrome://extensions page before retrying app readiness. unsupportedDeveloperExtension can mean Developer mode is off. Use normal setup controls in the isolated QA profile; do not disable browser security, bypass policy, reset the wallet or treat a blocked page as a product failure.",
232
+ "adapters": [
233
+ "extension"
234
+ ]
235
+ },
236
+ {
237
+ "text": "For LavaMoat execution errors, inspect the effective bundled policy as well as the calling code. A nested method grant can change receiver binding. Reproduce the mechanism in isolation, then validate the owning product correction with LavaMoat still enabled; never replace fetch in the live worker to manufacture proof.",
238
+ "adapters": [
239
+ "extension"
240
+ ]
241
+ },
242
+ {
243
+ "text": "Use LaunchDarkly for feature rollout. Do not add local flag overrides to unblock validation. Match compile-time capabilities to the intended product build; if its remote rollout excludes the feature, report that prerequisite or request targeting from its owner.",
244
+ "adapters": [
245
+ "mobile",
246
+ "extension"
247
+ ]
248
+ },
249
+ "For confirmed product-version drift, copy the closest recipe into the task and retain its working nodes. Adapt only the stale contract or setup condition against current source and observed behavior. Keep the task's acceptance criteria; do not rebuild a working journey or relax its proof to obtain a pass.",
250
+ {
251
+ "text": "Inspect selection before toggling; skip already-satisfied setup. Visibility and a matching locator do not prove click readiness: a menu can move between press and release. Require an uncovered, stable target within the action budget, click once, then assert the result. If it fails, inspect the actual pointer target before changing locators. No fixed sleeps or repeated clicks.",
252
+ "adapters": [
253
+ "mobile",
254
+ "extension"
255
+ ]
256
+ },
257
+ {
258
+ "text": "Use test values distinct from the product's defaults so resets are observable. If an intentional transition reseeds a form, assert its documented reset contract using a recorded baseline; do not claim preservation because the chosen value happened to equal the default.",
259
+ "adapters": [
260
+ "mobile",
261
+ "extension"
262
+ ]
263
+ },
264
+ {
265
+ "text": "A loaded form shell is not a settled quote. Recheck every required preview condition after polling expires; stopping the wait must never turn missing fields into success. Verify this with a real unavailable-preview case and retain the failure.",
266
+ "adapters": [
267
+ "mobile",
268
+ "extension"
269
+ ]
270
+ },
271
+ {
272
+ "text": "After changing quote inputs, bind the returned quote to those inputs. A debounced request may leave the previous positive output and enabled CTA visible briefly; neither proves the new quote is ready. Inspect the capture too, and preserve stale/loading evidence instead of refreshing invisibly.",
273
+ "adapters": [
274
+ "mobile",
275
+ "extension"
276
+ ]
277
+ },
278
+ {
279
+ "text": "Native trees may include controls covered by developer or system overlays. Verify the screenshot before changing a selector; move or dismiss an overlay only as explicit setup and restore it afterward. Gesture path and delta values are offsets from the resolved start, not absolute endpoints; inspect the resolved coordinates and assert the resulting state.",
280
+ "adapters": [
281
+ "mobile"
282
+ ]
283
+ },
284
+ "Reconcile any earlier side effects before repeating a step; an unknown order or transaction outcome must not be resubmitted. Probe the repaired node with call or a small recipe, re-plan, then validate the full task-local recipe and affected callers. Continue the task when the repaired path is proven; report a blocker only when no supported, authorized path remains.",
285
+ "Record the source recipe digest, tested product identity, repair, and fresh evidence. If the defect belongs to reusable harness code or bundled vocabulary, prepare a focused experimental-metamask-harness issue and open it when authorized. Put verified authoring lessons in version-matched harness help; keep task-specific evidence in the task and skills as thin workflow wrappers.",
286
+ "Promote a repair only after it works on the tested version and current main, or declare and enforce its compatibility boundary.",
287
+ "Authoring guide: https://farmslot.io/docs/guides/write-a-recipe/ ; canonical field and graph contract: https://farmslot.io/docs/reference/recipe-protocol-v1/",
288
+ {
289
+ "text": "Verify the visible screen as well as the route name; an old route identifier may now open a different screen.",
290
+ "adapters": [
291
+ "mobile",
292
+ "extension"
293
+ ]
294
+ },
295
+ {
296
+ "text": "Cold XCTest infrastructure belongs in explicit setup: consult agent-device help prepare using the same package, device and state directory. A preparation health check does not prove native snapshot or interaction latency.",
297
+ "adapters": [
298
+ "mobile"
299
+ ]
300
+ },
301
+ {
302
+ "text": "Successful RPC does not prove asset discovery: for empty balances, inspect the active asset controllers and compare compiled capabilities with remote rollout flags. Harness or skills updates do not synchronize slot build fixtures; correct stale build settings at their source and rebuild explicitly without resetting the wallet.",
303
+ "adapters": [
304
+ "extension"
305
+ ]
306
+ }
114
307
  ],
115
308
  "commands": []
116
309
  }
117
310
  ],
118
- "safety": "Recipe parameters never bypass mutation consent or live-funds gates. Preserve valid live financial rejections exactly; never tune or retry merely to obtain a pass, and always run guaranteed cleanup."
311
+ "safety": "Recipe parameters never bypass mutation consent or live-funds gates. Preserve valid live financial rejections; never tune or retry merely to obtain a pass. Run required cleanup and report its actual outcome."
119
312
  }
@@ -1,57 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "Assets release token hide and re-add",
4
- "description": "Hides one imported token and re-enables it through Manage tokens, proving both home-list states.",
5
- "paramsSchema": {
6
- "type": "object",
7
- "additionalProperties": false,
8
- "properties": {
9
- "query": { "type": "string", "default": "DAI" },
10
- "timeout_ms": { "type": "integer", "minimum": 1000, "default": 45000 }
11
- }
12
- },
13
- "workflow": {
14
- "entry": "open-wallet",
15
- "nodes": {
16
- "open-wallet": {
17
- "action": "ui.navigate",
18
- "page": "home",
19
- "intent": "Open the all-network asset list",
20
- "next": "hide-token"
21
- },
22
- "hide-token": {
23
- "action": "metamask.assets.set_token_visibility",
24
- "query": "{{params.query}}",
25
- "visible": false,
26
- "require_change": true,
27
- "timeout_ms": "{{params.timeout_ms}}",
28
- "intent": "Disable the imported token and prove its row disappears",
29
- "next": "capture-hidden"
30
- },
31
- "capture-hidden": {
32
- "action": "ui.screenshot",
33
- "path": "screenshots/assets-token-hidden.png",
34
- "label": "Token hidden",
35
- "intent": "Preserve reviewer-visible hidden state",
36
- "next": "readd-token"
37
- },
38
- "readd-token": {
39
- "action": "metamask.assets.set_token_visibility",
40
- "query": "{{params.query}}",
41
- "visible": true,
42
- "require_change": true,
43
- "timeout_ms": "{{params.timeout_ms}}",
44
- "intent": "Re-enable the token and prove its metadata row returns",
45
- "next": "capture-restored"
46
- },
47
- "capture-restored": {
48
- "action": "ui.screenshot",
49
- "path": "screenshots/assets-token-restored.png",
50
- "label": "Token restored",
51
- "intent": "Preserve reviewer-visible restored state",
52
- "next": "done"
53
- },
54
- "done": { "action": "end", "status": "pass" }
55
- }
56
- }
57
- }
@@ -1,44 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "Clean Perps testnet market",
4
- "description": "Converge one Core Perps testnet market to no matching open position or order.",
5
- "paramsSchema": {
6
- "type": "object",
7
- "additionalProperties": false,
8
- "required": [
9
- "market"
10
- ],
11
- "properties": {
12
- "market": {
13
- "type": "string",
14
- "default": "ETH",
15
- "description": "Perps market symbol to clean."
16
- }
17
- }
18
- },
19
- "workflow": {
20
- "entry": "clean-market",
21
- "nodes": {
22
- "clean-market": {
23
- "action": "metamask.perps.start_state",
24
- "intent": "Converge Core Perps to a clean testnet market",
25
- "profile": "clean_market_testnet",
26
- "network": "testnet",
27
- "market": "{{params.market}}",
28
- "positions": {
29
- "state": "none",
30
- "mode": "matching"
31
- },
32
- "orders": {
33
- "state": "none",
34
- "mode": "matching"
35
- },
36
- "next": "done"
37
- },
38
- "done": {
39
- "action": "end",
40
- "status": "pass"
41
- }
42
- }
43
- }
44
- }
@@ -1,82 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "MetaMask core headless Perps order lifecycle",
4
- "description": "Proves the headless `core` adapter places and cancels a REAL resting Perps LIMIT order on HyperLiquid testnet through the full signing path: a default viem signer backs the perps controller's wallet adapter, the active HyperLiquid testnet provider is initialized, a BTC limit BUY 30% below mid is placed (does not fill — rests on the book), asserted open, then canceled and asserted gone. Leaves the account FLAT — no open orders and no open positions. No CDP, bridge, or UI.",
5
- "workflow": {
6
- "entry": "status",
7
- "nodes": {
8
- "status": {
9
- "action": "app.status",
10
- "next": "start_flat",
11
- "intent": "Resolve the core checkout and report headless compatibility mode"
12
- },
13
- "start_flat": {
14
- "action": "metamask.perps.start_state",
15
- "market": "BTC",
16
- "positions": {
17
- "state": "none"
18
- },
19
- "orders": {
20
- "state": "none"
21
- },
22
- "network": "testnet",
23
- "timeout_ms": 45000,
24
- "next": "place_order",
25
- "intent": "Converge BTC testnet baseline to flat (no positions, no orders) before the proof window"
26
- },
27
- "place_order": {
28
- "action": "metamask.perps.place_order",
29
- "market": "BTC",
30
- "side": "long",
31
- "order_type": "limit",
32
- "offset_pct": -30,
33
- "notional": "11",
34
- "leverage": 2,
35
- "timeout_ms": 45000,
36
- "next": "assert_open",
37
- "intent": "Place a resting BTC limit BUY 30% below mid via the headless controller (real signed limit order to HL testnet; does not fill)"
38
- },
39
- "assert_open": {
40
- "action": "metamask.perps.assert_orders",
41
- "market": "BTC",
42
- "state": "open",
43
- "timeout_ms": 30000,
44
- "next": "cancel_order",
45
- "intent": "Assert the BTC resting limit order opened"
46
- },
47
- "cancel_order": {
48
- "action": "metamask.perps.close_orders",
49
- "market": "BTC",
50
- "timeout_ms": 45000,
51
- "next": "assert_none",
52
- "intent": "Cancel the BTC resting limit order via the headless controller (real signed cancel to HL testnet)"
53
- },
54
- "assert_none": {
55
- "action": "metamask.perps.assert_orders",
56
- "market": "BTC",
57
- "state": "none",
58
- "timeout_ms": 30000,
59
- "next": "teardown_flat",
60
- "intent": "Assert the BTC order canceled — no open orders remain"
61
- },
62
- "teardown_flat": {
63
- "action": "metamask.perps.teardown_state",
64
- "market": "BTC",
65
- "positions": {
66
- "state": "none"
67
- },
68
- "orders": {
69
- "state": "none"
70
- },
71
- "network": "testnet",
72
- "timeout_ms": 45000,
73
- "next": "done",
74
- "intent": "Restore BTC testnet baseline to flat after the proof (leave the shared account clean)"
75
- },
76
- "done": {
77
- "action": "end",
78
- "status": "pass"
79
- }
80
- }
81
- }
82
- }
@@ -1,36 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "MetaMask core headless Perps read",
4
- "description": "Proves the headless `core` adapter instantiates @metamask/perps-controller against a resolved MetaMask/core checkout and reads live HyperLiquid testnet Perps state (positions, open orders, account state) over HTTP — no CDP, bridge, or UI.",
5
- "workflow": {
6
- "entry": "status",
7
- "nodes": {
8
- "status": {
9
- "action": "app.status",
10
- "next": "read_positions",
11
- "intent": "Resolve the core checkout and report headless compatibility mode"
12
- },
13
- "read_positions": {
14
- "action": "metamask.perps.read_positions",
15
- "mode": "all",
16
- "next": "read_orders",
17
- "intent": "Read live Perps positions from the headless controller"
18
- },
19
- "read_orders": {
20
- "action": "metamask.perps.read_orders",
21
- "mode": "all",
22
- "next": "read_account",
23
- "intent": "Read live Perps open orders from the headless controller"
24
- },
25
- "read_account": {
26
- "action": "metamask.perps.read_account",
27
- "next": "done",
28
- "intent": "Read live Perps account state from the headless controller"
29
- },
30
- "done": {
31
- "action": "end",
32
- "status": "pass"
33
- }
34
- }
35
- }
36
- }