zeno-mobile-runner 0.1.8 → 0.2.1

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 (66) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/FEATURES.md +1 -1
  3. package/README.md +175 -238
  4. package/clients/kotlin/README.md +1 -1
  5. package/clients/kotlin/build.gradle.kts +1 -1
  6. package/clients/python/pyproject.toml +1 -1
  7. package/clients/rust/Cargo.lock +1 -1
  8. package/clients/rust/Cargo.toml +1 -1
  9. package/clients/typescript/package.json +1 -1
  10. package/docs/agent-discovery.md +10 -0
  11. package/docs/ai-agents.md +18 -0
  12. package/docs/benchmarking.md +39 -0
  13. package/docs/benchmarks/2026-06-09-android-workflow.md +73 -0
  14. package/docs/benchmarks/2026-06-09-android-workflow.results.jsonl +20 -0
  15. package/docs/benchmarks/2026-06-09-framework-baseline-status.md +32 -0
  16. package/docs/benchmarks/2026-06-09-ios-appium-comparison.md +115 -0
  17. package/docs/benchmarks/2026-06-09-ios-appium-comparison.results.jsonl +40 -0
  18. package/docs/benchmarks/2026-06-09-ios-demo.md +90 -0
  19. package/docs/benchmarks/2026-06-09-ios-demo.results.jsonl +20 -0
  20. package/docs/benchmarks/2026-06-09-ios-maestro-comparison.md +128 -0
  21. package/docs/benchmarks/2026-06-09-ios-maestro-comparison.results.jsonl +40 -0
  22. package/docs/benchmarks/2026-06-09-ios-workflow-comparison.md +143 -0
  23. package/docs/benchmarks/2026-06-09-ios-workflow-comparison.results.jsonl +40 -0
  24. package/docs/benchmarks/2026-06-09-ios-xctest-floor.md +106 -0
  25. package/docs/benchmarks/2026-06-09-ios-xctest-floor.results.jsonl +40 -0
  26. package/docs/benchmarks/README.md +36 -0
  27. package/docs/benchmarks/benchmark-lab-v1.json +155 -0
  28. package/docs/benchmarks/benchmark-lab-v1.md +95 -0
  29. package/docs/clients.md +16 -0
  30. package/docs/demo.md +36 -1
  31. package/docs/frameworks.md +10 -0
  32. package/docs/npm.md +44 -2
  33. package/docs/protocol-fixtures/core-session.responses.jsonl +1 -1
  34. package/docs/protocol.md +10 -10
  35. package/docs/scenario-authoring.md +15 -0
  36. package/docs/trace-privacy.md +9 -0
  37. package/docs/troubleshooting.md +6 -0
  38. package/examples/android-workflow.json +79 -0
  39. package/examples/ios-dev-client-open-link.json +24 -13
  40. package/examples/ios-dev-client-route-snapshot.json +33 -8
  41. package/examples/ios-shim-workflow.json +79 -0
  42. package/examples/react-native-expo-workflow.json +75 -0
  43. package/npm/scenarios.mjs +15 -8
  44. package/npm/wizard.mjs +1 -1
  45. package/package.json +6 -1
  46. package/prebuilds/darwin-arm64/zmr +0 -0
  47. package/prebuilds/darwin-x64/zmr +0 -0
  48. package/prebuilds/linux-arm64/zmr +0 -0
  49. package/prebuilds/linux-x64/zmr +0 -0
  50. package/scripts/benchmark-lab.py +253 -0
  51. package/scripts/create-android-demo-app.sh +324 -29
  52. package/scripts/create-ios-demo-app.sh +174 -7
  53. package/scripts/create-react-native-expo-demo-app.sh +727 -0
  54. package/scripts/demo.sh +3 -0
  55. package/scripts/install-ios-shim.sh +2 -2
  56. package/shims/ios/ZMRShim.swift +10 -0
  57. package/shims/ios/ZMRShimUITestCase.swift +49 -1
  58. package/shims/ios/protocol.md +1 -0
  59. package/src/cli_import.zig +31 -15
  60. package/src/cli_trace.zig +38 -16
  61. package/src/cli_validate.zig +12 -6
  62. package/src/ios.zig +44 -11
  63. package/src/ios_shim.zig +36 -2
  64. package/src/main.zig +6 -0
  65. package/src/version.zig +1 -1
  66. package/viewer/app.js +23 -3
