Skip to content

fix(ci): stop compose-preview firing on non-UI PRs - #1742

Merged
yschimke merged 1 commit into
mainfrom
claude/confetti-a11y-unrelated-prs-1v37zi
Jul 26, 2026
Merged

yschimke merged 1 commit into
mainfrom
claude/confetti-a11y-unrelated-prs-1v37zi

Conversation

@yschimke

Copy link
Copy Markdown
Collaborator

Summary

Two independent reasons the preview + a11y jobs ran and commented on PRs that cannot affect a single @Preview — e.g. #1738, a scrimage-filters bump used only by backend/service-graphql.

1. No path filter

The workflow ran both 45-minute jobs on every PR. Added paths-ignore for backend/, iosApp/, landing-page/, docs/, **.md.

Deliberately a denylist rather than an allowlist of UI paths: previews render against shared KMP code and the version catalog, so an allowlist would silently stop rendering the first time a preview picked up a new transitive dependency. Note this does not help dependency bumps that touch gradle/libs.versions.toml, even backend-only ones — those still render everything.

The list is duplicated across the push and pull_request triggers because GitHub Actions supports neither YAML anchors nor ! negation in path filters.

2. One nondeterministic a11y finding

The a11y comment logic is already correct — a11y.sh fetches compose-preview/a11y/main, diffs, and stays silent when nothing changed. It simply had something to report.

The report is bimodal. Two stable findings.json blobs alternate, and whichever one a PR lands on decides whether the bot posts:

blob seen on
1f5bdd25 compose-preview/a11y/main (the baseline), PRs #1737, #1733 → silent
23550c30 PRs #1738, #1732, #1740 → full 74-preview report

Diffing the two: 74 entries, 73 byte-identical, exactly one flaps.

wearApp / SpeakerDetailsScreen_Devices - Large Round
  DuplicateSpeakableTextCheck (INFO) — present in one variant, absent in the other
  "This non-clickable item's speakable text: "John O'Reilly" is identical to
   that of 1 other item(s)."   ImageView desc="John O'Reilly"

SubcomposeAsyncImage labelled the speaker photo with the speaker's name, while the SectionHeader immediately below announces the same string — so a screen reader read it twice. Which of the loading / error / success slots has settled when the a11y tree is scanned is a race, and only some of them carried the label, hence the finding appearing and disappearing between runs on identical code.

The photo is decorative next to that header, so the label is dropped from all three slots. That removes a real finding and makes the flap structurally impossible rather than merely less likely.

Test plan

  • No behaviour change to rendered pixels — contentDescription is semantics-only, so the preview PNGs are unaffected.
  • The a11y bot on this PR should now report the SpeakerDetailsScreen INFO as resolved, and subsequent unrelated PRs should stop getting the standing report.
  • Workflow syntax: both triggers keep identical paths-ignore lists; this PR itself touches wearApp/ so it is not skipped by its own filter.

Not addressed here

The underlying renderer nondeterminism that also makes ~6 wearApp preview PNGs flap on unrelated PRs is a separate fix in compose-ai-tools (stitcher anchor selection + downloadable-font resolution), not something this repo can fix.

Two MainActivity previews are still masked by missing-renders: warn — a persistent render failure, not a transient one. Left alone here; it needs the CI render report to diagnose.


Generated by Claude Code

Two independent reasons the preview + a11y jobs ran and commented on PRs
that cannot affect a single @Preview (e.g. a scrimage bump used only by
backend/service-graphql).

1. The workflow had no path filter, so both 45-minute jobs ran on every
   PR. Add paths-ignore for backend/iosApp/landing-page/docs/markdown.
   Deliberately a denylist: previews render against shared KMP code and
   the version catalog, so an allowlist would silently stop rendering the
   first time a preview picked up a new transitive dependency. Dependency
   bumps that touch gradle/libs.versions.toml still render everything.

2. The a11y report is bimodal, so roughly half of all runs disagreed with
   the baseline and posted the full 74-preview standing report. Diffing the
   two variants, exactly one preview flaps:

     wearApp / SpeakerDetailsScreen_Devices - Large Round
       DuplicateSpeakableTextCheck (INFO), present in one variant and
       absent in the other: ImageView desc="John O'Reilly" duplicates 1
       other item

   The speaker photo was labelled with the speaker's name while the
   SectionHeader immediately below announces the same string, so a screen
   reader read it twice. Which of SubcomposeAsyncImage's loading / error /
   success slots has settled when the a11y tree is scanned is a race, and
   only some of them carried the label - hence the finding appearing and
   disappearing between runs on identical code.

   The photo is decorative next to that header, so drop the label from all
   three slots. That removes a real finding and makes the flap structurally
   impossible rather than merely less likely.

