✨ server: assess transaction risk#607
Conversation
🦋 Changeset detectedLatest commit: a6c130c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughIntegrates Sardine risk assessments and issuer feedback into spend/refund/verification flows, expands spend transaction schema with merchant metadata, attaches risk results to tracing and captures high-risk events, and adds tests for high-risk and timeout scenarios. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Server as Panda Hook
participant DB as Database
participant Risk as Sardine Risk
participant Feedback as Issuer Feedback
Client->>Server: Spend / Refund / Verify request
Server->>DB: Load card / credential / transaction
DB-->>Server: Card & credential
rect rgb(225,240,255)
Note over Server,Risk: Risk assessment phase (new)
Server->>Risk: assess(transaction, card, credential, metadata)
Risk-->>Server: { level, score } or error/timeout
Server->>Server: attach exa.level/exa.score to trace
end
alt High or Very High risk
rect rgb(255,230,230)
Server->>Server: capture error (high risk)
Server->>Feedback: send negative feedback (optional)
Server-->>Client: 200 (handled + alarm)
end
else Low/Medium risk
rect rgb(230,255,235)
Server->>DB: Create/Update transaction
DB-->>Server: Persisted transaction
Server->>Feedback: send issuing feedback (state, ids, amounts)
Feedback-->>Server: ack
Server-->>Client: 200 (normal response)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Summary of ChangesHello @nfmelendez, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a crucial security enhancement by integrating a transaction risk assessment service into the server's transaction processing flow. The primary goal is to proactively identify and flag potentially fraudulent or high-risk transactions, such as suspicious refunds or authorizations, to improve overall system security and prevent financial losses. The changes involve updating transaction data structures, implementing risk evaluation logic, and providing feedback to the risk assessment system. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new transaction risk assessment feature by integrating with a 'Sardine' service. The changes include importing the risk assessment utility, updating transaction schemas to incorporate new fields like merchantCategoryCode, merchantId, and authorizationMethod, and modifying transaction processing logic in server/hooks/panda.ts. Risk assessments are now performed for 'requested' transactions (including refunds and verifications) and 'completed' transactions, with high-risk outcomes leading to error capturing. Additionally, the PR adds new tests to verify the alarming of high-risk authorizations and refunds. Review comments highlight that missing card records should throw a server-side error (5xx) instead of returning a 404, that transaction reversals should be reported as 'refund' instead of 'settled' to the risk service, and suggest refactoring duplicated risk assessment result handling logic into a helper function.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #607 +/- ##
==========================================
+ Coverage 48.41% 49.32% +0.90%
==========================================
Files 41 41
Lines 6985 7102 +117
Branches 501 526 +25
==========================================
+ Hits 3382 3503 +121
+ Misses 3586 3581 -5
- Partials 17 18 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
.changeset/wet-games-relate.mdserver/hooks/panda.tsserver/test/hooks/panda.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
server/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server.mdc)
server/**/*.ts: Usec.varobject to pass strongly-typed data between Hono middleware and route handlers; do not usec.set
All request validation (headers, body, params) must be handled by@hono/valibot-validatormiddleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwingnew HTTPException()for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLintplugin:n/recommendedconfiguration
Enforce Drizzle ORM best practices using ESLintplugin:drizzle/allconfiguration, including requiringwhereclauses forupdateanddeleteoperations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not accessprocess.envdirectly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; useasync/awaitcorrectly and be mindful of CPU-intensive tasks to prevent blocking the event loop
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{js,ts,tsx,jsx,sol}
📄 CodeRabbit inference engine (AGENTS.md)
Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No
anytype.
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Omit redundant type names in variable declarations - let the type system explain itself
**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas usingtype User = v.Input<typeof UserSchema>instead of manually defining interfaces
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation
**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Preferconstfor all variable declarations by default; only useletif the variable's value will be reassigned
Declare each variable on its own line with its ownconstorletkeyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always useimport type { ... }for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), andfor...ofloops over traditional syntax
Do not use abbreviations or cryptic names; write out full words likeerror,parameters,requestinstead oferr,params,req
UseNumber.parseInt()instead of the globalparseInt()function when parsing numbers
All classes called withnewmust use PascalCase
UseBuffer.from(),Buffer.alloc(), orBuffer.allocUnsafe()instead of the deprecatednew Buffer()
Use@ts-expect-errorinstead of@ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like-or:
Do not include the type in a variable's name; let the static type system do its job (e.g., useconst user: Usernotconst userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
server/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - usec.var.db
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
For files with a single
defaultexport, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/.changeset/*.md
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
Use a lowercase sentence in the imperative present tense for changeset summaries
Files:
.changeset/wet-games-relate.md
🧬 Code graph analysis (1)
server/hooks/panda.ts (1)
server/utils/sardine.ts (2)
risk(36-38)feedback(33-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Seer Code Review
- GitHub Check: test
🔇 Additional comments (10)
.changeset/wet-games-relate.md (1)
1-5: LGTM!The changeset follows the imperative present tense convention for the summary. The emoji prefix categorizes this as a feature addition.
server/hooks/panda.ts (6)
220-220: LGTM!Credential
idis now fetched alongsideaccountto support risk assessment and feedback calls.
252-259: High-risk refunds are alerted but not blocked.The current implementation captures an exception for monitoring but still returns
200 OKfor high-risk refunds. Verify this is the intended behavior—if blocking is desired, you would need to return an error status instead.
280-287: LGTM!Consistent with the refund path—high-risk verification triggers alerts but does not block the authorization.
289-326: LGTM!Good use of
Promise.allto parallelize the trace call and risk assessment, reducing latency in the authorization flow.
649-666: LGTM!Feedback hooks correctly map action types to authorization/settlement statuses, with amounts included only for settlements.
75-82: Verify that all Panda webhook sources providemerchantCountry.The schema change at line 75 from
v.nullish(v.string())tov.string()makesmerchantCountryrequired. Transactions missing this field will fail validation (returning 400). Confirm with the Panda service team that all webhook sources consistently send this field.server/test/hooks/panda.test.ts (3)
8-8: LGTM!Sardine mock import is correctly placed with other mock imports at the top of the file.
252-274: LGTM!Test correctly validates that high-risk authorizations trigger exception capture while still returning a successful response.
276-303: LGTM!Test correctly validates the high-risk refund flow with a negative amount, verifying exception capture without blocking the transaction.
|
@cursor review |
PR SummaryRisk assessment integrated into Panda transaction flows
Schema and validation adjustments
Stability and observability
Tests
Chore
Written by Cursor Bugbot for commit b305917. This will update automatically on new commits. Configure here. |
There was a problem hiding this comment.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
server/test/hooks/panda.test.ts (1)
252-303: Add tests for edge cases as previously discussed.Per the previous review, additional test coverage is still needed for:
- Risk assessment timeout (returning
{ status: "timeout", level: "unknown", score: 0 })very_highrisk level behavior- Non-timeout errors from risk assessment (returning
{ status: "error", level: "unknown", score: 0 })
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
.changeset/wet-games-relate.mdserver/hooks/panda.tsserver/test/hooks/panda.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
server/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server.mdc)
server/**/*.ts: Usec.varobject to pass strongly-typed data between Hono middleware and route handlers; do not usec.set
All request validation (headers, body, params) must be handled by@hono/valibot-validatormiddleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwingnew HTTPException()for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLintplugin:n/recommendedconfiguration
Enforce Drizzle ORM best practices using ESLintplugin:drizzle/allconfiguration, including requiringwhereclauses forupdateanddeleteoperations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not accessprocess.envdirectly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; useasync/awaitcorrectly and be mindful of CPU-intensive tasks to prevent blocking the event loop
Files:
server/hooks/panda.tsserver/test/hooks/panda.test.ts
**/*.{js,ts,tsx,jsx,sol}
📄 CodeRabbit inference engine (AGENTS.md)
Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No
anytype.
Files:
server/hooks/panda.tsserver/test/hooks/panda.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Omit redundant type names in variable declarations - let the type system explain itself
**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas usingtype User = v.Input<typeof UserSchema>instead of manually defining interfaces
Files:
server/hooks/panda.tsserver/test/hooks/panda.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation
**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Preferconstfor all variable declarations by default; only useletif the variable's value will be reassigned
Declare each variable on its own line with its ownconstorletkeyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always useimport type { ... }for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), andfor...ofloops over traditional syntax
Do not use abbreviations or cryptic names; write out full words likeerror,parameters,requestinstead oferr,params,req
UseNumber.parseInt()instead of the globalparseInt()function when parsing numbers
All classes called withnewmust use PascalCase
UseBuffer.from(),Buffer.alloc(), orBuffer.allocUnsafe()instead of the deprecatednew Buffer()
Use@ts-expect-errorinstead of@ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like-or:
Do not include the type in a variable's name; let the static type system do its job (e.g., useconst user: Usernotconst userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...
Files:
server/hooks/panda.tsserver/test/hooks/panda.test.ts
server/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - usec.var.db
Files:
server/hooks/panda.tsserver/test/hooks/panda.test.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
For files with a single
defaultexport, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word
Files:
server/hooks/panda.tsserver/test/hooks/panda.test.ts
**/.changeset/*.md
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
Use a lowercase sentence in the imperative present tense for changeset summaries
Files:
.changeset/wet-games-relate.md
🧠 Learnings (2)
📚 Learning: 2025-12-23T19:56:43.671Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.671Z
Learning: Applies to contracts/**/*.t.sol : Use fuzz testing (testFuzz_...) extensively for functions with numerical or address inputs to cover a wide range of scenarios
Applied to files:
server/test/hooks/panda.test.ts
📚 Learning: 2025-12-23T19:58:16.563Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.563Z
Learning: Applies to contracts/**/*.test.sol : Smart contracts testing: fuzzing required for inputs and gas snapshots mandatory
Applied to files:
server/test/hooks/panda.test.ts
🧬 Code graph analysis (1)
server/hooks/panda.ts (1)
server/utils/sardine.ts (2)
risk(36-38)feedback(33-35)
🔇 Additional comments (6)
server/hooks/panda.ts (5)
225-252: LGTM - Error handling now returns consistent fallback for all error types.The
assess()function now correctly returns a consistent fallback object{ status: "error"|"timeout", level: "unknown", score: 0 }for all error cases, ensuring downstream code receives a predictable structure. This addresses the previous review feedback.
291-328: LGTM - Parallel execution of trace and risk assessment.Good use of
Promise.allto run the trace call and risk assessment concurrently, improving authorization latency. The risk level is properly recorded on the span and high-risk transactions are captured as errors.
651-669: LGTM - Switch statement now handles all action types.The switch statement correctly handles "created", "updated", and "completed" actions for feedback. The "updated" case was added as noted in the previous review.
480-496: Verify edge case: partial capture sends "settled" feedback.When
payload.body.spend.amount > 0but less thanauthorizedAmount(partial capture with refund), this sends a "settled" feedback with the partial amount. Confirm this is the intended behavior for Sardine's feedback API, as the partial refund portion is handled separately via the refund transaction.
539-547: Confirm negative amount handling in "created" action is intentional.This block sends "authorization approved" feedback for negative amounts (refunds) in the "created" action. This is now reachable after the merge conflict fix. Verify this is the correct feedback type for refund authorizations.
server/test/hooks/panda.test.ts (1)
252-303: LGTM - High-risk scenario tests properly validate error capture.Both tests correctly:
- Mock the Sardine risk assessment to return high-risk responses
- Use unique card IDs for test isolation
- Verify that
captureExceptionis called with the appropriate error message- Confirm the response status is 200 (authorization proceeds but logs the risk)
fa6988c to
0c21650
Compare
95e76aa to
b305917
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
.changeset/wet-games-relate.md (1)
5-5: Changeset summary still contains emoji.Based on learnings, the changeset summary should be a lowercase sentence in the imperative present tense without emoji:
assess transaction risk.🔎 Suggested fix
-✨ assess transaction risk +assess transaction risk
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
.changeset/wet-games-relate.mdserver/hooks/panda.tsserver/test/hooks/panda.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/.changeset/*.md
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
Use a lowercase sentence in the imperative present tense for changeset summaries
Files:
.changeset/wet-games-relate.md
server/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server.mdc)
server/**/*.ts: Usec.varobject to pass strongly-typed data between Hono middleware and route handlers; do not usec.set
All request validation (headers, body, params) must be handled by@hono/valibot-validatormiddleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwingnew HTTPException()for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLintplugin:n/recommendedconfiguration
Enforce Drizzle ORM best practices using ESLintplugin:drizzle/allconfiguration, including requiringwhereclauses forupdateanddeleteoperations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not accessprocess.envdirectly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; useasync/awaitcorrectly and be mindful of CPU-intensive tasks to prevent blocking the event loop
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{js,ts,tsx,jsx,sol}
📄 CodeRabbit inference engine (AGENTS.md)
Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No
anytype.
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Omit redundant type names in variable declarations - let the type system explain itself
**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas usingtype User = v.Input<typeof UserSchema>instead of manually defining interfaces
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation
**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Preferconstfor all variable declarations by default; only useletif the variable's value will be reassigned
Declare each variable on its own line with its ownconstorletkeyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always useimport type { ... }for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), andfor...ofloops over traditional syntax
Do not use abbreviations or cryptic names; write out full words likeerror,parameters,requestinstead oferr,params,req
UseNumber.parseInt()instead of the globalparseInt()function when parsing numbers
All classes called withnewmust use PascalCase
UseBuffer.from(),Buffer.alloc(), orBuffer.allocUnsafe()instead of the deprecatednew Buffer()
Use@ts-expect-errorinstead of@ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like-or:
Do not include the type in a variable's name; let the static type system do its job (e.g., useconst user: Usernotconst userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
server/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - usec.var.db
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
For files with a single
defaultexport, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
🧠 Learnings (4)
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: Applies to **/.changeset/*.md : Use a lowercase sentence in the imperative present tense for changeset summaries
Applied to files:
.changeset/wet-games-relate.md
📚 Learning: 2025-12-23T19:57:14.465Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/git.mdc:0-0
Timestamp: 2025-12-23T19:57:14.465Z
Learning: Select the most precise gitmoji that best communicates the intent of the change (e.g., ✨ for new feature, 🐛 for bug fix, ♻️ for refactoring, ⚡️ for performance improvement, 📝 for documentation, 🚀 for deployment)
Applied to files:
.changeset/wet-games-relate.md
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Use fuzz testing (testFuzz_...) extensively for functions with numerical or address inputs to cover a wide range of scenarios
Applied to files:
server/test/hooks/panda.test.ts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Applies to contracts/**/*.test.sol : Smart contracts testing: fuzzing required for inputs and gas snapshots mandatory
Applied to files:
server/test/hooks/panda.test.ts
🧬 Code graph analysis (2)
server/test/hooks/panda.test.ts (2)
server/database/schema.ts (1)
cards(25-34)server/utils/sardine.ts (1)
feedback(33-35)
server/hooks/panda.ts (1)
server/utils/sardine.ts (2)
risk(36-38)feedback(33-35)
🔇 Additional comments (13)
server/test/hooks/panda.test.ts (3)
8-8: LGTM!Sardine mock and utility imports are correctly added to support the new risk assessment tests.
Also applies to: 53-53
234-270: LGTM!Good addition of feedback verification for the negative amount flow. The test correctly validates that Sardine feedback is sent with the expected issuing data structure.
1475-1475: LGTM!The
merchantCountryvalue correctly updated to ISO alpha-2 code format ("AR") to align with the new schema validation requiring exactly 2 characters.server/hooks/panda.ts (10)
56-56: LGTM!Clean import of
riskandfeedbackfunctions from sardine utility.
225-252: Well-structured risk assessment with consistent error handling.The
assess()function now returns a consistent object shape for all error cases, addressing the previous concern about implicitundefinedreturns. The timeout vs other error distinction is preserved in thestatusfield.
254-261: LGTM!Risk assessment for refunds (negative amounts) correctly logs high-risk transactions as errors while allowing the authorization to proceed.
282-328: LGTM!The parallel execution of
traceCallandassessviaPromise.allis efficient. Risk attributes are properly attached to the active span for observability.
480-496: LGTM!Feedback correctly differentiates between refund (negative amount) and settled (positive amount) for completed transactions.
527-547: LGTM!Feedback integration for declined transactions and negative amount authorizations is correctly implemented. The decline reason is properly forwarded to Sardine.
573-582: LGTM!Good handling of the no-call path with appropriate feedback type based on action (
authorizationfor created/updated,settlementfor completed).
651-669: LGTM!The switch statement now correctly handles
"updated"action alongside"created", addressing the previous concern about missing feedback for update-with-collection scenarios.
220-220: LGTM!Credential fetch correctly expanded to include
idfor Sardine customer identification.
74-82: Schema changes are intentional for risk assessment; verify with Panda documentation.
merchantCountryandmerchantCategoryCodeare required because the risk assessment integration depends on these fields (passed ascountryCodeandmcc). Existing tests consistently show Panda provides both fields, but you should confirm with Panda's API documentation that these fields are guaranteed in all webhook payloads before deploying to production.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
.changeset/wet-games-relate.md (1)
5-5: Changeset summary still contains emoji.The previous review already flagged that the summary should be a lowercase imperative present tense sentence (e.g., "assess transaction risk" instead of "✨ assess transaction risk"). You acknowledged you would fix this, but it appears unchanged. Based on learnings, changeset summaries must use lowercase imperative present tense.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
.changeset/wet-games-relate.mdserver/hooks/panda.tsserver/test/hooks/panda.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
server/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/server.mdc)
server/**/*.ts: Usec.varobject to pass strongly-typed data between Hono middleware and route handlers; do not usec.set
All request validation (headers, body, params) must be handled by@hono/valibot-validatormiddleware; do not perform manual validation inside route handlers
Use Hono's built-in error handling by throwingnew HTTPException()for expected errors; unhandled errors will be caught and logged automatically
Enforce Node.js best practices using ESLintplugin:n/recommendedconfiguration
Enforce Drizzle ORM best practices using ESLintplugin:drizzle/allconfiguration, including requiringwhereclauses forupdateanddeleteoperations
Use Drizzle ORM query builder for all database interactions; do not write raw SQL queries unless absolutely unavoidable
All authentication and authorization logic must be implemented in Hono middleware
Do not accessprocess.envdirectly in application code; load all configuration and secrets once at startup and pass them through dependency injection or context
Avoid long-running, synchronous operations; useasync/awaitcorrectly and be mindful of CPU-intensive tasks to prevent blocking the event loop
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{js,ts,tsx,jsx,sol}
📄 CodeRabbit inference engine (AGENTS.md)
Follow linter/formatter (eslint, prettier, solhint) strictly with high strictness level. No
anytype.
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Omit redundant type names in variable declarations - let the type system explain itself
**/*.{ts,tsx}: Use PascalCase for TypeScript types and interfaces
Use valibot for all runtime validation of API inputs, environment variables, and other data; define schemas once and reuse them
Infer TypeScript types from valibot schemas usingtype User = v.Input<typeof UserSchema>instead of manually defining interfaces
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Omit contextual names - don't repeat class/module names in members
Omit meaningless words like 'data', 'state', 'manager', 'engine', 'value' from variable and function names unless they add disambiguation
**/*.{ts,tsx,js,jsx}: Prefer function declarations for all multi-line functions; use function expressions or arrow functions only for single-line implementations
Preferconstfor all variable declarations by default; only useletif the variable's value will be reassigned
Declare each variable on its own line with its ownconstorletkeyword, not multiple declarations on one line
Use camelCase for TypeScript variables and functions
Always useimport type { ... }for type imports
Use relative paths for all imports within the project; avoid tsconfig path aliases
Follow eslint-plugin-import order: react, external libraries, then relative paths
Use object and array destructuring to access and use properties
Use object method shorthand syntax when a function is a property of an object
Prefer optional chaining (?.), nullish coalescing (??), object and array spreading (...), andfor...ofloops over traditional syntax
Do not use abbreviations or cryptic names; write out full words likeerror,parameters,requestinstead oferr,params,req
UseNumber.parseInt()instead of the globalparseInt()function when parsing numbers
All classes called withnewmust use PascalCase
UseBuffer.from(),Buffer.alloc(), orBuffer.allocUnsafe()instead of the deprecatednew Buffer()
Use@ts-expect-errorinstead of@ts-ignore; follow it immediately with a single-line lowercase comment explaining why the error is expected, without separators like-or:
Do not include the type in a variable's name; let the static type system do its job (e.g., useconst user: Usernotconst userObject: User)
Do not repeat the name of a class or module within its members; omit contextual names (e.g., use `class User { getProfil...
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
server/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
server/**/*.{ts,tsx}: Server API: implement schema-first approach using OpenAPI via hono with validation via valibot middleware
Server database: drizzle schema is source of truth. Migrations required. No direct database access in handlers - usec.var.db
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
For files with a single
defaultexport, name the file identically to the export; for files with multiple exports, use camelCase with a strong preference for a single word
Files:
server/test/hooks/panda.test.tsserver/hooks/panda.ts
**/.changeset/*.md
📄 CodeRabbit inference engine (.cursor/rules/style.mdc)
Use a lowercase sentence in the imperative present tense for changeset summaries
Files:
.changeset/wet-games-relate.md
🧠 Learnings (4)
📚 Learning: 2025-12-23T19:56:43.683Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/contracts.mdc:0-0
Timestamp: 2025-12-23T19:56:43.683Z
Learning: Applies to contracts/**/*.t.sol : Use fuzz testing (testFuzz_...) extensively for functions with numerical or address inputs to cover a wide range of scenarios
Applied to files:
server/test/hooks/panda.test.ts
📚 Learning: 2025-12-23T19:58:16.574Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-23T19:58:16.574Z
Learning: Applies to contracts/**/*.test.sol : Smart contracts testing: fuzzing required for inputs and gas snapshots mandatory
Applied to files:
server/test/hooks/panda.test.ts
📚 Learning: 2025-12-30T15:03:28.449Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/style.mdc:0-0
Timestamp: 2025-12-30T15:03:28.449Z
Learning: Applies to **/.changeset/*.md : Use a lowercase sentence in the imperative present tense for changeset summaries
Applied to files:
.changeset/wet-games-relate.md
📚 Learning: 2025-12-23T19:57:14.465Z
Learnt from: CR
Repo: exactly/exa PR: 0
File: .cursor/rules/git.mdc:0-0
Timestamp: 2025-12-23T19:57:14.465Z
Learning: Select the most precise gitmoji that best communicates the intent of the change (e.g., ✨ for new feature, 🐛 for bug fix, ♻️ for refactoring, ⚡️ for performance improvement, 📝 for documentation, 🚀 for deployment)
Applied to files:
.changeset/wet-games-relate.md
🧬 Code graph analysis (1)
server/hooks/panda.ts (1)
server/utils/sardine.ts (2)
risk(36-38)feedback(33-35)
🔇 Additional comments (16)
server/hooks/panda.ts (12)
56-56: LGTM!Clean import of risk assessment and feedback utilities from the sardine module.
97-97: Verify Panda doesn't sendnullfordeclinedReason.Changed from
v.nullabletov.optional. If Panda sendsnullinstead of omitting the field, validation will fail. Ensure this matches the actual webhook payload format.
225-252: LGTM! Consistent error handling for risk assessment.The
assess()function now returns a consistent fallback object for all error cases, addressing the previous review concern. The distinction between "timeout" and "error" status is useful for observability.
254-261: LGTM! Risk assessment for refunds with appropriate alerting.High-risk refunds are flagged via
captureExceptionbut allowed to proceed, which is appropriate for refund flows where blocking could negatively impact customer experience while still maintaining observability.
282-288: LGTM!Risk assessment for verification path follows the same pattern as other flows.
291-328: LGTM! Good use of parallel execution.Running
traceCallandassess()in parallel viaPromise.allreduces latency without sacrificing the risk assessment data. Risk results are properly attached to tracing spans for observability.
480-496: LGTM! Proper settlement feedback for refund flows.Correctly distinguishes between refunds (negative amount →
status: "refund") and partial captures (positive amount →status: "settled"). Fire-and-forget with error capture is appropriate for non-blocking feedback.
527-538: LGTM!Declined authorization feedback correctly reports
network_declinedstatus with the decline reason for Sardine's analysis.
539-548: LGTM!Negative amount authorization feedback is correctly placed and reachable after the earlier refactoring.
573-583: LGTM!Feedback correctly differentiates between authorization (
created/updated) and settlement (completed) when no collection call is needed.
651-669: LGTM! Complete feedback coverage for all action types.The switch statement now correctly handles
created,updated, andcompletedactions, addressing the previous review concern about missing theupdatedcase.
74-82: Verify that Panda webhooks always providemerchantCountryandmerchantCategoryCode.The schema now enforces both fields as required (
merchantCountrymust be 2 characters,merchantCategoryCodemust be present), with no defensive fallback if either is missing. All tests provide these fields, but if actual Panda payloads sometimes omit them, validation will fail and reject the transaction. Confirm with Panda that these fields are guaranteed in all webhook events.server/test/hooks/panda.test.ts (4)
8-8: LGTM!Sardine mock imported correctly for test isolation.
187-205: LGTM! Timeout error mock correctly setserror.name.The mock now properly sets
error.name = "TimeoutError"to trigger the timeout branch in the error handler, addressing the previous review feedback.
236-272: LGTM! Good feedback verification for negative amounts.The test properly verifies that the
feedbackfunction is called with the expected parameters for negative amount (refund) authorizations.
1477-1477: LGTM!Test fixtures correctly updated to use 2-letter ISO country code ("AR") matching the new schema validation.
closes #604
Summary by CodeRabbit
New Features
Improvements
Tests
Chore
✏️ Tip: You can customize this high-level summary in your review settings.