mobile-debug-mcp 0.32.2 → 0.33.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.
- package/.agents/plugins/marketplace.json +20 -0
- package/{skills → .agents/skills}/mcp-builder/SKILL.md +1 -2
- package/{skills → .agents/skills}/spec-review/SKILL.md +1 -1
- package/{skills → .agents/skills}/test-authoring/SKILL.md +1 -1
- package/.claude-plugin/marketplace.json +14 -0
- package/.cursor-plugin/marketplace.json +16 -0
- package/.github/copilot-instructions.md +7 -0
- package/AGENTS.md +21 -10
- package/README.md +67 -5
- package/agent-plugin/.claude-plugin/plugin.json +20 -0
- package/agent-plugin/.codex-plugin/plugin.json +34 -0
- package/agent-plugin/.cursor-plugin/plugin.json +23 -0
- package/agent-plugin/.mcp.json +14 -0
- package/agent-plugin/LICENSE +201 -0
- package/agent-plugin/README.md +29 -0
- package/agent-plugin/assets/mobile-debug-tools.svg +28 -0
- package/agent-plugin/mcp.json +11 -0
- package/agent-plugin/plugin.json +29 -0
- package/agent-plugin/skills/mobile-debug-mcp/SKILL.md +124 -0
- package/dist/interact/android.js +10 -4
- package/dist/interact/conditional-action.js +68 -0
- package/dist/interact/index.js +54 -14
- package/dist/interact/ios.js +14 -8
- package/dist/manage/android.js +4 -3
- package/dist/manage/ios.js +3 -2
- package/dist/observe/android.js +27 -22
- package/dist/observe/evidence.js +273 -0
- package/dist/observe/index.js +33 -6
- package/dist/observe/ios.js +25 -6
- package/dist/observe/readiness-service.js +115 -0
- package/dist/observe/readiness.js +81 -0
- package/dist/observe/recording.js +165 -0
- package/dist/observe/snapshot-metadata.js +10 -2
- package/dist/server/common.js +9 -0
- package/dist/server/condition-schema.js +32 -0
- package/dist/server/journey-schema.js +3 -2
- package/dist/server/readiness-schema.js +12 -0
- package/dist/server/tool-definitions.js +46 -0
- package/dist/server/tool-handlers.js +99 -17
- package/dist/server-core.js +1 -1
- package/dist/utils/ios/utils.js +4 -4
- package/dist/utils/operation-budget.js +24 -2
- package/dist/utils/resolve-device.js +7 -0
- package/docs/CHANGELOG.md +16 -2
- package/docs/benchmarks/ui-tree-performance/README.md +4 -3
- package/docs/specs/020-conditional-actions/intent.md +62 -0
- package/docs/specs/020-conditional-actions/plan.md +214 -0
- package/docs/specs/020-conditional-actions/spec.md +301 -0
- package/docs/specs/021-app-readiness-signals/intent.md +40 -0
- package/docs/specs/021-app-readiness-signals/plan.md +102 -0
- package/docs/specs/021-app-readiness-signals/spec.md +144 -0
- package/docs/specs/022-correlated-evidence/device-evidence.json +60 -0
- package/docs/specs/022-correlated-evidence/intent.md +37 -0
- package/docs/specs/022-correlated-evidence/modul8-evidence.json +1062 -0
- package/docs/specs/022-correlated-evidence/modul8-selector-fix-evidence.json +336 -0
- package/docs/specs/022-correlated-evidence/plan.md +171 -0
- package/docs/specs/022-correlated-evidence/spec.md +123 -0
- package/docs/specs/process.md +213 -0
- package/docs/tools/TOOLS.md +3 -0
- package/docs/tools/evidence.md +79 -0
- package/docs/tools/interact.md +125 -2
- package/docs/tools/observe.md +64 -2
- package/package.json +4 -2
- package/scripts/agent-plugin.mjs +98 -0
- package/src/interact/android.ts +10 -4
- package/src/interact/conditional-action.ts +75 -0
- package/src/interact/index.ts +42 -14
- package/src/interact/ios.ts +14 -8
- package/src/manage/android.ts +4 -3
- package/src/manage/ios.ts +3 -2
- package/src/observe/android.ts +35 -21
- package/src/observe/evidence.ts +255 -0
- package/src/observe/index.ts +32 -8
- package/src/observe/ios.ts +32 -8
- package/src/observe/readiness-service.ts +89 -0
- package/src/observe/readiness.ts +78 -0
- package/src/observe/snapshot-metadata.ts +12 -1
- package/src/server/common.ts +7 -0
- package/src/server/condition-schema.ts +32 -0
- package/src/server/journey-schema.ts +3 -2
- package/src/server/readiness-schema.ts +12 -0
- package/src/server/tool-definitions.ts +44 -0
- package/src/server/tool-handlers.ts +93 -17
- package/src/server-core.ts +1 -1
- package/src/types.ts +30 -1
- package/src/utils/ios/utils.ts +4 -4
- package/src/utils/operation-budget.ts +22 -2
- package/src/utils/resolve-device.ts +8 -0
- package/test/device/automated/observe/correlated-evidence.smoke.ts +70 -0
- package/test/device/manual/interact/conditional_actions.manual.ts +95 -0
- package/test/device/manual/interact/modul8_selector_tap.manual.ts +63 -0
- package/test/device/manual/interact/readiness.manual.ts +99 -0
- package/test/fixtures/readiness-app/MainActivity.java +23 -0
- package/test/fixtures/readiness-app/README.md +12 -0
- package/test/fixtures/readiness-app/build.ts +37 -0
- package/test/fixtures/readiness-app/main.m +27 -0
- package/test/unit/observe/android_tree_acquisition.test.ts +6 -0
- package/test/unit/observe/capture_debug_snapshot.test.ts +42 -32
- package/test/unit/observe/compact_tree_error.test.ts +24 -0
- package/test/unit/observe/conditional_snapshots.test.ts +33 -0
- package/test/unit/observe/correlated-evidence.test.ts +128 -0
- package/test/unit/observe/ios-getlogs.test.ts +3 -3
- package/test/unit/observe/ios_tree_acquisition.test.ts +2 -0
- package/test/unit/observe/readiness.test.ts +39 -0
- package/test/unit/observe/readiness_native.test.ts +68 -0
- package/test/unit/server/conditional_actions.test.ts +299 -0
- package/test/unit/server/conditional_schema.test.ts +59 -0
- package/test/unit/server/correlated-evidence.test.ts +194 -0
- package/test/unit/server/readiness.test.ts +170 -0
- package/test/unit/server/selector_tap_target.test.ts +79 -0
- package/test/unit/server/tap_selector.test.ts +2 -0
- package/skills/mobile-debug-tools-usage/SKILL.md +0 -74
- package/src/observe/android-tree-bridge.ts +0 -178
- package/test/device/automated/ui-tree-performance/bridge-probe.ts +0 -197
- package/test/fixtures/ui-tree-bridge/AndroidManifest.xml +0 -6
- package/test/fixtures/ui-tree-bridge/build.ts +0 -34
- package/test/fixtures/ui-tree-bridge/src/TreeInstrumentation.java +0 -126
- package/test/unit/observe/android_tree_bridge_cleanup.test.ts +0 -95
- /package/{skills → .agents/skills}/README.md +0 -0
- /package/{skills → .agents/skills}/mcp-builder/references/build-flags.md +0 -0
- /package/{skills → .agents/skills}/mcp-builder/references/diagnostics-schema.md +0 -0
- /package/{skills → .agents/skills}/mcp-builder/references/toolchain-details.md +0 -0
- /package/{skills → .agents/skills}/spec-review/references/spec-review-checklist.md +0 -0
- /package/{skills → .agents/skills}/spec-review/references/spec-review-template.md +0 -0
- /package/{skills → .agents/skills}/test-authoring/references/repo-test-layout.md +0 -0
- /package/{skills → .agents/skills}/test-authoring/references/test-authoring-workflow.md +0 -0
- /package/{skills → .agents/skills}/test-authoring/references/test-quality-checklist.md +0 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
{
|
|
2
|
+
"verified_on": "2026-10-30T09:14:34.967Z",
|
|
3
|
+
"device": {
|
|
4
|
+
"platform": "android",
|
|
5
|
+
"deviceId": "emulator-5554"
|
|
6
|
+
},
|
|
7
|
+
"package": "com.ideamechanics.modul8.dev",
|
|
8
|
+
"source": "rebuilt local MCP stdio server",
|
|
9
|
+
"build_sha256": "ab7f5916468b000b70f445de5a29406adfd141cea89e1298661562e68fbef61d",
|
|
10
|
+
"steps": [
|
|
11
|
+
{
|
|
12
|
+
"selector": {
|
|
13
|
+
"text": "FAVOURITES"
|
|
14
|
+
},
|
|
15
|
+
"waitForCondition": "default",
|
|
16
|
+
"status": "PASS",
|
|
17
|
+
"failure_code": null,
|
|
18
|
+
"evidence": {
|
|
19
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
20
|
+
"correlation_id": "01a328ba-91a9-4ac6-a768-b06701e71018",
|
|
21
|
+
"action_id": "01a328ba-91a9-4ac6-a768-b06701e71018",
|
|
22
|
+
"device": {
|
|
23
|
+
"platform": "android",
|
|
24
|
+
"id": "emulator-5554"
|
|
25
|
+
},
|
|
26
|
+
"association": "self",
|
|
27
|
+
"association_reason": null,
|
|
28
|
+
"operation_started_at_ms": 1793351680409,
|
|
29
|
+
"operation_completed_at_ms": 1793351683123,
|
|
30
|
+
"dispatch_started_at_ms": 1793351683067,
|
|
31
|
+
"dispatch_completed_at_ms": 1793351683123,
|
|
32
|
+
"verification_completed_at_ms": null,
|
|
33
|
+
"observations": [
|
|
34
|
+
{
|
|
35
|
+
"evidence_id": "1dc56459-d61e-4814-9612-2e3ad6c8782b",
|
|
36
|
+
"kind": "ui_tree",
|
|
37
|
+
"status": "captured",
|
|
38
|
+
"capture_started_at_ms": 1793351680628,
|
|
39
|
+
"capture_completed_at_ms": 1793351682798,
|
|
40
|
+
"source_captured_at_ms": 1793351682798,
|
|
41
|
+
"age_ms": 324.72998046875,
|
|
42
|
+
"freshness": "stale",
|
|
43
|
+
"freshness_reasons": [
|
|
44
|
+
"BEFORE_ACTION"
|
|
45
|
+
],
|
|
46
|
+
"device": {
|
|
47
|
+
"platform": "android",
|
|
48
|
+
"id": "emulator-5554"
|
|
49
|
+
},
|
|
50
|
+
"snapshot_session_id": "9f2a6439-590e-46a5-9025-d6c828525250",
|
|
51
|
+
"snapshot_revision": 1,
|
|
52
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
53
|
+
"correlation_id": "01a328ba-91a9-4ac6-a768-b06701e71018",
|
|
54
|
+
"action_id": "01a328ba-91a9-4ac6-a768-b06701e71018",
|
|
55
|
+
"association": "internal"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"trace_context": {
|
|
59
|
+
"supported": false,
|
|
60
|
+
"trace_id": null,
|
|
61
|
+
"markers": []
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"selector": {
|
|
67
|
+
"text": "GENER8"
|
|
68
|
+
},
|
|
69
|
+
"waitForCondition": "default",
|
|
70
|
+
"status": "PASS",
|
|
71
|
+
"failure_code": null,
|
|
72
|
+
"evidence": {
|
|
73
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
74
|
+
"correlation_id": "61cdf8f3-3702-4342-ad25-aaa7146f4e85",
|
|
75
|
+
"action_id": "61cdf8f3-3702-4342-ad25-aaa7146f4e85",
|
|
76
|
+
"device": {
|
|
77
|
+
"platform": "android",
|
|
78
|
+
"id": "emulator-5554"
|
|
79
|
+
},
|
|
80
|
+
"association": "self",
|
|
81
|
+
"association_reason": null,
|
|
82
|
+
"operation_started_at_ms": 1793351688186,
|
|
83
|
+
"operation_completed_at_ms": 1793351691068,
|
|
84
|
+
"dispatch_started_at_ms": 1793351691021,
|
|
85
|
+
"dispatch_completed_at_ms": 1793351691068,
|
|
86
|
+
"verification_completed_at_ms": null,
|
|
87
|
+
"observations": [
|
|
88
|
+
{
|
|
89
|
+
"evidence_id": "74bda6d0-fdf1-40d3-92d6-31f61e49316b",
|
|
90
|
+
"kind": "ui_tree",
|
|
91
|
+
"status": "captured",
|
|
92
|
+
"capture_started_at_ms": 1793351688428,
|
|
93
|
+
"capture_completed_at_ms": 1793351690795,
|
|
94
|
+
"source_captured_at_ms": 1793351690795,
|
|
95
|
+
"age_ms": 273.0615234375,
|
|
96
|
+
"freshness": "stale",
|
|
97
|
+
"freshness_reasons": [
|
|
98
|
+
"BEFORE_ACTION"
|
|
99
|
+
],
|
|
100
|
+
"device": {
|
|
101
|
+
"platform": "android",
|
|
102
|
+
"id": "emulator-5554"
|
|
103
|
+
},
|
|
104
|
+
"snapshot_session_id": "9f2a6439-590e-46a5-9025-d6c828525250",
|
|
105
|
+
"snapshot_revision": 2,
|
|
106
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
107
|
+
"correlation_id": "61cdf8f3-3702-4342-ad25-aaa7146f4e85",
|
|
108
|
+
"action_id": "61cdf8f3-3702-4342-ad25-aaa7146f4e85",
|
|
109
|
+
"association": "internal"
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"trace_context": {
|
|
113
|
+
"supported": false,
|
|
114
|
+
"trace_id": null,
|
|
115
|
+
"markers": []
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"selector": {
|
|
121
|
+
"text": "SETTINGS"
|
|
122
|
+
},
|
|
123
|
+
"waitForCondition": "exists",
|
|
124
|
+
"status": "PASS",
|
|
125
|
+
"failure_code": null,
|
|
126
|
+
"resolved_target": {
|
|
127
|
+
"elementId": "el_9b12a59a90203e47349f1943",
|
|
128
|
+
"text": null,
|
|
129
|
+
"resource_id": null,
|
|
130
|
+
"accessibility_id": null,
|
|
131
|
+
"class": "android.view.View",
|
|
132
|
+
"bounds": [
|
|
133
|
+
476,
|
|
134
|
+
1408,
|
|
135
|
+
708,
|
|
136
|
+
1528
|
|
137
|
+
],
|
|
138
|
+
"index": 12,
|
|
139
|
+
"state": {
|
|
140
|
+
"checked": false,
|
|
141
|
+
"selected": true,
|
|
142
|
+
"focused": false,
|
|
143
|
+
"enabled": true
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"evidence": {
|
|
147
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
148
|
+
"correlation_id": "4f52aadc-2249-47f0-8149-781123a3e765",
|
|
149
|
+
"action_id": "4f52aadc-2249-47f0-8149-781123a3e765",
|
|
150
|
+
"device": {
|
|
151
|
+
"platform": "android",
|
|
152
|
+
"id": "emulator-5554"
|
|
153
|
+
},
|
|
154
|
+
"association": "self",
|
|
155
|
+
"association_reason": null,
|
|
156
|
+
"operation_started_at_ms": 1793351696337,
|
|
157
|
+
"operation_completed_at_ms": 1793351699045,
|
|
158
|
+
"dispatch_started_at_ms": 1793351698985,
|
|
159
|
+
"dispatch_completed_at_ms": 1793351699045,
|
|
160
|
+
"verification_completed_at_ms": null,
|
|
161
|
+
"observations": [
|
|
162
|
+
{
|
|
163
|
+
"evidence_id": "35f26191-7b0f-466e-90b0-1cf22f9b03ac",
|
|
164
|
+
"kind": "ui_tree",
|
|
165
|
+
"status": "captured",
|
|
166
|
+
"capture_started_at_ms": 1793351696577,
|
|
167
|
+
"capture_completed_at_ms": 1793351698724,
|
|
168
|
+
"source_captured_at_ms": 1793351698724,
|
|
169
|
+
"age_ms": 321.01416015625,
|
|
170
|
+
"freshness": "stale",
|
|
171
|
+
"freshness_reasons": [
|
|
172
|
+
"BEFORE_ACTION"
|
|
173
|
+
],
|
|
174
|
+
"device": {
|
|
175
|
+
"platform": "android",
|
|
176
|
+
"id": "emulator-5554"
|
|
177
|
+
},
|
|
178
|
+
"snapshot_session_id": "9f2a6439-590e-46a5-9025-d6c828525250",
|
|
179
|
+
"snapshot_revision": 3,
|
|
180
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
181
|
+
"correlation_id": "4f52aadc-2249-47f0-8149-781123a3e765",
|
|
182
|
+
"action_id": "4f52aadc-2249-47f0-8149-781123a3e765",
|
|
183
|
+
"association": "internal"
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
"trace_context": {
|
|
187
|
+
"supported": false,
|
|
188
|
+
"trace_id": null,
|
|
189
|
+
"markers": []
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"selector": {
|
|
195
|
+
"text": "FAVOURITES"
|
|
196
|
+
},
|
|
197
|
+
"waitForCondition": "visible",
|
|
198
|
+
"status": "PASS",
|
|
199
|
+
"failure_code": null,
|
|
200
|
+
"resolved_target": {
|
|
201
|
+
"elementId": "el_25faaaa4e20f6ef0b85ab86b",
|
|
202
|
+
"text": null,
|
|
203
|
+
"resource_id": null,
|
|
204
|
+
"accessibility_id": null,
|
|
205
|
+
"class": "android.view.View",
|
|
206
|
+
"bounds": [
|
|
207
|
+
12,
|
|
208
|
+
1408,
|
|
209
|
+
244,
|
|
210
|
+
1528
|
|
211
|
+
],
|
|
212
|
+
"index": 13,
|
|
213
|
+
"state": {
|
|
214
|
+
"checked": false,
|
|
215
|
+
"selected": true,
|
|
216
|
+
"focused": false,
|
|
217
|
+
"enabled": true
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
"evidence": {
|
|
221
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
222
|
+
"correlation_id": "fbc19ace-4779-4b92-9677-11852aa6d339",
|
|
223
|
+
"action_id": "fbc19ace-4779-4b92-9677-11852aa6d339",
|
|
224
|
+
"device": {
|
|
225
|
+
"platform": "android",
|
|
226
|
+
"id": "emulator-5554"
|
|
227
|
+
},
|
|
228
|
+
"association": "self",
|
|
229
|
+
"association_reason": null,
|
|
230
|
+
"operation_started_at_ms": 1793351704414,
|
|
231
|
+
"operation_completed_at_ms": 1793351707038,
|
|
232
|
+
"dispatch_started_at_ms": 1793351706987,
|
|
233
|
+
"dispatch_completed_at_ms": 1793351707038,
|
|
234
|
+
"verification_completed_at_ms": null,
|
|
235
|
+
"observations": [
|
|
236
|
+
{
|
|
237
|
+
"evidence_id": "489de2e9-21fe-405d-a680-3d56ece84aae",
|
|
238
|
+
"kind": "ui_tree",
|
|
239
|
+
"status": "captured",
|
|
240
|
+
"capture_started_at_ms": 1793351704599,
|
|
241
|
+
"capture_completed_at_ms": 1793351706754,
|
|
242
|
+
"source_captured_at_ms": 1793351706754,
|
|
243
|
+
"age_ms": 284.26416015625,
|
|
244
|
+
"freshness": "stale",
|
|
245
|
+
"freshness_reasons": [
|
|
246
|
+
"BEFORE_ACTION"
|
|
247
|
+
],
|
|
248
|
+
"device": {
|
|
249
|
+
"platform": "android",
|
|
250
|
+
"id": "emulator-5554"
|
|
251
|
+
},
|
|
252
|
+
"snapshot_session_id": "9f2a6439-590e-46a5-9025-d6c828525250",
|
|
253
|
+
"snapshot_revision": 4,
|
|
254
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
255
|
+
"correlation_id": "fbc19ace-4779-4b92-9677-11852aa6d339",
|
|
256
|
+
"action_id": "fbc19ace-4779-4b92-9677-11852aa6d339",
|
|
257
|
+
"association": "internal"
|
|
258
|
+
}
|
|
259
|
+
],
|
|
260
|
+
"trace_context": {
|
|
261
|
+
"supported": false,
|
|
262
|
+
"trace_id": null,
|
|
263
|
+
"markers": []
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"selector": {
|
|
269
|
+
"text": "SETTINGS"
|
|
270
|
+
},
|
|
271
|
+
"waitForCondition": "default",
|
|
272
|
+
"status": "PASS",
|
|
273
|
+
"failure_code": null,
|
|
274
|
+
"evidence": {
|
|
275
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
276
|
+
"correlation_id": "c49cac9f-dca4-4a94-a4a4-f05119db855e",
|
|
277
|
+
"action_id": "c49cac9f-dca4-4a94-a4a4-f05119db855e",
|
|
278
|
+
"device": {
|
|
279
|
+
"platform": "android",
|
|
280
|
+
"id": "emulator-5554"
|
|
281
|
+
},
|
|
282
|
+
"association": "self",
|
|
283
|
+
"association_reason": null,
|
|
284
|
+
"operation_started_at_ms": 1793351712316,
|
|
285
|
+
"operation_completed_at_ms": 1793351715175,
|
|
286
|
+
"dispatch_started_at_ms": 1793351715131,
|
|
287
|
+
"dispatch_completed_at_ms": 1793351715175,
|
|
288
|
+
"verification_completed_at_ms": null,
|
|
289
|
+
"observations": [
|
|
290
|
+
{
|
|
291
|
+
"evidence_id": "f8c8f253-3e66-456b-94be-318fb94fc868",
|
|
292
|
+
"kind": "ui_tree",
|
|
293
|
+
"status": "captured",
|
|
294
|
+
"capture_started_at_ms": 1793351712552,
|
|
295
|
+
"capture_completed_at_ms": 1793351714774,
|
|
296
|
+
"source_captured_at_ms": 1793351714774,
|
|
297
|
+
"age_ms": 400.86767578125,
|
|
298
|
+
"freshness": "stale",
|
|
299
|
+
"freshness_reasons": [
|
|
300
|
+
"BEFORE_ACTION"
|
|
301
|
+
],
|
|
302
|
+
"device": {
|
|
303
|
+
"platform": "android",
|
|
304
|
+
"id": "emulator-5554"
|
|
305
|
+
},
|
|
306
|
+
"snapshot_session_id": "9f2a6439-590e-46a5-9025-d6c828525250",
|
|
307
|
+
"snapshot_revision": 5,
|
|
308
|
+
"session_id": "35528fe5-ba92-4d62-8380-5d977d390b08",
|
|
309
|
+
"correlation_id": "c49cac9f-dca4-4a94-a4a4-f05119db855e",
|
|
310
|
+
"action_id": "c49cac9f-dca4-4a94-a4a4-f05119db855e",
|
|
311
|
+
"association": "internal"
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
"trace_context": {
|
|
315
|
+
"supported": false,
|
|
316
|
+
"trace_id": null,
|
|
317
|
+
"markers": []
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"status": "PASS",
|
|
323
|
+
"cleanup": "PASS: restored Subscription; no settings, account data, favourites or sessions changed; no streams or screenshots created",
|
|
324
|
+
"server": {
|
|
325
|
+
"name": "mobile-debug-mcp",
|
|
326
|
+
"version": "0.32.4"
|
|
327
|
+
},
|
|
328
|
+
"starting_state": "Subscription",
|
|
329
|
+
"source_base": "3701f3987940a8abc76ed893b575ed370e3fb673",
|
|
330
|
+
"interaction_build_sha256": "79cb709c20fe8775571aee92413d01f28e9f8bc97da77476c08310cc555d7c2b",
|
|
331
|
+
"fixture_version_from_same_session": {
|
|
332
|
+
"versionName": "0.3.1-dev",
|
|
333
|
+
"versionCode": 14
|
|
334
|
+
},
|
|
335
|
+
"post_suite_cleanup": "PASS: relaunched Modul8 after the general device suite and confirmed Subscription via expect_element_visible"
|
|
336
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Plan: correlated evidence
|
|
2
|
+
|
|
3
|
+
Authorisation: [intent](intent.md), then [spec](spec.md), explicitly approved by
|
|
4
|
+
“yes” and “approve” respectively in this conversation on 2026-10-29.
|
|
5
|
+
|
|
6
|
+
## Implementation
|
|
7
|
+
|
|
8
|
+
- [x] Add per-call evidence context, bounded action history, clocks/freshness/types.
|
|
9
|
+
- [x] Propagate action/journey IDs; instrument dispatch and verification phases.
|
|
10
|
+
- [x] Instrument platform observations, snapshot components, stream device ownership.
|
|
11
|
+
- [x] Register/validate actionRef; preserve compact/debug/image/log responses.
|
|
12
|
+
- [x] Add regression coverage; align tool docs, README, changelog.
|
|
13
|
+
- [x] Review contract, ownership, concurrency, and privacy; complete checks below.
|
|
14
|
+
|
|
15
|
+
Reuse async-local context, resolution, budget, and trace helpers. Node >=18
|
|
16
|
+
(package/CI requirement); use installed Node/npm/ADB/Xcode tooling. No install,
|
|
17
|
+
publish, commit, push, or device helper APK is required. Retain old response data.
|
|
18
|
+
Risks are missed nested dispatch/capture paths and incorrect stream targeting;
|
|
19
|
+
test adapter boundaries and serialization as well as the metadata helper.
|
|
20
|
+
|
|
21
|
+
## Verification
|
|
22
|
+
|
|
23
|
+
| Criteria | Check |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| 1: matching identifiers | Handler tests: compact/debug actions, screenshot/log references, journey propagation; local-server Android/iOS journeys. |
|
|
26
|
+
| 2: accurate phases | Boundary tests: conditional rejection, no verification, failure/timeout, repeated input; real action before screenshot/log collection. |
|
|
27
|
+
| 3: freshness | Controlled clock/order tests for every specified status/reason and cached source time. |
|
|
28
|
+
| 4: isolation | Concurrent call/device tests; expired/evicted/foreign-session references; stream-owned device. |
|
|
29
|
+
| 5: compatibility/resources | Partial/disabled snapshot and response serialization tests; content-free bounded history. |
|
|
30
|
+
| 6: limitations | Assert unsupported trace context and device-log clock limitations on both providers. |
|
|
31
|
+
|
|
32
|
+
Commands: focused `npx tsx test/unit/observe/correlated-evidence.test.ts`,
|
|
33
|
+
`npm run verify`, `npm run test:device`. CI uses Node 18 for lint/build/unit;
|
|
34
|
+
Android integration is manual workflow dispatch; local verify additionally checks
|
|
35
|
+
the agent plugin. Device suite coverage must be reported, not assumed.
|
|
36
|
+
|
|
37
|
+
Device journey: updated local server (record package/build), Android emulator-5554
|
|
38
|
+
and booted iPhone 17 Pro simulator. Starting state: fixture/system Settings app;
|
|
39
|
+
launch it, collect referenced screenshot and bounded logs, verify IDs, dispatch
|
|
40
|
+
and capture intervals, image/log preservation and explicit clock limitations.
|
|
41
|
+
Use fresh device discovery. Exercise disabled/partial snapshot and invalid
|
|
42
|
+
reference without changing app data. Record pass/fail/blocked/unrun plus metadata
|
|
43
|
+
in this directory; avoid saving screenshot/log contents. Restore changed settings,
|
|
44
|
+
stop only owned streams, and remove temporary test data. No settings change is
|
|
45
|
+
needed. Android log healthcheck was degraded: targeted read is the next check;
|
|
46
|
+
if unavailable, record its concrete error and verify metadata failure behaviour.
|
|
47
|
+
iOS physical-device coverage is outside existing simulator support.
|
|
48
|
+
|
|
49
|
+
## Results
|
|
50
|
+
|
|
51
|
+
Implementation and focused review completed on 2026-10-30. Review corrected
|
|
52
|
+
journey step completion/verification timestamps, explicit Android stream dispatch
|
|
53
|
+
targeting, stream cleanup ownership, and concurrent iOS screenshot filenames.
|
|
54
|
+
No outstanding findings in correlation implementation. Correlation history
|
|
55
|
+
contains no capture content; later Modul8 testing below records selector limits.
|
|
56
|
+
|
|
57
|
+
- Local runtime: Node 23.11.0 / npm 10.9.2; CI's Node 18 runtime was not run locally.
|
|
58
|
+
- Focused evidence helper and MCP handler tests: **pass**, including fake-native
|
|
59
|
+
Android/iOS dispatch, timeout/precondition failures, compact/debug serialization,
|
|
60
|
+
deferred journey verification, stream ownership, clocks, expiry, eviction,
|
|
61
|
+
concurrent devices, partial/omitted captures, and reference rejection.
|
|
62
|
+
- `npm run verify`: **pass** after review fixes (lint, build, all automated
|
|
63
|
+
unit tests, agent-plugin consistency).
|
|
64
|
+
- `npm run test:device`: **pass** on final code. Six existing screenshot/log/tree
|
|
65
|
+
smokes cover Android and iOS with automatic targeting (their output does not
|
|
66
|
+
identify each selected device); the new smoke covers rebuilt stdio-server
|
|
67
|
+
correlation on Android emulator-5554 (Android 16) and iPhone 17 Pro simulator
|
|
68
|
+
F9243BAF-62A8-4990-8A99-17F527F56FDA (iOS 26.4). This does not exercise physical
|
|
69
|
+
iOS or all interaction journeys.
|
|
70
|
+
- New real-device journeys: **pass** for Settings launch, referenced screenshot,
|
|
71
|
+
bounded logs, UI-tree acquisition, disabled snapshot components, pinned device,
|
|
72
|
+
and foreign-session rejection. Targeted Android logs succeeded despite the
|
|
73
|
+
earlier healthcheck warning. Phase times/IDs/build hashes are in
|
|
74
|
+
[device-evidence.json](device-evidence.json); no image/log content is retained.
|
|
75
|
+
- Cleanup: test-owned fake streams/files removed. No device settings or app data
|
|
76
|
+
changed; system Settings remains foreground on the emulator and simulator.
|
|
77
|
+
- Physical-device correlation, installed/published-package verification: **unrun**.
|
|
78
|
+
No release or deployment was requested.
|
|
79
|
+
|
|
80
|
+
Validation logs for this local run: `/tmp/mobile-debug-correlated-verify.log` and
|
|
81
|
+
`/tmp/mobile-debug-correlated-device.log`. The `tsx` CLI requires local IPC blocked
|
|
82
|
+
by the sandbox; required npm checks ran with approved escalation. Focused checks
|
|
83
|
+
also passed via `node --import tsx` without that socket.
|
|
84
|
+
|
|
85
|
+
## Modul8 follow-up verification — 2026-10-30
|
|
86
|
+
|
|
87
|
+
User identified the installed Modul8 app as an additional fixture. Tested the
|
|
88
|
+
rebuilt local 0.32.4 server over MCP stdio on emulator-5554 (Android 16), using
|
|
89
|
+
`com.ideamechanics.modul8.dev` version 0.3.1-dev / code 14. Started on Subscription,
|
|
90
|
+
navigated to Favourites and Gener8, and restored Subscription, confirmed by the
|
|
91
|
+
final UI tree. No settings, account/subscription data, favourites, or sessions changed.
|
|
92
|
+
|
|
93
|
+
- **Pass:** screenshot-confirmed navigation, matching action/session/correlation
|
|
94
|
+
IDs across referenced screenshots, UI trees and app-scoped logs; distinct
|
|
95
|
+
capture/dispatch/verification times; pre-action stale and post-action fresh
|
|
96
|
+
records. Device-log freshness correctly remains unknown.
|
|
97
|
+
- **Pass:** an expectation matching the current screen allowed input. Reusing the
|
|
98
|
+
Favourites revision after navigating to Gener8 returned `PRECONDITION_FAILED`
|
|
99
|
+
with null dispatch timestamps. Failed selector calls also retained null
|
|
100
|
+
dispatch/verification times and could be referenced by subsequent captures.
|
|
101
|
+
- **Fail, existing selector limits:** default `tap_element` lookup exhausted its
|
|
102
|
+
1,500ms observation budget (baseline 3701f39 has the same default). With a
|
|
103
|
+
10,000ms lookup/15,000ms action budget, the Gener8 text leaf was found but
|
|
104
|
+
rejected as `ELEMENT_NOT_INTERACTABLE`; its parent is clickable. Guarded
|
|
105
|
+
screenshot-based coordinate navigation passed. These are not correlation
|
|
106
|
+
regressions and were not changed in this follow-up.
|
|
107
|
+
- Fresh screenshots can capture a crossfade: recent acquisition does not prove
|
|
108
|
+
settled UI. No settled-state or causal-log-emission claim was made.
|
|
109
|
+
|
|
110
|
+
[modul8-evidence.json](modul8-evidence.json) retains metadata and outcomes, excluding
|
|
111
|
+
screenshots, UI text, and log contents. Temporary screenshots/client were removed.
|
|
112
|
+
Only verification documents changed; link/JSON/whitespace checks passed. Existing
|
|
113
|
+
maintainer/device results above apply to the unchanged implementation.
|
|
114
|
+
|
|
115
|
+
## Selector repair — 2026-10-30
|
|
116
|
+
|
|
117
|
+
User explicitly requested fixing the Modul8 selector failures. Lightweight bug-fix
|
|
118
|
+
path: restore existing clickable-ancestor targeting for selector taps after an
|
|
119
|
+
exists/visible wait; use the configured action budget for a single fresh lookup
|
|
120
|
+
(default 5 seconds); preserve `ACTION_TIMEOUT` on failed acquisition. Keep matching,
|
|
121
|
+
ambiguity/index rules, standalone wait results, hidden/disabled-node checks, and
|
|
122
|
+
conditional dispatch guards intact. Preserve unrelated correlated-evidence work.
|
|
123
|
+
|
|
124
|
+
- Implementation: `executeTapElement` lookup budgeting and internal tap-target
|
|
125
|
+
resolution in `waitForUIHandler`, reusing the existing ancestor helper.
|
|
126
|
+
- Regression checks: actual resolution/tap pipeline with a Modul8-shaped label
|
|
127
|
+
and clickable tab parent; default/exists/visible/clickable waits; explicit
|
|
128
|
+
timeout budget; timeout vs absence; hidden/disabled labels/parents; plain
|
|
129
|
+
labels; ambiguity; standalone wait behaviour. Focused checks **pass**.
|
|
130
|
+
- Device check: explicit manual fixture helper
|
|
131
|
+
`node --import tsx test/device/manual/interact/modul8_selector_tap.manual.ts`;
|
|
132
|
+
rebuilt server, emulator-5554, Modul8 dev. Verify default selector navigation
|
|
133
|
+
through Favourites/Gener8, exists/visible selector taps, and restored Subscription
|
|
134
|
+
using semantic assertions. **Pass**: all five selector taps and destination
|
|
135
|
+
assertions succeeded; no coordinate fallback was used. Metadata is in
|
|
136
|
+
[modul8-selector-fix-evidence.json](modul8-selector-fix-evidence.json).
|
|
137
|
+
- Final checks: `npm run verify` **pass** (65 unit files, lint/build/plugin check);
|
|
138
|
+
`npm run test:device` **pass** (7 smoke files, Android/iOS observation and
|
|
139
|
+
correlation coverage). Native selector repair verified on Android/Modul8;
|
|
140
|
+
equivalent iOS app selector navigation remains **unrun**.
|
|
141
|
+
- Focused review: matching/index/ambiguity and direct handle behaviour preserved;
|
|
142
|
+
tap-only ancestor resolution reuses the existing policy and acquisition;
|
|
143
|
+
hidden/disabled labels cannot route through an enabled parent. No outstanding
|
|
144
|
+
findings. Documentation links/JSON/whitespace checks passed.
|
|
145
|
+
- Cleanup: after the general device suite reopened system Settings, relaunched
|
|
146
|
+
Modul8 and semantically confirmed the original Subscription screen. No app data
|
|
147
|
+
or device settings changed; temporary cleanup client removed.
|
|
148
|
+
- Historical failures in `modul8-evidence.json` are retained as before-fix evidence;
|
|
149
|
+
this repair supersedes their unresolved-selector status. Validation logs:
|
|
150
|
+
`/tmp/mobile-debug-selector-fix-verify.log`, `/tmp/mobile-debug-selector-fix-device.log`.
|
|
151
|
+
|
|
152
|
+
## Remaining readiness test flake — 2026-10-30
|
|
153
|
+
|
|
154
|
+
After push 0ae7300, [run 41034943919 passed](https://github.com/clivejefferies/mobile-debug-tools/actions/runs/41034943919)
|
|
155
|
+
while [run 41034949793 failed](https://github.com/clivejefferies/mobile-debug-tools/actions/runs/41034949793)
|
|
156
|
+
on the same commit. The failure was `server/readiness.test.ts:51`, expecting four
|
|
157
|
+
reads but observing five. Real timer rounding can leave the fourth sample just
|
|
158
|
+
short of the requested stability interval, legitimately requiring another read.
|
|
159
|
+
|
|
160
|
+
Test-only repair: the sequential fixture/poll timers now advance wall and
|
|
161
|
+
monotonic clocks by exactly their requested delay. Existing exact read counts,
|
|
162
|
+
late-read/deadline rejection, state transitions, predicate observations, and
|
|
163
|
+
forced second-read timeout assertions remain intact. Clock/timer hooks are
|
|
164
|
+
restored in `finally`. No production timing or readiness behaviour changed.
|
|
165
|
+
|
|
166
|
+
- Focused check: Node 23 pass; 25 separate Node 18.20.8 test-process runs pass.
|
|
167
|
+
- Full Node 18 maintainer verification with unavailable native defaults: **pass**
|
|
168
|
+
(65 unit files, lint, build, agent-plugin consistency). Changed whitespace and
|
|
169
|
+
local document links also pass; log: `/tmp/mobile-debug-readiness-clock-verify.log`.
|
|
170
|
+
- Native device suite not repeated for this test-only change; prior runtime
|
|
171
|
+
device results remain applicable. GitHub CI requires pushing this local repair.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Specification: correlated evidence
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-29. Status: approved.
|
|
4
|
+
Source: [issue #66](https://github.com/clivejefferies/mobile-debug-tools/issues/66).
|
|
5
|
+
[Intent](intent.md) approved by “yes”; this specification approved by the
|
|
6
|
+
maintainer’s “approve” on 2026-10-29 in this conversation.
|
|
7
|
+
|
|
8
|
+
## Scope and association
|
|
9
|
+
|
|
10
|
+
Add metadata to `start_app`, `restart_app`, `tap`, `tap_element`, `swipe`,
|
|
11
|
+
`scroll_to_element`, `type_text`, `press_back`, `adjust_control`, their
|
|
12
|
+
`run_journey` execution, and internal observations. Observation coverage:
|
|
13
|
+
`capture_screenshot`, `get_ui_tree`, `get_screen_fingerprint`,
|
|
14
|
+
`capture_debug_snapshot`, `get_logs`, `read_log_stream`.
|
|
15
|
+
|
|
16
|
+
Allocate action IDs before execution; reuse them in results, traces, and nested
|
|
17
|
+
observations. Journey steps share one correlation ID but retain individual action
|
|
18
|
+
IDs. Standalone actions use their action ID as correlation ID. Independent
|
|
19
|
+
observations receive a new correlation ID without an associated action.
|
|
20
|
+
|
|
21
|
+
Observation tools accept optional `actionRef: { sessionId: string, actionId:
|
|
22
|
+
string }`; strings must contain 1–128 characters. Malformed references return
|
|
23
|
+
`INVALID_ARGUMENT` before collection. Associate only known same-session,
|
|
24
|
+
same-device actions; never infer “last action”. Unknown/expired references allow
|
|
25
|
+
independent collection, retaining the requested reference and association reason.
|
|
26
|
+
Restart changes session ID. Retain completed action records for 10 minutes,
|
|
27
|
+
maximum 1,000, evicting oldest first; active records belong to running calls.
|
|
28
|
+
|
|
29
|
+
## Response contract
|
|
30
|
+
|
|
31
|
+
Add `evidence` to the first JSON text block in compact/debug responses; snapshots
|
|
32
|
+
place it alongside `raw`/`semantic`. Preserve existing fields, image blocks,
|
|
33
|
+
ordering, IDs, timestamps, and elapsed timings. Log metadata describes the
|
|
34
|
+
following log block.
|
|
35
|
+
|
|
36
|
+
| Field | Contract |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `session_id`, `correlation_id`, `action_id` | Action ID nullable when unassociated. |
|
|
39
|
+
| `device` | Resolved platform/ID, nullable before resolution; app/PID only when resolved. UI scope is device-wide. |
|
|
40
|
+
| `association` | `self`, `explicit`, `internal`, `none`, `unavailable`. |
|
|
41
|
+
| `association_reason` | Null or `ACTION_UNAVAILABLE`, `SESSION_MISMATCH`, `DEVICE_MISMATCH`. Unavailable association has null action ID and independent correlation ID. |
|
|
42
|
+
| Phase timestamps | `operation_started_at_ms`, `operation_completed_at_ms`, `dispatch_started_at_ms`, `dispatch_completed_at_ms`, `verification_completed_at_ms`; unreached/uninstrumented phases null. |
|
|
43
|
+
| `observations` | Component records defined below. |
|
|
44
|
+
| `trace_context` | `{ supported: false, trace_id: null, markers: [] }`; future tracing can reuse these identifiers. |
|
|
45
|
+
|
|
46
|
+
Each component has unique `evidence_id`, `kind` (screenshot/ui_tree/fingerprint/
|
|
47
|
+
activity/logs), `status` (`captured`, `failed`, `omitted`),
|
|
48
|
+
`capture_started_at_ms`, `capture_completed_at_ms`, nullable
|
|
49
|
+
`source_captured_at_ms`/`age_ms`, `freshness`, and `freshness_reasons`.
|
|
50
|
+
Retain component errors and UI-tree snapshot session/revision references.
|
|
51
|
+
Snapshot components, including fallback logs, have individual acquisition intervals.
|
|
52
|
+
|
|
53
|
+
## Timing and freshness
|
|
54
|
+
|
|
55
|
+
New epoch times use server UTC milliseconds; monotonic time governs ordering,
|
|
56
|
+
durations, and retention. Clock reversal yields `CLOCK_DISCONTINUITY`, unknown
|
|
57
|
+
freshness, and null age. Acquisition intervals bound server collection, not exact
|
|
58
|
+
device frame time. Instrument actual dispatch after conditional checks;
|
|
59
|
+
multi-input actions report first start/last completion. Preserve known times on
|
|
60
|
+
failure. Verification completion includes timeout/failure, is null when skipped,
|
|
61
|
+
and never overrides verification status.
|
|
62
|
+
|
|
63
|
+
Assess freshness at response assembly:
|
|
64
|
+
|
|
65
|
+
| Evidence | Freshness / reason |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| New successful visual acquisition, no intervening known dispatch on that device | `fresh`; no guarantee the app stayed unchanged. |
|
|
68
|
+
| Before associated action’s dispatch | `stale` / `BEFORE_ACTION`. |
|
|
69
|
+
| Overlapping dispatch | `unknown` / `OVERLAPPING_ACTION`. |
|
|
70
|
+
| Superseded by later covered dispatch | `stale` / `SUPERSEDED_BY_ACTION`. |
|
|
71
|
+
| Reused observation | Preserve source time; `unknown` / `REUSED_OBSERVATION` unless supersession proves stale. |
|
|
72
|
+
| Missing timing | `unknown` / `CAPTURE_TIME_UNKNOWN`. |
|
|
73
|
+
| Failed or omitted visual component | `unknown`. |
|
|
74
|
+
| Logs / omitted logs | `unknown` / `DEVICE_CLOCK_UNVERIFIED`; omitted logs `not_applicable`. |
|
|
75
|
+
|
|
76
|
+
Unassociated observations consider known concurrent dispatches. Age uses known
|
|
77
|
+
host source capture time, otherwise null; clients choose age limits. Conditional
|
|
78
|
+
safeguards remain unchanged. Preserve device log timestamps, declaring clock
|
|
79
|
+
`device_or_unknown`, nullable earliest/latest parseable entry times, and
|
|
80
|
+
`event_time_comparable: false`. Never infer emission freshness, causality, or
|
|
81
|
+
an action-window filter from collection time.
|
|
82
|
+
|
|
83
|
+
## Targeting, resources, and compatibility
|
|
84
|
+
|
|
85
|
+
Pin snapshot components to one resolved device. References never redirect targets;
|
|
86
|
+
stream reads use their stream’s device. Unknown scope means unknown freshness
|
|
87
|
+
and no matching association. Per-call asynchronous context isolates concurrent
|
|
88
|
+
calls/devices/steps; device dispatch ordering must not serialise independent calls.
|
|
89
|
+
Snapshots remain non-atomic.
|
|
90
|
+
|
|
91
|
+
Preserve existing errors, partial results, timeouts, and cancellation support;
|
|
92
|
+
attach available metadata on failure. Add no retries, deadline extensions,
|
|
93
|
+
processes, cancellation API, artifact removal, or stream termination. Release
|
|
94
|
+
call context on completion/cancellation; existing owners clean up subprocesses
|
|
95
|
+
and streams. History stores only IDs, scope, timings, and ordering: no captured
|
|
96
|
+
content, arguments, credentials, persistence, or telemetry.
|
|
97
|
+
|
|
98
|
+
Android ADB and iOS simulators share this contract; physical iOS retains provider
|
|
99
|
+
limitations. Exclude trace capture, clock synchronisation, debugger, recovery,
|
|
100
|
+
heap dumps, and background recording.
|
|
101
|
+
|
|
102
|
+
## Acceptance and verification
|
|
103
|
+
|
|
104
|
+
1. Referenced screenshots/logs share action identifiers in compact/debug responses.
|
|
105
|
+
2. Capture, dispatch, verification, skipped phases, precondition failures, timeouts,
|
|
106
|
+
and multi-input actions have accurate distinguishable timings.
|
|
107
|
+
3. Freshness follows the table, preserving uncertainty and component outcomes.
|
|
108
|
+
4. Concurrent steps/devices, expired/mismatched references, and server restarts
|
|
109
|
+
cannot falsely associate evidence.
|
|
110
|
+
5. Partial/disabled captures preserve existing responses; history is bounded/content-free.
|
|
111
|
+
6. Platform limitations and unsupported tracing are explicit.
|
|
112
|
+
|
|
113
|
+
Affected: server schemas/serialization, dispatch hooks, observation adapters,
|
|
114
|
+
shared types/context, journeys, tests, and tool/README/changelog docs. Risks:
|
|
115
|
+
missed dispatch paths, dropped metadata, retimestamped cache, wrong stream device.
|
|
116
|
+
|
|
117
|
+
Baseline (2026-10-29): checkout 0.32.4; connected build unverified. Discovery:
|
|
118
|
+
Android 16 emulator-5554, Pixel 9 Pro, iOS 26.4 iPhone 17 Pro simulator.
|
|
119
|
+
Android compact tree: revision 1, elapsed timing, no correlation/capture metadata.
|
|
120
|
+
Discovery/Android baseline passed; iOS capture/new behaviour unrun. Android logs
|
|
121
|
+
flagged unavailable by healthcheck; targeted read needed. Post-approval checks:
|
|
122
|
+
updated-server Android/iOS journeys, deterministic failure/concurrency coverage,
|
|
123
|
+
`npm run verify`, `npm run test:device`.
|