Skip to content

feat/face-compare-api-addition#1331

Open
RahulGupta0706 wants to merge 1 commit into
mainfrom
feat/face-compare-api-addition
Open

feat/face-compare-api-addition#1331
RahulGupta0706 wants to merge 1 commit into
mainfrom
feat/face-compare-api-addition

Conversation

@RahulGupta0706

@RahulGupta0706 RahulGupta0706 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates

Description

Additional Changes

  • This PR modifies the database schema (database migration added)
  • This PR modifies dhall configs/environment variables

Motivation and Context

How did you test it?

Checklist

  • I formatted the code and addressed linter errors ./dev/format-all-files.sh
  • I reviewed submitted code
  • I added unit tests for my changes where possible
  • I added a CHANGELOG entry if applicable

Summary by CodeRabbit

  • New Features

    • Added synchronous face-compare for document↔selfie and document↔document checks.
    • Results include match score, per-image details and a review recommendation; exposed via the verification interface and implemented for the Idfy provider.
  • Configuration

    • Added configurable retry limit for face-compare with retry behaviour and a user-facing error if retries are exhausted.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

A new face comparison endpoint is introduced across the Idfy client library and verification interface. Request and response types are defined at both the Idfy provider level and the generic interface level. The Idfy client implements the HTTP call via Servant. An adapter bridges interface types to the Idfy client, and a dispatcher routes requests to Idfy or returns "Not Implemented" for other providers.

Changes

Face Comparison Feature

Layer / File(s) Summary
Type definitions and data schemas
lib/mobility-core/src/Kernel/External/Verification/Interface/Types.hs, lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Request.hs, lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Response.hs
Interface DTO types FaceCompareReq and FaceCompareResp wrap document pairs and optional Idfy response data. Idfy request type FaceCompareRequestBody carries two document identifiers. Idfy response types FaceCompareResponseData and FaceImageResult model face detection results, match scores, and recommendation flags with JSON/schema derivations.
Idfy HTTP client and Servant API
lib/mobility-core/src/Kernel/External/Verification/Idfy/Client.hs
Servant API type FaceCompareAPI routes to the compare endpoint. Client function faceCompare sends FaceCompareRequest via shared callIdfyAPI helper and returns FaceCompareResponse.
Interface Idfy adapter function
lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs
Adapter faceCompare constructs an Idfy request from input documents, decrypts API credentials, calls the Idfy client, and wraps the result into FaceCompareResp format, retrying per IdfyCfg.faceCompareRetryLimit when needed.
Provider dispatch and routing
lib/mobility-core/src/Kernel/External/Verification/Interface.hs
Router function faceCompare dispatches requests to Idfy.faceCompare when IdfyConfig is present and returns InternalError "Not Implemented!" for other provider types (GovtDataConfig, FaceVerificationConfig, HyperVerge*, DigiLockerConfig, TtenVerificationConfig, MorthConfig).
Idfy configuration
lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs
Adds faceCompareRetryLimit :: Maybe Int to IdfyCfg to control retry attempts in the adapter.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant IdfyClient
  participant IdfyService
  Client->>IdfyClient: faceCompare(FaceCompareRequest)
  IdfyClient->>IdfyService: POST /v3/tasks/sync/compare/face
  IdfyService-->>IdfyClient: FaceCompareResponse
  IdfyClient-->>Client: FaceCompareResponse
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • RitikaHanish

Poem

🐰 I hopped through types and client land,
I stitched requests with steady hand,
Idfy calls and retries bright,
face-compare bound, the flow takes flight,
🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat/face-compare-api-addition' clearly and specifically describes the main change—the addition of a new face comparison API endpoint to the verification module.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feat/face-compare-api-addition

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.

@RahulGupta0706

Copy link
Copy Markdown
Contributor Author

@ClaudeWeb please review

@khuzema786

Copy link
Copy Markdown
Contributor

I'll fetch the PR details, diff, and run a security scan in parallel.Let me try using the GitHub MCP tools instead.Now let me get the changed files and look at the diff.Now let me look at the surrounding context in the existing source files to compare patterns.Now let me check the existing Idfy request/response types and the Interface/Idfy.hs for patterns around document1/document2 field types.Let me check the Response.hs export list and the existing NameCompare response pattern for completeness.I have a complete picture of all 5 changed files and the full codebase context. Here is the review.


PR Review: feat/face-compare-api-addition

Verdict: Approve with minor concerns. The implementation is structurally correct and faithfully follows the established nameCompare pattern. No bugs, no security issues. A couple of design points worth raising.


Warning

1. PR description is completely empty (confidence: 92)

None of the checkboxes are checked, no description of what is being compared or why, no testing methodology. Given that this is a new biometric API integration involving face images, the PR template fields (motivation, test evidence) are important for reviewers and future git archaeology.


Suggestion

2. FaceCompareReq leaks the Idfy field names through the interface (confidence: 68)

File: Interface/Types.hs

data FaceCompareReq = FaceCompareReq
  { document1 :: Text,   -- what is this? selfie? license face crop?
    document2 :: Text,
    driverId  :: Text
  }

Compare with NameCompareReq, where the interface type uses domain-meaningful names that are then mapped to Idfy's generic field names:

data NameCompareReq = NameCompareReq
  { extractedName :: Text,   -- meaningful
    verifiedName  :: Text,   -- meaningful
    ...
  }
-- mapped in Interface/Idfy.hs to name1 / name2

document1/document2 are opaque — callers won't know which image is the selfie and which is the document face. Suggested fix:

data FaceCompareReq = FaceCompareReq
  { selfieImage   :: Text,  -- base64-encoded selfie
    documentImage :: Text,  -- base64-encoded face crop from ID document
    driverId      :: Text
  }

Then map in Interface/Idfy.hs:

Idfy.FaceCompareRequestBody
  { document1 = req.selfieImage,
    document2 = req.documentImage
  }

3. FaceCompareResp exposes a vendor-specific type at the interface boundary (confidence: 65)

File: Interface/Types.hs

newtype FaceCompareResp = FaceCompareResp
  { faceComparedData :: Maybe Idfy.FaceCompareResponseData
  }

This is the same pattern used by NameCompareResp and is a pre-existing design choice, so it's consistent. However, as more vendor-specific types accumulate in the interface layer, migrating to another provider (e.g. HyperVerge for face compare) would require a breaking interface change. Worth tracking if multi-provider face compare is ever planned.


Code Quality: No issues found

  • The Servant API route (/v3/tasks/sync/compare/face) and HTTP method (Post) match the Idfy sync compare endpoint.
  • FaceCompareResponseData and FaceImageResult are correctly typed with Maybe fields throughout — consistent with how all other Idfy response types handle optional fields.
  • Response.hs uses an open export (module ... where), so FaceCompareResponseData and FaceImageResult are automatically exported — no missing exports.
  • The callIdfyAPI invocation pattern in Client.hs is identical to nameCompare — correct.
  • All throwError $ InternalError "Not Implemented!" cases in Interface.hs for non-Idfy providers are consistent with every other function in that file.

@RahulGupta0706

Copy link
Copy Markdown
Contributor Author

Checked ClaudeWeb comments . nothing critical

@RahulGupta0706 RahulGupta0706 force-pushed the feat/face-compare-api-addition branch from c35c0ce to 3caec28 Compare June 5, 2026 10:17
@RitikaHanish

Copy link
Copy Markdown
Member

@ClaudeWeb Can you review, if errors are handled properly ?

@khuzema786

Copy link
Copy Markdown
Contributor

Let me do a focused error handling review across all changed files.Let me fetch callIdfyAPI and the nameCompare equivalent to compare error handling patterns.Now I have everything needed. Here is the focused error handling review.


Error Handling Review — feat/face-compare-api-addition

How the call chain works

callIdfyAPI
  └── callApiUnwrappingApiError (identity @IdfyError)
        → HTTP 4xx/5xx  : throws IdfyError         ✓
        → network error : throws exception          ✓
        → JSON parse    : throws exception          ✓
        → HTTP 200 with status="failed", result=Nothing : returns normally ✗

callIdfyAPI handles transport-level failures cleanly. The gap is entirely at the application level inside Interface/Idfy.hs.


Critical — Silent failure when Idfy reports a processing error (confidence: 92)

File: lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs

This is a synchronous API (/v3/tasks/sync/compare/face). When Idfy processing fails (e.g. unreadable image, internal error), it still returns HTTP 200 but with status = "failed" and result = null. The current code passes that through silently:

resp <- Idfy.faceCompare apiKey accountId url idfyReq
pure
  FaceCompareResp
    { faceComparedData = resp.result   -- Nothing on Idfy processing failure
    }

The caller receives FaceCompareResp { faceComparedData = Nothing } with no signal that the comparison actually failed. For a biometric identity-verification call, this is a real risk — upstream code may interpret Nothing as "comparison not available, proceed anyway" rather than "hard error."

Compare with getTask, the only place in this file that correctly guards against a missing result:

-- getTask — the right pattern
result <- resp.result & fromMaybeM (InternalError ("Missing result in getTask response: " <> show resp))

Suggested fix for Interface/Idfy.hs:

faceCompare cfg req = do
  let url = cfg.url
  apiKey    <- decrypt cfg.apiKey
  accountId <- decrypt cfg.accountId
  let reqData = Idfy.FaceCompareRequestBody
        { document1 = req.document1
        , document2 = req.document2
        }
  idfyReq  <- buildIdfyRequest req.driverId reqData
  resp     <- Idfy.faceCompare apiKey accountId url idfyReq
  result   <- resp.result
               & fromMaybeM (InternalError $ "faceCompare: missing result, status=" <> resp.status)
  pure FaceCompareResp { faceComparedData = Just result }

Note: nameCompare has the same gap. It's a pre-existing issue, but face comparison carries higher risk because it is a binary identity-gate — a silent Nothing is not an acceptable ambiguous state there either.


Warning — face_detected = False is not guarded at the interface layer (confidence: 78)

File: lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Response.hs

data FaceImageResult = FaceImageResult
  { face_detected :: Maybe Bool
  , face_quality  :: Maybe Text
  }

When Idfy cannot detect a face in either image, face_detected comes back Just False (or Nothing). In that case, is_a_match and match_score in FaceCompareResponseData are unreliable. The current code returns this data to callers without any defensive check.

This is lower-severity because callers can check face_detected themselves, but a guard here would make misuse much harder:

-- in Interface/Idfy.hs, after obtaining `result`
let faceNotDetected = 
      result.image_1 >>= (.face_detected) == Just False ||
      result.image_2 >>= (.face_detected) == Just False
when faceNotDetected $
  throwError $ InternalError "faceCompare: face not detected in one or both images"

No issues found in

Layer Verdict
Client.hs HTTP transport errors callApiUnwrappingApiError handles 4xx/5xx/network
decrypt cfg.apiKey / cfg.accountId ✓ throws on decryption failure
buildIdfyRequest (GUID gen) ✓ monadic, no silent failure path
Interface.hs dispatcher throwError "Not Implemented!" ✓ non-Idfy configs fail loudly
JSON decode of FaceCompareResponseData ✓ all fields Maybe, Servant throws on parse failure

@RahulGupta0706 RahulGupta0706 force-pushed the feat/face-compare-api-addition branch 2 times, most recently from 0e06507 to a7dd9d8 Compare June 8, 2026 11:48

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs`:
- Line 26: IdfyCfg's faceCompareRetryLimit is currently Maybe Int with no
validation; update the decode/constructor to enforce a non-negative bounded
value (e.g., change the field to Maybe Natural/Word or validate in the FromJSON
instance for IdfyCfg) and apply a max cap constant (e.g.,
MAX_FACE_COMPARE_RETRIES) or reject out-of-range values, then ensure faceCompare
still uses retryLimit = fromMaybe 1 cfg.faceCompareRetryLimit but with the
validated/clamped value so negative or excessively large inputs are prevented;
modify the FromJSON for IdfyCfg (or a smart constructor) to perform this check
and return a parse error or clamp to the cap.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2886cb79-21cf-47f5-88de-12f63591df37

📥 Commits

Reviewing files that changed from the base of the PR and between 0e06507 and a7dd9d8.

📒 Files selected for processing (7)
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Client.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Request.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Response.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Types.hs
🚧 Files skipped from review as they are similar to previous changes (6)
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Client.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Types.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Request.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Response.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs

secret :: EncryptedField 'AsEncrypted Text,
url :: BaseUrl
url :: BaseUrl,
faceCompareRetryLimit :: Maybe Int

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all uses of faceCompareRetryLimit and whether any non-negative/bounded validation exists.
rg -n -C3 '\bfaceCompareRetryLimit\b|fromMaybe\s+1\s+cfg\.faceCompareRetryLimit|callWithRetry\s*\(' \
  lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs \
  lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs

Repository: nammayatri/shared-kernel

Length of output: 2361


🏁 Script executed:

#!/bin/bash
# Inspect callWithRetry definition and any handling of retryLimit/attemptsLeft <= 0
rg -n "callWithRetry|attemptsLeft" lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs -n

Repository: nammayatri/shared-kernel

Length of output: 212


🏁 Script executed:

#!/bin/bash
# Show the surrounding implementation area for callWithRetry
sed -n '470,560p' lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs

Repository: nammayatri/shared-kernel

Length of output: 3378


🏁 Script executed:

#!/bin/bash
# Inspect Config.hs around the IdfyCfg definition and the faceCompareRetryLimit field
sed -n '1,120p' lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs

Repository: nammayatri/shared-kernel

Length of output: 1269


🏁 Script executed:

#!/bin/bash
# Search whole repo for any other uses/validation of faceCompareRetryLimit
rg -n "\bfaceCompareRetryLimit\b" -S .

Repository: nammayatri/shared-kernel

Length of output: 310


Constrain faceCompareRetryLimit to a non-negative, bounded value

IdfyCfg defines faceCompareRetryLimit :: Maybe Int with derived FromJSON (no validation), and the only consumer is retryLimit = fromMaybe 1 cfg.faceCompareRetryLimit in faceCompare. Negative values make attemptsLeft > 0 false immediately (no retries, early failure), while very large values can amplify external-call retries and latency. Add non-negative/bounded validation at the config decode boundary (e.g., Maybe Natural/Word plus a max cap) and/or clamp/explicitly reject out-of-range values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs` at line
26, IdfyCfg's faceCompareRetryLimit is currently Maybe Int with no validation;
update the decode/constructor to enforce a non-negative bounded value (e.g.,
change the field to Maybe Natural/Word or validate in the FromJSON instance for
IdfyCfg) and apply a max cap constant (e.g., MAX_FACE_COMPARE_RETRIES) or reject
out-of-range values, then ensure faceCompare still uses retryLimit = fromMaybe 1
cfg.faceCompareRetryLimit but with the validated/clamped value so negative or
excessively large inputs are prevented; modify the FromJSON for IdfyCfg (or a
smart constructor) to perform this check and return a parse error or clamp to
the cap.

@RahulGupta0706 RahulGupta0706 force-pushed the feat/face-compare-api-addition branch from a7dd9d8 to 06bb283 Compare June 9, 2026 14:30
@coderabbitai coderabbitai Bot requested a review from RitikaHanish June 9, 2026 14:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs`:
- Around line 551-553: The code returns FaceCompareResp {faceComparedData = Just
result} for any Just result; update the case handling for resp.result to first
verify the face-detection flags on the returned result (the detection fields on
result) are present and true, and only then set faceComparedData to Just result;
if any detection flag is false or missing, throw/return InternalError instead of
returning faceComparedData. Ensure this validation is implemented where
resp.result is matched (the Just result branch) and that the error uses the
existing InternalError type/constructor used elsewhere in this module.
- Around line 548-555: The current retry loop regenerates idfyReq (and its
task_id) each attempt in callWithRetry by calling buildIdfyRequest(req.driverId
reqData) inside the recursion; change the logic to build idfyReq once before
starting retries and pass that same idfyReq into callWithRetry (or convert
callWithRetry to accept an idfyReq parameter) so Idfy.faceCompare always
receives the same payload; update references to idfyReq inside callWithRetry and
keep the same retry/decrement logic and error handling around Idfy.faceCompare
and the attemptsLeft parameter.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb64f86a-75d1-4562-a88c-c08cada6e8d3

📥 Commits

Reviewing files that changed from the base of the PR and between a7dd9d8 and 06bb283.

📒 Files selected for processing (7)
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Client.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Request.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Response.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Types.hs
🚧 Files skipped from review as they are similar to previous changes (6)
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Client.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Request.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Types/Response.hs
  • lib/mobility-core/src/Kernel/External/Verification/Idfy/Config.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface.hs
  • lib/mobility-core/src/Kernel/External/Verification/Interface/Types.hs

Comment on lines +548 to +555
let callWithRetry attemptsLeft = do
idfyReq <- buildIdfyRequest req.driverId reqData
resp <- Idfy.faceCompare apiKey accountId url idfyReq
case resp.result of
Just result -> pure FaceCompareResp {faceComparedData = Just result}
Nothing
| attemptsLeft > 0 -> callWithRetry (attemptsLeft - 1)
| otherwise -> throwError $ InternalError "Please contact customer support, as face match cannot be done."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid regenerating task_id on retries; reuse one request payload.

Line 549 currently rebuilds the request per retry, generating a new GUID each time. For external compare APIs this can create duplicate non-idempotent operations. Build idfyReq once before retry recursion and reuse it across attempts.

Suggested fix
 faceCompare cfg req = do
   let url = cfg.url
       retryLimit = fromMaybe 1 cfg.faceCompareRetryLimit
   apiKey <- decrypt cfg.apiKey
   accountId <- decrypt cfg.accountId
   let reqData =
         Idfy.FaceCompareRequestBody
           { document1 = req.selfieImage,
             document2 = req.documentImage
           }
-  let callWithRetry attemptsLeft = do
-        idfyReq <- buildIdfyRequest req.driverId reqData
+  idfyReq <- buildIdfyRequest req.driverId reqData
+  let callWithRetry attemptsLeft = do
         resp <- Idfy.faceCompare apiKey accountId url idfyReq
         case resp.result of
           Just result -> pure FaceCompareResp {faceComparedData = Just result}
           Nothing
             | attemptsLeft > 0 -> callWithRetry (attemptsLeft - 1)
             | otherwise -> throwError $ InternalError "Please contact customer support, as face match cannot be done."
   callWithRetry retryLimit
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs` around
lines 548 - 555, The current retry loop regenerates idfyReq (and its task_id)
each attempt in callWithRetry by calling buildIdfyRequest(req.driverId reqData)
inside the recursion; change the logic to build idfyReq once before starting
retries and pass that same idfyReq into callWithRetry (or convert callWithRetry
to accept an idfyReq parameter) so Idfy.faceCompare always receives the same
payload; update references to idfyReq inside callWithRetry and keep the same
retry/decrement logic and error handling around Idfy.faceCompare and the
attemptsLeft parameter.

Comment on lines +551 to +553
case resp.result of
Just result -> pure FaceCompareResp {faceComparedData = Just result}
Nothing

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate success on face-detection validity before returning match data.

At Line 552, success is returned for any Just result, but face-compare outputs are unreliable when one or both images have no detected face. Please enforce a validation guard on the detection flags and throw InternalError when detection is false/missing instead of returning faceComparedData.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/mobility-core/src/Kernel/External/Verification/Interface/Idfy.hs` around
lines 551 - 553, The code returns FaceCompareResp {faceComparedData = Just
result} for any Just result; update the case handling for resp.result to first
verify the face-detection flags on the returned result (the detection fields on
result) are present and true, and only then set faceComparedData to Just result;
if any detection flag is false or missing, throw/return InternalError instead of
returning faceComparedData. Ensure this validation is implemented where
resp.result is matched (the Just result branch) and that the error uses the
existing InternalError type/constructor used elsewhere in this module.

deriving (Show, Generic, FromJSON, ToJSON, ToSchema)

data FaceCompareReq = FaceCompareReq
{ selfieImage :: Text,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can keep generic names. Order doesn't matter anyway

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.

4 participants