trucking builder: widen catch-all bounce window 2d->5d to stop volume whipsaw

A 2-day guardrail window let one bad daily batch (Jun-24: 465 sent / 10.75%)
flip catch-all OFF, starving daily volume to ~200/day -- which then could not
reach the 300-sent min sample to ever re-enable (self-reinforcing trap). The
same period over 5 days is a true ~3.8% (7,995 sent / 303 bounced), well under
the 8% ceiling, so catch-all stays ON and steady ~3k/day flows. Still trips
fast on a sustained real spike.
This commit is contained in:
justin 2026-06-26 23:48:31 -05:00
parent 48fb9f7fbb
commit f3442872f2

View file

@ -612,11 +612,16 @@ CATCH_ALL_RESULTS = ["catch_all_domain", "catch_all_detected"]
# lands on Google/Microsoft is still held out by big_mx_exclude until day 30.
CATCH_ALL_MIN_WARMUP_DAY = int(os.getenv("CAMPAIGN_CATCH_ALL_MIN_DAY", "21"))
# Recent-window bounce-rate ceiling (percent). At/above this, catch-all stays OFF
# and an already-on rollout auto-reverts. A SHORT window is deliberate: a
# historical disaster (e.g. the Jun-16 ~45% 7-day rate) must NOT block the
# rollout forever, and a fresh spike must trip it fast.
# and an already-on rollout auto-reverts. The window is kept short enough that a
# historical disaster (e.g. the Jun-16 ~45% 7-day rate) does NOT block the
# rollout forever, but long enough that a single bad daily batch cannot whipsaw
# the whole program: a 2-day window let one 10.75% day (Jun-24, 465 sent) flip
# catch-all OFF and starve volume to ~200/day, which then could not reach the
# min-sent sample to ever re-enable -- a self-reinforcing trap. A 5-day window
# smooths that same period to a true ~3.8% (7,995 sent / 303 bounced) and keeps
# steady ~3k/day flowing, while still tripping fast on a sustained real spike.
CATCH_ALL_MAX_BOUNCE_PCT = float(os.getenv("CAMPAIGN_CATCH_ALL_MAX_BOUNCE_PCT", "8"))
CATCH_ALL_BOUNCE_WINDOW_DAYS = int(os.getenv("CAMPAIGN_CATCH_ALL_BOUNCE_WINDOW_DAYS", "2"))
CATCH_ALL_BOUNCE_WINDOW_DAYS = int(os.getenv("CAMPAIGN_CATCH_ALL_BOUNCE_WINDOW_DAYS", "5"))
# Minimum sent volume required in the window before the rate is trusted (else a
# tiny sample like 9 sent / 1 bounce = 11% would wrongly gate the decision).
CATCH_ALL_BOUNCE_MIN_SENT = int(os.getenv("CAMPAIGN_CATCH_ALL_BOUNCE_MIN_SENT", "300"))