Changelog#
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased#
Changed#
The suite on the installed cp314t wheel runs through the hub’s step (2026-10-12).
scripts/linux/ci_packaging.shcalls the hub’stest-free-threaded-wheel.sh(hub 9ade0dd1, CON66) with--extra tests --copy tests --copy pytest.ini --env KATAGLYPHIS_EXPECT_COMPILED=1, in place of the localscripts/linux/test-free-threaded-wheel.sh, which is gone. The lock’s set now comes fromuv export --lockedrather than--frozen. A local run of the wrapper in:latestproved 3 compiled modules and passed all 24 tests.
Added#
The whole suite runs against the installed cp314t wheel on both Linux rows (2026-10-11). The 3.14t test leg tested the uncompiled sources, and the hub’s proof only creates each compiled module without running it.
scripts/linux/ci_packaging.shnow runsscripts/linux/test-free-threaded-wheel.shafter the hub driver. It installs the lockedtestsextra and thecp314twheel into a fresh 3.14t venv, and runs pytest from a copy oftests/that has no package directory beside it.tests/unit/test_free_threading.pyfails when importing the package re-enables the GIL, and, underKATAGLYPHIS_EXPECT_COMPILED=1, when a module is not the compiled one.tests/test_webdav_client.pyadds eight threads that share one client and one destination. Locally in:latest: 22 passed on the wheel. Both negative controls fail: a wheel built withoutfreethreading_compatiblegivesassert True is Falseand the hub’s proof exits 1, and a run from the checkout imports the sources.A
packagingextra with auditwheel (2026-10-07). The hub’s Linux packaging repairs the Cython wheels to manylinux with the packaging venv’s auditwheel once the hub pin carries c0ad775a; PATH never had one, so the Linux binaries shipped aslinux_<arch>.A proved free-threaded wheel beside the GIL one (2026-10-07).
pyproject.tomldropsProgramming Language :: Python :: 3.14t, which is no trove classifier (PyPI refuses an upload that names it), for the officialProgramming Language :: Python :: Free Threading :: 2 - Beta: Beta, because the 3.14t test legs gate. The hub’s packaging drivers read that classifier: once the hub pin carries them, they build a second Cython wheel on the image’s 3.14t (cp314-cp314t) and load its compiled modules in a fresh 3.14t venv, failing when the GIL comes back on.setup.pytherefore sets Cython’sfreethreading_compatible=True(cython>=3.1, the first with the directive); without it the proof fails, as a local negative control showed. Proved locally with the hub’s new drivers in:latestand:winamd64: both lanes shipkataglyphis_webdavclient-0.0.1-cp314-cp314t-{linux_x86_64,win_amd64}.whl, its 3 compiled modules keep the GIL off, and the 18 tests pass on 3.14t against the installed wheel withsys._is_gil_enabled()still False.A Windows arm64 test lane (
.github/workflows/windows-arm64.yml, “Windows arm64 · test”, 2026-10-01). It is the hub’s runner-nativewindows-11-armjob (arm64-tests, hub 625b3653): no container and no build, just the whole pytest suite on the 3.14 and 3.14t legs. It uses arm64 CPython from uv, pinned and SHA-checked by the hub. The lock resolves fromwin_arm64wheels alone since py-spy and line_profiler stay off ARM64. ANTfrastructure moves from 8a45c75a to 625b3653.scripts/linux/run-lint-gates.shand.github/workflows/lint-gates.yml: the family lint lane. Seven gates over the tracked tree — shell lint, workflow lint plus the CI image-ref check, secret scan,ruff, the shared-config drift check, the consumer pin-forwarding check and the ratchets — all owned by ANTfrastructure’slinux/scripts/run-lint-gates.sh. Before this the repo had no shell, workflow or secret linting at all.comment-size.allow,function-size.allow,code-complexity.allow: the ratchet freeze files. The wrapper passes--ratchetsitself, so the seventh gate is not optional here: it runs the doc-link gate and eight measurement gates over this tree. Five measured clean and get no file at all. Every row in the three that exist carries a reason and is a queue entry, not an exemption — the contract fails on growth, on a new offender, on an unrecorded shrink AND on a stale row..antfrastructure-shared.manifest: declares the two upstream files this repo holds a copy of (antfrastructure-sh,resolve-build-module) so the shared-config gate compares them instead of trusting the word “verbatim” in a header..gitignorehad to un-ignore it — the PyInstaller*.manifestrule is unanchored..github/actionlint.yaml: teaches the pinned actionlint theubuntu-26.04runner labels it predates.
Changed#
uv.lockmaintenance: every locked package at its newest release (2026-10-07). The owner’s “bleeding edge” rule covers the lock too, and no Renovate manager reported this drift because the hub’s shared preset had nolockFileMaintenance.uv lock --upgrademoved 41 packages; the majors are chardet 6, filelock 4, more-itertools 11 and rich 15, all transitive, and pytest-benchmark 5.3 swaps py-cpuinfo for py-cpuinfo2. ty goes 0.0.23 -> 0.0.85, numpy 2.4.3 -> 2.5.3 (cp314t wheels on PyPI), cython 3.3.0. ruff stays at the hub’s 0.16.10. No code change was needed: in:latest,ci_static_analysis.shpasses its 6 gates (ty 0.0.85 included),ci_tests.shpasses 18 tests on 3.14 and on 3.14t (bcrypt 5.0.0 and numpy 2.5.3 from free-threaded wheels), andrun-lint-gates.shpasses 7/7.Windows packaging is the hub’s
Invoke-CiPackaging.ps1on 3.14 (2026-10-07).scripts/windows/Build-Windows.ps1built in a 3.13 venv with a bareuv build, which ignores the venv and takes whatever interpreter uv finds, a free-threaded one included. The driver asks for3.14+gil, as the Linux lane does, and adds the free-threaded wheel above.Comments are one line, only the why (2026-09-30). The family rule, in the hub’s
AGENTS.mdand linked fromAGENTS.md: 27 files lose their comment blocks, and code is unchanged. ANTfrastructure moves from539ee280to9e9d9828for the gate that grades every language and the bootstrap templates the two local copies follow. Itsversions.envpins ruff at 0.16.8, sopyproject.toml,.pre-commit-config.yamlanduv.lockfollow (0.16.7 and 0.16.8 report the same findings here).The Linux lane runs on 3.14 again, and atheris is 3.1.0. The 3.13 pin of 2026-09-15 (below, under Fixed) existed because atheris 3.0.0 shipped no cp314 wheel. atheris 3.1.0 ships cp312, cp313 and cp314 wheels, so
uv.lockmoves to it and the lane’s tests, static analysis, docs and packaging run on 3.14, the image’s interpreter; 3.14t stays experimental. The marker gainspython_version >= '3.12', because 3.1.0 has no sdist and no cp310/cp311 wheel. A source build is still no way out: atheris’find_libfuzzer.shlooks forlib/linux/libclang_rt.fuzzer_no_main-x86_64.a, which the family image’s per-target compiler-rt layout does not provide, and 3.0.0 refuses to import on 3.14 even once built withLIBFUZZER_LIB(measured 2026-09-29).The Linux wrappers no longer unset
VIRTUAL_ENV/UV_PYTHON. The family image stopped exporting both with hub CON18 (:latestof 2026-09-29), soci_tests.shandci_static_analysis.shdropped the lines described under Fixed below;UV_PROJECT_ENVIRONMENTin the latter stays, because the driver still never activates the venv it creates.2026-09-25: one workflow per platform + arch, and every lane a thin caller.
ubuntu-26.04-amd64-arm64.ymlis split intolinux-x64.yml(“Linux x64 · buildtest”) and
linux-arm64.yml(“Linux arm64 · build + test”), both calling ANTfrastructure’spython-ci-linux.ymlwitharches: x64/arches: arm64. The docs deploy stays on the x64 row, so only that file passes the FTP secrets.lint-gates.ymlnow calls the hub’s reusable lint lane withratchets: true, which runs whatscripts/linux/run-lint-gates.shruns locally; its header had asked for exactly this switch the day that lane existed. The README badges follow the new files.
2026-09-25: ANTfrastructure’s reusable workflows and composite actions are called at
@develop, no longer@mainas the older entry below says. Since 2026-09-16 every lane also runs on pushes and pull requests todevelop, not onlymain. The hub pin is539ee280(2026-09-16), which is on the hub’smain, as is the19286e9fthe NOTE below warns about.2026-09-24: the workflows follow the family naming convention (owner decision).
windows-2025.ymliswindows-x64.yml(“Windows x64 · build + test”) and the lint lane’s display name is plainLint gates, as in every other repo. Triggers, jobs and job ids are unchanged; the README badges follow the new file.ubuntu-26.04-amd64-arm64.ymlkeeps its name for now: its split intolinux-x64.ymlandlinux-arm64.ymlneeds a hub reusable-lane input that is not on hubmainyet.The hub pin moved to ANTfrastructure
19286e9f(from the published4f6f516a). The published hub still listed WebDavClient underunconfirmedin its.github/consumers.json, and the workflow-conventions gate refuses a tree it cannot key its allow rows to, so that gate could not pass at the old pin at all. NOTE:19286e9fis NOT PUSHED anywhere yet — do not push this repo before ANTfrastructure is, or the gitlink resolves to nothing.scripts/linux/lib/antfrastructure.shre-synced against the new pin (hub commite03bbe42rewrote the template).ANTFRASTRUCTURE_DIRnow resolves in a documented order — explicit env, then the submodule, then anantfrastructure-toolssibling clone — and the not-found error picks its hint from whether.gitmodulesactually declares the submodule.The two reusable-lane callers declare
permissions: contents: read, which is whatpython-ci-linux.ymlandpython-ci-windows.ymldeclare themselves; a called workflow runs on the caller’s token, and the only registry credential in either lane issecrets.GHCR_PAT. Without it GITHUB_TOKEN fell through to the repository default.*.allowjoins theeol=lfrules in.gitattributes: those files are read only by the hub’s Python gates, which run in the Linux container.The hub submodule moved from
ExternalLib/Kataglyphis-ContainerHubtothird_party/ANTfrastructure, matching every other consumer, and.gitmodulesnow points athttps://github.com/Kataglyphis/ANTfrastructure.git. The upstream repository was renamed from Kataglyphis-ContainerHub to ANTfrastructure; every reference in this repo followed, including thecontainerhub_*bootstrap entry points (nowantfrastructure_*),scripts/linux/lib/containerhub.sh(nowlib/antfrastructure.sh), and this repo’s own name, which dropped itsKataglyphis-prefix.The two reusable-workflow lanes now call
Kataglyphis/ANTfrastructure/.github/workflows/python-ci-{linux,windows}.yml@main. The Linux lane’s file was renamedubuntu-24.04-amd64-arm64.yml->ubuntu-26.04-amd64-arm64.yml: the reusable lane pinsubuntu-26.04andubuntu-26.04-arm, so the old file name had been wrong since adoption.scripts/windows/Resolve-BuildModule.ps1re-synced from the upstream template. The local copy had fallen 16 body lines behind: the.ps1arm ofResolve-BuildModule(which is what makesInitialize-CiEnvironment.ps1reachable) and the dot-source guard inImport-BuildModulewere both missing.ruffis pinned to0.16.7inpyproject.tomland.pre-commit-config.yaml, forwarded from ANTfrastructure’sversions.envand checked by the consumer-pins gate. The three numbers had drifted apart — the lockfile carried 0.15.6 while pre-commit asked for 0.13.2..github/github_copilot_instructions.mdrenamed to.github/copilot-instructions.md, the path GitHub Copilot actually reads.
Deprecated#
Placeholder for soon-to-be removed features.
Removed#
Placeholder for now removed features.
Fixed#
Every compiled module builds with clang-cl on Windows; the first one used MSVC’s
cluntil now (2026-10-12).ClangBuildExtset the compiler’scctoclang-clbefore the firstcompile(), which then raninitialize()and putcl.exeback, sokataglyphis_webdavclient/dummy.ccompiled and linked with MSVC’s tools in every Windows build (run 38214955666).build_extensionnow initializes the compiler first. Thespawnhook meant to catch this is gone: setuptools 84 never calls it.One loguru file sink per log file, not one per client (2026-10-11). Every
WebDavClient()calledlogger.add("logs/downloadMd_s.log"). Eight clients built on eight threads wrote each line eight times and rotated the file eight times (measured on 3.14t). The sinks are now a lock-guarded module set keyed by absolute path. That is the only mutable module state the thread-safety audit found, andfreethreading_compatible=Truerests on it.Downloads are renamed into place (2026-10-11). Each file streams into a private
.<name>.<uuid>.partbeside it, then replaces the target. Threads that share a destination no longer truncate each other’s file, and the response is closed on every status. Windows denies a replace while another thread replaces the same target, and the first CI run failed withPermissionErroron windows-11-arm (run 38142999677). There the replace retries for up to about 4 s; elsewhere the error is final.Wheels ship only the package (2026-10-11).
[tool.setuptools.packages.find]had noinclude, so namespace discovery packedthird_party/,scripts/andimages/, 218 packages, into every wheel. The pure wheel drops from 363 KB to 12 KB.cythonize(force=True)(2026-10-11). An in-tree.cleft by an earlier build was reused as is, so a changed compiler directive did not reach the next wheel.CI tests the WebDAV client again (2026-10-01).
Every lane now runs the whole configured suite: all 10 tests, including the 6
test_webdav_client.pytests against the mock server and the integration test.Since 2025-10-20 all lanes had run
tests/unitonly (3 dummy tests). Before that, the single Linux x64 lane ran all oftests/.The free-threaded 3.14t leg now really tests: it syncs only the tests extra and gates. Before, it synced nothing and passed on a warning.
Two dependency changes make that possible:
atheris is removed. Nothing used it, and it has no cp314t wheel.
bcrypt is overridden to >=5. wsgidav caps it below 5, and 4.x has no free-threaded wheel; the mock server runs without auth.
Windows gates on every leg instead of letting 3.14 and up fail.
py-spy and line_profiler leave the tests extra on Windows arm64 (
platform_machine != 'ARM64'). py-spy has no win_arm64 wheel, and line_profiler has none for 3.14t. No test imports either, so the lock now resolves from wheels alone there, for the arm64 test job that comes next.
tests/integration/test_dummy.pypatchednumpy.random.normalwhileSimpleMLPreprocessorcallsnp.random.default_rng().normal(...), so the fixture was never used and the label assertion was a fair coin on four rows — passing about one run in sixteen. It now patchesdefault_rng. Pre-existing: neither file had changed sinceorigin/main.Four references the doc-link gate resolves to nothing: two cross-repo pointers that named the hub’s
AGENTS.mdanddocs/adopting-in-a-new-project.mdas if they were this repo’s, and a relativeLICENSElink in the two WebDAV test fixtures that has never existed beside them.The Linux lane pinned 3.14, where this project cannot install.
testsdeclaresatheris, every lane syncs--all-extras, and atheris 3.0.0 ships cp311/cp312/cp313 wheels and nothing newer, so 3.14 falls back to an sdist whose build needs a Clang with libFuzzer and fails. That build did succeed in the family image on 2026-08-14 (run31823466662); it no longer does, on a runner or on a dev box with the same image. The lane’s test, static-analysis and packaging interpreters are 3.13 now — the newest every locked dependency of this project actually ships; 3.14t stays because the driver treats it as experimental and its sync failure only warns. Restore 3.14 when atheris ships a cp314 wheel, or give atheris a marker instead of the lane a pin.Neither half of the Linux lane’s gating ran, for one shared reason. Upstream’s
uv_runisuv run --activewith the image’sUV_PYTHON=/opt/venv/bin/pythonandVIRTUAL_ENV=/opt/venvstill in scope, while its siblinguv_sync_projectclears exactly those two for its own call and documents why. Static analysis: its driver never activates the venv it creates (uv_venv_ensureactivates only one that already existed), so all six gates hit root-owned/opt/venvand died withPermission deniedbefore running a check. Tests:uv_runfound the activated.venv-<ver>disagreeing withUV_PYTHON, deleted it, rebuilt it with the image’s interpreter and default groups — andpytestis in thetestsEXTRA, so the run died withFailed to spawn: `pytest`. The matrix only ever escaped that by testing the one interpreter the image happens to ship. The two wrappers now clear those variables (and static analysis namesUV_PROJECT_ENVIRONMENT, doing what theuv_venv_activateci_build_docs.shalready carries would do). Invisible until the pin reached604294e2: upstream ran those six behind|| trueuntil 2026-09-08.The two findings that surfaced once the analysers ran for real, fixed rather than ignored:
ruffCPY001 over twelve files (the MITLICENSE’s notice now heads each one), andvultureonmyst_heading_anchors, which was the one Sphinx setting missing fromconf.py’s own_SPHINX_EXPORTStuple.
Security#
The open Dependabot alerts in
uv.lockare fixed (2026-10-01), withuv lock --upgrade-packagefor exactly the affected packages:wsgidav 4.3.3 → 4.3.5, which adds bcrypt and passlib;
lxml 6.0.2 → 6.1.3;
urllib3 2.6.3 → 2.8.0;
soupsieve 2.8.3 → 2.10;
requests 2.32.5 → 2.34.2;
idna 3.11 → 3.20;
setuptools 82.0.1 → 84.0.0;
pygments 2.19.2 → 2.21.0;
virtualenv 21.2.0 → 21.14.2, which brings python-discovery 1.1.3 → 1.6.1. GitHub only raised this alert after rescanning the updated lock.
The five Dependabot PRs merged the same day (#22–#26) had already moved pytest past its advisory.
No version has been released yet: VERSION.txt reads 0.0.1, and the
repository carries no tags (2026-09-25).