From b2150b15f10cd6da26a0d150fad62258a371c962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20V=C3=A1squez?= Date: Tue, 7 Jul 2026 16:11:17 -0600 Subject: [PATCH 1/2] Upgrade Ruby 3.4.9 -> 4.0.4 Major-version Ruby hop. There is no 3.5-3.9 line -- Ruby went 3.4 -> 4.0 directly -- so this is the immediate next sequential hop, done with the full ruby-upgrade methodology (latest-patch baseline, deprecation sweep, floor audit, boot smoke, suite as the gate). Rails stays 8.1.3 on both boots. Ran the whole thing on the host per usual. Version lives in one place now (.ruby-version); the Gemfile (`ruby file: ...`) and CI (`ruby-version-file:`) follow it, so only .ruby-version, .tool-versions, and the Dockerfile tag needed editing. The one real change the sweep surfaced: - ostruct leaves Ruby's default gems in 4.0 (it becomes a bundled gem). Under Bundler that means `require "ostruct"` is no longer implicitly satisfied -- and Rails' own boot path (zeitwerk) requires it, so the app would fail to boot on 4.0. Added `gem "ostruct"` to the Gemfile (harmless on 3.4, required on 4.0). Lock picks up ostruct 0.6.3. Locks relocked on 4.0.4: RUBY VERSION 4.0.4, PLATFORMS ruby only. BUNDLED WITH kept at 4.0.15 -- the plain relock briefly dropped it to 4.0.10 (the bundler ruby 4.0.4 ships), restored via `bundle update --bundler=4.0.15` to avoid regressing the #74 pin. Verified on the host (ruby 4.0.4), both boots: - Deprecation sweep clean after the ostruct fix (the pre-bump 3.4.9 sweep had flagged exactly that removal). - bundle lock: no gem required_ruby_version conflicts. - Dev + production boot clean, zero deprecation warnings. - Suite green (16 runs, 52 assertions, 0 failures), rubocop (42 files, and it recognizes the 4.0 target) and reek both clean. --- .ruby-version | 2 +- .tool-versions | 2 +- Dockerfile | 2 +- Gemfile | 4 ++++ Gemfile.lock | 4 +++- Gemfile.next.lock | 4 +++- 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.ruby-version b/.ruby-version index 7bcbb38..c5106e6 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.4.9 +4.0.4 diff --git a/.tool-versions b/.tool-versions index c0d6a1e..75d5860 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -ruby 3.4.9 +ruby 4.0.4 nodejs 24.18.0 diff --git a/Dockerfile b/Dockerfile index 3b72ba2..a96077a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.4.9 +FROM ruby:4.0.4 RUN dpkg --add-architecture i386 \ && apt-get update -qq \ diff --git a/Gemfile b/Gemfile index 02c894e..70a0f72 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,10 @@ end gem "bundler-audit" gem "next_rails" +# ostruct leaves Ruby's default gems in 4.0 (becomes a bundled gem), so under +# Bundler it must be declared explicitly or `require "ostruct"` fails -- Rails' +# own boot path (zeitwerk) requires it. Harmless on 3.4, required on 4.0. +gem "ostruct" gem "concurrent-ruby", "< 1.3.5" gem "puma", "~> 3.7" # minitest 6.0 dropped minitest/mock.rb into a separate minitest-mock gem; diff --git a/Gemfile.lock b/Gemfile.lock index 0e66e25..0339fe1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -251,6 +251,7 @@ GEM nokogiri (1.19.4) mini_portile2 (~> 2.8.2) racc (~> 1.4) + ostruct (0.6.3) parallel (2.1.0) parser (3.3.11.1) ast (~> 2.4.1) @@ -442,6 +443,7 @@ DEPENDENCIES minitest (< 6) next_rails nokogiri (>= 1.13.0) + ostruct pg (~> 1.1) puma (~> 3.7) rails (>= 8.1.0, < 8.2.0) @@ -460,7 +462,7 @@ DEPENDENCIES wkhtmltopdf-binary (= 0.12.3.1) RUBY VERSION - ruby 3.4.9p82 + ruby 4.0.4 BUNDLED WITH 4.0.15 diff --git a/Gemfile.next.lock b/Gemfile.next.lock index 0e66e25..0339fe1 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -251,6 +251,7 @@ GEM nokogiri (1.19.4) mini_portile2 (~> 2.8.2) racc (~> 1.4) + ostruct (0.6.3) parallel (2.1.0) parser (3.3.11.1) ast (~> 2.4.1) @@ -442,6 +443,7 @@ DEPENDENCIES minitest (< 6) next_rails nokogiri (>= 1.13.0) + ostruct pg (~> 1.1) puma (~> 3.7) rails (>= 8.1.0, < 8.2.0) @@ -460,7 +462,7 @@ DEPENDENCIES wkhtmltopdf-binary (= 0.12.3.1) RUBY VERSION - ruby 3.4.9p82 + ruby 4.0.4 BUNDLED WITH 4.0.15 From e59da3541c415e9ff950bdb180a832d7cebb7bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20V=C3=A1squez?= Date: Tue, 7 Jul 2026 16:16:54 -0600 Subject: [PATCH 2/2] Drop the ostruct explanatory comment from the Gemfile --- Gemfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Gemfile b/Gemfile index 70a0f72..67018eb 100644 --- a/Gemfile +++ b/Gemfile @@ -23,9 +23,6 @@ end gem "bundler-audit" gem "next_rails" -# ostruct leaves Ruby's default gems in 4.0 (becomes a bundled gem), so under -# Bundler it must be declared explicitly or `require "ostruct"` fails -- Rails' -# own boot path (zeitwerk) requires it. Harmless on 3.4, required on 4.0. gem "ostruct" gem "concurrent-ruby", "< 1.3.5" gem "puma", "~> 3.7"