Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 3x 3x 3x 47x 45x 45x 45x 37x 8x | /**
* The velocity flag (FR-F-5).
*
* > "Submissions/day exceeding the partner's stated monthly closings band
* > raises a flag for review (flag, not auto-block)."
*
* FLAG, NOT BLOCK — said twice in the requirement and honoured here: nothing in
* this module refuses anything. A partner having a good week looks exactly like
* a partner inventing referrals, and the difference is a judgement an operator
* makes with the thread in front of them.
*
* THE DENOMINATOR IS OFTEN MISSING. `partners.closings_band` is optional at
* signup and is set nowhere else, so a large share of partners have no stated
* band at all. The rule therefore returns `no_band` explicitly rather than
* silently passing — an operator reading "not flagged" for a partner we could
* never have flagged is being told something false.
*
* Arithmetic only: no database, no clock.
*/
import type { PARTNER_CLOSINGS_BANDS } from "../../db/schema/enums";
export type ClosingsBand = (typeof PARTNER_CLOSINGS_BANDS)[number];
/**
* The TOP of each band, as monthly closings.
*
* The top, not the middle, because this is a fraud trigger and the cost of the
* two errors is not symmetric: flagging an honest partner wastes an operator's
* afternoon and insults someone doing well, while missing one costs money that
* has already gone out. Reading "2-3" as 3 makes the rule fire later and less
* often, which is the right direction for a signal a human then reads.
*
* `7+` is open-ended, so its top is a stated assumption rather than a fact —
* 12 is roughly three a week, past which "closings" and "referrals" have
* stopped meaning the same thing anyway.
*/
const BAND_TOP: Record<ClosingsBand, number> = {
"0-1": 1,
"2-3": 3,
"4-6": 6,
"7+": 12,
};
/**
* How many referrals in a day it takes to look unlike the band.
*
* A partner who closes 3 deals a month does not introduce 3 people a day, but
* they might well introduce several in one afternoon after a site visit. The
* multiple keeps a good day from being an accusation; the floor keeps the
* smallest band from firing on two referrals.
*/
const DAILY_MULTIPLE = 2;
const MINIMUM_TO_FLAG = 4;
export type VelocityVerdict =
| { flagged: false; reason: "no_band" | "within_band" }
| {
flagged: true;
referralsToday: number;
/** What the band says they close in a month. */
bandTop: number;
band: ClosingsBand;
};
export function velocityFlag(input: {
band: ClosingsBand | null;
referralsToday: number;
}): VelocityVerdict {
// Not "fine" — unanswerable. The distinction has to survive to the screen.
if (!input.band) return { flagged: false, reason: "no_band" };
const bandTop = BAND_TOP[input.band];
const threshold = Math.max(MINIMUM_TO_FLAG, bandTop * DAILY_MULTIPLE);
if (input.referralsToday < threshold) {
return { flagged: false, reason: "within_band" };
}
return {
flagged: true,
referralsToday: input.referralsToday,
bandTop,
band: input.band,
};
}
|