Yes. A lower bound in your manifest is a promise that your library works with that version, so test it. Add one CI job that installs the lowest allowed versions and runs your tests, next to the job that installs the latest.
Why the floor needs testing
Python's packaging guide says to give dependencies known lower and upper bounds, such as A>=1,<2. A bound is only known if you have run your code against it. Many libraries raise their code to use a newer feature, forget to raise the declared floor, and ship a range that does not work at its low end. Users who resolve to the minimum version, which happens when other packages constrain them, hit errors you never saw.
There is a security side too. If the floor allows a version with a known advisory that affects you, your users can end up there. Testing the floor makes you look at it.
Two jobs, two ends of every range
| Job | Installs | Catches |
|---|---|---|
| Lowest | The minimum allowed version of each dependency | Floors that are too low, missing feature checks |
| Latest | The newest allowed versions | Breakage from new releases |
The Cargo guide documents the latest side: run cargo update, build and test, in a job marked to continue on failure. The lowest job is the mirror image, and tooling for it varies by ecosystem, so check what your package manager offers.
Making a lowest job
The method depends on your ecosystem, but the pattern is the same:
- Install the dependencies at the declared minimum. Some package managers have a resolution option for this, and in others you generate a constraints file from your declared lower bounds.
- Run the same tests as normal.
- Fix failures by raising the floor, not by adding workarounds, unless the older version is important to users.
- Keep the job required, because a failing floor is a real bug in your promise.
Unlike the latest job, a lowest job usually should block merges. It tests something you control.
Raise the floor on purpose
There are three good reasons to raise a floor:
- Your code uses a feature from a newer release.
- An advisory affects older versions and your code reaches the flaw.
- Supporting the old version costs you more than it helps users.
Say so in your release notes. A raised floor is a visible change for users with older environments.
Choosing floors for security
When an advisory affects versions below a fixed release, and you are affected, set your floor at or above the fix. If you are not affected, you may keep a lower floor, but expect scanner questions. A short statement helps, and so does raising the floor anyway if it costs little.
Keep the matrix small
You do not need every combination. Test lowest, latest and whatever lockfile you use for development. Add more only where you have seen real failures.
Quick check
Do I need a lowest job for every dependency?
Run it on the whole set at once. Split it only if failures are hard to attribute.
Should the lowest job block merges?
Usually yes. It tests the promise your manifest makes.
Safeguard shows which dependency versions a project resolves and which have known advisories, which helps when choosing floors. Start with the free scan.
Sources
- Python Packaging User Guide, install_requires vs requirements files: https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/
- Cargo Book, continuous integration: https://doc.rust-lang.org/cargo/guide/continuous-integration.html
Last reviewed: 19 October 2026.