"Please do not text me again" — how wide should an opt-out reach?
The question. When a resident tells Clara to stop texting in the middle of a renewal thread, should that mean "stop the renewal texts," or "never contact me about anything — maintenance, emergencies, rent, lease paperwork — on any channel"? Today it means the second one, and Clara says so out loud. Pick one of the four options at the bottom.
What happened (Camellia, unit 614, Aug 15)
Victoria had already told us she signed a paper 6-month renewal. Two weeks later a timer texted her the same "sign or you roll to month-to-month" pitch anyway. She replied:
I already signed a paper 6 month lease. Please do not text me again
You're all set, Victoria — I've taken you off the list and you won't receive any more messages from us.
Behind that reply Clara recorded a total opt-out: phone (calls and texts) and her email address, which she never mentioned. In context she plainly meant "stop the renewal texts."
What we actually do today (verified in code and in her records)
- The opt-out tool has one setting: everything. There is no "renewal only," "marketing only," or "this thread" option — Clara literally cannot record a narrower request.
- The blocking side is smarter than the recording side. Once someone is on the list, our send-gate still lets through operational messages (a maintenance update, Clara answering a text the resident sends first) and emergency notices; it hard-blocks only "we're reaching out to you" messages like renewal offers and reminders. So Victoria will still get a leak notice — but nobody can see that, and Clara promised her the opposite.
- The confirmation Clara is scripted to say overstates it — "across calls, texts, and emails" is hardcoded in the tool's success message.
- Fan-out bug: a phone opt-out is copied to every other contact detail we hold for the person. That is how her email got suppressed too.
- A property manager can only flip the whole thing on or off — no way to say "renewal texts off, everything else on."
What the law allows (from our verified TCPA note)
- A "stop" in any reasonable words is a valid revocation and must be honored within 10 business days. HARD
- We may send one confirmation message back, with no marketing in it. HARD
- A texted "stop" to a phone number stops both texts and calls to that number — those can't be split. HARD
- The "one stop kills every channel including email" rule is real but not mandatory until Jan 31, 2027; before then it's our choice. Email is a different law (CAN-SPAM) with its own unsubscribe regime. HARD
- Whether that one confirmation may ask "did you mean everything?" is our reading, not something the note states outright — a reasonable reading, not settled law. INFERENCE
- Honoring narrower than the resident asked is the risky direction; honoring wider is only a business cost. Any design must default to the safe side when Clara is unsure.
The options
A · Keep it total (status quo)
Every "stop" = never contact on any channel. Safest possible legal reading, already ahead of the 2027 rule. Cost: a resident who was annoyed by renewal texts loses maintenance updates and, in her mind, emergency contact; the office has to reach her by hand forever.
Not recommended — it is the incident.
B · Scope it from context, silently · Picked
Give the opt-out tool real scopes — renewal outreach, all outreach, everything — and let Clara pick from the thread she is in. A "stop texting me" on a renewal thread records "no more renewal outreach"; a bare "leave me alone" records everything. Operational and emergency messages keep flowing and Clara's confirmation says exactly that. The fan-out to email happens only when the resident names email.
Risk: Clara misreads a "stop everything" as "stop renewals" and we under-honor a revocation.
C · B, plus one clarifying line
Same as B, but Clara's single confirmation names the scope she understood and offers the wider one, e.g. "Got it — no more renewal texts. If you'd rather not get any texts from Camellia at all, including maintenance updates, reply ALL." No reply = keep the narrow reading she actually said. "ALL" = total block, exactly like today.
Why this one: it fixes the incident (over-block + overstated promise) with the smallest change, keeps the resident in control of the width, uses the one confirmation message we are already allowed, and defaults to what she literally asked. It also fixes the fan-out bug as a by-product.
Open point to settle with counsel later, not now: whether the confirmation may pose a question at all. If counsel says no, we fall back to B — the scoping still stands, only the invitation to widen goes away.
D · Split by channel (texts off, calls/email on)
Not available: a text "stop" legally covers calls to the same number too. Phone-vs-email is already separate in our store; voice-vs-text on one number is not something we can offer.
Ruled out by law.
What ships (per B)
- Opt-out tool gains scopes (renewal outreach / all outreach / everything); the store and send-gate honor them; the fan-out copies only the scope that was asked for.
- Clara's confirmation is generated from the recorded scope, never a hardcoded "everything."
- Property managers see the scope on the resident and can widen/narrow it.
- Victoria's record is narrowed to "renewal outreach off" and her email un-suppressed — after this doc is approved, as a one-time correction with a note.
- Separately (own fix, not part of this decision): the lease-expiry timer that texted her in the first place must hold when the resident has already answered or the renewal is with a human. That is what caused both this and the unit-607 thread on the same day.
Architecture (Option B) — how it works
Design principle: one door, one record, one matrix. Nothing new runs on Temporal; an opt-out is a row, and enforcement is a synchronous check at the door every outbound message already passes through.
The pieces
| Layer | What changes |
|---|---|
| The record suppression store (DynamoDB) |
The opt-out row gains a real scope: renewal outreach · all outreach · everything. Today the only value is "everything." Existing rows keep meaning "everything" — no migration. |
| The ear Clara's opt-out tool |
Clara picks the scope from what the person said and the thread she is in: "stop texting me" on a renewal thread → renewal outreach; "stop contacting me" / "leave me alone" → everything; unsure → the wider reading (under-honoring is the legal risk, over-honoring is only a business cost). Her spoken confirmation is generated from the recorded scope — never a hardcoded "you'll never hear from us." |
| The door outbound send gate |
Every outbound message already declares what kind of message it is (renewal outreach, other outreach, operational, emergency). The gate compares kind against scope — see the matrix. This is the ONE enforcement point; timers, workflows and Clara herself all pass through it. |
| Fan-out | A texted "stop" suppresses the phone number for texts AND calls (legally one unit). It no longer touches email unless the person said so or the scope is "everything." |
| Temporal renewal workflow |
No new workflow. One behavior change: when the door refuses a renewal reminder because of an opt-out, the workflow treats that as "stop the ladder for this resident" instead of "try again later," and stamps why. |
| What PMs see | Renewals page: a chip on the resident's row — "renewal texts off — resident opted out" — so a PM knows why Clara went quiet. Tenant profile: the scope, who recorded it, the resident's own words, and a widen/narrow/lift control (lifting requires the resident asking, and is logged). |
The enforcement matrix (the whole policy in one table)
| Message kind ↓ · scope → | renewal outreach | all outreach | everything |
|---|---|---|---|
| Renewal offers / reminders / expiry nudges | blocked | blocked | blocked |
| Other outreach (specials, campaigns) | sent | blocked | blocked |
| Operational (maintenance updates, replies to their own message, rent/lease admin) | sent | sent | sent · logged |
| Emergency / safety | sent | sent | sent · logged |
The two right-hand columns are today's behavior, unchanged. The new column is the narrow scope. Every block is logged with the resident's verbatim words next to it.
Test harness — how we prove it before and after shipping
- The matrix as a unit test. The kind-vs-scope table above is one pure function; the test enumerates every cell and fails if code and doc ever disagree.
- Clara's ear, scored like an eval. A golden set of real utterances in real thread contexts ("stop texting me" on a renewal thread, "don't ever contact me again" on a maintenance thread, ambiguous ones) with the expected scope. Runs on the subscription eval runner; the pass bar: never narrower than the person meant. Victoria's actual message is case #1.
- Replay of the incident. Feed the unit-614 thread through the new path end-to-end: expect scope = renewal outreach, phone-only, email untouched, confirmation text says exactly that, and the next expiry-timer tick sends nothing and stops the ladder.
- Live on the test property. On appfolio-45 with a claimed test unit and Fede's phone: text a stop mid-renewal-thread → check the recorded row, fire the reminder timer → nothing arrives, send a maintenance update → it arrives. Clean up by lifting the suppression afterward.
Rollout order
- Matrix + scoped record + door enforcement (invisible until a scoped row exists; total rows behave exactly as today).
- Clara's tool picks scopes + scope-true confirmation copy.
- Renewal workflow stops the ladder on an opt-out block; renewals-page chip + tenant-profile control.
- One-time correction: narrow unit 614's record to renewal outreach and lift her email suppression, logged with a note.
Your pick
Sources: the resident's conversation record and suppression rows (read live 2026-08-16); the opt-out tool, suppression store and send-gate code; the July 2026 universal-suppression decision (which designed the category split but never considered a topical scope); the TCPA/SMS-consent note in the domain knowledge base (researched 2026-06-18).