Add ci-matrix.sh for running tests across the supported Python range

ci.sh exercises only whichever interpreter uv resolves for the local
environment — typically the newest Python installed on the dev
machine, which varies from one contributor to the next. Runtime bugs
specific to other versions in the supported range can slip through
silently. The import crash fixed in the parent commit is exactly
this class: a module-level subscripted annotation that raises
TypeError on 3.11/3.12/3.13 at import but is invisible on 3.14
thanks to PEP 649 deferred annotation evaluation.

ci-matrix.sh iterates over every interpreter version in the declared
`requires-python` range (currently 3.11 through 3.14) and runs an
import smoke check plus the full pytest suite against each. ruff,
mypy, pyright, and ty analyse code against a configured target rather
than executing it, so running them per interpreter would not add
coverage; ci.sh remains the canonical home for those checks.

Running the full pipeline per version is slow enough that it does not
belong in the default workflow, hence a sibling script rather than a
flag on ci.sh. Use it before releases and after changes that could
depend on version-specific runtime behaviour (import-time annotations,
stdlib APIs, syntax features).

Key points:
- Each version gets its own .venv-X.Y via UV_PROJECT_ENVIRONMENT, so
  successive runs are incremental and the default .venv is untouched.
- `uv python install $PYTHONS` is called up front so the script works
  even when UV_PYTHON_DOWNLOADS=manual is set globally.
- Failures are collected and reported at the end rather than bailing
  on the first broken interpreter, so a full matrix picture is shown
  in one run.
- Override the version list with PYTHONS="3.11 3.14" ./ci-matrix.sh.

Add `.venv-*` to .gitignore so per-version environments do not show
up in `git status`.

Assisted-by: claude-opus-4-7
Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
2 files changed