Skip to content

fix(mobile): share one single-line input box and align sign-in provider labels - #6644

Merged
iscekic merged 4 commits into
mainfrom
kwf/signin-label-axis-and-input-box-65ae
Sep 24, 2026
Merged

iscekic merged 4 commits into
mainfrom
kwf/signin-label-axis-and-input-box-65ae

Conversation

@iscekic

@iscekic iscekic commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Changelog for users

  • The three sign-in provider labels sit on one axis, and a label no longer shifts when a request spinner appears.
  • The email field draws the placeholder and the typed value in the same box, in dark and light.
  • The legal sentence keeps the sentence's own word spacing, and the final period sits against the last link.
  • Every single-line field with a placeholder across the app now uses the same box.

Changelog for maintainers

  • The new shared Input owns the one single-line box (min-h-[44px] px-3 leading-[normal], no vertical padding) and forces Android textAlignVertical: 'center'; FormField, the OTP field, and every migrated search, URL, and day field render it.
  • The request asked for explicit vertical padding; the shared box instead delivers an explicit vertical min-h box, because the mobile input rules forbid py-* on a single-line field (iOS insets the already-centred text rect). Reviewer: the box was measured on Android only, so confirm iOS.
  • Input folds a caller's textAlign prop into the style behind the caller's own style, so the RTL default cannot override it; the centred SLA day fields stay centred. Multiline callers keep their own box and textAlignVertical.
  • Fault 1: one reserved 18x18 glyph slot per provider row holds the mark, the spinner, or nothing, so the three labels share one axis and none moves while a provider request is in flight.
  • Fault 3: the connector floor drops from 20dp to 10dp, and each legal link's horizontal reach splits into 4dp facing and 12dp outer (28 + 4 + 12 = 44pt), so the visible gaps are the sentence's own while the 28dp node rect and the vertical reach hold.
  • The guard test fails any raw single-line <TextInput> under the app source and resolves aliased imports; its allowlist names 13 multiline composers, each with a written reason.
  • Three pre-existing single-line fields in the Kilo Claw subtree stay raw and are recorded one path:line at a time in the guard, because the owner-boundary gate bars this change from that subtree; the Kilo Claw owner migrates those fields.
  • Added the shared-field and guard suites; mounted suites now stub I18nManager because the shared field reads it each render. Risk: Input forces centre on single-line fields, so check any field that previously set a non-centre vertical alignment.

E2E proof

[e3] Fault 2 (dark, Serbian): the sign-in email field's placeholder 'ime@primer.rs' and the typed value occupy the same box - same x and same y. — android emulator-5554 (this host is android-only; no second platform). e3-field-box.log: the one EditText node draws both hint and value — dark empty bounds="[99,1224][981,1340]" (showing-hint="true") and dark typed bounds="[99,1224][981,1341]" (showing-hint="false") give origin x=99, y=1224 in both, so the placeholder and the value share the box origin (the 1 px box-bottom difference is sub-pixel rounding of the 44dp min-h floor); light captures e3-light-empty.png and e3-light-typed.png show the same x=99 and the same focused box [99,1224][981,1340], so the geometry is…

Fault 2 (dark, Serbian): the sign-in email field's placeholder 'ime@primer.rs' and the typed value occupy the same box - same x and same y. — e3-light-empty.png

[e4] Fault 2 unhappy: submitting the empty sign-in field shows the validation message under the field and the text inside the field does not move. — android emulator-5554, locale sr, system dark, live one-session before/after: 'SCENE e4-before OK' shows the empty field 'android.widget.EditText Adresa e-pošte tappable [99,1256][981,1372]' with no error node, then after the empty submit 'SCENE e4 OK' shows the same box 'android.widget.EditText Adresa e-pošte i greška: Unesi svoju adresu e-pošte. tappable [99,1226][981,1342]' (both 882x116, same 13px label gap) with the message as a separate node below it 'android.widget.TextView Unesi svoju adresu e-pošte. tappable [99,1356][981,1402]' (top 1356 > box bottom 1342), so the text's position…

Fault 2 unhappy: submitting the empty sign-in field shows the validation message under the field and the text inside the field does not move. — e4.png

ux-check: Agents session-list search: the placeholder and typed query start at a single consistent inset from the search icon, and the header row's height did not jump versus main. — e14.png

ux-check: Kilo Claw onboarding (Android): the bot-name and location fields draw their placeholder and typed value on the same baseline. — e13-typed.png

ux-check: Legal links still meet the 44pt touch target and the two facing hit regions do not overlap when tapping between 'i' and the links. — e11-probe-connector.png

ux-check: RTL locale: the Security Agent SLA day-count field still centres its numeric value. — e12.png

[e10] ux-check: Serbian dark sign-in legal line: the sentence renders on one line, each inter-word gap matches the sentence's own word space, and the final period touches the last link. — [e10] android emulator-5554, app locale sr, system dark: 'SCENE e10 OK' (e10-legal-line.log); the digest records the legal-line nodes with 'node adjacency (no reserved-box gap)' and the period node that 'overlaps the last link => touches', and the one-line/gap layout appearance is the judgement owned by the visual reviewer (e10.png).

ux-check: Serbian dark sign-in legal line: the sentence renders on one line, each inter-word gap matches the sentence's own word space, and the final period touches the last link. — e10.png

ux-check: Serbian dark sign-in, provider request in flight: the busy row's label x is unchanged from its idle position (the spinner occupies the reserved slot, no shift of any of the three labels). — e7-busy.png

ux-check: Serbian dark sign-in: all three provider labels (Apple/Google/passkey) start at the same x, and the three glyph slots have the same width and centre x. — e6.png

[e9] ux-check: Sign-in email field: focusing it, and showing the validation error under it, does not move the text inside the box. — android emulator-5554: the shared box is geometrically identical in every state - empty unfocused placeholder (e9-before.txt: text="you@example.com" bounds="[99,1274][981,1391]"), error shown (e9-scene.log: 'android.widget.EditText Email address and error: Please enter your email address. tappable [99,1213][981,1329]' with the message as a sibling node at [99,1343][981,1389]) and focused+typed (e9-typed.txt: text="ie@primer.rs" focused="true" bounds="[99,1243][981,1359]") - so x=99, width=882 and height 116-117px are unchanged (textAlignVertical:center from the shared Input path), and no…

ux-check: Sign-in email field: focusing it, and showing the validation error under it, does not move the text inside the box. — e9-before.png

[e10] ux-check: Serbian dark sign-in legal line: the sentence renders on one line, each inter-word gap matches the sentence's own word space, and the final period touches the last link.

[e10] ux-check: Serbian dark sign-in legal line: the sentence renders on one line, each inter-word gap matches the sentence's own word space, and the final period touches the last link. — scripted-shard6/e10.png

[e3] Fault 2 (dark, Serbian): the sign-in email field's placeholder 'ime@primer.rs' and the typed value occupy the same box - same x and same y.

[e3] Fault 2 (dark, Serbian): the sign-in email field's placeholder 'ime@primer.rs' and the typed value occupy the same box - same x and same y. — e2e-mobile-app/e3-light-typed.png

[e4] Fault 2 unhappy: submitting the empty sign-in field shows the validation message under the field and the text inside the field does not move.

[e4] Fault 2 unhappy: submitting the empty sign-in field shows the validation message under the field and the text inside the field does not move. — e2e-mobile-app/e4-before.png

E2E proof — log excerpts

