refactor(mobile): consolidate tap-target geometry into one module - #6707
Conversation
Surface: the mobile app (apps/mobile). ## Problem Mobile tap-target geometry is claimed to have one owner, but two modules export the same constant name with different values. Importing `COMPACT_CONTROL_HIT_SLOP_DP` from the wrong file silently applies 3dp instead of 8dp (or the reverse), so a compact icon button and an `h-11` PR-review control can drift without a type error. Evidence: - `apps/mobile/src/lib/a11y/tap-target.ts:1-3` — comment: the one place mobile tap-target geometry lives. - `apps/mobile/src/lib/a11y/tap-target.ts:10` — `MIN_TAP_TARGET_DP = 28`. - `apps/mobile/src/lib/a11y/tap-target.ts:26` — 32px compact box class. - `apps/mobile/src/lib/a11y/tap-target.ts:35` — `COMPACT_CONTROL_HIT_SLOP_DP = 8` (32 + 16 = 48pt reach). - `apps/mobile/src/lib/a11y/tap-target.ts:120-121` — `tapTargetReachDp(boxDp, slopDp)` is box + 2 * slop. - `apps/mobile/src/components/ui/icon-button.tsx:3` and `:10-14` — IconButton imports that 8dp slop from `tap-target`. - `apps/mobile/src/lib/a11y/touch-target.ts:17` — `MIN_AUDITED_CONTROL_FRAME_DP = 28` (same floor, second name). - `apps/mobile/src/lib/a11y/touch-target.ts:20` — `COMPACT_CONTROL_FRAME_DP = 38.5` (`h-11` at a 14pt rem). - `apps/mobile/src/lib/a11y/touch-target.ts:23` — `COMPACT_CONTROL_HIT_SLOP_DP = 3` (same export name, different value). - `apps/mobile/src/lib/a11y/touch-target.ts:26-27` — `compactControlTargetDp()` repeats `tapTargetReachDp` arithmetic. - `apps/mobile/src/components/pr-review/discussion/discussion-t
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe incremental commit Files Reviewed (1 file)
Incremental review of Previous Review Summary (commit 71f75e7)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 71f75e7)Status: No Issues Found | Recommendation: Merge Executive SummaryThe tap-target consolidation is a value-preserving rename (38.5/3 and 28/8 mappings verified identical) and the new empty-PLATFORM guard matches the existing PROJECT guard; no dangling references to the deleted Files Reviewed (11 files)
Notes
Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0 Review guidance: REVIEW.md from base branch |
|
Pushed Cause. The rename moved Fix. The test mocks Evidence. All runs for |
Changelog for users
Changelog for maintainers
apps/mobile/src/lib/a11y/tap-target.tsnow owns all mobile tap-target geometry;touch-target.tsand its test are deleted.@/lib/a11y/touch-targetremains, andrg -n 'export const COMPACT_CONTROL_HIT_SLOP_DP' apps/mobile/srcreturns exactly one hit, the 8dp value intap-target.ts.h-11geometry now uses distinct names,COMPACT_H11_FRAME_DP = 38.5andCOMPACT_H11_HIT_SLOP_DP = 3.compactControlTargetDp()delegates totapTargetReachDp, andMIN_TAP_TARGET_DP = 28is the single 28dp floor.tap-target.tsfirst; the rest is rename and repoint, and a stale import fails typecheck instead of drifting silently.E2E proof
[e2] ux-check: Agents header search opens and filter opens its sheet, 32px box — Aandroid emulator-5554 from signed-in-home (STATE HIT, e2-state7.log); filter sheet opens — e2-scene5.log 'SCENE e2 OK' with 'android.widget.TextView PROJECT tappable [101,1102][979,1139]' and 'android.widget.Button Apply tappable [821,1277][979,1393]' and no orphaned PLATFORM label (the changed guard); search opens — e2-search.log 'SCENE e2search OK' with 'android.widget.Button Clear search tappable [902,280][1001,380]' and 'android.widget.TextView No sessions match tappable [360,1084][720,1149]'; header tree e2-header.txt shows 'content-desc="Filter sessions"…
[e4] ux-check: header search opens search and filter opens its sheet — android emulator-5554; e4-scene.log 'SCENE e4 OK' with digest 'android.view.View Filter sessions tappable [100,971][978,1027]' plus PLATFORM/PROJECT/Apply proves the filter sheet; e4-header.txt shows the header controls (content-desc="Filter sessions" resource-id="agents-open-filters", content-desc="Search sessions") and e4-search.txt shows content-desc="Clear search" with 'No sessions match' after typing, so search opens. Header capture e4-header.png (header, search, filter stills) left for the visual reviewer; 32px visual box is their judgement. No UX-DEFECT observed.
[e2] PR review resolve control still toggles (android, platform:both scope) — Android: restored pr-review, then opened a real PR with a review thread (#6694) because that state opens #6054 which has no review thread, and ran the replay (e2nav.log: 'SCENE e2nav OK'); the tap flipped the thread to resolved (e2-thread-resolved.txt: content-desc="Unresolve thread", text="RESOLVED") and back to unresolved (e2-thread-unresolved.txt: content-desc="Resolve thread"), the control's frame bounds "[908,508][1009,609]" identical in both states; harness obstacle filed as obstacle:state-pr-review-empty-discussion.
[e5] ux-check: Resolve control toggles to Unresolve and back and keeps its h-11 frame (android, platform:both scope) — Android: tapped Resolve then Unresolve on the thread header control (e2nav.log: 'SCENE e2nav OK'; e2-thread-resolved.txt: content-desc="Unresolve thread" with text="RESOLVED"; e2-thread-unresolved.txt: content-desc="Resolve thread"), the 101px h-11 frame bounds "[908,508][1009,609]" unchanged on tap; UX audit of the visited thread-header, PR Overview and PR Review entry screens found no UX-DEFECT (screenshots e2-resolve-control-resolved.png, e2-resolve-control-unresolved.png, e2-pr-overview.png, e2-pr-review-entry.png).
[e5] ux-check: Resolve control toggles to Unresolve and back and keeps its h-11 frame (android, platform:both scope)
[p4] ux-check: On the Agents screen, tapping the compact header search control opens search and tapping the filter control opens its sheet; both still occupy their 32px visual box (screenshot the header). — Android (emulator-5604), pr-review start state restored (STATE HIT). One scene call: PR-detail -> Go back -> Agents tab -> tap 'Search sessions'+type -> assert 'Clear search' passed -> Clear -> tap 'Filter sessions' -> assert sheet passed; p4-scene.log line 108 'SCENE p4 OK' with the sheet digest 'android.widget.TextView PROJECT' plus Cancel/Apply and no PLATFORM label — the empty-platform guard omits the orphaned section (e4-filter repaired). Search-open recorded in p4search-scene.log:34 'SCENE p4search OK' showing 'android.widget.Button Clear search tappable [902,345][1001,445]' beside 'No…
Owner request
[e6] ux-check: overflowing comment row - overflow opens moderation sheet, pill opens session (android) — ux-check pass on android: from the pr-review state, tapping the h-11 overflow rendered the sheet options 'Report content'/'Report user'/'Mute'/'Block' plus 'Cancel' (e6-overflow.txt, still e6-overflow.png), and after Cancel the pill's own tap rendered 'New session' with the prefilled PR-comment link and none of the sheet options (e6-pill.txt, still e6-pill.png); the same both-branch result is in e3-run3.log.
[e6] ux-check: overflowing comment row - overflow opens moderation sheet, pill opens session (android)
[p4] ux-check: On the Agents screen, tapping the compact header search control opens search and tapping the filter control opens its sheet; both still occupy their 32px visual box (screenshot the header). — Android (emulator-5604), pr-review start state restored (STATE HIT). One scene call: PR-detail -> Go back -> Agents tab -> tap 'Search sessions'+type -> assert 'Clear search' passed -> Clear -> tap 'Filter sessions' -> assert sheet passed; p4-scene.log line 108 'SCENE p4 OK' with the sheet digest 'android.widget.TextView PROJECT' plus Cancel/Apply and no PLATFORM label — the empty-platform guard omits the orphaned section (e4-filter repaired). Search-open recorded in p4search-scene.log:34 'SCENE p4search OK' showing 'android.widget.Button Clear search tappable [902,345][1001,445]' beside 'No…
[p4] ux-check: On the Agents screen, tapping the compact header search control opens search and tapping the filter control opens its sheet; both still occupy their 32px visual box (screenshot the header).
Follow-ups (not changed here)
Open findings (not fixed here)