Skip to main content
score is an explainable roll-up over the returned signals: it is reproducible from the signals shown plus the published table below. Phase 1 is a transparent rule engine with equal weight for every signal, so the base score is the mean of the resolved contributions.

The published table

The table is versioned data, published alongside the scorer. A score is reproducible from the signals shown plus this table; calibrating the numbers is a data change and a version bump, not a silent re-scoring.
The response does not carry the table version today — data[].{score, band, reason, signals, input, correlation_id} is the whole scored item — so recompute against the version published here.

Band overrides and reason

A dominant check can override the band and set the reason. When several apply, the first one here sets the reason:
  1. any *_name_match = false → reason: name_mismatch, band forced to high_risk;
  2. any *_profile_match = false → reason: profile_contradiction, band forced to high_risk;
  3. phone_connectivity or premium_phone_connectivity = false → reason: phone_disconnected (band from the score);
  4. phone_type = false or phone_ported = false → reason: line_risk (band from the score).
The precedence settles the reason only. The band is the most severe band named by any override that fired, and only where that band is more severe than the score-derived one. A false *_name_match therefore lands high_risk even when another row publishes the reason. If no override fires, reason is the lowest-scoring resolved signal, named by its signal key.

Recomputing a score

Take the signals map, turn each resolved verdict into a contribution with the table, average them, round with the half_up rule, then apply the overrides.
half_up is applied to the exact decimal weighted mean. Recompute in decimal, not binary floating point: once a calibrated table carries a fractional weight, ordinary double arithmetic can land an exact x.5 just under the tie and round the wrong way. A decimal or rational library reproduces the published integer; double may not.

Worked example — a consistent identity

The requested email resolves to no one, so email_name_match is null and drops out of the denominator.
Result (GET /v1/signals/rq_7a1d)
Recompute: contributions 50 + 90/2 = 95, 50 + 98/2 = 99, 50 + 76/2 = 88; email_name_match is null and excluded. Mean (95 + 99 + 88) / 3 = 94 → score: 94, band clear (≥ 75). No override fired, so reason is the lowest-scoring resolved signal, phone_profile_match (88).

Worked example — a name mismatch

The phone is live but belongs to a different name and profile, so name_mismatch fires and forces high_risk.
Delivery
Recompute: contributions 50 − 100/2 = 0, 50 + 94/2 = 97, 50 − 78/2 = 11. Mean (0 + 97 + 11) / 3 = 36. phone_name_match is false, so name_mismatch fires and forces high_risk regardless of the score → score: 36, band high_risk, reason name_mismatch.