Retention nudges and the reply loop
Founder, 18:28 ET: "Definitely should send occassionaly nudges/reminders likely via email... to have them review/print their latest playset or review their upcoming plans. We could solicit feedback... reply to this email with your comments and pictures of the game, etc."
Implements the amended MA-D8 in [[2026-09-02-members-area-spec]] (the founder amended it; this plan carries its cadence and copy, it does not overrule it). Sits on the amended calendar: rolling two weeks with history, one playset per day, one kid at a time.
1. The loop
A parent plans the rolling two weeks (or lets Ray fill them), prints a day's playset, plays it, tells us how it went, and plans the next stretch better for it. Each nudge is one edge of the loop said out loud: "tomorrow's playset" sits between plan and print; "how did it go" between play and feedback; "blank days" and the recap between feedback and the next plan; the 21-day nudge is for a household that fell off. The charter sets the register: a plan arrives on a schedule, so the email is the product showing up, not marketing about it. One action per email, no encouragement, same as Ray's bubble on the sheets.
2. Nudge catalog
Five nudges. All from Ray at scribbleworks.co, plain text, one link, reply-to feedback+<token>@scribbleworks.co. Household means the lead adult plus any added adult who opted in themselves.
N1. Tomorrow's playset is ready. Trigger: a planned day with no print or download event by the evening before. Audience: any signed-in household with a plan, free or paid (the [[2026-09-02-tier-line-plan]]'s Decision 1 default makes the shelf-filled two-week plan free-authenticated, so a plan nudge cannot be paid-only without contradicting it). Timing: 18:00 household local (assumption). Subject: "Tomorrow's playset is ready. Print it tonight?" Body: what tomorrow is (game names; first name only if the parent chose it); the supplies line from the parent page; the link. Action: print. Reply-to: token bound to the playset.
N2. Blank days next week. Trigger: two or more empty days in the coming seven (assumption), checked Thursday (assumption). Audience: any signed-in household with a plan, free or paid (same reconciliation as N1). Timing: Thursday 18:00 local (assumption). Subject: "Three blank days next week. Want me to fill them?" Body: which days; what Ray would put there (one line from the auto-fill rules); a link to the calendar on those days. Action: fill. Reply-to: token bound to the plan window, so "more counting games" files as plan feedback.
N3. How did it go? Trigger: a printed playset whose day has passed, or a Done tick; send next morning. Audience: both. Timing: 08:00 local (assumption), at most one per household per week (assumption). Subject: "How did Who Eats What? go?" Body: one question ("What did they get stuck on, what made them laugh?"); "Reply with a note, or a photo of the sheet with your pen marks"; the no-faces line (section 3). Action: reply. Reply-to: token bound to household + game + date. The Grammy motion (pen note on a printed sheet, photographed), as a door parents can find.
N4. Two-week recap. Trigger: every other Sunday, for a household with at least one print or Done in the window. Audience: any signed-in household, free or paid (same reconciliation as N1; the earlier "free gets it monthly with the week card" line is dropped, because ruling 12's single week card is what the tier-line plan's Decision 1 reverses). Timing: Sunday 08:00 local (assumption). Subject: "Two weeks of games, and what's next." Body: what got printed and done (games and skill families, no scores); one thing we changed because of a reply, if any; the next two weeks with a link. Action: review the plan. Reply-to: token bound to the window.
N5. Quiet for 21 days. Trigger: no sign-in, print, Done or reply for 21 days (labeled assumption; no retention data exists to source it). Audience: both. Sent once; never repeats without a fresh sign-in. Subject: "Still here. One game for this week?" Body: one ready-made playset for the age band (shelf only, no generation); one line on what is new; the link. Action: print one thing. Reply-to: token bound to the household.
Cap and quiet hours. At most three nudges per household per week, all types combined (labeled assumption; the founder said "occasional"). When the cap binds: N3, then N1, N2, N4; N5 only fires in silence. No sends 20:00 to 07:00 household local (labeled assumption). Timezone is detected per household (see the Timezone section), never defaulted. No nudge mentions a card, a renewal or the paid tier.
3. The reply loop
A reply goes to feedback+<token>@scribbleworks.co. Email Routing hands it to the existing Worker sw-feedback-intake, which writes a D1 feedback row with attachments in R2 sw-feedback under the 180-day lifecycle (all four verified live). Verified-account sender screening (ruling 25) is claimed but not verified in the live-facts list: treat it as unbuilt until someone reads the Worker, because the photo and consent posture below assumes it.
Routing the plus-address (unverified, and a build gate). Cloudflare Email Routing matches a custom address either exactly or through the zone's catch-all; it does not pattern-match a + suffix. So feedback+<token>@scribbleworks.co reaches sw-feedback-intake only if the catch-all is pointed at the Worker, because the exact rule feedback@scribbleworks.co will not match it. Today the catch-all forwards to ben@raydata.co (ruling 23), so as configured the token replies would land in the founder's inbox, not the Worker. Not verified against the live zone. Two ways out, both new build: repoint the catch-all at the Worker (and re-home hello@ forwarding), or drop plus-addressing and carry the token in the subject only. Until the zone is read, the subject token is the primary, not the fallback. Two additions: the token is minted at send (signed: household, object, nudge id; stored on the nudges row) and carried in the plus-address and the subject, so the Worker keys the row to household and game or plan window without parsing prose; the subject token carries the same value for the routing reason above. A tokenless reply still lands as household feedback. Every reply gets an acknowledgement within a minute ("Got it. Ray reads every one.") and a real reply with a before-and-after when something changes (ruling 24).
Photos. The email carries one line: "Send the sheet, not the kid. We ask for no faces. We keep your note and the photo for 180 days, then the photo goes and the note stays." Everything else is at /privacy (ruling 22). The relationship model says no photograph of a child, ever, so a photo with a face is deleted at triage before anything displays and the note is kept; a face screen gates row visibility, and triage stays human-read until the screen is trusted.
Members area. The section 2.5 feedback list: date, game, thumbnail, status received or fixed with a before-and-after link. The parent can delete a row; the sweeper enforces the photo lifecycle either way.
UGC pipeline. Replies are feedback, not customizations, and never leave the household by default. A reply carrying a theme request ("more dinosaur ones") is tagged at triage and enters the ruling 21 theme queue only when the household's ugc_theme_log scope is on; the queue gets the theme tag, never the text, name or photo.
4. Consent and controls
Nudges get their own consent scope, email_nudges. This is a new scope: the relationship model enumerates child_profile, personalized_generation, classroom_link:<id>, progress_share:<id> and ugc_theme_log, and adding one is an edit to that doc's enumeration. It reuses the record's existing columns (who = adult id + identity, what = scope + policy_version, when, how verified, evidence, revocation), but the model's CONSENT row is keyed to a child_id; an adult-addressed email consent has no child subject, so either the column goes nullable or the scope lives on the adult. Flag for the relationship-model doc, not decided here. Not pre-checked. Asked once, at first plan or first print, one sentence per nudge type plus a timezone field; sign-up stays a magic link and nothing else. Each type is a preference under the scope, off until chosen. Every email carries a List-Unsubscribe header and a footer link, one click, per type, plus "stop all"; unsubscribe writes a revocation event, no confirmation page. Two bounces or one spam complaint stops all sends.
In the mail itself: no child name in any subject line. First name in the body only if the parent chose "use their name in email" (off by default). No sheet thumbnails, no tracking pixel (opens are unreliable, and the charter's no-third-party-analytics posture is worth keeping in email). Links are signed and expire in seven days (assumption). The nudges table never holds body text.
5. Build plan
Verified live: Resend sending from scribbleworks.co; Email Routing delivering feedback@scribbleworks.co to the Worker sw-feedback-intake, which writes D1 feedback and attachments to R2 sw-feedback under a 180-day lifecycle; the retention sweeper deleting past retain_until. No marketing email has been sent yet, so every deliverability number below is a first run.
Claimed but not on the verified list, so treat as new build until read: verified-sender screening in the intake Worker; accounts v1; saved playsets synced to the household; plus-address routing (section 3); the one-minute reply acknowledgement, which is an outbound Resend path nobody has built.
| Order | Piece | Size | Note |
|---|---|---|---|
| 1 | email_nudges scope + per-type preferences + timezone |
S | Consent record shape exists |
| 2 | nudges table: household, type, object id, token, sent_at, clicked_at, replied_at, unsubscribed_at |
S | No body text |
| 3 | Reply token: mint on send, parse in sw-feedback-intake; subject token primary |
S | Read the zone first: catch-all vs exact rule (section 3) |
| 4 | Unsubscribe endpoint + List-Unsubscribe header | S | Writes revocation |
| 4b | Reply acknowledgement send path (Resend, outbound from the intake Worker) | S | Not built today |
| 5 | N3 template + send path on playset print or download | M | Ships first |
| 6 | Scheduler: Cron Trigger → Workflow per household (select, cap, quiet hours, render, send, record); charter rung 4 | M | Serves N1, N2, N4, N5 |
| 7 | Members-area feedback rows, face screen before visibility | M | Inside v2 |
| 8 | N1, N2, N4 templates | M | Need the amended calendar schema |
| 9 | N5 template | S | Shelf only |
Ship N3 first: its trigger exists today (a print or download of a saved playset), it needs no calendar, and it exercises the whole reply loop: token, photo copy, members-area row. First recipient: the founder's household, then the cohort. Nothing here starts a bill at cohort scale (labeled assumption; check the Resend tier before the scheduler turns on).
6. Measures
Per type, per week: reply rate; print rate within 48 hours of send against households not sent that week; click rate; unsubscribe rate; photos received; photos deleted at the face screen. Thresholds, all labeled assumptions until sends exist: stop a type if unsubscribes pass 2 percent of sends over four weeks, or if after 200 sends its print or reply lift over unsent households is zero; stop everything if spam complaints pass 0.1 percent (the common provider line) or two face-screen deletions land in one week, because the copy is not working. Success for N3 is a photo a week from the cohort and a fix shipped back with a before-and-after: the Grammy loop at cohort scale.
7. Founder decisions
RN-D1. Where the opt-in lives. Ray default: first plan or first print, not sign-up. Wrong means lower opt-in coverage for a few weeks; reversible in a turn.
RN-D2. Does free get nudges? Reconciled with the tier-line plan rather than left contradicting it. Ray default: every signed-in household gets all five, because that plan's Decision 1 default makes the shelf-filled two-week plan free-authenticated, so a plan nudge to a free household is a nudge about something it has. If the founder instead answers tier-line Decision 1 "the plan is paid", N1, N2 and N4 revert to paid-only and this row follows it. Anonymous visitors get nothing: there is no address and no consent. Wrong means email volume to households that will never pay; the fix is a flag.
RN-D3. The weekly cap. Ray default: three per household per week, quiet 20:00 to 07:00. Too high shows up as unsubscribes we can see and undo; too low shows up only as churn.
Silence proceeds on the defaults. Not legal advice; consent and photo copy inherit the relationship model's [counsel] flags.
Related
[[2026-09-02-members-area-spec]] · [[2026-08-31-product-model-rulings]] (21, 22, 24, 25, 30 + addendum) · [[2026-08-31-studio-charter]] (rung 4) · [[2026-09-02-account-relationship-model-decision]] · [[2026-09-02-tier-line-plan]] · [[feedback/2026-09-02-grammy-feedback-log]]
Ruling 31 (18:44 ET) - effect on this plan
Delivery is the paid product: for paid households N1 (tomorrow's playset) is the playset itself, sent on schedule, with the print link; N2 (blank days) and N4 (recap) belong to the same paid delivery motion. N3 (how did it go) and N5 (quiet 21 days) go to every signed-in household. RN-D2 is therefore resolved by ruling 31; RN-D1 and RN-D3 remain open.
Timezone (18:48 ET, founder question)
Not a Resend capability (Resend schedules at a given instant only). Store a timezone per household and compute send times from it, the way Klaviyo, Braze and Customer.io do "send in recipient's local time". Fill it without asking: browser timezone read on the magic-link confirm page (Intl.DateTimeFormat().resolvedOptions().timeZone), Cloudflare request geolocation (request.cf.timezone) as the fallback at the sign-in request, a settings override, re-read on later visits. No Eastern default. Schema: households.timezone (IANA name) added to the v2 calendar-side migration.