agent-device 0.21.12 → 0.21.13

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 (190) hide show
  1. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.12.apk → agent-device-android-ime-helper-0.21.13.apk} +0 -0
  2. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.13.apk.sha256 +1 -0
  3. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.12.manifest.json → agent-device-android-ime-helper-0.21.13.manifest.json} +4 -4
  4. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.12.apk → agent-device-android-snapshot-helper-0.21.13.apk} +0 -0
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk.sha256 +1 -0
  6. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.12.manifest.json → agent-device-android-snapshot-helper-0.21.13.manifest.json} +6 -6
  7. package/apple/macos-helper/Package.swift +4 -0
  8. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +3 -6
  9. package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/ScreenshotResponseTests.swift +15 -0
  10. package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +47 -1
  11. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +99 -42
  12. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/Info.plist +23 -0
  13. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +17 -0
  14. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAppScreenCapture.swift +21 -13
  15. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerScrollViewportPolicy.swift +1 -162
  16. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +0 -9
  17. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +0 -56
  18. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +0 -48
  19. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +0 -50
  20. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +22 -568
  21. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +21 -9
  22. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +0 -36
  23. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +630 -0
  24. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +18 -2236
  25. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -338
  26. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +0 -12
  27. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+GestureExecution.swift +165 -0
  28. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -24
  29. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +0 -142
  30. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +90 -39
  31. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +78 -106
  32. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +23 -2
  33. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +147 -95
  34. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +0 -209
  35. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +86 -10
  36. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollDragExecution.swift +287 -0
  37. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +1 -200
  38. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +0 -185
  39. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +75 -285
  40. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotAcquisition.swift +23 -10
  41. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +0 -78
  42. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +83 -578
  43. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +106 -0
  44. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +142 -0
  45. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +49 -78
  46. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +0 -44
  47. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +27 -97
  48. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +1 -11
  49. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +11 -87
  50. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +2 -10
  51. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +1 -1
  52. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +0 -35
  53. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +0 -31
  54. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +2 -18
  55. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +34 -52
  56. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +0 -22
  57. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +142 -0
  58. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +22 -6
  59. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +140 -20
  60. package/dist/src/absence-observation-errors.js +1 -1
  61. package/dist/src/adapter.js +1 -1
  62. package/dist/src/agent-device-client.js +1 -1
  63. package/dist/src/alert-runtime.js +1 -1
  64. package/dist/src/android-adb.d.ts +1 -1
  65. package/dist/src/app-launch.js +2 -2
  66. package/dist/src/app-log-runtime2.js +3 -3
  67. package/dist/src/app-resolution.js +2 -2
  68. package/dist/src/back-mode.js +1 -1
  69. package/dist/src/capture-disclosure.js +1 -1
  70. package/dist/src/capture.js +1 -1
  71. package/dist/src/cli-config.js +1 -1
  72. package/dist/src/cli-help.js +6 -5
  73. package/dist/src/cli-runner.js +1 -1
  74. package/dist/src/cli.js +1 -1
  75. package/dist/src/client-types.d.ts +4 -5
  76. package/dist/src/code-signature.js +1 -1
  77. package/dist/src/command-schema.js +3 -3
  78. package/dist/src/command-tools.js +3 -3
  79. package/dist/src/connection.js +1 -1
  80. package/dist/src/daemon-client-lifecycle.js +1 -1
  81. package/dist/src/daemon-resolution.js +1 -1
  82. package/dist/src/device-claim-rule.js +2 -2
  83. package/dist/src/device-input-state.d.ts +1 -1
  84. package/dist/src/device-session.js +1 -1
  85. package/dist/src/devicectl.js +1 -1
  86. package/dist/src/display-inventory.js +1 -1
  87. package/dist/src/doctor-facade.js +1 -1
  88. package/dist/src/find.js +1 -1
  89. package/dist/src/gesture-plan-types.d.ts +38 -0
  90. package/dist/src/harmonyos.js +1 -1
  91. package/dist/src/helper.js +1 -1
  92. package/dist/src/host.js +1 -1
  93. package/dist/src/install-source-network-transport.js +1 -1
  94. package/dist/src/install-source2.js +1 -1
  95. package/dist/src/interaction-ref-policy.js +1 -1
  96. package/dist/src/interaction2.js +1 -1
  97. package/dist/src/interactor-operation-catalog.js +1 -1
  98. package/dist/src/interactor.js +4 -4
  99. package/dist/src/interactor2.js +1 -1
  100. package/dist/src/internal/bin.js +1 -1
  101. package/dist/src/internal/daemon.js +2 -2
  102. package/dist/src/inventory2.js +1 -1
  103. package/dist/src/ios-snapshot-acquisition.js +1 -1
  104. package/dist/src/ios-snapshot-runtime.js +1 -1
  105. package/dist/src/limrun-runtime-dependencies.js +1 -1
  106. package/dist/src/limrun.d.ts +435 -4
  107. package/dist/src/linux.js +1 -1
  108. package/dist/src/local-interactor-operation-set.js +1 -1
  109. package/dist/src/managed-device-scope.js +1 -1
  110. package/dist/src/mechanics.js +4 -4
  111. package/dist/src/mobile-snapshot-semantics.js +1 -1
  112. package/dist/src/perf-facade.js +1 -2
  113. package/dist/src/perf-runtime-plan.js +1 -1
  114. package/dist/src/perf-target.js +2 -0
  115. package/dist/src/physical-device-apps.js +1 -0
  116. package/dist/src/physical-device-control.js +1 -1
  117. package/dist/src/platform-request-scope.js +1 -1
  118. package/dist/src/platform-runtime-operation-host.js +1 -1
  119. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  120. package/dist/src/platform-runtime-unavailable.js +1 -1
  121. package/dist/src/platform-runtime.js +1 -1
  122. package/dist/src/platform-runtime2.js +1 -1
  123. package/dist/src/provider-webdriver.js +1 -1
  124. package/dist/src/proxy.js +1 -1
  125. package/dist/src/quality-warnings.js +1 -1
  126. package/dist/src/react-native.js +1 -1
  127. package/dist/src/record-runtime.js +1 -1
  128. package/dist/src/registry.js +35 -35
  129. package/dist/src/request-admission.js +1 -1
  130. package/dist/src/request-runtime-binding.js +1 -1
  131. package/dist/src/runner-client.js +1 -1
  132. package/dist/src/runner-dev-tools-security.js +1 -1
  133. package/dist/src/runner-device-readiness.js +1 -1
  134. package/dist/src/runner-disposal.js +1 -1
  135. package/dist/src/runner-error-classification.js +3 -0
  136. package/dist/src/runner-operations-facade.js +1 -1
  137. package/dist/src/runner-presentation.js +1 -1
  138. package/dist/src/runner.js +1 -1
  139. package/dist/src/runtime.js +3 -3
  140. package/dist/src/runtime10.js +1 -1
  141. package/dist/src/runtime2.js +2 -2
  142. package/dist/src/runtime4.js +5 -5
  143. package/dist/src/runtime5.js +1 -1
  144. package/dist/src/runtime6.js +1 -1
  145. package/dist/src/runtime7.js +1 -1
  146. package/dist/src/runtime8.js +1 -1
  147. package/dist/src/runtime9.js +1 -1
  148. package/dist/src/screen-recording-admission-ledger.js +1 -1
  149. package/dist/src/screen-recording-resource-recovery.js +1 -1
  150. package/dist/src/screen-recording-transport.js +1 -1
  151. package/dist/src/screenshot-runtime.js +1 -1
  152. package/dist/src/screenshot3.js +1 -1
  153. package/dist/src/script.js +1 -1
  154. package/dist/src/scroll-command.d.ts +377 -0
  155. package/dist/src/scroll-command.js +1 -1
  156. package/dist/src/sdk-batch.js +2 -2
  157. package/dist/src/sdk-contracts.d.ts +9 -0
  158. package/dist/src/sdk-device.js +1 -1
  159. package/dist/src/sdk-selectors.d.ts +23 -726
  160. package/dist/src/selection.js +0 -0
  161. package/dist/src/selector-runtime.js +1 -1
  162. package/dist/src/semantic-index.js +1 -1
  163. package/dist/src/server.js +1 -1
  164. package/dist/src/session-observation.js +1 -1
  165. package/dist/src/session-snapshot.js +1 -1
  166. package/dist/src/session2.js +2 -2
  167. package/dist/src/simctl-facade.js +1 -1
  168. package/dist/src/simctl.js +1 -1
  169. package/dist/src/simulator-state.js +1 -1
  170. package/dist/src/simulator.js +1 -1
  171. package/dist/src/snapshot-runtime-binding.js +1 -1
  172. package/dist/src/snapshot-runtime.js +1 -1
  173. package/dist/src/snapshot-state.js +1 -1
  174. package/dist/src/snapshot4.js +1 -1
  175. package/dist/src/src7.js +1 -1
  176. package/dist/src/text-entry-focus.js +1 -1
  177. package/dist/src/tool-provider.js +1 -1
  178. package/dist/src/touch-runtime.js +1 -1
  179. package/dist/src/tree.js +1 -1
  180. package/dist/src/update-check.js +1 -1
  181. package/dist/src/version.js +1 -1
  182. package/dist/src/web2.js +1 -1
  183. package/package.json +3 -2
  184. package/server.json +2 -2
  185. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.12.apk.sha256 +0 -1
  186. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.12.apk.sha256 +0 -1
  187. package/dist/src/app-inventory.d.ts +0 -4
  188. package/dist/src/apps-simctl.js +0 -1
  189. package/dist/src/cloud-artifacts.d.ts +0 -61
  190. package/dist/src/runner-contract.js +0 -3
@@ -37,6 +37,16 @@ enum SnapshotXCTestChannelPlanState: Equatable {
37
37
  case boundedXCTestProbe
38
38
  }
39
39
 
40
+
41
+
42
+
43
+
44
+
45
+ enum SnapshotTierOutcome: Equatable {
46
+ case completed
47
+ case deadlineExhausted
48
+ }
49
+
40
50
  struct EffectiveSnapshotCapturePlan {
41
51
  let plan: [SnapshotBackendKind]
42
52
  let xCTestChannelState: SnapshotXCTestChannelPlanState
@@ -142,12 +152,6 @@ extension RunnerTests {
142
152
  return penalized == bundleId
143
153
  }
144
154
 
145
- func consumeSnapshotXCTestPenaltyWarmupExemption() -> Bool {
146
- let pending = snapshotXCTestPenaltyWarmupExemptionPending
147
- snapshotXCTestPenaltyWarmupExemptionPending = false
148
- return pending
149
- }
150
-
151
155
 
152
156
 
153
157
 
@@ -260,7 +264,7 @@ extension RunnerTests {
260
264
 
261
265
  func runSnapshotCapturePlan(
262
266
  _ plan: [SnapshotBackendKind],
263
- app: XCUIApplication,
267
+ target: SnapshotCaptureTarget,
264
268
  options: PresentationOptions,
265
269
  terminal: SnapshotCaptureTerminalPolicy,
266
270
  deadline: Date? = nil
@@ -270,7 +274,7 @@ extension RunnerTests {
270
274
  var axFailure: SnapshotCaptureFailure?
271
275
 
272
276
  let deadline = deadline ?? Date().addingTimeInterval(Self.snapshotPlanBudget)
273
- let suppressXCTestPenalty = consumeSnapshotXCTestPenaltyWarmupExemption()
277
+ let suppressXCTestPenalty = snapshotXCTestPenaltyWarmupExemption.consume()
274
278
 
275
279
 
276
280
 
@@ -281,7 +285,7 @@ extension RunnerTests {
281
285
  var xCTestChannelPenalized = false
282
286
  var xCTestChannelPenalizedByBreaker = false
283
287
  #if os(iOS)
284
- xCTestChannelPenalizedByBreaker = isSnapshotXCTestChannelPenalized(bundleId: currentBundleId)
288
+ xCTestChannelPenalizedByBreaker = isSnapshotXCTestChannelPenalized(bundleId: target.bundleId)
285
289
  xCTestChannelPenalized = Self.snapshotXCTestChannelTreatedAsPenalized(
286
290
  penalized: xCTestChannelPenalizedByBreaker,
287
291
  preferredBackend: options.preferredBackend
@@ -305,9 +309,9 @@ extension RunnerTests {
305
309
  case .normal:
306
310
  break
307
311
  case .deferredToIndependentBackend:
308
- NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_XCTEST_CHANNEL_DEFERRED bundle=%@", currentBundleId ?? "")
312
+ NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_XCTEST_CHANNEL_DEFERRED bundle=%@", target.bundleId ?? "")
309
313
  case .boundedXCTestProbe:
310
- NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_XCTEST_CHANNEL_PROBE_BOUNDED bundle=%@", currentBundleId ?? "")
314
+ NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_XCTEST_CHANNEL_PROBE_BOUNDED bundle=%@", target.bundleId ?? "")
311
315
  }
312
316
 
313
317
  for kind in effectivePlan {
@@ -332,7 +336,7 @@ extension RunnerTests {
332
336
  }
333
337
  let attempt = try captureWithBackend(
334
338
  kind,
335
- app: app,
339
+ target: target,
336
340
  options: options,
337
341
  deadline: deadline,
338
342
  treeCaptureSliceBudgetOverride: effective.treeCaptureSliceBudgetOverride
@@ -340,6 +344,7 @@ extension RunnerTests {
340
344
  recordXCTestSnapshotBackendAttemptIfNeeded(
341
345
  kind,
342
346
  attempt: attempt,
347
+ bundleId: target.bundleId,
343
348
  penaltySuppressed: suppressXCTestPenalty
344
349
  )
345
350
  if case let .failed(failure, phase: _) = attempt.outcome {
@@ -356,8 +361,19 @@ extension RunnerTests {
356
361
  }
357
362
  guard case let .captured(capture) = attempt.outcome else { continue }
358
363
 
359
- if let sparseReason = Self.sparsePayloadReason(capture.qualityPayload ?? capture.payload) {
360
- if firstFailure == nil { firstFailure = sparseReason }
364
+ if attempt.tierOutcome == .deadlineExhausted {
365
+ NSLog(
366
+ "AGENT_DEVICE_RUNNER_SNAPSHOT_TIER_DEADLINE_EXHAUSTED backend=%@ nodes=%d",
367
+ kind.rawValue,
368
+ Self.payloadNodeCount(capture.payload)
369
+ )
370
+ }
371
+ if let rejection = Self.snapshotTierRejectionReason(
372
+ outcome: attempt.tierOutcome,
373
+ kind: kind,
374
+ payload: capture.qualityPayload ?? capture.payload
375
+ ) {
376
+ if firstFailure == nil { firstFailure = rejection }
361
377
  if Self.payloadNodeCount(capture.payload) > Self.payloadNodeCount(best?.capture.payload) {
362
378
  best = (kind, capture)
363
379
  }
@@ -412,19 +428,21 @@ extension RunnerTests {
412
428
 
413
429
  private func captureWithBackend(
414
430
  _ kind: SnapshotBackendKind,
415
- app: XCUIApplication,
431
+ target: SnapshotCaptureTarget,
416
432
  options: PresentationOptions,
417
433
  deadline: Date,
418
434
  treeCaptureSliceBudgetOverride: TimeInterval?
419
435
  ) throws -> SnapshotBackendAttempt {
436
+ let app = target.app
420
437
  let hint = SnapshotPresentation.captureHint(for: options)
421
438
  var timer = SnapshotPhaseTimer()
422
439
  let acquisition: SnapshotAcquisition?
440
+ let tierOutcome: SnapshotTierOutcome
423
441
 
424
442
 
425
443
  var keyboardBand: RunnerKeyboardBandFact?
426
444
  do {
427
- acquisition = try timer.measure(.acquisition) {
445
+ let measured = try timer.measure(.acquisition) { () -> (SnapshotAcquisition?, SnapshotTierOutcome) in
428
446
  switch kind {
429
447
  case .recursiveTree:
430
448
  guard
@@ -435,10 +453,10 @@ extension RunnerTests {
435
453
  treeCaptureSliceBudgetOverride: treeCaptureSliceBudgetOverride
436
454
  )
437
455
  else {
438
- return nil
456
+ return (nil, .completed)
439
457
  }
440
458
  keyboardBand = context.keyboardBand
441
- return try self.runMainThreadWork(
459
+ let tree = try self.runMainThreadWork(
442
460
  "tree_processing",
443
461
  timeout: min(self.treeCaptureSliceBudget, max(0.5, deadline.timeIntervalSinceNow)),
444
462
  timeoutError: self.snapshotMainThreadTimeoutError("processing tree snapshot")
@@ -447,26 +465,34 @@ extension RunnerTests {
447
465
  ? try self.rawTreeSnapshotAcquisition(context: context, hint: hint)
448
466
  : try self.recursiveTreeSnapshotAcquisition(context: context, hint: hint)
449
467
  }
468
+ return (tree, .completed)
450
469
  case .querySweep:
451
- return try self.runMainThreadWork(
470
+ let sliceDeadline = Self.querySweepSliceDeadline(startedAt: Date(), planDeadline: deadline)
471
+ let sweep = try self.runMainThreadWork(
452
472
  "query_sweep",
453
- timeout: min(Self.flatInteractiveFallbackBudget, max(0.1, deadline.timeIntervalSinceNow)),
473
+ timeout: max(0.1, sliceDeadline.timeIntervalSinceNow),
454
474
  timeoutError: self.snapshotMainThreadTimeoutError("running query-sweep snapshot")
455
475
  ) {
456
476
  self.querySweepSnapshotAcquisition(
457
477
  app: app,
458
478
  hint: hint,
459
- planDeadline: deadline
479
+ sliceDeadline: sliceDeadline
460
480
  )
461
481
  }
482
+ return (sweep.acquisition, sweep.outcome)
462
483
  case .privateAX:
463
- return self.privateAXSnapshotAcquisition(
464
- app: app,
465
- hint: hint,
466
- deadline: deadline
484
+ return (
485
+ self.privateAXSnapshotAcquisition(
486
+ target: target,
487
+ hint: hint,
488
+ deadline: deadline
489
+ ),
490
+ .completed
467
491
  )
468
492
  }
469
493
  }
494
+ acquisition = measured.0
495
+ tierOutcome = measured.1
470
496
  } catch let failure as SnapshotCaptureFailure {
471
497
  return SnapshotBackendAttempt(
472
498
  outcome: .failed(failure, phase: .acquisition),
@@ -476,7 +502,8 @@ extension RunnerTests {
476
502
  guard let acquisition else {
477
503
  return SnapshotBackendAttempt(
478
504
  outcome: .noCapture,
479
- timing: timer.timing
505
+ timing: timer.timing,
506
+ tierOutcome: tierOutcome
480
507
  )
481
508
  }
482
509
 
@@ -511,12 +538,14 @@ extension RunnerTests {
511
538
  } catch let failure as SnapshotPresentationFailure {
512
539
  return SnapshotBackendAttempt(
513
540
  outcome: .failed(Self.snapshotCaptureFailure(for: failure), phase: .presentation),
514
- timing: timer.timing
541
+ timing: timer.timing,
542
+ tierOutcome: tierOutcome
515
543
  )
516
544
  } catch let failure as SnapshotCaptureFailure {
517
545
  return SnapshotBackendAttempt(
518
546
  outcome: .failed(failure, phase: .presentation),
519
- timing: timer.timing
547
+ timing: timer.timing,
548
+ tierOutcome: tierOutcome
520
549
  )
521
550
  }
522
551
 
@@ -525,7 +554,8 @@ extension RunnerTests {
525
554
  capture.keyboardBand = keyboardBand?.payload
526
555
  return SnapshotBackendAttempt(
527
556
  outcome: .captured(capture),
528
- timing: timer.timing
557
+ timing: timer.timing,
558
+ tierOutcome: tierOutcome
529
559
  )
530
560
  }
531
561
 
@@ -547,6 +577,24 @@ extension RunnerTests {
547
577
 
548
578
 
549
579
 
580
+
581
+
582
+
583
+ static func snapshotTierRejectionReason(
584
+ outcome: SnapshotTierOutcome,
585
+ kind: SnapshotBackendKind,
586
+ payload: DataPayload
587
+ ) -> (reason: String, code: String)? {
588
+ if outcome == .deadlineExhausted {
589
+ return (
590
+ "the \(kind.rawValue) backend spent its capture slice with the collection unfinished",
591
+ "budget"
592
+ )
593
+ }
594
+ return sparsePayloadReason(payload)
595
+ }
596
+
597
+
550
598
  static func sparsePayloadReason(_ payload: DataPayload) -> (reason: String, code: String)? {
551
599
  guard let nodes = payload.nodes, !nodes.isEmpty else {
552
600
  return ("snapshot returned no nodes", "no-nodes")
@@ -629,13 +677,16 @@ extension RunnerTests {
629
677
 
630
678
 
631
679
 
632
- private func stampedSnapshotPayload(
680
+ func stampedSnapshotPayload(
633
681
  _ capture: SnapshotBackendCapture,
634
682
  backend: SnapshotBackendKind,
635
683
  state: String,
636
684
  reason: (reason: String, code: String)?
637
685
  ) -> DataPayload {
638
- runnerAccessibilityHealth = reason?.code == "ax-rejected" ? .unavailable : .healthy
686
+ let health: RunnerAccessibilityHealth = reason?.code == "ax-rejected" ? .unavailable : .healthy
687
+ applyMainOwnedSnapshotState("accessibility_health") {
688
+ self.runnerAccessibilityHealth = health
689
+ }
639
690
  let payload = capture.payload
640
691
  let quality = SnapshotQuality(
641
692
  state: state,
@@ -648,8 +699,7 @@ extension RunnerTests {
648
699
  timing: capture.timing
649
700
  )
650
701
  return DataPayload(
651
-
652
- message: Self.legacyQualityMessage(quality) ?? payload.message,
702
+ message: payload.message,
653
703
  nodes: payload.nodes,
654
704
 
655
705
 
@@ -666,549 +716,4 @@ extension RunnerTests {
666
716
  runnerFatalReason: payload.runnerFatalReason
667
717
  )
668
718
  }
669
-
670
-
671
-
672
-
673
- static func customActionCoverageWarnings(_ coverage: SnapshotCustomActionCoverage) -> [String] {
674
- var lines: [String] = []
675
- if coverage.blocked {
676
-
677
-
678
- lines.append(
679
- "Custom actions were not read: an earlier accessibility read is still hung, so this "
680
- + "capture skipped the read pass instead of queueing behind it. No element's actions "
681
- + "list is authoritative here. Reads resume once that call returns.")
682
- } else if coverage.read < coverage.candidates {
683
- lines.append(
684
- "Custom actions were read for \(coverage.read) of \(coverage.candidates) merged elements, "
685
- + "on-screen ones first; the remaining \(coverage.candidates - coverage.read) were not read, "
686
- + "so an absent actions list on those is not evidence that they have none. "
687
- + "Scroll them into view and re-run to read them.")
688
- }
689
- if coverage.truncated > 0 {
690
- lines.append(
691
- "\(coverage.truncated) element(s) published more custom actions than are shown; those "
692
- + "lists are clipped to the first 8 names, and long names are shortened.")
693
- }
694
- return lines
695
- }
696
-
697
- static func legacyQualityMessage(_ quality: SnapshotQuality) -> String? {
698
- let customActionWarnings =
699
- quality.customActions.map { Self.customActionCoverageWarnings($0) } ?? []
700
- guard quality.state != "healthy" || quality.collapsedLeafIndexes != nil
701
- || !customActionWarnings.isEmpty
702
- else { return nil }
703
- var parts: [String] = []
704
- if quality.state == "recovered" {
705
- let meaning: String
706
- switch quality.reasonCode {
707
- case "budget", "deferred":
708
- meaning = " The primary capture ran out of its time budget (busy app or simulator); the recovered tree is authoritative for this screen."
709
- case "presentation-failed":
710
- meaning = " The runner rejected a regular presentation because its cumulative clip invariant failed; report this as a runner bug and treat screenshot as visual truth."
711
- default:
712
- meaning = " This usually means the app publishes an unhealthy accessibility tree — fixing the app's accessibility is the real cure. Treat screenshot as visual truth when this warning appears."
713
- }
714
- parts.append(
715
- "Detected an overly complex or slow accessibility tree. Fell back to the \(quality.backend) snapshot backend"
716
- + (quality.reason.map { " after: \($0)." } ?? ".")
717
- + meaning
718
- )
719
- }
720
- if quality.state == "sparse" {
721
- parts.append(
722
- "No snapshot backend could read this screen"
723
- + (quality.reason.map { " (\($0))" } ?? "")
724
- + ". Use screenshot as visual truth and coordinate taps."
725
- )
726
- }
727
- parts.append(contentsOf: customActionWarnings)
728
- if let depth = quality.effectiveDepth {
729
-
730
-
731
-
732
- parts.append(
733
- "The accessibility server rejected deeper requests; content below depth \(depth) may be missing — re-run snapshot to retry deeper content."
734
- )
735
- }
736
- return parts.isEmpty ? nil : parts.joined(separator: " ")
737
- }
738
719
  }
739
-
740
-
741
-
742
-
743
-
744
-
745
-
746
-
747
-
748
-
749
-
750
-
751
-
752
-
753
-
754
-
755
-
756
-
757
-
758
-
759
-
760
-
761
-
762
-
763
-
764
-
765
-
766
-
767
-
768
-
769
-
770
-
771
-
772
-
773
-
774
-
775
-
776
-
777
-
778
-
779
-
780
-
781
-
782
-
783
-
784
-
785
-
786
-
787
-
788
-
789
-
790
-
791
-
792
-
793
-
794
-
795
-
796
-
797
-
798
-
799
-
800
-
801
-
802
-
803
-
804
-
805
-
806
-
807
-
808
-
809
-
810
-
811
-
812
-
813
-
814
-
815
-
816
-
817
-
818
-
819
-
820
-
821
-
822
-
823
-
824
-
825
-
826
-
827
-
828
-
829
-
830
-
831
-
832
-
833
-
834
-
835
-
836
-
837
-
838
-
839
-
840
-
841
-
842
-
843
-
844
-
845
-
846
-
847
-
848
-
849
-
850
-
851
-
852
-
853
-
854
-
855
-
856
-
857
-
858
-
859
-
860
-
861
-
862
-
863
-
864
-
865
-
866
-
867
-
868
-
869
-
870
-
871
-
872
-
873
-
874
-
875
-
876
-
877
-
878
-
879
-
880
-
881
-
882
-
883
-
884
-
885
-
886
-
887
-
888
-
889
-
890
-
891
-
892
-
893
-
894
-
895
-
896
-
897
-
898
-
899
-
900
-
901
-
902
-
903
-
904
-
905
-
906
-
907
-
908
-
909
-
910
-
911
-
912
-
913
-
914
-
915
-
916
-
917
-
918
-
919
-
920
-
921
-
922
-
923
-
924
-
925
-
926
-
927
-
928
-
929
-
930
-
931
-
932
-
933
-
934
-
935
-
936
-
937
-
938
-
939
-
940
-
941
-
942
-
943
-
944
-
945
-
946
-
947
-
948
-
949
-
950
-
951
-
952
-
953
-
954
-
955
-
956
-
957
-
958
-
959
-
960
-
961
-
962
-
963
-
964
-
965
-
966
-
967
-
968
-
969
-
970
-
971
-
972
-
973
-
974
-
975
-
976
-
977
-
978
-
979
-
980
-
981
-
982
-
983
-
984
-
985
-
986
-
987
-
988
-
989
-
990
-
991
-
992
-
993
-
994
-
995
-
996
-
997
-
998
-
999
-
1000
-
1001
-
1002
-
1003
-
1004
-
1005
-
1006
-
1007
-
1008
-
1009
-
1010
-
1011
-
1012
-
1013
-
1014
-
1015
-
1016
-
1017
-
1018
-
1019
-
1020
-
1021
-
1022
-
1023
-
1024
-
1025
-
1026
-
1027
-
1028
-
1029
-
1030
-
1031
-
1032
-
1033
-
1034
-
1035
-
1036
-
1037
-
1038
-
1039
-
1040
-
1041
-
1042
-
1043
-
1044
-
1045
-
1046
-
1047
-
1048
-
1049
-
1050
-
1051
-
1052
-
1053
-
1054
-
1055
-
1056
-
1057
-
1058
-
1059
-
1060
-
1061
-
1062
-
1063
-
1064
-
1065
-
1066
-
1067
-
1068
-
1069
-
1070
-
1071
-
1072
-
1073
-
1074
-
1075
-
1076
-
1077
-
1078
-
1079
-
1080
-
1081
-
1082
-
1083
-
1084
-
1085
-
1086
-
1087
-
1088
-
1089
-
1090
-
1091
-
1092
-
1093
-
1094
-
1095
-
1096
-
1097
-
1098
-
1099
-
1100
-
1101
-
1102
-
1103
-
1104
-
1105
-
1106
-
1107
-
1108
-
1109
-
1110
-
1111
-
1112
-
1113
-
1114
-
1115
-
1116
-
1117
-
1118
-
1119
-
1120
-
1121
-
1122
-
1123
-
1124
-
1125
-
1126
-
1127
-
1128
-
1129
-
1130
-
1131
-
1132
-
1133
-
1134
-
1135
-
1136
-
1137
-
1138
-
1139
-
1140
-
1141
-
1142
-
1143
-
1144
-
1145
-
1146
-
1147
-
1148
-
1149
-
1150
-
1151
-
1152
-
1153
-
1154
-
1155
-
1156
-
1157
-
1158
-
1159
-
1160
-
1161
-
1162
-
1163
-
1164
-
1165
-
1166
-
1167
-
1168
-
1169
-
1170
-
1171
-
1172
-
1173
-
1174
-
1175
-
1176
-
1177
-
1178
-
1179
-
1180
-
1181
-
1182
-
1183
-
1184
-
1185
-
1186
-
1187
-
1188
-
1189
-
1190
-
1191
-
1192
-
1193
-
1194
-
1195
-
1196
-
1197
-
1198
-
1199
-
1200
-
1201
-
1202
-
1203
-
1204
-
1205
-
1206
-
1207
-
1208
-
1209
-
1210
-
1211
-
1212
-
1213
-
1214
-