diff --git a/src/review/visual/paths.ts b/src/review/visual/paths.ts index 29ac0b011f..298a63e345 100644 --- a/src/review/visual/paths.ts +++ b/src/review/visual/paths.ts @@ -1,17 +1,17 @@ // Visual-path classifier (reviewbot→gittensory convergence — visual capture port). // // PORTED VERBATIM from reviewbot's src/agents/gittensory/capabilities.ts `isVisualPath` (the three -// VISUAL_PATTERNS), with the first pattern's app-folder segment widened to a wildcard (#3611 follow-up) so it -// isn't gittensory-ui-only — see capture.ts's DEFAULT_ROUTE_FILE for the same generalization. This is the -// EMPHATIC gate: screenshots fire ONLY for WEB-VISIBLE changes — any frontend app folder (apps/*/**, e.g. -// apps/gittensory-ui/** or apps/ui/**), a public asset (public/**, e.g. an OG image), or a front-of-house -// source extension (.tsx/.jsx/.css/.scss/.sass/.less/.html/.svg/.astro/.vue/.svelte/.mdx). A backend change +// VISUAL_PATTERNS), keeping capture scoped to file types and public assets that are directly web-visible. +// Route inference is still generalized in capture.ts's DEFAULT_ROUTE_FILE, but this cost gate must not treat +// every apps/* file as visual: screenshot-enabled repos often keep backend/config/docs files there too. This is +// the EMPHATIC gate: screenshots fire ONLY for WEB-VISIBLE changes — a public asset (public/**, e.g. an OG +// image), or a front-of-house source extension +// (.tsx/.jsx/.css/.scss/.sass/.less/.html/.svg/.astro/.vue/.svelte/.mdx). A backend change // (.ts/.md/.json/.py/...) matches NONE of these, so capture never triggers for it. // // PURE — no imports, no I/O. Callers MUST filter changed files through this before any capture. const VISUAL_PATTERNS: RegExp[] = [ - /^apps\/[^/]+\//i, /(^|\/)public\//i, /\.(tsx|jsx|css|scss|sass|less|html|svg|astro|vue|svelte|mdx)$/i, ]; diff --git a/test/unit/visual-paths.test.ts b/test/unit/visual-paths.test.ts index 785e621049..2daee5dfc7 100644 --- a/test/unit/visual-paths.test.ts +++ b/test/unit/visual-paths.test.ts @@ -2,19 +2,10 @@ import { describe, expect, it } from "vitest"; import { isVisualPath } from "../../src/review/visual/paths"; describe("isVisualPath (web-visible-only capture gate)", () => { - it("matches frontend app paths (apps/gittensory-ui/**)", () => { + it("matches frontend route files by web-visible extension, including generalized apps/* route folders", () => { expect(isVisualPath("apps/gittensory-ui/src/routes/index.tsx")).toBe(true); expect(isVisualPath("apps/gittensory-ui/src/routes/app.analytics.tsx")).toBe(true); - // Even a non-source file under the UI app is web-visible scope. - expect(isVisualPath("apps/gittensory-ui/public/og.png")).toBe(true); - expect(isVisualPath("apps/gittensory-ui/README.md")).toBe(true); - }); - - it("matches ANY app folder, not just gittensory-ui (#3611 follow-up — e.g. metagraphed's apps/ui/**)", () => { expect(isVisualPath("apps/ui/src/routes/index.tsx")).toBe(true); - // Same non-extension-matching-file case as gittensory-ui above, now for a different app folder name. - expect(isVisualPath("apps/ui/components.json")).toBe(true); - expect(isVisualPath("apps/marketing-site/README.md")).toBe(true); }); it("matches public asset paths (public/** — OG images etc.) at any depth", () => { @@ -55,12 +46,15 @@ describe("isVisualPath (web-visible-only capture gate)", () => { "Cargo.toml", "src/data/seed.sql", "config.yaml", + "apps/api/src/server.ts", + "apps/ui/components.json", + "apps/marketing-site/README.md", ]) { expect(isVisualPath(path), path).toBe(false); } }); - it("is case-insensitive on extensions and the app prefix", () => { + it("is case-insensitive on extensions", () => { expect(isVisualPath("APPS/GITTENSORY-UI/src/Page.TSX")).toBe(true); expect(isVisualPath("src/Icon.SVG")).toBe(true); // A .ts (backend) must still be false even upper-cased — it is not a web-visible extension.