Elbow-helper

Latest version: v0.1.7

Safety actively analyzes 1006753 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 1 of 2

0.1.7

Fixed
- **`candidates.generate_candidates`**: a failed `KneeLocator` construction at
a given (smoothing window, sensitivity) grid point was silently swallowed
(`except Exception: continue`) with no trace at all, unlike every other
numerical-safety-net catch in this codebase (`pipeline.py`,
`multi_pipeline.py`), which logs a warning and a diagnostic reason. A
degenerate combination failing occasionally is expected and not logged at
warning level, but a real regression breaking every grid point at once
would have looked identical to "no knee found" with zero diagnostic
signal. Now logged at debug level with the window/sensitivity pair and the
exception message.

0.1.6

Fixed
- **`elbow_helper.smoothing.smooth_curve`** (`method="moving_average"`): an
even smoothing window produced an asymmetric kernel, shifting the whole
smoothed curve by half a sample (found by testing: a linear ramp's moving
average, which should reproduce the ramp exactly at every interior point,
came out shifted by +0.5 for even windows). The window is now forced to
the nearest odd size below it, matching the always-odd Gaussian kernel's
centering. Affects `preprocessing.infer_curve_direction` and
`preprocessing._direction_violation_rate`, both of which call
`smooth_curve` with an unrounded, possibly-even window
(`max(5, n // 8)`), so this could bias the auto-detected `curve`/
`direction` and the direction-violation screen on some curve lengths.
- Ralph Eyeball Loop pass on `doc/ELBOW-en.tex`/`doc/LIKELIHOOD-en.tex`:
two real layout defects found and fixed by rendering every table and
`tikzpicture` and inspecting it — a Laplace-approximation figure's curve
labels running into the plotted line at its peak (re-anchored), and two
words hyphenated mid-word inside a narrow table column (rewrapped at the
word boundary). Both documents recompile with zero overfull/underfull/
undefined-reference warnings.

Changed
- CI restructured for speed: `pytest` and `ruff` now run as two separate,
fast jobs on Python 3.12 for every push and pull request, instead of one
job sweeping four Python versions. The full 3.10-3.13 compatibility
matrix still runs, on a weekly schedule and on manual dispatch, so the
version guarantee documented in `README.md`/`LISEZ-MOI.md` holds without
slowing down the default gate.
- Added a `pre-push` git hook (`.githooks/pre-push`, opt in via `git config
core.hooksPath .githooks`, documented in the new `CONTRIBUTING.md`) that
blocks a push on a lint or test failure locally, running `ruff check`,
`ruff format --check`, and the full `pytest` suite before CI ever sees
the commit.
- Consolidated the test suite from 114 tests to 85, with higher coverage
(69 missed lines instead of 76, out of 1793). `test_cli_argparse.py`,
`test_cli_click.py`, `test_api.py`, and `test_mcp_server.py` — 45 tests
that mostly hand-duplicated the same handful of scenarios (a clear knee
accepted, the y-only shorthand, elbow rejecting that shorthand,
diagnostics returning an SVG, the locator's raw payload) once per door —
are now `test_doors.py`: one behavioral test per scenario that drives
every door (argparse CLI, click CLI, HTTP API, MCP) through a small
adapter, so each scenario verifies parity across the whole surface
instead of whichever doors someone remembered to copy it into.
`test_doctests.py`'s five one-per-module tests are now one loop. Two new
tests close a real coverage gap in `pipeline.py`'s bootstrap/null-test
gate-failure paths and its numerical-safety-net exception handler,
previously only 83% covered.

0.1.5

Fixed
- **`KneeLocator`** raised spurious NumPy `RuntimeWarning`s on degenerate
curves: a single-point curve triggered `"Mean of empty slice"` computing
the sensitivity threshold's mean step (never actually reached by a
single-point curve, so `0.0` is a safe stand-in), and a constant or
single-point curve's min-max normalization divided by a zero range
(`0/0 = NaN` by design, correctly propagating to an abstain, but noisy).
Both warnings are now suppressed without changing the abstain behavior;
a regression test turns `RuntimeWarning` into an error to prove it.

Documentation
- Glossed previously-bare technical terms (blocked cross-validation, the
Bonferroni-gated permutation test, PCA) in `README.md`/`LISEZ-MOI.md`,
and removed punctuation-dash asides from five module docstrings' prose.

0.1.4

Fixed
- **`elbow_helper.plotting.render_svg_multi`** (and `plot_multi_diagnostics`):
an empty `(x, y)` crashed with `"zero-size array to reduction operation
minimum which has no identity"` on `x.min()`; a length-mismatched
`(x, y)` crashed with `IndexError` while sorting `y` by `x`'s own index
order. Both failures hit before `robust_knees` ever got a chance to
abstain with a clean reason code, the same failure mode CHANGELOG 0.1.3
already fixed once for `KneeLocator`. Both inputs now render the abstain
card instead.
- **argparse CLI**: `elbow-helper locator --online` was declared with
`action="store_true", default=True`, so the flag could only ever leave
`online` at its default `True`; there was no way to pass `online=False`
through this CLI, unlike the click twin's `--online/--no-online` pair.
Now uses `argparse.BooleanOptionalAction`, so `--online`/`--no-online`
both work and match the click twin.
- **Docs**: `README.md`, `LISEZ-MOI.md`, `EXAMPLES.md`, `EXEMPLES.md`, and
`PAYSAGE.md` still linked to `doc/ELBOW-fr.tex` / `doc/LIKELIHOOD-fr.tex`
and their compiled PDFs, removed from `doc/` earlier this session when
the math notes' scope narrowed to English only. Updated every reference
to point at the English notes, with `LISEZ-MOI.md`/`EXEMPLES.md`/
`PAYSAGE.md` now stating plainly that the math notes are English-only
while the rest of the docs keep their French twin. Also cleaned the same
dangling `ELBOW-fr.tex` mentions out of code comments/docstrings in
`src/elbow_helper/plotting.py`, `tests/test_multiknee.py`, and
`tests/test_real_world_examples.py`.

Added
- **`tests/test_cli_argparse.py`**: `_load_series`'s `--*-npy`/`--*-csv`
loading paths (shared by both CLI doors) and the x-only shorthand
branch of `_xy_from_args` had no test in either CLI's test file.
`cli_argparse.py` is now at 100% line coverage (was 77%).
- **`tests/test_plotting.py`**: `elbow_helper.plotting` (334 statements, the
package's largest module) had no dedicated test file, only indirect
coverage through the CLI's `diagnostics` subcommand and its own module
doctests. Added direct tests for `render_svg`'s clear/abstain/
`raw_axis`+`log_y` paths, `render_svg_multi`'s valid/invalid paths (the
two crashes above were both found writing these), and the `out=`
file-writing branches of `plot_multi_diagnostics`/
`plot_diagnostics_panels`.
- **`tests/test_doctests.py`**: the `>>> ...` examples embedded in
`_core_cli.py`, `cli_argparse.py`, `plotting.py`, `api.py`, and
`mcp_server.py` were never actually executed by `pytest -q`
(`pyproject.toml` scopes `testpaths` to `tests/` with no
`--doctest-modules`), so they could drift from real behaviour
unnoticed. Now run via `doctest.testmod` as part of the regular suite.

0.1.3

Fixed
- **`KneeLocator`**: an empty `(x, y)` input used to surface as a confusing
`"zero-size array to reduction operation minimum which has no identity"`
deep inside curve normalization, instead of a clear error at the actual
boundary. Now raises `ValueError` immediately. Reachable via the
unguarded `/locator` HTTP route and the CLI `locator` subcommand (unlike
`robust_knee`/`robust_elbow`, which have their own numerical-safety net).
- **API**: `/locator`'s `ValueError` (e.g. the empty-input case above)
collapsed into FastAPI's generic 500. Added a `ValueError` exception
handler mapping it to 400.
- **CLI**: a library exception now prints one clean `Error: ...` line to
stderr and exits 1, instead of a raw Python traceback, on both CLI
twins. `elbow-helper-click`'s console-script entry point now points at a
new `cli_click.main()` wrapper (was the bare `cli` group).

0.1.2

Added
- **`requirements.txt` / `requirements-dev.txt` / `environment.yaml`**, bringing
the project in line with the rest of the suite's manifests. `requirements.txt`
mirrors `pyproject.toml`'s `[project].dependencies`; `requirements-dev.txt`
points at the `[dev]` extra; `environment.yaml` is a minimal conda env that
hands off to `requirements.txt`, so it never drifts out of sync. README.md /
LISEZ-MOI.md's Installation sections now mention the conda path.
- **`robust_knees` section in README.md / LISEZ-MOI.md**: the plural multi-knee
API was fully public and tested but only mentioned in passing. Added a
concise section to both, output verified against the actual code.

Fixed
- **Three stale example outputs in `EXAMPLES.md` / `EXEMPLES.md`** no longer
matched `examples/*.py`'s current behavior despite identical code and seed:
`clear_knee.py` (`knee_x` 0.304 to 0.3418), `kmeans_elbow.py` (`knee_x` 8.0
to 9), `no_knee.py` (abstention reason `INCOMPATIBLE_GLOBAL_SHAPE` to
`NO_PERSISTENT_CLUSTER`). Updated all three to the verified current output.

Page 1 of 2

© 2026 Safety CLI Cybersecurity Inc. All Rights Reserved.