Skip to content

docs(standard): state what the floors job proves and the two traps that mask it - #110

Open
lesnik512 wants to merge 1 commit into
mainfrom
docs/floors-standard-amendments
Open

lesnik512 wants to merge 1 commit into
mainfrom
docs/floors-standard-amendments

Conversation

@lesnik512

@lesnik512 lesnik512 commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Closes #107.

The floors job asked for in #107 now runs in all 22 in-scope repos. Rolling it out surfaced three
things §7 does not say, one of which contradicts a claim §7 makes about the job.

The page gets one paragraph, three rules, one citation each, and the exemptions table gets one
row. The evidence for each rule is below rather than on the page: a standard should say what a repo
must do, not carry the investigation that produced the rule.

1. Wheel-only proves the declared range, not the declared floor

§7 says a floor "is a claim that the package installs and works against that version, and floors
is the only job that tests it." The job does not test that. Disabling builds makes a wheel-less
version ineligible, and lowest-direct then climbs to the lowest version that has a wheel, so the
job passes on a version the package never declared.

compose2pod declared PyYAML>=6. PyYAML 6.0 ships no cp312 or cp313 wheel, so the gate
resolved 6.0.1 and 6.0.2 there and went green, while the declared floor was unreachable on both
(modern-python/compose2pod#135).

Both spellings §7 offers behave identically. On 3.12, uv 0.12.5, --resolution lowest-direct:

flag specifier result
--no-build PyYAML>=6 ok, resolves 6.0.1
--only-binary PyYAML PyYAML>=6 ok, resolves 6.0.1
--no-build PyYAML==6.0 fails, no wheel
--only-binary PyYAML PyYAML==6.0 fails, no wheel
none PyYAML>=6 fails, sdist build error

The last row is the point. Without the wheel-only flag the resolver picks 6.0 and dies compiling
it. The flag concealed this defect rather than failing to catch it. The variable is the
specifier, not the flag.

The amendment keeps wheel-only non-optional and adds what makes a green leg mean something: a
marked floor per interpreter whose wheel coverage differs, so the resolved version equals the
declared one, and a readback rather than an assumption. That is the shape compose2pod,
httpware, db-retry and modern-di-aiogram each arrived at independently.

2. Nothing in [dependency-groups] may bound a published dependency

uv runs one resolution across every group, so a bound there silently lifts or holds back a floor
and the job reports a version it never tested. Four instances, all found the hard way:

repo group carried effect
modern-di-aiohttp pytest-aiohttp requires aiohttp>=3.11 lifted a declared floor of 3.9
modern-di-grpc grpcio-tools pins grpcio to its own version pinned the floor to the tool
db-retry advanced-alchemy requires sqlalchemy>=2.0.20 lifted a declared 2.0.18
modern-di-faststream unbounded typing-extensions in lint held pydantic down to a build with no wheel

The last one is the inverse and was found by the repo owner in modern-python/modern-di-faststream#63.
It is why the rule is stated as both directions rather than "floor your harness".

3. src-layout repos need PYTHONPATH on the run step

§7 mandates --no-install-project, which leaves no installed copy. [tool.pytest.ini_options]
pythonpath covers the pytest process but not an interpreter it spawns, so a test that subprocesses
an import fails for a reason unrelated to floors. Four tests in httpware, fixed with
PYTHONPATH: src (modern-python/httpware#134). It is the org's only src-layout repo today, so this
is documentation for the next one rather than a live defect.

Exemptions

One row added, owed by modern-python/faststream-concurrent-aiokafka#85: that gate omits 3.14t
because no aiokafka release ships a cp314t or py3-none-any wheel, so under --no-build the
entry cannot resolve at all. Its pytest job reaches 3.14t only by building the sdist with
AIOKAFKA_NO_EXTENSIONS=1, which this job forbids by design.

Not in this PR

  • A mechanised readback comparing resolved versions against declarations. There is no uv flag
    for it, and it is new tooling across 22 repos. It belongs in its own issue, as a sibling to Lint for published dependencies declared with no lower bound #108.
  • Four jobs still named lowest/lowest-direct rather than floors. Filed separately; the
    job names in three of those repos are the owner's call, not a drive-by rename.
  • lite-bootstrap's missing wheel-only flag, the one repo that has neither spelling. That is a
    repo fix and goes to that repo.

uv run pytest: 132 passed, 29 skipped.

@lesnik512
lesnik512 force-pushed the docs/floors-standard-amendments branch from 2b448e2 to b0b852e Compare September 23, 2026 23:31

This branch has not been deployed

No deployments
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.

CI never resolves dependencies at their declared lower bounds, so stale floors ship unnoticed

1 participant