fix(derivations): evaluate() returns the no-spread result for every bin method on a constant column - #120
Merged
Merged
Conversation
…in method on a constant column ## Summary - **What:** the no-spread guard in _evaluate_bin now also treats non-strictly-increasing edges as degenerate. - **Why:** equal_width and sd on a constant column fitted identical finite edges, passed the guard, and pd.cut raised "Bin edges must be unique". evaluate() promises never to raise on a routine state. Found via the app on a T=1 file with a constant TIME column. - **Scope:** derivations.py guard + fitted shape; tests; CHANGELOG. ## Contract / Invariants (must remain true) - Non-degenerate fits unchanged: edges, labels, nextafter top-edge widening untouched. - breaks on any column unchanged (user cut points are strictly increasing). - No chart math; validation/e2e_bishop_report.py exit 0, 280/280. ## Behavior Changes (explicit) - evaluate() returns instead of raising for equal_width / sd on a constant column. - The no-spread fitted dict gains n_bins: 0, edges: [], labels: []. ## Tests - test_constant_column_is_no_spread_for_every_method (parametrized over the three methods) - test_constant_column_with_explicit_breaks_still_bins - test_constant_column_validates_without_raising ## Manual Verification - pytest tests/: 2340 passed, 10 skipped - ruff check: clean; mypy processbehavior/derivations.py: clean - validation/e2e_bishop_report.py: exit 0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_evaluate_binnow also treats non-strictly-increasing fitted edges as degenerate, so all three automatic bin methods return the documented no-spread result on a constant column.equal_freqalready returned it (np.unique collapses the quantiles to one edge).equal_widthfitted identical finite edges andsdfitted a zero-sigma edge set; both passed the guard andpd.cutraisedValueError: Bin edges must be unique. The module docstring promisesevaluatenever raises on a routine state, and a constant column is one. Found through the app on a single-time-point file whose TIME column was all 1.derivations.py, the no-spreadfitteddict shape, three tests, CHANGELOG.Contract / invariants
nextaftertop-edge widening are untouched.validation/e2e_bishop_report.pyexits 0.fitteddict gainsn_bins: 0,edges: [],labels: [](additive;validate()readsn_binswith.get).'column has no spread; cannot bin'is unchanged.Behaviour changes
evaluate()returns instead of raising forequal_width/sdon a constant column.fitteddict carries a consistent shape. Explicitbreakson a constant column still bin (user cut points are strictly increasing; everything lands in one interval), covered by a test.Methodology
Tests
test_constant_column_is_no_spread_for_every_method(parametrized overequal_freq,equal_width,sd) — no raise, no-spread message, zero fitted bins, all-NA categorical with no categories.test_constant_column_with_explicit_breaks_still_bins— breaks are unaffected.test_constant_column_validates_without_raising—validate()callsevaluate()internally and must survive too.pytest tests/— 2340 passed, 10 skippedruff check .— cleanmypy processbehavior/derivations.py— cleanGolden masters untouched
Notes
The companion app fix (the preview panel must not take the page down on empty counts) is separate and works against the 0.2.0 pin; this change makes the library side honest regardless of caller.
🤖 Generated with Claude Code
https://claude.ai/code/session_01BKphCi1LC1hjGYteWEK9JV