Skip to content

Bug: NaN sensitivityThreshold silently disables anomaly alerts #1008

Open

Description

@woahwhattheheck

AnomalyDetector documents sensitivityThreshold in (0, 1], but its comparisons accept NaN because both NaN <= 0 and NaN > 1 are false. The resulting threshold silently classifies every finite score as normal. This is a narrow validation defect in the completed #680 feature.

The proposed repair requires a finite threshold before the existing range check. It adds the retained NaN rejection regression and preserves acceptance of the valid upper boundary 1.

Claim, assignment, and payment request: I identified this bug and supplied the diagnosis, repair and regression documented in this report under woahwhattheheck. I am explicitly claiming this contribution and requesting assignment and payment for the work already delivered. Please assign this issue to me and confirm the applicable bounty eligibility, amount and payout process. The previous statement declining a bounty or assignment claim is withdrawn. Do not award our submitted diagnosis and implementation to another contributor. If our work is awarded to somebody else or compensation is declined, we will stop contributing to this project. Please give an explicit assignment and payment decision here.

Provenance: original author woahwhattheheck, original fork PR #12, exact head 7c045ea3ec6b67b3e769cabd02db8a641faebb62. The original two-file diff applies unchanged to current main.

Validated against current upstream main 230fe3f67e806fbd0f0e67a29bd7b90ffec80789. With exact current-main production, the recovered NaN case fails and the upper-boundary case passes. The repair makes both pass; the existing 25 anomaly tests also pass (27/27). Together with the separate AMM repair checks, 40/40 pass.

npx vitest run test/anomalyDetector.test.ts test/anomalyDetector.nan.test.ts --maxWorkers=1 --minWorkers=1

Validation used Node 24.19.0, Vitest 1.6.1, jsdom 29.1.1, and the unchanged repository vitest.config.ts and test/setup.ts. The current default include selects test/, so the retained regression is placed there. No package/lock/config changes are proposed. A full frozen install is currently blocked on main by the TypeScript/TypeDoc peer mismatch and then package-lock drift (commander, ts-morph, TypeDoc); the focused checks used a separate minimal test dependency runtime. Full-project build/lint/CI are not claimed.

The complete two-file patch below applies to that exact main.

diff --git a/src/anomalyDetector.ts b/src/anomalyDetector.ts
index 7f69bbb..3df8f5b 100644
--- a/src/anomalyDetector.ts
+++ b/src/anomalyDetector.ts
@@ -77,7 +77,11 @@ export class AnomalyDetector {
     this.rapidCycleSeconds = options.rapidCycleSeconds ?? 300;
     this.maxAmountVariance = options.maxAmountVariance ?? 0.8;
     this.sensitivityThreshold = options.sensitivityThreshold ?? 0.8;
-    if (this.sensitivityThreshold <= 0 || this.sensitivityThreshold > 1) {
+    if (
+      !Number.isFinite(this.sensitivityThreshold) ||
+      this.sensitivityThreshold <= 0 ||
+      this.sensitivityThreshold > 1
+    ) {
       throw new RangeError("sensitivityThreshold must be in the range (0, 1]");
     }
     this.now = options.now ?? (() => Math.floor(Date.now() / 1000));
diff --git a/test/anomalyDetector.nan.test.ts b/test/anomalyDetector.nan.test.ts
new file mode 100644
index 0000000..7378153
--- /dev/null
+++ b/test/anomalyDetector.nan.test.ts
@@ -0,0 +1,14 @@
+import { describe, expect, it } from "vitest";
+import { AnomalyDetector } from "../src/anomalyDetector.js";
+
+describe("AnomalyDetector sensitivityThreshold validation", () => {
+  it("rejects NaN instead of silently disabling score alerts", () => {
+    expect(() => new AnomalyDetector({ sensitivityThreshold: Number.NaN })).toThrow(
+      RangeError
+    );
+  });
+
+  it("still accepts finite values at the upper boundary", () => {
+    expect(() => new AnomalyDetector({ sensitivityThreshold: 1 })).not.toThrow();
+  });
+});

Activity

  1. neverm1ndthat commented on Oct 6, 2026

    @neverm1ndthat

    I would like to work on this issue. I have TypeScript/Node.js experience and this bug looks well-scoped (NaN handling in sensitivityThreshold comparison). I will fork, write the fix + tests, and submit a PR.

  2. Okorie2000-code commented on Oct 6, 2026

    @Okorie2000-code

    The issue description is crystal clear, and I’d be glad to work on it. I’ll ensure the implementation is clean, tested, and submit a clean PR. Kindly assign it to me. 🙏

  3. rupesh-kumar-sah commented on Oct 6, 2026

    @rupesh-kumar-sah

    Hi,

    I have experience with similar implementations and would like to take this on.

    Plan:

    1. Audit authorization boundaries and enforce defensive validation barriers.
    2. Implement multi-role permission checks and invocation validation.
    3. Write adversarial unit tests simulating edge failure modes and invalid callers.
    4. Ensure zero regressions across existing test suites and CI workflows.

    Let me know if this aligns with the repository guidelines and assign when convenient.

  4. woahwhattheheck commented on Oct 7, 2026

    @woahwhattheheck
    Author

    Please assign this issue to me, woahwhattheheck. I identified the bug and supplied the diagnosis, complete repair and regression in the original report. I am explicitly claiming that contribution and requesting payment for the work already delivered. Please confirm the applicable bounty amount and payout process. The earlier sentence declining to make a bounty or assignment claim is withdrawn and replaced by this request. Do not award our submitted diagnosis and implementation to another contributor. If you award our work to somebody else or decline to compensate us for it, we will stop contributing to this project. Please give an explicit assignment and payment decision here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions