Skip to content

risk score calculation debug logs#1275

Merged
mantrakp04 merged 8 commits intodevfrom
chore/debug-logs-for-risk-calculation
Mar 21, 2026
Merged

risk score calculation debug logs#1275
mantrakp04 merged 8 commits intodevfrom
chore/debug-logs-for-risk-calculation

Conversation

@mantrakp04
Copy link
Copy Markdown
Collaborator

@mantrakp04 mantrakp04 commented Mar 21, 2026

  • Updated pnpm-lock.yaml to include 'rolldown' as a new optional dependency and upgraded 'minimatch' to version 10.2.4.
  • Added a debug log statement in risk-scores.tsx to indicate when the sign-up risk engine is disabled in the public build.

Summary by CodeRabbit

  • Bug Fixes

    • Signup risk scoring now returns a neutral (zero) score when the scoring engine is unavailable; scoring errors are logged and surfaced consistently instead of being silently swallowed.
    • Invalid or malformed engine implementations now fail loudly instead of falling back silently.
  • Chores

    • Updated the private engine reference and adjusted tests for the new loading/resolution behavior.
    • Expanded Next.js output tracing to include private package files used by API routes.

…and logging improvements

- Updated pnpm-lock.yaml to include 'rolldown' as a new optional dependency and upgraded 'minimatch' to version 10.2.4.
- Added a debug log statement in risk-scores.tsx to indicate when the sign-up risk engine is disabled in the public build.
Copilot AI review requested due to automatic review settings March 21, 2026 01:13
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-auth-hosted-components Ready Ready Preview, Comment Mar 21, 2026 5:06am
stack-backend Ready Ready Preview, Comment Mar 21, 2026 5:06am
stack-dashboard Ready Ready Preview, Comment Mar 21, 2026 5:06am
stack-demo Ready Ready Preview, Comment Mar 21, 2026 5:06am
stack-docs Ready Ready Preview, Comment Mar 21, 2026 5:06am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 21, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Simplified backend sign-up risk engine loading: made the engine type internal, replaced multi-path resolution with a single filesystem path + dynamic import, added an inline zero-score fallback and centralized error handling, updated tests, bumped packages/private submodule, and added Next.js tracing for the private bundle.

Changes

Cohort / File(s) Summary
Risk engine loader & API
apps/backend/src/lib/risk-scores.tsx
Made SignUpRiskEngine/dependency types internal; removed multi-path loader; introduced PRIVATE_ENGINE_PATH and single-path dynamic import of packages/private/dist; added inline zero-score engine fallback (uses new Date()); extracted calculateRiskAssessmentWithFallback to log via captureError and return zero-score on runtime errors; throws StackAssertionError for invalid engine shape; tests updated accordingly.
Next.js config
apps/backend/next.config.mjs
Added outputFileTracingIncludes mapping /api/** to include ../../packages/private/dist/** so Next.js includes private package outputs for API routes.
Submodule update
packages/private
Updated gitlink for packages/private to a newer commit hash (submodule pointer changed).

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant Loader as RiskEngineLoader
    participant FS as FileSystem
    participant Importer as DynamicImporter
    participant Engine as SignUpRiskEngine

    Caller->>Loader: calculateSignUpRiskAssessment(args)
    Loader->>FS: resolvePrivateEnginePath() / check existence
    FS-->>Loader: path exists / not found
    alt path exists
        Loader->>Importer: dynamic import(resolvedPath)
        Importer-->>Loader: module
        alt module has valid engine
            Loader->>Engine: engine.calculateRiskAssessment(args)
            Engine-->>Caller: assessment
        else invalid export
            Loader-->>Caller: throw StackAssertionError
        end
    else path not found
        Loader->>Loader: use INLINE_ZERO_SCORE_ENGINE (timestamp = new Date())
        Loader-->>Caller: zero-score assessment
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • N2D4

Poem

I hop through paths both found and lost,
I sniff the fs for engine's cost,
When imports fail, I still keep score,
I stamp the ground and check the door,
A rabbit's zero hops ashore 🐇✨

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete and misleading. It mentions only pnpm-lock.yaml and debug logs, but the actual changeset includes major refactoring of risk engine loading, type definition changes, Next.js configuration updates, and submodule changes—none of which are adequately described. Update the description to comprehensively cover the risk engine refactoring, private package integration, exported type changes, Next.js configuration updates, and the new PRIVATE_ENGINE_PATH constant and fallback mechanism.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'risk score calculation debug logs' is vague and does not accurately reflect the substantial changes made. The PR actually refactors the risk engine loading mechanism with fallback handling, updates Next.js configuration, and changes exported type definitions—far beyond just adding debug logs. Consider a more descriptive title like 'Refactor risk engine loading with private package integration and fallback handling' that accurately reflects the main architectural changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/debug-logs-for-risk-calculation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a debug log to the fallback sign-up risk engine path (when disabled) and updates the packages/private submodule pointer.

Changes:

  • Log a debug message when the sign-up risk engine is disabled and fallbackEngine is used.
  • Bump packages/private submodule commit reference.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/private Updates the git submodule commit pointer.
apps/backend/src/lib/risk-scores.tsx Adds a debug log when the fallback (disabled) risk engine runs.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

packages/private:1

  • The PR description mentions pnpm-lock/minimatch/rolldown changes, but the diff shown includes a packages/private submodule bump. Please update the PR description to explicitly call out why this submodule pointer changed (or split it into a separate PR if unrelated).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 21, 2026

Greptile Summary

This PR significantly refactors the private sign-up risk engine loader in apps/backend/src/lib/risk-scores.tsx, switching from a package-name-based import strategy to a filesystem path discovery approach (fs.existsSync at module load time), and adds a outputFileTracingIncludes entry to next.config.mjs so that Next.js standalone output tracing picks up the private package's built files. All previously flagged issues — the per-request debug log, unguarded import errors, duplicate concurrent imports, the poisoned-promise cache, and the validation-failure 500 — appear to have been addressed in this revision.

Key changes:

  • PRIVATE_ENGINE_PATH is resolved once at module load via fs.existsSync, replacing multi-attempt package/path imports
  • loadEngineFromPath catches both import failures and shape-validation failures, returning ZERO_SCORE_ENGINE with a captureError call in each case
  • Promise-caching pattern restored in getEngine() — the in-flight promise is stored synchronously before any await, eliminating the concurrent-import race window
  • calculateRiskAssessmentWithFallback wraps engine.calculateRiskAssessment with a zero-score fallback, giving two distinct layers of error protection
  • outputFileTracingIncludes added to next.config.mjs to ensure the private engine files are included in standalone Docker builds
  • SignUpRiskEngineDependencies simplified — removed now, normalizeEmail, isIpAddress, and createAssertionError from the dependency injection contract
  • Tests updated to reflect new APIs; test isolation is maintained via cachedEnginePromise = null in finally blocks

Confidence Score: 4/5

  • This PR is safe to merge; all previously identified critical issues have been addressed and the new design is robust.
  • All P0/P1 issues from the prior review round are resolved. The remaining items are style-level: a misleading test name and a getEngine catch block that is effectively dead code but re-throws rather than applying the zero-score fallback (a minor inconsistency with the rest of the error-handling design). Neither affects correctness in normal operation.
  • The getEngine catch block in apps/backend/src/lib/risk-scores.tsx (lines 127–134) deserves a second look — it re-throws rather than returning ZERO_SCORE_ENGINE, which is inconsistent with the rest of the error-handling design, though it is unreachable in practice.

Important Files Changed

Filename Overview
apps/backend/src/lib/risk-scores.tsx Substantial refactor of the private risk engine loader: switches from package-name import to fs.existsSync-based path discovery, restores promise-caching, and adds comprehensive zero-score fallbacks for both import and validation failures. All issues from the previous review round appear addressed. Two minor style items: a misleading test name for the loadEngineFromPath import-failure test, and a getEngine catch block that is effectively dead code but re-throws instead of falling back.
apps/backend/next.config.mjs Added outputFileTracingIncludes so that Next.js standalone output tracing picks up packages/private/dist/** for API routes. Straightforward and correct — this config key is stable (not experimental) in current Next.js versions and only takes effect when output: "standalone" is set.
packages/private Submodule pointer bumped from 6f708e4 to 2f2c031. Contents are not directly reviewable, but the updated risk-scores.tsx now looks for mod.signUpRiskEngine (a top-level named export) and validates its shape before using it, so the submodule is expected to export signUpRiskEngine with a calculateRiskAssessment function.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[calculateSignUpRiskAssessment] --> B[getEngine]
    B --> C{cachedEnginePromise\nnot null?}
    C -- yes --> D[await cached promise]
    C -- no --> E[loadEngine]
    E --> F{PRIVATE_ENGINE_PATH\n== null?}
    F -- yes --> G[console.debug\nreturn ZERO_SCORE_ENGINE]
    F -- no --> H[loadEngineFromPath]
    H --> I{import succeeds?}
    I -- no --> J[captureError\nreturn ZERO_SCORE_ENGINE]
    I -- yes --> K{isSignUpRiskEngine\nvalidation}
    K -- fails --> L[captureError\nreturn ZERO_SCORE_ENGINE]
    K -- passes --> M[console.info\nreturn engine]
    E --> N[cache enginePromise]
    N --> O{await resolves?}
    O -- error --> P[clear cache\nthrow error]
    O -- ok --> Q[return engine]
    D --> Q
    G --> Q
    J --> Q
    L --> Q
    M --> Q
    Q --> R[calculateRiskAssessmentWithFallback]
    R --> S{engine.calculateRiskAssessment\nthrows?}
    S -- yes --> T[captureError\nreturn createZeroRiskAssessment]
    S -- no --> U[return assessment]
Loading

Fix All in Claude Code Fix All in Cursor Fix All in Codex

Last reviewed commit: "Refactor risk-scores..."

Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
@mantrakp04 mantrakp04 enabled auto-merge (squash) March 21, 2026 01:38
@mantrakp04 mantrakp04 disabled auto-merge March 21, 2026 02:16
…agement

- Removed unused imports and streamlined the risk engine dependencies in risk-scores.tsx.
- Updated pnpm-lock.yaml to adjust minimatch version and include new dependencies for balanced-match and brace-expansion.
- Enhanced the private engine loading logic for better clarity and error handling.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/backend/src/lib/risk-scores.tsx (1)

103-108: Consider caching the loading promise to prevent redundant loads.

If multiple concurrent calls arrive when cachedEngine is null, each will invoke loadEngine() before any completes and caches. While not a correctness issue (the engine is idempotent), caching the promise avoids redundant I/O.

♻️ Optional fix using promise caching
-let cachedEngine: SignUpRiskEngine | null = null;
+let cachedEnginePromise: Promise<SignUpRiskEngine> | null = null;

 async function getEngine(): Promise<SignUpRiskEngine> {
-  if (cachedEngine == null) {
-    cachedEngine = await loadEngine();
+  if (cachedEnginePromise == null) {
+    cachedEnginePromise = loadEngine();
   }
-  return cachedEngine;
+  return cachedEnginePromise;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/src/lib/risk-scores.tsx` around lines 103 - 108, getEngine
currently checks cachedEngine and calls loadEngine() which can be invoked
multiple times if concurrent callers race; change to cache the loading promise:
introduce a module-level variable (e.g., cachedEnginePromise) and in getEngine,
if cachedEngine is null and cachedEnginePromise is null set cachedEnginePromise
= loadEngine(); await cachedEnginePromise, assign its result to cachedEngine,
clear cachedEnginePromise, and return cachedEngine; ensure subsequent callers
await cachedEnginePromise instead of calling loadEngine() directly so only one
loadEngine() runs concurrently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/backend/src/lib/risk-scores.tsx`:
- Around line 103-108: getEngine currently checks cachedEngine and calls
loadEngine() which can be invoked multiple times if concurrent callers race;
change to cache the loading promise: introduce a module-level variable (e.g.,
cachedEnginePromise) and in getEngine, if cachedEngine is null and
cachedEnginePromise is null set cachedEnginePromise = loadEngine(); await
cachedEnginePromise, assign its result to cachedEngine, clear
cachedEnginePromise, and return cachedEngine; ensure subsequent callers await
cachedEnginePromise instead of calling loadEngine() directly so only one
loadEngine() runs concurrently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3ebb2fd3-75ba-470c-b502-eab134988aeb

📥 Commits

Reviewing files that changed from the base of the PR and between 189af8e and 9ba7d84.

📒 Files selected for processing (2)
  • apps/backend/src/lib/risk-scores.tsx
  • packages/private
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/private

Comment thread apps/backend/src/lib/risk-scores.tsx
…or handling

- Introduced a new function, resolvePrivateEnginePath, to streamline the logic for locating the private sign-up risk engine.
- Enhanced the loadEngine function to utilize the new resolution method and improved logging for better clarity on engine loading status.
- Updated tests to reflect changes in engine loading behavior and ensure proper functionality when the private engine is available or not.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/backend/src/lib/risk-scores.tsx`:
- Around line 179-187: The tests referencing the private engine should be
skipped when the private package is not present: wrap the two
import.meta.vitest?.test calls to conditionally skip using HAS_PRIVATE_ENGINE
(e.g., use import.meta.vitest?.test.skipIf(!HAS_PRIVATE_ENGINE) for the first
test and likewise for the second), so the "resolvePrivateEnginePath finds the
engine in the monorepo" and "loadEngine loads the real engine when available"
tests only run when HAS_PRIVATE_ENGINE is true; ensure you still call
loadEngine() in the second test when running to verify calculateRiskAssessment
exists, but avoid running it in public/CI environments without the private
package.
- Around line 90-96: Guard against PRIVATE_ENGINE_PATH possibly being null
before dynamically importing: import throwErr from
"@stackframe/stack-shared/dist/utils/errors" (or the named export throwErr) and
add a defensive check where you use PRIVATE_ENGINE_PATH (the block that does
await import(/* webpackIgnore: true */ PRIVATE_ENGINE_PATH) and references
HAS_PRIVATE_ENGINE) — if PRIVATE_ENGINE_PATH is null/undefined call throwErr or
throw a StackAssertionError with context instead of passing null into import;
then proceed to import and validate mod.signUpRiskEngine as currently done so
TypeScript's strict-null checks are satisfied.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3dd481b-2fb2-431c-ab5f-dc560cda09ec

📥 Commits

Reviewing files that changed from the base of the PR and between 9ba7d84 and c1792b6.

📒 Files selected for processing (1)
  • apps/backend/src/lib/risk-scores.tsx

Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
…or reporting

- Updated the private engine resolution logic to streamline path detection and ensure compatibility with the monorepo structure.
- Introduced a fallback mechanism in calculateRiskAssessmentWithFallback to handle errors gracefully, capturing relevant context for better debugging.
- Refactored the getEngine function to utilize cached engine instances, improving performance and reducing redundant imports.
- Updated tests to validate the new error handling and engine loading behavior.
- Introduced a new function, getPrivateEnginePathOrThrow, to ensure the PRIVATE_ENGINE_PATH is defined, improving error reporting during engine loading.
- Refactored the getEngine function to utilize the new path retrieval method, enhancing clarity in logging.
- Updated tests to skip when PRIVATE_ENGINE_PATH is not available, ensuring more robust test execution and coverage for engine loading scenarios.
@mantrakp04
Copy link
Copy Markdown
Collaborator Author

@greptile-ai review

Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
Comment thread apps/backend/src/lib/risk-scores.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/backend/src/lib/risk-scores.tsx (1)

232-232: Prefer defensive pattern over non-null assertion.

While the callback only executes when vitest is available, the guideline recommends defensive coding with explicit error messages. As per coding guidelines: "Prefer ?? throwErr(...) over non-null assertions with good error messages."

Proposed fix
-  const { vi } = import.meta.vitest!;
+  const { vi } = import.meta.vitest ?? throwErr("import.meta.vitest should be defined inside vitest test callback");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/src/lib/risk-scores.tsx` at line 232, Replace the non-null
assertion on import.meta.vitest with a defensive check that throws a clear error
when vitest is unavailable: instead of using import.meta.vitest! to assign vi,
use a nullish-coalescing pattern that calls a descriptive throw (e.g.,
import.meta.vitest ?? throwErr('vitest not available when running risk-scores
tests')) so the assignment to vi fails with an actionable message; update the
assignment that initializes vi to reference import.meta.vitest and the throw
helper or an Error to provide the explicit error message.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/backend/src/lib/risk-scores.tsx`:
- Line 232: Replace the non-null assertion on import.meta.vitest with a
defensive check that throws a clear error when vitest is unavailable: instead of
using import.meta.vitest! to assign vi, use a nullish-coalescing pattern that
calls a descriptive throw (e.g., import.meta.vitest ?? throwErr('vitest not
available when running risk-scores tests')) so the assignment to vi fails with
an actionable message; update the assignment that initializes vi to reference
import.meta.vitest and the throw helper or an Error to provide the explicit
error message.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cff96163-b9ac-48c0-b8f1-b116a466b755

📥 Commits

Reviewing files that changed from the base of the PR and between 1818b94 and 0c2e32f.

📒 Files selected for processing (1)
  • apps/backend/src/lib/risk-scores.tsx

…isms

- Replaced cachedEngine with cachedEnginePromise to improve asynchronous handling of the sign-up risk engine.
- Introduced loadEngineFromPath function for better error handling during engine imports, ensuring fallback to zero scores on failure.
- Updated getEngine function to utilize the new promise-based caching, enhancing performance and clarity.
- Modified tests to reflect changes in engine loading behavior and ensure proper functionality when the private engine is unavailable.
@mantrakp04
Copy link
Copy Markdown
Collaborator Author

@greptile-ai review

@mantrakp04 mantrakp04 requested a review from N2D4 March 21, 2026 04:34
Comment thread apps/backend/src/lib/risk-scores.tsx
- Introduced getEngineWithLoader function to enhance the loading mechanism of the sign-up risk engine, ensuring that rejected promises clear the cached engine.
- Updated the getEngine function to utilize the new loader, maintaining performance while improving error management.
- Added a test case for getEngineWithLoader to verify that rejected promises correctly reset the cached engine state.
@mantrakp04
Copy link
Copy Markdown
Collaborator Author

@greptile-ai review

Comment thread apps/backend/src/lib/risk-scores.tsx Outdated
Comment thread apps/backend/src/lib/risk-scores.tsx
- Removed the getPrivateEnginePathOrThrow function and replaced it with a type guard, isSignUpRiskEngine, to streamline engine validation.
- Updated loadEngine and loadEngineFromPath functions to enhance error handling, ensuring fallback to zero scores when the private engine is invalid.
- Simplified the getEngine function by removing the loader wrapper, directly utilizing loadEngine for better clarity.
- Modified tests to validate the new engine loading behavior and ensure proper fallback mechanisms are in place.
@mantrakp04
Copy link
Copy Markdown
Collaborator Author

@greptile-ai review n rescore

Comment thread apps/backend/src/lib/risk-scores.tsx
Comment thread apps/backend/src/lib/risk-scores.tsx
@mantrakp04 mantrakp04 merged commit 0886586 into dev Mar 21, 2026
34 checks passed
@mantrakp04 mantrakp04 deleted the chore/debug-logs-for-risk-calculation branch March 21, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants