Skip to content

feat(screenshot-diff): replace odiff with unified Rust diff engine#2333

Draft
jsfez wants to merge 1 commit into
mainfrom
feat/unified-rust-diff
Draft

feat(screenshot-diff): replace odiff with unified Rust diff engine#2333
jsfez wants to merge 1 commit into
mainfrom
feat/unified-rust-diff

Conversation

@jsfez

@jsfez jsfez commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the odiff-based diff pipeline with a single call to diffScreenshots from @argos-ci/mask-fingerprint (see argos-ci/mask-fingerprint#6), which evaluates both thresholds in one pass over in-memory images and compensates vertical layout shifts.

What changes for users

When a section is inserted in a page, the content below it is realigned before comparison: the mask only marks the new section instead of painting everything below it red. The inserted section is fully counted in the score; removed sections are scored and marked with a thin seam at their former position.

before after
section insérée (fixture layoutShift) ~72% du mask en rouge bande rouge sur la section uniquement, score 0.14
perf (fixture big-images) 200ms (2 spawns odiff) 66ms (×3)

Implementation

  • diffImages is now a thin wrapper: one native call + the existing score gates (selectDiffResult, unchanged logic).
  • odiff-bin dependency removed (two process spawns and four PNG decodes per diff gone).
  • Same-width images are compared as-is — the engine pads with transparency natively and the row alignment works on unpadded rows. Different-width images keep the historical sharp scale-to-fit behavior (resolveComparablePaths).
  • Scores are quantized to 1e-4 to reproduce odiff's two-decimal percentage rounding (diffs under 0.005% of pixels still count as a match — this was load-bearing for minorChange2).

odiff parity

  • All 20 historical fixture cases pass unchanged; base-threshold pass verified bit-identical to odiff on identical inputs.
  • The color-sensitive pass (threshold 0.0225) differs by +0.1–2% relative due to float precision, with identical verdicts — 3 exact-score snapshots updated in test/diff.test.ts.

Tests

  • 24 fixture tests including 4 new layout-shift cases (mask content asserted pixel by pixel: section fully painted, shifted content clean)
  • full backend unit suite 225/225, screenshot-diff e2e 5/5

⚠️ Merge prerequisite

Draft until @argos-ci/mask-fingerprint@0.3.0 is published (argos-ci/mask-fingerprint#6): package.json still pins ^0.1.3 so local installs keep working — bump to ^0.3.0 here once published, then CI can pass.

Follow-ups (from design review)

  • shadow-mode observability before enabling widely (classic vs aligned scores are both returned by the engine, ready to log)
  • deletion-seam visibility in the UI; insertedRows/deletedRows are available to surface a "section added/removed" badge in the frontend
  • known limitation: full-width row hashing — a fixed sidebar crossing the shifted area disables the compensation (silent fallback to classic diff)

🤖 Generated with Claude Code

Replace the two odiff spawns (and their four PNG decodes) with a
single call to @argos-ci/mask-fingerprint's diffScreenshots: both
thresholds are evaluated in one pass over in-memory images, x3 faster
on big screenshots.

The engine also compensates vertical layout shifts: when a section is
inserted, the content below is realigned before comparison so the mask
only marks the new section instead of everything below it. Inserted
rows are fully counted in the score and painted on the mask; deleted
rows are scored and marked with a thin seam.

Behavior notes:
- scores are quantized to 1e-4 to reproduce odiff's two-decimal
  percentage rounding (diffs under 0.005% still count as a match)
- same-width images are now compared without going through sharp
  enlarge (the diff pads with transparency natively); different-width
  images keep the historical scale-to-fit behavior
- the color-sensitive pass differs from odiff by +0.1-2% relative
  (float precision), snapshots updated accordingly

Requires @argos-ci/mask-fingerprint 0.3.0 (to be published, package
bump will follow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@argos-ci

argos-ci Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
argos/default (Inspect) ⚠️ Changes detected (Review) 184 removed Jul 4, 2026, 4:39 PM
storybook/default (Inspect) ✅ No changes detected - Jul 4, 2026, 4:39 PM
Deployment Status Branch Updated (UTC)
storybook/preview (Open) Ready feat/unified-rust-diff Jul 4, 2026, 4:39 PM

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.

1 participant