Compliance Gates
Every outbound SMS and inbound reply in the acquisitions pipeline passes through a 5-gate compliance stack before any message is sent or response generated. This hub documents each gate, its enforcement point, the 10DLC campaign-ID status (B14 blocker), and the failure behavior for any gate that trips. Read this hub first before working on outreach-stage1, followup-stages-2-3-4, or buyer-blast. Owner: acquisitions agent + Aurora.
⚠️ A2P 10DLC repeat-denial active — TCPA risk uncapped, gates ALL SMS tiers. 10DLC campaign resubmission is tracked in osil-twilio-10dlc-resubmission-2026-05-03 (B14, pending B14a Henry signoff). Additional gates required once B14 resolves: BVP verified, EIN matched, opt-in documented, 6-element CTIA disclosure present. Until B14 resolves, all live sends carry elevated TCPA exposure.
Quick reference
| Field | Value |
|---|---|
| Stages | Pre-send qualification → Gate pass → Send → Post-send audit |
| Primary agent | _summary |
| Supporting agents | _summary, _summary |
| Agent handoff chain | gate-computer → compliance-gate → blast-safety → thread-context → response-generator |
| Compliance gates list | gate-computer, compliance-gate, blast-safety, thread-context, response-generator |
| Skills invoked | acquisitions-outreach, acquisitions-followup, messaging-compliance-gate |
| Success metrics | Zero TCPA violations; gate-pass rate logged to openphone_events; suppression list maintained |
| Cost per stage | ~$0.002 LLM tokens per gate evaluation; SMS send cost per carrier |
| Throughput | ~50-200 deals/day evaluated; rate capped at 1 send/CH/24h |
| Last run result | See openphone_events Supabase table — most recent created_at |
| Failure modes | Gate trips → no send, logged; 10DLC denial → uncapped TCPA risk; suppression miss → duplicate send |
The 5 compliance gates
Every outbound send (Stage 1 through Stage 4) runs these 5 gates in order. All 5 must pass. First failure = no send, error logged.
Gate 1: gate-computer.js
What it checks: 5-gate qualification progression state for this deal. Evaluates what data is still needed from the contract holder and selects the appropriate SMS template scenario.
Gate states:
| Gate | Name | Data required |
|---|---|---|
| 1 | Identity & Interest | Full address + asking price |
| 2 | Visual & Access | Photos or access scheduled |
| 3 | Vacancy & Possession | Occupancy status |
| 4 | Condition Assessment | Repair scope + known issues |
| 5 | Full Qualification | Price, timeline, urgency, access all confirmed |
Thread-context aware: if prior thread already covers a gate item, that gate is skipped via acquisitions-outreach thread-context.js.
Code: workspace/scripts/lib/gate-computer.js
Gate 2: compliance-gate.js (TCPA / quiet hours)
What it checks:
- Quiet hours: 8am–9pm local time in the contract holder’s state TZ
- Max 1 send per CH per 24-hour window
- Max 1 send per deal per send-window
- Dup content: same template not resent if last send <72h
- Thread hygiene: no interrupt on human-active thread
TCPA exposure: Until osil-twilio-10dlc-resubmission-2026-05-03 B14 resolves (campaign ID approved by carrier), quiet-hours enforcement is the primary TCPA guard. Do NOT disable this gate.
Code: workspace/scripts/lib/compliance-gate.js
Gate 3: blast-safety.js
What it checks:
- Cross-deal dedup: same CH receiving messages for multiple deals in same window
- Silence penalty: CH who replied “STOP” within last 30 days
- Line saturation: OpenPhone per-line daily send cap
Suppression table: messaging_suppression in Supabase CCP (svueekfvfrvhylxygktb). STOP replies persist across all deals for this CH.
Code: workspace/scripts/lib/blast-safety.js
Gate 4: thread-context.js
What it checks:
- Prior message history for this CH/deal combination
- If a human is actively mid-conversation, blocks automated send
- Injects conversation history into LLM context for response generation
- Resolves
conversationIdfromfromNumber→lineId(fail-closed: if lineId can’t be resolved, no send, per feedback_quo_lineid_required)
Code: workspace/scripts/lib/thread-context.js
Gate 5: response-generator.js
What it checks / produces:
- Selects mentor voice for touch count (Mike Ferry T1-2 → Mandeep Damji T3-6 → David Norton T7-13 → Grant Cardone T14-20 → Sean Terry T21+)
- Generates message via v3 Dispo Conversion Agent (5,138-msg trained)
- One question per send (Mike Ferry rule — enforced here)
- No em-dashes in outbound copy (per feedback_no_em_dash)
- No pass-and-pivot (per feedback_acq_no_pass_and_pivot)
- Message length: ≤160 chars per SMS segment for 10DLC campaigns
Code: workspace/scripts/lib/response-generator.js
10DLC campaign gates (B14 — pending)
Once osil-twilio-10dlc-resubmission-2026-05-03 B14a is approved by Henry and campaign registered:
| Additional gate | Description |
|---|---|
| BVP verified | Business verification profile confirmed at carrier |
| EIN matched | EIN in campaign registration matches IRS filing |
| Opt-in documented | CTIA-compliant opt-in proof on record per CH |
| 6-element CTIA disclosure | Program name, message frequency, help/stop instructions, terms URL, privacy URL, carrier disclaimer in initial message |
| Campaign ID routing | Every send tagged with approved 10DLC campaign ID (A2P) |
These 5 gates are additive to the existing 5 — all 10 must pass post-B14.
Related plan: osil-twilio-10dlc-resubmission-2026-05-03
Components
workspace/scripts/lib/gate-computer.js— 5-gate qualification progressionworkspace/scripts/lib/compliance-gate.js— TCPA, quiet hours, 24h dedupworkspace/scripts/lib/blast-safety.js— cross-deal dedup, suppression, line saturationworkspace/scripts/lib/thread-context.js— prior message history, lineId resolutionworkspace/scripts/lib/response-generator.js— v3 Dispo Conversion Agent, mentor voiceworkspace/scripts/lib/mentor-voice.js— touch→mentor cadence mappingworkspace/knowledge-base/openphone/OUTREACH-RULES.md— 10 compliance rulesworkspace/knowledge-base/twilio/WEBHOOKS.md— carrier-level compliance
How it’s used
- Trigger: every outbound send from acquisitions-outreach or acquisitions-followup passes all 5 gates before a message leaves
- Workflow:
unified-outreach-engine.js→gate-computer.js→compliance-gate.js→blast-safety.js→thread-context.js→response-generator.js→openphone-sms.jsORdispo-send.js - Agents involved: _summary (primary), _summary (inbound), _summary (oversight)
- Failure mode: any gate returning
false→no send, error reason logged toopenphone_events, deal status unchanged - Success criteria: gate-pass events in
openphone_eventswithevent_type='outbound_sms'; zero entries withevent_type='compliance_block'in alert window
Cross-links
Agents that touch this
- _summary — primary sender; gates enforced on every dispatch
- _summary — inbound reply routing; also compliance-checked
- _summary — oversight, compliance audit view
- _summary — Solara variant follow-up also routes through these gates
Skills that invoke this
- acquisitions-outreach — Stage 1 sends; all 5 gates required
- acquisitions-followup — Stage 2-4 sends; same 5 gates
- messaging-compliance-gate — standalone compliance check skill
- dispo-blast — buyer-blast also passes compliance-gate + blast-safety
Plans that govern this
- osil-twilio-10dlc-resubmission-2026-05-03 — B14 10DLC campaign resubmission (adds 5 additional gates)
- openclaw-fragmentation-fix-2026-05-01 — governance gates G-NO-PLAINTEXT-CREDS enforced here
Feedback rules
- feedback_acq_no_pass_and_pivot — banned pass+pivot move in response-generator
- feedback_acq_thread_history_aware_gates — skip gates already satisfied by thread history
- feedback_acq_mentor_voice_cadence — touch→mentor cadence in response-generator
- feedback_quo_lineid_required — fail-closed behavior when lineId cannot be resolved
- feedback_never_send_without_auth — explicit Henry auth required for any live send
- feedback_aurora_outbound_guardrails — outbound dispatch rules for Aurora
- feedback_no_em_dash — no em-dashes in outbound SMS copy
- feedback_action_gate_violation_repeated — service restarts require explicit auth
KB / source docs
- README — OpenPhone API + compliance rules
- README — Twilio A2P/10DLC carrier compliance
- README — SalesMsg API quirks (query-param token, NOT HMAC)
System maps
- vm-messaging-flow — SMS routing overview
- vm-acq-agent-flow — acquisitions agent dispatch flow
Related: SMS/Carrier compliance cluster
This hub is the cluster anchor for SMS/carrier compliance. All SMS-sending hubs link here.
| Hub | Role in cluster |
|---|---|
| twilio | 10DLC registration, A2P campaign, carrier gateway |
| salesmsg | SalesMsg send path (query-param auth); P0 security note |
| openphone-quo | OpenPhone send + inbound webhook (:18792) |
| outreach-stage1 | Stage 1 initial send — all 5 gates required |
| followup-stages-2-3-4 | Stage 2-4 follow-up — same gates |
| buyer-blast | 4-channel buyer blast — compliance-gate + blast-safety |
B14 blocker cross-link (10DLC): osil-twilio-10dlc-resubmission-2026-05-03
Open issues / TODOs
- B14: 10DLC campaign resubmission pending Henry signoff (B14a) — adds 5 additional gates post-approval. Until resolved, TCPA risk is uncapped.
- Suppression list export/sync between OpenPhone and SalesMsg paths not yet unified — possible duplicate suppression entries.
compliance-gate.jsquiet-hours logic uses hardcoded state TZ map — verify against current DST rules.- Gate 5 mentor voice: touch counter persists in
acquisition_deals.touch_countbut not currently validated againstopenphone_eventsactual send count — drift risk.
Recent activity
- 2026-05-03: hub created (W1-S8)