You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
No repo in the org ever installs its dependencies at the lower bound of what it declares. Every gate — PR checks and the daily scheduled check alike — resolves highest. A floor that is a lie is therefore invisible until a user hits it.
24 repos have a _checks.yml. None of them has a lower-bound job.
Why now — three instances in one day, 2026-09-20
faststream-outbox declared faststream>=0.7.1 while the code needed 0.7.6. import faststream_outbox failed outright on 0.7.5 with TypeError: TestOutboxBroker.__init_subclass__() takes no keyword arguments. Caught only because someone asked whether the work was backward compatible; fixed in chore(deps): adapt to faststream 0.7.6 and raise its floor faststream-outbox#182.
faststream-outbox declares asyncpg>=0.29 and claims support for Python 3.11–3.14. asyncpg 0.29.0 ships wheels for cp38–cp312 only, but declares requires-python >=3.8.0, so on 3.13+ uv falls through to the sdist and the build fails. The first release with cp313 wheels is 0.30.0. That floor is unsatisfiable on half the supported Python range, today, and nothing reports it.
Item 3 was found by running the proposed job by hand. It is not hypothetical.
Proposal
A lowest job in _checks.yml, alongside the existing matrix. The naive form does not work — see below — so the shape that does:
uv venv
uv pip install --resolution lowest-direct ".[all]"# runtime deps pinned to their declared floors
uv pip install pytest pytest-asyncio pytest-cov # test tooling at current resolution
uv run --no-sync pytest --no-cov
Every runtime dependency sits on its declared floor while the test tooling stays current.
Why not just set UV_RESOLUTION=lowest-direct on the existing job
Because lowest-direct applies to every direct dependency, dev groups included, and all 24 repos declare dev/lint dependencies with no version specifier at all:
pytest with no floor resolves to 2.0.0, which fails to build, and the job dies before it tests anything. Same for asgi-lifespan (0.0.1) and friends. Splitting the install in two sidesteps this entirely and keeps the job about what it is actually for: the runtime contract we publish.
Adding floors across every dev group would also work, but it is 24 repos of churn to fix a problem the two-step install does not have.
Caveats worth deciding on
Python version. The job has to pick one. Old floors frequently predate the newest interpreters (item 3 above), so running it on the lowest supported Python is the honest choice — a floor only has to be installable somewhere in the declared range, and pinning the job to 3.14 would report failures that are not really floor lies.
Repos with service dependencies (faststream-outbox, faststream-redis-timers, faststream-concurrent-aiokafka, db-retry) need their Postgres/Redis/redpanda service block on this job too, or the job runs unit tests only. Unit-only still catches the import-time failures, which is what items 1 and 3 were.
Rollout. Worth doing on one repo first and reading the result before the other 23. faststream-outbox is the obvious candidate: it is the repo where two of the three instances were found, and item 3 means it will fail immediately with something real.
What
No repo in the org ever installs its dependencies at the lower bound of what it declares. Every gate — PR checks and the daily scheduled check alike — resolves highest. A floor that is a lie is therefore invisible until a user hits it.
24 repos have a
_checks.yml. None of them has a lower-bound job.Why now — three instances in one day, 2026-09-20
faststream-outboxdeclaredfaststream>=0.7.1while the code needed 0.7.6.import faststream_outboxfailed outright on 0.7.5 withTypeError: TestOutboxBroker.__init_subclass__() takes no keyword arguments. Caught only because someone asked whether the work was backward compatible; fixed in chore(deps): adapt to faststream 0.7.6 and raise its floor faststream-outbox#182.faststream-redis-timersandfaststream-concurrent-aiokafkawere both capped<0.7.6and then re-floored within the hour (redis-timers#84 → Relative links in README.md 404 on the PyPI package page #85, aiokafka#80 → docs: stop asserting the PR-body shape in AGENTS.md #79). Floor-range edits made under time pressure, with nothing verifying either end.faststream-outboxdeclaresasyncpg>=0.29and claims support for Python 3.11–3.14.asyncpg 0.29.0ships wheels for cp38–cp312 only, but declaresrequires-python >=3.8.0, so on 3.13+ uv falls through to the sdist and the build fails. The first release with cp313 wheels is 0.30.0. That floor is unsatisfiable on half the supported Python range, today, and nothing reports it.Item 3 was found by running the proposed job by hand. It is not hypothetical.
Proposal
A
lowestjob in_checks.yml, alongside the existing matrix. The naive form does not work — see below — so the shape that does:Verified on
faststream-outboxat Python 3.11:Every runtime dependency sits on its declared floor while the test tooling stays current.
Why not just set
UV_RESOLUTION=lowest-directon the existing jobBecause
lowest-directapplies to every direct dependency, dev groups included, and all 24 repos declare dev/lint dependencies with no version specifier at all:that-dependshttpware,modern-di-faststreammodern-di,modern-di-grpcdb-retry,modern-di-aiohttp,modern-di-fastapi,modern-di-starlette,modern-di-typer,semvertagpytestwith no floor resolves to 2.0.0, which fails to build, and the job dies before it tests anything. Same forasgi-lifespan(0.0.1) and friends. Splitting the install in two sidesteps this entirely and keeps the job about what it is actually for: the runtime contract we publish.Adding floors across every dev group would also work, but it is 24 repos of churn to fix a problem the two-step install does not have.
Caveats worth deciding on
faststream-outbox,faststream-redis-timers,faststream-concurrent-aiokafka,db-retry) need their Postgres/Redis/redpanda service block on this job too, or the job runs unit tests only. Unit-only still catches the import-time failures, which is what items 1 and 3 were.faststream-outboxis the obvious candidate: it is the repo where two of the three instances were found, and item 3 means it will fail immediately with something real.Related