Signup nudge eligibility treats subscribed-then-unsubscribed members as never subscribed
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
調査の方向性
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.
索引モデルが issue の本文から書いたものです。
説明
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
- 主要言語
- Ruby
- スター
- 104
- フォーク
- 205
- 平均マージ
- 1日 6時間
- マージ済み PR(30日)
- 70
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
codebar/planner のほかの issue
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
expenses
難易度 3/5 1〜2日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
codebar/planner の issue をすべて見る
似ている issue
-
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
L: javascript T: bug 🐞
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
dependabot/dependabot-core#16397 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
-
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
TheOdinProject/curriculum#31423 ·
メンテナーはふだん 1 日以内に返信