Skip to content

feat(growth): attribute campaign sends per template with a bounded Resend tag - #1020

Merged
blove merged 1 commit into
mainfrom
blove/eloquent-chebyshev-59c2a5
Sep 5, 2026
Merged

feat(growth): attribute campaign sends per template with a bounded Resend tag#1020
blove merged 1 commit into
mainfrom
blove/eloquent-chebyshev-59c2a5

Conversation

@blove

@blove blove commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a bounded campaign_template Resend tag (immediate, day-3, day-8, streaming_foundation, debugging_layers, event_state_boundary) to every send_step so replies, bookings, and unsubscribes can be attributed per template, not just per step.
  • Threads the id chosen in draftFor through PreparedCampaignMessage and RecipientEmailInput; resend.ts validates it against a closed allowlist, requires it for send_step, and rejects it on any other job kind. Never contact data.
  • Fixes a latent regression in the webhook receiver: its canonical-send check counted send_step tags exactly, so a fifth tag would have turned every new send's early webhook from retryable_unmatched_job into a dropped unmatched_job. It now accepts both the legacy 4-tag and the new 5-tag shape.

Internal analytics stays step-only by decision; the Resend dashboard is the v1 surface for per-template numbers.

Test plan

  • npx vitest run --config apps/lifecycle/vitest.config.ts (399 passed)
  • npx vitest run --config libs/growth/vite.config.mts (471 passed)
  • npx nx run lifecycle:check
  • npx nx run growth:build
  • lint on growth + lifecycle: 0 errors

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Ready Ready Preview Sep 5, 2026 10:49pm UTC

Request Review

@blove
blove enabled auto-merge (squash) September 5, 2026 21:44
@blove
blove force-pushed the blove/eloquent-chebyshev-59c2a5 branch from b7dbf94 to 3286250 Compare September 5, 2026 21:44
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

…send tag

Every send_step now carries a campaign_template tag alongside
campaign_version and campaign_step, so replies, bookings, and
unsubscribes can be attributed to the exact template that rendered the
message rather than only its step.

- draftFor returns the chosen template id (immediate, day-3, day-8, or
  the cited evidence angle) and prepareCampaignMessage exposes it.
- RecipientEmailInput accepts campaignTemplate; resend.ts validates it
  against a closed allowlist, requires it for send_step, and rejects it
  on any other job kind. The value is a fixed id, never contact data.
- The webhook receiver's canonical-send check counted send_step tags
  exactly, which would have downgraded every new send's early webhook
  from retryable to dropped. It now accepts the legacy 4-tag shape for
  in-flight sends and the 5-tag shape when the template is allowlisted.

Internal analytics stays step-only by decision; the Resend dashboard is
the v1 surface for per-template numbers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@blove
blove force-pushed the blove/eloquent-chebyshev-59c2a5 branch from 3286250 to b951bdd Compare September 5, 2026 22:45
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit a3e1cf4 into main Sep 5, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant