Skip to content

ci: cut ds-shots PR wall-clock — build cache + 2-width captures (TASK-22081) - #2907

Merged
innolope-dev merged 3 commits into
devfrom
ci/ds-shots-speed-22081
Sep 2, 2026
Merged

ci: cut ds-shots PR wall-clock — build cache + 2-width captures (TASK-22081)#2907
innolope-dev merged 3 commits into
devfrom
ci/ds-shots-speed-22081

Conversation

@kushagrasarathe

@kushagrasarathe kushagrasarathe commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Slava reports the ds-shots job adds 4–5 minutes to every PR check. The job is advisory and blocks nothing (it is deliberately not in ci-success.needs), but at ~9–12 min it is the longest job on every PR, so the checks list looks busy long after the blocking gates went green. Two cuts, keeping the always-on pre-merge signal:

  1. Cache the Next build (.next/cache, Next.js docs recipe). A warm cache roughly halves the ~4 min build. Key ds-shots-next-<os>-<lockfile>-<src-hash> with a per-lockfile restore-keys fallback. Restore-only on PR runs; the save happens on push runs (dev/main) only — a per-PR save would upload a fresh 100–400 MB branch-scoped entry no other PR can read, churning the shared 10 GB Actions cache quota and spending 1–2 min per push on the upload (agentic-review finding, validated). Push runs land several times a day, so every PR restores a near-fresh dev-scoped entry. The save sits right after Build, not in a post step, so a capture failure doesn't lose the cache.
  2. PR runs capture 2 widths instead of 4 — 320 (finds the most overflow bugs) and 430 (widest device), the extremes of the range. Baseline pushes to dev/main keep all four widths. Width selection costs zero code: the Playwright projects are already named by width, so the capture step passes --project=320 --project=430 on pull_request events.

Expected: ~10 min → roughly 4–6 min per PR run. No permission or trust-boundary changes — the job keeps contents: read and nothing else.

Task: TASK-22081

The diff-noise fix that makes (2) possible

The 4-width baseline vs a 2-width capture would report ~60 "removed" shots per PR. scripts/visual-diff.mjs now counts a file as removed only when its width exists in the after capture — a width the run never shot proves nothing. A screen that is really deleted is still reported at the captured widths. Covered by scripts/__tests__/visual-diff-widths.test.js (real PNGs through the actual CLI): partial-width capture produces zero noise, a genuinely deleted screen still reports, changed/added detection intact.

Design notes / accepted trade-offs

  • Breakpoint bugs specific to 375/393 surface after merge, not on the PR: the next dev push captures all four widths and the following PR diffs against it. Judged acceptable — 320/430 bound the layout range and catch the overflow/wrap extremes.
  • Stale Next cache risk: the exact-key entry is per source-hash; the restore-keys fallback gives Next a previous cache to rebuild incrementally from, which is its supported mode. If a phantom diff is ever suspected, deleting the ds-shots-next-* cache entries restores cold builds.
  • Interacts cleanly with ci: publish ds-shots visual diff as a sticky PR comment (TASK-22044) #2897 (comment publisher): different hunks in tests.yml, no shared lines; the publisher validates whatever the report contains and the report schema is unchanged.

QA

  • New jest suite: 3 cases, green; full suite 4989 passed; typecheck, prettier, ds-lint ratchet all green.
  • tests.yml YAML-parses; the ds-shots job shows the cache step before Build.
  • Real-world before/after timing lands with the first PRs after merge — compare the ds-shots job duration against the ~9–12 min current baseline.

Screenshots: N/A (no visible app change — CI only).

The job is advisory and blocks nothing, but at ~9-12 min it is the
longest job on every PR, so the checks list looks busy long after the
blocking gates are green. Two cuts, no lost always-on signal:

- cache .next/cache (Next docs recipe) — a warm cache roughly halves
  the ~4 min build
- PR runs capture the two extreme widths (320 finds the most overflow,
  430 is the widest device); baseline pushes keep all four, and
  visual-diff.mjs no longer reports widths a partial capture never
  shot as removed, so the 4-width baseline diffs cleanly

Accepted trade-off: a breakpoint bug specific to 375/393 surfaces
after merge instead of on the PR.

TASK-22081
@notion-workspace

Copy link
Copy Markdown

@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
peanut-wallet Ready Ready Preview Sep 1, 2026 4:19pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: ae4ab8af-a0bf-4dcc-ad8b-bd57f6d8cf65

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 7153.05 → 7153.05 (0)
Findings: 0 net (+0 new, -0 resolved)

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 5023 ran, 0 failed, 0 skipped, 1.5m

📊 Coverage (unit)

metric %
statements 73.5%
branches 58.9%
functions 64.7%
lines 74.5%
⏱ 10 slowest test cases
time test
4.1s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
1.9s src/components/Profile/views/__tests__/ResidenceChangeModal.test.tsx › moving to a country in neither slot leaves the second document alone
1.3s src/components/Profile/views/__tests__/ResidenceChangeModal.test.tsx › the change cooldown shows its date and blocks changing to another country, not re-saving
1.3s src/components/Profile/views/__tests__/ResidenceChangeModal.test.tsx › saves the declared residence, refetches, and closes
1.2s src/components/Profile/views/__tests__/ResidenceChangeModal.test.tsx › prefers the server value over a stale device mirror
1.1s src/components/Profile/views/__tests__/ResidenceChangeModal.test.tsx › swaps from the server value with no device mirror at all
1.0s src/hooks/query/__tests__/user.test.tsx › does NOT clear a token that rotated mid-request (stale 401 racing a fresh login)
0.9s src/components/Setup/Views/__tests__/Residence.test.tsx › reveals the second selector via the multi-doc link
0.9s src/components/Setup/Views/__tests__/Residence.test.tsx › disables Continue until a country is chosen
0.9s src/components/Setup/Views/__tests__/Residence.test.tsx › returns to the selector from the heads-up
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@chip-peanut-bot chip-peanut-bot 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.

Chip review — no blocking findings — this is not an approval

Clean review. The two-width PR capture keeps actionable added, changed, and removed-screen reporting at captured widths, while the Next build cache and capture arguments preserve the workflow's read-only trust boundary.

Checked clean

  • Verified detached HEAD, trusted author, dev base ref, and exact merge base against the supplied SHAs.
  • Reviewed the Next build cache key and restore behavior, pull-request-only 320/430 project selection, and unchanged contents:read permission boundary.
  • Exercised the visual-diff logic adversarially against partial-width captures, genuine fixture removal, additions, pixel changes, empty or failed captures, and the fixture filename contract.
  • Exact-head blocking CI completed green, including unit, typecheck, format, eslint, ds-lint, and ci-success; the modified ds-shots cache, build, capture, baseline restore, diff, list, upload, and summary steps also succeeded while downstream regression specs were still running.
  • Checked recent history and surrounding Playwright capture and visual-comment contracts for regressions and architecture drift.

Second opinion by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only, so treat its findings as advice.

Exact head: 5f2b4229277b · Context: repo

@chip-peanut-bot chip-peanut-bot 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.

Chip review — no blocking findings — this is not an approval

Clean review. The two-width PR capture preserves actionable added, changed, and removed-screen reporting at captured widths, while the Next build cache and capture arguments keep the workflow's read-only trust boundary intact.

Checked clean

  • Verified detached HEAD, trusted author, ready PR state, dev base ref, and exact merge base against the supplied SHAs.
  • Reviewed the Next build cache key and restore behavior, pull-request-only 320/430 project selection, push behavior, and unchanged contents:read permission boundary.
  • Checked partial-width diff behavior for baseline-only widths, genuine fixture removal, pixel changes, additions, and the fixture filename contract; the new CLI-level tests cover those paths.
  • All exact-head CI completed green, including unit, typecheck, format, eslint, ds-lint, ci-success, Deploy Preview, and the full ds-shots build, two-width capture, baseline restore, diff, summary, and regression flow.
  • Checked recent workflow history and surrounding Playwright capture and visual-comment contracts for regressions, unsafe credential flow, and architecture drift.

