Skip to content

Make two address-space tests able to fail (#213) - #574

Merged
kgdunn merged 2 commits into
mainfrom
claude/audit-todo-fixme-items-gy9vj6
Sep 13, 2026
Merged

kgdunn merged 2 commits into
mainfrom
claude/audit-todo-fixme-items-gy9vj6

Conversation

@kgdunn

@kgdunn kgdunn commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Summary

Tests only, no source change. A sweep of all 2922 test functions for bodies that check nothing turned up two real cases, both in tests/test_tool_safety.py, and both where the test name promises a postcondition the body never asserted.

The two tests

test_apply_memory_limit_is_safe_with_generous_cap and test_pool_initializer_warms_registry each called the function, restored the rlimit in a finally, and asserted nothing. They passed whether or not the function did anything at all.

Why the obvious fix does not work

The finally restore is a fiction. RLIMIT_AS starts at infinity in this environment; lowering it is permitted and raising it back is not:

RLIMIT_AS at start: (-1, -1)
set to 1TB: ok -> (1099511627776, 1099511627776)
RESTORE FAILED: ValueError not allowed to raise maximum limit

So setrlimit(original) raises, is suppressed, and the test runner stays capped for the rest of the session.

That also traps the obvious fix, and it trapped me. My first attempt probed whether the platform allows the change by setting the limit in the runner. It could not undo that, so by the time the assertion ran the cap was already in place and getrlimit() == expected was satisfied regardless of what the function under test did. I only caught it because the mutation check below still passed.

Both checks now run in a child process, which sheds the limit on exit. The platform probe runs in a child of its own, so a skip means the platform genuinely refuses rather than that an earlier probe already applied the cap.

One incidental trap worth recording, since it cost a cycle: interpolating a multi-line block into an indented f-string and calling textwrap.dedent does not work. Only the first line of the interpolated block picks up the surrounding indent, so dedent finds nothing in common to strip and the child dies with an IndentationError. The source is assembled by concatenation instead, with a comment saying why.

Verified by mutation

A test that cannot fail is not worth adding, so both were checked against a broken source:

Mutation test_apply_memory_limit... test_pool_initializer...
_apply_memory_limit replaced by return fails fails
discover_tools() removed from _pool_initializer passes fails

The second row is the separation wanted: the initializer test catches the discovery regression, the cap test correctly does not.

Source restored clean afterwards (git diff --stat on tool_safety.py empty).

What the sweep found, and what I left alone

31 of 2922 flagged. Only the two above are real:

Bucket Count Verdict
Helper-wrapped warning context 6 My detector's false positive. _no_specification_warning() does simplefilter("error", SpecificationWarning); a warning does fail them. The check was behind a helper, not inline.
Validators whose contract is "does not raise" 11 Correct as written. validate_input returns None by design.
json.dumps(...) with no assert 6 Real but weak: dumps raises on failure. Proves serialisability, not correctness.
Inline warnings context 6 Correct: the context turns warnings into errors.
Name promises a postcondition, body checks nothing 2 Fixed here.

I did not bolt assertions onto the other 29 for a metric's sake.

Test plan

  • tests/test_tool_safety.py -k "memory_limit or pool_initializer": 2 passed, and 2 failed / 1 failed under the two mutations above.
  • Full suite (running; will report).
  • ruff check ., ruff format --check . clean.

Checklist

  • Version bumped (PATCH: 1.93.0 to 1.93.1, tests only; CITATION.cff version and date in step in the same commit)
  • Tests updated
  • ruff check . passes
  • CHANGELOG.md updated

On #213 itself

Every item the issue lists is already done, across #562, #563 and #566: the PLS structural identities replaced test_pls_properties_todo, DModX is cross-checked against SIMCA-P, the TPLS plot and cross-validation tests carry 24 and 9 assertions, test_inconsistent_sizes asserts all three shapes, and the NaN items were split to #557 and #558 and fixed. There are zero live TODO/FIXME markers left in tests/. This PR is the extra sweep rather than the issue's own list; #213 is closable once it merges.

🤖 Generated with Claude Code

https://claude.ai/code/session_0123j56Hk6jRz9zy91Doc1og


Generated by Claude Code

A sweep of all 2922 test functions for bodies that check nothing turned up two
where the name promises a postcondition the body never asserted:
`_apply_memory_limit` applying its cap, and `_pool_initializer` warming the
registry. Each called the function and restored the rlimit in a `finally`,
nothing more, so both passed whether or not the function did anything.

The restore was a fiction as well. RLIMIT_AS starts at infinity here; lowering
it is permitted and raising it back is not, so `setrlimit(original)` raises
"not allowed to raise maximum limit", is suppressed, and leaves the test runner
capped for the rest of the session.

That also traps the obvious fix. Asserting the cap in the runner, after anything
has lowered it, is satisfied whether or not the function under test did the
lowering: my first attempt probed by setting the limit itself, could not undo it,
and so asserted nothing. Both checks now run in a child process, which sheds the
limit on exit, and the platform probe runs in a child of its own so a skip means
the platform genuinely refuses rather than that an earlier probe already applied
the cap.

Verified by mutation, since a test that cannot fail is not worth adding:

- `_apply_memory_limit` replaced by `return`: both tests fail.
- `_pool_initializer` with the `discover_tools()` call removed: the initializer
  test fails, the other still passes, which is the separation wanted.

Nothing else from the sweep is changed. Of the 31 flagged, six were my detector
failing to follow a helper context manager that turns SpecificationWarning into
an error, eleven are validators whose only contract is not raising, six assert
serialisability through `json.dumps` raising, and six use a warnings context that
does fail on a warning. Those read correctly as written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123j56Hk6jRz9zy91Doc1og
PATCH: tests only, no source change and no behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123j56Hk6jRz9zy91Doc1og
@codecov

codecov Bot commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kgdunn
kgdunn merged commit 02475da into main Sep 13, 2026
14 checks passed
@kgdunn
kgdunn deleted the claude/audit-todo-fixme-items-gy9vj6 branch September 13, 2026 07:41
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