Split out of #2682 / PR #2693 by adversarial review.
What is already shipped
The Apple runner stamps targetActivation on the response of every accepted command that had to re-activate the session app (RunnerTests+CommandExecution.swift, executeAccepted). PR #2691 decodes it for captures; PR #2693 discloses it on the daemon routes that consumed a capture: snapshot, find, get, is, wait, and an interaction whose target tree was captured for it.
The gap
A command that consumes no capture — press <x> <y>, or press @ref answered from a live ref frame — still answers with no disclosure even when the runner paid for a foreground repair to serve it. The stamp is on that command's runner response and is dropped at the Apple interaction projection: only packages/platform-apple/src/runner/snapshot-presentation.ts decodes it today.
This is the ADR 0012 category: a repair happened and the response does not say so. Silence must not be read as "no repair". website/docs/docs/commands.md ("Foreground repairs on iOS") states that boundary until this closes.
Shape of the fix
- Decode the stamped fact where runner responses are read for every command, not just snapshots:
packages/platform-apple/src/runner/runner-session.ts (the shared parseRunnerResponse seam that already reads the runnerMainThreadBusy stamp) plus whatever per-command projection needs to let it through.
- Give interaction results a carrier to the daemon response for it, and append the disclosure through
buildInteractionResponseData (the shared interaction response builder) so no interaction verb can drop it.
- Cover both commands in the live lane
test/integration/smoke-ios-target-activation.test.ts (now wired into ios.yml and replays-manual.yml), which asserts the disclosure for capture-consuming commands today.
Acceptance
press <x> <y> and press @ref after an off-app handoff each carry targetActivation and the appended warning for the repair they paid for.
- A command that performed no repair stays silent, and the docs' claim is inverted from "stays silent" back to "silence means no repair" — the current wording must be updated in the same PR that closes this.
Not in scope
Foreground ownership: otherActiveApplicationPid remains a liveness claim; activeApplications exposes no ordering, so no field here proves which app owned the screen.
Split out of #2682 / PR #2693 by adversarial review.
What is already shipped
The Apple runner stamps
targetActivationon the response of every accepted command that had to re-activate the session app (RunnerTests+CommandExecution.swift,executeAccepted). PR #2691 decodes it for captures; PR #2693 discloses it on the daemon routes that consumed a capture:snapshot,find,get,is,wait, and an interaction whose target tree was captured for it.The gap
A command that consumes no capture —
press <x> <y>, orpress @refanswered from a live ref frame — still answers with no disclosure even when the runner paid for a foreground repair to serve it. The stamp is on that command's runner response and is dropped at the Apple interaction projection: onlypackages/platform-apple/src/runner/snapshot-presentation.tsdecodes it today.This is the ADR 0012 category: a repair happened and the response does not say so. Silence must not be read as "no repair".
website/docs/docs/commands.md("Foreground repairs on iOS") states that boundary until this closes.Shape of the fix
packages/platform-apple/src/runner/runner-session.ts(the sharedparseRunnerResponseseam that already reads therunnerMainThreadBusystamp) plus whatever per-command projection needs to let it through.buildInteractionResponseData(the shared interaction response builder) so no interaction verb can drop it.test/integration/smoke-ios-target-activation.test.ts(now wired intoios.ymlandreplays-manual.yml), which asserts the disclosure for capture-consuming commands today.Acceptance
press <x> <y>andpress @refafter an off-app handoff each carrytargetActivationand the appended warning for the repair they paid for.Not in scope
Foreground ownership:
otherActiveApplicationPidremains a liveness claim;activeApplicationsexposes no ordering, so no field here proves which app owned the screen.