Skip to content

Conversation

@nicolas-grekas
Copy link
Contributor

This is a behavior that we had in symfony/flex but that has been broken about one year ago.

When resolving dependencies with --prefer-lowest and --prefer-stable, the dev version should be considered as more stable than any other non-stable release. The reason is that the dev version is the one that's receiving fixes before the next stable.

An example today is this job: https://github.com/symfony/symfony/actions/runs/18909610115/job/53976430689?pr=62204
We released 7.4-beta1 and framework-bundle needs a fix that is in http-kernel 7.4-dev. We can fix the job by bumping the require from ^7.4 to ^7.4-beta2, but that's a hack: once the stable version will be released, we'll have to revert that change back to ^7.4.

Quality of life improvement as maintainers + just something that makes sense.

Thanks for considering! 🙏

@naderman
Copy link
Member

I'll have to look at this some more, but just intuitively, isn't 7.4-dev the version you'll release as 7.4-beta2 and thus a newer version than 7.4-beta1 so you would expect --prefer-lowest to pick 7.4.-beta1, not 7.4-dev, since beta1 is lower than dev?

Now I get your use case about wanting to test with upcoming releases, but I'm not sure that doing this in general isn't going to lead to regressions elsewhere? Would be good to have a better understanding of other --prefer-lowest usecases, especially of dependencies you do not control yourself. I take it you're mostly thinking about packages you control yourself here? I wonder whether people in those other situations would like this change, or if this should be an additional flag, or something to be specified per package/dependency instead?

@naderman
Copy link
Member

And to add to that, i think it's super confusing that you would expect --prefer-stable to do the exact opposite and prefer an unstable version?

@nicolas-grekas
Copy link
Contributor Author

nicolas-grekas commented Oct 29, 2025

--prefer-lowest changes the intuition one could have about stability: between an alpha and a stable, dev is always the most stable code base when testing with a to-be-released dependency.

@GromNaN
Copy link
Contributor

GromNaN commented Oct 29, 2025

@nicolas-grekas You could say the same for 6.4.x-dev which is more stable than 6.4.99 because it contains only bug fixes. But a package author can decide to perform more advanced tests on a branch before creating a tag.

@naderman
Copy link
Member

The typical use case for --prefer-lowest that I am familiar with, is to check if the lowest versions of dependencies in my composer.json are still compatible with my project. So I want the actual lowest versions, not some upcoming new release of those versions to test with. Now I understand your use case, it just seems like that is a different one from what those flags do/are there for, and should just get its own set of flag(s)?

@glaubinix
Copy link
Contributor

I do see the use case, but it definitely feels unexpected that --prefer-stable would suddenly pick a dev version over a stable version. Stable in Composer refers to the version stability (anything but dev) and not how bug free/stable the code is, which isn't something Composer can evaluate anyway.

@nicolas-grekas
Copy link
Contributor Author

nicolas-grekas commented Oct 29, 2025

You could say the same for 6.4.x-dev which is more stable than 6.4.99

I think I explained why not: there's a special window between an alpha and a stable where dev is a WIP towards more stability.
It is this window that needs special care.

I don't know how to convince you with clearer words: I'm sharing my experience here, 10+ years of juggling with releases. It's quite easy to miss the point by just using the meaning of words. Words are not always exact. That's the case here: dev is more stable than alpha in the window between alpha and stable.

What's really a shame is that composer used to be open enough to allow us to work around this deficiency. But recent progress did close any possibility for plugins to adjust the behavior. So now you're the only master and you can force us to spend more time as maintainers. With only theory as an argument :( You cannot imagine the amount of time small things like this consume...

@naderman
Copy link
Member

I'm not really sure what that last paragraph is about.

Generally: There is a very clear understanding of what "stable" means in Composer and providing reliable, understandable and predictable behavior is a core goal here.

I think what GromNaN is getting at is that by your argument a 3.1.2-dev version may be more "stable" than a 3.1.2 version, since it fixes bug in 3.1.2 as well. But the very nature of it being "dev" makes it unstable, as it can change at any time and frequently will. So somehow making some magic combination of flags somehow determine that a dev version is considered more stable than an actually stable release by Composer definition (stability: PL > stable > RC > beta > alpha > dev) would be extremely confusing to users.

Now all I'm saying here is don't make this a magic flip where somehow combining prefer lowest and prefer stable invert the meaning of what stable is, just add a flag that accurately describes what usecase exactly you are trying to address here and make a PR for that?

@nicolas-grekas
Copy link
Contributor Author

The last paragraph was referencing to this:

This is a behavior that we had in symfony/flex but that has been broken about one year ago.

It also embedded some disappointment, because no:

by your argument a 3.1.2-dev version may be more "stable" than a 3.1.2 version

That's missing the point. The situation I'm raising is when there's no stable release compatible with some lowest requirement. Then, and only then, dev is more stable than alpha/etc because it's a WIP towards stable.

There's absolutely zero situations where a maintainer testing lowest dependency would want to prioritize the alpha that's broken vs the dev that's going to be released as stable soon.

@naderman
Copy link
Member

naderman commented Oct 29, 2025

As a maintainer I disagree with that last statement.

When I require "foo/bar": "^2.0-beta2" in my library, where current versions of foo/bar is 2.0-rc3 and 2.0-dev will be the next rc or final release, when I update with --prefer-lowest and --prefer-stable and run my test suite I want to test if my test suite still succeeds with 2.0-beta2, not if it works with the very newest 2.0-dev about to be released as 2.0.0 final.

I think there are probably very few libraries out there that use flex (as opposed to actual applications), so this is probably not something a lot of people had to deal with, but I personally would be super annoyed and extremely confused if flex made this change for me.

@naderman
Copy link
Member

Rereading my own comment I suppose that does show a different issue with Composer here, cause I would have run my tests with 2.0-rc1 - still closer to what I was trying to do than -dev would have been - but not what I expected either.

@nicolas-grekas
Copy link
Contributor Author

nicolas-grekas commented Oct 29, 2025

When I require "foo/bar": "^2.0-beta2" in my library

That's the point: nobody does that. No libs go as low as bounding to a beta.

@naderman
Copy link
Member

Kind of regardless of what we're discussing here (and can continue to do) - Why don't you just add a new flag --prefer-dev-over-prereleases that has the effect you are looking for?

@nicolas-grekas
Copy link
Contributor Author

nicolas-grekas commented Oct 29, 2025

I will eventually. It's just that it's adding a lot of public complexity for something that should be how things behave. I'm trying to resit crippling the command line :) - those flags and concerns are coupled.

@nicolas-grekas
Copy link
Contributor Author

nicolas-grekas commented Oct 29, 2025

🤔🤔🤔 It might be possible to do this in flex by removing all alpha/beta/RC from the pools of packages when --prefer-lowest is set. I'm going to give it a try tomorrow. Of course, that doesn't mean this shouldn't be done in composer. The point I'm making here is generic to me. But we might also prefer closing if we can't reach a consensus instead of adding yet another flag.

@naderman
Copy link
Member

I think we have a fundamental disagreement here on what a dev version is. I would not consider a dev version following an RC more stable than the RC. It's a fast moving branch, there may be a faulty merge that makes it less stable than the RC.

Dev versions also have other implications, as they change over time, meaning they do not point to a specific release at all. This for example will most likely also prevent them from benefitting from any future package artifact signing work.

I really think doing this type of thing without visibility to users in flex is worse than working out an option or even adding the option via flex. It's a weird subtle change that nobody who runs into unexpected behavior with this will ever be able to understand or debug.

nicolas-grekas added a commit to symfony/flex that referenced this pull request Oct 30, 2025
…refer-stable (nicolas-grekas)

This PR was merged into the 2.x branch.

Discussion
----------

Fix ignoring unstable releases with --prefer-lowest and --prefer-stable

This is a behavior that has been broken about one year ago by [a change is composer](composer/composer@685add7).

The attached implementation is way more robust since it uses a documented hook for plugins.

I tried to explain why this behavior should be the default also for composer without success so far, see:
composer/composer#12581

This is a must when testing lowest deps seriously, backed by years of practice :)

Commits
-------

73537e7 Fix ignoring unstable releases with --prefer-lowest and --prefer-stable
@nicolas-grekas
Copy link
Contributor Author

do this in flex by removing all alpha/beta/RC from the pools of packages

This worked out! Sorry for the trouble, I was wrong about composer being too closed on this one :)
see symfony/flex#1066

Let me close as it might not be worth arguing any longer :)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants