From 285227e3081b0ad43d96fa6f7515b38aaa2eb678 Mon Sep 17 00:00:00 2001 From: Nelson Spence Date: Mon, 25 May 2026 17:20:34 -0500 Subject: [PATCH 1/4] ci: add a coverage job for the PyO3 binding's Rust layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The core coverage.yml job is scoped -p ordvec, so the binding's FFI guard layer (ordvec-python/src/lib.rs) had no coverage signal. coverage-python.yml fills the gap: cargo-llvm-cov instruments the cdylib via show-env's RUSTC_WRAPPER, maturin builds that instrumented extension into a venv, pytest drives it, and report -p ordvec-python aggregates the per-process profraw. Uploaded to Codecov under a python-binding flag (tracked apart from the core line); informational, no floor yet. Measured locally against the full pytest suite (incl. the binding red-team from #63) at 84.1% line / 70.0% function — the uncovered share is mostly unreachable FFI error arms (from_shape_vec map_err; checked_mul usize-overflow guards that can't fire on 64-bit). The job reports whatever the suite exercises, so the number rises once #63's red-team tests reach main. Signed-off-by: Nelson Spence --- .github/workflows/coverage-python.yml | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 .github/workflows/coverage-python.yml diff --git a/.github/workflows/coverage-python.yml b/.github/workflows/coverage-python.yml new file mode 100644 index 00000000..d8009588 --- /dev/null +++ b/.github/workflows/coverage-python.yml @@ -0,0 +1,81 @@ +name: coverage-python + +# Coverage of the PyO3 binding's *Rust* layer (ordvec-python/src/lib.rs) as +# exercised by the pytest suite — the half the core coverage.yml job (scoped +# -p ordvec) cannot see. cargo-llvm-cov instruments the cdylib via a +# RUSTC_WRAPPER (show-env); maturin builds that instrumented extension into a +# venv; pytest drives it (each test process emits .profraw); and +# "report -p ordvec-python" aggregates them. Uploaded to Codecov under the +# python-binding flag so the binding's number is tracked apart from the core +# line. Informational like the core coverage job: no floor yet (the FFI glue +# has guard branches unreachable on 64-bit, e.g. the usize-overflow arms), and +# fail_ci_if_error is false so a failed or absent upload never blocks a PR. +# The upload runs without credentials (supported for public repos). +on: + push: + branches: [main] + paths: + - "ordvec-python/**" + - "src/**" + - "Cargo.toml" + - "Cargo.lock" + - ".github/workflows/coverage-python.yml" + pull_request: + paths: + - "ordvec-python/**" + - "src/**" + - "Cargo.toml" + - "Cargo.lock" + - ".github/workflows/coverage-python.yml" + workflow_dispatch: + +concurrency: + group: coverage-python-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + coverage-python: + name: coverage (binding, cargo-llvm-cov + pytest) + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.13" + - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable (2026-03-27) + with: + toolchain: stable + components: llvm-tools-preview + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - name: Install cargo-llvm-cov (pinned) + run: cargo install cargo-llvm-cov --version 0.8.7 --locked + # One shell: the cargo-llvm-cov env from show-env must stay live across the + # instrumented maturin build, the pytest run, and the report, so they share + # a single step. The venv isolates maturin's editable install. + - name: Build instrumented extension, run pytest, collect coverage + run: | + python -m venv .venv + . .venv/bin/activate + pip install --require-hashes -r ordvec-python/requirements-dev.txt + source <(cargo llvm-cov show-env --sh) + cargo llvm-cov clean --workspace + ( cd ordvec-python && maturin develop ) + python -m pytest ordvec-python/tests -q + cargo llvm-cov report -p ordvec-python --summary-only + cargo llvm-cov report -p ordvec-python --lcov --output-path binding-lcov.info + - name: Upload binding coverage to Codecov + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + with: + files: binding-lcov.info + flags: python-binding + fail_ci_if_error: false From 8f198600a5dd78f256a2be2ce001556c76575b9f Mon Sep 17 00:00:00 2001 From: Nelson Spence Date: Mon, 25 May 2026 17:47:07 -0500 Subject: [PATCH 2/4] ci: pin bash + surface show-env failures in the binding coverage job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address qodo round 1 on #64: the coverage step used bash-only process substitution (source <(...)) without pinning the shell, and a cargo llvm-cov show-env failure would not stop the step — risking pytest/report running uninstrumented and uploading misleading coverage. Pin shell: bash and write show-env to a file before sourcing, so a failure aborts the step under set -e. Verified locally: the file-sourced env sets RUSTC_WRAPPER / LLVM_PROFILE_FILE / CARGO_LLVM_COV; yaml parses. Signed-off-by: Nelson Spence --- .github/workflows/coverage-python.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage-python.yml b/.github/workflows/coverage-python.yml index d8009588..ddefa9c3 100644 --- a/.github/workflows/coverage-python.yml +++ b/.github/workflows/coverage-python.yml @@ -61,13 +61,18 @@ jobs: run: cargo install cargo-llvm-cov --version 0.8.7 --locked # One shell: the cargo-llvm-cov env from show-env must stay live across the # instrumented maturin build, the pytest run, and the report, so they share - # a single step. The venv isolates maturin's editable install. + # a single step. shell: bash is pinned explicitly (the step uses bash), and + # show-env is written to a file first so that a failure aborts the step + # under `set -e` instead of letting pytest/report run uninstrumented and + # upload misleading coverage. The venv isolates maturin's editable install. - name: Build instrumented extension, run pytest, collect coverage + shell: bash run: | python -m venv .venv . .venv/bin/activate pip install --require-hashes -r ordvec-python/requirements-dev.txt - source <(cargo llvm-cov show-env --sh) + cargo llvm-cov show-env --sh > "$RUNNER_TEMP/llvm-cov-env.sh" + source "$RUNNER_TEMP/llvm-cov-env.sh" cargo llvm-cov clean --workspace ( cd ordvec-python && maturin develop ) python -m pytest ordvec-python/tests -q From 3cb3660316b47a806d21d6a19cedba150711c38f Mon Sep 17 00:00:00 2001 From: Nelson Spence Date: Mon, 25 May 2026 18:14:42 -0500 Subject: [PATCH 3/4] ci: set -euo pipefail in the binding coverage step Round 2 (qodo) on #64: make the strict bash options explicit in the multi-command coverage step. shell: bash already runs -eo pipefail (so each command already fails the step), and this adds -u (error on unset vars) plus states the intent in the script. Verified python -m venv activate is set -u-safe on 3.13. Signed-off-by: Nelson Spence --- .github/workflows/coverage-python.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage-python.yml b/.github/workflows/coverage-python.yml index ddefa9c3..14926969 100644 --- a/.github/workflows/coverage-python.yml +++ b/.github/workflows/coverage-python.yml @@ -68,6 +68,7 @@ jobs: - name: Build instrumented extension, run pytest, collect coverage shell: bash run: | + set -euo pipefail python -m venv .venv . .venv/bin/activate pip install --require-hashes -r ordvec-python/requirements-dev.txt From b2035878f739e9cfaf8f2ed2290e352d1a17f041 Mon Sep 17 00:00:00 2001 From: Nelson Spence Date: Mon, 25 May 2026 18:59:16 -0500 Subject: [PATCH 4/4] ci: use python -m pip in the binding coverage step Round 3 (copilot) on #64: switch pip install to python -m pip install so the pip instance always matches the active venv interpreter, consistent with the repo's other workflows and robust to PATH/activation changes. Signed-off-by: Nelson Spence --- .github/workflows/coverage-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage-python.yml b/.github/workflows/coverage-python.yml index 14926969..19e0c0d9 100644 --- a/.github/workflows/coverage-python.yml +++ b/.github/workflows/coverage-python.yml @@ -71,7 +71,7 @@ jobs: set -euo pipefail python -m venv .venv . .venv/bin/activate - pip install --require-hashes -r ordvec-python/requirements-dev.txt + python -m pip install --require-hashes -r ordvec-python/requirements-dev.txt cargo llvm-cov show-env --sh > "$RUNNER_TEMP/llvm-cov-env.sh" source "$RUNNER_TEMP/llvm-cov-env.sh" cargo llvm-cov clean --workspace