Skip to content

Six runtime dependencies have no version constraint, including ruby-openai (locked at 7.1.0, consumers resolve 8.3.0) #16

Description

@minerva-sky

Six of the gem's fourteen runtime dependencies have no version constraint at all. agentic.gemspec:35-48:

spec.add_dependency "dry-schema"     # unbounded
spec.add_dependency "ruby-openai"    # unbounded
spec.add_dependency "zeitwerk"       # unbounded
spec.add_dependency "ostruct"        # unbounded
spec.add_dependency "logger"         # unbounded
spec.add_dependency "cgi"            # unbounded
spec.add_dependency "async", "~> 2.0"
spec.add_dependency "thor", "~> 1.2"
spec.add_dependency "tty-spinner", "~> 0.9"
# ...the rest of the tty-* family, all pessimistic

The tty-* gems got it right. The one that talks to OpenAI didn't.

What that costs, concretely

Gemfile.lock pins ruby-openai (7.1.0). RubyGems currently serves 8.3.0. CI tests 7.1.0. A developer running bundle add agentic today resolves 8.3.0, because nothing in the gemspec says otherwise. So every new user of this gem is running a major version of its most important dependency that the project has never once tested.

That's the semver contract inverted. WORLD.md says "Public API changes follow semver and deprecation cycles. People's agents run on this." An unbounded dependency means someone's agents can break on a bundle update that never touched agentic at all, and there's nothing you could have released to stop it.

I checked whether it's already broken

It isn't, today. bundle update ruby-openai (7.1.0 → 8.3.0, pulling faraday-net_http 3.3.0 → 3.4.4), then:

610 examples, 0 failures

So OpenAI::Client.new(access_token:, uri_base:) and the whole OpenAI::Error hierarchy that lib/agentic/llm_client.rb:221-252 switches on survived the major bump intact.

Two honest caveats on that green run. The suite uses VCR and WebMock, so it proves Ruby-level API compatibility and says nothing about wire behavior against the real API. And it ran on Ruby 4.0.6, not CI's 3.2.4.

Which makes this the cheap moment rather than the urgent one. Right now the constraint can be added and the lock moved in the same breath, with a passing suite on both sides. Wait for a breaking 9.x and it's an incident report instead.

What I'd do

1. Bound the six. For each, the constraint that matches how the code actually uses it:

spec.add_dependency "ruby-openai", ">= 7.1", "< 9"
spec.add_dependency "dry-schema", "~> 1.13"
spec.add_dependency "zeitwerk", "~> 2.6"
spec.add_dependency "ostruct", "~> 0.6"
spec.add_dependency "logger", "~> 1.6"
spec.add_dependency "cgi", "~> 0.4"

ruby-openai gets a range rather than ~> deliberately: 7 and 8 are both verified working here, and narrowing to ~> 7.1 would strand every consumer already resolving 8.x. The other five get standard pessimistic bounds at their locked minors.

Adding a constraint where none existed can break resolution for a consumer sitting outside it, so this is semver-visible and wants a minor bump plus a CHANGELOG line. Your call, which is why it's an issue and not a PR.

2. Decide the lockfile separately. Whether dev/CI moves to ruby-openai 8.3.0 is a smaller question and I'm happy to take it once you've ruled on the constraint. My lean is yes: testing 7.1.0 while shipping consumers onto 8.x is the worst of both.

3. Note the interaction with logger and cgi. Those two are declared because they become bundled gems in Ruby 3.5 (the gemspec comments say so). They deserve bounds like anything else, but they're also the deps most likely to be affected by whatever floor gets picked in #15.

Related

Verification

Run against upstream/main at 99a9167 on Ruby 4.0.6. bundle outdated shows 40 gems behind, of which ruby-openai is the only unbounded runtime dep with a major available.


Filed by the loop:deps session. Labels: loop:deps, status:analyzed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    loop:depsDependency / language upgrade loopstatus:analyzedAnalyzed, awaiting decision

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions