You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of the Sep-2026 designer's-eye QA of the 138 "Artistant iOS Light" screens (theme T12b, category consistency; epic #161). Full report with evidence and per-screen coverage: docs/DESIGN_QA_2026-09.md; the per-section appendices under docs/design-qa/ carry the code excerpts.
Why it matters. Two private DestructiveButtons each documented as the only one, two ReasonRows, a pre-redesign field and chip still shipping in the press-kit panes, hand-rolled BasicTextFields that lose the focus state, and a secondary button whose height and label step disagree with the token sheet.
Fix direction. Promote the one good copy of each into designsystem/component/ and delete the rest.
Findings (22: P2 ×12, P3 ×10)
F-CC-03 (P3) — The token sheet and the secondary button disagree about its height
Screens: 57, 07, 94, 118, 25 and every EmptyState with two actions
Where: designsystem/component/PrimaryButton.kt:86 vs :142 (KDoc at :111-119); docs/REDESIGN_2026-09.md §2 Geometry. (The design-system auditor adds: PrimaryButton sets type.cta 16.5/700 while SecondaryButton sets type.rowTitle 14.5/600 — the label step differs too.)
Fix: Measure screen 57 in the export once and make §2 and the KDoc say the same number; one label step for both buttons.
F-GS-06 (P2) — LegalSegments duplicates the design-system SegmentedControl
Fix: Drop the trailing "Cancel" and make the footer line an InlineLink("Back to Apple and Google", onCancel); on Legal keep the footer row and drop the header circle.
Fix: Have the footer slot render BottomActionBar(modifier = Modifier.imePadding()) { footer() } and let one component own the tailroom.
F-BC-21 (P3) — The counter amount well ignores the section's field recipe
Screens: 61
Where: feature/booking/CounterOfferScreen.kt:405-412 vs designsystem/component/AppTextField.kt:89-98 and RequestQuoteScreen.kt:323-325 (PickerField); KDoc :396 says 22sp, displaySmall is 19 (Type.kt:257-258)
Fix: surface2 fill, hairline rim, ink rim only while focused (track interactionSource), and correct the KDoc to 19sp.
F-BN-10 (P2) — Two private DestructiveButtons, each documented as the only one
Screens: 52, plus Delete account
Where: feature/booking/BookingDetailScreen.kt:1190-1213 vs feature/profile/DeleteAccountScreen.kt:576-605
Fix: promote one into designsystem/component/ with enabled, and use it in both places.
F-BN-11 (P2) — On screen 18 "Cancel" is the third of three identical grey buttons
Fix: use ink2 for the unselected day letter and either give the tech presets the chip's accent fill or give the day strip the brandSoft+stroke treatment — two languages at most (grid-of-answers vs list-of-demands), not three.
F-WZ-12 (P3) — Two hand-rolled BasicTextFields lose the app's focus state
Fix: pick one — the icon + danger label row — and use it for all four; colors.danger in both places.
F-AS-13 (P2) — Screen 106: the dock is hand-rolled and the reason Save vanished is at the bottom of a scroll
Screens: 106, 22
Where: ManageAvailabilityScreen.kt:298-312; error text at :285-288; copy at feature/availability/ManageAvailabilityViewModel.kt:141; peer dock at GigRequestDetailScreen.kt:231
Fix: .dockSurface().padding(gutter), keep "Save changes" present-but-disabled, and put the reason in a Banner(Failure, actionLabel = "Retry") immediately above the dock.
F-AC-06 (P2) — Two private copies of DestructiveButton, each documented as the only one
Fix: promote one DestructiveButton (with the enabled state) into designsystem/component/, delete both copies, and pick one reason-row component for both flows.
F-AC-07 (P2) — The calendar picker is a hand-rolled single-select with a sub-44dp target
Screens: 47
Where: feature/profile/AccountScreen.kt:412-439
Fix: replace with CheckRow(state = if (selected) MarkState.Done else MarkState.Pending, onClick = …).
F-AC-19 (P3) — Profile hand-rolls the feedback line the section already exports
Screens: 26
Where: feature/profile/ProfileScreen.kt:217-229; component at feature/profile/AccountChrome.kt:211-228
Fix: give Meter a thickness parameter defaulted to one token (component.meter), route the five inline bars through it, and delete the three redundant Dimens entries.
F-DSYS-19 (P3) — OtpField draws a 1.5dp stroke at rest; every other input draws 1dp
Fix: add a component.playDisc (36) / reuse size.iconLg-family token for the glyph, and swap the two alpha mixes for surface2 / hairline and the aliases for accent / page.
Acceptance
Every finding above is closed on the cited lines (or refuted in a comment with the reason).
./gradlew :app:assembleDebug, :app:testDebugUnitTest and :app:lintDevDebug green.
The screens listed above walked on the artistant AVD with the debug harness (RELEASE.md §10) and the fix confirmed visually — this audit was code-grounded, not device-walked.
Part of the Sep-2026 designer's-eye QA of the 138 "Artistant iOS Light" screens (theme T12b, category consistency; epic #161). Full report with evidence and per-screen coverage: docs/DESIGN_QA_2026-09.md; the per-section appendices under
docs/design-qa/carry the code excerpts.Why it matters. Two private
DestructiveButtons each documented as the only one, twoReasonRows, a pre-redesign field and chip still shipping in the press-kit panes, hand-rolledBasicTextFields that lose the focus state, and a secondary button whose height and label step disagree with the token sheet.Fix direction. Promote the one good copy of each into
designsystem/component/and delete the rest.Findings (22: P2 ×12, P3 ×10)
EmptyStatewith two actionsPrimaryButtonsetstype.cta16.5/700 whileSecondaryButtonsetstype.rowTitle14.5/600 — the label step differs too.)LegalSegmentsduplicates the design-systemSegmentedControlSegmentedControl(options = LegalDoc.entries, selected = selected, onSelect = …, label = { it.tab })and deleteLegalSegments.TextAction(orSecondaryButton) used at both sites,rowMin-tall,accentInk.InlineLink("Back to Apple and Google", onCancel); on Legal keep the footer row and drop the header circle.SignupScaffold's footer re-implementsBottomActionBarBottomActionBar(modifier = Modifier.imePadding()) { footer() }and let one component own the tailroom.surface2fill,hairlinerim,inkrim only while focused (trackinteractionSource), and correct the KDoc to 19sp.DestructiveButtons, each documented as the only onedesignsystem/component/withenabled, and use it in both places.dangerlabel text, and say "Cancel booking" to both sides.ReasonRowis implemented twice, with different ring weightsRadioRowtodesignsystem/component/, use it from both sheets, and make the selected markink-on-surface2so the CTA keeps the accent.ink2for the unselected day letter and either give the tech presets the chip's accent fill or give the day strip thebrandSoft+stroke treatment — two languages at most (grid-of-answers vs list-of-demands), not three.BasicTextFields lose the app's focus stateminLinestoAppTextFieldand use it for the bio; give the sample title the same field chrome (or an explicit edit affordance).ListRowwith a trailing Edit action, set the value line atsubtitle, and give both progress tracks one token pair.EpkChipsites toChipand the fiveEpkFieldsites toAppTextField, then deleteEpkComponents.kt.colors.dangerin both places..dockSurface().padding(gutter), keep "Save changes" present-but-disabled, and put the reason in aBanner(Failure, actionLabel = "Retry")immediately above the dock.DestructiveButton, each documented as the only oneDestructiveButton(with theenabledstate) intodesignsystem/component/, delete both copies, and pick one reason-row component for both flows.CheckRow(state = if (selected) MarkState.Done else MarkState.Pending, onClick = …).AccountFeedbackLine(message, colors.danger, onDismissMessage, "profile.actionError").SecondaryButton(54dp,surface2) for all three, and give the help card's pilldefaultMinSize(minHeight = size.controlMin).Meter, used by one feature; four other bar geometries hand-rolledMeterathicknessparameter defaulted to one token (component.meter), route the five inline bars through it, and delete the three redundant Dimens entries.OtpFielddraws a 1.5dp stroke at rest; every other input draws 1dpAppTextField—if (active || isError) focusStroke else size.hairline.SampleRowis the one off-token component: raw 36/18dp and alpha-mixed greyscomponent.playDisc(36) / reusesize.iconLg-family token for the glyph, and swap the two alpha mixes forsurface2/hairlineand the aliases foraccent/page.Acceptance
./gradlew :app:assembleDebug,:app:testDebugUnitTestand:app:lintDevDebuggreen.artistantAVD with the debug harness (RELEASE.md §10) and the fix confirmed visually — this audit was code-grounded, not device-walked.