Transaction Fraud Report Part 4 — Smart Fraud Error Reporting
Problem statement
Four-part sequence: This is Part 4 of one progressive transaction-fraud interview exercise. It retains Parts 1–3 and adds prioritized error reporting.
- Part 1: Verify Transaction Data Integrity.
- Part 2: High-Risk Rule Validation.
- Part 3: User Behavior Matching.
- Part 4: Smart Fraud Error Reporting (you are here).
Implement the final cumulative behavior: check six CSV fields, apply two high-risk rules, compare behavior with a user baseline, and report prioritized errors.
Input
Each string in transactions is one unquoted CSV row with exactly six comma-separated fields, in this order: transaction_id,user_id,amount,payment_method,country,hour. Trim surrounding whitespace from every field. A field containing only whitespace is empty. Rows are processed in input order, and repeated transaction IDs remain separate rows.
Each row of baselines has six strings: [user_id,usual_country,start_hour,end_hour,min_amount,max_amount]. Every nonempty transaction row has exactly one matching user baseline. Hour and amount intervals are inclusive and do not wrap. Numeric fields on nonempty rows are valid decimal integers.
Review rules
- If any transaction field is empty, assign only
MISSING_FIELD. Do not run the later levels for that row. - Otherwise, assign
AMOUNT_OUT_OF_RANGEwhen the amount is outside the inclusive global interval[normalMin, normalMax]. AssignBLOCKED_METHODwhen the payment method appears inblockedMethods; membership is case-sensitive. - Compare the transaction with its user's baseline on three features: exact country, hour inside the baseline interval, and amount inside the baseline interval. If fewer than two of the three features match, assign
BEHAVIOR_MISMATCH. This is the at-least-50% matching threshold for three features.
Report
Return a string table. Its first row is ["transaction_id","status","error_1","error_2"]. Append one four-cell row for every transaction, keeping the original transaction ID as its first cell, including an empty ID when that field is missing.
For each transaction, collect error codes in this priority order: MISSING_FIELD, AMOUNT_OUT_OF_RANGE, BLOCKED_METHOD, BEHAVIOR_MISMATCH. Put only the first two codes in the final two cells, using an empty string for any unused code cell. Use status OK when there is no error; otherwise use SUSPICIOUS. The four-cell rows form an aligned columnar report.
Function
buildFraudReport(transactions: String[], baselines: String[][], normalMin: int, normalMax: int, blockedMethods: String[]) → String[][]Examples
Example 1
transactions = ["tx1,u1,500,card,US,10","tx2,u1,50,cash,CA,20","tx3,u1,550,card,CA,10","tx4,u1,550,card,CA,20","tx5,u1,,card,US,10"]baselines = [["u1","US","9","17","400","600"]]normalMin = 100normalMax = 1000blockedMethods = ["cash"]return = [["transaction_id","status","error_1","error_2"],["tx1","OK","",""],["tx2","SUSPICIOUS","AMOUNT_OUT_OF_RANGE","BLOCKED_METHOD"],["tx3","OK","",""],["tx4","SUSPICIOUS","BEHAVIOR_MISMATCH",""],["tx5","SUSPICIOUS","MISSING_FIELD",""]]tx1 passes every check. tx2 violates the global amount rule and blocked-method rule; its behavior also mismatches, but only the first two priority codes are reported. tx3 matches hour and amount, so two of three baseline features pass. tx4 matches only amount. tx5 has an empty amount and stops after integrity validation.
Example 2
transactions = ["edge,u2,100,Card,US,0"," ,u2,100,Card,US,0"]baselines = [["u2","US","0","0","100","100"]]normalMin = 100normalMax = 100blockedMethods = ["card"]return = [["transaction_id","status","error_1","error_2"],["edge","OK","",""],["","SUSPICIOUS","MISSING_FIELD",""]]The global and baseline interval endpoints are inclusive. Card does not equal blocked method card. The second row's trimmed transaction ID is empty, so no later check runs.
Constraints
1 <= transactions.length <= 10000; every row has exactly six CSV fields and contains no quoted commas.1 <= baselines.length <= 10000; user IDs are unique across baseline rows.0 <= normalMin <= normalMax <= 1000000000.- Every nonempty transaction amount and baseline amount bound is an integer from
0through1000000000. - Every nonempty transaction hour and baseline hour bound is an integer from
0through23, and each baseline lower bound is at most its upper bound. - Every nonempty transaction user ID appears in
baselines. All identifiers, country labels, and method labels have at most 100 characters.