diff --git a/.device-evidence/CHECKLIST-runner-failures.md b/.device-evidence/CHECKLIST-runner-failures.md index cc94966a48..b69fcb13c4 100644 --- a/.device-evidence/CHECKLIST-runner-failures.md +++ b/.device-evidence/CHECKLIST-runner-failures.md @@ -268,7 +268,7 @@ diagnostic a row keys on. `runner-startup-failure-fixtures.ts` so the rows read as host-gated, not unexamined. #2680 §4 needs a build that fails for an unrelated reason while naming no signing fact; the -classifier's behaviour there is pinned by `runner-startup-failure-reasons.test.ts` and needs no +classifier's behaviour there is pinned by `runner-xctestrun-startup-failure-reasons.test.ts` and needs no device claim to hold. ### #2683 — what the phone actually reported diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 38d3deff41..9c3f5de1d9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -168,7 +168,7 @@ jobs: run: | pnpm build pnpm exec vitest run \ - packages/platform-apple/src/snapshot-source/native-runtime.test.ts \ + packages/platform-apple/src/snapshot-source/cache-native-runtime.test.ts \ packages/platform-apple/src/foldable/fold-helper-cache.test.ts \ packages/platform-apple/src/foldable/simulator-hid-native.test.ts \ packages/capture-kit/src/recording/__tests__/recording-scripts.test.ts diff --git a/contracts/fixtures/runner-requests.json b/contracts/fixtures/runner-requests.json index c5586e3c26..2345dbb582 100644 --- a/contracts/fixtures/runner-requests.json +++ b/contracts/fixtures/runner-requests.json @@ -1,73 +1,73 @@ [ - {"name": "ios-device.physical-device-control.activate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "activate", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-device.physical-device-control.terminate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "terminate", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-device.physical-device-screenshot.coredevice-file", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, - {"name": "ios-device.physical-device-screenshot.xctest-inline", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "inlineScreenshot": true, "commandId": ""}}, + {"name": "ios-device.physical-device-control.activate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "activate", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-device.physical-device-control.terminate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "terminate", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-device.physical-device-screenshot.coredevice-file", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, + {"name": "ios-device.physical-device-screenshot.xctest-inline", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "inlineScreenshot": true, "commandId": ""}}, {"name": "ios-device.recording-start-abort.stop", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStop", "appBundleId": "com.example.app"}}, {"name": "ios-device.recording-start.fps", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStart", "outPath": "agent-device-recording-1700000000000.mp4", "fps": 30, "appBundleId": "com.example.app"}}, {"name": "ios-device.recording-stop.no-app", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStop"}}, {"name": "ios-device.recording-stop.session", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStop", "appBundleId": "com.example.app"}}, - {"name": "ios-simulator.alert.accept", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "alert", "action": "accept", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, - {"name": "ios-simulator.alert.dismiss", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "alert", "action": "dismiss", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, - {"name": "ios-simulator.alert.get", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "alert", "action": "get", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, - {"name": "ios-simulator.interactions-double-tap.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-fill.non-hittable-fallback", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "textEntryMode": "replace", "allowNonHittableCoordinateFallback": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-fill.replace", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "delayMs": 10, "textEntryMode": "replace", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-focus.synthesized", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-gesture-viewport.read", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "gestureViewport", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-gesture.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "single", "intent": "pan", "executionProfile": "timed-pan", "durationMs": 120, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 100, "y": 400}}, {"offsetMs": 120, "point": {"x": 100, "y": 200}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-gesture.two", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "two", "intent": "pinch", "durationMs": 250, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 150, "y": 422}}, {"offsetMs": 250, "point": {"x": 100, "y": 422}}]}, {"pointerId": 1, "samples": [{"offsetMs": 0, "point": {"x": 240, "y": 422}}, {"offsetMs": 250, "point": {"x": 290, "y": 422}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-long-press.duration", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-press-series.double-tap", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20, "pauseMs": 50}, {"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-press-series.long-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "longPress", "x": 10, "y": 20, "durationMs": 600, "pauseMs": 50}, {"kind": "longPress", "x": 10, "y": 20, "durationMs": 600}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-press-series.tap", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "tap", "x": 10, "y": 20, "synthesized": true, "pauseMs": 50}, {"kind": "tap", "x": 10, "y": 20, "synthesized": true}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-scroll.amount", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "scroll", "direction": "down", "amount": 0.65, "durationMs": 400, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-scroll.inertial", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "scroll", "direction": "left", "amount": 0.5, "durationMs": 400, "scrollReleaseBehavior": "inertial", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "scroll", "direction": "up", "pixels": 200, "durationMs": 300, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-single-press-double-tap.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-single-press-long-press.hold", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-single-press-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-tap-element-selector.expected-point", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "selectorKey": "label", "selectorValue": "Go", "allowNonHittableCoordinateFallback": true, "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-type.append", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "text": "hello", "delayMs": 10, "textEntryMode": "append", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-type.newline", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "text": "\n", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-action-button.press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "actionButton", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-app-state.read", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "appState", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-app-switcher.open", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "appSwitcher", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-back.in-app", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "backInApp", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-back.system", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "backSystem", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-find-text.text", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "findText", "text": "Ready", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-home.press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "home", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-keyboard-dismiss.dismiss", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "keyboardDismiss", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-keyboard-enter.return", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "keyboardReturn", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-read-text.point", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "readText", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-set-orientation.rotate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "rotate", "orientation": "landscape-left", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-snapshot.every-option", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "interactiveOnly": true, "preferredBackend": "tree", "customActions": true, "depth": 3, "scope": "Go", "raw": true, "commandId": ""}}, - {"name": "ios-simulator.interactor-snapshot.observe-only", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "observeOnly": true, "commandId": ""}}, - {"name": "ios-simulator.interactor-write-clipboard.text", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "pasteboardWrite", "text": "one-time code 246810", "commandId": ""}}, + {"name": "ios-simulator.alert.accept", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "alert", "action": "accept", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, + {"name": "ios-simulator.alert.dismiss", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "alert", "action": "dismiss", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, + {"name": "ios-simulator.alert.get", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "alert", "action": "get", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, + {"name": "ios-simulator.interactions-double-tap.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-fill.non-hittable-fallback", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "textEntryMode": "replace", "allowNonHittableCoordinateFallback": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-fill.replace", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "delayMs": 10, "textEntryMode": "replace", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-focus.synthesized", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-gesture-viewport.read", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "gestureViewport", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-gesture.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "single", "intent": "pan", "executionProfile": "timed-pan", "durationMs": 120, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 100, "y": 400}}, {"offsetMs": 120, "point": {"x": 100, "y": 200}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-gesture.two", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "two", "intent": "pinch", "durationMs": 250, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 150, "y": 422}}, {"offsetMs": 250, "point": {"x": 100, "y": 422}}]}, {"pointerId": 1, "samples": [{"offsetMs": 0, "point": {"x": 240, "y": 422}}, {"offsetMs": 250, "point": {"x": 290, "y": 422}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-long-press.duration", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-press-series.double-tap", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20, "pauseMs": 50}, {"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-press-series.long-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "longPress", "x": 10, "y": 20, "durationMs": 600, "pauseMs": 50}, {"kind": "longPress", "x": 10, "y": 20, "durationMs": 600}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-press-series.tap", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "tap", "x": 10, "y": 20, "synthesized": true, "pauseMs": 50}, {"kind": "tap", "x": 10, "y": 20, "synthesized": true}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-scroll.amount", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "scroll", "direction": "down", "amount": 0.65, "durationMs": 400, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-scroll.inertial", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "scroll", "direction": "left", "amount": 0.5, "durationMs": 400, "scrollReleaseBehavior": "inertial", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "scroll", "direction": "up", "pixels": 200, "durationMs": 300, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-single-press-double-tap.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-single-press-long-press.hold", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-single-press-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-tap-element-selector.expected-point", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "selectorKey": "label", "selectorValue": "Go", "allowNonHittableCoordinateFallback": true, "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-type.append", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "text": "hello", "delayMs": 10, "textEntryMode": "append", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-type.newline", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "text": "\n", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-action-button.press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "actionButton", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-app-state.read", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "appState", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-app-switcher.open", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "appSwitcher", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-back.in-app", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "backInApp", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-back.system", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "backSystem", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-find-text.text", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "findText", "text": "Ready", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-home.press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "home", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-keyboard-dismiss.dismiss", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "keyboardDismiss", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-keyboard-enter.return", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "keyboardReturn", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-read-text.point", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "readText", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-set-orientation.rotate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "rotate", "orientation": "landscape-left", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-snapshot.every-option", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "interactiveOnly": true, "preferredBackend": "tree", "customActions": true, "depth": 3, "scope": "Go", "raw": true, "commandId": ""}}, + {"name": "ios-simulator.interactor-snapshot.observe-only", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "observeOnly": true, "commandId": ""}}, + {"name": "ios-simulator.interactor-write-clipboard.text", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "pasteboardWrite", "text": "one-time code 246810", "commandId": ""}}, {"name": "ios-simulator.recording-clock-anchor.snapshot", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "interactiveOnly": true, "depth": 1}}, {"name": "ios-simulator.recording-start.default", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStart", "outPath": "capture.mp4", "appBundleId": "com.example.app"}}, - {"name": "ios-simulator.runner-adoption.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "ios-simulator.runner-client-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "ios-simulator.runner-client-target-reset.relaunch", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "targetReset", "commandId": ""}}, - {"name": "ios-simulator.runner-command-recovery.status", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "status", "statusCommandId": ""}}, - {"name": "ios-simulator.runner-disposal.shutdown", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "shutdown", "commandId": ""}}, - {"name": "ios-simulator.runner-lifecycle-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "ios-simulator.runner-selector-query.label", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "querySelector", "selectorKey": "label", "selectorValue": "Go", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.runner-session-readiness.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "macos.desktop-scroll.amount", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "down", "amount": 0.5, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.desktop-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "up", "pixels": 200, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-drag.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "drag", "x": 100, "y": 400, "x2": 100, "y2": 200, "durationMs": 120, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-focus.coordinate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-mouse-click.middle", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "middle", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-mouse-click.secondary", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "secondary", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-single-press-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.runner-adoption.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "ios-simulator.runner-client-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "ios-simulator.runner-client-target-reset.relaunch", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "targetReset", "commandId": ""}}, + {"name": "ios-simulator.runner-command-recovery.status", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "status", "statusCommandId": ""}}, + {"name": "ios-simulator.runner-disposal.shutdown", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "shutdown", "commandId": ""}}, + {"name": "ios-simulator.runner-lifecycle-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "ios-simulator.runner-selector-query.label", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "querySelector", "selectorKey": "label", "selectorValue": "Go", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.runner-session-readiness.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "macos.desktop-scroll.amount", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "down", "amount": 0.5, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.desktop-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "up", "pixels": 200, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-drag.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "drag", "x": 100, "y": 400, "x2": 100, "y2": 200, "durationMs": 120, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-focus.coordinate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-mouse-click.middle", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "middle", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-mouse-click.secondary", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "secondary", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-single-press-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, {"name": "macos.recording-start.output-path", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStart", "outPath": "/tmp/capture.mp4", "appBundleId": "com.example.app"}}, - {"name": "macos.screenshot-runner.fullscreen", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, - {"name": "tvos.interactions-scroll.remote-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "down", "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactions-swipe.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "swipe", "direction": "up", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactor-back.remote-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "menu", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactor-home.remote-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "home", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactor-tv-remote.hold", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "select", "durationMs": 500, "appBundleId": "com.example.app", "commandId": ""}} + {"name": "macos.screenshot-runner.fullscreen", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, + {"name": "tvos.interactions-scroll.remote-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "down", "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactions-swipe.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "swipe", "direction": "up", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactor-back.remote-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "menu", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactor-home.remote-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "home", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactor-tv-remote.hold", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "select", "durationMs": 500, "appBundleId": "com.example.app", "commandId": ""}} ] diff --git a/docs/adr/0005-ios-runner-interaction-lifecycle.md b/docs/adr/0005-ios-runner-interaction-lifecycle.md index 01d91a6836..68f6e0ec2e 100644 --- a/docs/adr/0005-ios-runner-interaction-lifecycle.md +++ b/docs/adr/0005-ios-runner-interaction-lifecycle.md @@ -69,7 +69,7 @@ What a `RUNNER_BUSY` refusal then costs the caller turns on the daemon's own per trait, not on any runner-side classification of the command: `RUNNER_COMMAND_TRAITS` in `packages/platform-apple/src/runner/runner-command-traits.ts`, read through `isReadOnlyRunnerCommand` where `runAppleRunnerCommand` decides whether to wrap the send in a resend -loop. The asymmetry is shipped, and asserted in `runner-command-busy-resend.test.ts`: a read-only +loop. The asymmetry is shipped, and asserted in `runner-client-busy-resend.test.ts`: a read-only command treats the refusal as *not yet*, waiting the drain out on the busy-specific budget sized to outlast it and resending until the runner answers or the window ends; a mutating command treats the same refusal as *not mine to send again* — one attempt, and the refusal reaches the caller unwrapped diff --git a/docs/ios-runner-protocol-optimizations.md b/docs/ios-runner-protocol-optimizations.md index ab7aa62964..d09c3ecc31 100644 --- a/docs/ios-runner-protocol-optimizations.md +++ b/docs/ios-runner-protocol-optimizations.md @@ -28,8 +28,8 @@ Acceptance criteria: iOS simulator validation: -- Unit: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts`. -- Unit bundle: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-client.test.ts packages/platform-apple/src/runner/__tests__/runner-session.test.ts packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts packages/platform-apple/src/runner/__tests__/runner-provider.test.ts`. +- Unit: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts`. +- Unit bundle: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-client.test.ts packages/platform-apple/src/runner/__tests__/runner-session.test.ts packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts packages/platform-apple/src/runner/__tests__/runner-provider.test.ts`. - Build: `pnpm build:xcuitest`. - Manual sim smoke after build: - `pnpm build` diff --git a/packages/contracts/src/dispatch-disclosure.fixtures.ts b/packages/contracts/src/dispatch-disclosure.fixtures.ts index bcf8d9ab65..0d318fe712 100644 --- a/packages/contracts/src/dispatch-disclosure.fixtures.ts +++ b/packages/contracts/src/dispatch-disclosure.fixtures.ts @@ -42,7 +42,7 @@ export const DISPATCH_DISCLOSURE_DRIVER_OWNERS: Readonly> 'daemon.route.': 'src/__tests__/daemon-composition/request-dispatch-disclosure.test.ts', 'post-action-guard.': 'src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts', - 'ios-runner.': 'packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts', + 'ios-runner.': 'packages/platform-apple/src/runner/__tests__/index-dispatch-disclosure.test.ts', 'ios-runner.pre-send.': 'packages/platform-apple/src/runner/__tests__/runner-lifecycle-dispatch-disclosure.test.ts', 'ios-runner.transport.': diff --git a/packages/contracts/src/interactor-types.ts b/packages/contracts/src/interactor-types.ts index c927c27c74..270864341b 100644 --- a/packages/contracts/src/interactor-types.ts +++ b/packages/contracts/src/interactor-types.ts @@ -107,7 +107,7 @@ export const MAESTRO_NON_HITTABLE_FALLBACK_MESSAGE = 'tapped via non-hittable co * its only producer and the boundary that narrows it * (readTypeTextBackendResult, packages/platform-apple/src/interactions.ts) drops a * route it cannot name — so a Swift-side addition would silently vanish. The - * route-parity test in packages/platform-apple/src/core/__tests__/interactions.test.ts + * route-parity test in packages/platform-apple/src/interactions.test.ts * reads the Swift sources and fails instead. */ export const TEXT_ENTRY_ROUTES = [ diff --git a/packages/platform-apple/src/__tests__/runner-requests.test.ts b/packages/platform-apple/src/__tests__/index-runner-requests.test.ts similarity index 99% rename from packages/platform-apple/src/__tests__/runner-requests.test.ts rename to packages/platform-apple/src/__tests__/index-runner-requests.test.ts index c90ce9f2ce..ebd939a40a 100644 --- a/packages/platform-apple/src/__tests__/runner-requests.test.ts +++ b/packages/platform-apple/src/__tests__/index-runner-requests.test.ts @@ -26,7 +26,7 @@ import { mkdtempForTest } from './tmp-dir.ts'; // Every Apple runner request site outside `runner/`, driven through its production entry point and // pinned to contracts/fixtures/runner-requests.json. The drives never write a request themselves; -// runner/__tests__/runner-requests.test.ts reads this source to keep it that way. +// runner/__tests__/index-runner-requests.test.ts reads this source to keep it that way. const APP = 'com.example.app'; const XCTEST_DEVICE: DeviceInfo = { ...IOS_DEVICE, iosPhysicalDeviceBackend: 'xctest' }; diff --git a/packages/platform-apple/src/__tests__/screenshot-backend.test.ts b/packages/platform-apple/src/__tests__/interactor-screenshot-backend.test.ts similarity index 100% rename from packages/platform-apple/src/__tests__/screenshot-backend.test.ts rename to packages/platform-apple/src/__tests__/interactor-screenshot-backend.test.ts diff --git a/packages/platform-apple/src/__tests__/watchos-sentinel.test.ts b/packages/platform-apple/src/__tests__/interactor-watchos-sentinel.test.ts similarity index 100% rename from packages/platform-apple/src/__tests__/watchos-sentinel.test.ts rename to packages/platform-apple/src/__tests__/interactor-watchos-sentinel.test.ts diff --git a/packages/platform-apple/src/core/__tests__/runner-mac-arch.test.ts b/packages/platform-apple/src/core/__tests__/runner-client-mac-arch.test.ts similarity index 100% rename from packages/platform-apple/src/core/__tests__/runner-mac-arch.test.ts rename to packages/platform-apple/src/core/__tests__/runner-client-mac-arch.test.ts diff --git a/packages/platform-apple/src/foldable/fold-helper-cache.test.ts b/packages/platform-apple/src/foldable/fold-helper-cache.test.ts index 6dae3e3dd9..06bfe6b57a 100644 --- a/packages/platform-apple/src/foldable/fold-helper-cache.test.ts +++ b/packages/platform-apple/src/foldable/fold-helper-cache.test.ts @@ -221,7 +221,7 @@ test('an abort while a second caller waits on the fold-helper lock reports a can // // The compile runs in beforeAll, not in the test body: it is a real clang invocation (see the // unit slow-test budget in docs/agents/testing.md), and the snapshot-bridge sibling gate in -// native-runtime.test.ts keeps its compile out of test-case wall time the same way. +// cache-native-runtime.test.ts keeps its compile out of test-case wall time the same way. describe.skipIf(process.platform !== 'darwin')('fold helper warning gate', () => { let compiled: { exitCode: number; stderr: string }; beforeAll(async () => { diff --git a/packages/platform-apple/src/core/__tests__/interactions.test.ts b/packages/platform-apple/src/interactions.test.ts similarity index 97% rename from packages/platform-apple/src/core/__tests__/interactions.test.ts rename to packages/platform-apple/src/interactions.test.ts index 2834331578..6fbba09587 100644 --- a/packages/platform-apple/src/core/__tests__/interactions.test.ts +++ b/packages/platform-apple/src/interactions.test.ts @@ -6,15 +6,15 @@ import { iosRunnerOverrides, performGestureApple, resolveAppleBackRunnerCommand, -} from '../../interactions.ts'; -import { runAppleRunnerCommand } from '../runner-client.ts'; +} from './interactions.ts'; +import { runAppleRunnerCommand } from './core/runner-client.ts'; import { AppError } from '@agent-device/kernel/errors'; import { gestureRefusalMessage, PHYSICAL_IOS_MULTI_TOUCH_UNSUPPORTED_HINT, } from '@agent-device/contracts/gesture-admission'; import type { GesturePlan } from '@agent-device/contracts/gesture-plan-types'; -import type { RunnerCommand } from '../../runner/index.ts'; +import type { RunnerCommand } from './runner/index.ts'; import { TEXT_ENTRY_ROUTES } from '@agent-device/contracts/interactor-types'; import { IOS_TEST_DEVICE, @@ -22,15 +22,15 @@ import { MACOS_TEST_DEVICE, TVOS_TEST_SIMULATOR, VISIONOS_TEST_SIMULATOR, -} from './apple-core-stub-helpers.ts'; +} from './core/__tests__/apple-core-stub-helpers.ts'; -vi.mock('../runner-client.ts', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('./core/runner-client.ts', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, runAppleRunnerCommand: vi.fn(actual.runAppleRunnerCommand) }; }); const runnerActual = - await vi.importActual('../runner-client.ts'); + await vi.importActual('./core/runner-client.ts'); const mockRunAppleRunnerCommand = vi.mocked(runAppleRunnerCommand); @@ -630,7 +630,7 @@ test('iosRunnerOverrides reports no route when the runner names one it does not test('TEXT_ENTRY_ROUTES names every route the Swift runner assigns', () => { const runnerTestsDir = path.resolve( import.meta.dirname, - '../../../../../apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests', + '../../../apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests', ); const swiftRoutes = new Set(); for (const entry of fs.readdirSync(runnerTestsDir)) { diff --git a/packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts b/packages/platform-apple/src/runner/__tests__/index-dispatch-disclosure.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts rename to packages/platform-apple/src/runner/__tests__/index-dispatch-disclosure.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-requests.test.ts b/packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-requests.test.ts rename to packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-command-busy-resend.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client-busy-resend.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-command-busy-resend.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-client-busy-resend.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-recovery-wiring.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client-recovery-wiring.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-recovery-wiring.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-client-recovery-wiring.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-readiness-routing.test.ts b/packages/platform-apple/src/runner/__tests__/runner-command-traits-readiness-routing.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-readiness-routing.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-command-traits-readiness-routing.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-response.test.ts b/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts similarity index 61% rename from packages/platform-apple/src/runner/__tests__/runner-response.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts index d626730d90..977340b269 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-response.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts @@ -7,14 +7,9 @@ import { isRunnerResponseOk, readRunnerResponseData, } from '../runner-contract.ts'; -import { isStructuredRunnerFailure } from '../runner-error-classification.ts'; -import { parseRunnerResponse } from '../runner-exchange.ts'; -import type { RunnerSessionState } from '../runner-session-types.ts'; // A body cut off mid-write: the shape a runner that died while answering leaves behind. const TRUNCATED_BODY = '{"ok":true,"data":{"nodes":[{"label":"Sign In"'; -// `ok` is a Swift `Bool`, so this is what a private truthiness rule used to accept as an answer. -const STRINGLY_TYPED_BODY = '{"ok":"true","data":{"tapped":true}}'; describe('decodeRunnerResponseBody', () => { test('decodes the runner envelope', () => { @@ -111,59 +106,3 @@ describe('buildRunnerResponseError', () => { assert.equal(error.details?.hint, undefined); }); }); - -describe('parseRunnerResponse', () => { - test('refuses a body whose ok is not the boolean true', async () => { - const session: { state: RunnerSessionState } = { state: 'starting' }; - - await assert.rejects( - () => parseRunnerResponse(new Response(STRINGLY_TYPED_BODY), session), - (error: unknown) => { - assert.ok(error instanceof AppError); - assert.equal(error.code, 'COMMAND_FAILED'); - assert.deepEqual(error.details?.runner, { ok: 'true', data: { tapped: true } }); - return true; - }, - ); - - assert.equal(session.state, 'starting'); - }); - - test('refuses a body that is not readable JSON', async () => { - const session: { state: RunnerSessionState } = { state: 'starting' }; - - await assert.rejects( - () => parseRunnerResponse(new Response(TRUNCATED_BODY), session), - (error: unknown) => { - assert.ok(error instanceof AppError); - assert.equal(error.code, 'COMMAND_FAILED'); - assert.equal(error.details?.text, TRUNCATED_BODY); - // Transport-shaped: no `runner` detail, so the session keeps its recency bets (#2552). - assert.equal(error.details?.runner, undefined); - return true; - }, - ); - - assert.equal(session.state, 'starting'); - }); - - test('reads a JSON scalar body as transport-shaped, not as an empty reply', async () => { - // The chain #2965 turns on: an error carrying a `runner` detail counts as an answer and discharges - // the command's charge. A bare `null` is not an envelope the runner's encoder emits, so decoding it - // into `{}` and erroring from that would have answered a command the runner may still be running. - const session: { state: RunnerSessionState } = { state: 'starting' }; - - await assert.rejects( - () => parseRunnerResponse(new Response('null'), session), - (error: unknown) => { - assert.ok(error instanceof AppError); - assert.equal(error.message, 'Invalid runner response'); - assert.equal(error.details?.runner, undefined); - assert.equal(isStructuredRunnerFailure(error), false); - return true; - }, - ); - - assert.equal(session.state, 'starting'); - }); -}); diff --git a/packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts b/packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts new file mode 100644 index 0000000000..21d6d1211b --- /dev/null +++ b/packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'vitest'; +import { AppError } from '@agent-device/kernel/errors'; +import { isStructuredRunnerFailure } from '../runner-error-classification.ts'; +import { parseRunnerResponse } from '../runner-exchange.ts'; +import type { RunnerSessionState } from '../runner-session-types.ts'; + +// A body cut off mid-write: the shape a runner that died while answering leaves behind. +const TRUNCATED_BODY = '{"ok":true,"data":{"nodes":[{"label":"Sign In"'; +// `ok` is a Swift `Bool`, so this is what a private truthiness rule used to accept as an answer. +const STRINGLY_TYPED_BODY = '{"ok":"true","data":{"tapped":true}}'; + +describe('parseRunnerResponse', () => { + test('refuses a body whose ok is not the boolean true', async () => { + const session: { state: RunnerSessionState } = { state: 'starting' }; + + await assert.rejects( + () => parseRunnerResponse(new Response(STRINGLY_TYPED_BODY), session), + (error: unknown) => { + assert.ok(error instanceof AppError); + assert.equal(error.code, 'COMMAND_FAILED'); + assert.deepEqual(error.details?.runner, { ok: 'true', data: { tapped: true } }); + return true; + }, + ); + + assert.equal(session.state, 'starting'); + }); + + test('refuses a body that is not readable JSON', async () => { + const session: { state: RunnerSessionState } = { state: 'starting' }; + + await assert.rejects( + () => parseRunnerResponse(new Response(TRUNCATED_BODY), session), + (error: unknown) => { + assert.ok(error instanceof AppError); + assert.equal(error.code, 'COMMAND_FAILED'); + assert.equal(error.details?.text, TRUNCATED_BODY); + // Transport-shaped: no `runner` detail, so the session keeps its recency bets (#2552). + assert.equal(error.details?.runner, undefined); + return true; + }, + ); + + assert.equal(session.state, 'starting'); + }); + + test('reads a JSON scalar body as transport-shaped, not as an empty reply', async () => { + // The chain #2965 turns on: an error carrying a `runner` detail counts as an answer and discharges + // the command's charge. A bare `null` is not an envelope the runner's encoder emits, so decoding it + // into `{}` and erroring from that would have answered a command the runner may still be running. + const session: { state: RunnerSessionState } = { state: 'starting' }; + + await assert.rejects( + () => parseRunnerResponse(new Response('null'), session), + (error: unknown) => { + assert.ok(error instanceof AppError); + assert.equal(error.message, 'Invalid runner response'); + assert.equal(error.details?.runner, undefined); + assert.equal(isStructuredRunnerFailure(error), false); + return true; + }, + ); + + assert.equal(session.state, 'starting'); + }); +}); diff --git a/packages/platform-apple/src/runner/__tests__/runner-request-cancellation.test.ts b/packages/platform-apple/src/runner/__tests__/runner-lifecycle-request-cancellation.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-request-cancellation.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-lifecycle-request-cancellation.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-close-finalization.test.ts b/packages/platform-apple/src/runner/__tests__/runner-session-close-finalization.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-close-finalization.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-session-close-finalization.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts b/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts index 289f00c271..ab7a494392 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts @@ -532,7 +532,7 @@ test('a command abandoned by a cancelled transport keeps the runner occupied', a // An answered queued exchange forgives the abandoned charge: the serial queue makes it evidence that // the abandoned handling ahead of it finished, and whatever is still draining is stamped onto that // very reply. An answer the runner serves inline forgives nothing (#2965); that case is pinned in - // `runner-recovery-wiring.test.ts`, where the probe reaches a real session. + // `runner-client-recovery-wiring.test.ts`, where the probe reaches a real session. await serveOneCommand(device, session); assert.equal(session.commandCharges.hasOutstandingCharges, false); assert.equal(await detachIosRunnerSessionsForShutdown(), 1); diff --git a/packages/platform-apple/src/runner/__tests__/runner-early-exit-diagnosis.test.ts b/packages/platform-apple/src/runner/__tests__/runner-startup-transport-early-exit.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-early-exit-diagnosis.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-startup-transport-early-exit.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts b/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts index 41e75cb065..b1172a489a 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts @@ -37,7 +37,7 @@ const CASE_HEADER = /\bcase\s+(\.\w+(?:\s*,\s*\.\w+)*):/g; * command queue, which is exactly why a reply to one is no evidence about queued work. * * A reader here can only fail in two directions, and each is caught: a misread that names an extra - * command fails `runner-readiness-routing.test.ts`, which compares this list against the daemon's + * command fails `runner-command-traits-readiness-routing.test.ts`, which compares this list against the daemon's * `readinessProbe` trait in both directions, and a misread that loses an arm makes a real probe look * queued, which that same tie reports. What is left to guard locally is the case both miss — a `case` * these two patterns do not recognize, which would otherwise drop an arm and leave a set that still diff --git a/packages/platform-apple/src/runner/__tests__/runner-start-admission.test.ts b/packages/platform-apple/src/runner/__tests__/runner-xctestrun-start-admission.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-start-admission.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-xctestrun-start-admission.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-startup-failure-reasons.test.ts b/packages/platform-apple/src/runner/__tests__/runner-xctestrun-startup-failure-reasons.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-startup-failure-reasons.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-xctestrun-startup-failure-reasons.test.ts diff --git a/packages/platform-apple/src/runner/runner-exchange.ts b/packages/platform-apple/src/runner/runner-exchange.ts index a7254a70e1..6608635e19 100644 --- a/packages/platform-apple/src/runner/runner-exchange.ts +++ b/packages/platform-apple/src/runner/runner-exchange.ts @@ -296,7 +296,7 @@ async function sendRunnerCommandAfterPreflight(params: { // nobody is waiting for any more. A readiness probe is charged no more than the preflight's own // probe is: the runner serves it inline, so its reply says nothing about the queued work a charge // stands for, and charging it would let one probe settle another command's debt (#2965). The trait - // that names the probe is pinned to the runner's inline routing by `runner-readiness-routing.test.ts`. + // that names the probe is pinned to the runner's inline routing by `runner-command-traits-readiness-routing.test.ts`. const charged = !isRunnerReadinessProbeCommand(runnerCommand); if (charged) session.commandCharges.charge(runnerCommand.commandId); try { diff --git a/packages/platform-apple/src/snapshot-source/native-runtime.test.ts b/packages/platform-apple/src/snapshot-source/cache-native-runtime.test.ts similarity index 100% rename from packages/platform-apple/src/snapshot-source/native-runtime.test.ts rename to packages/platform-apple/src/snapshot-source/cache-native-runtime.test.ts diff --git a/packages/test-kit/src/boundary-fault-matrix.ts b/packages/test-kit/src/boundary-fault-matrix.ts index 8ce74ef7dd..7b55945c2a 100644 --- a/packages/test-kit/src/boundary-fault-matrix.ts +++ b/packages/test-kit/src/boundary-fault-matrix.ts @@ -144,7 +144,9 @@ export const BOUNDARY_FAULT_MATRIX = { 'lost-response-after-mutation': { mutation: { kind: 'covered', - evidence: ['packages/platform-apple/src/runner/__tests__/runner-recovery-wiring.test.ts'], + evidence: [ + 'packages/platform-apple/src/runner/__tests__/runner-client-recovery-wiring.test.ts', + ], invariants: ['no-mutation-replay', 'typed-error-identity'], }, read: { diff --git a/test/integration/command-coverage/declarations.ts b/test/integration/command-coverage/declarations.ts index 1b02aff3bb..28ac621948 100644 --- a/test/integration/command-coverage/declarations.ts +++ b/test/integration/command-coverage/declarations.ts @@ -1052,7 +1052,7 @@ const COMMAND_COVERAGE_DECLARATIONS = { 'fixture gesture counters prove pan/fling/pinch/rotate', ), macos: macos.contract( - 'packages/platform-apple/src/core/__tests__/interactions.test.ts', + 'packages/platform-apple/src/interactions.test.ts', 'performGestureApple composes macOS one-contact plans with the drag executor', 'macOS gesture dispatch preserves the one-contact drag plan', ),