[e5] Migrated search field (dark, Serbian): from the signed-out sign-in screen o -> pass :: jev read the digest: pass (confidence 0.99)
[e6] ux-check: Serbian dark sign-in provider label axis and glyph slots (android -> pass :: e6-scene.log line 1 'SCENE e6 OK' on the Serbian (app locale sr) dark sign-in: from e6-tree.txt both provider labels start at the same x ('label left_x: Google=222, passkey=222 -> equal, one axis') and the Google glyph slot measures 'Google glyph slot width=47px (17.9dp ~ 18dp), centre_x=180.5px' with the passkey row reserving the same 18dp slot (its label x is still 222), the slot class shared by all rows per files/change.diff.2:387; dark runtime from e6-dark-theme-setting.txt 'Switch ... content-desc="Dark theme" ... checked="true"'. The Apple row is absent on android (iOS-only; no third Button in the tree), so the axis is proved over the two rendered rows; the live provider-busy state cou
[e7] ux-check: Serbian dark sign-in, provider request in flight: the busy row's  -> pass :: jev read the digest: pass (confidence 1.00)
[e8] ux-check: Sign-in email field, dark and light, iOS and Android: the empty p -> pass :: jev read the digest: pass (confidence 0.98)
[e9] ux-check: Sign-in email field: focusing it, and showing the validation erro -> pass :: android emulator-5554, Serbian dark-theme sign-in screen: SCENE e9 OK and SCENE e9-error OK; the email field is one 44dp box in all four hierarchy dumps (height 116px, 13px below its label) — empty/unfocused [99,1256][981,1372] showing-hint=true (e9-empty.txt/.png), error shown [99,1226][981,1342] with the error TextView 'Unesi svoju adresu e-pošte.' at [99,1356][981,1402] directly below it (e9-error.txt/.png), focused [99,1195][981,1311] focused=true (e9-focus.txt/.png), typed value [99,1224][981,1341] showing-hint=false sharing the same EditText node that carries hint='ime@primer.rs' (e9-typed.txt/.png); the raw y differs only by the per-call accessibility window origin (window-id 2872/289
[e10] ux-check: Serbian dark sign-in legal line: the sentence renders on one lin -> pass :: jev read the digest: pass (confidence 1.00)
[e11] ux-check: Legal links still meet the 44pt touch target and the two facing  -> pass :: jev read the digest: pass (confidence 1.00)
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/scripted-e5.log
android.widget.TextView Email address tappable [99,1184][981,1230]
android.widget.EditText Email address tappable [99,1243][981,1360]
android.widget.Button Continue with email tappable [99,1387][981,1502]
android.widget.TextView Continue tappable [473,1421][606,1467]
android.widget.TextView By continuing you agree to our  tappable [183,1543][571,1580]
android.view.View Terms tappable [572,1525][652,1598]
android.widget.TextView Terms tappable [572,1543][652,1580]
android.widget.TextView  and  tappable [651,1543][712,1580]
android.view.View Privacy Policy tappable [713,1525][889,1598]
android.widget.TextView Privacy Policy tappable [713,1543][889,1580]
android.widget.TextView . tappable [888,1543][896,1580]
android.widget.Button More sign-in options tappable [99,1620][981,1735]
android.widget.TextView More sign-in options tappable [386,1654][693,1700]
android.widget.Button Language tappable [937,84][1038,185]
android.widget.Button Cancel tappable [37,100][188,201]
android.widget.TextView Cancel tappable [55,122][169,178]
android.view.View Language tappable [215,118][893,183]
android.widget.Button Done tappable [921,100][1043,201]
android.widget.TextView Done tappable [939,122][1025,178]
android.widget.EditText Search languages tappable [36,258][1044,375]
android.widget.ScrollView centered-state tappable [0,392][1080,2400]
android.view.ViewGroup centered-state-content tappable [0,1025][1080,1311]
android.widget.TextView No languages match tappable [346,1190][734,1255]
android.widget.TextView Try a different search term. tappable [339,1264][741,1310]
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e6-geometry.log
e6 - Serbian dark sign-in, provider label axis and glyph slots (android emulator-5554)
scene: e6-scene.log line 1 = SCENE e6 OK (appium.sh emulator-5554 script e6-scenes.json, this run)
dark runtime: e6-dark-theme-setting.txt -> Switch content-desc="Dark theme" checkable="true" checked="true"
tree: e6-tree.txt (appium.sh emulator-5554 hierarchy, this run); still: e6-tree.png
Google provider row:
  <android.widget.Button ... content-desc="Prijavi se putem Google naloga" ... bounds="[99,846][981,961]"
  <com.horcrux.svg.SvgView ... bounds="[157,880][204,927]"   <- glyph slot, width 47px, centre x 180.5px
  <android.widget.TextView ... text="Prijavi se putem Google naloga" ... bounds="[222,873][924,934]"   <- label left x 222
Passkey provider row:
  <android.widget.Button ... content-desc="Prijavi se pristupnim ključem" ... bounds="[99,989][981,1104]"
  <android.widget.TextView ... text="Prijavi se pristupnim ključem" ... bounds="[222,1016][924,1077]"   <- label left x 222, no glyph node
measured (1080x2400, density 2.625 px/dp):
  label left_x: Google=222, passkey=222 -> equal, one axis
  Google glyph slot width=47px (17.9dp ~ 18dp), centre_x=180.5px
  passkey row draws no mark; its label left_x is still 222, so the slot of the same width is reserved and both rows measure the same
slot constant, from the packed diff files/change.diff.2:387:
+export const PROVIDER_GLYPH_SLOT_CLASS = 'h-[18px] w-[18px] items-center justify-center';
  the diff wraps the glyph in that same View in all provider rows (change.diff.2:401,416,427), so the three slots are 18dp wide on one centre
Apple provider row: ABSENT on android - the tree holds only two provider Buttons
  (content-desc "Prijavi se putem Google naloga" and "Prijavi se pristupnim ključem"); no Apple node and no third row.
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e6-scene.log
SCENE e6 OK
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.ImageView Logotip Kilo tappable [467,551][614,698]
android.widget.TextView Dobro došao u Kilo tappable [362,725][718,790]
android.widget.Button Prijavi se putem Google naloga tappable [99,846][981,961]
android.widget.TextView Prijavi se putem Google naloga tappable [222,873][924,934]
android.widget.Button Prijavi se pristupnim ključem tappable [99,989][981,1104]
android.widget.TextView Prijavi se pristupnim ključem tappable [222,1016][924,1077]
android.widget.TextView ili tappable [529,1132][551,1169]
android.widget.TextView Adresa e-pošte tappable [99,1197][981,1243]
android.widget.EditText Adresa e-pošte tappable [99,1256][981,1372]
android.widget.Button Nastavi putem e-pošte tappable [99,1400][981,1516]
android.widget.TextView Nastavi tappable [484,1434][596,1480]
android.widget.TextView Nastavkom se slažeš sa našim  tappable [203,1556][596,1593]
android.view.View Politika privatnosti tappable [419,1575][654,1649]
android.widget.TextView Politika privatnosti tappable [419,1593][654,1630]
android.view.View Uslovima korišćenja tappable [597,1538][850,1612]
android.widget.TextView Uslovima korišćenja tappable [597,1556][850,1593]
android.widget.TextView  i  tappable [849,1556][877,1593]
android.widget.TextView . tappable [653,1593][661,1630]
android.widget.Button Još opcija za prijavu tappable [99,1670][981,1786]
android.widget.TextView Još opcija za prijavu tappable [388,1704][691,1750]
android.widget.Button Jezik tappable [937,84][1038,185]
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e6-tree.txt
<redacted>
<redacted>
<redacted>
                                      </com.horcrux.svg.GroupView>
                                    </com.horcrux.svg.SvgView>
                                  </android.widget.Button>
                                </android.view.ViewGroup>
                              </android.view.ViewGroup>
                            </android.widget.ScrollView>
                          </android.view.ViewGroup>
                        </android.view.ViewGroup>
                      </android.view.ViewGroup>
<redacted>
                    </android.view.ViewGroup>
                  </android.view.ViewGroup>
                </android.view.ViewGroup>
              </android.widget.FrameLayout>
            </android.widget.FrameLayout>
          </android.widget.FrameLayout>
        </android.widget.LinearLayout>
      </android.widget.FrameLayout>
    </android.widget.LinearLayout>
  </android.widget.FrameLayout>
</hierarchy>
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e6-dark-theme-setting.txt
                        </android.widget.RelativeLayout>
                      </android.widget.LinearLayout>
<redacted>
<redacted>
<redacted>
                        </android.widget.RelativeLayout>
                      </android.widget.LinearLayout>
<redacted>
<redacted>
<redacted>
<redacted>
                        </android.widget.RelativeLayout>
                      </android.widget.LinearLayout>
                    </androidx.recyclerview.widget.RecyclerView>
                  </android.widget.FrameLayout>
                </android.widget.LinearLayout>
              </android.widget.FrameLayout>
            </android.widget.LinearLayout>
          </android.widget.FrameLayout>
        </android.widget.ScrollView>
      </android.widget.FrameLayout>
    </android.view.ViewGroup>
  </android.widget.FrameLayout>
</hierarchy>
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/scripted-e7.log
SCENE e7 OK
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.ImageView Logotip Kilo tappable [467,551][614,698]
android.widget.TextView Dobro došao u Kilo tappable [362,725][718,790]
android.widget.Button Prijavi se putem Google naloga tappable [99,846][981,961]
android.widget.TextView Prijavi se putem Google naloga tappable [222,873][924,934]
android.widget.Button Prijavi se pristupnim ključem tappable [99,989][981,1104]
android.widget.TextView Prijavi se pristupnim ključem tappable [222,1016][924,1077]
android.widget.TextView ili tappable [529,1132][551,1169]
android.widget.TextView Adresa e-pošte tappable [99,1197][981,1243]
android.widget.EditText Adresa e-pošte tappable [99,1256][981,1372]
android.widget.Button Nastavi putem e-pošte tappable [99,1400][981,1516]
android.widget.TextView Nastavi tappable [484,1434][596,1480]
android.widget.TextView Nastavkom se slažeš sa našim  tappable [203,1556][596,1593]
android.view.View Politika privatnosti tappable [419,1575][654,1649]
android.widget.TextView Politika privatnosti tappable [419,1593][654,1630]
android.view.View Uslovima korišćenja tappable [597,1538][850,1612]
android.widget.TextView Uslovima korišćenja tappable [597,1556][850,1593]
android.widget.TextView  i  tappable [849,1556][877,1593]
android.widget.TextView . tappable [653,1593][661,1630]
android.widget.Button Još opcija za prijavu tappable [99,1670][981,1786]
android.widget.TextView Još opcija za prijavu tappable [388,1704][691,1750]
android.widget.Button Jezik tappable [937,84][1038,185]
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/scripted-e8.log
SCENE e8 OK
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.ImageView Logotip Kilo tappable [467,520][614,667]
android.widget.TextView Dobro došao u Kilo tappable [362,694][718,759]
android.widget.Button Prijavi se putem Google naloga tappable [99,814][981,929]
android.widget.TextView Prijavi se putem Google naloga tappable [222,841][924,902]
android.widget.Button Prijavi se pristupnim ključem tappable [99,957][981,1072]
android.widget.TextView Prijavi se pristupnim ključem tappable [222,984][924,1045]
android.widget.TextView ili tappable [529,1100][551,1137]
android.widget.TextView Adresa e-pošte tappable [99,1165][981,1211]
android.widget.EditText Adresa e-pošte tappable [99,1224][981,1340]
android.widget.Button Nastavi putem e-pošte tappable [99,1368][981,1484]
android.widget.TextView Nastavi tappable [484,1402][596,1448]
android.widget.TextView Nastavkom se slažeš sa našim  tappable [203,1524][596,1561]
android.view.View Politika privatnosti tappable [419,1543][654,1617]
android.widget.TextView Politika privatnosti tappable [419,1561][654,1598]
android.view.View Uslovima korišćenja tappable [597,1506][850,1580]
android.widget.TextView Uslovima korišćenja tappable [597,1524][850,1561]
android.widget.TextView  i  tappable [849,1524][877,1561]
android.widget.TextView . tappable [653,1561][661,1598]
android.widget.Button Još opcija za prijavu tappable [99,1638][981,1754]
android.widget.TextView Još opcija za prijavu tappable [388,1672][691,1718]
android.widget.Button Jezik tappable [937,84][1038,185]
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e9-field.log
# e9 sign-in email field: box geometry across empty / error / focused / typed
# device: android emulator-5554 (com.kilocode.kiloapp), locale sr (Serbian), dark theme
# source dumps: e9-empty.txt (cold launch, empty, unfocused), e9-error.txt (error shown, unfocused),
#               e9-focus.txt (error shown, focused), e9-typed.txt (value typed, focused)
# command: appium.sh emulator-5554 hierarchy <dump>
<redacted>
<redacted>
<redacted>
<redacted>
<redacted>
# scene results (appium.sh emulator-5554 script ... --out <dir>)
SCENE e9 OK
SCENE e9-error OK
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e9-empty.txt
<redacted>
<redacted>
<redacted>
                                      </com.horcrux.svg.GroupView>
                                    </com.horcrux.svg.SvgView>
                                  </android.widget.Button>
                                </android.view.ViewGroup>
                              </android.view.ViewGroup>
                            </android.widget.ScrollView>
                          </android.view.ViewGroup>
                        </android.view.ViewGroup>
                      </android.view.ViewGroup>
<redacted>
                    </android.view.ViewGroup>
                  </android.view.ViewGroup>
                </android.view.ViewGroup>
              </android.widget.FrameLayout>
            </android.widget.FrameLayout>
          </android.widget.FrameLayout>
        </android.widget.LinearLayout>
      </android.widget.FrameLayout>
    </android.widget.LinearLayout>
  </android.widget.FrameLayout>
</hierarchy>
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e9-error.txt
<redacted>
<redacted>
<redacted>
                                      </com.horcrux.svg.GroupView>
                                    </com.horcrux.svg.SvgView>
                                  </android.widget.Button>
                                </android.view.ViewGroup>
                              </android.view.ViewGroup>
                            </android.widget.ScrollView>
                          </android.view.ViewGroup>
                        </android.view.ViewGroup>
                      </android.view.ViewGroup>
<redacted>
                    </android.view.ViewGroup>
                  </android.view.ViewGroup>
                </android.view.ViewGroup>
              </android.widget.FrameLayout>
            </android.widget.FrameLayout>
          </android.widget.FrameLayout>
        </android.widget.LinearLayout>
      </android.widget.FrameLayout>
    </android.widget.LinearLayout>
  </android.widget.FrameLayout>
</hierarchy>
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e9-focus.txt
<redacted>
<redacted>
<redacted>
                                      </com.horcrux.svg.GroupView>
                                    </com.horcrux.svg.SvgView>
                                  </android.widget.Button>
                                </android.view.ViewGroup>
                              </android.view.ViewGroup>
                            </android.widget.ScrollView>
                          </android.view.ViewGroup>
                        </android.view.ViewGroup>
                      </android.view.ViewGroup>
<redacted>
                    </android.view.ViewGroup>
                  </android.view.ViewGroup>
                </android.view.ViewGroup>
              </android.widget.FrameLayout>
            </android.widget.FrameLayout>
          </android.widget.FrameLayout>
        </android.widget.LinearLayout>
      </android.widget.FrameLayout>
    </android.widget.LinearLayout>
  </android.widget.FrameLayout>
</hierarchy>
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/e9-typed.txt
<redacted>
<redacted>
<redacted>
                                      </com.horcrux.svg.GroupView>
                                    </com.horcrux.svg.SvgView>
                                  </android.widget.Button>
                                </android.view.ViewGroup>
                              </android.view.ViewGroup>
                            </android.widget.ScrollView>
                          </android.view.ViewGroup>
                        </android.view.ViewGroup>
                      </android.view.ViewGroup>
<redacted>
                    </android.view.ViewGroup>
                  </android.view.ViewGroup>
                </android.view.ViewGroup>
              </android.widget.FrameLayout>
            </android.widget.FrameLayout>
          </android.widget.FrameLayout>
        </android.widget.LinearLayout>
      </android.widget.FrameLayout>
    </android.widget.LinearLayout>
  </android.widget.FrameLayout>
</hierarchy>
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/scripted-e10.log
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.ImageView Logotip Kilo tappable [467,490][614,637]
android.widget.TextView Dobro došao u Kilo tappable [362,664][718,729]
android.widget.Button Prijavi se putem Google naloga tappable [99,785][981,901]
android.widget.TextView Prijavi se putem Google naloga tappable [222,812][924,873]
android.widget.Button Prijavi se pristupnim ključem tappable [99,928][981,1043]
android.widget.TextView Prijavi se pristupnim ključem tappable [222,955][924,1016]
android.widget.TextView ili tappable [529,1071][551,1108]
android.widget.TextView Adresa e-pošte tappable [99,1136][981,1182]
android.widget.EditText Adresa e-pošte i greška: Unesi svoju adresu e-pošte. tappable [99,1195][981,1311]
android.widget.TextView Unesi svoju adresu e-pošte. tappable [99,1325][981,1371]
android.widget.Button Nastavi putem e-pošte tappable [99,1398][981,1514]
android.widget.TextView Nastavi tappable [484,1432][596,1478]
android.widget.TextView Nastavkom se slažeš sa našim  tappable [203,1555][596,1592]
android.view.View Politika privatnosti tappable [419,1574][654,1648]
android.widget.TextView Politika privatnosti tappable [419,1592][654,1629]
android.view.View Uslovima korišćenja tappable [597,1537][850,1611]
android.widget.TextView Uslovima korišćenja tappable [597,1555][850,1592]
android.widget.TextView  i  tappable [849,1555][877,1592]
android.widget.TextView . tappable [653,1592][661,1629]
android.widget.Button Još opcija za prijavu tappable [99,1669][981,1785]
android.widget.TextView Još opcija za prijavu tappable [388,1703][691,1749]
android.widget.Button Jezik tappable [937,84][1038,185]
/home/igor_kilocode_ai/.local/share/kwf/sections/signin-label-axis-and-input-box-65ae/e2e-mobile-app/scripted-e11.log
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.ImageView Logotip Kilo tappable [467,490][614,637]
android.widget.TextView Dobro došao u Kilo tappable [362,664][718,729]
android.widget.Button Prijavi se putem Google naloga tappable [99,785][981,901]
android.widget.TextView Prijavi se putem Google naloga tappable [222,812][924,873]
android.widget.Button Prijavi se pristupnim ključem tappable [99,928][981,1043]
android.widget.TextView Prijavi se pristupnim ključem tappable [222,955][924,1016]
android.widget.TextView ili tappable [529,1071][551,1108]
android.widget.TextView Adresa e-pošte tappable [99,1136][981,1182]
android.widget.EditText Adresa e-pošte i greška: Unesi svoju adresu e-pošte. tappable [99,1195][981,1311]
android.widget.TextView Unesi svoju adresu e-pošte. tappable [99,1325][981,1371]
android.widget.Button Nastavi putem e-pošte tappable [99,1398][981,1514]
android.widget.TextView Nastavi tappable [484,1432][596,1478]
android.widget.TextView Nastavkom se slažeš sa našim  tappable [203,1555][596,1592]
android.view.View Politika privatnosti tappable [419,1574][654,1648]
android.widget.TextView Politika privatnosti tappable [419,1592][654,1629]
android.view.View Uslovima korišćenja tappable [597,1537][850,1611]
android.widget.TextView Uslovima korišćenja tappable [597,1555][850,1592]
android.widget.TextView  i  tappable [849,1555][877,1592]
android.widget.TextView . tappable [653,1592][661,1629]
android.widget.Button Još opcija za prijavu tappable [99,1669][981,1785]
android.widget.TextView Još opcija za prijavu tappable [388,1703][691,1749]
android.widget.Button Jezik tappable [937,84][1038,185]
Owner request

Surface: mobile-app

Three visual fixes on the sign-in screen: the three SSO button labels read ragged, the email
placeholder does not sit in the same box as typed text, and the legal links still carry odd gaps.
The screen is: sign-in, dark theme, Serbian, logo on top, three SSO buttons, an email field, a yellow
Nastavi button.

Fix the second one at the shared field component so the class cannot come back, and add the guard
that keeps it from coming back.

Read this first: PR #6567 is already merged

0863fe611d fix(mobile): unify sign-in provider chrome and tighten login spacing (#6567) is on main,
and it already did three things. Do not redo them, and do not undo them.

  • All three provider buttons are now the app's own Button variant="outline" with the same chrome.
    The native Apple control is gone.
  • The email-field-to-Continue gap is fixed.
  • The links lost the px-1 padding that was widening every gap.

So each fault below is what is LEFT after #6567, confirmed in the source at origin/main.

Fault 1 — the three provider labels do not share an axis

apps/mobile/src/components/login/idle-auth.tsx, the three buttons at :225-289. Each is:

<Button variant="outline" size="lg"
        className="min-h-[44px] w-full flex-row gap-2 rounded-[8px] py-2.5" ...>
  {glyph}
  <Text className="flex-1 text-center text-[17px] font-medium">{t('login.signInWithApple')}</Text>
</Button>

The row is flex-row gap-2 and the label is flex-1 text-center, so the label centres in the space
LEFT OVER after the glyph, not on the button. The glyph differs per row:

  • Apple: <AppleLogo size={18} />.
  • Google: <GoogleLogo size={18} />.
  • Passkey: nothing. The label fills the whole width and centres on the button.

That puts the passkey label about half a glyph plus a gap to the left of the other two, which is the
raggedness the owner sees. The busy state makes it worse: Apple and Google swap the 18pt glyph for an
ActivityIndicator of a different width, and the passkey ADDS one where there was none, so every
label shifts while a request is in flight.

Required: the three labels sit on one axis, the three glyph slots are the same width and sit in the
same place, and a label does not move when a spinner replaces its glyph. A passkey row with no glyph
of its own still reserves the slot. Pick the treatment that reads best and say why: a reserved glyph
slot on all three, an absolutely positioned glyph with the label centred on the button, or a real
passkey mark. Whatever you choose, the three rows must measure the same.

Fault 2 — the placeholder does not share the value's box. Fix it once.

apps/mobile/src/components/ui/form-field.tsx:85-95 is the shared field, and its own comment admits
the fault:

className={cn(
  // min-h-[44px] with no vertical padding: the 44pt height meets the
  // Apple HIG touch floor and centers the text, while the padding
  // draws the single-line text below the middle. min-h (not h) still
  // lets Dynamic Type grow the field past the floor.
  'min-h-[44px] rounded-md border border-input bg-background px-3 text-sm leading-[normal] text-foreground',
  ...
)}

A 44pt box with no vertical padding leaves the value's vertical position to the platform. On Android
textAlignVertical defaults to the top of a taller box while the placeholder is drawn by a different
path, so ime@primer.rs and typed text land on different baselines. leading-[normal] leaves the
line box to the font as well, so the two can differ in height as well as position.

Required, on both platforms:

  • One box for the placeholder and the value: explicit vertical padding, a defined line height, and
    textAlignVertical: 'center' on Android. The horizontal inset is already shared through px-3;
    keep it shared, and keep the existing RTL handling (withRtlInputAlignment in
    apps/mobile/src/lib/rtl-text.ts, applied at form-field.tsx:72).
  • The 44pt touch floor and Dynamic Type growth both survive: min-h, never a fixed h.
  • A focused field and an unfocused one put the text in the same place, and an error appearing under
    the field does not move the text inside it.

Then close the leak, so it cannot recur

FormField is the shared component, but 42 files still pass placeholder= to a raw <TextInput>,
so a fix in FormField alone does not reach them and a new raw input would reintroduce the class
tomorrow. Two deliverables:

  • A guard. A test that enumerates raw <TextInput> in apps/mobile/src/** and fails when a
    single-line field outside the shared component is added. It carries an explicit allowlist with a
    written reason for every exemption, and adding an entry must require stating why. Multiline
    composers are legitimately different controls and belong on that list; a one-line text field does
    not.
  • The migration the guard forces. Route every single-line field that shows a placeholder through
    the shared component, or give it the shared box through the same one place. The guard's allowlist
    is the complete list of what you left, and each entry needs its reason in the code. Do not migrate
    a multiline composer's behaviour; only its box, if it has the same fault.

This is the "never again" half of the request. A shared fix with no guard is the shape that let this
come back.

Fault 3 — the legal links still carry odd gaps

idle-auth.tsx:357-378. #6567 removed the px-1, so the remaining slack comes from the reserved
boxes in apps/mobile/src/lib/a11y/tap-target.ts:

  • INLINE_LINK_BOX_CLASS = min-h-[28px] min-w-[28px] items-center justify-center, so the row is
    28pt tall around a text-xs line of about 14pt. That vertical inflation is the "weird gap" above
    and below the sentence, and the comment at idle-auth.tsx:348-355 shows the row carries extra
    margin on top of it for the 44pt reach.
  • INLINE_LINK_CONNECTOR_CLASS = min-w-[20px] text-center, so a short conjunction such as the
    Serbian i is centred inside 20pt of reserved width.
  • login.termsPrefix ends with a space AND the connector carries its own leading and trailing
    spaces, so at least one gap is a double space.

Required: the sentence reads as one line of text with the sentence's own spacing, the final period
sits against the last link, and the row is no taller than the text it holds. The 44pt touch reach and
the 28dp control-size audit floor must both survive — the audit reads the control's own node rect, so
hitSlop alone cannot carry it. The facing slops must not overlap. Keep the mechanism layout-neutral
so the visible line is plain prose.

Non-goals

Files

  • apps/mobile/src/components/ui/form-field.tsx — fault 2, the shared field.
  • apps/mobile/src/lib/rtl-text.ts — the shared input style helper.
  • apps/mobile/src/components/ui/form-field.mounted.test.tsx — the field's existing tests.
  • apps/mobile/src/components/login/idle-auth.tsx — faults 1 and 3.
  • apps/mobile/src/components/ui/button.tsx — only if the label axis is best fixed in the Button.
  • apps/mobile/src/lib/a11y/tap-target.ts — fault 3.
  • The single-line fields the new guard enumerates, each with its reason if it stays exempt.
  • A new test for the guard.

Do not edit a file outside this list.

Proof

Reproduce first. Sign out, then capture the sign-in screen in dark theme with the Serbian locale
and show all three faults. Then capture the same screen after the change. This change is visible, so
the screenshots are required, not optional.

  • Fault 1: one capture with all three provider buttons visible, and the measured x of each label
    and each glyph slot. The three labels must start at the same x. Capture the busy state too, or
    state that you could not, so the label does not move when the spinner appears.
  • Fault 2: capture the email field empty and with ime@primer.rs typed, in dark and in light.
    Quote the resolved input style that makes the two share a box, and say which platform you measured.
    Prove the other platform if the two differ; if you could not, say so plainly.
  • Fault 3: capture the legal line, and give the gap widths in the same units the earlier report
    used. The sentence's own word space is the reference.
  • The guard: show the guard test failing when a raw single-line TextInput is added, and passing
    when it is routed through the shared component. That is the proof the class cannot recur.
  • Keep pnpm --filter @kilocode/mobile test green, plus the mounted suite the section runbook names.

[e13] ux-check: Kilo Claw onboarding (Android): the bot-name and location fields draw their placeholder and typed value on the same baseline. — android emulator-5554 (app locale sr), identity step forced via the pack's sanctioned temporary fixture (gate at onboarding-flow.tsx), reverted after capture (git clean); e13-live-scene.log 'SCENE e13 OK' + 'SCENE e13-typed OK' shows EditText 'Ime bota' and 'KiloBot' both at [193,250][1043,379] and 'Grad ili region (opciono)' and 'Beograd' both at [37,761][925,863]; e13-scene.xml/e13-typed-scene.xml show the same node with showing-hint true vs false over the identical bounds, so placeholder and value share the baseline; static nodes identical between frames, no UX-DEFECT; screenshots for the…

[e13] ux-check: Kilo Claw onboarding (Android): the bot-name and location fields draw their placeholder and typed value on the same baseline. — e13.png

[e1] Fault 1 provider label axis + glyph slot (android, sr, dark) — android emulator-5554, app locale sr: Google label x=222 and passkey label x=222 are equal (e1-hierarchy.xml), the passkey row reserves the 18dp slot though it draws no mark (no glyph node, same 123px label offset), the Google slot is 47px=17.9dp; the Apple row is iOS-only so android shows two provider rows; busy state not driven (SSO ceremony, allowed by the request); fresh SCENE e1 OK after STATE HIT signed-out.

[e1] Fault 1 provider label axis + glyph slot (android, sr, dark) — e1.png

[e1] Fault 1 provider label axis + glyph slot (android, sr, dark)

[e1] Fault 1 provider label axis + glyph slot (android, sr, dark) — e1-hierarchy.png

Follow-ups (not changed here)

  • not proved live: Fault 1 (dark, Japanese-free Serbian locale): the sign-in screen shows all three provider rows and each label starts at the same x with the same 18pt glyph slot; the passkey row reserves its slot though it draws no mark. Verifier: read the three labels' and the three slots' bounds from the UI tree and report the x of each (they must be equal); optionally drive a provider to busy and capture that the label x is unchanged - the request allows recording that you could not drive a sign-in ceremony. (no capture cited it)
  • not proved live: Fault 3 (dark, Serbian): the legal line reads as one prose line - 'Nastavkom se slaze se sa nasim Uslovima koriscenja i Politika privatnosti.' - with the period tight to the last link and the gap around the conjunction 'i' no wider than the sentence's own word space; both links still carry a 44pt touch region on a 28dp node rect whose facing regions do not overlap. Verifier: measure the gap widths around 'i' in dp against the word space between two ordinary words in the same line, and read both links' bounds from the UI tree. (no capture cited it)
  • not proved live: Migrated search field (dark, Serbian): from the signed-out sign-in screen open the language picker and use its search box - the placeholder 'Pretraga jezika' and the typed query sit in the same box (same x and y), and clearing the query brings the placeholder back. Verifier: measure the text origin with the field empty and after typing, and confirm the typed text is filtered from the same node. (no capture cited it)
  • not proved live: ux-check: Sign-in email field, dark and light, iOS and Android: the empty placeholder and the typed value 'ime@primer.rs' share one baseline and one horizontal inset; a value cannot be distinguished from its placeholder by position. (no capture cited it)
  • not proved live: iOS: not run — the diff forks on no platform, so Android proves both

e6-tree

Merge proof

origin/main merged into this branch as merge commit 589317d638 (parents 51033771f2 + 8d07bf579c). Four files conflicted; each kept main's discoverability/react-native structure plus this branch's shared Input. One follow-up commit 88950b86aa aligned main's newly added test and the merged value imports with the resolved component.

Merged cleanly with no conflict markers:

$ git grep -n "^<<<<<<< " -- .
(no output)

Full mobile suite, from apps/mobile:

$ pnpm exec vitest run
 Test Files  1030 passed (1030)
      Tests  15897 passed (15897)

The one real merge defect the suite caught, and its fix:

FAIL |mobile-pure| src/components/pr-review/pr-review-entry-screen.test.ts > provider-neutral URL field > states the instruction once, in the header eyebrow, not the field caption
Error: no TextInput matched the predicate

main's #6614 added that test looking for a raw TextInput host, while the resolved screen renders the shared single-line box (@/components/ui/input), so the assertion follows the other nine in the same file to find(tree, 'Input', () => true). The same repair marked TextInput as a type-only import in pr-review-entry-screen.tsx and model-picker-content.tsx; pnpm run typecheck (tsgo --noEmit) exits 0 and the mobile oxlint config reports 0 errors.

@iscekic
iscekic marked this pull request as draft September 23, 2026 12:26
Comment thread apps/mobile/src/lib/single-line-input-guard.test.ts Outdated
Comment thread apps/mobile/src/lib/single-line-input-guard.test.ts Outdated
Comment thread apps/mobile/src/components/agents/session-list-search-header.tsx Outdated
Comment thread apps/mobile/src/components/login/email-otp-form.tsx
@kilo-code-bot

kilo-code-bot Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of the origin/main merge (589317d6) plus follow-up 88950b86 found no new defects: the only PR-authored changes since the prior review at 8556f2f are a type-only TextInput import correction and one test finder aligned to the shared Input, and the ten files that changed reconcile main's FlashList and ref-clearing work with this branch's shared single-line Input correctly.

Files Reviewed (10 incremental files; 29 unchanged since commit 8556f2f)
  • apps/mobile/src/components/agents/model-picker-content.tsx
  • apps/mobile/src/components/agents/model-picker-content.mounted.test.tsx
  • apps/mobile/src/components/agents/picker-search.mounted.test.tsx
  • apps/mobile/src/components/language-picker-sheet.tsx
  • apps/mobile/src/components/language-picker-sheet.mounted.test.tsx
  • apps/mobile/src/components/voice-language-picker-sheet.tsx
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts
  • apps/mobile/src/components/share/share-destination-list.tsx
  • apps/mobile/src/components/share/share-destination-list.mounted.test.tsx
Previous Review Summaries (2 snapshots, latest commit 8556f2f)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 8556f2f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the full 39-file mobile change at HEAD 8556f2f (the shared single-line Input, the raw-TextInput guard, the asymmetric inline-link hit slop, and the sign-in provider/legal-line work); no new defects found, and the two previously reported guard findings (bare multiline token match and unescaped alias interpolation) are fixed in the current code.

Files Reviewed (39 files)
  • apps/mobile/src/app/(app)/agent-chat/repo-picker.tsx
  • apps/mobile/src/components/agents/model-picker-content.mounted.test.tsx
  • apps/mobile/src/components/agents/model-picker-content.tsx
  • apps/mobile/src/components/agents/picker-search.mounted.test.tsx
  • apps/mobile/src/components/agents/question-card-actions.mounted.test.tsx
  • apps/mobile/src/components/agents/question-card.mounted.test.tsx
  • apps/mobile/src/components/agents/question-card.tsx
  • apps/mobile/src/components/agents/session-list-search-header.mounted.test.tsx
  • apps/mobile/src/components/agents/session-list-search-header.touch-target.test.tsx
  • apps/mobile/src/components/agents/session-list-search-header.tsx
  • apps/mobile/src/components/code-reviewer/bitbucket-connect-form.tsx
  • apps/mobile/src/components/code-reviewer/manual-review-screen.mounted.test.tsx
  • apps/mobile/src/components/code-reviewer/manual-review-screen.tsx
  • apps/mobile/src/components/language-picker-sheet.mounted.test.tsx
  • apps/mobile/src/components/language-picker-sheet.tsx
  • apps/mobile/src/components/login/__tests__/idle-auth-email-flow.mounted.test.tsx
  • apps/mobile/src/components/login/__tests__/idle-auth.mounted.test.tsx
  • apps/mobile/src/components/login/email-otp-form.tsx
  • apps/mobile/src/components/login/idle-auth.tsx
  • apps/mobile/src/components/pr-review/diff/pr-diff-file-navigator.test.tsx
  • apps/mobile/src/components/pr-review/diff/pr-diff-file-navigator.tsx
  • apps/mobile/src/components/pr-review/pr-review-entry-screen-test-utils.ts
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx
  • apps/mobile/src/components/rename-modal.mounted.test.tsx
  • apps/mobile/src/components/rename-modal.tsx
  • apps/mobile/src/components/security-agent/notification-settings-screen.tsx
  • apps/mobile/src/components/security-agent/sla-settings-screen.tsx
  • apps/mobile/src/components/share/share-destination-list.mounted.test.tsx
  • apps/mobile/src/components/share/share-destination-list.tsx
  • apps/mobile/src/components/ui/form-field.mounted.test.tsx
  • apps/mobile/src/components/ui/form-field.tsx
  • apps/mobile/src/components/ui/input.mounted.test.tsx
  • apps/mobile/src/components/ui/input.tsx
  • apps/mobile/src/components/voice-language-picker-sheet.tsx
  • apps/mobile/src/lib/a11y/tap-target.test.ts
  • apps/mobile/src/lib/a11y/tap-target.ts
  • apps/mobile/src/lib/rtl-text.ts
  • apps/mobile/src/lib/single-line-input-guard.test.ts

Previous review (commit d7e3d5a)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 3
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/lib/single-line-input-guard.test.ts 117 The guard's multiline token test matches the bare word, so multiline={false} passes and an allowlisted composer can hide a single-line field

SUGGESTION

File Line Issue
apps/mobile/src/lib/single-line-input-guard.test.ts 172 Alias names interpolated into the scan RegExp unescaped ($ is a legal identifier char yet a regex anchor) and only the first alias per import block is registered
apps/mobile/src/components/agents/session-list-search-header.tsx 62 The shared 44pt field floor now makes the row ~56.5pt, so the min-h-[51px] comment is stale and the PR proof's no-jump claim no longer holds
apps/mobile/src/components/login/email-otp-form.tsx 71 min-h-[48px] is 6pt taller than the removed h-12 (42pt at the app's 14pt rem), so the comment's scale claim is inaccurate
Files Reviewed (38 files)
  • apps/mobile/src/app/(app)/agent-chat/repo-picker.tsx
  • apps/mobile/src/components/agents/model-picker-content.mounted.test.tsx
  • apps/mobile/src/components/agents/model-picker-content.tsx
  • apps/mobile/src/components/agents/picker-search.mounted.test.tsx
  • apps/mobile/src/components/agents/question-card-actions.mounted.test.tsx
  • apps/mobile/src/components/agents/question-card.mounted.test.tsx
  • apps/mobile/src/components/agents/question-card.tsx
  • apps/mobile/src/components/agents/session-list-search-header.mounted.test.tsx
  • apps/mobile/src/components/agents/session-list-search-header.touch-target.test.tsx
  • apps/mobile/src/components/agents/session-list-search-header.tsx - 1 issue
  • apps/mobile/src/components/code-reviewer/bitbucket-connect-form.tsx
  • apps/mobile/src/components/code-reviewer/manual-review-screen.mounted.test.tsx
  • apps/mobile/src/components/code-reviewer/manual-review-screen.tsx
  • apps/mobile/src/components/language-picker-sheet.tsx
  • apps/mobile/src/components/login/__tests__/idle-auth-email-flow.mounted.test.tsx
  • apps/mobile/src/components/login/__tests__/idle-auth.mounted.test.tsx
  • apps/mobile/src/components/login/email-otp-form.tsx - 1 issue
  • apps/mobile/src/components/login/idle-auth.tsx
  • apps/mobile/src/components/pr-review/diff/pr-diff-file-navigator.test.tsx
  • apps/mobile/src/components/pr-review/diff/pr-diff-file-navigator.tsx
  • apps/mobile/src/components/pr-review/pr-review-entry-screen-test-utils.ts
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx
  • apps/mobile/src/components/rename-modal.mounted.test.tsx
  • apps/mobile/src/components/rename-modal.tsx
  • apps/mobile/src/components/security-agent/notification-settings-screen.tsx
  • apps/mobile/src/components/security-agent/sla-settings-screen.tsx
  • apps/mobile/src/components/share/share-destination-list.mounted.test.tsx
  • apps/mobile/src/components/share/share-destination-list.tsx
  • apps/mobile/src/components/ui/form-field.mounted.test.tsx
  • apps/mobile/src/components/ui/form-field.tsx
  • apps/mobile/src/components/ui/input.mounted.test.tsx
  • apps/mobile/src/components/ui/input.tsx
  • apps/mobile/src/components/voice-language-picker-sheet.tsx
  • apps/mobile/src/lib/a11y/tap-target.test.ts
  • apps/mobile/src/lib/a11y/tap-target.ts
  • apps/mobile/src/lib/rtl-text.ts
  • apps/mobile/src/lib/single-line-input-guard.test.ts - 2 issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@iscekic

iscekic commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator Author

bot: rejected: a suggestion, not a defect. A typed review read this finding as needing no code change before merge; the code stays as is. Say so here if one of them does change behaviour and it will be repaired.

  • apps/mobile/src/components/login/email-otp-form.tsx:71 — min-h-[48px] is 6pt taller than the removed h-12 (42pt at the app's 14pt rem), so the comment's scale claim is inaccurate (p=0.81)

@iscekic
iscekic force-pushed the kwf/signin-label-axis-and-input-box-65ae branch from 2cdd920 to 8556f2f Compare September 23, 2026 16:58
@iscekic
iscekic marked this pull request as ready for review September 23, 2026 17:18
@iscekic

iscekic commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator Author

This description names a scenario the proof did not capture:

  • not proved live: Fault 1 (dark, Japanese-free Serbian locale): the sign-in screen shows all three provider rows and each label starts at the same x with the same 18pt glyph slot; the passkey row reserves its slot though it draws no mark. Verifier: read the three labels' and the three slots' bounds from the UI tree and report the x of each (they must be equal); optionally drive a provider to busy and capture that the label x is unchanged - the request allows recording that you could not drive a sign-in ceremony. (no capture cited it)

A repeated proof run rebuilds the same evidence, so no proof run is dispatched for a named gap. Merging with this gap open is your decision.

@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 23, 2026
@iscekic iscekic self-assigned this Sep 23, 2026
Four conflicts, all from main's FlashList migration and the merged #6614
PR Review header tidy meeting this branch's shared single-line input box.

- model-picker-content.tsx: take main's react-native import (FlashList
  replaced FlatList in the body).
- share-destination-list.tsx: import only View and ViewStyle; the body
  keeps this branch's shared Input and main's FlashList.
- share-destination-list.mounted.test.tsx: main's react-native + flash-list
  mock structure, keeping the I18nManager stub the shared Input needs.
- pr-review-entry-screen.tsx: take main's tidied paste block (no separate
  header, from #6614) and swap its TextInput back to the shared Input box,
  which owns the height floor and the one line box.
The merge of origin/main into this branch kept main's new
pr-review-entry-screen test looking for a `TextInput` host and main's
value imports of `TextInput`, while this branch renders the shared
single-line box from `@/components/ui/input` and only uses `TextInput`
as a ref type.
@iscekic
iscekic merged commit 3a8c645 into main Sep 24, 2026
29 checks passed
@iscekic
iscekic deleted the kwf/signin-label-axis-and-input-box-65ae branch September 24, 2026 14:36
iscekic pushed a commit to Kilo-Org/kilocode that referenced this pull request Sep 26, 2026
…4554)

## Automated docs sync — 2026-09-25

This PR keeps kilo.ai/docs in sync with features merged to [Kilo-Org/cloud](https://github.com/Kilo-Org/cloud) and [Kilo-Org/kilocode](https://github.com/Kilo-Org/kilocode). Every change below links to the merged PR it documents.

- Window: `2026-09-24T07:08:33.639Z` → `2026-09-25T07:05:29.302Z`
- Verification (docs build + tests): **passing**

### Surface: `cloud-mobile`

- Assignees / requested reviewers: @iscekic and @eshurakov
- Derivation: Derived from the repository layout. A product surface is a package under packages/ that ships a distinct client, plugin, backend, or hosted service: cli = packages/opencode/ + packages/tui/ + packages/server/ + packages/sdk/ + packages/plugin/; vscode = packages/kilo-vscode/ + packages/kilo-web-ui/ + packages/kilo-ui/; jetbrains = packages/kilo-jetbrains/; gateway = packages/kilo-gateway/; web = packages/kilo-console/ + packages/kilo-indexing/ + packages/kilo-memory/ + packages/kilo-sandbox/. Docs route from the IA tree packages/kilo-docs/pages/ plus docs/jetbrains-vscode-settings-parity.md: each surface lists the pages sections that document it, and the per-platform pages under packages/kilo-docs/pages/code-with-ai/platforms/ map to the matching extension surface (the vscode/ directory to vscode, jetbrains.md to jetbrains). A doc path belongs to the surface with the longest matching prefix; a path that matches none of those prefixes falls to `other` (the explicit other prefixes are listed under other.docs). The cloud surfaces are derived the same way from the Kilo-Org/cloud layout: cloud-mobile = apps/mobile/, cloud-web = apps/web/, cloud-extension = apps/extension/, and cloud-agent = the cloud-agent packages under packages/ (packages/cloud-agent-sdk/ + packages/cloud-agent-profile/). A cloud source names its repository while a bare string still means this repository. The pages under packages/kilo-docs/pages/collaborate/ document the cloud web app (app.kilo.ai: teams dashboard, billing, SSO, adoption dashboard), so they route to cloud-web. No page under packages/kilo-docs/pages/ documents the browser side-panel extension yet, so cloud-extension lists no docs prefix.
- Map: `.github/docs-sync/surfaces.json`
- Surface map: `cli`, `vscode`, `jetbrains`, `gateway`, `web`, `cloud-mobile`, `cloud-web`, `cloud-extension`, `cloud-agent`, `other`
- Source prefixes: `apps/mobile/` (Kilo-Org/cloud)
- Doc prefixes: `packages/kilo-docs/pages/code-with-ai/platforms/mobile.md`
- Paths that fall to `other`: `packages/kilo-docs/pages/community/`, `packages/kilo-docs/pages/kiloclaw/`, `packages/kilo-docs/pages/contributing/`, `packages/kilo-docs/LEARNINGS.md`, `docs/`
- Reviewers are ranked from `Kilo-Org/cloud`; the workflow needs a token with `contents: read` on that repository (repository secret `CROSS_REPO_ACCESS_TOKEN`, exposed to the upsert step as `CLOUD_REPO_TOKEN`).
- How the two were computed: Reviewers for `cloud-mobile` are ranked from `Kilo-Org/cloud` git history over `apps/mobile/` (a commit 180 days old counts half as much, half-life 180 days). Bots (author type "Bot" or a login matching /\[bot\]$/i) and people without admin, write, or maintain permission are excluded.

### Changes

<!-- docs-sync:changes:start -->
| Docs change | Source |
| --- | --- |
| updated pages/code-with-ai/platforms/mobile.md | [Kilo-Org/cloud#6386](Kilo-Org/cloud#6386) |
| updated pages/ai-providers/openai-chatgpt-plus-pro.md | [Kilo-Org/cloud#6702](Kilo-Org/cloud#6702) |
| updated pages/code-with-ai/platforms/cloud-agent.md | [Kilo-Org/cloud#6683](Kilo-Org/cloud#6683) |
| updated pages/getting-started/byok.md | [Kilo-Org/cloud#6692](Kilo-Org/cloud#6692) |
<!-- docs-sync:changes:end -->

### Pending — will retry

<!-- docs-sync:pending:start -->
_None._
<!-- docs-sync:pending:end -->

### Considered, no docs change needed

<!-- docs-sync:skipped:start -->
| PR | Reason |
| --- | --- |
| [Kilo-Org/cloud#6658](Kilo-Org/cloud#6658) | Internal sandbox lifecycle fix with no user-visible workflow or setting. |
| [Kilo-Org/cloud#6673](Kilo-Org/cloud#6673) | Internal container CA trust plumbing, no user-facing behavior. |
| [Kilo-Org/cloud#6672](Kilo-Org/cloud#6672) | Internal sandbox launch/recovery fix with no documented workflow change. |
| [Kilo-Org/cloud#6660](Kilo-Org/cloud#6660) | Internal cloud-agent queue delivery fix; no new command, setting, or workflow for users. |
| [Kilo-Org/cloud#6226](Kilo-Org/cloud#6226) | Internal gateway alias-routing change, not user-visible. |
| [#14490](#14490) | Tool-call animation and streaming UI polish; users do not need to learn a new workflow. |
| [#14530](#14530) | Bug fix restoring intended worktree-pool behavior, no doc change needed. |
| [#14529](#14529) | Bug fix restoring tab/panel state across project switches. |
| [#14531](#14531) | Reconnect recovery bug fix, restores already-documented behavior. |
| [#14532](#14532) | Bug fix keeping session tab title in sync on rename. |
| [Kilo-Org/cloud#6088](Kilo-Org/cloud#6088) | Removes internal/admin model-experiment surfaces, not public product docs. |
| [Kilo-Org/cloud#6682](Kilo-Org/cloud#6682) | Internal control-socket reconnect race fix, no user-facing change. |
| [#14534](#14534) | Transcript re-render performance bug fix. |
| [#14535](#14535) | Bug fix preserving the loaded browser page across context switches. |
| [Kilo-Org/cloud#6684](Kilo-Org/cloud#6684) | Reverted by Kilo-Org/cloud#6685. |
| [Kilo-Org/cloud#6678](Kilo-Org/cloud#6678) | Dead-code constant removal, no user-visible effect. |
| [Kilo-Org/cloud#6687](Kilo-Org/cloud#6687) | Removes internal model-experiment maintenance and retains tables, no user-facing change. |
| [#14515](#14515) | JetBrains plugin unload crash fix, no documented behavior change. |
| [#14520](#14520) | JetBrains transcript/list rendering performance work. |
| [Kilo-Org/cloud#6614](Kilo-Org/cloud#6614) | Mobile PR Review header and session title bug fix, no doc change needed. |
| [Kilo-Org/cloud#6625](Kilo-Org/cloud#6625) | Internal mobile secure-store error-handling refactor. |
| [Kilo-Org/cloud#6624](Kilo-Org/cloud#6624) | Mobile auth bug fix that stops a retry loop; restores expected sign-in behavior with no new setting or workflow. |
| [#14310](#14310) | Contributor/CI fix making the kilo-v2 checkout installable; not user-visible product behavior. |
| [Kilo-Org/cloud#6611](Kilo-Org/cloud#6611) | Mobile notification-tap fix that selects the session's organization; restores correct behavior rather than adding a learnable feature. |
| [Kilo-Org/cloud#6644](Kilo-Org/cloud#6644) | Mobile sign-in layout/alignment polish; no change to what a user must do. |
| [Kilo-Org/cloud#6601](Kilo-Org/cloud#6601) | Mobile layout fix keeping empty states clear of the tab bar; purely visual. |
| [#14543](#14543) | CI/release infrastructure adding Windows binary code signing; no public docs impact. |
| [Kilo-Org/cloud#6616](Kilo-Org/cloud#6616) | Mobile visual defect fixes and a session-title fallback; no new user workflow or setting. |
| [Kilo-Org/cloud#6630](Kilo-Org/cloud#6630) | Reports an edge-case partial worktree restore; failure-path plumbing with no new user-facing workflow, target setting, or config. |
| [Kilo-Org/cloud#6699](Kilo-Org/cloud#6699) | Cloud Agent e2e stabilization plus internal idle-sandbox capacity handling; not user-visible. |
| [#14545](#14545) | Automated JetBrains release/changelog PR; underlying user-facing changes are triaged from their own PRs. |
| [Kilo-Org/cloud#6708](Kilo-Org/cloud#6708) | Internal AI-gateway request-logging policy change in the admin panel; no existing public docs surface and no change to how users run Kilo Code. |
| [#14533](#14533) | Documentation already shipped with the merged PR. The experimental.task_model_selection flag is gone from the current source, and pages/code-with-ai/agents/model-selection.md, pages/code-with-ai/agents/context-mentions.md, and pages/getting-started/settings/index.md already describe per-task selection as default-on with no stale experiment references. |
| [#14510](#14510) | Documentation already shipped with the merged PR. Marketplace companion-skill support is present in the current source (packages/opencode/src/kilocode/marketplace/companions.ts and installer), and pages/customize/marketplace.md already documents installing, publishing, and removing MCP servers with companion skills. |
<!-- docs-sync:skipped:end -->

---

(bot) Generated by the docs-sync workflow. Humans review and merge; while this PR stays open, the next daily run appends new changes here. Branch: `docs/auto-sync-2026-09-25`.
<!-- docs-sync: processed-through 2026-09-25T07:05:29.302Z -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants