Skip to content

Document the grouped test layout and add public-API doctests - #74

Merged
tschm merged 1 commit into
mainfrom
quality/test-layout-doctests
Aug 1, 2026
Merged

Document the grouped test layout and add public-API doctests#74
tschm merged 1 commit into
mainfrom
quality/test-layout-doctests

Conversation

@tschm

@tschm tschm commented Aug 1, 2026

Copy link
Copy Markdown
Member

Addresses #72 and #73 from a /rhiza:quality run. Docstrings and one config table — no
source behaviour changes.

#72 — document the grouped test layout

Adds a [tool.check_test_layout] table recording the grouped layout as an accepted
deviation from Rhiza's 1:1 mirroring. CLAUDE.md already documents this as by-design; this
makes the decision machine-readable, so scripts/check_test_layout.py reports it as
intentional instead of as 18 missing/orphan files:

Before: Test-layout check failed:
          ✗ missing test file tests/nncg/test__active_set.py for src/nncg/_active_set.py
          ... 9 missing, 5 orphan under tests/test_nncg/, 4 orphan under tests/test_paper/

After:  Test layout OK: parity not enforced by request — Tests are grouped by concern …

The opt-out is the right call here rather than renaming tests/test_nncgtests/nncg:
that would fix only 14 of the 18 lines, because tests/test_paper/ is organised by paper
claim
(Chebyshev energy-norm bound, conditioning of the regularising split, the
saddle-point reduction, the results table) and has no source counterpart by design.

The reason string deliberately avoids a literal % — tools that read [tool.*] tables
through configparser treat it as interpolation syntax and crash. radon does exactly
that, and it currently crashes in a sibling repo for this reason. Verified uvx radon cc src
still runs from the repo root here.

#73 — doctest examples on the public API

Docstring coverage was already 100%, but no docstring carried a runnable example, so the
template's doctest gate skipped itself:

Before: .rhiza/tests/test_docstrings.py s
        SKIPPED [1] No doctests were found in any module
After:  .rhiza/tests/test_docstrings.py .

A skipped gate is a gate that cannot fail — nothing was catching the documented examples
drifting from the real signatures. Examples added to all four public entry points:

  • solve_nnqp — the bound binding where the unconstrained minimiser goes negative
  • solve_nnqp_eq — the p = 1 normalisation, i.e. the minimum-norm point on the simplex
  • solve_nnqp_mprgp — the same program reached by projection, same unique minimiser
  • kkt_violation — certifies at zero for the optimum, positive at the origin, and notes
    that a bare array raises TypeError

They use .round(6).tolist() rather than round() on numpy scalars, whose repr leaks
np.float64(...) and shifts between numpy versions. All values were verified by running
them before being written into the docstrings.

A note on #71

#71 needs no work here — it was already resolved on main. That issue reported the
template pinned to v1.2.1, four releases behind, with a latent License-classifier conflict.
main is in fact already on v1.2.5 with the classifier removed and license = "MIT" in
place.

The stale v1.2.1 pin existed only on the MPRGP branch the assessment happened to be run
against — the original report disclosed the branch but did not check main. #71 should be
closed as already-done rather than actioned.

Verification

All eight gates pass on this branch:

Gate Result
make fmt PASS (exit 0, no failed hooks)
make typecheck PASS — 10 files, ty + mypy --strict
make docs-coverage PASS — 100.0% (min 100.0%)
make deptry PASS
make security PASS
make rhiza-test PASS — 34/34, test_docstrings now runs rather than skipping
make test PASS — 137 passed, 100% coverage
test-layout PASS — reported as an intentional opt-out (was 18 violations)

Diff is 3 files, 62 insertions, 0 deletions.

🤖 Generated with Claude Code

Addresses #72 and #73 from a /rhiza:quality run.

Add a `[tool.check_test_layout]` table recording the grouped test layout
as an accepted deviation from Rhiza's 1:1 mirroring (#72). CLAUDE.md
already documented this as by-design; this makes it machine-readable, so
scripts/check_test_layout.py reports it as intentional rather than as 18
missing/orphan files. The `reason` string deliberately avoids a literal
`%`, which breaks tools that read [tool.*] tables through configparser
(radon crashes on exactly that in a sibling repo).

Add doctest examples to the four public entry points — solve_nnqp,
solve_nnqp_eq, solve_nnqp_mprgp and kkt_violation (#73). Docstring
coverage was already 100%, but no docstring carried a runnable example,
so the template's doctest gate skipped itself with "No doctests were
found in any module" — a gate that could not fail. It now executes.

Examples use `.round(6).tolist()` rather than `round()` on numpy scalars,
whose repr leaks `np.float64(...)` and varies by numpy version; values
were verified by running them before being written in.

Docstrings only — no source behaviour changes. All eight gates pass: fmt,
typecheck (ty + mypy --strict), docs-coverage 100%, deptry, security,
rhiza-test 34/34, test 137 passed at 100% coverage, and the test-layout
check.

Note on #71 (the template sync): already resolved on main, which is
pinned to v1.2.5 with the License classifier removed. The v1.2.1 pin the
assessment reported existed only on the stale MPRGP branch it was run
against, so nothing is needed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 19:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves project quality tooling and user-facing documentation by (1) recording the intentional “grouped-by-concern” test layout in pyproject.toml and (2) adding runnable doctest examples to the public API so the docstring-doctest gate executes instead of skipping.

Changes:

  • Add a [tool.check_test_layout] configuration table documenting the intentional opt-out from 1:1 test mirroring.
  • Add doctest Examples: blocks to the main public entry points in src/nncg/api.py.
  • Add a doctest example for kkt_violation in src/nncg/certificate.py.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
pyproject.toml Adds a machine-readable test-layout opt-out via [tool.check_test_layout].
src/nncg/api.py Adds runnable doctest examples to public convenience wrappers (solve_nnqp, solve_nnqp_eq, solve_nnqp_mprgp).
src/nncg/certificate.py Adds a doctest example for the KKT-violation certificate.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pyproject.toml
Comment on lines +61 to +64
# Accepted deviation from Rhiza's 1:1 mirroring — see the "Test layout" section
# of CLAUDE.md for the full rationale. This table makes that decision
# machine-readable so scripts/check_test_layout.py reports it as intentional
# instead of as 18 missing/orphan files.
Comment thread src/nncg/certificate.py
Comment on lines +52 to +58
Examples:
Note that ``a`` must be an operator — a bare array raises ``TypeError``:

>>> import numpy as np
>>> from cvx.linalg import DenseOperator
>>> a = DenseOperator(np.array([[2.0, 0.0], [0.0, 2.0]]))
>>> b = np.array([2.0, -2.0])
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.

2 participants