From c1786282ba7e8c38d730b4fb267ff3cf6ccdaa81 Mon Sep 17 00:00:00 2001 From: Tobias Oberstein Date: Wed, 1 Jul 2026 20:33:34 +0200 Subject: [PATCH 1/4] start new dev branch; add audit file --- .audit/oberstet_fix_1875.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .audit/oberstet_fix_1875.md diff --git a/.audit/oberstet_fix_1875.md b/.audit/oberstet_fix_1875.md new file mode 100644 index 000000000..a5248ed64 --- /dev/null +++ b/.audit/oberstet_fix_1875.md @@ -0,0 +1,8 @@ +- [ ] I did **not** use any AI-assistance tools to help create this pull request. +- [x] I **did** use AI-assistance tools to *help* create this pull request. +- [x] I have read, understood and followed the projects' [AI Policy](https://github.com/crossbario/autobahn-python/blob/main/AI_POLICY.md) when creating code, documentation etc. for this pull request. + +Submitted by: @oberstet +Date: 2026-07-01 +Related issue(s): #1875 +Branch: oberstet:fix_1875 From 92f1e6a934a2755b16ea913915ac58706c1846b8 Mon Sep 17 00:00:00 2001 From: Tobias Oberstein Date: Wed, 1 Jul 2026 21:09:40 +0200 Subject: [PATCH 2/4] Guard wheel builds against a wrong ABI tag; reserve cpy314t spec (#1875) The aarch64 CPython 3.14 wheel in 26.6.x shipped the free-threaded ABI (cp314-cp314t-...aarch64.whl) in the GIL cp314 slot, so there was no GIL cp314 aarch64 wheel and those users fell back to the sdist. Root cause: an older uv resolved `cpython-3.14` to the free-threaded interpreter on the aarch64 manylinux container. Verified under QEMU aarch64 on asgard1 that current uv (0.11.26) resolves `cpython-3.14` -> GIL (Py_GIL_DISABLED=0) and `cpython-3.14t` -> free-threaded (Py_GIL_DISABLED=1), so the interpreter spec is already correct; a rebuild now yields the right cp314 wheel. To make it regression-proof (the wheel ABI tag is fixed by the building interpreter), add a `_check-venv-abi` guard invoked by `just build`: it asserts the interpreter's GIL/free-threaded status matches the env name (cpy314 -> GIL, cpy314t -> free-threaded, pypy skipped) and aborts on mismatch. Also add a reserved `cpy314t` -> `cpython-3.14t` spec for the future free-threaded wheel variant (Part 2, gated on an NVX free-threading assessment). Verified locally on x86_64: the guard passes for cpy314 (GIL) and cpy314t (free-threaded), skips pypy311, and rejects a free-threaded interpreter in a GIL slot. Note: the `_check-venv-abi` recipe exceeds the 10-line new-logic guideline in AI_POLICY.md and warrants explicit human review. Note: This work was completed with AI assistance (Claude Code). --- docs/changelog.rst | 1 + justfile | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index ef11b2707..4ffae1113 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,7 @@ Changelog * Add CalVer / PEP 440 version-management ``just`` recipes (``file-version``, ``bump-dev``, ``bump-next``, ``prep-release``) mirroring Crossbar.io, and document the versioning policy in ``CONTRIBUTING.md`` (#1894) * Add ``ruff check --select ANN,UP,TCH`` (annotation presence, ``pyupgrade`` modern syntax, ``TYPE_CHECKING`` imports) to the ``just check-typing`` recipe so annotation/style regressions are caught in the ``quality-checks`` CI job. The existing gaps in ``src/autobahn/`` are ratcheted via an explicit ``--ignore`` allowlist to be removed module-by-module (#1839); all other ``UP``/``TC`` rules are enforced immediately, and generated code is excluded. The annotation rules are scoped to this recipe via the command line rather than the global ``[tool.ruff.lint]`` select, so the repo-wide ``check-format`` gate is unaffected (#1840) +* Guard wheel builds against a wrong ABI tag: ``just build`` now asserts (via ``_check-venv-abi``) that the building interpreter's GIL / free-threaded status matches the target env, so a free-threaded ``cp314t`` wheel can never be published in the GIL ``cp314`` slot. This closes the aarch64 mis-tag seen in 26.6.x (an older ``uv`` resolved ``cpython-3.14`` to the free-threaded interpreter on the aarch64 manylinux container; current ``uv`` resolves to GIL — verified under QEMU aarch64). A reserved ``cpy314t`` env spec (``cpython-3.14t``) is added for a future free-threaded wheel variant (#1875) 26.6.2 ------ diff --git a/justfile b/justfile index c47dd0bc9..35d69dd93 100644 --- a/justfile +++ b/justfile @@ -81,6 +81,7 @@ _get-spec short_name: set -e case {{short_name}} in cpy314) echo "cpython-3.14";; # cpython-3.14.0b3-linux-x86_64-gnu + cpy314t) echo "cpython-3.14t";; # CPython 3.14 free-threaded (no-GIL); reserved for #1875 Part 2 cpy313) echo "cpython-3.13";; # cpython-3.13.5-linux-x86_64-gnu cpy312) echo "cpython-3.12";; # cpython-3.12.11-linux-x86_64-gnu cpy311) echo "cpython-3.11";; # cpython-3.11.13-linux-x86_64-gnu @@ -88,6 +89,29 @@ _get-spec short_name: *) echo "Unknown environment: {{short_name}}" >&2; exit 1;; esac +# Assert the venv interpreter's ABI (GIL vs free-threaded) matches the env name, so a wheel +# is never published with the wrong ABI tag -- e.g. a free-threaded cp314t wheel in the GIL +# cp314 slot, which shipped on aarch64 in 26.6.1 when an older uv resolved `cpython-3.14` to +# the free-threaded interpreter (autobahn #1875 / zlmdb #124). The wheel ABI tag is fixed by +# the building interpreter, so checking the interpreter catches the mismatch at build time. +_check-venv-abi venv: + #!/usr/bin/env bash + set -e + VENV_NAME="{{ venv }}" + VENV_PYTHON=$(just --quiet _get-venv-python "${VENV_NAME}") + case "${VENV_NAME}" in + pypy*) echo "==> ABI check skipped for '${VENV_NAME}' (PyPy)"; exit 0 ;; + *t) EXPECT_FT=1 ;; # e.g. cpy314t -> free-threaded (no-GIL) + *) EXPECT_FT=0 ;; # e.g. cpy314 -> GIL + esac + ACTUAL_FT=$(${VENV_PYTHON} -c "import sysconfig; print(1 if sysconfig.get_config_var('Py_GIL_DISABLED') else 0)") + if [ "${ACTUAL_FT}" != "${EXPECT_FT}" ]; then + echo "ERROR: interpreter ABI mismatch for '${VENV_NAME}': Py_GIL_DISABLED=${ACTUAL_FT}, expected free-threaded=${EXPECT_FT}." >&2 + echo " Building would emit a wrong-ABI wheel (e.g. cp314t in the cp314 slot). Aborting." >&2 + exit 1 + fi + echo "==> ABI check OK: '${VENV_NAME}' interpreter free-threaded=${ACTUAL_FT} (expected ${EXPECT_FT})" + # uv python install pypy-3.11-linux-aarch64-gnu --preview --verbose # file /home/oberstet/.local/share/uv/python/pypy-3.11.11-linux-aarch64-gnu/bin/pypy3.11 # /home/oberstet/.local/share/uv/python/pypy-3.11.11-linux-aarch64-gnu/bin/pypy3.11: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=150f642a07dc36d3e465beaa0109e70da76ca67e, for GNU/Linux 3.7.0, stripped @@ -1673,6 +1697,11 @@ build venv="": (install-build-tools venv) fi VENV_PATH="{{ VENV_DIR }}/${VENV_NAME}" VENV_PYTHON=$(just --quiet _get-venv-python "${VENV_NAME}") + + # Fail fast if the interpreter ABI doesn't match the env (autobahn #1875 / zlmdb #124): + # prevents publishing e.g. a free-threaded cp314t wheel in the GIL cp314 slot. + just _check-venv-abi "${VENV_NAME}" + echo "==> Building wheel package..." # Build the wheel with NVX acceleration From 608072bbe27fe0ef55f9a2e6abf5cf1febd28064 Mon Sep 17 00:00:00 2001 From: Tobias Oberstein Date: Wed, 1 Jul 2026 21:41:21 +0200 Subject: [PATCH 3/4] Bump .cicd submodule to wamp-cicd #11 (exact ABI-tag release gate) (#1875) Advance the .cicd (wamp-cicd) submodule f77ca2b -> f9a9a7e, which includes the exact CPython ABI-tag matching fix in the shared check-release-fileset action (wamp-cicd #11). This is the release-gate companion to the build-time _check-venv-abi guard: a cp314t wheel in a cp314 slot now fails both the build and the release fileset check. The action is consumed at @main, so the fix is already effective in CI; this pins the vendored .cicd tooling to match. Note: This work was completed with AI assistance (Claude Code). --- .cicd | 2 +- docs/changelog.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.cicd b/.cicd index f77ca2b6a..f9a9a7e2e 160000 --- a/.cicd +++ b/.cicd @@ -1 +1 @@ -Subproject commit f77ca2b6a3ac1399bcd24c3ccc674cc68e85273f +Subproject commit f9a9a7e2eb85aa176dd4cf233955deabdd39a2cc diff --git a/docs/changelog.rst b/docs/changelog.rst index 4ffae1113..5ca9f4b0b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,7 @@ Changelog * Add CalVer / PEP 440 version-management ``just`` recipes (``file-version``, ``bump-dev``, ``bump-next``, ``prep-release``) mirroring Crossbar.io, and document the versioning policy in ``CONTRIBUTING.md`` (#1894) * Add ``ruff check --select ANN,UP,TCH`` (annotation presence, ``pyupgrade`` modern syntax, ``TYPE_CHECKING`` imports) to the ``just check-typing`` recipe so annotation/style regressions are caught in the ``quality-checks`` CI job. The existing gaps in ``src/autobahn/`` are ratcheted via an explicit ``--ignore`` allowlist to be removed module-by-module (#1839); all other ``UP``/``TC`` rules are enforced immediately, and generated code is excluded. The annotation rules are scoped to this recipe via the command line rather than the global ``[tool.ruff.lint]`` select, so the repo-wide ``check-format`` gate is unaffected (#1840) * Guard wheel builds against a wrong ABI tag: ``just build`` now asserts (via ``_check-venv-abi``) that the building interpreter's GIL / free-threaded status matches the target env, so a free-threaded ``cp314t`` wheel can never be published in the GIL ``cp314`` slot. This closes the aarch64 mis-tag seen in 26.6.x (an older ``uv`` resolved ``cpython-3.14`` to the free-threaded interpreter on the aarch64 manylinux container; current ``uv`` resolves to GIL — verified under QEMU aarch64). A reserved ``cpy314t`` env spec (``cpython-3.14t``) is added for a future free-threaded wheel variant (#1875) +* Bump the ``.cicd`` (wamp-cicd) submodule to include exact CPython ABI-tag matching in the shared ``check-release-fileset`` release-gate action, so a wrong-ABI wheel (e.g. ``cp314t`` in the ``cp314`` slot) is also rejected at release-fileset validation, not only by the build-time guard above (wamp-cicd #11, completes #1875) 26.6.2 ------ From 9811e7edac3dd80c63e3674ce6d99c755117612b Mon Sep 17 00:00:00 2001 From: Tobias Oberstein Date: Wed, 1 Jul 2026 22:45:24 +0200 Subject: [PATCH 4/4] Fix uv resolving cpy314 to free-threaded on manylinux (PATH strip) (#1875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI proved the real root cause: the ARM64 manylinux_2_28 image pre-installs both GIL (/opt/python/cp314-cp314) and free-threaded (/opt/python/cp314-cp314t) 3.14 and prepends both to PATH, with the free-threaded dir ahead of the GIL one. uv 0.11.26 then resolved `cpython-3.14` to the free-threaded interpreter (log: "Using CPython 3.14.6+freethreaded ... cp314-cp314t"), which the _check-venv-abi guard correctly caught (Py_GIL_DISABLED=1) and aborted the build. (My earlier QEMU/debian test missed this because bare debian has no system 3.14, so uv downloaded a managed GIL build.) Fix in the shared `create` recipe: for GIL envs, drop free-threaded `…t/bin` dirs from PATH before `uv venv`, so uv selects the GIL /opt/python interpreter (the reserved cpy314t env keeps them for building free-threaded wheels). No-op off manylinux (local builds download a managed GIL python as before). The build-time guard stays as defence-in-depth. Verified locally: the PATH filter strips cp314t/cp315t and keeps cp314 (GIL) against the exact failing CI PATH; `just create cpy314` still builds a GIL venv (Py_GIL_DISABLED=0) and passes the guard. Note: the create PATH filter and the guard exceed the 10-line new-logic guideline in AI_POLICY.md and warrant explicit human review. Note: This work was completed with AI assistance (Claude Code). --- docs/changelog.rst | 2 +- justfile | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 5ca9f4b0b..1b4aa6bc1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,7 +17,7 @@ Changelog * Add CalVer / PEP 440 version-management ``just`` recipes (``file-version``, ``bump-dev``, ``bump-next``, ``prep-release``) mirroring Crossbar.io, and document the versioning policy in ``CONTRIBUTING.md`` (#1894) * Add ``ruff check --select ANN,UP,TCH`` (annotation presence, ``pyupgrade`` modern syntax, ``TYPE_CHECKING`` imports) to the ``just check-typing`` recipe so annotation/style regressions are caught in the ``quality-checks`` CI job. The existing gaps in ``src/autobahn/`` are ratcheted via an explicit ``--ignore`` allowlist to be removed module-by-module (#1839); all other ``UP``/``TC`` rules are enforced immediately, and generated code is excluded. The annotation rules are scoped to this recipe via the command line rather than the global ``[tool.ruff.lint]`` select, so the repo-wide ``check-format`` gate is unaffected (#1840) -* Guard wheel builds against a wrong ABI tag: ``just build`` now asserts (via ``_check-venv-abi``) that the building interpreter's GIL / free-threaded status matches the target env, so a free-threaded ``cp314t`` wheel can never be published in the GIL ``cp314`` slot. This closes the aarch64 mis-tag seen in 26.6.x (an older ``uv`` resolved ``cpython-3.14`` to the free-threaded interpreter on the aarch64 manylinux container; current ``uv`` resolves to GIL — verified under QEMU aarch64). A reserved ``cpy314t`` env spec (``cpython-3.14t``) is added for a future free-threaded wheel variant (#1875) +* Fix the aarch64 CPython 3.14 wheel shipping the free-threaded ABI (``cp314t``) in the GIL ``cp314`` slot (26.6.x). Root cause: manylinux images pre-install both the GIL and free-threaded 3.14 under ``/opt/python`` and prepend them to ``PATH``, and ``uv`` resolved ``cpython-3.14`` to the free-threaded interpreter (first on ``PATH``). The ``create`` recipe now drops free-threaded ``…t/bin`` dirs from ``PATH`` for GIL envs so ``uv`` selects the GIL build. As defence-in-depth, ``just build`` also asserts (via ``_check-venv-abi``) that the interpreter's GIL/free-threaded status matches the env and aborts on mismatch, so a wrong-ABI wheel can never be published. A reserved ``cpy314t`` env spec (``cpython-3.14t``) is added for a future free-threaded wheel variant (#1875) * Bump the ``.cicd`` (wamp-cicd) submodule to include exact CPython ABI-tag matching in the shared ``check-release-fileset`` release-gate action, so a wrong-ABI wheel (e.g. ``cp314t`` in the ``cp314`` slot) is also rejected at release-fileset validation, not only by the build-time guard above (wamp-cicd #11, completes #1875) 26.6.2 diff --git a/justfile b/justfile index 35d69dd93..110e01090 100644 --- a/justfile +++ b/justfile @@ -280,9 +280,18 @@ create venv="": # Get the Python spec just-in-time PYTHON_SPEC=$(just --quiet _get-spec "${VENV_NAME}") + # For a GIL env, drop free-threaded CPython dirs (…t/bin, e.g. cp314t) that + # manylinux images pre-install on PATH ahead of the GIL build, so uv does not + # resolve e.g. cpy314 to a free-threaded cp314t interpreter (#1875). The dedicated + # cpy314t env is used to build free-threaded wheels. No-op off manylinux. + CREATE_PATH="${PATH}" + if [[ "${VENV_NAME}" != *t ]]; then + CREATE_PATH="$(printf '%s' "${PATH}" | tr ':' '\n' | grep -vE '/opt/python/[^/]*t/bin$' | paste -sd: -)" + fi + echo "==> Creating Python virtual environment '${VENV_NAME}' using ${PYTHON_SPEC} in ${VENV_PATH}..." mkdir -p "{{ VENV_DIR }}" - uv venv --seed --python "${PYTHON_SPEC}" "${VENV_PATH}" + PATH="${CREATE_PATH}" uv venv --seed --python "${PYTHON_SPEC}" "${VENV_PATH}" echo "==> Successfully created venv '${VENV_NAME}'." else echo "==> Python virtual environment '${VENV_NAME}' already exists in ${VENV_PATH}."