The comment logic itself was already correct: a11y.sh fetches
compose-preview/a11y/main and stays silent on no change. It simply had
nothing to stay silent about.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014XYVcWMboPQeAHgw5Y7qCM
@yschimke
yschimke merged commit f59ffd3 into main Jul 26, 2026
7 checks passed
@yschimke
yschimke deleted the claude/confetti-a11y-unrelated-prs-1v37zi branch July 26, 2026 11:47
github-actions Bot added a commit that referenced this pull request Jul 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Preview Changes

Warning

2 preview(s) failed to render in this PR's render run. The diff below covers only the previews that produced a PNG.

Changed (1 variant(s) across 1 function(s))

HomeListViewKotlinConf (wearApp)

Before After

Render Failures (2 variant(s) across 2 function(s))

The render task completed but produced no PNG for these previews. Common causes: Robolectric sandbox crash, composePreviewRender NO-SOURCE, or a runtime exception inside the composable. Check the composePreviewRender-reports artifact attached to this run.

  • MainActivity (androidApp)
    • androidApp/activity__MainActivity · MainActivity
  • MainActivity (wearApp)
    • wearApp/activity__MainActivity · MainActivity
Unchanged (94 function(s), 199 variant(s))
  • Android Dark theme
  • Android Light theme
  • AndroidMakers Dark theme
  • AndroidMakers Light theme
  • AndroidMakers theme
  • AndroidSessionDetailPreview
  • AndroidSpeakerDetailsPreview
  • BackgroundAndroid
  • BackgroundDefault
  • BackgroundDynamic
  • BookmarkAddPreview
  • BookmarkOnPreview
  • BookmarksPreview
  • BookmarksPreviewEmpty
  • BookmarksPreviewError
  • BookmarksPreviewErrorLong
  • BookmarksPreviewLoading
  • BookmarksPreviewLong
  • BookmarksTilePreview
  • ColorSchemeSpecimenPreview
  • Color_0x000080
  • Color_0x000080Swatches
  • Color_0x008000
  • Color_0x008000Swatches
  • Color_0x800000
  • Color_0x800000Swatches
  • ConferenceHomeScreen
  • ConferenceHomeScreenLoading
  • ConferenceHomeScreenWithBookmarks
  • ConferencesViewCuratedPreview
  • ConferencesViewErrorPreview
  • ConferencesViewLongPreview
  • ConferencesViewPreview
  • Confetti (default) theme
  • Confetti brand Dark theme
  • Confetti brand Light theme
  • ConfettiHeaderPreview
  • DayChipPreview
  • Defaults
  • DefaultsSwatches
  • DevFest Dark theme
  • DevFest Light theme
  • DevFest theme
  • Droidcon Dark theme
  • Droidcon Light theme
  • Droidcon theme
  • Dynamic Dark theme
  • Dynamic Light theme
  • HomeListViewAndroidMakers
  • HomeListViewDevFest
  • HomeListViewDroidcon
  • HomeListViewLongPreview
  • HomeListViewPreview
  • KotlinConf Dark theme
  • KotlinConf Light theme
  • KotlinConf theme
  • LoginTilePreview
  • NoConferenceTilePreview
  • NotSet
  • NotSetSwatches
  • PlaceholderButtonPreview
  • ScheduleScreenPreview
  • ScreenHeaderPreview
  • SectionHeaderPreview
  • SessionCardBookmarkedPreview
  • SessionCardLoadingPreview
  • SessionCardPopulatedPreview
  • SessionDetailViewPreview
  • SessionDetailsPreview
  • SessionDetailsScreen
  • SessionDetailsScreenPreview
  • SessionItemBreakPreview
  • SessionItemLightningPreview
  • SessionItemPopulatedPreview
  • SessionListViewLongPreview
  • SessionListViewPreview
  • SessionSpeakerChipPreview
  • SettingsListViewLongPreview
  • SettingsListViewPreview
  • SocialIconPreview
  • SpeakerDetailsScreen
  • SpeakerDetailsScreenPreview
  • SpeakerDetailsViewPreview
  • SpeakerItemPreview
  • ThemeFoundationAndroidMakersPreview
  • ThemeFoundationAndroidPreview
  • ThemeFoundationConferenceSeedPreview
  • ThemeFoundationConfettiPreview
  • ThemeFoundationDefaultPreview
  • ThemeFoundationDevFestPreview
  • ThemeFoundationDroidconPreview
  • ThemeFoundationDynamicPreview
  • ThemeFoundationKotlinConfPreview
  • TypographySpecimenPreview

github-actions Bot added a commit that referenced this pull request Jul 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Accessibility Report

5 error(s) · 0 warning(s) · 7 info across 74 preview(s).

wearApp

BookmarksPreviewLoading · wearos_large_round

# Level Rule Element Message
1 ERROR SpeakableTextPresentCheck android.view.View This item may not have a label readable by screen readers.
2 ERROR SpeakableTextPresentCheck android.view.View This item may not have a label readable by screen readers.

ColorSchemeSpecimenPreview

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "Aa" is identical to that of 5 other item(s).

Color_0x000080Swatches

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "onSurfaceVariant / surface" is identical to that of 1 other item(s).

Color_0x008000Swatches

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "onSurfaceVariant / surface" is identical to that of 1 other item(s).

Color_0x800000Swatches

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "onSurfaceVariant / surface" is identical to that of 1 other item(s).

ConferenceHomeScreenLoading · wearos_large_round

# Level Rule Element Message
1 ERROR SpeakableTextPresentCheck android.view.View This item may not have a label readable by screen readers.

DefaultsSwatches

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "onSurfaceVariant / surface" is identical to that of 1 other item(s).

NotSetSwatches

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "onSurfaceVariant / surface" is identical to that of 1 other item(s).

SessionCardLoadingPreview

# Level Rule Element Message
1 ERROR SpeakableTextPresentCheck android.view.View This item may not have a label readable by screen readers.

SocialIconPreview

# Level Rule Element Message
1 ERROR TouchTargetSizeCheck android.widget.ImageView desc="Github" This item's size is 24dp x 24dp. Consider making this touch target 32dp wide and 32dp high or larger.

ThemeFoundationConfettiPreview

# Level Rule Element Message
1 INFO DuplicateSpeakableTextCheck android.widget.TextView This non-clickable item's speakable text: "Confetti" is identical to that of 1 other item(s).
Unchanged (63 preview(s))
  • AndroidSessionDetailPreview
  • AndroidSpeakerDetailsPreview
  • BackgroundAndroid
  • BackgroundDefault
  • BackgroundDynamic
  • BookmarkAddPreview
  • BookmarkOnPreview
  • ColorSchemeSpecimenPreview
  • ConfettiHeaderPreview
  • ScheduleScreenPreview
  • SessionDetailsPreview
  • SessionDetailsScreenPreview
  • SessionItemBreakPreview
  • SessionItemLightningPreview
  • SessionItemPopulatedPreview
  • SpeakerDetailsScreenPreview
  • SpeakerItemPreview
  • ThemeFoundationAndroidPreview
  • ThemeFoundationConferenceSeedPreview
  • ThemeFoundationDefaultPreview
  • ThemeFoundationDynamicPreview
  • TypographySpecimenPreview
  • BookmarksPreview
  • BookmarksPreviewEmpty
  • BookmarksPreviewError
  • BookmarksPreviewErrorLong
  • BookmarksPreviewLong
  • Color_0x000080
  • Color_0x008000
  • Color_0x800000
  • ConferenceHomeScreen
  • ConferenceHomeScreenWithBookmarks
  • ConferencesViewCuratedPreview
  • ConferencesViewErrorPreview
  • ConferencesViewLongPreview
  • ConferencesViewPreview
  • DayChipPreview
  • Defaults
  • HomeListViewAndroidMakers
  • HomeListViewDevFest
  • HomeListViewDroidcon
  • HomeListViewKotlinConf
  • HomeListViewPreview
  • NotSet
  • PlaceholderButtonPreview
  • ScreenHeaderPreview
  • SectionHeaderPreview
  • SessionCardBookmarkedPreview
  • SessionCardPopulatedPreview
  • SessionDetailViewPreview
  • SessionDetailsScreen
  • SessionListViewLongPreview
  • SessionListViewPreview
  • SessionSpeakerChipPreview
  • SettingsListViewLongPreview
  • SettingsListViewPreview
  • SpeakerDetailsScreen
  • SpeakerDetailsViewPreview
  • ThemeFoundationAndroidMakersPreview
  • ThemeFoundationDevFestPreview
  • ThemeFoundationDroidconPreview
  • ThemeFoundationKotlinConfPreview
  • TypographySpecimenPreview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants