ATS automation health checklist

Yesterday I opened the dashboard to 14 auto-rejects on a brand-new CS req, and a quick audit showed our knockout regex was tagging any phone number without a country code because the form started saving dashes differently after a UI tweak. I can wire up stage-change webhooks and a weekly validation query to watch for spikes and rule drift, but before I reinvent this, does anyone have a lightweight checklist or dashboard template for monitoring ATS automations and data quality?

‌⁠‍⁠​‍​‍‌⁠‌​​‍​‍​⁠‍‍​‍​‍‌‍‌⁠‌⁠​‍‌‍‍‍​‍​‍​‍⁠​​‍​‍‌‍‍⁠​‍​‍​⁠‍‍​‍​‍‌‍⁠‍‌‍‌‌‌⁠‌⁠‌‌⁠⁠‌⁠‌​‌‍⁠⁠‌⁠​​‌‍‍‌‌‍​⁠​‍​‍​‍⁠​​‍​‍‌‍‍‌‌‍‌​​‍​‍​⁠‍‍​‍​‍‌‍⁠‍‌‍‌‌‌⁠‌⁠​‍​‍​‍⁠​​‍​‍‌‍‌​​‍​‍​⁠‍‍​‍​‍​⁠​‍​⁠​​​⁠​‍​⁠‌‌​⁠​​​⁠‍‌​⁠​‌​⁠‍​​‍​‍​‍⁠​​‍​‍‌‍‍​​‍​‍​⁠‍‍​‍​‍‌‌⁠⁠​⁠​‌‌‌⁠⁠‌⁠‌​‌‌​‌‌⁠‌‌‌⁠‍‌‌​‌‌‌‍‍‍‌​‍‌​⁠‌‌‌⁠‍‌‌​‌​‌⁠‍‌‌‍‍‌‌​⁠‍​‍​‍‌⁠⁠‌​​

We killed this class of bugs by normalizing phones to E.164 at ingest (libphonenumber) and keeping knockout rules in a config repo with a tiny test suite so UI dashes can’t break them. We also send a weekly canary application with weird-but-valid values and alert if it gets auto-rejected — want the normalizer snippet?

‌⁠‍⁠​‍​‍‌⁠‌​​‍​‍​⁠‍‍​‍​‍‌‍‌⁠‌⁠​‍‌‍‍‍​‍​‍​‍⁠​​‍​‍‌‍‍⁠​‍​‍​⁠‍‍​‍​‍‌⁠​‍‌‍‌‌‌⁠​​‌‍⁠​‌⁠‍‌​‍​‍​‍⁠​​‍​‍‌‍‍‌‌‍‌​​‍​‍​⁠‍‍​⁠​‍​⁠​​​⁠‌‍​⁠‌​​⁠‌‌​‍⁠​​‍​‍‌‍‌​​‍​‍​⁠‍‍​‍​‍​⁠​‍​⁠​​​⁠​‍​⁠‌‌​⁠​​​⁠‍‌​⁠​‍​⁠​‍​‍​‍​‍⁠​​‍​‍‌‍‍​​‍​‍​⁠‍‍​‍​‍‌‍⁠‌‌‌‌‌‌​‌‍​⁠‌⁠‌⁠​⁠‌⁠‌​‌‍‍‌‌‍⁠‍‌‌‌‍‌​⁠⁠​⁠​‍‌‍‌​‌⁠​⁠‌⁠​‍​‍⁠‌‌‍‌​​‍​‍‌⁠⁠‌

We added a shadow mode for knockout changes: they score but don’t block for a week, we send daily counts with 3 sample apps to Slack, and auto-disable if the rate jumps >2x baseline — caught a phone formatting flip like this.

‌⁠‍⁠​‍​‍‌⁠‌​​‍​‍​⁠‍‍​‍​‍‌‍‌⁠‌⁠​‍‌‍‍‍​‍​‍​‍⁠​​‍​‍‌‍‍⁠​‍​‍​⁠‍‍​‍​‍‌⁠​‍‌‍‌‌‌⁠​​‌‍⁠​‌⁠‍‌​‍​‍​‍⁠​​‍​‍‌‍‍‌‌‍‌​​‍​‍​⁠‍‍​⁠​‍​⁠​​​⁠‌‍​⁠‌​​⁠‌‌​‍⁠​​‍​‍‌‍‌​​‍​‍​⁠‍‍​‍​‍​⁠​‍​⁠​​​⁠​‍​⁠‌‌​⁠​​​⁠‍‌​⁠​‍​⁠‌​​‍​‍​‍⁠​​‍​‍‌‍‍​​‍​‍​⁠‍‍​‍​‍‌‌‍‌‌⁠​​​‍⁠‌‌‍‍​‌‌‍‍‌​‍⁠‌‌‌‍‌⁠​​‌‍‍‍‌‍‌‍‌‌‍​‌‌‌⁠‌⁠‍​‌‍​‌​⁠​‌​⁠‍‌​‍​‍‌⁠⁠‌

Quick example: we keep a ‘golden’ set of synthetic applicants with edge‑case phones and replay them nightly through the ATS; if any decision changes, a diff posts to Slack with the ruleset commit and form version, like canaries for your rules. It caught a dash-format change last month before it hit candidates; small caveat: make sure your integrations ignore the fakes so they don’t email hiring managers.

‌⁠‍⁠​‍​‍‌⁠‌​​‍​‍​⁠‍‍​‍​‍‌‍‌⁠‌⁠​‍‌‍‍‍​‍​‍​‍⁠​​‍​‍‌‍‍⁠​‍​‍​⁠‍‍​‍​‍‌⁠​‍‌‍‌‌‌⁠​​‌‍⁠​‌⁠‍‌​‍​‍​‍⁠​​‍​‍‌‍‍‌‌‍‌​​‍​‍​⁠‍‍​⁠​‍​⁠​​​⁠‌‍​⁠‌​​⁠‌‌​‍⁠​​‍​‍‌‍‌​​‍​‍​⁠‍‍​‍​‍​⁠​‍​⁠​​​⁠​‍​⁠‌‌​⁠​​​⁠‍‌​⁠​‍​⁠‌‍​‍​‍​‍⁠​​‍​‍‌‍‍​​‍​‍​⁠‍‍​‍​‍‌​​‌‌‍⁠​‌‌‍‍‌​​‍‌‍‍​​⁠​​‌⁠‍‌​⁠‍​‌‌‌​‌‍⁠⁠‌‌​⁠‌​‌​‌‌‌‍‌‌​‍‌‌‍​‌‌‌‍​‍​‍‌⁠⁠‌

Borrowing @dlee82’s idea, we run a per-req “canary”: the first 25 apps only score and require a quick human approve before the knockout flips to block; if reject rate >10% we auto-park the rule, post 3 examples to Slack, and add a one-click “rescue” for anything caught in the last 24h. It slows day 1 by about 10 minutes, but it caught a date-format flip and saved us a week of cleanup.

‌⁠‍⁠​‍​‍‌⁠‌​​‍​‍​⁠‍‍​‍​‍‌‍‌⁠‌⁠​‍‌‍‍‍​‍​‍​‍⁠​​‍​‍‌‍‍⁠​‍​‍​⁠‍‍​‍​‍‌⁠​‍‌‍‌‌‌⁠​​‌‍⁠​‌⁠‍‌​‍​‍​‍⁠​​‍​‍‌‍‍‌‌‍‌​​‍​‍​⁠‍‍​⁠​‍​⁠​​​⁠‌‍​⁠‌​​⁠‌‌​‍⁠​​‍​‍‌‍‌​​‍​‍​⁠‍‍​‍​‍​⁠​‍​⁠​​​⁠​‍​⁠‌‌​⁠​​​⁠‍‌​⁠​⁠​⁠​​​‍​‍​‍⁠​​‍​‍‌‍‍​​‍​‍​⁠‍‍​‍​‍‌‌‍‍‌⁠‍‌‌​⁠‌‌‍‍‌​⁠​‍‌​⁠⁠‌‍​‍‌⁠‌‍‌⁠​​‌‌‌​‌‍‍⁠​⁠​⁠​⁠‌⁠‌⁠‍‌‌⁠​‌‌⁠‌‍​‍​‍‌⁠⁠‌

Normalize to E.164 via libphonenumber (GitHub - google/libphonenumber: Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers.) before knockouts; prevents country-code false rejects; tiny overhead.

‌⁠‍⁠​‍​‍‌⁠‌​​‍​‍​⁠‍‍​‍​‍‌‍‌⁠‌⁠​‍‌‍‍‍​‍​‍​‍⁠​​‍​‍‌‍‍⁠​‍​‍​⁠‍‍​‍​‍‌⁠​‍‌‍‌‌‌⁠​​‌‍⁠​‌⁠‍‌​‍​‍​‍⁠​​‍​‍‌‍‍‌‌‍‌​​‍​‍​⁠‍‍​⁠​‍​⁠​​​⁠‌‍​⁠‌​​⁠‌‌​‍⁠​​‍​‍‌‍‌​​‍​‍​⁠‍‍​‍​‍​⁠​‍​⁠​​​⁠​‍​⁠‌‌​⁠​‌​⁠​​​⁠​​​⁠‌‌​‍​‍​‍⁠​​‍​‍‌‍‍​​‍​‍​⁠‍‍​‍​‍‌‍​‌‌‍‌‍‌‍‌⁠‌​⁠⁠‌​⁠⁠‌⁠‌⁠‌‌​‍‌‍​‍‌​‍‍‌‌‍​‌‍‍‌‌​‌‌‌‌​⁠‌​​‌‌‌‌‌​‍⁠‌​‍​‍‌⁠⁠‌