mobile-debug-mcp 0.36.0 → 0.37.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 (171) hide show
  1. package/README.md +10 -0
  2. package/agent-plugin/.antigravity-plugin/plugin.json +1 -1
  3. package/agent-plugin/.claude-plugin/plugin.json +2 -2
  4. package/agent-plugin/.codex-plugin/plugin.json +1 -1
  5. package/agent-plugin/.cursor-plugin/plugin.json +2 -2
  6. package/agent-plugin/.mcp.json +1 -1
  7. package/agent-plugin/cursor/.cursor-plugin/plugin.json +2 -2
  8. package/agent-plugin/cursor/skills/mobile-debug-mcp/SKILL.md +10 -2
  9. package/agent-plugin/mcp.json +1 -1
  10. package/agent-plugin/mcp_config.json +1 -1
  11. package/agent-plugin/plugin.json +1 -1
  12. package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +10 -2
  13. package/dist/contracts/device-readiness.js +1 -0
  14. package/dist/interact/waits/ui-change-wait.js +9 -2
  15. package/dist/interact/waits/ui-wait.js +7 -3
  16. package/dist/manage/index.js +3 -0
  17. package/dist/observe/device-readiness.js +116 -0
  18. package/dist/observe/evidence.js +31 -0
  19. package/dist/observe/ios-trace/sessions.js +5 -3
  20. package/dist/observe/readiness-service.js +21 -9
  21. package/dist/observe/readiness.js +30 -0
  22. package/dist/observe/screenshot-encoding.js +4 -0
  23. package/dist/observe/snapshot-collection.js +7 -2
  24. package/dist/server/definitions/manage.js +3 -2
  25. package/dist/server/handlers/action-execution.js +23 -14
  26. package/dist/server/handlers/compact-interaction.js +106 -0
  27. package/dist/server/handlers/compact-state.js +47 -0
  28. package/dist/server/handlers/input.js +2 -0
  29. package/dist/server/handlers/interact.js +2 -0
  30. package/dist/server/handlers/interaction-diagnostics.js +62 -0
  31. package/dist/server/handlers/journey.js +18 -20
  32. package/dist/server/handlers/observe.js +2 -1
  33. package/dist/server/handlers/tool-handlers.js +9 -5
  34. package/dist/server/schemas/interaction-diagnostics.js +9 -0
  35. package/dist/server/tool-definitions.js +9 -4
  36. package/dist/server-core.js +5 -2
  37. package/dist/server.js +1 -1
  38. package/dist/system/android.js +19 -15
  39. package/dist/system/index.js +2 -1
  40. package/dist/utils/android/utils.js +7 -16
  41. package/dist/utils/app-installation.js +77 -0
  42. package/dist/utils/benchmark-metrics.js +43 -0
  43. package/dist/utils/exec.js +4 -0
  44. package/dist/utils/ios/utils.js +4 -11
  45. package/dist/utils/resolve-device.js +3 -2
  46. package/dist/utils/timing.js +3 -3
  47. package/docs/CHANGELOG.md +25 -0
  48. package/docs/benchmarks/README.md +1 -0
  49. package/docs/benchmarks/end-to-end-latency/README.md +98 -0
  50. package/docs/benchmarks/end-to-end-latency/android-snapshot-pair.json +6532 -0
  51. package/docs/benchmarks/end-to-end-latency/android-snapshot-pair.md +30 -0
  52. package/docs/benchmarks/end-to-end-latency/baseline-attempt-1.json +15901 -0
  53. package/docs/benchmarks/end-to-end-latency/baseline-attempt-1.md +14 -0
  54. package/docs/benchmarks/end-to-end-latency/baseline.json +233843 -0
  55. package/docs/benchmarks/end-to-end-latency/baseline.md +21 -0
  56. package/docs/benchmarks/end-to-end-latency/investigation.md +128 -0
  57. package/docs/benchmarks/end-to-end-latency/ios-smoke.json +84 -0
  58. package/docs/benchmarks/end-to-end-latency/ios-smoke.md +9 -0
  59. package/docs/benchmarks/end-to-end-latency/smoke.json +19601 -0
  60. package/docs/benchmarks/end-to-end-latency/smoke.md +21 -0
  61. package/docs/specs/031-ios-system-traces/plan.md +28 -0
  62. package/docs/specs/033-device-readiness-blockers/android-evidence.json +437 -0
  63. package/docs/specs/033-device-readiness-blockers/android-physical-evidence.json +28 -0
  64. package/docs/specs/033-device-readiness-blockers/android-physical-power-evidence.json +29 -0
  65. package/docs/specs/033-device-readiness-blockers/intent.md +41 -0
  66. package/docs/specs/033-device-readiness-blockers/ios-investigation.md +55 -0
  67. package/docs/specs/033-device-readiness-blockers/ios-probe-evidence.json +24 -0
  68. package/docs/specs/033-device-readiness-blockers/ios-tool-evidence.json +73 -0
  69. package/docs/specs/033-device-readiness-blockers/plan.md +249 -0
  70. package/docs/specs/033-device-readiness-blockers/spec.md +134 -0
  71. package/docs/specs/034-app-installation-status/intent.md +41 -0
  72. package/docs/specs/034-app-installation-status/native-evidence.json +654 -0
  73. package/docs/specs/034-app-installation-status/plan.md +73 -0
  74. package/docs/specs/034-app-installation-status/spec.md +114 -0
  75. package/docs/specs/035-compact-interaction-results/baseline.md +45 -0
  76. package/docs/specs/035-compact-interaction-results/intent.md +38 -0
  77. package/docs/specs/035-compact-interaction-results/plan.md +43 -0
  78. package/docs/specs/035-compact-interaction-results/spec.md +118 -0
  79. package/docs/specs/035-compact-interaction-results/verification.md +111 -0
  80. package/docs/specs/036-end-to-end-interaction-latency/android-snapshot-amendment.md +60 -0
  81. package/docs/specs/036-end-to-end-interaction-latency/android-snapshot-plan.md +32 -0
  82. package/docs/specs/036-end-to-end-interaction-latency/intent.md +37 -0
  83. package/docs/specs/036-end-to-end-interaction-latency/plan.md +59 -0
  84. package/docs/specs/036-end-to-end-interaction-latency/spec.md +126 -0
  85. package/docs/specs/036-end-to-end-interaction-latency/verification.md +87 -0
  86. package/docs/tools/TOOLS.md +1 -0
  87. package/docs/tools/compact-interactions.md +56 -0
  88. package/docs/tools/correlated-evidence.md +6 -0
  89. package/docs/tools/interact.md +17 -8
  90. package/docs/tools/manage.md +10 -2
  91. package/docs/tools/observe.md +42 -2
  92. package/docs/tools/system.md +6 -0
  93. package/package.json +1 -1
  94. package/src/contracts/device-readiness.ts +8 -0
  95. package/src/interact/waits/ui-change-wait.ts +7 -2
  96. package/src/interact/waits/ui-wait.ts +6 -3
  97. package/src/manage/index.ts +2 -0
  98. package/src/observe/device-readiness.ts +96 -0
  99. package/src/observe/evidence.ts +30 -1
  100. package/src/observe/ios-trace/sessions.ts +4 -2
  101. package/src/observe/readiness-service.ts +21 -9
  102. package/src/observe/readiness.ts +33 -0
  103. package/src/observe/screenshot-encoding.ts +4 -0
  104. package/src/observe/snapshot-collection.ts +7 -2
  105. package/src/server/common.ts +2 -2
  106. package/src/server/definitions/manage.ts +3 -2
  107. package/src/server/handlers/action-execution.ts +22 -14
  108. package/src/server/handlers/compact-interaction.ts +91 -0
  109. package/src/server/handlers/compact-state.ts +43 -0
  110. package/src/server/handlers/input.ts +2 -0
  111. package/src/server/handlers/interact.ts +2 -0
  112. package/src/server/handlers/interaction-diagnostics.ts +50 -0
  113. package/src/server/handlers/journey.ts +15 -17
  114. package/src/server/handlers/observe.ts +2 -1
  115. package/src/server/handlers/payload.ts +2 -1
  116. package/src/server/handlers/tool-handlers.ts +9 -5
  117. package/src/server/schemas/interaction-diagnostics.ts +10 -0
  118. package/src/server/tool-definitions.ts +8 -4
  119. package/src/server-core.ts +5 -2
  120. package/src/server.ts +1 -1
  121. package/src/system/android.ts +18 -11
  122. package/src/system/index.ts +2 -1
  123. package/src/types.ts +2 -0
  124. package/src/utils/android/utils.ts +8 -10
  125. package/src/utils/app-installation.ts +73 -0
  126. package/src/utils/benchmark-metrics.ts +42 -0
  127. package/src/utils/exec.ts +5 -0
  128. package/src/utils/ios/utils.ts +4 -10
  129. package/src/utils/resolve-device.ts +4 -2
  130. package/src/utils/timing.ts +3 -2
  131. package/test/device/automated/debugger/runtime.android.test.ts +5 -0
  132. package/test/device/automated/debugger/runtime.ios.test.ts +7 -1
  133. package/test/device/automated/interact/compact-results.smoke.ts +58 -0
  134. package/test/device/automated/latency/end-to-end-environment.ts +61 -0
  135. package/test/device/automated/latency/end-to-end-report.ts +90 -0
  136. package/test/device/automated/latency/end-to-end-session.ts +98 -0
  137. package/test/device/automated/latency/end-to-end.ts +149 -0
  138. package/test/device/automated/latency/owned-transport.ts +81 -0
  139. package/test/device/automated/latency/snapshot-pair.ts +143 -0
  140. package/test/device/automated/latency-ios/benchmark.ts +126 -0
  141. package/test/device/automated/observe/correlated-evidence.smoke.ts +7 -5
  142. package/test/device/automated/observe/device-readiness-cleanup.ts +14 -0
  143. package/test/device/automated/observe/device-readiness.android.smoke.ts +78 -0
  144. package/test/device/automated/observe/ios-system-trace.smoke.ts +2 -2
  145. package/test/device/automated/observe/system-trace.smoke.ts +2 -2
  146. package/test/fixtures/contracts/tool-definitions.json +51 -15
  147. package/test/fixtures/latency-journey-app/build.ts +3 -3
  148. package/test/unit/debugger/handle-guards.test.ts +2 -1
  149. package/test/unit/interact/ui-change-readiness-interruption.test.ts +37 -0
  150. package/test/unit/observe/capture_debug_snapshot.test.ts +66 -12
  151. package/test/unit/observe/device-readiness-cleanup.test.ts +24 -0
  152. package/test/unit/observe/device-readiness.test.ts +97 -0
  153. package/test/unit/observe/ios-trace-sessions.test.ts +23 -0
  154. package/test/unit/observe/readiness-retained-blockers.test.ts +40 -0
  155. package/test/unit/server/compact-interaction.test.ts +87 -0
  156. package/test/unit/server/compact-journey-evidence.test.ts +40 -0
  157. package/test/unit/server/compact-review-regressions.test.ts +78 -0
  158. package/test/unit/server/conditional_actions.test.ts +7 -3
  159. package/test/unit/server/correlated-evidence.test.ts +18 -6
  160. package/test/unit/server/end-to-end-report.test.ts +46 -0
  161. package/test/unit/server/input-device-readiness.test.ts +55 -0
  162. package/test/unit/server/interaction-diagnostics.test.ts +45 -0
  163. package/test/unit/server/owned-benchmark-transport.test.ts +32 -0
  164. package/test/unit/server/readiness-retained-deadline.test.ts +32 -0
  165. package/test/unit/server/readiness.test.ts +24 -1
  166. package/test/unit/server/run_journey.test.ts +2 -1
  167. package/test/unit/server/selector_tap_target.test.ts +2 -1
  168. package/test/unit/server/system-trace.test.ts +6 -4
  169. package/test/unit/utils/app-installation.test.ts +78 -0
  170. package/test/unit/utils/benchmark-metrics.test.ts +36 -0
  171. package/test/unit/utils/resolve_device.test.ts +11 -0
@@ -0,0 +1,21 @@
1
+ # End-to-end latency smoke (not performance evidence)
2
+
3
+ Status: finished. Build: 8f3a9bc8f498181686362c829e7395f301e85681d8ea1667692e2b33c18d011c.
4
+
5
+ | Case | Successful/measured | p50 ms | p95 ms | Failures | Warm-up failures |
6
+ | --- | ---: | ---: | ---: | ---: | ---: |
7
+ | standalone | 1/1 | 146335.1 | 146335.1 | 0 | 0 |
8
+ | full-debug | 1/1 | 84684.9 | 84684.9 | 0 | 0 |
9
+ | full-compact | 1/1 | 85400.3 | 85400.3 | 0 | 0 |
10
+ | light-debug | 1/1 | 65161.8 | 65161.8 | 0 | 0 |
11
+ | light-compact | 1/1 | 50780.4 | 50780.4 | 0 | 0 |
12
+ | screenshot-on | 1/1 | 884.2 | 884.2 | 0 | 0 |
13
+ | screenshot-off | 1/1 | 658.8 | 658.8 | 0 | 0 |
14
+ | tree-on | 1/1 | 2611.1 | 2611.1 | 0 | 0 |
15
+ | tree-off | 1/1 | 2509.6 | 2509.6 | 0 | 0 |
16
+ | snapshot-on | 1/1 | 4575.6 | 4575.6 | 0 | 0 |
17
+ | snapshot-off | 1/1 | 4667.2 | 4667.2 | 0 | 0 |
18
+
19
+ See smoke.json for exact source/build hashes, environment, phase durations, attempt order, inclusive components and failure records. Percentiles use the successful measured count shown for each case. With 1–19 successful samples, nearest-rank p95 is the sample maximum. Zero successful samples yield no percentiles. Failed attempts are excluded from percentiles, retained in raw data, and fail the run.
20
+
21
+ Intervals can overlap; component sums are not an additive latency budget. Client-minus-handler includes scheduling, transport and uninstrumented work. Handler residual excludes the union of recorded spans. Tree acquisition/parse/retry events are separate nested diagnostics. Application work inside requests remains included. Startup, fixture builds/resets and external validation are excluded from steady-state round trips. SDK wire serialization is not isolated.
@@ -136,3 +136,31 @@ Logs: `/private/tmp/mobile-debug-pr102-verify.log`,
136
136
  `/private/tmp/mobile-debug-pr102-device.log`,
