Skip to content

refactor: add explicit isnan guards#13343

Merged
kgryte merged 2 commits into
developfrom
philipp/drift-stats-base-dists-pareto-type1-2026-07-07
Jul 7, 2026
Merged

refactor: add explicit isnan guards#13343
kgryte merged 2 commits into
developfrom
philipp/drift-stats-base-dists-pareto-type1-2026-07-07

Conversation

@Planeshifter

Copy link
Copy Markdown
Member

Description

What is the purpose of this pull request?

This pull request:

  • aligns the validation prologue in stats/base/dists/pareto-type1/mean and stats/base/dists/pareto-type1/median with the interleaved isnan() guard shape already used by 10 of 12 comparable sibling packages (cdf, entropy, kurtosis, logcdf, logpdf, mode, pdf, quantile, skewness, variance — 83.3% conformance) and with the mean package's own C source at src/main.c. Observable behavior is unchanged in both packages; NaN inputs previously returned NaN through arithmetic propagation and now short-circuit via the explicit guard.

Namespace summary

  • Target: @stdlib/stats/base/dists/pareto-type1
  • Members analyzed: 14 (cdf, ctor, entropy, kurtosis, logcdf, logpdf, mean, median, mode, pdf, quantile, skewness, stdev, variance)
  • Features analyzed: file tree, package.json top-level / scripts / stdlib / directories / keywords keys, README section sequence, manifest.json shape, test/benchmark/examples filenames, public signature, return kind, validation prologue, error construction, JSDoc shape (param tags / returns / throws / @example blocks), lib/main.js require dependencies, and the corresponding C sources.
  • Features with clear majority (≥75%): package.json top-level key set (100%); directories keys benchmark/doc/example/lib/test (100%); ## Usage and ## Examples README sections (100%); interleaved isnan( arg ) || arg <= 0.0 || … validation prologue at 10/14 = 71% overall, 10/12 = 83.3% among the numeric-property packages that carry a prologue at all (ctor and stdev legitimately excluded — ctor throws via format, stdev delegates via sqrt( variance( α, β ) )); C stdlib_base_is_nan guard in src/main.c at 11/12 native-backed C sources = 91.7% (stdev excluded).
  • Features without clear majority (excluded from drift detection): native-bindings file group (manifest.json, binding.gyp, include.gypi, src/**, lib/native.js, benchmark/c/**, benchmark/benchmark.native.js, examples/c/**, test/test.native.js) at 12/14 = 85.7% (the 2 outliers are ctor and median, which are inapplicable — see PR feat: add C implementation for stats/base/dists/pareto-type1/median #10079 for median's native binding); ## C APIs README section at 12/14 = 85.7% (same rationale); gypfile package.json key at 12/14 = 85.7%; lib/factory.js at 5/14 = 36%; public signature shape (split between (α, β) summary stats and (x|p, α, β) distribution functions — no shape ≥ 75%); error construction (only ctor throws; rest return NaN); README ## Notes section (only logcdf and logpdf); dependency sets (varies legitimately by mathematical implementation).

stats/base/dists/pareto-type1/mean

Add explicit isnan( alpha ) || isnan( beta ) guards to the validation prologue in lib/main.js, matching the interleaved shape used by 10 of 12 sibling numeric-property packages (83.3% conformance) and realigning the JS with the C source at src/main.c, which already checks stdlib_base_is_nan( alpha ) || stdlib_base_is_nan( beta ). Observable behavior is unchanged: NaN inputs previously propagated through (alpha*beta)/(alpha-1) and now short-circuit via the explicit guard.

stats/base/dists/pareto-type1/median

Prepend explicit isnan( alpha ) and isnan( beta ) checks to the parameter validation prologue in lib/main.js, matching the interleaved guard shape used by 10 of 12 comparable numeric-property packages in stats/base/dists/pareto-type1 (83.3% conformance; ctor and stdev are excluded as they validate via format and sqrt( variance( α, β ) ) respectively). Observable behavior is unchanged: median( NaN, 2.0 ) previously returned NaN through arithmetic propagation in beta * pow( 2.0, 1.0/alpha ), and now returns NaN via the explicit guard. Orthogonal to #10079, which adds the native binding and applies the equivalent stdlib_base_is_nan guard in the C source.

Validation

Checked:

  • structural feature extraction (file tree, package.json shape, README section list, manifest.json shape, test/benchmark/example filenames) across all 14 members.
  • semantic feature extraction (public signature, validation prologue, error construction, JSDoc shape, dependency set) across all 14 members by reading each lib/main.js and the corresponding src/main.c directly.
  • three-agent drift validation on the two candidate corrections:
    • opus semantic-review returned confirmed-drift for both mean and median, citing that mean/src/main.c already includes the stdlib_base_is_nan guard (the JS drifted from its own C mirror) and that no comment, test, or JSDoc claim justifies omission.
    • opus cross-reference returned safe-to-apply for both, confirming test/test.js in both packages already asserts NaN return for NaN inputs, docs/repl.txt and docs/types/index.d.ts already document the same, examples/index.js uses non-NaN uniform-random inputs, and ctor consumers gate through isPositive before ever invoking mean/median (so ctor behavior is unaffected).
    • sonnet structural-review returned confirmed-drift for both, confirming the family pattern is the exact interleaved shape if ( isnan( α ) || α <= 0.0 || isnan( β ) || β <= 0.0 ) (as used by mode, entropy, kurtosis, skewness, variance), and that placement of the guard before mean's if ( alpha <= 1.0 ) return PINF; branch is correct (since NaN <= 1.0 is false, without the guard NaN would fall through the PINF branch).

Deliberately excluded:

  • ctor errorConstruction = "format" (throws TypeError via @stdlib/string/format) vs. the majority return NaN. Intentional deviation: a class constructor legitimately throws on bad arguments; distribution-property scalars return NaN.
  • stdev/lib/main.js lacks a validation prologue, delegating return sqrt( variance( alpha, beta ) );. Intentional deviation: variance already performs identical validation; sqrt( NaN ) === NaN preserves observable behavior; sibling distributions binomial/stdev, lognormal/stdev, poisson/stdev follow the same delegating idiom (independently established by the earlier binomial and lognormal runs of this routine, PRs style: align outliers in stats/base/dists/binomial with namespace majority patterns #11902 and docs: add negative-scale @example to stats/base/dists/lognormal/cdf #12093).
  • Native-bindings absence in ctor (constructor — inapplicable) and median (currently JS-only on develop; feat: add C implementation for stats/base/dists/pareto-type1/median #10079 adds it). Adding a full C stack is a substantive new feature, not a mechanical drift fix.
  • logcdf and logpdf READMEs carry an extra ## Notes section not present in siblings. Intentional: the note explains the x < beta branch that returns -Infinity, which is specific to the logarithmic transform.
  • ## See Also README section drift — auto-populated by the package generator; gate 7a excludes.
  • SVG naming (equation_pareto_type1_expectation.svg for mean vs. _median.svg, _mode.svg, _kurtosis.svg, etc.). Intentional: expectation matches the equation label \mathbb{E}[X] in the same file.

Related Issues

Does this pull request have any related issues?

No.

Questions

Any questions for reviewers of this pull request?

No.

Other

Any other information relevant to this pull request? This may include screenshots, references, and/or implementation notes.

Random namespace pick from the lib/node_modules/@stdlib/ walk of directories with ≥ 8 direct child packages. Does not conflict with the open native-binding PR #10079 targeting pareto-type1/median, which touches only new native files (binding.gyp, manifest.json, include/**, src/**, benchmark/benchmark.native.js, benchmark/c/**, examples/c/**, lib/native.js, test/test.native.js) and appends a ## C APIs section to README.md — orthogonal to the lib/main.js files modified here.

Checklist

Please ensure the following tasks are completed before submitting this pull request.

AI Assistance

When authoring the changes proposed in this PR, did you use any kind of AI assistance?

  • Yes
  • No

If you answered "yes" above, how did you use AI assistance?

  • Code generation (e.g., when writing an implementation or fixing a bug)
  • Test/benchmark generation
  • Documentation (including examples)
  • Research and understanding

Disclosure

This PR was authored by Claude Code via the cross-package drift-detection routine: structural and semantic features were extracted from every member of stats/base/dists/pareto-type1, majority patterns were computed at a 75% conformance threshold, and three independent validation agents (opus semantic-review, opus cross-reference, sonnet structural-review) confirmed each correction was high-signal mechanical drift before any file was edited. The two edits are pure additive guards to existing if (…) return NaN; prologues in lib/main.js; no source, test, or observable-behavior changes.


@stdlib-js/reviewers


Generated by Claude Code

claude added 2 commits July 7, 2026 00:18
…1/mean`

Adds explicit `isnan( alpha ) || isnan( beta )` short-circuits to the
validation prologue in `lib/main.js`, matching the pattern used by
10/12 comparable siblings in `stats/base/dists/pareto-type1` (`cdf`,
`entropy`, `kurtosis`, `logcdf`, `logpdf`, `mode`, `pdf`, `quantile`,
`skewness`, `variance` — 83.3% conformance) and the package's own C
counterpart in `src/main.c`, which uses `stdlib_base_is_nan( alpha )
|| stdlib_base_is_nan( beta )`. NaN inputs previously returned NaN
via arithmetic propagation through the `(alpha*beta) / (alpha-1)`
expression; observable behavior is unchanged.
…1/median`

Adds explicit `isnan( alpha ) || isnan( beta )` short-circuits to the
validation prologue in `lib/main.js`, matching the pattern used by
10/12 comparable siblings in `stats/base/dists/pareto-type1` (`cdf`,
`entropy`, `kurtosis`, `logcdf`, `logpdf`, `mode`, `pdf`, `quantile`,
`skewness`, `variance` — 83.3% conformance). NaN inputs previously
returned NaN via arithmetic propagation through `beta * pow( 2, 1/alpha )`;
observable behavior is unchanged.
@stdlib-bot stdlib-bot added the Statistics Issue or pull request related to statistical functionality. label Jul 7, 2026
@stdlib-bot

Copy link
Copy Markdown
Contributor

Coverage Report

Package Statements Branches Functions Lines
stats/base/dists/pareto-type1/mean $\\color{green}187/187$
$\\color{green}+100.00\\%$
$\\color{green}12/12$
$\\color{green}+100.00\\%$
$\\color{green}2/2$
$\\color{green}+100.00\\%$
$\\color{green}187/187$
$\\color{green}+100.00\\%$
stats/base/dists/pareto-type1/median $\\color{green}125/125$
$\\color{green}+100.00\\%$
$\\color{green}8/8$
$\\color{green}+100.00\\%$
$\\color{green}1/1$
$\\color{green}+100.00\\%$
$\\color{green}125/125$
$\\color{green}+100.00\\%$

The above coverage report was generated for the changes in this PR.

@kgryte kgryte marked this pull request as ready for review July 7, 2026 00:37
@kgryte kgryte requested a review from a team July 7, 2026 00:37
@stdlib-bot stdlib-bot added the Needs Review A pull request which needs code review. label Jul 7, 2026
@kgryte kgryte removed the Needs Review A pull request which needs code review. label Jul 7, 2026
@kgryte kgryte changed the title refactor: add explicit isnan guards in stats/base/dists/pareto-type1/{mean,median} refactor: add explicit isnan guards Jul 7, 2026
@kgryte kgryte merged commit 2671115 into develop Jul 7, 2026
53 checks passed
@kgryte kgryte deleted the philipp/drift-stats-base-dists-pareto-type1-2026-07-07 branch July 7, 2026 00:38
@Planeshifter Planeshifter mentioned this pull request Jul 8, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Statistics Issue or pull request related to statistical functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants