Add Ruby 4.0.6 as the default version, with its own CI suite - #204
Conversation
- .ruby-version (tracked) pins the project default to 4.0.6. The existing
.tool-versions is gitignored, so it could only ever set a personal
default; .ruby-version is read by rbenv/chruby/mise and by
ruby/setup-ruby.
- CI gains a dedicated test-ruby-4 job running RuboCop and RSpec on
4.0.6. The existing matrix job keeps 3.2/3.3 as the compatibility
floor the gemspec still declares (>= 3.2.0), so its check names are
unchanged.
- One spec asserted the pre-3.4 Hash#inspect format ({"key"=>"value"});
Ruby 3.4 added spaces around the arrow. It now compares against
#inspect of the same hash, which is correct on every version — the
client only forwards whatever #inspect produced.
- Gemfile.lock: ffi 1.17.2 -> 1.17.4. The 1.17.2 prebuilt arm64-darwin
gem has no Ruby 4 ABI build, so `bundle install` on Apple Silicon
drifted the lock on every run. 1.17.4 ships one; verified on 3.3.5 too.
Verified locally: full suite and RuboCop pass on both 4.0.6 and 3.3.5.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Codex independent verificationI asked Codex ( Verdict:
The useful independent check here is the It also confirmed the VerificationUnchanged since the original push: CI green on all three suites — Codex review requested and summarized by Claude Code; the quoted text is Codex's, the framing is mine. |
# Conflicts: # .github/workflows/ci.yml
## Summary Follow-up to #204, found while verifying merged `main`. Making Ruby 4.0.6 the default left `Gemfile.lock` pinning `BUNDLED WITH 2.5.16`, which predates Ruby 4. Locally that combination breaks: - every child process spawned from `bundle exec` inherits `RUBYOPT=-rbundler/setup`, and bundler 2.5.16 floods stderr with `already initialized constant Gem::Platform::*` against Ruby 4's RubyGems while re-resolving; - that delayed the two **real-subprocess** stdio compliance specs past their timeouts (`server_stdio_compliance_spec.rb:38` and `:54`), and made the whole suite ~4× slower (3m59s vs 56s). I confirmed it is not related to the security merges: the same two specs fail with the **pre-merge** stdio code under 4.0.6, and pass on 4.0.6 as soon as a compatible bundler is used. CI never caught this because `ruby/setup-ruby` installs its own bundler rather than the one in the lockfile — so it only affected anyone following `.ruby-version`, which is exactly what #204 told people to do. ## Fix `BUNDLED WITH` → `4.0.17`. It declares `required_ruby_version >= 3.2.0`, the same floor as this gem, so it covers all three tested Rubies (4.0.6, 3.3, 3.2). ## Testing | | before | after | |---|---|---| | `server_stdio_compliance_spec.rb` on 4.0.6 | 2 failures | 10 examples, 0 failures | | full suite on 4.0.6 | 2 failures, 3m59s | **1693 examples, 0 failures, 56s** | RuboCop clean (136 files). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Adds Ruby 4.0.6, gives it a dedicated CI suite, and makes it the project's default Ruby.
.ruby-version(new, tracked) pins the default to4.0.6. The repo already had.tool-versions, but it is gitignored (.gitignore:14), so it could only ever set a personal default — it would not have made 4.0.6 the default for anyone else..ruby-versionis read by rbenv, chruby, mise andruby/setup-ruby.test-ruby-4CI job runs RuboCop + RSpec on 4.0.6 as its own suite, listed first.['3.2', '3.3']— that is the compatibility floor the gemspec still declares (required_ruby_version >= 3.2.0). Keeping it as-is also means the existingtest (3.2)/test (3.3)check names don't change, so any branch protection rules keep working.Two things Ruby 4 actually broke
Both were found by running the suite on 4.0.6, not by inspection:
Hash#inspectformat.spec/lib/mcp_client/logging_spec.rbasserted{"key"=>"value"}; Ruby 3.4 changed the format to{"key" => "value"}, so the spec failed on 4.0.6. The library itself is fine — it just forwards whatever#inspectreturns — so the spec now compares againstpayload.inspectof the same hash, which is correct on every version rather than pinned to one.ffi1.17.2 has no Ruby 4 ABI build forarm64-darwin. With the old lock,bundle installon Apple Silicon re-resolved to 1.17.4 on every run, dirtyingGemfile.lock. Bumped to 1.17.4, which ships an arm64-darwin build covering Ruby 4. (1.17.2 does still compile from source on 4.0.6 — I checked — so Linux CI was never blocked; this is about lockfile stability for local development, which matters now that 4.0.6 is the default.) Verified the suite still passes on 3.3.5 with 1.17.4.What I deliberately did not change
gemspec required_ruby_versionstays>= 3.2.0. Supporting 4.0 doesn't raise the floor, and 3.2/3.3 remain tested..rubocop.ymlTargetRubyVersionstays3.3.5. It should track the oldest supported Ruby, not the newest — bumping it to 4.0 would let RuboCop suggest Ruby-4-only idioms that break the 3.2 users the gemspec promises to support.Testing
Ran locally against a real 4.0.6 install (
ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +PRISM), not just in CI:3.2 is covered by CI only — I don't have that interpreter locally.
Note on overlap with #203
#203 pins the CI actions to commit SHAs and touches the same file. Whichever lands second needs a trivial merge; if this one lands first, the new job's
actions/checkout@v4/ruby/setup-ruby@v1should be pinned the same way as the rest. I kept this job's style matching its neighbours onmainso the file stays internally consistent either way.🤖 Generated with Claude Code