chore(deps): raise Django floor to 6.1, refresh Cargo.lock
Summary
Routine dependency update, plus a support-floor decision that came out of it.
Django floor is now 6.1. 5.2 and 6.0 are dropped. The async extra moves to
django-async-backend >= 6.1.1 — the release whose SQLCompiler fork learned
compiler.quote_name and can therefore actually drive Django 6.1. Before it,
every async ORM query on 6.1 raised AttributeError.
Cargo.lock refreshed — 32 packages, latest semver-compatible (pyo3 0.29.2,
rustls 0.23.43, futures 0.3.34, aws-lc-rs 1.18.0, ...). No manifest floors moved:
deadpool stays 0.12 and fallible-iterator stays 0.2 because
deadpool-postgres and postgres-protocol require those majors, and bumping either
would put two copies of the same trait in the graph. Upstream tokio-postgres is
still 0.7.18, so the vendored buffer-cap patch is current.
CI. The async job's Django pin moves 6.0 → 6.1 rather than disappearing: it
can only ever run the minor django-async-backend's fork supports, and that
package's metadata (django>=6.1, unbounded) won't stop pip pairing it with a
Django it can't drive — unpinned, the next Django release would turn that job
red on every branch with no repo change. python-tests-no-async carries the
"newest Django still works" claim instead, and now runs a two-entry matrix
(latest + the declared floor) so both ends of django>=6.1 stay exercised.
The async job also gains a no-skip guard (scripts/ci_orm_no_skip.sh).
tests/test_orm_live.py self-skips when the environment can't support it —
right on a contributor's machine, and wrong in the one job whose purpose is
running the async ORM against real PostgreSQL, where it used to mean a green
pipeline that had quietly tested nothing. Each cause now fails loudly and names
itself.
uv for the publish job goes 0.11.32 → 0.12.3. Please sanity-check this one
— see the note at the bottom.
Testing
Live PostgreSQL 18 throughout (VPG_TEST_DSN), extension rebuilt with the new
lockfile:
- Django 6.1 + django-async-backend 6.1.1: 346 passed, 0 skipped — including
the 18 async ORM tests in
test_orm_live.pythat were skipping on 6.1 before. - Django 6.1, no async extra: 313 passed, 25 skipped; the sync-only degrade
contract (
AsyncDatabaseWrapper is None) still holds. scripts/check.shgreen: fmt,clippy -D warnings, vpg-core tests, the vendored buffer-cap tests, ruff.mkdocs build --strictclean.- Guard script exercised in all three paths against a live database: healthy run exits 0; a fork that can't drive Django and a missing DSN each exit 1 naming their own cause.
- The hardened version probe verified by simulating a future Django that deletes a symbol the fork imports at module scope — 7 passed / 18 skipped, instead of the collection error the previous version produced.
Performance sniff (AI-assisted, see disclosure)
A/B of the driver microbench (benchmarks/driver/ab.py, workloads
jsonb_read / fetch_models / batch, 1000 rounds, 2 reps per variant) built
from the old vs new lockfile on the same 12-thread box and the same PostgreSQL.
No regression. 23 of 24 (cell, metric) pairs land inside the run-to-run noise
floor. The one that doesn't — batch/vpg CPU, +10.7% against a 7.9% noise
floor — is environmental drift, not vpg: the batch/psycopg control cell, which
cannot be affected by a Rust dependency bump, moved +9.7% in the same direction
over the same window, and batch/vpg_query_many moved −1.3%. Headline ratios
intact (jsonb_read vpg 46 µs CPU/op vs psycopg 201 µs; fetch_models fused
150 µs vs 446 µs).
AI disclosure: Claude Code — dependency bump, CI/doc edits, changelog and this description drafted with AI; the benchmark A/B and a two-reviewer adversarial pass over the diff were designed and run by AI on my hardware. All test and pipeline results quoted above are real runs, not claimed. Reviewed by me before opening.
Reviewer, two things worth your judgement. (1) The uv bump crosses
0.12.0, where uv publish began silently skipping distributions with
non-normalized filenames — our artifacts are normalized and the sdist tag guard
enforces that shape, and there are no OIDC changes in the range, but the new
failure mode is a partial upload that exits 0, on the one job that burns a
version number. Reverting that single line is zero-cost if you'd rather not find
out during a release. (2) The floor bump is breaking for downstream pins:
glitchtip-backend carries django-vpg>=0.4.0,<0.5; if it is still on Django
6.0, the next vpg release becomes uninstallable there. The next tag also needs
to be ≥ 0.5.0, since published 0.4.0 declares django>=5.2.