package/docs/ai-agents.md CHANGED
@@ -4,6 +4,24 @@ ZMR is built for external agents. The runner provides device state, typed
4
4
  actions, waits, assertions, trace explanation, and trace export; the agent
5
5
  decides the next step.
6
6
 
7
+ ```mermaid
8
+ sequenceDiagram
9
+ participant Agent as AI agent
10
+ participant ZMR
11
+ participant Device as Emulator / simulator
12
+ Agent->>ZMR: semantic_snapshot
13
+ ZMR->>Device: capture UI + screenshot
14
+ ZMR-->>Agent: roles, stable selectors, bounds
15
+ Agent->>ZMR: tap / type / swipe / open_link
16
+ ZMR->>Device: execute + settle
17
+ Agent->>ZMR: wait_visible / assert_visible
18
+ ZMR-->>Agent: typed result + trace events
19
+ Agent->>ZMR: trace_discover
20
+ ZMR-->>Agent: reviewable replay scenario
21
+ Agent->>ZMR: trace_export --redact
22
+ ZMR-->>Agent: .zmrtrace evidence bundle
23
+ ```
24
+
7
25
  ## Agent Setup Loop
8
26
 
9
27
  Start inside the app checkout:
@@ -4,6 +4,39 @@ ZMR benchmark output is intentionally simple: each run appends one JSON object
4
4
  to `results.jsonl`, and `zmr report` turns that directory into local HTML and
5
5
  optional JUnit XML artifacts.
6
6
 
7
+ ## Public Evidence
8
+
9
+ Public-safe benchmark evidence lives in [docs/benchmarks](benchmarks/README.md).
10
+ The first committed pack is
11
+ [2026-06-09 iOS simulator demo](benchmarks/2026-06-09-ios-demo.md): 20 repeated
12
+ runs of the generated iOS smoke scenario with a 100% pass rate. It is a
13
+ single-tool reliability benchmark, not a competitive speed claim.
14
+
15
+ The first baseline comparison is documented in
16
+ [docs/benchmarks](benchmarks/README.md): 20 ZMR runs and 20 baseline runner
17
+ runs against the same generated iOS demo app.
18
+
19
+ Additional public-safe packs in that directory include a second baseline
20
+ comparison and a native shim floor. The floor is not a product comparison; it
21
+ shows the warmed platform path ZMR can approach after runner and trace overhead
22
+ are reduced.
23
+
24
+ A richer iOS workflow pack is also committed there: 20 ZMR rows and 20 baseline
25
+ runner rows against the same generated app build, covering profile entry,
26
+ catalog item selection, save, review, and final-state assertion.
27
+
28
+ Benchmark Lab v1 is the next public evidence layer. It defines framework
29
+ fixtures, timing modes, runner-adapter labels, and claim rules in a manifest
30
+ that can be validated or rendered with `zmr-benchmark-lab`.
31
+
32
+ The generated Android workflow now has its first 20-run evidence pack in
33
+ [docs/benchmarks](benchmarks/README.md), using the platform UIAutomator path
34
+ without the optional Android instrumentation shim.
35
+
36
+ A generated React Native/Expo fixture is now available for the next evidence
37
+ slice. It includes stable `testID` values, accessibility labels, deep-link
38
+ setup, and Android/iOS ZMR workflow scenarios, but no public timing rows yet.
39
+
7
40
  ## Single Tool Benchmark
8
41
 
9
42
  ```bash
@@ -70,6 +103,10 @@ For `--runs 1`, the script exports normal and redacted `.zmrtrace` bundles.
70
103
  For `--runs > 1`, the pilot wrappers and generated app reliability scripts
71
104
  write benchmark directories with HTML and JUnit reports.
72
105
 
106
+ Apps scaffolded by `zmr-wizard` get matching package scripts, so app-local
107
+ reliability gates run as `bun run zmr:android:reliability` and
108
+ `bun run zmr:ios:reliability` (or the npm equivalents).
109
+
73
110
  The iOS pilot wrapper supports the same repeated-run gates:
74
111
 
75
112
  ```bash
@@ -138,6 +175,8 @@ Benchmark reports include:
138
175
 
139
176
  Before making public performance claims, run the same scenario repeatedly on a clean emulator image and include the raw `results.jsonl` plus the redacted trace bundle for any failure.
140
177
 
178
+ ![ZMR HTML trace report showing the trace summary and per-event timeline](assets/report-html.png)
179
+
141
180
  ## Compare Against A Baseline
142
181
 
143
182
  Use `zmr-compare-benchmarks` when a private app repo has benchmark rows from
@@ -0,0 +1,73 @@
1
+ # 2026-06-09 Android Emulator Workflow
2
+
3
+ This evidence pack records 20 repeated ZMR runs of the generated public Android
4
+ workflow demo app. The flow launches the app, fills a profile form, scrolls the
5
+ catalog, opens an item detail page, saves the item, reviews the order, and
6
+ asserts the final state.
7
+
8
+ This is a single-tool reliability and timing pack, not a comparison against
9
+ another runner. Treat it as reproducible evidence for this app, host, emulator,
10
+ app build, and workflow shape.
11
+
12
+ ## Result
13
+
14
+ | Tool | Runs | Pass rate | Failures | Mean duration | p95 duration |
15
+ | --- | ---: | ---: | ---: | ---: | ---: |
16
+ | ZMR | 20 | 100.00% | 0 | 44134 ms | 46385 ms |
17
+
18
+ The fastest run was 38627 ms and the slowest run was 49875 ms. The later rows
19
+ clustered around 43 seconds, which points to Android UIAutomator snapshot and
20
+ scroll execution as the next optimization target for this fixture.
21
+
22
+ ## Environment
23
+
24
+ | Field | Value |
25
+ | --- | --- |
26
+ | ZMR runner | `0.1.8` |
27
+ | ZMR protocol | `2026-04-28` |
28
+ | Host OS | macOS 26.6, arm64 |
29
+ | Android emulator | 36.4.10.0 |
30
+ | ADB | 1.0.41, platform-tools 37.0.0 |
31
+ | Android platform | Android 15, API 35, arm64-v8a |
32
+ | Emulator viewport | 720 x 1280, 320 dpi |
33
+ | App id | `com.example.mobiletest` |
34
+ | App build label | `generated-android-workflow-demo-20260609` |
35
+ | Demo app source | Generated by `scripts/create-android-demo-app.sh` |
36
+
37
+ Before collection, the emulator was booted fresh, the app was reinstalled, the
38
+ screen was unlocked, and Android window, transition, and animator duration
39
+ scales were set to `0`.
40
+
41
+ ## Command
42
+
43
+ ```bash
44
+ ZMR_BIN="$PWD/zig-out/bin/zmr" scripts/benchmark.sh \
45
+ --zmr examples/android-workflow.json \
46
+ --platform android \
47
+ --device emulator-5554 \
48
+ --app-id com.example.mobiletest \
49
+ --app-build generated-android-workflow-demo-20260609 \
50
+ --runs 20 \
51
+ --trace-root traces/public-benchmarks/20260609-android-workflow/zmr \
52
+ --results traces/public-benchmarks/20260609-android-workflow/results.jsonl \
53
+ --replace \
54
+ --min-pass-rate 100 \
55
+ --max-failures 0
56
+ ```
57
+
58
+ The ZMR scenario is committed as
59
+ [`examples/android-workflow.json`](../../examples/android-workflow.json).
60
+
61
+ ## Rows
62
+
63
+ The sanitized result rows are committed in
64
+ [2026-06-09-android-workflow.results.jsonl](2026-06-09-android-workflow.results.jsonl).
65
+
66
+ Raw local trace and runner logs are not committed because they can include local
67
+ absolute paths.
68
+
69
+ ## Scope
70
+
71
+ This benchmark uses the platform UIAutomator path without the optional Android
72
+ instrumentation shim. It does not compare cloud execution, React Native, Expo,
73
+ Flutter, Appium, Maestro, Detox, or Android instrumentation-runner baselines.
@@ -0,0 +1,20 @@
1
+ {"tool":"zmr","run":1,"status":"ok","durationMs":49875,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-1","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
2
+ {"tool":"zmr","run":2,"status":"ok","durationMs":45169,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-2","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
3
+ {"tool":"zmr","run":3,"status":"ok","durationMs":46093,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-3","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
4
+ {"tool":"zmr","run":4,"status":"ok","durationMs":44695,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-4","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
5
+ {"tool":"zmr","run":5,"status":"ok","durationMs":44028,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-5","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
6
+ {"tool":"zmr","run":6,"status":"ok","durationMs":44821,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-6","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
7
+ {"tool":"zmr","run":7,"status":"ok","durationMs":46385,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-7","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
8
+ {"tool":"zmr","run":8,"status":"ok","durationMs":45751,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-8","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
9
+ {"tool":"zmr","run":9,"status":"ok","durationMs":38627,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-9","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
10
+ {"tool":"zmr","run":10,"status":"ok","durationMs":42599,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-10","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
11
+ {"tool":"zmr","run":11,"status":"ok","durationMs":42968,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-11","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
12
+ {"tool":"zmr","run":12,"status":"ok","durationMs":43299,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-12","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
13
+ {"tool":"zmr","run":13,"status":"ok","durationMs":43684,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-13","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
14
+ {"tool":"zmr","run":14,"status":"ok","durationMs":43056,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-14","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
15
+ {"tool":"zmr","run":15,"status":"ok","durationMs":43418,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-15","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
16
+ {"tool":"zmr","run":16,"status":"ok","durationMs":43267,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-16","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
17
+ {"tool":"zmr","run":17,"status":"ok","durationMs":43780,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-17","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
18
+ {"tool":"zmr","run":18,"status":"ok","durationMs":43371,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-18","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
19
+ {"tool":"zmr","run":19,"status":"ok","durationMs":43095,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-19","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
20
+ {"tool":"zmr","run":20,"status":"ok","durationMs":44693,"traceDir":"traces/public-benchmarks/20260609-android-workflow/zmr/zmr-20","platform":"android","device":"emulator-5554","appId":"com.example.mobiletest","scenario":"examples/android-workflow.json","appBuild":"generated-android-workflow-demo-20260609","traceStatus":"passed"}
@@ -0,0 +1,32 @@
1
+ # 2026-06-09 Framework Baseline Status
2
+
3
+ This note tracks the requested baseline coverage beyond the committed iOS demo
4
+ comparisons.
5
+
6
+ ## Completed
7
+
8
+ | Baseline | Status | Evidence |
9
+ | --- | --- | --- |
10
+ | Maestro | Completed | [iOS ZMR vs Maestro comparison](2026-06-09-ios-maestro-comparison.md) |
11
+ | Appium | Completed | [iOS ZMR vs Appium comparison](2026-06-09-ios-appium-comparison.md) |
12
+ | XCTest floor | Completed | [iOS XCTest shim floor](2026-06-09-ios-xctest-floor.md) |
13
+
14
+ ## Not Yet Fair To Publish
15
+
16
+ | Baseline | Why it needs a fixture first | Next evidence pack |
17
+ | --- | --- | --- |
18
+ | Detox | The CLI requires a project-local `detox` install and a React Native app with Detox configuration, native iOS/Android build targets, and a test file. Running it against the generated Swift demo would not be representative. | React Native fixture with the same launch, deep link, assertion, and warm-suite/cold-command modes. |
19
+ | Flutter | The local machine does not have the Flutter CLI installed, and ZMR should not claim Flutter widget-tree-driver coverage. | Flutter fixture using platform-level labels/deep links plus either Flutter `integration_test` or an external runner baseline. |
20
+ | Espresso | No Android emulator is currently attached in this workspace. Espresso should compare against an Android fixture with an instrumentation target rather than an iOS-only demo. | Android generated demo with ZMR, direct Espresso instrumentation, and Appium UIAutomator2 rows. |
21
+
22
+ ## Speed Work Opened By This Pass
23
+
24
+ The XCTest floor showed that ZMR can be made faster. The first fix from this
25
+ pass skips the expensive iOS system-open alert probe for custom URL schemes and
26
+ keeps it for `http://` and `https://` links. On the generated iOS demo smoke
27
+ flow, the shim-backed ZMR mean dropped to `2007 ms` while the direct warmed
28
+ XCTest shim floor measured `1004 ms`.
29
+
30
+ The next speed target is a warm-suite mode where one ZMR process executes many
31
+ iterations in a single device session, avoiding repeated CLI startup and trace
32
+ setup for benchmark loops.
@@ -0,0 +1,115 @@
1
+ # 2026-06-09 iOS Simulator ZMR vs Appium Comparison
2
+
3
+ This evidence pack compares ZMR with Appium on the generated public iOS demo
4
+ app. It is a command-level benchmark: each row starts one local runner command,
5
+ executes the same smoke flow on the same booted simulator, and records command
6
+ duration.
7
+
8
+ This is not a universal claim about either project. Treat it as reproducible
9
+ evidence for this app, host, simulator, and flow shape.
10
+
11
+ ## Result
12
+
13
+ | Tool | Runs | Pass rate | Failures | Mean duration | p95 duration |
14
+ | --- | ---: | ---: | ---: | ---: | ---: |
15
+ | ZMR | 20 | 100.00% | 0 | 2315 ms | 2339 ms |
16
+ | Appium | 20 | 100.00% | 0 | 3837 ms | 3883 ms |
17
+
18
+ For this run, ZMR was 1.66x faster on mean duration and 1.66x faster on p95
19
+ duration.
20
+
21
+ ## Environment
22
+
23
+ | Field | Value |
24
+ | --- | --- |
25
+ | ZMR runner | `0.1.8` |
26
+ | ZMR protocol | `2026-04-28` |
27
+ | Appium | `3.5.0` |
28
+ | Appium XCUITest driver | `11.10.0` |
29
+ | Host OS | macOS 26.6, arm64 |
30
+ | Xcode | 26.5, build 17F42 |
31
+ | Simulator | Booted iOS 26.5 simulator, `zmr-iPhone` |
32
+ | App id | `com.example.mobiletest` |
33
+ | App build label | `generated-ios-demo-20260609` |
34
+ | Demo app source | Generated by `scripts/create-ios-demo-app.sh` |
35
+
36
+ ## ZMR Command
37
+
38
+ ```bash
39
+ ZMR_BIN="$PWD/zig-out/bin/zmr" scripts/benchmark.sh \
40
+ --zmr examples/ios-smoke.json \
41
+ --platform ios \
42
+ --ios-device-type simulator \
43
+ --device booted \
44
+ --app-id com.example.mobiletest \
45
+ --xcrun xcrun \
46
+ --app-build generated-ios-demo-20260609 \
47
+ --runs 20 \
48
+ --trace-root traces/public-benchmarks/20260609-ios-appium-comparison/zmr \
49
+ --results traces/public-benchmarks/20260609-ios-appium-comparison/results.jsonl \
50
+ --replace \
51
+ --min-pass-rate 100 \
52
+ --max-failures 0
53
+ ```
54
+
55
+ The ZMR scenario launches the app, opens `exampleapp:///e2e-auth?probe=1`, and
56
+ captures a snapshot.
57
+
58
+ ## Appium Command
59
+
60
+ The Appium server was started with a temp Appium home:
61
+
62
+ ```bash
63
+ APPIUM_HOME=/tmp/zmr-appium-home-20260609 npx --yes appium@latest --port 4723 --log-level error
64
+ ```
65
+
66
+ The XCUITest driver was installed in that temp home:
67
+
68
+ ```bash
69
+ APPIUM_HOME=/tmp/zmr-appium-home-20260609 npx --yes appium@latest driver install xcuitest
70
+ ```
71
+
72
+ Each measured Appium row created a fresh XCUITest WebDriver session against the
73
+ same bundle id, opened the same deep link with `simctl openurl`, read page
74
+ source, asserted `Deep link opened`, and deleted the session.
75
+
76
+ ```bash
77
+ scripts/benchmark-command.sh \
78
+ --tool appium \
79
+ --platform ios \
80
+ --device booted \
81
+ --app-id com.example.mobiletest \
82
+ --scenario examples/ios-smoke.json \
83
+ --app-build generated-ios-demo-20260609 \
84
+ --runs 20 \
85
+ --trace-root traces/public-benchmarks/20260609-ios-appium-comparison/appium \
86
+ --results traces/public-benchmarks/20260609-ios-appium-comparison/results.jsonl \
87
+ -- node -e '<create session, open deep link, assert page source, delete session>'
88
+ ```
89
+
90
+ ## Comparison Report
91
+
92
+ ```text
93
+ # Benchmark Comparison
94
+
95
+ | Tool | Runs | Pass rate | Failures | Mean ms | P95 ms |
96
+ | --- | ---: | ---: | ---: | ---: | ---: |
97
+ | zmr | 20 | 100.00% | 0 | 2315 | 2339 |
98
+ | appium | 20 | 100.00% | 0 | 3837 | 3883 |
99
+
100
+ - Mean speedup: 1.66x (-39.7% candidate vs baseline)
101
+ - P95 speedup: 1.66x (-39.8% candidate vs baseline)
102
+ - Same benchmark context: yes
103
+ ```
104
+
105
+ The sanitized result rows are committed in
106
+ [2026-06-09-ios-appium-comparison.results.jsonl](2026-06-09-ios-appium-comparison.results.jsonl).
107
+
108
+ Raw local trace and runner logs are not committed because they can include local
109
+ absolute paths.
110
+
111
+ ## Scope
112
+
113
+ This benchmark compares local command surfaces under repeated execution. It
114
+ does not compare cloud execution, long multi-screen flows, Detox, Flutter,
115
+ Espresso, XCTest-only app tests, or app-specific selectors.
@@ -0,0 +1,40 @@
1
+ {"tool":"zmr","run":1,"status":"ok","durationMs":2327,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-1","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
2
+ {"tool":"zmr","run":2,"status":"ok","durationMs":2326,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-2","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
3
+ {"tool":"zmr","run":3,"status":"ok","durationMs":2312,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-3","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
4
+ {"tool":"zmr","run":4,"status":"ok","durationMs":2305,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-4","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
5
+ {"tool":"zmr","run":5,"status":"ok","durationMs":2305,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-5","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
6
+ {"tool":"zmr","run":6,"status":"ok","durationMs":2295,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-6","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
7
+ {"tool":"zmr","run":7,"status":"ok","durationMs":2339,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-7","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
8
+ {"tool":"zmr","run":8,"status":"ok","durationMs":2289,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-8","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
9
+ {"tool":"zmr","run":9,"status":"ok","durationMs":2292,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-9","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
10
+ {"tool":"zmr","run":10,"status":"ok","durationMs":2320,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-10","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
11
+ {"tool":"zmr","run":11,"status":"ok","durationMs":2332,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-11","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
12
+ {"tool":"zmr","run":12,"status":"ok","durationMs":2333,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-12","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
13
+ {"tool":"zmr","run":13,"status":"ok","durationMs":2316,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-13","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
14
+ {"tool":"zmr","run":14,"status":"ok","durationMs":2291,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-14","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
15
+ {"tool":"zmr","run":15,"status":"ok","durationMs":2342,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-15","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
16
+ {"tool":"zmr","run":16,"status":"ok","durationMs":2308,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-16","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
17
+ {"tool":"zmr","run":17,"status":"ok","durationMs":2298,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-17","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
18
+ {"tool":"zmr","run":18,"status":"ok","durationMs":2297,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-18","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
19
+ {"tool":"zmr","run":19,"status":"ok","durationMs":2339,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-19","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
20
+ {"tool":"zmr","run":20,"status":"ok","durationMs":2329,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/zmr/zmr-20","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609","traceStatus":"passed"}
21
+ {"tool":"appium","run":1,"status":"ok","durationMs":3825,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-1","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
22
+ {"tool":"appium","run":2,"status":"ok","durationMs":3779,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-2","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
23
+ {"tool":"appium","run":3,"status":"ok","durationMs":3773,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-3","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
24
+ {"tool":"appium","run":4,"status":"ok","durationMs":3776,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-4","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
25
+ {"tool":"appium","run":5,"status":"ok","durationMs":3790,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-5","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
26
+ {"tool":"appium","run":6,"status":"ok","durationMs":3797,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-6","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
27
+ {"tool":"appium","run":7,"status":"ok","durationMs":3747,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-7","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
28
+ {"tool":"appium","run":8,"status":"ok","durationMs":3799,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-8","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
29
+ {"tool":"appium","run":9,"status":"ok","durationMs":4022,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-9","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
30
+ {"tool":"appium","run":10,"status":"ok","durationMs":3871,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-10","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
31
+ {"tool":"appium","run":11,"status":"ok","durationMs":3864,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-11","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
32
+ {"tool":"appium","run":12,"status":"ok","durationMs":3882,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-12","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
33
+ {"tool":"appium","run":13,"status":"ok","durationMs":3858,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-13","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
34
+ {"tool":"appium","run":14,"status":"ok","durationMs":3883,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-14","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
35
+ {"tool":"appium","run":15,"status":"ok","durationMs":3852,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-15","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
36
+ {"tool":"appium","run":16,"status":"ok","durationMs":3879,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-16","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
37
+ {"tool":"appium","run":17,"status":"ok","durationMs":3871,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-17","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
38
+ {"tool":"appium","run":18,"status":"ok","durationMs":3825,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-18","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
39
+ {"tool":"appium","run":19,"status":"ok","durationMs":3825,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-19","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
40
+ {"tool":"appium","run":20,"status":"ok","durationMs":3818,"traceDir":"traces/public-benchmarks/20260609-ios-appium-comparison/appium/appium-20","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","appBuild":"generated-ios-demo-20260609"}
@@ -0,0 +1,90 @@
1
+ # 2026-06-09 iOS Simulator Demo Benchmark
2
+
3
+ This evidence pack records a repeat-run reliability benchmark for the public
4
+ ZMR iOS demo app. It is a single-tool benchmark, not a comparison against
5
+ Maestro, Appium, Detox, XCTest, or another runner.
6
+
7
+ ## Result
8
+
9
+ | Metric | Value |
10
+ | --- | --- |
11
+ | Scenario | `examples/ios-smoke.json` |
12
+ | Platform | iOS simulator |
13
+ | Runs | 20 |
14
+ | Passed | 20 |
15
+ | Failed | 0 |
16
+ | Pass rate | 100.00% |
17
+ | Mean duration | 4192 ms |
18
+ | p95 duration | 5409 ms |
19
+ | Min duration | 3065 ms |
20
+ | Max duration | 6395 ms |
21
+
22
+ ## Environment
23
+
24
+ | Field | Value |
25
+ | --- | --- |
26
+ | ZMR runner | `0.1.8` |
27
+ | Protocol | `2026-04-28` |
28
+ | Host OS | macOS 26.6, arm64 |
29
+ | Xcode | 26.5, build 17F42 |
30
+ | Simulator | Booted iOS 26.5 simulator, `zmr-iPhone` |
31
+ | App id | `com.example.mobiletest` |
32
+ | Demo app source | Generated by `scripts/create-ios-demo-app.sh` |
33
+
34
+ ## Command
35
+
36
+ ```bash
37
+ rm -rf traces/public-benchmarks/20260609-ios-demo /tmp/zmr-public-benchmark-ios-demo-20260609-plain
38
+
39
+ scripts/create-ios-demo-app.sh \
40
+ --out /tmp/zmr-public-benchmark-ios-demo-20260609-plain \
41
+ --name ZMRDemo \
42
+ --bundle-id com.example.mobiletest \
43
+ --deployment-target 16.0
44
+
45
+ xcodebuild \
46
+ -project /tmp/zmr-public-benchmark-ios-demo-20260609-plain/ios/ZMRDemo.xcodeproj \
47
+ -scheme ZMRDemo \
48
+ -destination 'generic/platform=iOS Simulator' \
49
+ -configuration Debug \
50
+ -derivedDataPath /tmp/zmr-public-benchmark-ios-demo-20260609-plain/DerivedData \
51
+ build
52
+
53
+ ZMR_BIN="$PWD/zig-out/bin/zmr" scripts/run-ios-pilot.sh \
54
+ --app-root /tmp/zmr-public-benchmark-ios-demo-20260609-plain \
55
+ --app-path /tmp/zmr-public-benchmark-ios-demo-20260609-plain/DerivedData/Build/Products/Debug-iphonesimulator/ZMRDemo.app \
56
+ --device booted \
57
+ --app-id com.example.mobiletest \
58
+ --xcrun xcrun \
59
+ --runs 20 \
60
+ --trace-root traces/public-benchmarks/20260609-ios-demo \
61
+ --min-pass-rate 100 \
62
+ --max-failures 0
63
+ ```
64
+
65
+ The local run wrote:
66
+
67
+ - `traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/results.jsonl`
68
+ - `traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/report.html`
69
+ - `traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/junit.xml`
70
+
71
+ Those raw artifacts are intentionally not committed because generated reports
72
+ and JUnit properties include absolute local paths. The sanitized result rows are
73
+ committed in
74
+ [2026-06-09-ios-demo.results.jsonl](2026-06-09-ios-demo.results.jsonl).
75
+
76
+ ## Scope
77
+
78
+ This run validates the public iOS simulator smoke path: install, launch, deep
79
+ link, snapshot, trace collection, benchmark gate, HTML report generation, and
80
+ JUnit report generation.
81
+
82
+ This run does not measure the app-local XCTest shim path. During collection, a
83
+ shim compatibility check found a generated wrapper portability issue in
84
+ one-shot mode: the wrapper used a `mktemp` template with `XXXXXX` before a
85
+ `.log` suffix, which is not portable on macOS. That generator bug was fixed
86
+ before this evidence pack was committed.
87
+
88
+ Do not use this evidence as a speed comparison against another mobile testing
89
+ framework. Baseline comparisons require equivalent candidate and baseline rows
90
+ from the same app build, device state, and scenario.
@@ -0,0 +1,20 @@
1
+ {"tool":"zmr","run":1,"status":"ok","durationMs":5409,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-1","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
2
+ {"tool":"zmr","run":2,"status":"ok","durationMs":3289,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-2","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
3
+ {"tool":"zmr","run":3,"status":"ok","durationMs":3319,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-3","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
4
+ {"tool":"zmr","run":4,"status":"ok","durationMs":3323,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-4","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
5
+ {"tool":"zmr","run":5,"status":"ok","durationMs":3562,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-5","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
6
+ {"tool":"zmr","run":6,"status":"ok","durationMs":4048,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-6","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
7
+ {"tool":"zmr","run":7,"status":"ok","durationMs":3606,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-7","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
8
+ {"tool":"zmr","run":8,"status":"ok","durationMs":3065,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-8","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
9
+ {"tool":"zmr","run":9,"status":"ok","durationMs":3692,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-9","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
10
+ {"tool":"zmr","run":10,"status":"ok","durationMs":3514,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-10","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
11
+ {"tool":"zmr","run":11,"status":"ok","durationMs":3702,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-11","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
12
+ {"tool":"zmr","run":12,"status":"ok","durationMs":5092,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-12","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
13
+ {"tool":"zmr","run":13,"status":"ok","durationMs":4929,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-13","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
14
+ {"tool":"zmr","run":14,"status":"ok","durationMs":4340,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-14","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
15
+ {"tool":"zmr","run":15,"status":"ok","durationMs":6395,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-15","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
16
+ {"tool":"zmr","run":16,"status":"ok","durationMs":5128,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-16","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
17
+ {"tool":"zmr","run":17,"status":"ok","durationMs":3955,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-17","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
18
+ {"tool":"zmr","run":18,"status":"ok","durationMs":4410,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-18","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
19
+ {"tool":"zmr","run":19,"status":"ok","durationMs":4634,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-19","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}
20
+ {"tool":"zmr","run":20,"status":"ok","durationMs":4425,"traceDir":"traces/public-benchmarks/20260609-ios-demo/ios-smoke-benchmark/zmr-20","platform":"ios","device":"booted","appId":"com.example.mobiletest","scenario":"examples/ios-smoke.json","traceStatus":"passed"}