Review of the external UI/UX audit (Antigravity, 2026-09-17)
Status: Accepted · Date: 2026-09-17 · Reviewed: ui_ux_audit_report.md ("Comprehensive UI/UX System Audit & Implementation Harness") · Method: every claim checked against the code that runs today (file:line), the ratified canon (docs/canon/*) and the owner rulings of 2026-09-06 → 2026-09-17.
Verdict
The report reads the canon well and its principles are sound, but its execution matrix is not safe to run as written:
- 9 of its 21 concrete items are already shipped — six of them before the report was written, three by this morning's primitive-drift pass.
- 5 items reverse rulings the owner made in the last eleven days (profile stays flat; native static-map thumbnails; no middle-dot joins; emoji never labels an action; the 경기 tab keeps its four panes). The report's own mock-ups break two of those rules, which shows it was written without them.
- 4 items describe code that does not exist (ClubCard nesting a whole session card, a missing PlaceShell inset provider, a 4 px skeleton shift, chips pinning over the bar).
- 3 items are valid and small — worth doing now.
- 3 items are real design proposals — the card simplification, the profile cockpit and a bottom-docked panel — that belong in the wireframe lane, not the build queue.
Item-by-item
| # | Report item | Finding | Evidence |
|---|---|---|---|
| 4.2 | Button flex auto-width | Shipped (2026-08-07) | packages/ui/src/button-visual.ts:25 resolveButtonWidth returns 'auto' when flex is set |
| 4.3 | FactRow chevron + 44pt hitSlop when pressable | Shipped (2026-09-06) | packages/ui/src/fact-row.tsx:114 shouldShowFactRowChevron, :136 resolveFactRowHitSlop |
| 4.4 | StyledInput focus ring + error border | Shipped today (aee4d359, PD-01) | labeled-field.tsx reads FOCUS_RING; resolveStyledInputBorderState |
| 4.5a | Live pulse $error not $badgeErrorText | Shipped (2026-09-10 design-harmony HIGH-1) | no $badgeErrorText pulse remains; strip pulse is $textInverse on the deep fill |
| 4.5b | Hard-court swatch → $courtHard | Shipped (2026-09-10 HIGH-2) | directory-venue-detail/format-helpers.ts:240 records the removal; one getSurfaceAccent source |
| 4.5c | Outline button $borderStrong | Shipped (2026-09-06) | button.tsx:99 |
| 4.6 / 07 | PlaceShell lacks BottomInsetReservationProvider | False — and the band law changed today | place-shell.tsx:51 has had it since 2026-09-10; 8ce1dad9 replaced the whole clearance formula |
| 02 | ClubCard nests an entire SessionCardV2 | False | club-card.tsx:279 renders ClubCardSessionRow — the one-line dot/date/time/venue/meter teaser the report asks for (iteration 22, 2026-08-04) |
| 06 | PickupHostCard legacy card box | Shipped (2026-09-14) | pickup-host-card.tsx:5 "no outer Card box" |
| 09 | Score stepper hit area | Shipped | stepper.tsx:96 hitSlop brings the 32 px circle to 44 |
| 10 | 4 px skeleton shift on FriendshipButton | Not in code | public-profile-screen.tsx:109 skeleton height is TOUCH_TARGET.MIN (44) |
| 14 | DM keyboard offset 8 px short | Shipped (2026-09-10 spacing #3) | dm-thread-screen.tsx:270 uses resolveAppHeaderHeight(Boolean(headerSubtitle)) |
| 15 | Consent-history skeleton jumps 16 px | Not in code | consent-history-screen.tsx:124 skeleton rows sit inside the list's own railedList container, no second rail |
| 07 | Feed chips pin over the collapsed bar | Not in code | club-detail-screen.tsx:466-475 pins them under the bar at topInset + TOP_BAR_HEIGHT, only after the inline row scrolled beneath it |
| 04 | Records medal contrast | Shipped (2026-09-06); widgets moved out of cards on 2026-09-14 | podium fix verified in today's primitive audit |
| 05 | Profile → card cockpit | Contradicts the hub-vs-detail ruling (owner 2026-09-14) — profile is a single entity, so it stays flat even though it is a tab | docs/canon/components.md hub-vs-detail law; memory project_hub_detail_visual_breaks_2026_09_14 |
| 2.2-3 | Replace the map thumbnail with a colour pill | Contradicts the owner's 2026-09-14 ruling that session cards use the native NCP static-map thumbnail | same ruling; SessionCardV2 mapUrl slot |
| 2.2 mocks | 📅 오늘 19:00 · 🥇 Gold III, 25,000원 · 3/4명 확정, the club teaser line | Break the no-middle-dot law (owner 2026-09-14, zero waivers) — facts are MetaSegments with hairline breaks | lint @twomore/no-middle-dot-join at error |
| 3 mock | 📤 공유, 🚪 로그아웃 rows | Break the glyph law (owner 2026-08-23: emoji never labels an action) | components.md glyph law |
| 03 | Consolidate the 경기 tab's four panes | Contradicts today's VENUE-RESIDUALS ruling (테니스장 찾기 stays the explore entry on the 경기 tab) | docs/design/decision-log-autonomous-2026-09-17.md |
| 2.2-1 | Drop weather from feed cards | Design call — weather is a glance label on the venue line (use-session-card-models.ts:87), not a chip; removing it is a product decision, not a defect | wireframe lane if pursued |
| 2.2-2/4 | Fee beside the meter; four-line reading order | Design call, partly moot: the card already closes with the meter; the reading order is the 2026-09-07 F1 card decision | session-card.jsx board |
| 4.1 / 12 / 02 | ModalPanel placement="bottom" | Design call, technically compatible: STYLE-3 retired the libraries (portal bugs, web bundle), not a bottom position on the native Modal; but "no handle, no snap points" stays — needs a board before the reaction picker / filter cascade move | docs/canon/styling.md:79 |
| 01 | Home feed is a one-row FeedList | Valid, verify first — home-feed-screen.tsx:165 renders [{kind:'temporal'}], so the pane is one item; whether it costs anything depends on card counts — check scroll:home-feed perf telemetry before restructuring | yarn debug:logs --kind=perf --route=index |
| 03 | Activity rows wrapped in a per-item paddingHorizontal="$4" | Valid, small — the list's contentContainerStyle should own the rail (SCROLL_CONTENT.railedList), one owner per seam | activity-screen.tsx:89,152 |
| 04 | Un-scrubbable ELO chart | Valid as a proposal — EloTrendCard is a SparkLine; a scrub needs the no-scroll+drag-on-one-axis law | elo-trend-card.tsx:2 |
| 06 | "CTA flash; memoize CTA resolution" | Unverified — no repro given; primary-action.tsx is a pure switch; treat as a device-QA item |
What to do with it
- Build the two valid small items now (activity rail ownership; home-feed one-row list after a telemetry check).
- Route the three design proposals (card simplification, profile cockpit, bottom-docked panel) through the wireframe lane with the rulings above stated on the board, so the owner reverses a ruling consciously or not at all.
- Drop the rest; this review is the record of why.