From 47395eadf38615a02fb9feebd1ca9e2bf65aff3b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Jul 2026 07:19:32 +0000 Subject: [PATCH 1/2] Fix docstring drift surfaced by audit - Model.params (db/models.py): reflect that today's blob holds x_loadings, explained_variance, and r2_cumulative, not P/W/means/scales. - apply_transform (core/transforms.py): the power branch's signature default is c1=0.0; 0.5 (signed root) is only substituted internally when c1==0.0. - suggest_transform (core/profiling.py): describe the actual branches (POWER only for strongly skewed + not-strictly-positive/narrow-range; milder skew is left alone). --- src/scorepilot/core/profiling.py | 14 +++++++++++--- src/scorepilot/core/transforms.py | 4 +++- src/scorepilot/db/models.py | 12 ++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/scorepilot/core/profiling.py b/src/scorepilot/core/profiling.py index 74f0540..1f8313a 100644 --- a/src/scorepilot/core/profiling.py +++ b/src/scorepilot/core/profiling.py @@ -142,9 +142,17 @@ def sequence(series: pd.Series) -> list[float | None]: def suggest_transform(summary: VariableSummary) -> TransformKind: """Suggest a transform from a variable's shape. - A strongly right-skewed, strictly positive variable with a wide dynamic range - is a candidate for a log transform; a milder skew suggests a signed power - (root). Otherwise no transform is suggested. + Only strongly right-skewed quantitative variables (skewness > 1.0) trigger a + suggestion: + + - If the variable is also strictly positive and has a wide dynamic range + (min-max ratio > 20), suggest a log transform. + - Otherwise (skewed, but either not strictly positive or not wide-range), + suggest a signed power (root). + + Anything else -- non-quantitative, unknown skewness, or skewness at or below + 1.0 -- returns ``TransformKind.NONE``. Milder skew is deliberately left + alone. """ if summary.column_type is not ColumnType.QUANTITATIVE or summary.skewness is None: return TransformKind.NONE diff --git a/src/scorepilot/core/transforms.py b/src/scorepilot/core/transforms.py index 80a2ab2..3e4b4ac 100644 --- a/src/scorepilot/core/transforms.py +++ b/src/scorepilot/core/transforms.py @@ -48,7 +48,9 @@ def apply_transform( - ``neglog``: ``sign(x) * log1p(abs(x))`` (sign-symmetric log) - ``logit``: ``log(p / (1 - p))`` with ``p = x`` (defined for ``0 < x < 1``) - ``exponential``: ``exp(x)`` - - ``power``: ``sign(x) * abs(x) ** c1`` (default ``c1 = 0.5``, i.e. signed root) + - ``power``: ``sign(x) * abs(x) ** c1``. The signature default is ``c1 = 0.0``; + when ``c1 == 0.0`` the function substitutes ``0.5`` internally (signed + square root). Pass an explicit ``c1`` for any other exponent. """ values = to_numeric(series).astype(float).to_numpy() diff --git a/src/scorepilot/db/models.py b/src/scorepilot/db/models.py index 61b9bf6..c81b589 100644 --- a/src/scorepilot/db/models.py +++ b/src/scorepilot/db/models.py @@ -47,10 +47,14 @@ def __repr__(self) -> str: class Model(Base): """A fitted PCA/PLS model variant. - Queryable metadata lives in real columns and JSON; the fitted arrays (P, W, - means, scales, ...) are stored as a compressed ``npz`` blob in ``params``. If - those artifacts grow, ``params`` can be swapped for an object-storage path - behind the same repository method without changing anything upstream. + Queryable metadata lives in real columns and JSON; a compact set of fitted + diagnostics is stored as a compressed ``npz`` blob in ``params``. Today the + blob holds ``x_loadings`` (the X-block loadings matrix), ``explained_variance`` + (per-component), and ``r2_cumulative`` (cumulative R²X across components) -- + the arrays needed by the current API's diagnostic endpoints. If more fitted + state is later persisted, or those artifacts grow, ``params`` can be swapped + for an object-storage path behind the same repository method without changing + anything upstream. """ __tablename__ = "model" From 6dd34531cda469094297953af04455f3a38d36b1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Jul 2026 07:19:36 +0000 Subject: [PATCH 2/2] Bump version to 0.22.1 (PATCH: docstrings only) --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8e22790..9ccca90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "scorepilot" -version = "0.22.0" +version = "0.22.1" description = "Web-based tool for PCA/PLS model analysis in chemometrics." readme = "README.md" requires-python = ">=3.12" diff --git a/uv.lock b/uv.lock index c8ef9aa..fd0368a 100644 --- a/uv.lock +++ b/uv.lock @@ -1021,7 +1021,7 @@ wheels = [ [[package]] name = "scorepilot" -version = "0.22.0" +version = "0.22.1" source = { editable = "." } dependencies = [ { name = "alembic" },