chore: stabilize Maestro CI#7311
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR upgrades Maestro to 2.5.1 (Android/iOS), changes Android AVD caching and emulator RAM/options, replaces the Android monkey pre-test step with ChangesMaestro Test Infrastructure Upgrade
Sidebar View Layout Change
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/maestro-android.yml (1)
41-48:⚠️ Potential issue | 🟠 Major | ⚡ Quick winShard 14 can poison the shared AVD cache, defeating the snapshot optimization for all other shards
The
Cache Android AVDstep has noifcondition, so shard 14 participates in both cache restore and save under the same key (avd-${{ runner.os }}-api34).On a cold run, all 14 shards race to save to that key (GitHub Actions is first-writer-wins). If shard 14 wins, the cache stores only
Pixel_API_34_Keyboard.avd+Pixel_API_34_Keyboard.ini. On subsequent runs:
- Non-keyboard shards see
steps.avd-cache.outputs.cache-hit == 'true'- The "Generate AVD snapshot" step is skipped (its condition checks
cache-hit != 'true')- The test step runs with
force-avd-creation: false— but the expected default-profile AVD is absent from the restored cacheThe behavior of
reactivecircus/android-emulator-runnerwhenforce-avd-creation: falseand the named AVD doesn't exist is unspecified; it may silently cold-boot (losing the optimization) or fail outright. Either way, the caching strategy is silently broken.🐛 Proposed fix — exclude shard 14 from AVD caching
- name: Cache Android AVD + if: ${{ inputs.shard != '14' }} id: avd-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/.android/avd/* ~/.android/adb* key: avd-${{ runner.os }}-api34🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/maestro-android.yml around lines 41 - 48, The "Cache Android AVD" step (id: avd-cache, name: Cache Android AVD, key: avd-${{ runner.os }}-api34) must be excluded from shard 14 so it doesn't poison the shared AVD cache; update the step to run only when the shard is not 14 (e.g. add an if condition referencing your matrix/shard variable such as if: matrix.shard != 14) so shard 14 neither restores nor saves to the common key, leaving other shards to generate and cache the full AVD snapshot correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/maestro-android.yml:
- Around line 24-33: The workflow currently uses the jlumbroso/free-disk-space
action with swap-storage: true while configuring the emulator's ram-size: 6144M,
which disables swap and leaves under ~800MB host memory — change either the
swap-storage or ram-size to avoid OOMs: set swap-storage: false to retain the
runner swapfile, or reduce ram-size to 5120M or 4608M so host+emulator fit in
physical RAM; update the keys swap-storage and ram-size in the action usage
(uses: jlumbroso/free-disk-space@...) and apply the same change to the other
occurrences noted (the other blocks referenced) so all workflow entries are
consistent.
In @.github/workflows/maestro-ios.yml:
- Around line 14-15: The comment incorrectly mentions the Android-specific
"dadb"/ADB change; update the comment text that currently references "dadb" and
ADB to an iOS-appropriate note explaining that iOS Maestro uses
idb/libimobiledevice (not ADB) and that the Android-specific CLI 2.5.0 change
does not apply to the iOS workflow; either remove the ADB-specific sentence or
replace it with a short iOS-focused explanation and keep or adjust the release
link as needed so the comment accurately reflects iOS tooling.
---
Outside diff comments:
In @.github/workflows/maestro-android.yml:
- Around line 41-48: The "Cache Android AVD" step (id: avd-cache, name: Cache
Android AVD, key: avd-${{ runner.os }}-api34) must be excluded from shard 14 so
it doesn't poison the shared AVD cache; update the step to run only when the
shard is not 14 (e.g. add an if condition referencing your matrix/shard variable
such as if: matrix.shard != 14) so shard 14 neither restores nor saves to the
common key, leaving other shards to generate and cache the full AVD snapshot
correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ee299d9c-ce31-45fd-89b1-673983985558
📒 Files selected for processing (3)
.github/scripts/run-maestro.sh.github/workflows/maestro-android.yml.github/workflows/maestro-ios.yml
💤 Files with no reviewable changes (1)
- .github/scripts/run-maestro.sh
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: E2E Build Android / android-build
- GitHub Check: ESLint and Test / run-eslint-and-test
|
Android Build Available Rocket.Chat 4.72.0.108814 |
|
Android Build Available Rocket.Chat 4.72.0.108814 Internal App Sharing: https://play.google.com/apps/test/RQQ8k09hlnQ/ahAO29uNRwjAsJvaiquGjKRmucVItIwkqzqmtF75VX3MLDxOhuznxMA2GxetWxp_dAfRbh33wL0-dHZMTeQVHqchi7 |
|
Android Build Available Rocket.Chat Experimental 4.72.0.108813 |
|
Android Build Available Rocket.Chat Experimental 4.72.0.108813 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNTowuRjjHlDYUgXqroMl8epJWmBJOAe-7N_6W5JjAcJyBHu-MfbZDIilMfFnPJkwzs7kKMzme1NVFTUUxnE |
|
iOS Build Available Rocket.Chat Experimental 4.72.0.108816 |
|
Android Build Available Rocket.Chat Experimental 4.72.0.108821 Internal App Sharing: https://play.google.com/apps/test/RQVpXLytHNc/ahAO29uNQLTMEQOTK7Yu4n98ufM0ImDLGPoEI7tdqqt4_8PqA3XXsk_0JhIS1tJIiRPRZJU0Eh3mtvcPjDUgnnZ0rq |
|
Android Build Available Rocket.Chat 4.72.0.108820 Internal App Sharing: https://play.google.com/apps/test/RQQ8k09hlnQ/ahAO29uNQrTqib34jYoZve6A-78lxC3zI5hjF5NuHRtFdGLOxp7tcQ3xwQyvjeTqlI5Lq2c3nCQqQiv5zaR2Rc0VBd |
|
iOS Build Available Rocket.Chat Experimental 4.72.0.108822 |
… shard - maestro-ios.yml: start the simulator cold boot asynchronously before installing Maestro + idb so the ~3.5min cold boot overlaps the ~30s install, then block on bootstatus afterwards. Trim post-boot settle 15s -> 5s. - Fold the lone shard-9 flow (e2e-encryption) into shard 3 and drop shard 9 from both iOS and Android matrices, removing one cold boot per platform per run.
The android-emulator-runner action's internal 'Install Android SDK' step re-downloads the emulator binary and the api-34 system image (~1 GB) from dl.google.com on every one of the 13 parallel Maestro shards. Under that concurrent load the download intermittently arrives corrupt/truncated and sdkmanager dies with 'Error on ZipFile unknown archive', failing a random shard before any test runs. The existing AVD cache only persists the AVD instance (~/.android/avd), not the SDK packages. Promote the e2e-seed-android-avd seed job to also seed the SDK packages: - a separate read-write cache (key android-sdk-emu-<os>-api34) over the emulator + system-image dirs, and - a single serialized, retried sdkmanager install (3x, clearing partial downloads between tries) that runs before the snapshot step, so a corrupt archive self-heals instead of failing the matrix. Each Maestro shard restores that cache read-only (seed job is the single writer), so android-emulator-runner's install becomes a no-op and the per-shard dl.google.com download is eliminated.
#7311 carried the original cherry-pick base of the deeplink/orphan-socket fix. The standalone PR #7380 refined it before merging to develop: - guard the login gate against the connect-before-select race (METEOR.SUCCESS may fire before SERVER.SELECT_SUCCESS; the unconditional take would hang) - added regression tests for that ordering + the call-push path - clarified the SDK patch comments (FIX A primary/defense) Bring app/sagas/deepLinking.js, its test, and the SDK patch in line with develop's merged #7380 version so #7311 stops carrying a divergent copy.
The Android test shards start with ~89 GB free (/dev/root 145G, 39% used) before anything runs; the emulator image + snapshot + downloaded APK use a few GB against that. jlumbroso/free-disk-space cost ~62s on every shard to free space nothing was competing for. The real emulator constraint is RAM, which this action doesn't address (and swap-storage was already kept). Removes ~1 min from the matrix critical path and ~13 runner-minutes/run.
Android shards each persisted a ~3 GB AVD snapshot under a shared key. With multiple open PRs this pushed the repo past GitHub's 10 GB Actions cache cap, LRU-evicting the SDK system-image cache before the shards restored it. Evicted shards then cold-booted and re-downloaded the system image in a single unretried sdkmanager call, intermittently hitting "Error on ZipFile unknown archive" and failing the shard. - AVD cache -> actions/cache/restore (restore-only). The seed job is the single writer, so shards no longer duplicate the 3 GB snapshot per PR; the footprint stays under the 10 GB cap and the SDK cache survives. - Add a 3x-retried sdkmanager install (mirrors the seed job), gated on an SDK-cache miss and run before any emulator boot, so a corrupt download self-heals on both the default cold-boot path and shard 14.
The Unstar step swiped the action sheet up once and asserted 'Unstar' was visible, while the symmetric Star step uses scrollUntilVisible. When a single swipe didn't fully expand the sheet, 'Unstar' stayed below the fold and the shard failed with "Assertion is false: 'Unstar' is visible". Mirror the Star step so the sheet is scrolled until the item is on screen.
Flows are driven by REST calls (login, users.create, …) that data-setup.js makes to the test server. When the server is down or blips, a flow fails deep inside an evalScript as an opaque "[Failed] <flow>" with no reason in the job log — diagnosing it meant downloading the Maestro artifact and reading maestro.log. Two shell-level signals (run-maestro.sh stdout is the job console, so these render as GitHub annotations without opening logs): - Preflight: probe <server>/api/info before running flows; on non-200 emit a red annotation and exit. A full outage makes every shard fail with the same clear reason instead of 13 mystery flow failures. - Mid-run scan: on failure, grep the local Maestro logs for retryRequest's "Non-retryable error <code>" / connection-error fingerprints and annotate that the failure is likely a server/environment flake.
No code change. Re-run the Build PR matrix to get a fresh stability signal.
…che real Maestro's iOS driver has used XCUITest since 1.18.0 and no longer needs idb-companion to drive the simulator. Verified on Maestro 2.5.1 + iOS 26 with idb absent: launchApp, tapOn, assertVisible (hierarchy read), back and takeScreenshot all pass. Removing `brew tap facebook/fb` + the idb install drops ~110s per iOS shard (the tap triggers a full Homebrew auto-update), ~24 min cumulative macOS runner time per run across 13 shards. Also gate the Maestro install on a cache hit on both platforms. The install script (get.maestro.mobile.dev) rm -rf's ~/.maestro and re-downloads on every run with no "already installed" check, so the existing Cache Maestro step was overwritten and wasted. With the gate, warm runs skip the ~70s download.
…helper - Extract the duplicated Android SDK preinstall block into a .github/actions/preinstall-android-sdk composite action; build-pr.yml (seed job) and maestro-android.yml now reference it instead of copy-pasting the serialized 3x-retried install. - Remove the now-dead per-shard "Generate AVD snapshot" step in maestro-android.yml: e2e-seed-android-avd is a hard needs: and the single writer of the avd-<os>-api34 cache, so the shard restore always hits; the cold-boot fallback creates the AVD on the fly on a rare miss. - Add getAttachmentText() in message/utils.ts as the single source of truth for a quote/reply's displayed text (text || title); Reply.tsx and useQuoteDescriptionLabel.ts both use it so the rendered quote and its VoiceOver label stay in sync.
When the Maestro session never produces a JUnit report (e.g. the iOS XCUITest runner not attaching within MAESTRO_DRIVER_STARTUP_TIMEOUT), run-maestro.sh exited 1 immediately. The existing per-flow rerun loop can't recover that class — it needs a report to know which flows to retry. Retry the whole suite once (MAX_STARTUP_RETRIES, default 1) when no main report is produced, and on exhaustion annotate it as an environment failure rather than an app/test regression. A report that exists with failures is still routed to the per-flow rerun loop unchanged.
- Drop redundant 'simctl launch booted com.apple.springboard' + sleep 5: SpringBoard is already up once bootstatus -b returns, so warming it was pure overhead (~20-90s/shard depending on runner). - Fix UIAnimationDragCoefficient: it is a duration MULTIPLIER, so the previous -float 10 made every UIKit/native-stack transition 10x SLOWER (the opposite of the 'Disabling animations' intent). Set 0.0001 so transitions are near-instant and Maestro never waits on them, mirroring Android's disable-animations. - Start the async simctl boot right after Configure Simulator, before the Java/app-download/E2E-account/Maestro setup steps, so the cold boot overlaps that work instead of running after it.
…o job The step exported $UDID to $GITHUB_ENV but nothing consumed it — Install App uses the 'booted' keyword and Maestro auto-detects the single booted simulator. Removing it so the workflow no longer implies a UDID is needed.
- AVD/SDK snapshot caches are written only on develop and restored read-only by PRs (a PR-scoped cache can't be shared across PRs); a miss cold-boots instead of skipping shards. - Narrow the Maestro cache to bin/lib/deps so stale run logs can't be restored and mis-grepped as server flakes. - Bound each `maestro test` with `timeout -k` and drop the in-script whole-suite startup retry; job timeouts sit just above the in-script bound. - Single-source the shard list for both platforms via a preflight job that fails loud if the flow test-<N> set drifts from the declared 1..14 range; restore the missing test-9 (E2E encryption) shard. - iOS small-screen shard picks the smallest available iPhone (SE) and fails loud if none resolves. - Fail loud when the E2E server URL can't be scraped from data.js, and redact the session token from uploaded Maestro logs. a11y: drop the quoted-reply suffix on Android (TalkBack already enumerates the quote subtree, so the suffix double-announced); correct the FormTextInput note on iOS E2E credential-masking suppression.
The preflight had no needs:, so it ran on every PR open in parallel with lint — before the e2e approval gate. Add needs: [e2e-hold] so it runs only once e2e is approved, alongside the e2e builds. A PR that never opts into e2e no longer burns a runner here, nor gets a red X from the drift guard for a suite it isn't running. The run matrices still consume its output, so nothing downstream changes.
GNU `timeout` bounds each `maestro test`, but it ships as `timeout` only on the Linux (Android) runners; macOS provides it as `gtimeout` (Homebrew coreutils). The hardcoded `timeout` aborted every iOS shard with `timeout: command not found` before Maestro ran, so no JUnit report was produced and the run went red. Resolve whichever binary is present, falling back to running unbounded under the job-level timeout-minutes backstop when neither exists.
The e2e shards used actions/cache with a single static key (maestro-<os>-<version>), so on a cold cache every shard in the first runner wave missed, installed Maestro independently, then raced to save the same key — one won and the rest logged "failed to save: another job may be creating this cache". Whether a shard hit became a function of which runner wave it landed in, not anything deterministic. Populate the cache once in the e2e build jobs (e2e-build-ios on macOS, e2e-build-android on Linux), which already run on the matching runner.os and gate every shard via needs, and switch the shards to actions/cache/restore. Every shard now gets a deterministic hit and only restores: no per-shard install, no first-writer race, no save noise. The build jobs use lookup-only + install/save on miss, so a warm cache is a cheap existence check and they touch the Maestro CDN only on a version bump or eviction. The shards keep their cache-miss Install Maestro step as a fallback. MAESTRO_VERSION is now pinned in the build workflows too; it must stay in sync with the shard workflows or the cache key drifts.
…undle # Conflicts: # app/containers/FormContainer.tsx
The single-use fix in PR #7311 prevents unconditional empty-string appending. However, once any 2FA-protected call completes, this.code retains the TOTP value and leaks it into every subsequent methodCall on that connection, re-introducing the trailing-arg breakage and replaying a spent code. Clear the field immediately after the initial attempt consumes it (no await between write and read, so the retry sees the fresh value and only uses it once). Covered by four test cases: no-2FA path, 2FA prompt + retry, code non-leakage to subsequent calls, and 2FA cancellation.
When the target message id is not yet in the loaded list, the jump loop retries every 600 ms by scrolling to the top to trigger onEndReached. Previously it retried forever, so a deleted or unreachable message held the spinner for the full caller-race timeout (up to 20 s). Track the loaded-message count across retries; if it stays the same for 5 consecutive rounds (~3 s) the target cannot appear — reset and resolve instead of waiting for the backstop timer. Adds useScroll.test.ts covering: no-progress exit, growth keeps retrying, cancel mid-loop, and counter reset between jumps.
| # Single source of the shard list both platforms fan out over, and the guard | ||
| # that keeps it honest: it asserts every flow under .maestro/tests is tagged | ||
| # test-<N> within the declared range and every shard in the range has a flow, | ||
| # then emits the list as JSON for the matrices below. A flow tagged outside | ||
| # the range, or a gap in the range, fails here instead of letting that flow | ||
| # silently never run. No AVD seeding happens on PRs — the avd/sdk caches are | ||
| # written only on develop (build-develop.yml's seed-android-avd); shards | ||
| # restore them read-only and cold-boot on a miss. | ||
| # Gated behind e2e-hold, alongside the e2e builds, so it runs only once e2e is | ||
| # approved — a PR that never opts into e2e neither burns a runner here nor gets | ||
| # a red X from the drift guard for a suite it isn't running. |
There was a problem hiding this comment.
Weird and long comment
| # Single writer of the Maestro install cache the e2e Android shards | ||
| # restore. Keep in sync with maestro-android.yml — the key must match. |
| # Warm the Maestro install cache once here: this job is the single writer | ||
| # of the key the e2e Android shards restore (Linux runner — matching their | ||
| # runner.os — and it gates them via needs). Every shard then gets a | ||
| # deterministic cache hit and only restores: no per-shard install, no | ||
| # concurrent first-writer race. lookup-only skips pulling the payload this | ||
| # job never uses on a warm cache. |
| # Single writer of the Maestro install cache the e2e iOS shards restore. | ||
| # Keep in sync with maestro-ios.yml — the cache key must match exactly. |
| # Warm the Maestro install cache once here: this job is the single writer | ||
| # of the key the e2e iOS shards restore (it runs on macOS — matching their | ||
| # runner.os — and gates them via needs). Every shard then gets a | ||
| # deterministic cache hit and only restores: no per-shard install, no | ||
| # concurrent first-writer race, no "failed to save" noise. lookup-only | ||
| # avoids pulling the ~200 MB payload this job never uses on a warm cache. |
| # Slowest passing shard ~27 min; bounds a wedged session above the in-script | ||
| # timeout -k wrap so a hang fails the job instead of burning the full 6h cap. |
| # 2.5.0 switched gRPC to dadb direct ADB socket — eliminates flaky TCP forwarding (Broken pipe at install). | ||
| # https://github.com/mobile-dev-inc/maestro/releases/tag/cli-2.5.0 |
|
iOS Build Available Rocket.Chat 4.74.0.109084 |
|
Android Build Available Rocket.Chat 4.74.0.109083 Internal App Sharing: https://play.google.com/apps/test/RQQ8k09hlnQ/ahAO29uNQdXkXkqEOf0G7eJdbK_8A8VOCvsyOTnROvyzCSVHlGldJe2okeL0M6o5AtsUjSW3aSc5WFsxkwKDaQAmH4 |
Proposed changes
Stabilizes the Maestro E2E suite (CI infra + flaky-flow fixes) and folds in the app-code
fixes that unblock specific shards. The CI changes carry no app behavior change; the app
changes are listed first since they're what needs review.
App changes
sdk.tsappended the 2FA code as a trailing''on every DDP call. Harmless until the server'sloadSurroundingMessagesgrew a typedshowThreadMessages: boolean3rd param (RocketChat/Rocket.Chat#39092); the''then failscheck(…, Boolean)→ 500 → the quoted-message jump never navigates. Fix: append the TOTP codeonly when a 2FA flow is in progress (matches the REST path), and clear it as soon as the retry
consumes it — so a spent code never leaks into subsequent calls on the same connection. Non-2FA
calls send exactly their declared params. Unit-tested (
sdk.test.ts: no-2FA path, 2FA prompt +retry, non-leakage, cancellation).
RoomViewraced the list scroll against a fixed 5s cap;off-screen targets on the slow CI emulator exceed it. Raised to 20s as an interim measure.
The scroll-retry loop also now exits early when history stops loading: if the loaded-message
count stays flat for 5 consecutive 600 ms rounds (~3 s), the target can't appear (deleted or
unreachable message), so it resolves instead of holding the spinner for the full 20 s.
Unit-tested (
useScroll.test.ts). The proper O(1) anchored-window rework is not here — itships separately under NATIVE-1224.
accessibility label so VoiceOver announces it (the nested
<Markdown>is merged into the parenta11y element and never read on its own). On Android the suffix is omitted: TalkBack already
enumerates the quote subtree, so appending it too would double-announce. Mirrors
useImageDescriptionLabel; unit-tested on both platforms. Also unblocks thejump-to-message.yamlquote assertion.FormContainerswapsKeyboardAvoidingView + ScrollViewforKeyboardAwareScrollView(react-native-keyboard-controller, already a dep). Affects the authscreens (Login, Register, ForgotPassword, SendEmailConfirmation, Workspace, NewServer) on both
platforms — see How to test.
Save Password?sheet after credential-field submit that blocks XCUITest. Under
RUNNING_E2E_TESTS=trueon iOS,FormTextInputdeclassifies the field (dropssecureTextEntry/textContentType/autoComplete).Production behavior is unchanged; mirrors what
RegisterViewalready does.SidebarViewwraps theScrollViewin aViewcarryingtestID; Androiddoesn't propagate
testIDfrom aScrollViewto the native tree. (Folded in from fix: restore sidebar-view testID visibility for Maestro #7319.)CI / Maestro stabilization — infra only, no app behavior change
Versions & runners
2.2.0 → 2.5.1(both platforms); 2.5.0's dadb ADB socket kills the AndroidBroken pipeinstall flake.macos-26+ Xcode 26.2.0 to match the iOS-26 build artifact.Android caching / flake fixes
developand restored read-only by PR shards. A single writer means per-PR cache duplication no longer blows the 10 GB Actions cap and LRU-evicts the SDK cache; on a miss a shard cold-boots and installs on the fly.sdkmanagerinstall (clears partial downloads) self-heals theError on ZipFile unknown archiveflake.4 GB → 6 GB; droppedjlumbroso/free-disk-space(shards already start with ~89 GB free) and themonkeywarmup.iOS speed-ups
idb-companion(Maestro's iOS driver uses XCUITest since 1.18.0) — ~110s/shard.Configure Simulator(before Java / app download / E2E account / Maestro setup) so the cold boot overlaps that work; block later onbootstatus -b.Wait for Simulator Ready: dropped the redundantsimctl launch booted com.apple.springboard+sleep 5— SpringBoard is already up oncebootstatus -breturns.UIAnimationDragCoefficient: it is a duration multiplier, so the prior-float 10made every UIKit / native-stack transition 10× slower (the opposite of the "disable animations" intent). Set0.0001so transitions are near-instant and Maestro never waits on them — the iOS analogue of Android'sdisable-animations.iPhone N Pro. No match fails the shard loudly instead of silently falling back.Both platforms
bin/lib/deps), never run logs — so the server-flake log scan can't be fooled by a restored prior run. Shards keep a cache-miss install as a fallback./api/infobefore flows) + mid-run scan of Maestro logs → a server outage/blip renders as a single red job annotation instead of opaque[Failed] <flow>. If the server URL can't be scraped from the test config the job fails loudly (a CI-config error), rather than silently using a fallback.maestro testis bounded in-script (timeout -k 30s 35m) and annotated as an environment failure, with a 40-min job backstop above it. This replaces the old whole-suite startup retry: a run that produces no report now goes red for a human to re-run, rather than auto-retrying and masking real startup breakage. Per-flow rerun rounds3 → 2.&token=…session token the deeplink-login flow writes (the logs ship as a public artifact)..maestro/testsis tagged within the declared range and every shard in the range has a flow, then emits the list as JSON for the matrices. A mistagged or orphaned flow fails fast instead of silently never running.~/.maestro/teststree.Flaky-flow fixes
open-deeplink: anchor the dialog tap to^Open$(unanchoredOpenmatched the iOS 26 alert title).profile: collapse 3 rate-limitedusers.updateOwnBasicInfosubmits into one;hide-keyboardbefore clipped fields.room-actions:scrollUntilVisibletheUnstaritem instead of asserting after one swipe.search-room/discussion/create-team/login: more robust waits andtestID/header-backselectors.Known remaining flaky flows (tracked as follow-ups)
Server / emulator-infra blips (workspace outages, adb socket loss) surface as a single red annotation, not app or test regressions.
Issue(s)
Fixes NATIVE-1123 · NATIVE-1126
Related (deferred, not fixed here): NATIVE-1125 · NATIVE-1128 · NATIVE-1224
How to test or reproduce
NewServer) on iOS and Android after the
KeyboardAwareScrollViewswap — focus each field with thekeyboard open/closed and confirm no clipping or scroll regressions, on phone and tablet.
Screenshots
n/a
Types of changes
Checklist
Further comments
The sidebar testID fix was originally #7319, folded here so CI stabilization and its dependency ship
together (#7319 closed). Acceptance is measured over a 10-run window on
developafter this lands.