From b9a0e6f0ece8a6d708663651e31b01cf2d73ba2a Mon Sep 17 00:00:00 2001 From: Qiyuanqiii <267806965+Qiyuanqiii@users.noreply.github.com> Date: Thu, 22 Oct 2026 02:46:44 +0800 Subject: [PATCH] fix(ci): classify acceptance screenshots as documentation --- docs/ci.md | 7 +++++++ scripts/ci/classify_changes.py | 5 +++++ scripts/ci/test_classify_changes.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/docs/ci.md b/docs/ci.md index 1ecb8b46d..e64886432 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -19,6 +19,13 @@ run; releases require that result for their exact source commit. | Go module dependencies, CI machinery or unclassified inputs | Full checks | Only if release tooling also changes | | Nightly or manual CI | Full checks, platform matrix, packaging and Go vulnerability audit | Version tags / manual releases still use the release workflow | +PNG, JPEG and WebP screenshots under `docs/acceptance/`, `docs/evidence/` and +`docs/images/` count as documentation. Adding before/after screenshots to a +frontend PR keeps its frontend and workbench-journey checks without starting +unrelated backend/platform checks. Runtime images under `assets/branding/`, +`web/` or Go package test data retain their existing checks. Other files in +the evidence directories still use the normal classification rules. + The selection rules live in `scripts/ci/classify_changes.py`. Main uses the push before/after commits, so merging a frontend change does not rerun the entire backend matrix. Nightly CI runs at 19:23 UTC (03:23 Asia/Hong_Kong). The Actions diff --git a/scripts/ci/classify_changes.py b/scripts/ci/classify_changes.py index 8f5da9920..44d6312c4 100644 --- a/scripts/ci/classify_changes.py +++ b/scripts/ci/classify_changes.py @@ -16,6 +16,8 @@ CHECKS = ("full", "backend", "store", "web", "journeys", "lsp", "rust", "native", "ui", "race", "audit", "packaging") _FULL_PATHS = {"go.mod", "go.sum", ".github/workflows/ci.yml"} +_DOCUMENTATION_IMAGE_PREFIXES = ("docs/acceptance/", "docs/evidence/", "docs/images/") +_DOCUMENTATION_IMAGE_SUFFIXES = (".png", ".jpg", ".jpeg", ".webp") _PACKAGING_PREFIXES = ( "packaging/", "assets/branding/", "scripts/build-desktop", "scripts/release-desktop", "scripts/package-", "scripts/verify-", @@ -84,8 +86,11 @@ def classify_paths(paths: Sequence[bytes], affected: Sequence[str] = ()) -> dict "scripts/tests/prepare-windows-fixed-go")): checks["native"] = True elif (path.endswith(".md") or path.startswith("docs/convergence/") + or (path.startswith(_DOCUMENTATION_IMAGE_PREFIXES) + and path.lower().endswith(_DOCUMENTATION_IMAGE_SUFFIXES)) or path in {".gitignore", ".gitattributes", "LICENSE", "LICENSE.md"} or path.startswith((".github/ISSUE_TEMPLATE/", ".github/PULL_REQUEST_TEMPLATE"))): + # Acceptance screenshots are documentation, not runtime assets. # Generated registry/inventory and documentation contracts are # checked in the always-on Go checks job. pass diff --git a/scripts/ci/test_classify_changes.py b/scripts/ci/test_classify_changes.py index bc287b505..ad7b22e4f 100644 --- a/scripts/ci/test_classify_changes.py +++ b/scripts/ci/test_classify_changes.py @@ -38,6 +38,34 @@ def test_go_dependencies_select_store_without_unrelated_platforms(self): ) self.assertEqual(selected, {"backend", "store", "journeys"}) + def test_documentation_screenshots_do_not_expand_frontend_checks(self): + for directory in ("docs/acceptance", "docs/evidence", "docs/images"): + for suffix in (".png", ".jpg", ".jpeg", ".webp", ".PNG"): + screenshot = f"{directory}/browser-viewer/before{suffix}".encode() + with self.subTest(screenshot=screenshot): + self.assertEqual(self.enabled([screenshot]), set()) + for paths in ([screenshot, b"web/src/v2/components/agent-browser.tsx"], + [b"web/src/v2/components/agent-browser.tsx", screenshot]): + self.assertEqual(self.enabled(paths), {"web", "journeys"}) + + def test_screenshot_documentation_keeps_other_input_checks(self): + screenshot = b"docs/acceptance/browser-viewer/after.png" + for paths, affected in ( + ([b"assets/branding/traverse-board-mark.png"], ()), + ([b"web/public/traverse-board-favicon-32.png"], ()), + ([b"internal/workspace/testdata/reference.png"], ("project/internal/workspace",)), + ([b"internal/domain/run.go"], ("project/internal/domain", "project/internal/store")), + ([b"docs/openapi.json"], ()), + ([b"go.mod"], ()), + ([b"scripts/ci/classify_changes.py"], ())): + with self.subTest(paths=paths): + self.assertEqual(self.enabled([screenshot, *paths], affected), self.enabled(paths, affected)) + for path in (b"docs/acceptance/verify.py", b"docs/evidence/trace.json", + b"docs/images/browser.svg", b"docs/images/browser.png.sh", + b"docs/acceptance-runtime/before.png", b"unknown-assets/before.png"): + with self.subTest(path=path): + self.assertEqual(self.enabled([path, screenshot]), set(CHECKS)) + def test_product_journeys_follow_backend_consumers_without_native_matrix(self): checks = self.enabled([b"internal/llm/model_catalog.go"], ["project/internal/llm", "project/internal/application"])