fix(mobile): keep the sign-in submit button clear of the iOS keyboard - #4820
Merged
Conversation
The login form is centred in a ScrollView, so on shorter iPhones the "Send code" button's centre fell inside UIRemoteKeyboardWindow (iPhone 17 Pro: centre 568pt vs keyboard window top 566pt). iOS hands such a touch to the keyboard, so Maestro's centre tap was a silent no-op: e2e/login.sh logged the tap COMPLETED, the OTP request never went out, and the flow timed out 15s later on a missing "Verify code" behind Maestro's generic "could be a real regression" advice. automaticallyAdjustKeyboardInsets only made the ScrollView scrollable — it never scrolls, and iOS auto-reveals only the focused field — so the root KeyboardAvoidingView now runs on iOS too with behavior="padding", and the inset it replaces is removed (stacking both pushes the form off the top). Harness side: login-request-code.yaml erases the email field before typing (it is uncontrolled, so inputText appended at a caret the tap dropped mid-string and interleaved two attempts into one malformed address) and asserts the typed address before submitting; login.sh cold-relaunches before its single retry and names which half failed instead of leaving Maestro's advice as the only signal. Verified on an iPhone 17 Pro simulator from three starting states: already signed in, signed out with a dirty email field, and a cold app launch.
Contributor
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryReviewed the iOS keyboard-avoidance fix, e2e harness hardening, and documentation updates; no security, correctness, or reliability issues found in the changed lines. Files Reviewed (5 files)
Reviewed by claude-sonnet-5 · Input: 18 · Output: 3.8K · Cached: 406.6K Review guidance: REVIEW.md from base branch |
iscekic
enabled auto-merge (squash)
July 28, 2026 13:07
6 tasks
jeanduplessis
approved these changes
Jul 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was broken
apps/mobile/e2e/login.shstopped being able to sign in: every attempt died atAssert that "Verify code" is visible... FAILEDafter the 15s wait, behind Maestro'sgeneric "This could be a real regression that needs to be addressed" — which sent an
agent hunting a product bug for four rounds.
It is not a backend problem and not a typing problem. The email lands in the field
correctly; the submit tap is swallowed by the keyboard.
Root cause
The login form is vertically centred in a ScrollView, so the "Send code" button sits a
few points from the keyboard's top edge. On an iPhone 17 Pro:
Maestro taps an element's centre, and iOS delivers any touch inside
UIRemoteKeyboardWindowto the keyboard. From the failing run's own device log:The app never saw the touch.
requestEmailCodenever ran, noPOST /api/auth/native/otpwas sent (the outbox directory did not even exist), and Maestro reported the tap
COMPLETEDbecause it gets no hit-test result back. The garbled field content seen inlater rounds (
-cli-69f6@example.com@ee2e-mobile-…) is a downstream artefact of retriestyping into a field that was never cleared, not the cause.
automaticallyAdjustKeyboardInsetsdid not save it: it only makes the ScrollViewscrollable, it never scrolls, and iOS auto-reveals only the focused field — which was
already visible.
On the regression hunt
Not caused by
304b31e3d(Mobile Audit W1-B). I checked out that commit's parentversions of
login-screen.tsx+idle-auth.tsxon the device and measured again:identical geometry — field 506–538, submit 549–588, more-options 598–637, submit still
under the keyboard. Screenshot of the pre-commit build shows "Send code" cut off by the
keyboard exactly as HEAD does. That commit only mitigated the Android half of this
same defect (
returnKeyType="go"+onSubmitEditing).The defect is older than the sign-in screen's last few changes: the margin at the
submit button's centre was ~2pt, and it is a function of screen height minus keyboard
height, so the same flow passes on a taller simulator and fails on a shorter one. The
simulator pool here spans iPhone SE through 17 Pro Max, and
dev:mobile:simulator claimtakes whichever iPhone is free — that is the "this used to work". I did not re-run
history on the other models, so which model the earlier green runs used is unproven;
the geometry above is measured, the model-dependence is arithmetic from it.
The fix
Product (
login-screen.tsx, the real user-visible half): the rootKeyboardAvoidingViewnow runs on iOS too, withbehavior="padding". It shrinks theScrollView so the whole form re-centres above the keyboard. The now-redundant
automaticallyAdjustKeyboardInsetsis removed — stacking both pushes the form off thetop of the screen (observed, then fixed). After the change, submit centre 414 vs
keyboard top 566: clear by 152pt, with the logo, field, submit and "More sign-in
options" all visible.
No unit test: the change is a platform-conditional prop, there is no extractable logic
to assert. It is covered by the device runs below.
Harness:
login-request-code.yamlerases the field before typing (it is uncontrolled, so alogin page left on screen still holds its address and
inputTextinserts at the caretthe tap dropped mid-string) and asserts the typed address before submitting — a
mismatch now fails instantly and legibly instead of 15s later on
Verify code.login.shcold-relaunches throughopen-app.yamlbefore its single retry, and if thatfails too it names which half broke: no new outbox email means the request never
reached the backend; a new email means the request worked and only the code screen was
never reached.
e2e/AGENTS.mdrecords both constraints; the swallowed-tap diagnosis (including thetwo log greps that prove which window got the touch) is in
.kilo_workflow/learnings/maestro-tap-swallowed-by-ios-keyboard.md.Verification
iPhone 17 Pro simulator (iOS 26.5), this worktree's own stack and Metro.
Reproduced at HEAD first:
login.shexit 1, both attempts dying onVerify code, livemaestro hierarchyconfirming submit centre 568 inside the keyboard window at 566.With the fix,
apps/mobile/e2e/login.sh <udid>reached Home from all three startingstates, first attempt each time, no retry needed:
Erase 100 characters→Assert that "${EMAIL}" is visible... COMPLETED→ HomeThe OTP screen shares the same container and was re-checked with the number pad up:
Verify code238–276,Resend code287–325,Back336–374, all above the keyboardwindow at 566.
Checks from
apps/mobile:pnpm format,pnpm typecheck,pnpm lint(0 errors),pnpm check:unused,pnpm test(2337 passed).git diff --checkclean,bash -n login.shandmaestro check-syntaxOK.What remains unexplained
Which simulator model the historical green runs used — the fix makes it moot (there is
now 152pt of clearance instead of 2), but the "used to work" timeline is inferred from
geometry, not from a recovered passing run. The OTP screen now has both this
KeyboardAvoidingView and its own keyboard-padding listener; both were verified working
together, and collapsing that duplication was out of scope here.