Skip to content

fix(scripts): address visual-diff PR review comments#2578

Merged
riderx merged 9 commits into
mainfrom
fix/visual-diff-pr-comments
Jul 6, 2026
Merged

fix(scripts): address visual-diff PR review comments#2578
riderx merged 9 commits into
mainfrom
fix/visual-diff-pr-comments

Conversation

@riderx

@riderx riderx commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary (AI generated)

  • Harden scripts/visual-diff.ts based on CodeRabbit and Bugbot feedback from feat(frontend): add visual diff tooling for UI PR reviews #2576.
  • Validate CLI option values (--phase, --base, --head, --threshold, --routes).
  • Add fetch timeouts and require HTTP 2xx for backend readiness checks.
  • Restart the Supabase/functions backend between base and head git checkouts.
  • Log in once per capture session instead of before every authenticated route.
  • Create diff output directories before writing size-mismatch PNGs.
  • Make PR label detection tolerant of compact JSON from toJson().

Motivation (AI generated)

PR #2576 introduced the visual diff system but review bots flagged correctness and robustness issues. This PR closes the remaining feedback without changing the overall workflow design.

Business Impact (AI generated)

More reliable visual diff captures and CI comments reduce false negatives/positives during UI PR review.

Test Plan (AI generated)

  • bun run lint:deadcode
  • bun scripts/visual-diff.ts capture validates missing --phase
  • Run bun run visual:capture:before / after / diff locally on a small UI tweak
  • Open PR with visual-change label and confirm workflow posts the sticky comment

Generated with AI

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Enhanced visual-diff CLI validation (thresholds 0–100) and improved backend “readiness” logic with optional success requirements.
  • Bug Fixes
    • Visual change detection now tolerates whitespace variations in PR label payloads.
    • Visual diffs fail clearly when no screenshot pairs are available.
    • Frontend/backend start/stop and forcing behaviors are more consistent across ref-based runs.
  • CI/CD
    • Tightened visual-diff workflow permissions to least privilege.
  • Chores
    • Expanded static analysis coverage for the visual-diff configuration.

riderx and others added 4 commits June 23, 2026 20:34
Introduce a Playwright-based before/after screenshot workflow with CI reporting so PRs that change console UI can attach and refresh visual evidence automatically.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reload route config after git checkout, honor --routes in diff,
restore the original branch on failure, dedupe Supabase status helpers,
and remove an unused import.

Co-authored-by: Cursor <cursoragent@cursor.com>
Correct pull_request trigger types list syntax and register
visual-diff.config.ts as a knip entry so dynamic imports pass deadcode.

Co-authored-by: Cursor <cursoragent@cursor.com>
Harden CLI parsing, HTTP readiness checks, backend restarts across git
checkouts, single login per capture, and diff directory creation.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0fd4bbf6-7075-4499-a165-80e2bebfdf95

📥 Commits

Reviewing files that changed from the base of the PR and between 6478738 and 7fd43d2.

📒 Files selected for processing (1)
  • .github/workflows/visual-diff.yml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

📝 Walkthrough

Walkthrough

This PR tightens the visual-diff workflow permissions and label matching, adds a Supabase status parsing utility and knip entry wiring, and hardens scripts/visual-diff.ts across CLI validation, backend/frontend lifecycle control, screenshot capture, and pipeline orchestration.

Changes

Visual Diff Workflow and Script Refinements

Layer / File(s) Summary
Workflow permissions and label detection
.github/workflows/visual-diff.yml
Narrows top-level permissions to contents: read, moves pull-requests: write to the visual-diff job, and changes visual-change label detection to a regex match.
Supabase status parsing utility and knip entry
scripts/supabase-worktree-status.ts, knip.json
Adds SupabaseStatus plus parseSupabaseStatus and getSupabaseStatus with subprocess timeout handling, and registers playwright/visual-diff.config.ts as a knip entry point.
CLI threshold and argument validation
scripts/visual-diff.ts
Adds parseThreshold() for validated 0–100 threshold parsing and tighter CLI argument handling.
Backend/frontend stack lifecycle and readiness
scripts/visual-diff.ts
Extends isHttpReady() with a success-required option, reworks subprocess log handling and waitForExit, and adds stopBackendStack() plus a force option on ensureBackendStack().
Screenshot capture and diff error handling
scripts/visual-diff.ts
Adds forceFrontend and forceBackend capture options, logs in once per session, creates diff output directories before size-mismatch writes, and throws when no screenshot pairs are available.
Pipeline stack orchestration
scripts/visual-diff.ts
Updates runPipeline() to stop and start stacks around the “before” checkout, pass forcing flags into capture calls, and re-run bun install when restoring the original git ref.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant runPipeline
  participant ensureBackendStack
  participant stopBackendStack
  participant captureScreenshots
  participant Backend

  runPipeline->>ensureBackendStack: ensureBackendStack(force)
  ensureBackendStack->>Backend: isHttpReady(/ok, requireSuccess)
  alt force or not ready
    ensureBackendStack->>stopBackendStack: stopBackendStack()
    stopBackendStack->>Backend: remove marker, terminate processes
    ensureBackendStack->>Backend: restart backend
  end
  runPipeline->>captureScreenshots: captureScreenshots(forceFrontend, forceBackend)
  captureScreenshots->>ensureBackendStack: ensureBackendStack(forceBackend)
  captureScreenshots->>captureScreenshots: login once on first auth route
Loading

Compact metadata:

  • Related issues: Not specified in the provided context.
  • Related PRs: Not specified in the provided context.
  • Suggested labels: visual-diff, ci, tooling
  • Suggested reviewers: Not specified in the provided context.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main visual-diff hardening work.
Description check ✅ Passed The PR includes Summary, Motivation, Business Impact, and Test Plan sections, and screenshots are reasonably omitted for a backend-focused change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1c2b316. Configure here.

Comment thread scripts/visual-diff.ts
Comment thread scripts/visual-diff.ts
@cursor cursor Bot requested review from Dalanir and WcaleNieWolny June 23, 2026 19:46

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: medium. Not approving: Cursor Bugbot reported 2 unresolved findings on the latest commit and its check completed as skipped. Requested human review from WcaleNieWolny and Dalanir.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: medium. Cursor Bugbot skipped and reported 2 potential issues (empty diff false success, git restore dependency mismatch). Human review is needed before merge; assigned WcaleNieWolny and Dalanir.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Approver External

@coderabbitai coderabbitai Bot added the codex label Jun 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/visual-diff.yml:
- Around line 17-20: The `pull-requests: write` permission is currently set at
the workflow-wide level in the top-level permissions section, granting it to all
jobs even though only the visual-diff job needs it. Remove `pull-requests:
write` from the top-level permissions block and keep only `contents: read` there
for read-only access. Then add a new `permissions` section under the
`jobs.visual-diff` job configuration to explicitly grant `pull-requests: write`
only to that job, reducing the token exposure surface by limiting write
permissions to only where needed.

In `@scripts/supabase-worktree-status.ts`:
- Around line 25-30: The spawnSync call in the getSupabaseStatus function lacks
a timeout option, which allows it to block indefinitely if the Bun or Supabase
command hangs during startup. Add a timeout property to the options object
passed to spawnSync to establish a maximum wait time for the command execution,
preventing the function from blocking the visual-diff and Playwright backend
startup processes.

In `@scripts/visual-diff.ts`:
- Around line 92-95: The requireArg function should reject option tokens (values
starting with -- or -) when validating flag arguments. Modify the validation
check in requireArg to not only ensure a value exists, but also verify that the
value does not start with a dash character, which would indicate it is another
flag rather than an actual argument value. If the value starts with a dash,
throw an error indicating that the flag requires a non-flag value.
- Around line 88-117: The thresholdPercent variable initialization on line 88
from the VISUAL_DIFF_THRESHOLD_PERCENT environment variable lacks range
validation, and the CLI argument validation around line 115-116 only checks if
the value is numeric but not if it falls within a valid range (should be between
0 and 100). Add validation after parsing the threshold value from the
environment variable to ensure it is within acceptable bounds, and enhance the
existing Number.isFinite check in the --threshold argument handler to also
validate that thresholdPercent is within the safe range of 0 to 100 before
accepting it.
- Around line 257-262: The waitForExit function uses a Promise chain with
.then() (specifically `sleep(timeoutMs).then(() => hasExited())`) which does not
align with the repository's async/await style requirement. Refactor the
Promise.race call to use async/await syntax instead of the .then() chain,
ensuring the function properly awaits the sleep operation and calls hasExited()
asynchronously without relying on Promise chaining methods.
- Around line 232-240: The current implementation pipes both child.stdout and
child.stderr to logStream without specifying the end option, which causes the
stream to close prematurely when the first source finishes writing. This results
in lost logs from the second stream. Additionally, logStream is never explicitly
closed, creating a resource leak. Fix this by passing { end: false } as the
second argument to both the child.stdout.pipe() and child.stderr.pipe() calls to
prevent automatic stream closure, then add a listener to the child process close
or exit event to explicitly call logStream.end() once the child process has
fully terminated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c7bf92ef-d3a5-43c3-be6c-a911ea957023

📥 Commits

Reviewing files that changed from the base of the PR and between 9a48e19 and 1c2b316.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/visual-diff.yml
  • .gitignore
  • AGENTS.md
  • knip.json
  • package.json
  • playwright/visual-diff.config.ts
  • scripts/serve-backend-playwright.ts
  • scripts/supabase-worktree-status.ts
  • scripts/visual-diff.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

Comment thread .github/workflows/visual-diff.yml
Comment thread scripts/supabase-worktree-status.ts
Comment thread scripts/visual-diff.ts Outdated
Comment thread scripts/visual-diff.ts
Comment thread scripts/visual-diff.ts Outdated
Comment thread scripts/visual-diff.ts
Keep PR visual-diff workflow and script improvements while adopting
main lockfile updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_2811213d-81ea-42e2-856c-b8ec3d435974)

@codspeed-hq

codspeed-hq Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will degrade performance by 32.16%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 42 untouched benchmarks
⏩ 2 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
/updates manifest response with metadata 114.7 µs 169 µs -32.16%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing fix/visual-diff-pr-comments (7fd43d2) with main (b8f27fe)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Visual diff failed

Visual diff did not produce a report. Check the workflow logs and artifacts.

Commit: 647873897b88e531255be567972a6acd350c6eca
Download the HTML report from workflow artifacts (artifact: visual-diff-report-647873897b88e531255be567972a6acd350c6eca).

Open index.html from the artifact for side-by-side before/after/diff screenshots.

Harden CLI arg parsing and threshold validation, prevent premature log
stream closure, fail when no screenshots are compared, restore deps after
git checkout, scope workflow write permissions, and add Supabase status timeout.

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_f5be1c02-7aed-462f-aa94-b4ebef683ae7)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/visual-diff.ts (1)

720-734: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

throw inside finally trips Biome's noUnsafeFinally and is redundant.

The throw at line 728 is nested in a try that's immediately caught by the enclosing catch (same block), so it never escapes the finally — but Biome's lint (lint/correctness/noUnsafeFinally) still flags any throw lexically inside a finally regardless of nested try/catch, per the static analysis hint. This will fail CI lint. Since the error is only ever logged via the very next catch, drop the throw/catch round-trip and log directly.

🩹 Proposed fix
       try {
         const currentRef = git(['rev-parse', 'HEAD'])
         if (currentRef !== originalRef) {
           git(['checkout', '--force', originalRef])
           const install = spawnSync('bun', ['install'], { cwd: repoRoot, stdio: 'inherit', env: process.env })
-          if ((install.status ?? 1) !== 0)
-            throw new Error(`bun install failed after restoring git ref ${originalRef}`)
+          if ((install.status ?? 1) !== 0)
+            console.error(`[visual-diff] bun install failed after restoring git ref ${originalRef}`)
         }
       }
       catch (error) {
         console.error(`[visual-diff] failed to restore git ref ${originalRef}:`, error)
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/visual-diff.ts` around lines 720 - 734, The cleanup in visual-diff’s
finally block still contains a throw inside the finally scope, which triggers
Biome’s noUnsafeFinally lint. In the restore/ref checkout logic around
currentRef/originalRef, remove the throw/catch round-trip after bun install and
handle the failure by logging it directly in the same branch, so no throw
remains lexically inside finally.

Source: Linters/SAST tools

knip.json (1)

44-50: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the duplicate playwright/visual-diff.config.ts! entry from knip.json.
It appears twice in the same entry array; keep only one copy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@knip.json` around lines 44 - 50, The knip.json entry array contains a
duplicate exclusion for playwright/visual-diff.config.ts!, so remove the extra
copy and keep only one instance in the same list. Update the entry configuration
near the repeated playwright/visual-diff.config.ts! symbol so the array has
unique values only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/visual-diff.yml:
- Around line 46-48: Add a brief inline comment in the workflow permissions
block that explains why this least-privilege grant is needed, especially the
purpose of pull-requests: write. Locate the permissions section in
visual-diff.yml and document the scope so the intent of the GitHub Actions
permissions is clear to auditors. Keep the comment short and directly tied to
the workflow’s PR-related behavior.

---

Outside diff comments:
In `@knip.json`:
- Around line 44-50: The knip.json entry array contains a duplicate exclusion
for playwright/visual-diff.config.ts!, so remove the extra copy and keep only
one instance in the same list. Update the entry configuration near the repeated
playwright/visual-diff.config.ts! symbol so the array has unique values only.

In `@scripts/visual-diff.ts`:
- Around line 720-734: The cleanup in visual-diff’s finally block still contains
a throw inside the finally scope, which triggers Biome’s noUnsafeFinally lint.
In the restore/ref checkout logic around currentRef/originalRef, remove the
throw/catch round-trip after bun install and handle the failure by logging it
directly in the same branch, so no throw remains lexically inside finally.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1803a559-1bef-4aa0-9a3d-4871625d07e3

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2b316 and 6478738.

📒 Files selected for processing (4)
  • .github/workflows/visual-diff.yml
  • knip.json
  • scripts/supabase-worktree-status.ts
  • scripts/visual-diff.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

Comment thread .github/workflows/visual-diff.yml Outdated
@cursor

cursor Bot commented Jul 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_20387296-67b1-4304-826a-e91e792e5990)

@cursor

cursor Bot commented Jul 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_8bc2c2d1-34e4-4c02-80a3-c4cc9f80c6bd)

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Jul 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_032deefe-2fe0-4ddf-9292-bbacfcbee099)

@sonarqubecloud

sonarqubecloud Bot commented Jul 5, 2026

Copy link
Copy Markdown

@riderx riderx merged commit eae05ce into main Jul 6, 2026
68 of 70 checks passed
@riderx riderx deleted the fix/visual-diff-pr-comments branch July 6, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant