From 79f54a8b49e0f2ee9d7cf4cd1751cef00541e134 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Sun, 6 Sep 2026 19:01:27 -0400 Subject: [PATCH] fix(mobile): wait for adversarial review content and route readiness Wait for the diff body rather than just Review controls, and handle Back through Source Control before opening file previews. iOS confirms terminal links and rendered adversarial diff; the full unattended journey remains tracked. Required gates pass in native-chat-read-gates. --- .../hosted-ios-adversarial-content.mjs | 1 + .../hosted-webview-adversarial-content.mjs | 4 +++- .../hosted-webview-adversarial-files.mjs | 21 ++++++++++++++++++- ...sted-android-source-control-review-e2e.mjs | 4 +++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/mobile/scripts/hosted-ios-adversarial-content.mjs b/mobile/scripts/hosted-ios-adversarial-content.mjs index 8c9223ec530..061ab8f1a3c 100644 --- a/mobile/scripts/hosted-ios-adversarial-content.mjs +++ b/mobile/scripts/hosted-ios-adversarial-content.mjs @@ -69,6 +69,7 @@ export function createHostedIosAdversarialContentInspector({ emulator, fixture, observations.push( await captureHostedWebViewAdversarialObservation({ document, + expectedMarker: phase === 'review' ? HOSTED_ADVERSARIAL_CONTENT_MARKER : undefined, timeoutMs: Math.min(timeoutMs, 15_000) }) ) diff --git a/mobile/scripts/hosted-webview-adversarial-content.mjs b/mobile/scripts/hosted-webview-adversarial-content.mjs index 3befecaede9..588db8a8d81 100644 --- a/mobile/scripts/hosted-webview-adversarial-content.mjs +++ b/mobile/scripts/hosted-webview-adversarial-content.mjs @@ -55,7 +55,9 @@ export async function captureHostedWebViewAdversarialObservation({ } await delay(250) } while (Date.now() < deadline) - throw new Error(`Hosted adversarial marker was not rendered: ${expectedMarker}`) + throw new Error( + `Hosted adversarial marker was not rendered: ${expectedMarker}; state=${JSON.stringify(observation?.state).slice(0, 4000)}` + ) } export function hostedWebViewAdversarialContentObservations(observations) { diff --git a/mobile/scripts/hosted-webview-adversarial-files.mjs b/mobile/scripts/hosted-webview-adversarial-files.mjs index 9b9f01f9ebd..76979d62daa 100644 --- a/mobile/scripts/hosted-webview-adversarial-files.mjs +++ b/mobile/scripts/hosted-webview-adversarial-files.mjs @@ -34,7 +34,7 @@ export async function inspectHostedWebViewAdversarialFiles({ }) { const reviewRoute = routeFromDocument(document, 'review') await activateHostedWebViewControl(document, { kind: 'label', value: 'Back' }, WebSocketCtor) - await waitForRoute(document, '/session/', 'tabs', timeoutMs, WebSocketCtor) + await returnToSession(document, timeoutMs, WebSocketCtor) await waitForLabel(document, 'Open file explorer', timeoutMs, WebSocketCtor) await activateHostedWebViewControl( document, @@ -87,6 +87,25 @@ export async function inspectHostedWebViewAdversarialFiles({ } } +async function returnToSession(document, timeoutMs, WebSocketCtor) { + const deadline = Date.now() + timeoutMs + while (Date.now() < deadline) { + const state = await readHostedWebViewState(document, WebSocketCtor) + if (state.href.includes('/session/')) { + return + } + if (state.href.includes('/source-control/') && state.labels.includes('Back to session')) { + await activateHostedWebViewControl( + document, + { kind: 'label', value: 'Back to session' }, + WebSocketCtor + ) + } + await delay(250) + } + throw new Error('Hosted adversarial journey did not return to Session') +} + async function openPreview(document, filename, timeoutMs, WebSocketCtor) { const label = `Preview file ${filename}` await waitForLabel(document, label, timeoutMs, WebSocketCtor) diff --git a/mobile/scripts/run-hosted-android-source-control-review-e2e.mjs b/mobile/scripts/run-hosted-android-source-control-review-e2e.mjs index 570341cdd5f..0d61b33260f 100644 --- a/mobile/scripts/run-hosted-android-source-control-review-e2e.mjs +++ b/mobile/scripts/run-hosted-android-source-control-review-e2e.mjs @@ -327,7 +327,9 @@ async function main() { await captureHostedWebViewAdversarialObservation({ document, expectedMarker: - phase === 'sessionDiff' ? HOSTED_ADVERSARIAL_CONTENT_MARKER : undefined, + phase === 'sessionDiff' || phase === 'review' + ? HOSTED_ADVERSARIAL_CONTENT_MARKER + : undefined, timeoutMs: Math.min(options.timeoutMs, 15_000) }) )