Fraud scoring, as scripts see it. The division of labour is deliberate, and follows anomaly detection: this side owns the score arithmetic, the band decision and the persisted record, because those want unit tests and must behave identically whichever app asked, while the app side owns the rule definitions and their queries, because that is where the criteria builders and the app providers already live and because a rule's query belongs with the app that owns the data. Scoring is additive, not averaged: a rule's weight is a number of risk points, and the score is the sum of value times weight, capped at 100 - averaging was the obvious alternative and is wrong here, because with ten rules configured, two strong signals firing at full strength would average to 20 and could never reach a block threshold no matter how damning they were, whereas adding points keeps each rule's contribution stable as rules are added. A rule that throws contributes a failed signal, worth no points, and is reported on the event; it is never treated as a rule that fired.
Group: Managers
Properties
| Property | Returns | Description |
|---|---|---|
| anonymousProxy | boolean | Whether the current request's IP is a known anonymising proxy. Indexed on every web hit by MaxMind, so this costs nothing extra to ask. |
| store | FraudPolicyStore | Where this account's rule overrides, custom rules and thresholds live. |
Methods
getStore() · newContextBuilder() · newSignalBuilder() · newSignalList() · decide(FraudContext context, List<FraudSignal> signals) · decide(FraudContext context, List<FraudSignal> signals, FraudThresholds thresholds) · recordDecision(FraudContext context, FraudDecision decision) · calcSummary(FraudDecision decision) · findCurrentLocation() · findCurrentCountryCode() · isAnonymousProxy() · findCurrentIp()
getStore()
Returns: FraudPolicyStore
Where this account's rule overrides, custom rules and thresholds live.
newContextBuilder()
Returns: Builder
Start building the operation to be scored.
newSignalBuilder()
Returns: Builder
Start building one rule's contribution to a score.
newSignalList()
Returns: List<FraudSignal>
A fresh mutable list for a script to accumulate signals into, since building a Java list from script is awkward.
decide(FraudContext context, List<FraudSignal> signals)
Returns: FraudDecision
Score an operation using this account's stored thresholds.
| Parameter | Description |
|---|---|
context | the operation being scored. Must not be null |
signals | what the rules found. Must not be null, but may be empty |
decide(FraudContext context, List<FraudSignal> signals, FraudThresholds thresholds)
Returns: FraudDecision
Score an operation against given thresholds. Pure computation: no queries, no persistence, no events - that is what makes the arithmetic testable independently of everything around it.
| Parameter | Description |
|---|---|
context | the operation being scored. Must not be null |
signals | what the rules found. Must not be null, but may be empty |
thresholds | where the band boundaries sit. Must not be null |
recordDecision(FraudContext context, FraudDecision decision)
Returns: FraudEvent
Persist a decision and announce it, if it is worth recording. A clear score is neither stored nor announced: recording every checkout that was fine would be a great deal of noise for no information. Everything from the watch band up is stored and announced, including scores that reached the block band while blocking was switched off - which is precisely the data calibration needs.
| Parameter | Description |
|---|---|
context | the operation that was scored. Must not be null |
decision | what was decided. Must not be null |
calcSummary(FraudDecision decision)
Returns: String
A short human-readable account of which rules fired and by how much, strongest first.
| Parameter | Description |
|---|---|
decision | the decision to describe. Must not be null |
findCurrentLocation()
Returns: CityResponse
The current request's client location, for a rule that needs to know where this operation came from.
findCurrentCountryCode()
Returns: String
The two-letter country code the current request came from.
isAnonymousProxy()
Returns: boolean
Whether the current request's IP is a known anonymising proxy. Indexed on every web hit by MaxMind, so this costs nothing extra to ask.
findCurrentIp()
Returns: String
The client IP for the current request, as the fraud rules should see it.