Predictive Models Reference
Flash's predictive layer is a glass box: twelve classic, deterministic models — no black-box scoring. Every model is pure TypeScript, deterministic by construction (fixed optimizers and schedules, no random init, no sampling — the same data always produces the same model, so a score change always traces to a data change), refit nightly per tenant from that tenant's own data, and honesty-gated: below each model's stated minimum of real history, the output is NULL/absent — surfaces render nothing rather than a guess. Predictions rank and suggest; execution stays behind the platform's approvals, caps and consent checks.
This page is the per-model engineering reference: what each model computes, its method, inputs, outputs and where they land, its honesty gates, and the surfaces that consume it. For the business-facing story see the Predictive Intelligence product page; for the governance rails every model runs behind, see the AI Governance guide.
Four guarantees, shared by every model
Deterministic by construction
Every model is pure TypeScript with fixed optimizers and schedules — no random initialization, no sampling. The same data always produces the same model, so a score change always traces to a data change.
Refit nightly, per tenant
Each model is refit every night from that tenant's own data — its own ledger, its own sends, its own orders. No cross-tenant pooling.
Honesty-gated
Below each model's stated minimum of real history, the output is NULL/absent — surfaces render nothing rather than a guess. Every gate is listed on this page.
Rank and suggest, never execute
Predictions rank and suggest; execution stays behind the platform's approvals, caps and consent checks. No model moves money or contacts a member on its own.
The twelve models
1. Churn risk & 12-month CLV
For every buyer: the probability the customer has silently lapsed (churn_risk, 0–100) and the expected spend over the next twelve months (predicted_clv_12m).
| Method | BG/NBD — a Pareto-family purchase-pattern model of purchase frequency and dropout — combined with a Gamma-Gamma spend model. Both are fitted per team, per night, via deterministic Nelder-Mead. |
| Inputs | The purchase ledger — the team's own point-earn transactions — as the single source of each member's purchase history. Nothing outside the tenant's ledger. |
| Outputs & where they land | member_behavior_rollup columns: churn_risk (0–100, computed as 100 × (1 − P(alive))), predicted_clv_12m (E[repeat transactions in 365 days] × E[spend per transaction]) and predictive_confidence. |
| Honesty gates | Team fit gates: ≥200 buyers, ≥50 repeat buyers, and both fits must converge. Gamma-Gamma additionally requires a finite population mean — otherwise CLV falls back to the member's own mean spend, stated as the weaker basis. Member gates: non-buyers are never scored; fewer than 3 purchases or under 2 months of history → NULL. |
| Consumption surfaces | The profile's Predictive Outlook, the churn_risk and predicted_clv_12m segment conditions, win-back ranking, and recommended-action cards. |
2. Expected next purchase date
When each member's next purchase is expected, and how wide the window around that date is. The expected date may be in the past — that is a deliberate, honest overdue signal, not a bug.
| Method | A method-of-moments Gamma view of the member's own inter-purchase gaps. |
| Inputs | The same earn-transaction SSOT as churn/CLV — the member's observed gaps between their own purchases. |
| Outputs & where they land | next_order_expected_at (may be in the past = overdue) and next_order_window_days (± the sample standard deviation, minimum 1 day). |
| Honesty gates | ≥3 observed gaps, coefficient of variation ≤1.5 (an irregular rhythm is refused, never guessed), and a mean gap ≥0.25 days — otherwise NULL. |
| Consumption surfaces | The profile tile and the days_until_expected_order segment condition (negative = overdue; the replenishment audience is “between −14 and 3”). |
3. Click propensity
P(click | send) for each member, expressed as click_propensity on a 0–100 scale.
| Method | Per-team L2-regularized logistic regression over the last 90 days of sends, trained by deterministic full-batch gradient descent on a fixed schedule. The label is clicks ONLY — opens are excluded because Apple MPP prefetch inflates them. A leakage guard ensures each training send's prior-click-rate feature excludes that send's own outcome, and one shared feature builder serves both training and scoring, so training and scoring rows cannot drift apart. |
| Inputs | The team's own last 90 days of send outcomes. |
| Outputs & where they land | click_propensity (0–100) plus propensity_computed_at. |
| Honesty gates | Team fit gates: ≥500 sends, ≥30 clicks, ≥50 distinct members. Member gate: ≥3 recent sends — otherwise NULL. |
| Consumption surfaces | The profile tile and the click_propensity segment condition. |
4. Best time to send
Each member's preferred engagement hour in their own local timezone, and an audience-level hour recommendation for a whole send.
| Method | An engagement-hour histogram per member over 90 days, in the member's local timezone: clicks weighted 3× non-proxy opens, bots excluded, Apple MPP proxy-opens dropped. The preferred hour is the circularly smoothed mode (hour 23 and hour 0 are neighbours). |
| Inputs | 90 days of the member's own engagement events, mapped to the member's local timezone. |
| Outputs & where they land | preferred_send_hour (0–23, local) plus send_timing_sample. The audience recommendation is the mode over the audience's preferred hours, reported with coverage counts. |
| Honesty gates | A member without qualifying engagement history has no preferred hour. When auto-apply finds no signal it keeps the caller's configured time — it never silently delays a send. |
| Consumption surfaces | The schedule-step card, the preferred_send_hour segment condition, and auto-apply via the send API (optimizeSendTime), which schedules the next occurrence of the recommended hour. |
5. A/B traffic auto-optimization
Hourly delivery-weight allocations across a recurring campaign's experiment variants, from live click performance.
| Method | A deterministic allocator over live per-variant clicks: the Laplace-smoothed posterior-mean CTR is raised to a temperature, then normalized above a 10% per-arm exploration floor. It never declares a statistical winner — that remains the separate formal A/B verdict. |
| Inputs | Live per-variant delivery and click counts for the campaign. |
| Outputs & where they land | The latest allocation is overlaid at send time — the configured split is never mutated. Every hourly recompute appends one row to the bandit_allocations decision log with the weights applied and a human-readable rationale. |
| Honesty gates | Recurring campaigns only (automation/journey), opt-in per campaign. Traffic stays at an even split until every arm has ≥100 deliveries — no reallocation on thin data. |
| Consumption surfaces | The send-time weight overlay on opted-in recurring campaigns; the append-only bandit_allocations log is the audit surface. |
6. Win-back uplift
Which at-risk members the win-back agent should work first — a persuadability-aware rank, not just value at risk.
| Method | Two-model logistic uplift on the program's own randomized holdout experiment: uplift(x) = P(convert | treated, x) − P(convert | holdout, x). Per-member arms are immutable; conversion = ≥1 order in the attribution window. |
| Inputs | Matured winback_attribution rows. Features come from the task's enqueue-time snapshot when present, else the current rollup (stated as an approximation). |
| Outputs & where they land | The worklist rank key = value-at-risk × uplift. Negative uplift (do-not-disturb) sinks to the bottom, floored at priority 0. task.reason carries the full arithmetic. |
| Honesty gates | ≥200 matured treated rows, ≥50 matured holdout rows, ≥20 conversions, and both fits must converge — otherwise ranking stays pure value-at-risk. |
| Consumption surfaces | SoClaw win-back worklist ordering — the ranked queue the agent claims tasks from. |
The worklist itself — claiming tasks, levers, completion — is documented in the SoClaw Win-Back Integration guide.
7. Item-similarity (item-kNN)
“Also bought” product-to-product similarity.
| Method | A nightly co-purchase materialization scored by cosine-normalized co-occurrence: co_count / sqrt(buyers(A) × buyers(B)) — the normalization corrects popularity bias. The raw co_count is kept as a column, as inspectable evidence. |
| Inputs | The tenant's own co-purchase history — who bought what together. |
| Outputs & where they land | Materialized item-pair similarity scores, with the raw co-occurrence count stored alongside each score. |
| Honesty gates | Pairs need ≥2 shared buyers to materialize. Thin or cold cases fall back to category top-sellers, then global top-sellers; cold members get nothing rather than random products. |
| Consumption surfaces | The email Recommendations block, the member portal, and the public + v2 recommendation APIs. |
8. Association rules
Cross-sell rules of the form “buyers of A also buy B”, with support, confidence and lift.
| Method | Order-level product pairs mined nightly. Thresholds: ≥3 pair-orders and ≥5% confidence; the top 25 rules per antecedent are kept, ranked by lift. |
| Inputs | The merchant's own order lines. |
| Outputs & where they land | catalog_association_rules rows carrying support / confidence / lift plus the raw counts they derive from (pair, antecedent and consequent order counts) — so every metric is recomputable by hand. |
| Honesty gates | ≥3 pair-orders and ≥5% confidence — below that, no rule exists. |
| Consumption surfaces | The profile cross-sell action card — active buyers only, with already-owned products excluded. |
9. Lookalike similarity
How similar every member of the base is to a seed audience, with a per-member breakdown of why.
| Method | Seed → Rocchio centroid: IDF-weighted tag cosine similarity + Gower-normalized numeric distance (RFM, purchase count, recency), plus profile fusion when the seed has the data — value-tier match, primary-category match, churn-outlook proximity — with weights renormalized over the dimensions actually PRESENT, so a seed with no profile data degrades exactly to the tag + numeric tier. |
| Inputs | The seed members' tags, numeric behavior (RFM, purchase count, recency) and profile fields, matched against the tenant's own member base. |
| Outputs & where they land | Per-member similarity scores with per-dimension breakdowns that power the “Why they're similar” summary. |
| Honesty gates | Small seeds get shrinkage plus an explicit warning rather than confident scores. |
| Consumption surfaces | The find-lookalike audience flow. In-base only — lookalikes are never uploaded to ad platforms. |
10. Behavior-outlier fraud detector
Whether a member's 30-day points activity is an extreme statistical outlier against the team's own member distribution.
| Method | Per-team robust statistics over 30-day points activity — earn transaction count, earned points, ledger redemptions — median + MAD per feature, robust z = 0.6745 × (x − median) / MAD, flag at z ≥ 6 AND ≥10 earn transactions. |
| Inputs | 30 days of the team's own points activity, per member. |
| Outputs & where they land | A freeze on the member's still-present points plus a fraud_points_hold review task. A flag only freezes points for review — it never voids on its own. The reason payload carries per-feature value / median / robust-z. |
| Honesty gates | Teams under 50 active members are skipped entirely (no meaningful baseline); MAD = 0 features are skipped; already-frozen members are never piled on; dedup is month-bucketed. |
| Consumption surfaces | The points-fraud review worklist. |
The freeze-then-verdict pipeline this detector feeds — holds, verdict semantics, admin controls — is documented in the Points Fraud Protection guide.
11. Retention survival (KM + Cox)
Retention curves per monthly signup cohort, and which member attributes correlate with retention.
| Method | Kaplan-Meier product-limit curves per monthly signup cohort; the churn event is 90 days without a purchase (churn time = last purchase + 90 days), recent purchasers are right-censored, never-purchasers are excluded. Cox proportional hazards via Breslow partial likelihood, maximized with the same deterministic Nelder-Mead. |
| Inputs | The tenant's own signup and purchase history. |
| Outputs & where they land | Cohort survival curves, and Cox hazard ratios rendered as plain sentences — with ratios between 0.95 and 1.05 reported as “no meaningful difference”, and everything labelled correlation, not causation. |
| Honesty gates | Cohorts need ≥30 members; curves never extrapolate beyond a cohort's observed horizon. The Cox fit is capped at 3 covariates, needs ≥30 events, and returns null on non-convergence. |
| Consumption surfaces | The retention cohort view and its correlates panel. |
12. Revenue outlook (Holt-Winters)
A 14-day daily revenue forecast with an honest error band.
| Method | Additive triple exponential smoothing with weekly seasonality m = 7 and FIXED constants α = 0.3, β = 0.05, γ = 0.3 — self-tuning is a deliberate non-goal — deterministically initialized from the first two seasons. |
| Inputs | Daily GMV read through the certified metrics semantic layer (no second aggregation); missing days densified to $0; zeros before the first sale trimmed. |
| Outputs & where they land | A 14-day forecast, clamped ≥0, with a band = in-sample mean absolute one-step error × 1.5 (a stated basis, not a distributional confidence interval). |
| Honesty gates | ≥28 days of nonzero history — otherwise null, and nothing renders. |
| Consumption surfaces | The dashboard revenue outlook. |
Consuming the scores
The member-level scores land as rollup columns and flow outward through four surfaces, in order of increasing reach:
- Rollup columns. Nightly refits write the per-member scores (
churn_risk,predicted_clv_12m,click_propensity,preferred_send_hour,next_order_expected_at…) onto the member behavior rollup — NULL wherever a gate wasn't met. - Segment conditions. Six predictive conditions target on the scores:
churn_risk,predicted_clv_12m,preferred_send_hour,click_propensity,days_until_expected_order, plus tags. A member whose score is NULL simply never matches — segments inherit the honesty gates. - Member profile API / insights payload. The same scores ship in the member profile read surface, so what an integrator reads is exactly what the profile page shows.
- MCP for agents. AI agents read the scores through
get_member_profileon the governed MCP server — same data, behind the same scopes and governance.
For the business-facing story of these capabilities, see Predictive Intelligence; for the approval gears, decision logs and PII masking every model operates behind, see AI Governance: Introspection & Approvals.