Skip to content

Agree on an explicit criterion for raising a dependency version floorย #7116

Closed

Description

@albertvillanova

The problem

We have two contradictory positions on the same question live in the repo right now, and no way to tell which one applies.

Every dependency floor bump so far has been feature-driven, with the required feature named: datasets>=4.7.0 for the Json dtype (#5376), kernels>=0.14.0 for trust_remote_code, vllm>=0.11.0 (#5443). In #6447 I made that explicit for bitsandbytes: "Do not bump the floor solely to drop this filter: wait for an independent reason to require 0.50.0."

#7102 raises the peft floor on a different rationale: the floor should be no older than two years. That is a reasonable rule, and it is not the rule in #6447.

Meanwhile #6893 raises the bitsandbytes floor to drop a warning filter, which is exactly what #6447 says not to do and exactly what #7102's rationale would allow. It has been open for two weeks. There is no way to resolve it in either direction, because there is nothing to point at.

Why an explicit criterion

  • Contributors cannot tell in advance whether the work is wanted. Require bitsandbytes>=0.50.0 and drop the _check_is_size warning filterย #6893 is defensible under one of our positions and refused under the other. That is not the contributor's mistake, there was nothing for them to read before they started.
  • Any maintainer should be able to review one of these. Without a stated rule, a floor bump needs a judgment call rather than a check, so it queues behind whoever is presumed to hold the position instead of being reviewable by whoever picks it up. A criterion makes it verifiable from the diff.
  • The floor is a public promise. It is what users install against, so deciding it case by case means it drifts in whichever direction the most recent PR argued.

Prior art

  • SPEC 0 (scientific-python.org), which superseded NEP 29, recommends dropping support for dependency releases older than 24 months and Python releases older than 36 months. Calendar-driven and predictable. This is essentially the rationale in Require peft>=0.13.0 and drop the 0.12 version guardsย #7102.
  • transformers itself has no time-based policy. Tightly coupled cores get narrow ranges with upper bounds (huggingface-hub>=1.5.0,<2.0, tokenizers>=0.23.1,<0.24.0), and everything else gets an oldest-that-works floor that is left alone for years (accelerate>=1.1.0, numpy>=1.17). peft and accelerate behave the same way.

TRL sits closer to the transformers pattern, since we are a thin downstream of fast-moving libraries. But unlike transformers we carry a lot of in-tree version guards and compatibility shims, each with a known expiry, so the question of when a floor may rise comes up for us far more often than it does for them.

Proposal

Two separate questions. I have a suggested answer for each, but the point of this issue is to agree on something, not to argue for these specifically.

1. When is a bump justified at all?

Any one of these is sufficient, and the PR body says which one applies:

2. Guard or bump?

Proposal: guarding is the default, and a bump has to be argued on what it deletes.

Version guards exist precisely so the floor can stay low while newer features light up only on newer installs. Adding a guard is not a user-visible break; raising a floor is. So when TRL wants to use an API newer than the floor, the first answer is a guard, and a floor bump needs its own justification under question 1 rather than being presented as the fix.

The counterweight, which is why this is a trade-off and not a one-liner: a guard is only worth writing when the older version keeps working with reduced capability, rather than the guard merely producing a nicer error. And because trainers here are self-contained by design, a guard inside a trainer block is not one guard, it is a dozen copies that then have to stay aligned. So "always guard" is not free either.

Open points

  • The two numbers: is 6 months the right bar for a cleanup bump, and do we accept 24 months for staleness, or do we want to be more conservative than SPEC 0 given how fast our dependencies move?
  • Is staleness alone enough, or must a stale floor also delete something to be worth touching?
  • Does the same rule apply to optional extras (deepspeed, vllm, bitsandbytes, liger) as to the core dependencies, where the blast radius is different?
  • Does experimental code get the same treatment as main code?

What agreeing on this unblocks

#6893 gets a yes or a no on its merits rather than on which maintainer looks at it. Future bumps of this kind become reviewable by anyone. And we stop re-deriving the same argument in each PR thread.

cc @huggingface/trl

Activity

  1. qgallouedec commented on Sep 8, 2026

    @qgallouedec
    Member

    Thanks for opening the discussion on this. IMO it's hard to write one rule that fits every dependency, but let's try.

    • Past 2 years: fine to drop, no further justification: unlikely anyone is still on a 2024 version.
    • Under 2 years: it's a balance between two things
      • how hard the old version is to keep working, and
      • how critical is it, how many user depend on it (hard to evaluate precisely)

    So:

    • if it's cheap to keep: keep it until it hits 2 years. A warning filter or a one-line guard costs us nothing.
    • if it's hard to keep, few users: raise the floor.
    • if it's hard to keep, lots of users: keep it, and accept that it takes real work. That's where the effort should go.

    So the question is not "does this bump delete something", it's "what does the old version cost us, and who pays if we drop it".


    How it materializes:

    • transformers is a core dep and everyone is on it, so it's the third case almost every time. We support as wide a range as we can, even when that means a lot of branching.
    • vLLM is still unstable and moves fast, very hard to the floor old + only used in RL trainers: we agreed on 5 months there.

    For the two open PRs:

    One gap: bitsandbytes has no floor at all right now, we should add one I think


    @albertvillanova you suggested 6 month, I think it's too short, 2 years is arbitrary, happy to target 1.5 years instead, but I feel like everything below 1 year is too fast.

  2. albertvillanova commented on Sep 8, 2026

    @albertvillanova
    MemberAuthor

    Agreed on the cost model, and your reframe is better than mine.

    On the 6 months I explained it badly: it was not an alternative to the 2 years, nor a permission to drop. It was an extra condition on your second case: under 2 years and the target release older than 6 months. The two answer different questions:

    • 2 years: safe to drop the old version? Nobody is still there.
    • 6 months: safe to require the new one? Everybody can get there.

    So it only ever blocks a bump, never licenses one: below the minimum we don't bump, between it and 2 years your balance decides. Same for your first case.

    The only number in dispute is that minimum, and 1 year works for me.

    #6893: agreed, no. bitsandbytes: agreed, and declaring a first floor drops support for nothing, so it needn't wait on #6893.

  3. qgallouedec commented on Oct 1, 2026

    @qgallouedec
    Member

    Agreed, thanks. So, for core dependencies:

    • past 2 years, drop freely.
    • Under 2 years, weigh the cost of keeping the old version against who uses it.
    • And never require a release younger than 1 year.

    Note that we already broke the last one: datasets>=4.7.0 (#5376) is from March 2026, 7 months old today.

    Could you put all that in a short section of CONTRIBUTING.md so we can point to it? Then we can close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions