@deeeed/metamask-harness 0.40.0 → 0.41.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 (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/adapters/manifest.json +8 -0
  3. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +5 -4
  4. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +24 -5
  5. package/adapters/mobile/metro-config.cjs +94 -0
  6. package/adapters/mobile/start-metro.sh +13 -1
  7. package/dist/commands/device-target.js +3 -0
  8. package/dist/commands/run-engine.js +4 -14
  9. package/dist/funding-execution-context.js +35 -28
  10. package/dist/heal-bounds.js +1 -0
  11. package/dist/live-adapter-contract.js +2 -1
  12. package/dist/mm-harness-cli.js +1 -1
  13. package/docs/RECIPES.md +25 -19
  14. package/library/actions/extension/perps/mutation-receipt.mjs +12 -8
  15. package/library/actions/extension/perps/select_activity_filter.mjs +1 -1
  16. package/library/actions/extension/perps/select_market_filter.mjs +1 -1
  17. package/library/actions/mobile/perps/capture_performance.mjs +2 -2
  18. package/library/actions/mobile/perps/performance-capture.mjs +375 -17
  19. package/library/actions/mobile/perps/perps.mjs +56 -10
  20. package/library/actions/mobile/platform/bridge.mjs +59 -1
  21. package/library/actions/mobile/wallet/ensure_unlocked.mjs +60 -26
  22. package/library/actions/mobile/wallet/import.mjs +2 -0
  23. package/library/actions/mobile/wallet/select_account.mjs +21 -2
  24. package/library/manifests/mobile.action-manifest.json +47 -6
  25. package/library/recipes/mobile/perps/performance.recipe.json +680 -26
  26. package/package.json +1 -1
  27. package/library/recipes/mobile/perps/performance.background-resume.recipe.json +0 -56
  28. package/library/recipes/mobile/perps/performance.cold-start.recipe.json +0 -56
  29. package/library/recipes/mobile/perps/performance.homepage.android-background-reconnect.recipe.json +0 -159
  30. package/library/recipes/mobile/perps/performance.homepage.android-background-short.recipe.json +0 -157
  31. package/library/recipes/mobile/perps/performance.homepage.android-cold-disk-cache.recipe.json +0 -165
  32. package/library/recipes/mobile/perps/performance.homepage.android-cold-no-cache.recipe.json +0 -139
  33. package/library/recipes/mobile/perps/performance.homepage.android-network-recovery.recipe.json +0 -149
  34. package/library/recipes/mobile/perps/performance.homepage.cold-position-sample.recipe.json +0 -120
  35. package/library/recipes/mobile/perps/performance.homepage.ios-background-reconnect.recipe.json +0 -111
  36. package/library/recipes/mobile/perps/performance.homepage.ios-background-short.recipe.json +0 -108
  37. package/library/recipes/mobile/perps/performance.homepage.ios-cold-disk-cache.recipe.json +0 -122
  38. package/library/recipes/mobile/perps/performance.homepage.ios-cold-no-cache.recipe.json +0 -95
  39. package/library/recipes/mobile/perps/performance.warm-start.recipe.json +0 -49
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.40.0",
3
+ "version": "0.41.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -1,56 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "MetaMask Mobile Perps performance recipe — background resume",
4
- "description": "Measured Perps recipe from a deterministic background-resume state. The graph backgrounds and foregrounds the installed app without rebuilding, unlocks if needed, then records Perps list, state, and BTC detail timings.",
5
- "workflow": {
6
- "entry": "background-app",
7
- "nodes": {
8
- "open-perps-list": {
9
- "action": "ui.navigate",
10
- "page": "perps",
11
- "intent": "Open the Perps market list screen",
12
- "next": "read-positions"
13
- },
14
- "read-positions": {
15
- "action": "metamask.perps.read_positions",
16
- "intent": "Read the live Perps positions shown on the market list",
17
- "next": "open-market-detail"
18
- },
19
- "open-market-detail": {
20
- "action": "ui.navigate",
21
- "page": "perps-market",
22
- "market": "BTC",
23
- "intent": "Open the BTC Perps market detail screen",
24
- "next": "end"
25
- },
26
- "end": {
27
- "action": "end",
28
- "status": "pass"
29
- },
30
- "start-state": {
31
- "action": "app.status",
32
- "intent": "Record the stable run start status after background-resume setup",
33
- "next": "open-perps-list"
34
- },
35
- "ensure-unlocked": {
36
- "action": "metamask.wallet.ensure_unlocked",
37
- "intent": "Unlock the wallet before timing the Perps journey",
38
- "next": "start-state"
39
- },
40
- "foreground-app": {
41
- "action": "app.lifecycle",
42
- "command": "foreground",
43
- "settle_ms": 15000,
44
- "intent": "Foreground the installed app through the Expo dev-client deep link",
45
- "next": "ensure-unlocked"
46
- },
47
- "background-app": {
48
- "action": "app.lifecycle",
49
- "command": "background",
50
- "settle_ms": 3000,
51
- "intent": "Put the installed app in the background before measuring resume",
52
- "next": "foreground-app"
53
- }
54
- }
55
- }
56
- }
@@ -1,56 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "MetaMask Mobile Perps performance recipe — cold process start",
4
- "description": "Measured Perps recipe from a deterministic cold-process state. The graph terminates and relaunches the installed app without rebuilding, unlocks if needed, then records Perps list, state, and BTC detail timings.",
5
- "workflow": {
6
- "entry": "terminate-app",
7
- "nodes": {
8
- "open-perps-list": {
9
- "action": "ui.navigate",
10
- "page": "perps",
11
- "intent": "Open the Perps market list screen",
12
- "next": "read-positions"
13
- },
14
- "read-positions": {
15
- "action": "metamask.perps.read_positions",
16
- "intent": "Read the live Perps positions shown on the market list",
17
- "next": "open-market-detail"
18
- },
19
- "open-market-detail": {
20
- "action": "ui.navigate",
21
- "page": "perps-market",
22
- "market": "BTC",
23
- "intent": "Open the BTC Perps market detail screen",
24
- "next": "end"
25
- },
26
- "end": {
27
- "action": "end",
28
- "status": "pass"
29
- },
30
- "start-state": {
31
- "action": "app.status",
32
- "intent": "Record the stable run start status after cold-start setup",
33
- "next": "open-perps-list"
34
- },
35
- "ensure-unlocked": {
36
- "action": "metamask.wallet.ensure_unlocked",
37
- "intent": "Unlock the wallet before timing the Perps journey",
38
- "next": "start-state"
39
- },
40
- "launch-app": {
41
- "action": "app.lifecycle",
42
- "command": "launch",
43
- "settle_ms": 15000,
44
- "intent": "Launch the installed app through the Expo dev-client deep link",
45
- "next": "ensure-unlocked"
46
- },
47
- "terminate-app": {
48
- "action": "app.lifecycle",
49
- "command": "terminate",
50
- "settle_ms": 3000,
51
- "intent": "Terminate the installed app process before measuring cold start",
52
- "next": "launch-app"
53
- }
54
- }
55
- }
56
- }
@@ -1,159 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "Android Homepage Perps reconnect visible performance proof",
4
- "description": "Establishes a visible live order on Wallet Home, backgrounds the physical Android app beyond the 20-second connection grace period, restores it, and validates the reconnect-to-fresh-visible pipeline.",
5
- "workflow": {
6
- "entry": "prepare-open-order",
7
- "nodes": {
8
- "prepare-open-order": {
9
- "action": "metamask.perps.start_state",
10
- "profile": "open_order_testnet",
11
- "provider": "hyperliquid",
12
- "network": "testnet",
13
- "market": "ETH",
14
- "page": "perps_home",
15
- "side": "short",
16
- "orders": {
17
- "state": "open",
18
- "mode": "matching",
19
- "market": "ETH",
20
- "side": "short",
21
- "notional": 10,
22
- "leverage": 2,
23
- "timeout_ms": 90000
24
- },
25
- "positions": false,
26
- "intent": "Prepare a deterministic live order before the reconnect proof",
27
- "timeout_ms": 120000,
28
- "next": "open-wallet-home"
29
- },
30
- "open-wallet-home": {
31
- "action": "ui.navigate",
32
- "page": "home",
33
- "intent": "Open Wallet Home before the connection expires",
34
- "timeout_ms": 30000,
35
- "next": "wait-content-mounted"
36
- },
37
- "wait-content-mounted": {
38
- "action": "ui.wait_for",
39
- "test_id": "homepage-perps-positions",
40
- "expected": "present",
41
- "intent": "Confirm the data-backed Homepage section is rendered",
42
- "timeout_ms": 30000,
43
- "next": "show-content"
44
- },
45
- "show-content": {
46
- "action": "ui.scroll",
47
- "test_id": "homepage-perps-positions",
48
- "scroll_into_view": true,
49
- "animated": true,
50
- "settle": true,
51
- "intent": "Make the live order reviewable before disconnecting",
52
- "timeout_ms": 30000,
53
- "next": "wait-order-before"
54
- },
55
- "wait-order-before": {
56
- "action": "ui.wait_for",
57
- "text": "Limit short",
58
- "expected": "visible",
59
- "intent": "Prove the same live order is visible before reconnect",
60
- "timeout_ms": 30000,
61
- "next": "start-performance-capture"
62
- },
63
- "start-performance-capture": {
64
- "action": "metamask.perps.capture_performance",
65
- "phase": "start",
66
- "intent": "Start the evidence window immediately before the long background interval",
67
- "next": "background-app"
68
- },
69
- "background-app": {
70
- "action": "app.lifecycle",
71
- "command": "background",
72
- "settle_ms": 25000,
73
- "intent": "Keep the app inactive beyond the connection grace period",
74
- "next": "foreground-app"
75
- },
76
- "foreground-app": {
77
- "action": "app.lifecycle",
78
- "command": "foreground",
79
- "settle_ms": 15000,
80
- "intent": "Restore the installed app and allow stream recovery",
81
- "next": "wait-content-after"
82
- },
83
- "wait-content-after": {
84
- "action": "ui.wait_for",
85
- "test_id": "homepage-perps-positions",
86
- "expected": "present",
87
- "intent": "Confirm the Homepage Perps state remains rendered after reconnect",
88
- "timeout_ms": 30000,
89
- "next": "show-content-after"
90
- },
91
- "show-content-after": {
92
- "action": "ui.scroll",
93
- "test_id": "homepage-perps-positions",
94
- "scroll_into_view": true,
95
- "animated": true,
96
- "settle": true,
97
- "intent": "Make the recovered data directly reviewable",
98
- "timeout_ms": 30000,
99
- "next": "wait-order-after"
100
- },
101
- "wait-order-after": {
102
- "action": "ui.wait_for",
103
- "text": "Limit short",
104
- "expected": "visible",
105
- "intent": "Prove the live order is displayed after stream recovery",
106
- "timeout_ms": 30000,
107
- "next": "capture-after"
108
- },
109
- "capture-after": {
110
- "action": "ui.screenshot",
111
- "path": "screenshots/homepage-order-after-reconnect.png",
112
- "intent": "Preserve reviewer-visible reconnect proof",
113
- "next": "settle-frame"
114
- },
115
- "settle-frame": {
116
- "action": "wait",
117
- "duration_ms": 2500,
118
- "intent": "Allow the fresh visible frame checkpoint to finish",
119
- "next": "finish-performance-capture"
120
- },
121
- "finish-performance-capture": {
122
- "action": "metamask.perps.capture_performance",
123
- "phase": "end",
124
- "required_stages": [
125
- "viewport_demand",
126
- "socket_received",
127
- "react_commit",
128
- "next_frame_checkpoint"
129
- ],
130
- "required_lifecycles": ["background_reconnect"],
131
- "required_sources": ["resident_state", "fresh_socket"],
132
- "required_fresh_content_variants": ["orders"],
133
- "intent": "Preserve and validate the reconnect measurement cohort",
134
- "next": "cleanup-order"
135
- },
136
- "cleanup-order": {
137
- "action": "metamask.perps.teardown_state",
138
- "provider": "hyperliquid",
139
- "network": "testnet",
140
- "market": "ETH",
141
- "page": "home",
142
- "positions": false,
143
- "orders": {
144
- "state": "none",
145
- "mode": "matching",
146
- "market": "ETH",
147
- "timeout_ms": 60000
148
- },
149
- "intent": "Cancel the deterministic testnet order after evidence capture",
150
- "timeout_ms": 90000,
151
- "next": "done"
152
- },
153
- "done": {
154
- "action": "end",
155
- "status": "pass"
156
- }
157
- }
158
- }
159
- }
@@ -1,157 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "Android Homepage Perps short-background visible performance proof",
4
- "description": "Establishes a visible live order on Wallet Home, backgrounds the physical Android app for less than the 20-second reconnect threshold, restores it, and correlates the resumed frame with run-scoped performance evidence.",
5
- "workflow": {
6
- "entry": "prepare-open-order",
7
- "nodes": {
8
- "prepare-open-order": {
9
- "action": "metamask.perps.start_state",
10
- "profile": "open_order_testnet",
11
- "provider": "hyperliquid",
12
- "network": "testnet",
13
- "market": "ETH",
14
- "page": "perps_home",
15
- "side": "short",
16
- "orders": {
17
- "state": "open",
18
- "mode": "matching",
19
- "market": "ETH",
20
- "side": "short",
21
- "notional": 10,
22
- "leverage": 2,
23
- "timeout_ms": 90000
24
- },
25
- "positions": false,
26
- "intent": "Prepare a deterministic live order before the lifecycle proof",
27
- "timeout_ms": 120000,
28
- "next": "open-wallet-home"
29
- },
30
- "open-wallet-home": {
31
- "action": "ui.navigate",
32
- "page": "home",
33
- "intent": "Open Wallet Home before the lifecycle transition",
34
- "timeout_ms": 30000,
35
- "next": "wait-content-mounted"
36
- },
37
- "wait-content-mounted": {
38
- "action": "ui.wait_for",
39
- "test_id": "homepage-perps-positions",
40
- "expected": "present",
41
- "intent": "Confirm the data-backed Homepage section is rendered",
42
- "timeout_ms": 30000,
43
- "next": "show-content"
44
- },
45
- "show-content": {
46
- "action": "ui.scroll",
47
- "test_id": "homepage-perps-positions",
48
- "scroll_into_view": true,
49
- "animated": true,
50
- "settle": true,
51
- "intent": "Make the order card available before the app leaves the foreground",
52
- "timeout_ms": 30000,
53
- "next": "wait-order-before"
54
- },
55
- "wait-order-before": {
56
- "action": "ui.wait_for",
57
- "text": "Limit short",
58
- "expected": "visible",
59
- "intent": "Prove the same live order is visible before the lifecycle transition",
60
- "timeout_ms": 30000,
61
- "next": "start-performance-capture"
62
- },
63
- "start-performance-capture": {
64
- "action": "metamask.perps.capture_performance",
65
- "phase": "start",
66
- "intent": "Start the evidence window immediately before backgrounding",
67
- "next": "background-app"
68
- },
69
- "background-app": {
70
- "action": "app.lifecycle",
71
- "command": "background",
72
- "settle_ms": 3000,
73
- "intent": "Leave the app inactive for less than the reconnect grace period",
74
- "next": "foreground-app"
75
- },
76
- "foreground-app": {
77
- "action": "app.lifecycle",
78
- "command": "foreground",
79
- "settle_ms": 10000,
80
- "intent": "Restore the same installed app and wallet session",
81
- "next": "wait-content-after"
82
- },
83
- "wait-content-after": {
84
- "action": "ui.wait_for",
85
- "test_id": "homepage-perps-positions",
86
- "expected": "present",
87
- "intent": "Confirm the Homepage Perps state survived the short background interval",
88
- "timeout_ms": 30000,
89
- "next": "show-content-after"
90
- },
91
- "show-content-after": {
92
- "action": "ui.scroll",
93
- "test_id": "homepage-perps-positions",
94
- "scroll_into_view": true,
95
- "animated": true,
96
- "settle": true,
97
- "intent": "Make the restored data directly reviewable after foregrounding",
98
- "timeout_ms": 30000,
99
- "next": "wait-order-after"
100
- },
101
- "wait-order-after": {
102
- "action": "ui.wait_for",
103
- "text": "Limit short",
104
- "expected": "visible",
105
- "intent": "Prove the live order remains displayed after the short resume",
106
- "timeout_ms": 30000,
107
- "next": "capture-after"
108
- },
109
- "capture-after": {
110
- "action": "ui.screenshot",
111
- "path": "screenshots/homepage-order-after-short-background.png",
112
- "intent": "Preserve reviewer-visible short-resume proof",
113
- "next": "settle-frame"
114
- },
115
- "settle-frame": {
116
- "action": "wait",
117
- "duration_ms": 2500,
118
- "intent": "Allow the visible frame checkpoint to finish",
119
- "next": "finish-performance-capture"
120
- },
121
- "finish-performance-capture": {
122
- "action": "metamask.perps.capture_performance",
123
- "phase": "end",
124
- "required_stages": [
125
- "viewport_demand",
126
- "react_commit",
127
- "next_frame_checkpoint"
128
- ],
129
- "required_lifecycles": ["background_short"],
130
- "required_sources": ["resident_state", "fresh_socket"],
131
- "intent": "Preserve and validate the short-background measurement cohort",
132
- "next": "cleanup-order"
133
- },
134
- "cleanup-order": {
135
- "action": "metamask.perps.teardown_state",
136
- "provider": "hyperliquid",
137
- "network": "testnet",
138
- "market": "ETH",
139
- "page": "home",
140
- "positions": false,
141
- "orders": {
142
- "state": "none",
143
- "mode": "matching",
144
- "market": "ETH",
145
- "timeout_ms": 60000
146
- },
147
- "intent": "Cancel the deterministic testnet order after evidence capture",
148
- "timeout_ms": 90000,
149
- "next": "done"
150
- },
151
- "done": {
152
- "action": "end",
153
- "status": "pass"
154
- }
155
- }
156
- }
157
- }
@@ -1,165 +0,0 @@
1
- {
2
- "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
- "title": "Android Homepage Perps cold disk-cache visible performance proof",
4
- "description": "Creates a deterministic visible order, restarts the Android process without clearing app data, and validates disk-cache-to-fresh visible content after cold launch.",
5
- "workflow": {
6
- "entry": "prepare-open-order",
7
- "nodes": {
8
- "prepare-open-order": {
9
- "action": "metamask.perps.start_state",
10
- "profile": "open_order_testnet",
11
- "provider": "hyperliquid",
12
- "network": "testnet",
13
- "market": "ETH",
14
- "page": "perps_home",
15
- "side": "short",
16
- "orders": {
17
- "state": "open",
18
- "mode": "matching",
19
- "market": "ETH",
20
- "side": "short",
21
- "notional": 10,
22
- "leverage": 2,
23
- "timeout_ms": 90000
24
- },
25
- "positions": false,
26
- "intent": "Prepare a persisted live order before cold process launch",
27
- "timeout_ms": 120000,
28
- "next": "open-wallet-home"
29
- },
30
- "open-wallet-home": {
31
- "action": "ui.navigate",
32
- "page": "home",
33
- "intent": "Open Wallet Home so the Perps disk cache is current",
34
- "timeout_ms": 30000,
35
- "next": "wait-order-before"
36
- },
37
- "wait-order-before": {
38
- "action": "ui.wait_for",
39
- "text": "Limit short",
40
- "expected": "present",
41
- "intent": "Prove the persisted order exists before restart",
42
- "timeout_ms": 30000,
43
- "next": "start-performance-capture"
44
- },
45
- "start-performance-capture": {
46
- "action": "metamask.perps.capture_performance",
47
- "phase": "start",
48
- "intent": "Start the evidence window before the process restart",
49
- "next": "restart-app"
50
- },
51
- "restart-app": {
52
- "action": "app.lifecycle",
53
- "command": "restart",
54
- "settle_ms": 15000,
55
- "intent": "Cold-restart the app while preserving persisted app data",
56
- "next": "unlock-after-restart"
57
- },
58
- "unlock-after-restart": {
59
- "action": "metamask.wallet.ensure_unlocked",
60
- "target_timeout_ms": 90000,
61
- "unlock_timeout_ms": 90000,
62
- "intent": "Restore the fixture wallet after the cold process launch",
63
- "next": "open-wallet-home-after"
64
- },
65
- "open-wallet-home-after": {
66
- "action": "ui.navigate",
67
- "page": "home",
68
- "intent": "Return to Wallet Home after unlocking the cold-started process",
69
- "timeout_ms": 30000,
70
- "next": "wait-content-after"
71
- },
72
- "wait-content-after": {
73
- "action": "ui.wait_for",
74
- "test_id": "homepage-perps-positions",
75
- "expected": "present",
76
- "intent": "Confirm Wallet Home restores data-backed Perps content after cold launch",
77
- "timeout_ms": 30000,
78
- "next": "show-content-after"
79
- },
80
- "show-content-after": {
81
- "action": "ui.scroll",
82
- "test_id": "homepage-perps-positions",
83
- "scroll_into_view": true,
84
- "animated": true,
85
- "settle": true,
86
- "intent": "Bring the cold-start Perps content into the viewport",
87
- "timeout_ms": 30000,
88
- "next": "wait-order-after"
89
- },
90
- "wait-order-after": {
91
- "action": "ui.wait_for",
92
- "text": "Limit short",
93
- "expected": "visible",
94
- "intent": "Prove the same live order is visible after cold launch",
95
- "timeout_ms": 30000,
96
- "next": "capture-after"
97
- },
98
- "capture-after": {
99
- "action": "ui.screenshot",
100
- "path": "screenshots/homepage-order-after-cold-start.png",
101
- "intent": "Preserve reviewer-visible cold-start proof",
102
- "next": "settle-frame"
103
- },
104
- "settle-frame": {
105
- "action": "wait",
106
- "duration_ms": 2500,
107
- "intent": "Allow the fresh visible frame checkpoint to finish",
108
- "next": "finish-performance-capture"
109
- },
110
- "finish-performance-capture": {
111
- "action": "metamask.perps.capture_performance",
112
- "phase": "end",
113
- "artifact_prefix": "logs/homepage-order-cold-disk-cache",
114
- "required_stages": [
115
- "disk_cache_hydrated",
116
- "viewport_demand",
117
- "socket_received",
118
- "subscriber_delivery",
119
- "react_commit",
120
- "next_frame_checkpoint"
121
- ],
122
- "required_lifecycles": ["cold_disk_cache"],
123
- "required_sources": ["fresh_socket"],
124
- "required_fresh_content_variants": ["orders"],
125
- "first_fresh_delivery_requirements": [
126
- {
127
- "stream": "positions",
128
- "lifecycle": "cold_disk_cache",
129
- "subscriber_throttle_ms": 5000,
130
- "max_socket_to_subscriber_ms": 1000
131
- },
132
- {
133
- "stream": "orders",
134
- "lifecycle": "cold_disk_cache",
135
- "subscriber_throttle_ms": 5000,
136
- "max_socket_to_subscriber_ms": 1000
137
- }
138
- ],
139
- "intent": "Require cache hydration, fresh visible order content, and immediate first-fresh positions/orders delivery",
140
- "next": "cleanup-order"
141
- },
142
- "cleanup-order": {
143
- "action": "metamask.perps.teardown_state",
144
- "provider": "hyperliquid",
145
- "network": "testnet",
146
- "market": "ETH",
147
- "page": "home",
148
- "positions": false,
149
- "orders": {
150
- "state": "none",
151
- "mode": "matching",
152
- "market": "ETH",
153
- "timeout_ms": 60000
154
- },
155
- "intent": "Cancel the deterministic testnet order after evidence capture",
156
- "timeout_ms": 90000,
157
- "next": "done"
158
- },
159
- "done": {
160
- "action": "end",
161
- "status": "pass"
162
- }
163
- }
164
- }
165
- }