Repository navigation
Conversation
The reformatting is what rubocop -a did: spaces inside array brackets, no trailing comma on the last hash entry. No behaviour changed. rake now runs the suite and the cop, so the default task is the whole check rather than half of it.
0.1.0 declared rack >= 2.2 and did not work on Rack 2. Rack 3 requires response header keys to be lowercase; Rack 2 left the case alone and its file server returns Content-Type. This endpoint reads that header to decide whether to inject the <base> tag, so on Rack 2 the injection never fired and a mounted game served its index.html and then none of its assets. Bounding the version rather than doing a case-insensitive lookup: on Rack 3 the lowercase key is a guarantee, so the failure mode stops existing instead of being defended against for good. The floor is 3.0.3 and not 3.0 because Rack::URLMap up to 3.0.2 calls Regexp.new with the third argument Ruby 3.2 removed, and URLMap is what backs Rack::Builder#map and Rails' mount alike. required_ruby_version said 3.1, but the development dependencies have needed 3.2 since they were written.
The suite on Ruby 3.2, 3.3 and 3.4, plus one run pinned to the oldest Rack the gemspec claims to support. That pinned run is the point: 0.1.0 shipped a lower bound nothing had ever executed, and it was wrong twice over — the header case and Rack::URLMap both moved underneath it. Separate jobs lint, and build the gem, install it and require it, because a gemspec whose files list has a hole still packages fine and only fails for whoever installs it.
Three things the workflow itself got wrong, all of which only showed up by running it: An unset matrix axis arrives as RACK_VERSION="", and an empty string is true in Ruby, so every unpinned job asked for `gem "rack", ""` and failed to resolve before it ever reached the suite. gem install --local forbids the network, so installing the built gem into an empty directory could not fetch the rack it depends on — which is the one thing that step exists to check. An include entry whose keys match an existing matrix combination is merged into it rather than added, so the pinned-rack entry swallowed the plain Ruby 3.2 run instead of joining it. Spelled out as include entries alone, where each is its own job.
v4 runs on Node 20, which the runners now force onto Node 24 and warn about on every job.
rstammer
marked this pull request as ready for review
August 2, 2026 12:33
Same engine underneath, opposite stance: omakase enables 45 cops and expects you to override it, Standard enables 353 and expects you not to. The visible difference is bracket spacing — [ "lib" ] becomes ["lib"] — which is why this touches every file that has a literal in it. Two of the rewrites are not whitespace. Dir.children(dir).empty? became Dir.empty?(dir), and a bare rescue StandardError lost the redundant class. Both mean exactly what they meant before.
rstammer
marked this pull request as draft
August 2, 2026 12:48
rstammer
marked this pull request as ready for review
August 2, 2026 12:48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
0.1.0 declared
rack >= 2.2and did not work on Rack 2.Rack 3 requires response header keys to be lowercase. Rack 2 left the case alone, and its file server returns
Content-Type. The endpoint reads that header to decide whether to inject the<base>tag — so on Rack 2 the injection never fired, and a mounted game served itsindex.htmland then none of its assets. Silent: correct status, correct headers, blank canvas.Bounding the version rather than adding a case-insensitive lookup. On Rack 3 the lowercase key is a guarantee, so the failure mode stops existing instead of being defended against forever.
The floor is 3.0.3, not 3.0
Found by actually running it.
Rack::URLMapup to 3.0.2 callsRegexp.newwith the third argument Ruby 3.2 removed, and URLMap backs bothRack::Builder#mapand Rails'mount— so on the Ruby this gem now requires, anything below 3.0.3 raisesArgumentErrorthe moment you mount it, which is the only way the gem is ever used.Changes
rack >= 3.0.3, < 4;required_ruby_version >= 3.2(it said 3.1, but the dev dependencies have needed 3.2 since they were written)rakeruns spec + standardrb.A note on the linter commits
This branch adopts
rubocop-rails-omakasein one commit and replaces it with Standard in a later one. That is the actual sequence of the work rather than a tidied-up version of it, kept because the two configs are worth contrasting: omakase enables 45 cops and is designed to be overridden, Standard enables 353 and is designed not to be. The visible difference is bracket spacing ([ "lib" ]vs["lib"]), which is why the switch touches every file containing a literal.Two rewrites in that commit are not whitespace:
Dir.children(dir).empty?becameDir.empty?(dir), and a barerescue StandardErrorlost the redundant class. Both mean what they meant before.Verified
CI green on all six jobs. The first run was not, and one commit is the workflow being fixed against itself:
RACK_VERSION="", and an empty string is truthy in Ruby, so every unpinned job asked forgem "rack", ""gem install --localforbids the network, so the install-into-an-empty-dir step could not fetch the dependency it exists to checkincludeentry matching an existing combination is merged into it, so the pinned-rack entry swallowed the plain Ruby 3.2 job rather than joining itLocally:
bundle exec rakegreen on Ruby 3.4.7, suite green on 3.3.5, across all three rack resolutions (latest 3.2.6, empty env, pinned 3.0.3).Note
This is a breaking change for anyone on Rack 2, and 0.1.0 is published. In practice nobody could have been running it there, since the feature that breaks is the one the gem exists for.