@deeeed/metamask-harness 0.17.2 → 0.17.4

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 (81) hide show
  1. package/CHANGELOG.md +35 -8
  2. package/README.md +12 -6
  3. package/adapters/core/cleanup.sh +0 -0
  4. package/adapters/core/inject.sh +0 -0
  5. package/adapters/extension/cleanup.mjs +0 -0
  6. package/adapters/extension/console-tail.mjs +5 -1
  7. package/adapters/extension/ensure-browser.sh +0 -0
  8. package/adapters/extension/inject.mjs +0 -0
  9. package/adapters/extension/launch-browser.cjs +0 -0
  10. package/adapters/extension/launch.sh +0 -0
  11. package/adapters/extension/live.sh +0 -0
  12. package/adapters/extension/readiness.mjs +0 -0
  13. package/adapters/extension/reattach.sh +0 -0
  14. package/adapters/extension/refresh-build.sh +0 -0
  15. package/adapters/extension/seed-fixture.sh +0 -0
  16. package/adapters/extension/sidepanel-toggle.sh +0 -0
  17. package/adapters/extension/snapshot-dist.sh +0 -0
  18. package/adapters/extension/stamp-runtime-title.cjs +18 -9
  19. package/adapters/extension/start-watch.sh +1 -0
  20. package/adapters/extension/stop-viewers.sh +0 -0
  21. package/adapters/extension/sync-webpack-dist.cjs +9 -7
  22. package/adapters/extension/verify.sh +0 -0
  23. package/adapters/extension/wallet-fixture-state.cjs +0 -0
  24. package/adapters/manifest.json +9 -1
  25. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +0 -0
  26. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
  27. package/adapters/mobile/bridge-runtime/setup-wallet.sh +0 -0
  28. package/adapters/mobile/cleanup.sh +0 -0
  29. package/adapters/mobile/inject.sh +13 -11
  30. package/adapters/mobile/launch-console-forwarder.cjs +0 -0
  31. package/adapters/mobile/lib/metro-listener.sh +0 -0
  32. package/adapters/mobile/lib/tmux-viewer.sh +0 -0
  33. package/adapters/mobile/open-device.sh +0 -0
  34. package/adapters/mobile/prewarm-bundle.sh +0 -0
  35. package/adapters/mobile/start-console-forwarder.sh +3 -3
  36. package/adapters/mobile/start-metro.sh +0 -0
  37. package/adapters/mobile/stop-metro.sh +0 -0
  38. package/adapters/mobile/verify.sh +0 -0
  39. package/adapters/mobile/wait-for-bridge.sh +22 -8
  40. package/adapters/mobile/yarn-setup.sh +0 -0
  41. package/adapters/shared/activate-repo-node.sh +0 -0
  42. package/adapters/shared/activate-repo-ruby.sh +0 -0
  43. package/adapters/shared/cli-ux.sh +0 -0
  44. package/adapters/shared/ensure-runner-deps.sh +0 -0
  45. package/adapters/shared/harness-path.sh +0 -0
  46. package/adapters/shared/hash-helpers.sh +0 -0
  47. package/adapters/shared/install-repo-deps.sh +0 -0
  48. package/adapters/shared/json-field.sh +0 -0
  49. package/adapters/shared/open-debug.mjs +7 -1
  50. package/adapters/shared/open-log-window.sh +0 -0
  51. package/adapters/shared/reap-checkout-metros.sh +0 -0
  52. package/adapters/shared/resolve-slot-ports.mjs +0 -0
  53. package/adapters/shared/resolve-slot-ports.sh +0 -0
  54. package/adapters/shared/sync-wallet-fixture.sh +0 -0
  55. package/adapters/shared/tmux-session.sh +0 -0
  56. package/adapters/shared/tmux-viewer.sh +0 -0
  57. package/adapters/shared/update-check-worker.mjs +11 -5
  58. package/dist/adapters/extension/console-capture.js +10 -1
  59. package/dist/adapters/mobile/prepare.js +5 -5
  60. package/dist/adapters/slot-ports.js +8 -0
  61. package/dist/cli.js +1 -1
  62. package/dist/commands/doctor.js +33 -8
  63. package/dist/commands/run-engine.js +2 -4
  64. package/dist/commands/update.js +2 -1
  65. package/dist/harness.js +24 -9
  66. package/dist/mm-harness-cli.js +7 -6
  67. package/dist/run-diagnostics.js +1 -6
  68. package/docs/ADAPTER-SURFACE.md +19 -112
  69. package/docs/CLI-ERGONOMICS-HUMAN-QA.md +16 -0
  70. package/docs/UX-PRINCIPLES.md +1 -1
  71. package/docs/VIDEO-DEMO-VALIDATION.md +56 -44
  72. package/docs/recipe-libraries.md +45 -275
  73. package/library/README.md +4 -0
  74. package/library/manifests/core.action-manifest.json +7 -7
  75. package/library/recipes/runner/smoke.core.recipe.json +27 -0
  76. package/library/recipes/wallet/smoke.extension.recipe.json +42 -0
  77. package/library/recipes/wallet/smoke.mobile.recipe.json +42 -0
  78. package/package.json +4 -2
  79. package/scripts/completions.sh +0 -0
  80. package/scripts/install-completions.sh +0 -0
  81. package/scripts/validate-human-outcomes.mjs +169 -0
@@ -1,301 +1,71 @@
1
- # Recipe Libraries
1
+ # Recipe libraries
2
2
 
3
- Per-change recipes are throwaway proofs: generated for one PR, run as evidence,
4
- discarded. A **recipe library** is the durable keep behind them — the reusable
5
- flows ("set up a funded wallet", "converge Perps to a clean BTC baseline") a
6
- per-change recipe is composed FROM. Libraries are owned bottom-up: each
7
- developer accumulates their own, teams share theirs, and this runner ships only
8
- a minimal canonical set. Nothing here requires central governance to function.
3
+ A library shares reusable behavior without coupling it to one ticket:
9
4
 
10
- ## The three sources and who owns them
5
+ - an **action** is one typed operation supplied by a platform adapter;
6
+ - a **flow** is a reusable parameterized action sequence;
7
+ - a **recipe** is a complete executable proof and owns task acceptance criteria.
11
8
 
12
- | Source | Location | Owned by | Contains |
13
- | --- | --- | --- | --- |
14
- | Personal | `<farmslot home>/recipe-library` (`FARMSLOT_HOME`, default `~/.farmslot`) | the developer, entirely | the developer's accumulated flow history |
15
- | Team | a repo the team owns (any host); checked out locally and configured as a source | the team's developers directly — not a MetaMask-governed artifact | richer domain flows the team maintains |
16
- | Canonical (repo-native) | this runner's `library/` | this runner | minimal, stable primitives only (see `library/flows/`) |
9
+ Use a flow when several recipes repeat the same product journey. Keep ticket copy,
10
+ layout claims, and one-off assertions in the task recipe.
17
11
 
18
- A library is just a directory:
12
+ ## Directory
19
13
 
20
14
  ```text
21
- <library-root>/
22
- library.json { "kind": "recipe-library", "schema_version": 1, "name": "..." }
23
- flows/*.flows.json standard recipe-flow-catalog documents (Recipe Protocol v1 §8)
15
+ team-recipes/
16
+ library.json
17
+ flows/
18
+ wallet.flows.json
19
+ recipes/
20
+ onboarding/
21
+ smoke.extension.recipe.json
24
22
  ```
25
23
 
26
- There is no new format: library flows are the same flow-catalog documents a
27
- recipe can reference through `uses`, and per-change recipes call them with the
28
- standard `call` node.
29
-
30
- ## Resolution and precedence
31
-
32
- `mm-harness run` resolves `call` refs from ordered sources; the first
33
- source that declares a ref wins:
34
-
35
- 1. recipe-local declarations (inline `flows` and explicit `uses` paths) — always win;
36
- 2. your explicit entries: repeatable/colon-separated `--library name=path` or `RECIPE_LIBRARY_PATH` (order = precedence), or, when neither is set, your personal library;
37
- 3. the canonical `metamask` library, appended last.
38
-
39
- Personal and team flows therefore shadow canonical ones **by default** — that
40
- is intentional (your history is the point; the canonical set is fallback
41
- vocabulary, not authority). Shadowing is never silent: it is printed at run
42
- start, recorded in `summary.json` under `flowResolution`, and the exact
43
- definitions a run executed are snapshotted into the `resolved-flows.json`
44
- artifact so reviewers can inspect the evidence without access to your
45
- libraries.
46
-
47
- ```bash
48
- mm-harness flows list # every flow across your sources, with provenance
49
- RECIPE_LIBRARY_PATH="team=~/dev/team-recipes" mm-harness flows list
50
- mm-harness run recipe.json --adapter extension --artifacts-dir artifacts \
51
- --library "team=~/dev/team-recipes"
52
- ```
53
-
54
- ## Promoting a flow (building your history)
55
-
56
- After a successful run, keep a flow that proved useful:
57
-
58
- ```bash
59
- mm-harness flows promote --from recipe.json --flow perps.my_baseline \
60
- --run artifacts # stamps provenance.lastVerified from the passing run
61
- ```
62
-
63
- Promotion is the contract gate: the flow must have a `description`, `ensure_*`
64
- flows must declare a `postcondition`, and the stored flow is stamped with
65
- provenance (origin recipe, promotion date, and `lastVerified` only when backed
66
- by a passing run's artifacts). The personal library is created on first
67
- promote.
68
-
69
- ## Sharing with your team
70
-
71
- Sharing is a plain PR: copy or promote the flow into the team's library repo
72
- and let the team review it like any other change. Their repo, their rules —
73
- there is no registration step and no org approval involved.
74
-
75
- ## Trust and drift
76
-
77
- Library flows rot as the app changes. Three guards, cheapest first:
78
-
79
- 1. **Postconditions** — a stale flow fails its postcondition at run time and
80
- fails the recipe loudly; promotion nudges every flow toward asserting its
81
- outcome.
82
- 2. **Freshness warnings** — `flows list` and run-start resolution flag flows
83
- whose `lastVerified` is older than 30 days.
84
- 3. **Provenance in evidence** — `flowResolution` + `resolved-flows.json` make
85
- it visible exactly which flow, from which source, produced a proof.
86
-
87
- ## Rules for the canonical library
88
-
89
- Additions to `library/flows/` are held to the flow-catalog maintenance rules
90
- (`docs/perps-flow-catalog.md`, Recipe Protocol v1 §8.1): parameterized
91
- primitives over name multiplication, a real reusable domain concept per flow,
92
- and a small flow budget. If a flow is team- or task-specific, it belongs in a
93
- team or personal library — that is what the precedence order is for.
94
- `scripts/check.mjs` validates every committed catalog against the action
95
- manifests.
96
-
97
- ## Your own measured flow: creating a personal recipe library
98
-
99
- A **measured flow** is a recipe you run the same way every time to watch how long
100
- each user-visible step takes. The runner has no benchmark verb: timings are just
101
- the per-node `duration`s in a passing run's `trace.json`, so a flow is comparable
102
- across runs only when you pin the run (same device, healing off) and keep the node
103
- graph stable. The repo ships one canonical example,
104
- `library/recipes/perps/performance.mobile.recipe.json` — unlock → open the Perps
105
- market list → read live state → open a market detail. This walkthrough copies it
106
- into a library of your own and retargets it to your journey. A peer engineer can
107
- follow it verbatim; the same steps run as the `perps.performance-recipe` contract
108
- test.
109
-
110
- ### 1. Scaffold a personal library
111
-
112
- A library is a directory with a `library.json` marker. Keep reusable `flows/`
113
- (referenced via `call`) beside a domain-grouped `recipes/` folder for the full
114
- flows you run:
115
-
116
- ```bash
117
- mkdir -p ~/my-recipes/flows ~/my-recipes/recipes/my-perps
118
- cat > ~/my-recipes/library.json <<'JSON'
119
- { "kind": "recipe-library", "schema_version": 1, "name": "mydev", "owner": "mydev" }
120
- JSON
121
- ```
122
-
123
- In real use this is discovered for you: with no `--library` flag and no
124
- `RECIPE_LIBRARY_PATH`, the runner reads your personal library at
125
- `$FARMSLOT_HOME/recipe-library` (default `~/.farmslot/recipe-library`). The
126
- explicit `--library mydev=<dir>` form below is the same mechanism, spelled out so
127
- it works headlessly (CI, a scratch checkout) and so the path is unambiguous.
128
-
129
- ### 2. Copy the canonical recipe as a starting point
130
-
131
- Copy it out of your runner checkout's `library/recipes/`:
132
-
133
- ```bash
134
- cp library/recipes/perps/performance.mobile.recipe.json \
135
- ~/my-recipes/recipes/my-perps/performance.mobile.recipe.json
136
- ```
137
-
138
- ### 3. Edit the nodes to your journey
139
-
140
- Open the copy and change what you measure while keeping the measured-flow shape.
141
- Retarget `open-market-detail` to your market and add one extra measured step —
142
- here, reading live orders on the detail screen:
143
-
144
- ```jsonc
145
- "open-market-detail": {
146
- "action": "ui.navigate",
147
- "page": "perps-market",
148
- "market": "ETH", // was BTC
149
- "intent": "Open the ETH Perps market detail screen",
150
- "next": "read-orders" // was "end"
151
- },
152
- "read-orders": { // your extra measured step
153
- "action": "metamask.perps.read_orders",
154
- "market": "ETH",
155
- "intent": "Read live ETH orders on the market detail screen",
156
- "next": "end"
157
- }
158
- ```
159
-
160
- The canonical recipe keeps its nodes inline — a clean measured baseline. For
161
- bigger journeys you can extract repeated setup steps into a personal `flows/`
162
- segment and `call` it. For example, define an unlock + open-Perps-list segment
163
- in `~/my-recipes/flows/mydev.flows.json`:
24
+ `library.json`:
164
25
 
165
26
  ```json
166
27
  {
167
- "schema_version": 1, "kind": "recipe-flow-catalog", "owner": "mydev",
168
- "flows": {
169
- "mydev.open_perps_setup": {
170
- "version": 1,
171
- "description": "Unlock the wallet and open the Perps market list.",
172
- "workflow": {
173
- "entry": "ensure-unlocked",
174
- "nodes": {
175
- "ensure-unlocked": {
176
- "action": "metamask.wallet.ensure_unlocked",
177
- "intent": "Unlock the wallet before the Perps journey",
178
- "next": "open-perps-list"
179
- },
180
- "open-perps-list": {
181
- "action": "ui.navigate",
182
- "page": "perps",
183
- "intent": "Open the Perps market list screen",
184
- "next": "done"
185
- },
186
- "done": { "action": "end", "status": "pass" }
187
- }
188
- }
189
- }
190
- }
28
+ "kind": "recipe-library",
29
+ "schema_version": 1,
30
+ "name": "wallet-team",
31
+ "owner": "wallet-team"
191
32
  }
192
33
  ```
193
34
 
194
- Then replace the two inline setup nodes in your recipe with a single `call` node:
35
+ ## Enable a team library
195
36
 
196
- ```jsonc
197
- "setup": {
198
- "action": "call",
199
- "ref": "mydev.open_perps_setup",
200
- "intent": "Run the personal Perps setup segment (unlock + open list)",
201
- "next": "read-positions"
202
- }
37
+ ```bash
38
+ export RECIPE_LIBRARY_PATH="wallet=$HOME/shared-library/wallet-team"
39
+ mm-harness flows
40
+ mm-harness run onboarding.smoke --plan
41
+ mm-harness run onboarding.smoke --artifacts-dir temp/onboarding-proof
203
42
  ```
204
43
 
205
- The segment validates via `--plan` the plan step verifies the `call` ref
206
- resolves from the library. Keep flow segment actions within the mobile action
207
- surface: the flow catalog format has no `platform`/`adapter` dimension today,
208
- so a flow using a core-only action (e.g. `command`) will pass `--plan` on mobile
209
- but fail at live-run time with "No adapter registered for flow action X". There
210
- is no plan-time cross-adapter enforcement; that gap would require an `adapters`
211
- field on flow catalog entries — not yet in the protocol.
44
+ Use `--library wallet=/path/to/library` for a one-command override. Without an
45
+ explicit library, the personal library is read from
46
+ `$FARMSLOT_HOME/recipe-library` (default `~/.farmslot/recipe-library`).
212
47
 
213
- ### 4. Run it and read the timings
48
+ Resolution order is recipe-local, explicit/personal/team, then bundled MetaMask.
49
+ The first matching flow wins. Runs print provenance and save resolved definitions
50
+ in `resolved-flows.json`, so shadowing is reviewable.
214
51
 
215
- Validate statically **by name** first — `run` probes each library source's
216
- `recipes/` directory in precedence order (personal → team → canonical), so
217
- `my-perps.performance` resolves from
218
- `~/my-recipes/recipes/my-perps/performance.mobile.recipe.json` without you
219
- spelling out the path:
52
+ ## Promote useful behavior
220
53
 
221
54
  ```bash
222
- # Static validation by NAME — resolves from the personal library via --library.
223
- mm-harness run my-perps.performance \
224
- --library mydev=~/my-recipes --plan --adapter mobile
225
-
226
- # Zero-flag personal-library: when ~/my-recipes is placed at
227
- # $FARMSLOT_HOME/recipe-library (default ~/.farmslot/recipe-library), the runner
228
- # discovers it automatically and run-by-name works without --library:
229
- mm-harness run my-perps.performance --plan --adapter mobile
230
-
231
- # Pinned live run — same device, healing OFF, so durations are comparable.
232
- mm-harness run my-perps.performance \
233
- --library mydev=~/my-recipes \
234
- --adapter mobile --device <serial> --heal off --artifacts-dir artifacts
235
-
236
- # Canonical start-state variants — same installed app, no rebuild.
237
- mm-harness run app.lifecycle.android-smoke \
238
- --adapter mobile --device <serial> --heal off --artifacts-dir artifacts/lifecycle-smoke
239
- mm-harness run perps.performance.warm-start \
240
- --adapter mobile --device <serial> --heal off --artifacts-dir artifacts/warm
241
- mm-harness run perps.performance.background-resume \
242
- --adapter mobile --device <serial> --heal off --artifacts-dir artifacts/background
243
- mm-harness run perps.performance.cold-start \
244
- --adapter mobile --device <serial> --heal off --artifacts-dir artifacts/cold
245
-
246
- # Per-node durations to diff across runs (trace.json is an array of entries, or
247
- # { metadata, entries: [...] }; each entry carries nodeId + durationMs):
248
- node -e 'const t=require("./artifacts/trace.json"); \
249
- for (const e of Array.isArray(t)?t:t.entries) console.log(e.nodeId, e.durationMs)'
55
+ mm-harness flows promote --from recipe.json --flow wallet.ensure_ready --run artifacts
250
56
  ```
251
57
 
252
- A miss with `--library` names the sources that were searched, so you can tell at a
253
- glance whether a typo or a missing library entry caused the failure.
254
-
255
- Run `app.lifecycle.android-smoke` first when validating a new Android slot; it
256
- isolates lifecycle control from wallet setup and Perps navigation. The start-state
257
- variants use the standard outer `app.lifecycle` action. Every
258
- variant begins with `app.status` so `trace.json` records an idempotent start
259
- marker before lifecycle setup and Perps timing nodes. Android background resume
260
- sends HOME, then relaunches through the Expo dev-client deep link. Cold start
261
- force-stops the installed package, then launches the same build through the deep
262
- link.
263
-
264
- ### The measured-flow pattern
58
+ Promotion requires a description. `ensure_*` flows require a machine-checkable
59
+ postcondition. A passing run stamps verification provenance.
265
60
 
266
- Five rules keep timings meaningful and diffable:
61
+ ## Keep libraries durable
267
62
 
268
- 1. **Pin the run** `--device <serial> --heal off`. Healing retries hide the
269
- regressions you are trying to measure.
270
- 2. **One node per user-visible step** a node's `duration` is only a signal when
271
- it maps to a single thing the user sees.
272
- 3. **Stable, human-meaningful node keys** operators diff node keys across runs;
273
- renaming `open-market-detail` breaks every historical comparison.
274
- 4. **No destructive side effects** — a measured flow should be repeatable. The
275
- canonical recipe stops at read + navigate; add `place_order`/`close` only in a
276
- personal copy when you deliberately want to measure the trade path.
277
- 5. **Read timings from `trace.json`, not the console** — the trace is the durable
278
- per-node record; the console is for humans watching the run.
279
-
280
- ### Shadowing, in practice
281
-
282
- Because `--library` sources resolve `call` refs before the canonical `metamask`
283
- library, a personal flow named like a canonical one shadows it — your history is
284
- the point. You can watch this happen on mobile with the segment recipe from the
285
- walkthrough above:
286
-
287
- ```bash
288
- # A mobile recipe with "action": "call", "ref": "mydev.open_perps_setup"
289
- # fails without the library source…
290
- mm-harness run my-perps-with-segment --plan --adapter mobile
291
- # → workflow.unresolved_call_ref
292
-
293
- # …and resolves once the personal library is on the path:
294
- mm-harness run my-perps-with-segment --plan --adapter mobile \
295
- --library "mydev=~/my-recipes"
296
- # → plan pass
297
- ```
63
+ - Parameterize before adding another name.
64
+ - Keep setup idempotent and prove postconditions.
65
+ - Keep secrets and wallet material out of libraries.
66
+ - Review shared libraries like code.
67
+ - Re-run their recipes when the product changes; stale provenance is surfaced.
68
+ - Keep generic graph or UI mechanics in Recipe Protocol, not a team library.
298
69
 
299
- That resolution unresolved without the source, `pass` with it — is what the
300
- `perps.performance-recipe` contract test asserts, alongside the canonical recipe
301
- resolving by name and the personal mobile copy planning by path and basename.
70
+ The bundled examples `runner.smoke`, `wallet.smoke`, and `perps.smoke` show the
71
+ same structure at increasing product specificity.
package/library/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Recipe library
2
2
 
3
+ - An **action** performs one typed operation.
4
+ - A **flow** packages a reusable parameterized sequence of actions.
5
+ - A **recipe** is a complete proof that may call actions and flows.
6
+
3
7
  - `actions/<adapter>/<group>/<name>.mjs` — executable action modules.
4
8
  **Importing an action module RUNS it**: each ends with `runAdapter(main)` at top
5
9
  level, which reads the live-adapter input path from the environment and executes.
@@ -446,7 +446,7 @@
446
446
  },
447
447
  "account": {
448
448
  "type": "string",
449
- "description": "EVM address to read positions for; defaults to MM_TEST_ACCOUNT_ADDRESS."
449
+ "description": "EVM address to read positions for; defaults to the canonical wallet fixture account."
450
450
  },
451
451
  "timeout_ms": {
452
452
  "type": "number"
@@ -523,7 +523,7 @@
523
523
  },
524
524
  "account": {
525
525
  "type": "string",
526
- "description": "EVM address to read orders for; defaults to MM_TEST_ACCOUNT_ADDRESS."
526
+ "description": "EVM address to read orders for; defaults to the canonical wallet fixture account."
527
527
  },
528
528
  "timeout_ms": {
529
529
  "type": "number"
@@ -558,7 +558,7 @@
558
558
  },
559
559
  "account": {
560
560
  "type": "string",
561
- "description": "EVM address to read account state for; defaults to MM_TEST_ACCOUNT_ADDRESS."
561
+ "description": "EVM address to read account state for; defaults to the canonical wallet fixture account."
562
562
  },
563
563
  "timeout_ms": {
564
564
  "type": "number"
@@ -653,7 +653,7 @@
653
653
  },
654
654
  "account": {
655
655
  "type": "string",
656
- "description": "EVM address to trade for; defaults to MM_TEST_ACCOUNT_ADDRESS."
656
+ "description": "EVM address to trade for; defaults to the canonical wallet fixture account."
657
657
  },
658
658
  "timeout_ms": {
659
659
  "type": "number"
@@ -748,7 +748,7 @@
748
748
  },
749
749
  "account": {
750
750
  "type": "string",
751
- "description": "EVM address to close for; defaults to MM_TEST_ACCOUNT_ADDRESS."
751
+ "description": "EVM address to close for; defaults to the canonical wallet fixture account."
752
752
  },
753
753
  "timeout_ms": {
754
754
  "type": "number"
@@ -837,7 +837,7 @@
837
837
  },
838
838
  "account": {
839
839
  "type": "string",
840
- "description": "EVM address to read for; defaults to MM_TEST_ACCOUNT_ADDRESS."
840
+ "description": "EVM address to read for; defaults to the canonical wallet fixture account."
841
841
  },
842
842
  "timeout_ms": {
843
843
  "type": "number"
@@ -937,7 +937,7 @@
937
937
  },
938
938
  "account": {
939
939
  "type": "string",
940
- "description": "EVM address to trade for; defaults to MM_TEST_ACCOUNT_ADDRESS."
940
+ "description": "EVM address to trade for; defaults to the canonical wallet fixture account."
941
941
  },
942
942
  "timeout_ms": {
943
943
  "type": "number"
@@ -0,0 +1,27 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask Core runner smoke",
4
+ "description": "Proves the headless Core runner resolves the checkout, executes generic actions, and writes a valid artifact package.",
5
+ "validate": {
6
+ "workflow": {
7
+ "entry": "status",
8
+ "nodes": {
9
+ "status": {
10
+ "action": "app.status",
11
+ "next": "package",
12
+ "intent": "Resolve the Core checkout and report headless readiness"
13
+ },
14
+ "package": {
15
+ "action": "assert_file",
16
+ "path": "package.json",
17
+ "next": "done",
18
+ "intent": "Prove generic project-file assertions work in Core"
19
+ },
20
+ "done": {
21
+ "action": "end",
22
+ "status": "pass"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask Extension wallet smoke",
4
+ "description": "Fixture-backed proof that the Extension wallet is reachable, unlocked, readable, and visually capturable without depending on a product feature domain.",
5
+ "validate": {
6
+ "workflow": {
7
+ "entry": "status",
8
+ "nodes": {
9
+ "status": {
10
+ "action": "app.status",
11
+ "next": "fixture",
12
+ "intent": "Confirm the Extension runtime is reachable"
13
+ },
14
+ "fixture": {
15
+ "action": "metamask.wallet.fixture_status",
16
+ "next": "unlock",
17
+ "intent": "Confirm the checkout wallet fixture is ready"
18
+ },
19
+ "unlock": {
20
+ "action": "metamask.wallet.ensure_unlocked",
21
+ "next": "state",
22
+ "intent": "Ensure the fixture-backed wallet is unlocked"
23
+ },
24
+ "state": {
25
+ "action": "metamask.wallet.read_state",
26
+ "next": "screenshot",
27
+ "intent": "Read the current wallet state through the public adapter"
28
+ },
29
+ "screenshot": {
30
+ "action": "ui.screenshot",
31
+ "path": "screenshots/wallet-smoke.png",
32
+ "next": "done",
33
+ "intent": "Capture visual wallet evidence"
34
+ },
35
+ "done": {
36
+ "action": "end",
37
+ "status": "pass"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask Mobile wallet smoke",
4
+ "description": "Fixture-backed proof that the Mobile wallet is reachable, unlocked, readable, and visually capturable without depending on a product feature domain.",
5
+ "validate": {
6
+ "workflow": {
7
+ "entry": "status",
8
+ "nodes": {
9
+ "status": {
10
+ "action": "app.status",
11
+ "next": "fixture",
12
+ "intent": "Confirm the Mobile runtime is reachable"
13
+ },
14
+ "fixture": {
15
+ "action": "metamask.wallet.fixture_status",
16
+ "next": "unlock",
17
+ "intent": "Confirm the checkout wallet fixture is ready"
18
+ },
19
+ "unlock": {
20
+ "action": "metamask.wallet.ensure_unlocked",
21
+ "next": "state",
22
+ "intent": "Ensure the fixture-backed wallet is unlocked"
23
+ },
24
+ "state": {
25
+ "action": "metamask.wallet.read_state",
26
+ "next": "screenshot",
27
+ "intent": "Read the current wallet state through the public adapter"
28
+ },
29
+ "screenshot": {
30
+ "action": "ui.screenshot",
31
+ "path": "screenshots/wallet-smoke.png",
32
+ "next": "done",
33
+ "intent": "Capture visual wallet evidence"
34
+ },
35
+ "done": {
36
+ "action": "end",
37
+ "status": "pass"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.17.2",
3
+ "version": "0.17.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -11,6 +11,7 @@
11
11
  "prepack": "npm run build",
12
12
  "dev:link-farmslot": "node scripts/link-local-farmslot.mjs",
13
13
  "check": "node scripts/check.mjs",
14
+ "qa:human": "node scripts/validate-human-outcomes.mjs",
14
15
  "self-test": "bin/mm-harness self-test",
15
16
  "manifest:mobile": "bin/mm-harness actions --raw --adapter mobile --json",
16
17
  "manifest:extension": "bin/mm-harness actions --raw --adapter extension --json",
@@ -57,6 +58,7 @@
57
58
  "library",
58
59
  "scripts/completions.sh",
59
60
  "scripts/install-completions.sh",
61
+ "scripts/validate-human-outcomes.mjs",
60
62
  "!scripts/README.md",
61
63
  "docs",
62
64
  "README.md",
@@ -71,4 +73,4 @@
71
73
  "url": "https://github.com/MetaMask/experimental-metamask-harness/issues"
72
74
  },
73
75
  "homepage": "https://github.com/MetaMask/experimental-metamask-harness#readme"
74
- }
76
+ }
File without changes
File without changes