137
137
  `/private/tmp/mobile-debug-pr102-android-rerun.log` and
138
138
  `/private/tmp/mobile-debug-pr102-monitor.log`.
139
+
140
+
141
+ ## Shutdown cleanup repair — 2026-11-05
142
+
143
+ A simulator run exposed a discarded trace directory left after recorder stop
144
+ failed. Finalization skipped artifact cleanup on any stop exception, including
145
+ when the owned recorder had already exited (such as after forced termination).
146
+ The fix removes discarded files only after confirmed recorder exit and preserves
147
+ the failed state/reason; a possibly live recorder still retains its directory for
148
+ retry. Storage-limit cleanup retains its existing behaviour.
149
+
150
+ Regression coverage proves both the live-writer safety case and shutdown after
151
+ stop failure with confirmed exit. The latter failed before the fix and passed
152
+ afterward. The complete simulator trace regression and `npm run verify` passed. The
153
+ original shutdown deadline and assertions were unchanged. The repaired run
154
+ established tap-to-Done via a fresh UI-tree assertion, 59 exported sample rows,
155
+ cancel/expiry/stale-ID handling, server shutdown directory removal and complete
156
+ owned trace/fixture cleanup. It used the documented test-owned compatibility
157
+ companion; the default idb/Xcode HID limitation remains separate. The baseline `MCP_READINESS_DEVICE=emulator-5554 npm run test:device` suite also
158
+ passed, with optional fixture skips reported separately. The full affected iOS
159
+ trace smoke was run explicitly above rather than inferred from the baseline
160
+ suite. The test-owned companion/alias was removed and simulator shutdown restored.
161
+
162
+ Logs: `/tmp/ios-shutdown-fixed-device.log`,
163
+ `/tmp/ios-shutdown-fixed-evidence.json`, `/tmp/ios-shutdown-verify.log`,
164
+ `/tmp/ios-shutdown-device-suite.log`.
165
+ Existing readiness verification edits in spec 033 and debugger device tests are
166
+ preserved separately; no physical-device operations are needed for this repair.
@@ -0,0 +1,437 @@
1
+ {
2
+ "deviceId": "emulator-5554",
3
+ "server": "dist/server.js",
4
+ "server_sha256": "49fa8b8969b5f6bae270c56912b3b1259edb400087b551538dcf0b45855aae34",
5
+ "runtime": "v23.11.0",
6
+ "observations": [
7
+ {
8
+ "tool": "get_app_readiness",
9
+ "args": {},
10
+ "result": {
11
+ "success": true,
12
+ "device": {
13
+ "platform": "android",
14
+ "id": "emulator-5554",
15
+ "osVersion": "16",
16
+ "model": "sdk_gphone64_arm64",
17
+ "simulator": true,
18
+ "appInstalled": false
19
+ },
20
+ "readiness": {
21
+ "state": "settled",
22
+ "scope": "device_ui",
23
+ "basis": "observed",
24
+ "captured_at_ms": 1793824169556,
25
+ "snapshot_session_id": "760cfc72-9c17-4855-8a9e-4491f35284c1",
26
+ "snapshot_revision": 1,
27
+ "sample_count": 2,
28
+ "stable_for_ms": 2774.727875,
29
+ "evidence": [
30
+ {
31
+ "code": "INSUFFICIENT_SAMPLES",
32
+ "source": "ui_tree",
33
+ "captured_at_ms": 1793824166781,
34
+ "snapshot_revision": 1
35
+ },
36
+ {
37
+ "code": "SNAPSHOT_STABLE",
38
+ "source": "ui_tree",
39
+ "captured_at_ms": 1793824169556,
40
+ "snapshot_revision": 1
41
+ }
42
+ ],
43
+ "limitations": [
44
+ "NORMALIZED_UI_ONLY",
45
+ "FOREGROUND_APP_UNVERIFIED",
46
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
47
+ "MANAGED_DEBUGGER_ONLY"
48
+ ],
49
+ "capabilities": {
50
+ "loading": true,
51
+ "transitioning": true,
52
+ "settled": true,
53
+ "unresponsive": false,
54
+ "debugger_paused": true
55
+ }
56
+ },
57
+ "device_readiness": {
58
+ "wakefulness": "awake",
59
+ "lock_state": "unlocked",
60
+ "input_ready": null,
61
+ "blockers": [],
62
+ "evidence": [
63
+ {
64
+ "code": "DEVICE_AWAKE",
65
+ "source": "android_power",
66
+ "captured_at_ms": 1793824167338
67
+ },
68
+ {
69
+ "code": "DEVICE_UNLOCKED",
70
+ "source": "android_window",
71
+ "captured_at_ms": 1793824167382
72
+ }
73
+ ],
74
+ "limitations": []
75
+ },
76
+ "elapsed_ms": 5454.18075
77
+ }
78
+ },
79
+ {
80
+ "tool": "get_app_readiness",
81
+ "args": {},
82
+ "result": {
83
+ "success": true,
84
+ "device": {
85
+ "platform": "android",
86
+ "id": "emulator-5554",
87
+ "osVersion": "16",
88
+ "model": "sdk_gphone64_arm64",
89
+ "simulator": true,
90
+ "appInstalled": false
91
+ },
92
+ "readiness": {
93
+ "state": "unknown",
94
+ "scope": "device_ui",
95
+ "basis": "insufficient",
96
+ "captured_at_ms": null,
97
+ "sample_count": 0,
98
+ "stable_for_ms": 0,
99
+ "snapshot_session_id": null,
100
+ "snapshot_revision": null,
101
+ "evidence": [],
102
+ "limitations": [
103
+ "NORMALIZED_UI_ONLY",
104
+ "FOREGROUND_APP_UNVERIFIED",
105
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
106
+ "MANAGED_DEBUGGER_ONLY",
107
+ "INSUFFICIENT_SAMPLES",
108
+ "DEVICE_BLOCKED"
109
+ ],
110
+ "capabilities": {
111
+ "loading": true,
112
+ "transitioning": true,
113
+ "settled": true,
114
+ "unresponsive": false,
115
+ "debugger_paused": true
116
+ }
117
+ },
118
+ "device_readiness": {
119
+ "wakefulness": "asleep",
120
+ "lock_state": "unlocked",
121
+ "input_ready": false,
122
+ "blockers": [
123
+ "DEVICE_ASLEEP"
124
+ ],
125
+ "evidence": [
126
+ {
127
+ "code": "DEVICE_ASLEEP",
128
+ "source": "android_power",
129
+ "captured_at_ms": 1793824170627
130
+ },
131
+ {
132
+ "code": "DEVICE_UNLOCKED",
133
+ "source": "android_window",
134
+ "captured_at_ms": 1793824170662
135
+ }
136
+ ],
137
+ "limitations": []
138
+ },
139
+ "elapsed_ms": 1055.0427499999996
140
+ }
141
+ },
142
+ {
143
+ "tool": "start_app",
144
+ "args": {
145
+ "appId": "com.android.settings",
146
+ "verificationMode": "none",
147
+ "responseMode": "compact",
148
+ "actionTimeoutMs": 10000
149
+ },
150
+ "result": {
151
+ "action_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
152
+ "device_readiness": {
153
+ "wakefulness": "asleep",
154
+ "lock_state": "unlocked",
155
+ "input_ready": false,
156
+ "blockers": [
157
+ "DEVICE_ASLEEP"
158
+ ],
159
+ "evidence": [
160
+ {
161
+ "code": "DEVICE_ASLEEP",
162
+ "source": "android_power",
163
+ "captured_at_ms": 1793824171199
164
+ },
165
+ {
166
+ "code": "DEVICE_UNLOCKED",
167
+ "source": "android_window",
168
+ "captured_at_ms": 1793824171242
169
+ }
170
+ ],
171
+ "limitations": []
172
+ },
173
+ "action_type": "start_app",
174
+ "success": true,
175
+ "lifecycle_state": "pending_verification",
176
+ "delivery_status": "delivered",
177
+ "dispatch_started": true,
178
+ "verification": {
179
+ "mode": "none",
180
+ "status": "not_requested"
181
+ },
182
+ "timing": {
183
+ "total_ms": 579.8293329999997
184
+ },
185
+ "evidence": {
186
+ "session_id": "fe501f9e-b707-4763-854c-4a1c81931fe1",
187
+ "correlation_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
188
+ "action_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
189
+ "device": {
190
+ "platform": "android",
191
+ "id": "emulator-5554"
192
+ },
193
+ "association": "self",
194
+ "association_reason": null,
195
+ "operation_started_at_ms": 1793824170663,
196
+ "operation_completed_at_ms": 1793824171242,
197
+ "dispatch_started_at_ms": 1793824170713,
198
+ "dispatch_completed_at_ms": 1793824171015,
199
+ "verification_completed_at_ms": null,
200
+ "observations": [
201
+ {
202
+ "evidence_id": "2d8052cc-f6f2-4f77-98e9-ff1ca0f2e3a5",
203
+ "kind": "activity",
204
+ "status": "captured",
205
+ "capture_started_at_ms": 1793824171015,
206
+ "capture_completed_at_ms": 1793824171135,
207
+ "source_captured_at_ms": 1793824171135,
208
+ "age_ms": 106.934326171875,
209
+ "freshness": "fresh",
210
+ "freshness_reasons": [],
211
+ "device": {
212
+ "platform": "android",
213
+ "id": "emulator-5554"
214
+ },
215
+ "session_id": "fe501f9e-b707-4763-854c-4a1c81931fe1",
216
+ "correlation_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
217
+ "action_id": "fad30314-3242-43b7-b61c-97ec974bf9b4",
218
+ "association": "internal"
219
+ }
220
+ ],
221
+ "trace_context": {
222
+ "supported": false,
223
+ "trace_id": null,
224
+ "markers": []
225
+ }
226
+ }
227
+ }
228
+ },
229
+ {
230
+ "tool": "wait_for_app_ready",
231
+ "args": {
232
+ "timeoutMs": 1200,
233
+ "pollIntervalMs": 100
234
+ },
235
+ "result": {
236
+ "success": false,
237
+ "device": {
238
+ "platform": "android",
239
+ "id": "emulator-5554",
240
+ "osVersion": "16",
241
+ "model": "sdk_gphone64_arm64",
242
+ "simulator": true,
243
+ "appInstalled": false
244
+ },
245
+ "readiness": {
246
+ "state": "unknown",
247
+ "scope": "device_ui",
248
+ "basis": "insufficient",
249
+ "captured_at_ms": null,
250
+ "sample_count": 0,
251
+ "stable_for_ms": 0,
252
+ "snapshot_session_id": null,
253
+ "snapshot_revision": null,
254
+ "evidence": [],
255
+ "limitations": [
256
+ "NORMALIZED_UI_ONLY",
257
+ "FOREGROUND_APP_UNVERIFIED",
258
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
259
+ "MANAGED_DEBUGGER_ONLY",
260
+ "INSUFFICIENT_SAMPLES",
261
+ "DEVICE_BLOCKED",
262
+ "DEADLINE_EXCEEDED"
263
+ ],
264
+ "capabilities": {
265
+ "loading": true,
266
+ "transitioning": true,
267
+ "settled": true,
268
+ "unresponsive": false,
269
+ "debugger_paused": true
270
+ }
271
+ },
272
+ "device_readiness": {
273
+ "wakefulness": "unknown",
274
+ "lock_state": "unknown",
275
+ "input_ready": null,
276
+ "blockers": [],
277
+ "evidence": [],
278
+ "limitations": [
279
+ "DEVICE_POWER_OBSERVATION_FAILED",
280
+ "DEVICE_LOCK_OBSERVATION_FAILED"
281
+ ]
282
+ },
283
+ "elapsed_ms": 1245.8765839999996,
284
+ "failure_code": "READINESS_TIMEOUT"
285
+ }
286
+ },
287
+ {
288
+ "tool": "get_app_readiness",
289
+ "args": {},
290
+ "result": {
291
+ "success": true,
292
+ "device": {
293
+ "platform": "android",
294
+ "id": "emulator-5554",
295
+ "osVersion": "16",
296
+ "model": "sdk_gphone64_arm64",
297
+ "simulator": true,
298
+ "appInstalled": false
299
+ },
300
+ "readiness": {
301
+ "state": "settled",
302
+ "scope": "device_ui",
303
+ "basis": "observed",
304
+ "captured_at_ms": 1793824178604,
305
+ "snapshot_session_id": "760cfc72-9c17-4855-8a9e-4491f35284c1",
306
+ "snapshot_revision": 2,
307
+ "sample_count": 2,
308
+ "stable_for_ms": 2779.1579999999994,
309
+ "evidence": [
310
+ {
311
+ "code": "INSUFFICIENT_SAMPLES",
312
+ "source": "ui_tree",
313
+ "captured_at_ms": 1793824175825,
314
+ "snapshot_revision": 2
315
+ },
316
+ {
317
+ "code": "SNAPSHOT_STABLE",
318
+ "source": "ui_tree",
319
+ "captured_at_ms": 1793824178604,
320
+ "snapshot_revision": 2
321
+ }
322
+ ],
323
+ "limitations": [
324
+ "NORMALIZED_UI_ONLY",
325
+ "FOREGROUND_APP_UNVERIFIED",
326
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
327
+ "MANAGED_DEBUGGER_ONLY"
328
+ ],
329
+ "capabilities": {
330
+ "loading": true,
331
+ "transitioning": true,
332
+ "settled": true,
333
+ "unresponsive": false,
334
+ "debugger_paused": true
335
+ }
336
+ },
337
+ "device_readiness": {
338
+ "wakefulness": "awake",
339
+ "lock_state": "unlocked",
340
+ "input_ready": null,
341
+ "blockers": [],
342
+ "evidence": [
343
+ {
344
+ "code": "DEVICE_AWAKE",
345
+ "source": "android_power",
346
+ "captured_at_ms": 1793824176383
347
+ },
348
+ {
349
+ "code": "DEVICE_UNLOCKED",
350
+ "source": "android_window",
351
+ "captured_at_ms": 1793824176424
352
+ }
353
+ ],
354
+ "limitations": []
355
+ },
356
+ "elapsed_ms": 6075.207875
357
+ }
358
+ },
359
+ {
360
+ "tool": "wait_for_app_ready",
361
+ "args": {
362
+ "timeoutMs": 15000,
363
+ "stabilityMs": 100,
364
+ "pollIntervalMs": 100
365
+ },
366
+ "result": {
367
+ "success": true,
368
+ "device": {
369
+ "platform": "android",
370
+ "id": "emulator-5554",
371
+ "osVersion": "16",
372
+ "model": "sdk_gphone64_arm64",
373
+ "simulator": true,
374
+ "appInstalled": false
375
+ },
376
+ "readiness": {
377
+ "state": "settled",
378
+ "scope": "device_ui",
379
+ "basis": "observed",
380
+ "captured_at_ms": 1793824183495,
381
+ "snapshot_session_id": "760cfc72-9c17-4855-8a9e-4491f35284c1",
382
+ "snapshot_revision": 2,
383
+ "sample_count": 2,
384
+ "stable_for_ms": 2404.0407909999994,
385
+ "evidence": [
386
+ {
387
+ "code": "INSUFFICIENT_SAMPLES",
388
+ "source": "ui_tree",
389
+ "captured_at_ms": 1793824181091,
390
+ "snapshot_revision": 2
391
+ },
392
+ {
393
+ "code": "SNAPSHOT_STABLE",
394
+ "source": "ui_tree",
395
+ "captured_at_ms": 1793824183495,
396
+ "snapshot_revision": 2
397
+ }
398
+ ],
399
+ "limitations": [
400
+ "NORMALIZED_UI_ONLY",
401
+ "FOREGROUND_APP_UNVERIFIED",
402
+ "UNRESPONSIVE_SIGNAL_UNSUPPORTED",
403
+ "MANAGED_DEBUGGER_ONLY"
404
+ ],
405
+ "capabilities": {
406
+ "loading": true,
407
+ "transitioning": true,
408
+ "settled": true,
409
+ "unresponsive": false,
410
+ "debugger_paused": true
411
+ }
412
+ },
413
+ "device_readiness": {
414
+ "wakefulness": "awake",
415
+ "lock_state": "unlocked",
416
+ "input_ready": null,
417
+ "blockers": [],
418
+ "evidence": [
419
+ {
420
+ "code": "DEVICE_AWAKE",
421
+ "source": "android_power",
422
+ "captured_at_ms": 1793824181241
423
+ },
424
+ {
425
+ "code": "DEVICE_UNLOCKED",
426
+ "source": "android_window",
427
+ "captured_at_ms": 1793824181281
428
+ }
429
+ ],
430
+ "limitations": []
431
+ },
432
+ "elapsed_ms": 4855.992333
433
+ }
434
+ }
435
+ ],
436
+ "cleanup": "wake, dismiss disposable keyguard, Home; no security settings changed"
437
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "device": {
3
+ "platform": "android",
4
+ "id": "adb-51181FDAP0031Y-gxy7FO._adb-tls-connect._tcp"
5
+ },
6
+ "model": "Pixel 9 Pro",
7
+ "osVersion": "Android 17",
8
+ "runtime": "v23.11.0",
9
+ "scope": "read-only current state; no sleep/lock/unlock/input dispatched",
10
+ "result": {
11
+ "wakefulness": "unknown",
12
+ "lock_state": "locked",
13
+ "input_ready": false,
14
+ "blockers": [
15
+ "DEVICE_LOCKED"
16
+ ],
17
+ "evidence": [
18
+ {
19
+ "code": "DEVICE_LOCKED",
20
+ "source": "android_window",
21
+ "captured_at_ms": 1793824059095
22
+ }
23
+ ],
24
+ "limitations": [
25
+ "DEVICE_WAKEFULNESS_UNVERIFIED"
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "device": {
3
+ "platform": "android",
4
+ "id": "adb-51181FDAP0031Y-gxy7FO._adb-tls-connect._tcp"
5
+ },
6
+ "model": "Pixel 9 Pro",
7
+ "osVersion": "Android 17",
8
+ "runtime": "v23.11.0",
9
+ "scope": "read-only current state; main Power Manager State section; no input dispatched",
10
+ "result": {
11
+ "wakefulness": "awake",
12
+ "lock_state": "unlocked",
13
+ "input_ready": null,
14
+ "blockers": [],
15
+ "evidence": [
16
+ {
17
+ "code": "DEVICE_AWAKE",
18
+ "source": "android_power",
19
+ "captured_at_ms": 1793824124380
20
+ },
21
+ {
22
+ "code": "DEVICE_UNLOCKED",
23
+ "source": "android_window",
24
+ "captured_at_ms": 1793824124492
25
+ }
26
+ ],
27
+ "limitations": []
28
+ }
29
+ }
@@ -0,0 +1,41 @@
1
+ # Intent: device readiness blockers
2
+
3
+ Status: intent and revised specification approved; implementation authorised.
4
+ Originator: clivejefferies, GitHub issue #101, created 2026-11-04.
5
+ Captured: 2026-11-04.
6
+ Source: https://github.com/clivejefferies/mobile-debug-tools/issues/101
7
+
8
+ ## Problem
9
+
10
+ Recent agent feedback reports that a successful app launch left the agent
11
+ inspecting a sleeping or locked phone. Existing app readiness signals (#65)
12
+ need to distinguish launch dispatch from an app observed to be visible and
13
+ ready for input.
14
+
15
+ ## Desired outcome and scope
16
+
17
+ Extend existing launch, readiness, and relevant interaction results so MCP
18
+ clients can identify device-level readiness blockers on Android and iOS.
19
+ Report sleeping or locked states only when supported evidence establishes
20
+ them; otherwise expose explicit unknown or unsupported outcomes. Include
21
+ evidence timestamps and coordinate with existing debugger-paused reporting.
22
+
23
+ Success means launch dispatch alone cannot imply visibility or input readiness,
24
+ and supported awake/unlocked, sleeping, locked, transitioning, and debugger-paused
25
+ flows have recorded verification. Distinguish Android and iOS evidence and record
26
+ any inaccessible scenarios. Reproduce the reported flow where practical.
27
+
28
+ ## Constraints and questions
29
+
30
+ Preserve bounded waits, device targeting, and existing action contracts unless a
31
+ compatibility change is explicitly approved. Do not automatically unlock devices
32
+ or change security settings. New diagnostic capabilities are outside scope.
33
+
34
+ Investigation must establish which device states each platform can reliably
35
+ observe, which existing results need the evidence, and how stale or conflicting
36
+ observations should be represented. These decisions belong in the specification.
37
+
38
+ ## Approval
39
+
40
+ User approved this problem and scope with “ok” in the current chat on 2026-11-04,
41
+ in response to the captured intent and explicit intent-approval question.
@@ -0,0 +1,55 @@
1
+ # iOS readiness investigation — 2026-11-04
2
+
3
+ ## Findings
4
+
5
+ Blanket iOS unsupported was not justified by the initial sandbox failure.
6
+ Running the probes outside the sandbox established an actual capability
7
+ boundary, separately from tool-access failures.
8
+
9
+ Apple's installed `devicectl` documents `device info lockState` as a read-only
10
+ lock-state query, and `device info displays` supplies structured backlight
11
+ information. Its help documents JSON output as the automation interface.
12
+ [Apple's device command-line documentation](https://developer.apple.com/documentation/xcode/interacting-with-devices-using-the-command-line)
13
+ is the upstream reference. This investigation relies on actual local command
14
+ help and output for the conclusions below.
15
+
16
+ ## Environment and results
17
+
18
+ Target: iPhone 17 Pro simulator, UDID
19
+ `F9243BAF-62A8-4990-8A99-17F527F56FDA`, listed as iOS 26.4.
20
+ CoreDevice CLI version: `651.32`; JSON version: 5.
21
+ No physical iOS device was listed by `devicectl list devices`.
22
+ No server implementation was changed or tested.
23
+
24
+ | Probe | Observed result | Meaning |
25
+ | --- | --- | --- |
26
+ | `xcrun simctl list devices booted` outside sandbox | No booted simulators initially | Initial runtime state only |
27
+ | `xcrun simctl boot <UDID>` / `bootstatus <UDID> -b` | Boot succeeded; later bootstatus confirmed booted | Runtime available |
28
+ | `xcrun devicectl device info lockState --device <UDID> --timeout 10 --json-output <path>` | CoreDevice error 1001, feature `com.apple.coredevice.feature.getlockstate`, capability not supported | Explicit lock-probe unsupported on this target/toolchain |
29
+ | `xcrun devicectl device info displays --device <UDID> --timeout 10 --json-output <path>` | Per-display backlight unknown; top-level backlight `activeOn` after boot | Does not establish lock state |
30
+ | `xcrun simctl io <UDID> enumerate` | Display ports report power On | Port-level evidence only |
31
+ | `xcrun simctl io <UDID> screenConfig --display 1 power off` followed by display probes | Command accepted; display ports still On; devicectl top-level `activeOn` | These probes did not distinguish the commanded display-off state |
32
+ | Repeat display-off experiment after bootstatus completed | Baseline and off JSON both `activeOn` | No reliable sleep inference from this experiment |
33
+ | `screenConfig --display 1 power on`, then `simctl shutdown <UDID>` | Both completed successfully | Restored original shutdown state |
34
+
35
+ The display-off command is not independently verified OS sleep or lock. The
36
+ experiment disproves treating command acknowledgement or port power as sufficient
37
+ readiness evidence; it does not establish that every iOS display API is unusable.
38
+ Transient timing and simulator-specific semantics remain limitations.
39
+
40
+ ## Proposed specification correction
41
+
42
+ - Explicit unsupported is per axis and target, established by capability evidence.
43
+ - Probe failures or uninterpretable observations yield unknown.
44
+ - On this simulator: lock state unsupported through CoreDevice; wakefulness
45
+ unknown with an unverified-signal limitation.
46
+ - Physical iOS lock detection has an Apple CLI route, but no physical iOS device
47
+ was available to validate output or locked/unlocked transitions. The repository's
48
+ current iOS discovery/lifecycle path is simulator-based; extending that is a
49
+ separate scope decision.
50
+ - No private API fallback, app instrumentation, automatic unlock, or security
51
+ changes are proposed.
52
+
53
+ This is investigation evidence, not implementation verification or proof of
54
+ all iOS runtimes. Real lock/unlock transitions and true sleep recovery remain
55
+ unrun on iOS.
@@ -0,0 +1,24 @@
1
+ {
2
+ "device": {
3
+ "platform": "ios",
4
+ "id": "F9243BAF-62A8-4990-8A99-17F527F56FDA"
5
+ },
6
+ "runtime": "v23.11.0",
7
+ "server": "dist/observe/device-readiness.js",
8
+ "result": {
9
+ "wakefulness": "unknown",
10
+ "lock_state": "unsupported",
11
+ "input_ready": null,
12
+ "blockers": [],
13
+ "evidence": [
14
+ {
15
+ "code": "DEVICE_LOCK_SIGNAL_UNSUPPORTED",
16
+ "source": "coredevice",
17
+ "captured_at_ms": 1793823876688
18
+ }
19
+ ],
20
+ "limitations": [
21
+ "DEVICE_WAKEFULNESS_UNVERIFIED"
22
+ ]
23
+ }
24
+ }