SMS-Compliance Auditor · Internal reference

How a case travels from a domain to a Twilio-ready submission.

The auditor is a four-stage pipeline. Each stage produces a saved report a Twilio reviewer could read. The document below walks the flow end-to-end and zooms in on the piece we rebuilt this session — the TCPA scope-alignment step inside the Submit Package Draft.

Backend · sms-compliance-auditor Region · us-east1 Frontend · brand-audit.html (CDN) Storage · Firestore cases/{domain}
1 · the pipeline

Four stages, each one saveable and shareable.

Every case walks the same path: audit the brand's website, generate the implementation package the brand needs to update on their site, generate the submit package the operator sends to Twilio, and, if the submission is rejected, generate a remediation package. Each stage writes a Firestore report; each stage's public URL is what the operator shares with the brand.

STAGE 1 Initial scan Audit the site score + findings STAGE 2 Implementation Corrected copy for the brand's site STAGE 3 · this session Submit package Draft the 3 fields Twilio requires STAGE 4 Rejection fix Only if Twilio rejects the kit Operator enters site + signup URLs Every stage writes a report doc to Firestore cases/{domain} and returns a public URL the operator shares with the brand.

Stage 3 is where the TCPA scope-alignment feature lives — it's the diagram we spend the rest of this document unpacking.

2 · what happens inside an audit

The audit does three passes in one call.

When the operator hits Run audit, the backend does three concurrent-ish passes: fetch every page the operator listed, run deterministic regex checks against the extracted text, and run the LLM audit that produces the human-facing findings. This session added a fourth pass — the TCPA checkbox classifier — that reads the sign-up consent text and figures out which message categories the live checkbox actually authorizes. That output is the ground truth Stage 3 later uses to pre-select scopes.

POST /audit site_url · privacy_url · terms_url · signup_url · signup screenshot Pass 1 · Fetch & render pages HTML + text stored on pages.{site,privacy,terms,signup} Pass 2 · Deterministic Regex checks (STOP, HELP, rates, frequency, links, addr) Extracts consent paragraph Pass 3 · LLM audit Reads all pages + screenshots Emits PASS/FAIL per check, recommends Path A / B / D Pass 4 · TCPA classifier Reads the extracted checkbox text and/or the screenshot; outputs authorized scope IDs consent paragraph handed off Audit report saved to Firestore report.sections.signup.checkbox_scope_analysis is where the classifier's verdict lives — Stage 3 reads it directly. Blue outline = new in this session · The classifier writes both authorization verdicts and per-scope evidence with quoted phrases.
3 · what happens when you press "generate submit package draft"

Stage 3 is the TCPA loop — from checkbox to Twilio-ready draft.

This is the flow we rebuilt this session. The operator picks a path (A, B, or D), and the picker below the path selector pre-ticks the scopes the classifier said the live checkbox authorizes. Every deviation from that ground truth surfaces as an alert; the operator either fixes the checkbox, force-includes with a written justification, or accepts the warning and proceeds. Once the operator hits Generate, the backend assembles a prompt that feeds the LLM the verbatim live checkbox text, the selected scopes, and any force-included scopes with their admin justification.

Operator opens the draft card Picks Path A / B / D from the dropdown Picker pre-ticks scopes the checkbox authorized Reads checkbox_scope_analysis.detected_scope_ids Blue AUTO badges with hoverable quoted evidence Operator ticks / unticks scopes Every change re-computes the alert banner in real time Alert banner evaluates 5 conditions H1 empty overlap · H2 authorization absent · H3 no consent text S1 over-selected · S2 low classifier confidence (reference table further down) Fix the checkbox "Copy suggested language" — operator updates site, re-audits, warning clears. Force include Per-scope chip opens modal; 40-char justification + ack; stored on the case record. Accept the warning Proceed at compliance risk. Twilio reviewer will likely reject with 30454 / 30496. POST /submit-draft Payload: selected_scopes + forced_scopes[] + extracted_consent_text LLM emits the 3 Twilio fields, aligned to the scopes opt_in_workflow_description · use_case_description · sample_messages

The forced_scopes payload carries the admin justification into the LLM prompt so the model treats the override exactly like an operator-selected scope for alignment purposes — descriptions and samples still cover it, and the audit trail lives on the case record.

4 · reference — the three checkbox states

What the picker shows for each scope.

Every scope checkbox lands in one of three visual states. The state encodes the compliance basis behind the tick, not the operator's preference — the amber FORCED pill on a scope means an admin approved it out-of-band, not that the operator "really wants" it.

Auto-detected

Blue left border, "AUTO" badge, hoverable tooltip showing the exact phrase from the checkbox that authorized this category.

Fires when: the scope appears in detected_scope_ids

Manually added

Amber-tinted row with a red "not in checkbox" chip. The operator ticked something the classifier didn't detect — a compliance risk that needs to be resolved before submission.

Fires when: operator ticks a scope not in the detected set

Force-included

Amber left border, "FORCED" pill, tooltip showing the admin justification, timestamp, and the live checkbox snapshot at time of override.

Fires when: admin approved via the Force Include modal
5 · reference — the five alert conditions

What the "Checkbox Insufficient" banner is telling you.

Hard conditions block confident submission — the campaign is misaligned with what the checkbox legally authorizes. Soft conditions signal something worth eyeballing but not blocking. Both fire live as the operator toggles scopes.

H1
None of your selected scopes are authorized by the checkbox. Every ticked scope is outside the detected set — the campaign has no TCPA basis. Untick the mismatched scopes, update the checkbox, or force-include each one.
Hard
H2
Marketing (or transactional) authorization is absent. The classifier read the checkbox and found no language authorizing this path at all. Path A campaigns with an absent marketing authorization are the Vitalveo failure mode — Twilio reject 30496.
Hard
H3
No consent-checkbox text could be read. Neither the sign-up URL fetch nor the uploaded screenshot yielded readable text. Provide a clearer sign-up URL or a higher-res screenshot and re-audit.
Hard
S1
N selected scopes are NOT covered by your checkbox. Each over-selected scope gets its own per-scope "Force include" chip in the banner body — the primary Force Include entry point.
Soft
S2
N auto-detected scopes have low confidence. Classifier match confidence is below 0.5 for at least one detected scope. Hover the AUTO badge, read the quoted phrase, decide whether it really authorizes that category.
Soft
6 · the force-include lifecycle

What happens when an admin overrides.

Force Include is the escape hatch for cases where the operator has confirmed out-of-band that the live checkbox will be updated before submission, or where legal has separately authorized the override. Every use writes an audit-trail entry. Re-audits preserve the entry and flag it for re-verification unless the fresh classifier now catches the scope on its own.

1 · Modal opens Admin clicks per-scope "Force include" chip in the alert banner. 2 · Justify & acknowledge Min 40 chars written reason; acknowledgement checkbox; save button unlocks. 3 · Recorded on the case Firestore arrayUnion writes to cases/{domain}. force_included_scopes[] 4 · Scope row swaps to FORCED Amber left border, "FORCED" pill, tooltip carries the justification. No page reload. 5 · Next Generate carries it forward The scope pre-ticks; the payload includes forced_scopes[] with the justification. LLM aligns descriptions + samples to it. 6 · Re-audits preserve, with a re-verify flag If the fresh classifier still misses the scope: entry carries over, shows a "Re-verify" badge. If the checkbox has caught up and the classifier now detects it natively: entry is marked redundant.
Where this leaves us. Every campaign the operator submits is now anchored to the actual TCPA consent basis on the brand's live sign-up form. The alignment isn't guessed from brand voice or industry — it's classified from the operator's real checkbox and displayed as a compliance verdict the operator has to reckon with before generating a draft. When the classifier is wrong, or the checkbox is thin, the escape hatch is explicit, audited, and reversible.