Skip to content

2.1: delete the legacy namespace trees - #240

Closed
pftg wants to merge 2 commits into
masterfrom
v2.1/delete-legacy-namespace-trees
Closed

2.1: delete the legacy namespace trees#240
pftg wants to merge 2 commits into
masterfrom
v2.1/delete-legacy-namespace-trees

Conversation

@pftg

@pftg pftg commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Draft. Nothing ships until the 2.1 plan is approved. No version bump, no
CHANGELOG entry, no release.

Stacked on #239 (the canonical/legacy test-split gate) — review that first;
this branch contains it.

2.0 ships the v1 compatibility layer intact: the old names keep working, each
one warns with the caller's own file:line, and one migration notice per
process points at the guide. 2.1 removes it. This PR is that removal, and
below is what a project on 2.0 changes to follow.


Migrating from 2.0 to 2.1

Measured, not imagined: a real consumer (a Jekyll/Rails site with committed
visual baselines, running its suite in Docker) was upgraded end to end against
this deletion. 17 lines, two files, zero blockers — 38 runs, 0 failures,
55 screenshots compared, byte-identical before and after. Every v1 API had a
canonical equivalent.

Requires

before after
require "capybara_screenshot_diff/minitest" require "snap_diff/integrations/minitest"
require "capybara_screenshot_diff/rspec" require "snap_diff/integrations/rspec"
require "capybara_screenshot_diff/cucumber" require "snap_diff/integrations/cucumber"
require "capybara_screenshot_diff/reporters/html" require "snap_diff/reporters/html"
require "capybara/screenshot/diff" require "snap_diff"
gem "capybara-screenshot-diff" (Bundler auto-require) gem "snap_diff-capybara"

Configuration

Both v1 holders collapse into one object. SnapDiff.configure is the single
config entry point (ADR-008).

before after
Capybara::Screenshot.<setting> = … SnapDiff.config.<setting> = …
Capybara::Screenshot::Diff.<setting> = … SnapDiff.config.<setting> = …
Capybara::Screenshot::Diff.configure { |c| … } SnapDiff.configure { |config| … }
SnapDiff.start { |screenshot, diff| … } SnapDiff.configure { |config| … }

SnapDiff.start yielded the two v1 holders, so it could not outlive them —
removed, not renamed. Same for SnapDiff.silence_deprecations and
SNAP_DIFF_SILENCE_DEPRECATIONS: with no deprecations left to emit there is
nothing to silence.

Constants and includes

before after
Capybara::Screenshot::Os.name SnapDiff::Os.name
Capybara::Screenshot::Diff::ImageCompare SnapDiff::Comparison
CapybaraScreenshotDiff::Reporters::HTML SnapDiff::Reporters::HTML
CapybaraScreenshotDiff::ScreenshotAssertion SnapDiff::ScreenshotAssertion
include CapybaraScreenshotDiff::DSL
include CapybaraScreenshotDiff::Minitest::Assertions
include SnapDiff::Minitest::Assertionsthe two collapse into one

Capybara::Screenshot::Os is the one to grep for. In the real upgrade it
was the only hard crash: on 2.0 it raises NameError from the shim internals
once the require line has been migrated but the constant has not — a
partially-migrated setup looks fine (config setters keep working) until Os
aborts the whole suite before a single test runs. On 2.1 it is simply gone.

Stubbing point

If your suite stubs the detected driver list, the constant moved:

# before
Capybara::Screenshot::Diff.stub_const(:AVAILABLE_DRIVERS, []) {  }
# after
SnapDiff::Drivers.stub_const(:AVAILABLE_DRIVERS, []) {  }

SnapDiff::Drivers::AVAILABLE_DRIVERS is the published stubbing point;
SnapDiff::Drivers.available is the read API.


What this deletes

lib/capybara/, lib/capybara_screenshot_diff/,
lib/capybara-screenshot-diff.rb, lib/capybara_screenshot_diff.rb,
lib/snap_diff/legacy_shims.rb, lib/snap_diff/deprecation.rb,
test/legacy/.

48 files, 2483 lines removed — 858 lines in 38 lib/ files, 1429 in the 9
test/legacy/ files, 196 in the deletion simulation. Whole diff: 57 files,
+140 / −2639.

Two edits carry the deletion, exactly as deletion_3_0_test.rb had been
asserting them for weeks: lib/snap_diff.rb drops
require "snap_diff/legacy_shims", and lib/snap_diff-capybara.rb repoints
at snap_diff/integrations/minitest.

Fallout beyond those two

  • test/test_helper.rbSnapDiff::Deprecation.suppress_migration_notice!
    and the Warning guard that raised on any [snap_diff deprecation] message
    both go. The channel that emitted them no longer exists, so the guard could
    never fire again.
  • Rakefiletest:canonical was defined as "everything except
    test/legacy/", which is now exactly test. Deleted rather than kept as a
    second name for one thing; rake test is the gate. Also deleted
    test:benchmark: it requires scripts/benchmark/find_region_benchmark,
    which is not in the repo, so the task has been raising LoadError (and its
    body named a v1 constant).
  • scripts/generate_sample_report.rb (rake report:sample) and
    bin/console loaded v1 entry points; repointed at canonical names. Both
    verified running.

Gate dispositions

gate disposition why
test/legacy/legacy_tree_is_alias_only_test.rb dies it proved the v1 trees held no logic; the trees are gone
test/unit/core_tree_has_no_legacy_deps_test.rb kept, repurposed a legacy require now fails loudly by itself, but a user-facing message or docstring naming Capybara::Screenshot.* does not — it survives the deletion and starts lying. Its DELETED_IN_3_0 exclusion list is gone (both files it named are deleted) and its framing moved from "so git rm doesn't break the gem" to "so the removed names don't creep back"
test/unit/canonical_suite_has_no_legacy_refs_test.rb (#239) kept, unchanged same job as before; its allowlist swaps deletion_3_0_test.rb for the replacement below and still holds two entries
test/unit/deletion_3_0_test.rb replaced it simulated the deletion (copy lib/, delete, probe entry points in a subprocess) because the trees were still there. They are not, and support_load_probe_test.rb already runs the same entry-point and advertised-constant tables against the real lib/ on every run — so the ~200 lines of simulation harness, including the gate line that existed to prove the simulation was looking at the deleted tree, went with the trees

Its replacement, test/unit/legacy_surface_removed_test.rb (~50 lines), keeps
the one claim nothing else makes — absence: no removed path is back under
lib/ (everything there is packaged, so a bad rebase ships it), and a fresh
process loading the gem defines none of the removed names. Both halves were
mutation-checked: touch lib/snap_diff/deprecation.rb reds the first,
def self.start in snap_diff.rb reds the second.

Suites

$ mise x ruby@4.0.6 -- bundle exec rake test
468 runs, 1323 assertions, 0 failures, 0 errors, 1 skips

$ mise x ruby@4.0.6 -- bundle exec rake test:unit
440 runs, 1278 assertions, 0 failures, 0 errors, 0 skips

$ mise x ruby@4.0.6 -- bundle exec standardrb
111 files inspected, no offenses detected

Baseline on master was 598/0/1 for rake test and 570/0 for test:unit; the
drop is test/legacy/ (9 files) and the deletion simulation leaving, minus the
new gates arriving.


Two things a reviewer will ask

1. Removing a public API in a MINOR departs from semver. It does. The
mitigation is that it is announced rather than surprising: 2.0's release
notes, docs/UPGRADING.md, and the runtime migration notice must all say
"removed in 2.1" explicitly, so the contract is published before it is
enforced. On 2.0 a v1 user gets working legacy names, a per-constant warning
carrying their own file:line, and one migration notice per process pointing
at the guide — the deprecation machinery built in #237 serves real users, not
just the beta line. Prerequisite on master, not on this branch (this branch
deletes the notice): the notice text currently says "REMOVED in 3.0" and must
be changed to 2.1 before 2.0 ships.

2. chunky_png and shift_distance_limit. ADR-008 also schedules both for
removal. Not implemented here — that is a separate decision, still pending,
and this PR neither removes nor blesses them.

Not done here, deliberately: the docs sweep

Docs still describe the v1 surface as present and still say "3.0" where they
now mean "2.1". Left out to keep this diff reviewable; listing what I saw, by
match count:

docs/UPGRADING.md (62) · docs/configuration.md (31) · docs/framework-setup.md (19)
· docs/architecture.md (17, and it documents legacy_shims.rb as an existing
file) · README.md (13) · docs/snapdiff.md (10) · docs/drivers.md (4) ·
docs/ci-integration.md (3) · docs/migration-guide.md (3) · CONTRIBUTING.md (3)
· docs/organization.md (2) · docs/thread_safety.md (2) · docs/reporters.md (2)

Not all are wrong — a migration guide must name the old API — but every one
needs a read. Same for the remaining 3.0 vocabulary outside the files this PR
touches.

Summary by Sourcery

Delete the v1 compatibility surface and enforce the canonical SnapDiff API for 2.1.

Enhancements:

  • Remove the legacy Capybara and CapybaraScreenshotDiff namespace trees and deprecation machinery, leaving the canonical SnapDiff API as the supported surface.
  • Consolidate configuration around SnapDiff.configure and update bundled entry points and sample tooling to use canonical namespaces.
  • Simplify the test task layout by making rake test the primary gate and removing obsolete canonical and broken benchmark tasks.

Tests:

  • Replace legacy compatibility and deletion-simulation coverage with tests that enforce the removed API's absence and prevent legacy references from returning to canonical code and tests.

pftg added 2 commits August 23, 2026 13:42
`rake test:canonical` is defined as "exactly what must still pass once
test/legacy/ and the v1 trees are gone". Three times in one day a test
asserting LEGACY behaviour was written into test/unit/, i.e. into that
suite: a canonical surface table demanding the shim-only SnapDiff.start
(#236), three legacy-constant probes in a canonical file (#237), and a
pre-existing umbrella guard #236 had to relocate. Each would have failed
the day the deletion landed, long after its author moved on. Reviews
caught all three; the fourth would ship.

The test-tree twin of core_tree_has_no_legacy_deps_test.rb: no file under
test/unit/ or test/integration/ may require a doomed path, name a v1
namespace constant, or use a shim-only name (SnapDiff.start,
.silence_deprecations, SnapDiff::Deprecation, suppress_migration_notice!).
test/legacy/ is deliberately not policed -- exercising the legacy surface
is its job.

Same conventions as the twin: file:line: reason -- `code`, whole-line
comments ignored, a vacuity guard, and a sub-test that fails on stale
allowlist entries. The allowlist holds two entries, both gates rather
than tests of behaviour (deletion_3_0_test.rb, which names the deletion
set by construction, and the twin gate's own pattern literal). A third
entry means canonical tests are still entangled and needs a decision, not
a green build.

This file cannot scan itself: a line-level allowlist has to quote the
lines it blesses, and every quote is itself an offence -- no fixed point
exists.
Removes the v1 compatibility surface: lib/capybara/, lib/capybara_screenshot_diff/,
the two gem-name entry points, snap_diff/legacy_shims.rb, snap_diff/deprecation.rb
and test/legacy/. 48 files, 2483 lines.

2.0 ships the compat layer intact -- working legacy names, per-constant
deprecation warnings, one migration notice per process. 2.1 completes the
move; docs/UPGRADING.md is the path.

The two edits the deletion needs, exactly as deletion_3_0_test.rb had been
asserting them for weeks:

  - lib/snap_diff.rb drops `require "snap_diff/legacy_shims"`
  - lib/snap_diff-capybara.rb repoints at "snap_diff/integrations/minitest"

Fallout beyond those two:

  - test/test_helper.rb: SnapDiff::Deprecation.suppress_migration_notice! and
    the Warning guard that raised on "[snap_diff deprecation]" both go -- the
    channel that emitted those warnings no longer exists.
  - Rakefile: `test:canonical` was "everything except test/legacy", which is
    now `test`. Deleted rather than kept as a second name for one thing.
    `test:benchmark` deleted too: it required
    scripts/benchmark/find_region_benchmark, which is not in the repo, so the
    task has been raising LoadError.
  - scripts/generate_sample_report.rb (rake report:sample) and bin/console
    loaded v1 entry points; repointed at canonical names.

Gates, per gate:

  - test/legacy/legacy_tree_is_alias_only_test.rb -- proved the v1 trees held
    no logic. Subject deleted; the test goes with it.
  - test/unit/core_tree_has_no_legacy_deps_test.rb -- KEPT, repurposed. A
    legacy require now fails loudly on its own, but a message or docstring
    naming Capybara::Screenshot.* does not: it survives the deletion and
    starts lying. The DELETED_IN_3_0 exclusion list is gone (both files it
    named are deleted).
  - test/unit/canonical_suite_has_no_legacy_refs_test.rb -- KEPT unchanged in
    mechanism; the allowlist swaps deletion_3_0_test.rb for its replacement
    and still holds two entries.
  - test/unit/deletion_3_0_test.rb -- SIMULATED the deletion (copy lib/,
    delete, probe). It is now real, and support_load_probe_test.rb runs the
    same entry-point and advertised-constant tables against the real lib/ on
    every run. Replaced by test/unit/legacy_surface_removed_test.rb, which
    keeps the one claim nothing else makes: the removed paths are not back
    under lib/ (everything there is packaged) and a fresh process defines
    none of the removed names.

rake test: 468 runs, 0 failures, 1 skip. rake test:unit: 440/0. standardrb clean.
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3786c44d-2b4f-4db2-a88d-061e3e68088c

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@sourcery-ai

sourcery-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This PR removes the entire v1/legacy Capybara namespace surface and its deprecation machinery, repoints the remaining entry points and scripts to the canonical SnapDiff APIs, and replaces the legacy test split/deletion simulation with targeted gates that assert the legacy surface stays removed and never creeps back into the shipped code.

Flow diagram for legacy surface removal verification

flowchart TD
    Start["Load the real lib/ tree"] --> Paths["Assert removed paths are absent"]
    Paths --> Process["Load the gem in a fresh process"]
    Process --> Names["Assert removed names are undefined"]
    Names --> Refs["Scan canonical code for legacy references"]
    Refs --> Gate["rake test passes"]
Loading

File-Level Changes

Change Details Files
Remove all legacy Capybara Screenshot Diff namespaces, shims, and deprecation machinery so only the canonical SnapDiff surface remains.
  • Delete all lib/capybara/screenshot/diff/* and lib/capybara_screenshot_diff/* implementation and forwarding files, plus their top-level entrypoints.
  • Remove snap_diff/legacy_shims.rb and snap_diff/deprecation.rb that constructed and announced the v1 compatibility layer.
  • Update lib/snap_diff.rb to stop requiring legacy_shims and to document SnapDiff.configure as the single configuration entry point with SnapDiff.start removed.
lib/capybara-screenshot-diff.rb
lib/capybara/screenshot/diff.rb
lib/capybara/screenshot/diff/annotation_service.rb
lib/capybara/screenshot/diff/area_calculator.rb
lib/capybara/screenshot/diff/browser_helpers.rb
lib/capybara/screenshot/diff/config_legacy.rb
lib/capybara/screenshot/diff/cucumber.rb
lib/capybara/screenshot/diff/difference.rb
lib/capybara/screenshot/diff/drivers.rb
lib/capybara/screenshot/diff/drivers/base_driver.rb
lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb
lib/capybara/screenshot/diff/drivers/vips_driver.rb
lib/capybara/screenshot/diff/image_compare.rb
lib/capybara/screenshot/diff/image_preprocessor.rb
lib/capybara/screenshot/diff/os.rb
lib/capybara/screenshot/diff/region.rb
lib/capybara/screenshot/diff/reporters/default.rb
lib/capybara/screenshot/diff/screenshot_matcher.rb
lib/capybara/screenshot/diff/screenshoter.rb
lib/capybara/screenshot/diff/stable_screenshoter.rb
lib/capybara/screenshot/diff/utils.rb
lib/capybara/screenshot/diff/vcs.rb
lib/capybara/screenshot/diff/version.rb
lib/capybara_screenshot_diff.rb
lib/capybara_screenshot_diff/attempts_reporter.rb
lib/capybara_screenshot_diff/cucumber.rb
lib/capybara_screenshot_diff/dsl.rb
lib/capybara_screenshot_diff/error_with_filtered_backtrace.rb
lib/capybara_screenshot_diff/minitest.rb
lib/capybara_screenshot_diff/reporters/html.rb
lib/capybara_screenshot_diff/rspec.rb
lib/capybara_screenshot_diff/screenshot_assertion.rb
lib/capybara_screenshot_diff/screenshot_namer.rb
lib/capybara_screenshot_diff/snap.rb
lib/capybara_screenshot_diff/snap_manager.rb
lib/capybara_screenshot_diff/static.rb
lib/snap_diff/deprecation.rb
lib/snap_diff/legacy_shims.rb
lib/snap_diff.rb
Simplify gem entry points and scripts to use canonical SnapDiff integrations and reporters instead of legacy Capybara names.
  • Change the Bundler auto-require entry point to load snap_diff/integrations/minitest instead of the legacy minitest shim.
  • Update the sample report generator script to require snap_diff and SnapDiff::Reporters::HTML, and to build comparisons and assertions using SnapDiff::Comparison and SnapDiff::ScreenshotAssertion instead of legacy ImageCompare and CapybaraScreenshotDiff classes.
  • Adjust bin/console to load canonical SnapDiff entry points (details in diff) rather than legacy namespaces.
lib/snap_diff-capybara.rb
scripts/generate_sample_report.rb
bin/console
Collapse the test suite’s legacy split, remove legacy-specific helpers, and add/retune gates that assert the legacy surface remains absent from both code and runtime.
  • Remove the legacy test directory and all tests whose subject was the v1 compatibility surface.
  • Delete the test:canonical Rake task and its LEGACY_SURFACE_TESTS constant now that test/legacy no longer exists; make rake test the single gate and keep test:unit scoped to unit tests only.
  • Remove the SnapDiff::Deprecation-based migration notice suppression and Warning guard from test/test_helper.rb because the deprecation channel no longer exists.
  • Retarget core_tree_has_no_legacy_deps_test.rb from guarding a future git rm to guarding against reintroduction of removed names in the canonical core, dropping the DELETED_IN_3_0 exclusion list and tightening its failure messaging.
  • Replace deletion_3_0_test.rb’s simulated deletion harness with legacy_surface_removed_test.rb, which asserts (a) no removed path exists under lib/ and (b) a fresh process that requires the gem defines none of the removed constants or methods.
  • Update canonical_suite_has_no_legacy_refs_test.rb’s ALLOWED map to reference legacy_surface_removed_test.rb and its explicit checks for removed constants instead of the old deletion simulation.
Rakefile
test/test_helper.rb
test/legacy/errors_alias_test.rb
test/legacy/legacy_config_accessors_test.rb
test/legacy/legacy_config_default_timing_test.rb
test/legacy/legacy_entry_point_probe_test.rb
test/legacy/legacy_forwarders_test.rb
test/legacy/legacy_namespace_deprecation_test.rb
test/legacy/legacy_tree_is_alias_only_test.rb
test/legacy/namespace_forwarding_test.rb
test/legacy/snap_diff_deprecation_test.rb
test/unit/canonical_suite_has_no_legacy_refs_test.rb
test/unit/core_tree_has_no_legacy_deps_test.rb
test/unit/deletion_3_0_test.rb
test/unit/legacy_surface_removed_test.rb

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@pftg

pftg commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #249.

#240 was opened before #242/#245/#246/#247/#248 landed, and the 2.1 scope has since grown to include the chunky_png driver, shift_distance_limit, the whole driver abstraction, and ruby-vips as a real gemspec runtime dependency. Nearly every file this branch touched was rewritten by those merges, so #249 is redone from current master rather than rebased.

@pftg pftg closed this Aug 23, 2026
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