Coverage hardening: regression floor, experimental coverage, and adversarial red-team - #63
Conversation
The coverage job measured line coverage and uploaded to Codecov but enforced no threshold, so a regression could land silently. Add an 'Enforce coverage floor' step that reuses the lcov step's profdata (no re-run) and fails the job if line coverage drops below 85% — well under the current ~89%. A visible regression signal so coverage can't silently erode, supporting the OpenSSF silver statement-coverage criterion. Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
MultiBucketBitmap (the experimental bucket-overlap scaffold) had the weakest coverage of any module: 64.7% function, 85.5% line. top_m_bilinear, the candidate-generation primitive, was entirely untested; the bilinear_score weight==0 skip branch is unreachable from the outer-product-weights tests; and most accessors were unexercised. Add a tie-robust top-m correctness check (boundary property plus the m==0 and m>n clamps), a diagonal-weight matrix that exercises the zero-weight skip, and an accessor sweep before and after add. Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
Two adversarial suites authored as an offensive-security pass ahead of going public, pinning the FFI and loader boundary as regressions. tests/redteam_delta.rs (18 tests): malformed loader headers (incl. a huge declared n_vectors over an empty file — the ~137 GiB-implied DoS, rejected in microseconds before allocating), dim/n_vectors/version boundaries, all-0xFF files, the i64 Rank::search accumulator at dim=u16::MAX, search_asymmetric_subset candidate-list edges (empty, k==0, k>m, the duplicate-id gather contract, dup+out-of-range), empty-index search across all four types, and the documented byte-LUT b=1 fail-loud. ordvec-python/tests/test_redteam_fuzz.py (210 tests): negative and >=2**64 integer scalars (clean OverflowError, no wrap-to-usize OOM), huge-but-valid usize clamping, dtype confusion, signaling/quiet NaN bit patterns, non-contiguous arrays, on-disk loader corruption, the PyO3 borrow-flag reentrancy contract, and argument type confusion — abort-class probes are subprocess-isolated. Verdict: zero genuine bugs — every probe hit a clean typed error, an intentional fail-loud assert, or a correct result. No production source changed. Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
Review Summary by QodoCoverage hardening: regression floor, multi_bucket expansion, and adversarial red-team suites
WalkthroughsDescription• Add coverage regression floor (85% line coverage) to CI workflow • Expand multi_bucket test coverage to 100% line/function - top_m_bilinear correctness with tie-robust boundary checks - diagonal-weight matrix exercising zero-weight skip branch - accessor sweep before and after add • Add 18-test adversarial red-team suite for core loaders and search - Malformed headers, DoS allocation attempts, integer overflow at u16::MAX - search_asymmetric_subset edge cases and documented fail-loud contracts - Empty-index/empty-input search paths • Add 210-test Python FFI adversarial fuzz suite (Cipher) - Integer scalar abuse, dtype confusion, NaN bit patterns - Loader corruption and forged file handling - PyO3 borrow-flag reentrancy contract verification Diagramflowchart LR
A["CI Coverage Job"] -->|"Enforce floor"| B["85% Line Coverage Gate"]
C["multi_bucket Tests"] -->|"100% coverage"| D["top_m_bilinear + Accessors"]
E["Core Red-Team Suite"] -->|"18 tests"| F["Loaders + Search Boundaries"]
G["Python FFI Red-Team"] -->|"210 tests"| H["Integer/dtype/NaN/Reentrancy Guards"]
B --> I["Regression Prevention"]
D --> I
F --> I
H --> I
File Changes1. .github/workflows/coverage.yml
|
Code Review by Qodo
1.
|
There was a problem hiding this comment.
Code Review
This pull request introduces comprehensive adversarial and red-team fuzzing tests to harden the ordvec FFI boundary and Rust core API. It adds a Python fuzzing suite (test_redteam_fuzz.py) targeting integer overflow, NaN handling, type confusion, and loader corruption, alongside Rust-native integration tests (multi_bucket.rs and redteam_delta.rs) verifying boundary constraints. The review feedback highlights critical cross-platform compatibility issues on 32-bit architectures where hardcoded 64-bit integer values cause unexpected OverflowError exceptions, and suggests robust resource cleanup strategies using context managers and drop guards to prevent temporary file leaks during test execution.
There was a problem hiding this comment.
Pull request overview
This PR hardens the project’s quality gates and boundary robustness ahead of publication by enforcing a CI coverage regression floor and adding adversarial “red-team” test suites for both the Rust core and the Python bindings (plus expanded experimental MultiBucketBitmap coverage).
Changes:
- Add a CI coverage floor check to prevent silent coverage regressions.
- Add targeted integration tests to bring
MultiBucketBitmap’s candidate-generation and bilinear scoring paths to full coverage. - Add adversarial red-team suites: a Rust loader/overflow/subset/search-edge suite and a Python FFI-boundary fuzz suite covering dtype/shape/int-scalar abuse and loader corruption.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
.github/workflows/coverage.yml |
Adds an “Enforce coverage floor” step after generating lcov coverage. |
tests/index/multi_bucket.rs |
Adds correctness + branch-coverage tests for top_m_bilinear, diagonal weights, and accessors. |
tests/redteam_delta.rs |
Introduces a new Rust red-team regression suite targeting loaders, overflow boundaries, subset edge cases, and fail-loud contracts. |
ordvec-python/tests/test_redteam_fuzz.py |
Introduces a large Python red-team suite probing the PyO3/numpy boundary and loader corruption behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…eanup copilot/gemini round 1 on #63: test_redteam_fuzz.py: gate the huge usize test values (2**40/2**62/2**63) and the batched-m sweeps on sys.maxsize, so on a 32-bit target they use values that fit usize (exercising the core clamp) rather than raising OverflowError at the PyO3 conversion; wrap the forged-dim isolated probe's scratch dir in tempfile.TemporaryDirectory so it self-cleans. redteam_delta.rs: forge() returns a self-deleting TempFile RAII guard so a panicking test can't leak its temp file; clarify the 'ids 0..=3' comment. The copilot note on the coverage-floor step is a non-issue (cargo llvm-cov report reuses the lcov step's profdata, no rerun). Gate: fmt + clippy -D warnings clean; redteam_delta 18 pass; pytest 210 pass. Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
/gemini review |
|
/review |
PR Reviewer Guide 🔍Warning
Here are some key observations to aid the review process:
|
There was a problem hiding this comment.
Code Review
This pull request introduces extensive red-team and adversarial fuzzing test suites in both Python and Rust to harden the FFI boundaries, input guards, file loaders, and edge cases. Feedback on these additions suggests using tmp_path instead of a hardcoded root-level path in Python tests, utilizing std::fs::write for more idiomatic Rust file writing, and dynamically bounding a loop in multi_bucket.rs to prevent potential out-of-bounds panics if the corpus size changes.
Round 2 (gemini) on #63: write the nonexistent-directory probe under the tmp_path fixture instead of a hardcoded root-level path (portable across OS/containers); forge() uses the idiomatic std::fs::write (dropping the now-unused std::io::Write import); and the diagonal-weights loop is bounded by std::cmp::min(8, N) so it cannot panic if N shrinks. Gate: fmt + clippy -D warnings clean; multi_bucket 6, redteam_delta 18, pytest 210 pass. Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
…, assertion clarity) qodo's findings were in review comments (the gemini/copilot inline threads were resolved earlier): coverage.yml folds the regression floor into the single --all-features cargo llvm-cov run, dropping the separate report step, so the floor is computed on exactly the uploaded data (report rejects --all-features, which is why the two-step form appeared to differ in selection). redteam_delta.rs: the DELTA-A1 DoS-rejection wall-clock bound goes 2s to 30s (a generous regression guard, not a perf assertion) so it cannot flake on loaded CI runners; and delta_c3's candidate-membership assertion is split into a separate i64 sentinel check (g >= 0) and a u32 membership check, for type-consistency. test_redteam_fuzz.py: lower the subprocess abort-probe timeout 120s to 30s (the probes complete well under a second). Gate: fmt + clippy -D warnings clean; redteam_delta 18, pytest 210 pass; combined coverage+floor command verified locally. Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
|
Cleared the qodo review findings in d1a4826:
Gate green locally: clippy -D warnings, redteam_delta 18, pytest 210. |
Summary
Follow-up to the test-coverage push. Investigating the Codecov badge (showing 80%) revealed it was stale — actual line coverage on
mainis 89.1% (verified three ways; the lcov CI uploads computes to 89.10%), already past the OpenSSF silvertest_statement_coverage80bar. So this is less "reach 80%" and more lock it in, close the weak spots, and harden the boundary ahead of going public.Three parts:
ci: coverage regression floor. The coverage job uploaded to Codecov but enforced no threshold, so a regression could land silently. Adds anEnforce coverage floorstep (cargo llvm-cov report --fail-under-lines 85, reusing the lcov step's profdata — no re-run) so line coverage can't erode below 85%.test: experimentalmulti_bucketcoverage.MultiBucketBitmapwas the weakest module (64.7% fn / 85.5% line);top_m_bilinear, the candidate-generation primitive, was entirely untested. Adds a tie-robust top-m correctness test (boundary property +m==0/m>nclamps), a diagonal-weight test that exercises theweight==0skip branch, and an accessor sweep → 100% line / 100% function.test: Cipher adversarial red-team suites. Two "throw garbage at it" offensive-security passes (run on Opus), pinning the FFI/loader boundary as regressions ahead of the public flip:tests/redteam_delta.rs— 18 tests (core: malformed loader headers, integer overflow atdim=u16::MAX,search_asymmetric_subsetcandidate-list edges, empty-index search, documented fail-louds).ordvec-python/tests/test_redteam_fuzz.py— 210 tests (bindings: negative/>=2**64int scalars, dtype confusion, signaling/quiet NaN patterns, non-contiguous arrays, loader corruption, PyO3 borrow-flag reentrancy; abort-class probes subprocess-isolated).Verdict: zero genuine bugs. Every one of ~240 adversarial probes hit a clean typed error, an intentional fail-loud assert, or a correct result. Notable confirmations: the ~137 GiB-implied loader DoS is rejected in microseconds before allocating; negative /
>=2**64Python ints raiseOverflowError(no wrap-to-usize OOM); the duplicate-candidate gather contract is pinned.Coverage impact (core crate,
--all-features)multi_bucket.rs85.5%→100% line;rank.rs92.8%→95.2%;quant.rs83.4%→86.4%;bitmap.rs89.6%→91.0%. (fastscan.rs81.5% unchanged —#[doc(hidden)]optional path, not targeted;sign_bitmap.rs~84% is capped by the AVX-512 kernels the hosted coverage runner can't exercise without SDE.)Notes / follow-ups (not in this PR)
test_statement_coverage80is substantively met (90.9% ≫ 80%) and now floored — it can be marked met on bestpractices.dev (project 12977) with the Codecov dashboard as the justification URL. (Your call — it's your account.)pubrank_norm/rankquant_normprimitives accept degenerated ∈ {0,1}(returning0/-0) rather than rejecting — no crash, just an asymmetry with the fail-loudrank_to_bucket. Unreachable from the index API (constructors and loaders rejectdim < 2). Candidate for a small follow-up issue alongside consistency: rank_to_bucket clamps rank >= d instead of rejecting (mirror #26 bucket_centre fail-loud) #28.Test plan
cargo fmt --all --checkcargo clippy --all-targets --all-features -- -D warnings(clean)cargo test+cargo test --features experimental(all green)cargo test --no-default-featurespython -m pytest ordvec-python/tests— 365 passed (155 existing + 210 new), debug + release builds--fail-under-lines 85) verified exit 0