Skip to content

ios: snapshot --observe-only can label a substituted system-alert tree as an app observation #3348

Description

@thymikee

Follow-up to #3108 (merged 2026-10-08), from the #3106 decision.

Problem

snapshot --observe-only stamps observation (an app observation made without activating the app) on a payload that may not come from the app.

RunnerTests+SnapshotExecution.swift runs the ordinary capture first (snapshotFast / snapshotRaw), then checks only that target.app.state == .runningForeground and that the process identifier is unchanged, and then sets payload.observation. But snapshotFast (RunnerTests+Snapshot.swift) first calls boundedBlockingSystemAlertSnapshot(...) and returns the SpringBoard alert tree in place of the app's tree when one is presented. The post-capture check can still pass, because a system alert doesn't change the app's process and #2696 shows XCUIApplication.state can report foreground while another surface is in front. The result is a system-alert tree labelled as an observe-only capture of the app.

The default (non-observe-only) path is fine: it discloses the substitution through systemSurface provenance. The defect is only that the observe-only contract asserts app provenance without checking which tier produced the payload.

Required behavior

Pick one, and encode it in the observe-only branch:

  • Refuse: when the capture tier substituted a system-alert or system-surface payload, return the typed observe-only-unavailable response (the existing observeOnlyUnavailableResponse()), or
  • Disclose: keep the payload but omit observation and carry the substitution provenance, so a caller can't read the payload as an app observation.

Key the decision on the tier or provenance the capture returns, not on payload contents or message text.

Done when

  • A runner unit test using systemModalProbeOverrideForTesting shows an observe-only snapshot with a presented system alert never carries observation alongside the alert tree.
  • The interaction or observation guarantee wording for observe-only states the chosen behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions