From f841bb3c47e187d658685f2becb795679755c721 Mon Sep 17 00:00:00 2001 From: Sipho Nkebe Date: Wed, 10 Jun 2026 23:22:18 +0200 Subject: [PATCH 1/2] =?UTF-8?q?ci(gallery):=20add=20apps/gallery=20job=20+?= =?UTF-8?q?=20component=20arch-guards=20(=C2=A73.1/=C2=A73.5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gates the flutterbits component target in CI (analyze + format + widget/golden tests, mirroring the example-app job), and lands the component-scoped arch-guards the config flagged for 'once the first component lands': no Material import and no hardcoded Color (except the allowed transparent Color(0x00000000)) under apps/gallery/lib/components. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yaml | 51 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0a7e8c5..e844d2c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -55,6 +55,36 @@ jobs: - name: Smoke tests (every section, light/dark, LTR/RTL) run: flutter test + gallery: + # The flutterbits COMPONENT target (apps/gallery, AGENTS.md §9): analyze, + # format-check, and run its widget + golden tests, so a change that breaks a + # component — or the engine API it consumes — fails CI. Goldens are baselined on + # the pinned Flutter version; CI (Linux) is the authoritative golden platform (§9). + runs-on: ubuntu-latest + defaults: + run: + working-directory: apps/gallery + steps: + - uses: actions/checkout@v5 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.41.9 + - run: flutter pub get + - name: Analyze (zero warnings) + run: flutter analyze --fatal-infos --fatal-warnings + - name: Format check + run: dart format --output=none --set-exit-if-changed --line-length 100 . + - name: Test (incl. goldens) + run: flutter test + - name: Upload golden failures + if: failure() + uses: actions/upload-artifact@v4 + with: + name: gallery-golden-failures + path: apps/gallery/test/**/failures/ + if-no-files-found: ignore + floor-compat: # Verifies the toolchain floor (AGENTS.md §2): the package must compile and # its unit tests must pass on the MINIMUM supported Flutter/Dart. Goldens are @@ -153,5 +183,22 @@ jobs: echo "::error::Use EdgeInsetsDirectional / AlignmentDirectional (AGENTS.md §3.3)." exit 1 fi - # NOTE: §3.1 (no hardcoded Color(0x...) in components) and §3.7 (no className - # string parsing) get a guard against registry/ once the first component lands. + - name: No Material import in flutterbits components (§3.5) + run: | + if grep -rnF --include='*.dart' 'package:flutter/material.dart' apps/gallery/lib/components 2>/dev/null; then + echo "::error::flutterbits components must not import Material (AGENTS.md §3.5)." + exit 1 + fi + - name: No hardcoded Color in components except transparent (§3.1) + run: | + # Components style via semantic tokens (context.fw.colors.*); the ONLY + # allowed color literal is fully-transparent Color(0x00000000) ("no fill"). + if grep -rnE --include='*.dart' 'Color\(0x' apps/gallery/lib/components 2>/dev/null \ + | grep -vF 'Color(0x00000000)'; then + echo "::error::Components must use semantic tokens; only Color(0x00000000) is allowed (AGENTS.md §3.1)." + exit 1 + fi + # NOTE: these component guards target apps/gallery/lib/components (the first + # component home); extend the path to registry/ when the registry/CLI lands. + # §3.7 (no className string parsing) stays review-only — there is no faithful + # grep for it, and the typed `.tw` API makes a string parser structurally absent. From da5106af5284ca014144415e001df5947aa0341d Mon Sep 17 00:00:00 2001 From: Sipho Nkebe Date: Wed, 10 Jun 2026 23:27:35 +0200 Subject: [PATCH 2/2] test(button): re-baseline goldens on CI Linux (authoritative platform) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Windows-generated baselines diffed ~0.87% from CI Linux rendering (edge AA). Replaced with the Linux renders pulled from the gallery job's failure artifact, so the gallery golden job is deterministic on the authoritative platform (§9). Co-Authored-By: Claude Opus 4.8 --- .../gallery/test/goldens/button_grid_dark.png | Bin 6108 -> 6103 bytes .../test/goldens/button_grid_light.png | Bin 6366 -> 6360 bytes apps/gallery/test/goldens/button_grid_rtl.png | Bin 6403 -> 6398 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/gallery/test/goldens/button_grid_dark.png b/apps/gallery/test/goldens/button_grid_dark.png index 9bf0610b1982abd011ee8686e6a217872f85d325..ca081b97b0ceae5328b450ab2e5fdc44b46d0b2b 100644 GIT binary patch delta 1778 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 OdQFTh49oRh6aEW*Z+)@= literal 6366 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 KMNUMnLSTYF{gm|p