Signup nudge eligibility treats subscribed-then-unsubscribed members as never subscribed
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Accessibilité débutants
- 35/100
Piste de recherche
Start with app/services/signup_nudge_email_service.rb#never_subscribed and app/controllers/subscriptions_controller.rb#destroy, then inspect the subscription and activity data model. Confirm which persistence direction maintainers choose before implementing it. Done means a member who subscribed and later unsubscribed is not treated as never subscribed, while group-specific eligibility and followup behavior remain correct.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Summary
SignupNudgeEmailService#never_subscribed defines eligibility as "has no row in subscriptions". But SubscriptionsController#destroy deletes the subscription row when a member unsubscribes from a chapter group. A member who subscribed and later left is therefore indistinguishable from a member who never subscribed at all — and becomes nudge-eligible again.
Real production case
Member 31302 (dump of 2026-09-24), full timeline from activities + workshop_invitations:
| Time (2026-09, UTC) | Event |
|---|---|
| 09-02 11:16 | Signs up |
| 09-02 11:18 | RSVPs as Coach (2 minutes after signup) |
| 09-09 18:30 | Attends London workshop |
| 09-17 09:16 | RSVPs to the next London workshop |
| 09-17 09:34 | Unsubscribes from London Coaches group (subscription.removed activity, id 569) |
| 09-17 13:04 | Receives a "Let's get you connected with codebar!" signup nudge |
Four hours after choosing to leave the chapter group, this actively engaged coach got an email whose premise is "you never connected with codebar". The unsubscribe made him eligible again; the nudge arrived same-day.
Two compounding facts:
subscription.createdactivity tracking only started 2026-09-13 (65 events / 41 members) andsubscription.removedon 2026-09-14 (61 events / 45 members). His subscription predates tracking, so its removal left no "was subscribed" evidence — only the removal event exists.- In the dump, 37 of the 45 members with a tracked unsubscribe now have zero subscription rows — i.e. the nudge service currently classifies all 37 as "never subscribed". One of them is inside the current nudge window and not banned.
Why this is separate from #2919
The daily duplicate-send bug (#2919, .merge clobbering the delivery anti-join) causes the same member to be emailed repeatedly, but fixing it does not fix this: a subscribe-then-unsubscribe member with no prior nudge is genuinely selected by the corrected query. The eligibility rule itself needs to account for unsubscribes.
Scope of the wrongness
- Messaging mismatch: the nudge copy assumes a dormant lurker; unsubscribers made an active choice to leave. Re-pitching them risks reading as ignoring their opt-out.
- Same-day turnarounds are possible for any churn event shortly before the daily 12:00 UTC run, as the timeline shows.
- The unsubscribe may have been from one group only (e.g. left Coaches, still interested in Students) — naive "any unsubscribe = never eligible" would over-correct. Today's schema can't tell, because the row is gone.
Possible directions (for discussion)
- Tombstone subscriptions — soft-delete/discards (
discarded_at) or astatecolumn, so history survives; eligibility then reads "never had an active subscription". Most robust; biggest change. - Eligibility excludes members with a
subscription.removedactivity — cheap, but blind to all pre-2026-09-13 subscriptions, and depends on activity rows never being cleaned (nothing prunesactivitiestoday, but nothing guarantees that). - Member-level flag set on unsubscribe (mirroring the
received_student/coach_welcome_emailpattern) — simple, but loses which group/chapter was left.
Happy to take whichever direction maintainers prefer; option 1 is the only one that also preserves the data for the followup email logic (which keys off member_email_deliveries.created_at and would otherwise send a followup to someone who already left).
Environment
app/services/signup_nudge_email_service.rb(never_subscribed) andapp/controllers/subscriptions_controller.rb#destroyata50b5214- Rails 8.1 / Ruby 4.0, verified against
codebar_production_dump2026-09-24
- Langage dominant
- Ruby
- Étoiles
- 105
- Forks
- 206
- Merge moyen
- 17 h 2 min
- PR mergées (30 j)
- 69
Préparer son environnement
- Fournit un Dockerfile ou un fichier Docker Compose
- Aucun modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de codebar/planner
-
DashboardQuery eager-loads workshop_host with :sponsors in one join (same host-loss trap as #2975)Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 1 jour
-
enhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
Les mainteneurs répondent en général sous 1 jour
-
404 link in footerPeut-être pris @SourindraNathBasak l’a pris aujourd’hui. Ouvertegood first issue sponsoring
Difficulté 1/5 Moins d'une heure Accessibilité débutants 18/100
codebar/planner#3004 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Homepage shows deactivated chapters (sidebar fragment invalidation deletes the wrong key)Peut-être pris @mroderick l’a pris il y a 2 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 30/100
codebar/planner#2993 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de codebar/planner
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Homebrew/homebrew-cask#293134 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
notch8/iiif_print#430 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
Les mainteneurs répondent en général sous 1 jour
-
ActionText::Content#to_markdown: <br> in a table cell and empty <tr> produce malformed Markdown tablesPeut-être pris @azmi2409 l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
Les mainteneurs répondent en général sous 1 jour