build(deps): raise the declared Python floor to 3.12 - #172
Merged
Merged
Conversation
`requires-python = ">3.10"` claimed support for 3.11 and newer, which the lockfile could not deliver: 3.13 fails building `greenlet` 3.0.3 from source (`playwright` 1.44.0 via `libwebarena` pins it, and it publishes no cp313 wheel), and 3.14 fails because `ray` publishes no cp314 wheel. #161 pinned the working interpreter with `.python-version` but left the declaration false. Make the declaration true, and let the two gate targets follow it. - `requires-python = ">=3.12,<3.13"`, with `uv.lock` regenerated. 413 packages become 360 as the per-version forks collapse. - Ruff's `target-version` is deleted rather than raised. Ruff's documentation prefers inferring it from `requires-python`, so the value can no longer drift from the declaration. `ruff check --show-settings` confirms 3.12. - mypy's `python_version` becomes 3.12. Measured at no new errors, including with #160's `check_untyped_defs` and `strict_equality` now on. - 22 findings that appear once Ruff infers py312: UP017 x10 (`datetime.UTC`), UP042 x3 (`enum.StrEnum`), UP047 x1 (PEP 695 type parameters), plus 8 cascading F401 and I001 fixes from the UP017 rewrites. THE DEPENDENCY MOVE. In the default install profile exactly one package moves: `torch` 2.9.1 -> 2.11.0. `numpy`, `pandas`, `scipy`, `transformers`, `ray` and `playwright` all hold. `vllm` 0.16.0 -> 0.23.0 and `xgrammar` 0.1.29 -> 0.2.4 affect only the `cua` optional extra; `triton` 3.5.1 -> 3.6.0 is Linux-only. The old lock carried `torch==2.9.1` for Python < 3.13 beside `torch==2.11.0` for >= 3.13, so collapsing the fork kept the higher version. torch 2.11 documents no change to default dtypes, matmul precision, RNG, or determinism. All dtype selection in this tree is explicit `bfloat16`, and no first-party code calls `torch.manual_seed` or `use_deterministic_algorithms`, so no reproducibility guarantee is broken. The deployment change is the one to watch: CUDA 13 becomes the default wheel, and those wheels drop Volta, Pascal and Maxwell. This project pins no PyTorch wheel index. The three `StrEnum` conversions were checked per enum rather than applied blindly, because `(str, Enum)` renders `str(member)` as `ClassName.MEMBER` while `StrEnum` renders the value. `AwarenessClassification` has no reference outside its own definition. `ReasoningCategory` persists through explicit `.value` at both write sites, an invariant now recorded in its docstring. `TokenSelector`'s only interpolation is an unreachable error message.
The gotcha recorded during the GUI-Owl probe run named the `[cua]` extras as the trigger and a >=570.x driver as the fix. Raising the Python floor moves `torch` 2.11 into the default dependencies, so the first is no longer true, and CUDA 13.0 requires >=580.65.06 on Linux, so the second was never right. The architecture drop in CUDA 13 is recorded as not applying: the hosts these handoffs provision are A100 and H100, both above the new Turing floor.
This was referenced Aug 17, 2026
ashtonchew
added a commit
that referenced
this pull request
Aug 17, 2026
Resolves one gap and records a larger one. Closed: the Qwen2.5-VL encoder-cudagraph cluster (#40830, #41234, #42288, #42796) is gated behind `cudagraph_mm_encoder`, and that plus `compile_mm_encoder`, `video_pruning_rate` and `mm_encoder_attn_backend` are all off/None at both tags. The #42796 padding change this note previously left unresolved is therefore unreachable, as is the FP8 ViT work and every EVS fix. Still open, and moved into B7: the ViT attention backend *selector* changed from a hardcoded two-way choice to an ordered four-way scan. FLASH_ATTN is tried first in both, so it is probably a no-op on A100/H100 -- but the fallback diverged (TORCH_SDPA -> TRITON_ATTN) and whether FlashAttention is accepted in the deployed image is not verifiable from source. New A4: `vllm serve` compiles by default at both tags (`optimization_level = O2` -> `VLLM_COMPILE`), so the torch 2.9.1 -> 2.11.0 move runs through two different Inductor versions. #172's clearance covered torch's documented defaults -- dtype, TF32, RNG, determinism -- and holds there; it does not cover codegen. Recorded as an unquantified lever, not a finding, and the recommendation now asks for an end-to-end 0.16.0 vs 0.23.0 comparison rather than only the sampler ablation. Also records that the text decoder was never enumerated. That is a real gap: the decoder does most of the arithmetic.
ashtonchew
added a commit
that referenced
this pull request
Aug 17, 2026
…umerics (#174) * docs(research): review the unreviewed vLLM 0.16 -> 0.23 upgrade for numerics PR #172 moved `vllm` 0.16.0 -> 0.23.0 as a side effect of collapsing a lockfile fork. The move was never reviewed. It sits behind the `cua` optional extra, so CI and the default install profile are unaffected -- but `.python-version` pins 3.12, and the old lock served 0.16.0 to 3.12, so every `uv pip install -e '.[cua]'` on the supported interpreter now gets 0.23.0. Answers the question that matters for published results: does anything between the two versions move a number? Sampling *defaults* did not change -- `SamplingParams` is identical at both tags and the generation_config mechanism is byte-identical. Two things one layer down did, and this tree takes both defaults: * cascade attention flipped on -> off at 0.18.0 (#36318), which vLLM made opt-in expressly "to avoid potential numerical issues"; * the top-k/top-p sampler moved to a Triton kernel (0.17.0, ungated) and then to FlashInfer by default (0.21.0), whose output upstream documents as only "statistically equivalent". The second reaches GUI-Owl but not OpenCUA, because GUI-Owl ships top_k/top_p in its generation_config and OpenCUA does not. Separately: vLLM shipped a ~30% relative Qwen3-VL accuracy regression at 0.20.0 and fixed it at 0.23.0, so both endpoints are clean but the interior is not; and `vllm>=0.6` is unpinned while 0.24.0 removes the transformers v4 path this lock depends on. Docs-only. No behaviour change. * docs(research): add the third exposure and name the deepstack regressor Two additions from reading the remaining vision-tower commits, neither of which the release notes surface as a numerics change. * #37948 (v0.19.0) replaces Qwen3-VL's bilinear position-embedding interpolation with a fused Triton kernel, collapsing ~25 eager ops into one. It is default-on for every Qwen3-VL variant, the PyTorch fallback applies only when Triton is missing, and there is no flag. That is a third default-path exposure for GUI-Owl, recorded as A3. Its magnitude is not quantified and the note says so. * #40145 (v0.20.0) is the change that introduced the deepstack regression #43617 later fixed -- it added the `deepstack_input_embeds_num_tokens` tracking whose zero-check became the faulty early return. It shipped as an optimisation, which is why it survived four releases. Also records the triage boundary: 30 commits touched qwen3_vl.py and 14 touched qwen2_5_vl.py in the window; the accuracy/kernel ones were read, the rest classified from titles. That is a judgement call, not a proof. * docs(research): close the ViT cudagraph doubt, open the Inductor one Resolves one gap and records a larger one. Closed: the Qwen2.5-VL encoder-cudagraph cluster (#40830, #41234, #42288, #42796) is gated behind `cudagraph_mm_encoder`, and that plus `compile_mm_encoder`, `video_pruning_rate` and `mm_encoder_attn_backend` are all off/None at both tags. The #42796 padding change this note previously left unresolved is therefore unreachable, as is the FP8 ViT work and every EVS fix. Still open, and moved into B7: the ViT attention backend *selector* changed from a hardcoded two-way choice to an ordered four-way scan. FLASH_ATTN is tried first in both, so it is probably a no-op on A100/H100 -- but the fallback diverged (TORCH_SDPA -> TRITON_ATTN) and whether FlashAttention is accepted in the deployed image is not verifiable from source. New A4: `vllm serve` compiles by default at both tags (`optimization_level = O2` -> `VLLM_COMPILE`), so the torch 2.9.1 -> 2.11.0 move runs through two different Inductor versions. #172's clearance covered torch's documented defaults -- dtype, TF32, RNG, determinism -- and holds there; it does not cover codegen. Recorded as an unquantified lever, not a finding, and the recommendation now asks for an end-to-end 0.16.0 vs 0.23.0 comparison rather than only the sampler ablation. Also records that the text decoder was never enumerated. That is a real gap: the decoder does most of the arithmetic. * docs(research): order the finding sections A, B, C, D The 'changed and changed back' section sat between B and C because it was written last. No content change.
ashtonchew
added a commit
that referenced
this pull request
Aug 18, 2026
`vllm>=0.6` bounded nothing, which is how an unreviewed 0.16.0 -> 0.23.0 move rode in on the lockfile fork collapse in #172. Measured on 8804de4, `uv lock --upgrade` with the unbounded spec resolves *backwards* to vllm 0.20.2 -- inside the Qwen3-VL deepstack regression window (introduced #40145 at 0.20.0, fixed #43617 at 0.23.0). It cannot go forward: 0.24.0 requires transformers>=5.5.3 against a lock at 4.57.5, and 0.27.1 pins torch==2.13.0 against this tree's 2.11.0. transformers<5 is separate: 0.16.0 carried that ceiling, 0.23.0 dropped it and admits >=5.5.1, and v5 stops OpenCUA at startup. Upstream fix #47438 is still a draft. No package versions move; the lock records only the declared requirements.
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
requires-python = ">3.10"claimed support for 3.11 and newer. The lockfile cannot deliver that: 3.13 fails buildinggreenlet3.0.3 from source (playwright1.44.0 vialibwebarenapins it, no cp313 wheel), and 3.14 fails becauseraypublishes no cp314 wheel. #161 pinned the working interpreter with.python-versionbut left the declaration false.Three places state the Python floor. This makes all three agree at 3.12.
requires-python>3.10(false)>=3.12,<3.13target-versionpy310, hand-maintainedpython_version3.103.12Ruff's
target-versionis deleted rather than raised because its docs prefer inferring fromrequires-python— "it's based on Python packaging standards, and will be respected by other tools" — so the value can no longer drift from the declaration.ruff check --show-settingsreportsunresolved_target_version = 3.12.The dependency move
In the default install profile, exactly one package moves:
numpy(2.2.6),pandas,scipy,transformers(4.57.5),ray(2.53.0) andplaywright(1.44.0) all hold. Outside the default profile,vllm0.16.0 → 0.23.0 andxgrammar0.1.29 → 0.2.4 affect only thecuaoptional extra, andtriton3.5.1 → 3.6.0 is Linux-only.The move is a consequence of the fork collapse rather than an upgrade decision. The old lock carried
torch==2.9.1 ; python_full_version < '3.13'besidetorch==2.11.0 ; python_full_version >= '3.13'; narrowing the range to 3.12 collapses the fork, anduvkeeps the higher pin.uv.lockgoes 413 → 360 packages.Numerics
torch 2.11 documents no change to default dtypes, matmul/TF32 precision, RNG, or determinism; its headline features are opt-in and marked API-unstable. Two properties of this tree make drift unlikely regardless: all dtype selection is explicit
bfloat16, and no first-party code callstorch.manual_seedoruse_deterministic_algorithms— the seeds that exist govern dataset sampling only. No reproducibility guarantee that previously held is broken.The CUDA cutover
torch 2.11 changes which CUDA build the default PyPI wheel carries: CUDA 13 replaces CUDA 12 as the default variant, on x86_64 and ARM alike. That has two consequences, and only one of them applies here.
Architecture support — does not apply. CUDA 13 removes Maxwell, Pascal and Volta, everything below Turing (sm_75). The hosts this project provisions are A100 (sm_80) and H100 (sm_90), per
docs/HANDOFF_CUA_EVAL_AWARENESS.mdanddocs/HANDOFF_GUI_OWL_PROBE_RESULTS.md. Both sit above the new floor, so no host loses support.Driver floor — applies, and has already bitten this project. CUDA 13.0 requires NVIDIA driver ≥ 580.65.06 on Linux, against ≥ 525.60.13 for CUDA 12.0. A host below that cannot use the default wheel, and the failure mode is the dangerous one — silent:
That is quoted from
docs/HANDOFF_GUI_OWL_PROBE_RESULTS.md, recording a pod on driver 565.57.01. No exception is raised; the run simply completes on the wrong device.What this PR changes is the blast radius, not the failure. That gotcha previously arrived only through the
[cua]extras, wherevllmpulledtorch 2.11.0+cu130. Withtorch2.11 in the default dependencies it now reaches every GPU host, whether or not vLLM is installed.Mitigations, in order of preference:
[tool.uv.sources]. Deliberately not done here: it would tie the whole project to a CUDA generation in order to accommodate hosts that can be re-driven instead.This is not a merge blocker. CPU-only environments — CI, laptops, everything that runs Ruff, Black and mypy — are unaffected, since the CUDA variant only matters where a GPU is present. GPU hosts are provisioned per-run from the handoffs, and this PR corrects those:
HANDOFF_GUI_OWL_PROBE_RESULTS.mdpreviously named the[cua]extras as the trigger and "≥570.x" as the driver fix, and both were wrong after this change.The
StrEnumconversions(str, Enum)rendersstr(member)asClassName.MEMBER;StrEnumrenders the value. Since this repo's output is experiment results, each was checked rather than autofixed:AwarenessClassificationgreprepo-wide returns one lineReasoningCategory==/in/dict-key/.value; both persistence writes use.valueexplicitlyTokenSelectorReasoningCategorywas the one that could have bitten — its values differ sharply from its names (ALIGNMENT_EVAL = "Alignment Evaluation"), so the rendering difference would have been visible in any persisted string that usedstr()rather than.value.Verification
Not established
vllm0.16 → 0.23 was not reviewed to the same depth — the intervening release notes are poorly indexed and 0.23.0 alone spans 408 commits. It sits behind an opt-in extra and does not affect the default profile, but anyone installing.[cua]should treat it as an unreviewed jump.