Second opinion skipped: daily-budget-reached.

Exact head: 5f2b4229277b · Context: repo

Review finding (validated): the full cache action saved a fresh
100-400 MB entry on nearly every PR push — branch-scoped, so no other
PR could read it — churning the shared 10 GB quota and spending 1-2
min of post-step upload that ate part of the speedup. PRs now
restore-only and pick up the near-fresh dev-scoped entry via
restore-keys; push runs save, right after Build so a capture failure
does not lose the cache.

TASK-22081

@chip-peanut-bot chip-peanut-bot 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.

Chip review — no blocking findings — this is not an approval

Clean review. The PR-only two-width capture remains compatible with four-width baselines, and the push-only Next cache preserves the workflow's read-only PR trust boundary.

Findings

  • MINOR · scripts/visual-diff.mjs:104 · [moonshotai/kimi-k3] Empty head capture now diffs all-green instead of reporting every shot removed
    The new filter counts a baseline file as removed only if its width exists anywhere in the after set (afterWidths.has(widthOf(f))). If the capture step ever succeeds while producing zero PNGs — e.g. a capture-script or playwright config regression that exits 0 with no output, or a project filter matching a project with no tests — afterWidths is empty, so removed is [] and the report shows no removals at all: 120 vanished screenshots look identical to a clean pass. Before this change, an empty after directory reported every baseline file as removed, which is exactly the loud failure signal you want. The job is advisory, so nothing blocks, but the diff-noise fix has converted the tool's most catastrophic input into silence. Fix: guard the degenerate case, e.g. if (before.size > 0 && after.size === 0) fail (exit non-zero or report all before files as removed) before applying the width-aware filter, and/or only apply the filter when after.size > 0`.

Checked clean

  • Verified the detached worktree head, exact merge base, trusted author, and dev target against the supplied metadata.
  • Checked partial-width removal detection against the screenshot filename contract and Playwright project names; deleted screens remain detectable at captured widths.
  • Checked Next cache restore/save scoping and keys; PR runs remain restore-only and no write permission or credential boundary was added.
  • Checked capture command argument expansion and push-versus-pull-request paths.
  • Exact-head CI is green, including unit, ds-shots, typecheck, lint, formatting, and provenance gates. Local dependency-based reruns were unavailable in the detached worktree, so CI supplied the executable validation.

Second opinion by moonshotai/kimi-k3: 1 finding(s), marked with the model name. It reads the diff only, so treat its findings as advice.

Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.

Exact head: f91940338da1 · Context: repo

Comment thread scripts/visual-diff.mjs
Chip/kimi finding on the width-aware removal filter: with zero
after-files the filter reported an empty capture as all-green — the
tool's most catastrophic input became silence. A non-empty baseline
with an empty capture now exits 2 before the filter applies, matching
the script's contract that non-zero means the tool broke.

TASK-22081

@chip-peanut-bot chip-peanut-bot 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.

Chip review — no blocking findings — this is not an approval

Reviewed the exact head against the pinned dev base. The prior empty-capture finding is fixed, and no actionable correctness, security, adversarial, or maintainability defects remain.

Checked clean

  • Confirmed P1 is fixed: a non-empty baseline with an empty head capture exits 2 before width filtering, with a CLI-level regression case.
  • Checked partial-width capture selection and width-aware removed-shot reporting; real removals at captured widths remain visible while uncaptured baseline widths are ignored.
  • Checked the Next build cache event gating, branch-scoped restore strategy, read-only job permissions, and push-only save behavior.
  • Exact-head CI completed successfully, including unit, ds-shots, typecheck, lint, format, and ci-success.
  • A focused local Jest rerun was unavailable because the detached worktree has no installed Jest binary; the exact-head unit and ds-shots checks are green.

Second opinion by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only, so treat its findings as advice.

Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.

Exact head: 6127f4ac17fa · Context: repo · Took 4m (queued 6m)

@innolope-dev
innolope-dev merged commit e374cb6 into dev Sep 2, 2026
23 of 24 checks passed
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