The rule
No outbound touch (email, sequence enrollment, postcard, HS push, campaign add) of ANY kind to anyone on the DNC list. This is a hard gate, not a soft warning. Violating it is what caused the Froelich incident (2026-04-22) and 3 additional customer leaks found 2026-04-23.
Data source
/Users/josephbowens/Desktop/SkyRun/DNC_active_homeowners.json — canonical union of:
1. Rachel's active-homeowner list (Winter_Park_Active_Homeowners_YYYY-MM-DD.xlsx) — authoritative
2. HubSpot customers — contacts with lifecyclestage=customer, contact_type=Home Owner, or relationship_to_the_property contains "Current Owner"
3. Track active-account owners — supplementary, for owners outside Winter Park
Structure:
emails(141+) — exact-matchphones_last10(97+) — last 10 digitsname_tokens(263+) — fuzzy name match (2+ specific tokens overlap)refreshed— ISO timestamprefresh_cadence— monthly from Rachel; nightly-consolidation Section J flags if stale >45d
The check function
~/Library/Application Support/SkyRun/dnc_check.py — Python callable:
bash
echo '{"email":"...","phone":"+1...","name":"Last First"}' | python3 "/Users/josephbowens/Library/Application Support/SkyRun/dnc_check.py"
Returns: {"hit": true, "reason": "email_match|phone_match|name_fuzzy", "match": "..."}
Or: {"hit": false}
Two-tier check pattern
Every outreach skill must use BOTH tiers:
Tier 1 — Local DNC (instant, required first):
- Call
dnc_check.pywith whatever identifiers you have - If
hit=true, BLOCK and logskipped_current_owners - No Tier 2 needed for this record
Tier 2 — HS live check (catches owners added since DNC refresh):
- Call
is_current_owner(email)via HS CSRF fetch (see~/Library/Application Support/SkyRun/current_owner_check.md) - If returns
true, BLOCK - If returns
null(API error), treat as "unknown" — BLOCK (fail safely)
Wired into these skills
- ✅
live-eaStep 4c — before drafting any reply - ✅
daily-beenverified-enrichmentStep 7b — before SmartLead push - ✅
daily-data-quality-checkStep 5G — nightly enrollee audit - ✅
grand-county-property-scoutStep 1b — before adding any new lead - ✅
nightly-consolidationSection J — rebuild DNC + audit all outbound channels
Nightly rebuild (Section J of nightly-consolidation)
Every night:
1. Check Rachel's file freshness (alert if >45 days stale)
2. Rebuild DNC.json as union of Rachel + HS customers + Track
3. Audit every outbound channel (SmartLead × 3 campaigns, SoT, pending_drafts, pending_postcards) against DNC
4. Check HS for lifecycle mismatches (customer-type contacts with non-customer lifecycle)
5. Any total_leaks > 0 or HS_LIFECYCLE_MISMATCH → morning brief priority #1 + ntfy-urgent push
How to get a refreshed Rachel list
Ask Rachel for a re-export from Track of all active Winter Park homeowners with emails + phones. She has done this before — the canonical format is 27 columns starting with "Unit Name". Monthly cadence is sufficient.
Audit history / incidents
- 2026-04-22 Froelich incident: John Froelich got cold outreach because HS sequence filtered on
lead_statusnotlifecyclestage. Response: builtis_current_owner()check + wired into 3 skills. - 2026-04-22 HS sequence drain: 25 cold emails fired from paused HS sequences (queue-not-flushed). Remediation: deleted sequences + HS removed from outreach entirely.
- 2026-04-23 comprehensive audit: Rachel's canonical list integrated. Found 3 more current-customer leaks in SmartLead HOT+WARM (abuckner, planghans, mbirkhead), 9 current customers in SoT prospecting list, 8 HS lifecycle mismatches. All remediated. DNC file + two-tier check system built and wired into all 5 outbound skills + nightly consolidation.
Files
/Users/josephbowens/Desktop/SkyRun/DNC_active_homeowners.json— canonical list/Users/josephbowens/Desktop/SkyRun/Winter_Park_Active_Homeowners_2026-04-23.xlsx— Rachel's source~/Library/Application Support/SkyRun/dnc_check.py— check function~/Library/Application Support/SkyRun/current_owner_check.md— HS live check (Tier 2)/Users/josephbowens/Desktop/SkyRun/Current Owner Audit 2026-04-22/— audit workspace + backups + remediation log