Skip to content

Test hardening: property-based tests + mutation-score gaps closed - #8

Merged
zolizoli merged 1 commit into
mainfrom
test-hardening
Jun 29, 2026
Merged

Test hardening: property-based tests + mutation-score gaps closed#8
zolizoli merged 1 commit into
mainfrom
test-hardening

Conversation

@zolizoli

Copy link
Copy Markdown
Member

What this does

Challenges the test suite with property-based tests and a mutation pass.

Property-based tests (Hypothesis)

New tests/strategies.py holds shared strategies (trainable corpora, orthogonal matrices, embedding pairs, valid PPMI-kernel inputs). New properties target real contracts, not trivia:

  • SVDAlgebra save/load round-trip — a reloaded model has identical vocabulary and embeddings.
  • ProcrustesAligner.transform is an isometry — the orthogonal map preserves vector norms (the basis of distance-preserving alignment).
  • ProcrustesAligner save/load round-trip — rotation and anchor bookkeeping survive a pickle cycle.
  • PPMI non-negativityPPMIComputer output is non-negative for arbitrary valid count inputs (a hard precondition for NMF).

These complement the 5 existing property tests (distance symmetry, most_similar contract, learned-matrix orthogonality, topic distributions, CMS underestimate/merge).

Mutation testing (MUTATION_TESTING.md)

mutmut v3 was added as instructed but is incompatible with this src/-layout + editable-install + Cython setup (it runs from a mutants/ copy where chronowords.algebra isn't importable). Rather than commit broken config, the dep/config were removed and a guided mutation pass was run — the method the /mutation-testing skill actually prescribes.

  • Core-sample score: 5/9 → 8/9 (89%) after closing gaps.
  • Three new tests kill the worthwhile survivors:
    • CMS.query returns the row-wise minimum (min vs max was indistinguishable without forced collisions).
    • get_heavy_hitters threshold is strict (>, not >=).
    • find_common_words returns the intersection (fit-based tests missed this — fit silently skips non-shared words).
  • One survivor left intentionally (align_with >=/> — an unreachable float-equality boundary), documented.

Verification

  • uv run pytest — 55 passed
  • uv run pytest --doctest-modules src/chronowords — passed
  • uv run ty check src tests — clean
  • uv run ruff check . && uv run ruff format --check . — clean

Part of the docs/design/tests hardening effort. Do not merge — review queue only.

🤖 Generated with Claude Code

Property-based tests (new tests/strategies.py for shared strategies):
- SVDAlgebra.save_model/load_model round-trip preserves vocabulary + embeddings.
- ProcrustesAligner.transform is an isometry (orthogonal map preserves norms).
- ProcrustesAligner save/load round-trip preserves rotation and anchors.
- PPMIComputer output is non-negative for arbitrary valid count inputs.

Mutation testing (MUTATION_TESTING.md):
- mutmut v3 is incompatible with this src-layout/editable/Cython setup, so a
  guided mutation pass (the /mutation-testing skill's method) was used.
- Score on a 9-mutation core sample: 5/9 -> 8/9 (89%) after closing gaps.
- Added 3 targeted tests killing the worthwhile survivors:
  - CMS.query returns the row-wise minimum (min vs max was indistinguishable).
  - get_heavy_hitters threshold is strict (`>` not `>=`).
  - find_common_words returns the intersection (not union).
- One surviving mutation (align_with `>=`/`>`) left as documented brittle
  float-equality boundary.

All tests, ty, ruff, and doctests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zolizoli
zolizoli merged commit fc53a3d into main Jun 29, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant