control tower / journal
Journal
engine connected
Proposed -- needs human approval

This tower does not push to git. To approve, a human makes this exact edit and commits it:

1. Open docs/marketing/journal/006-marketing-sends-growth-native.md in the docs repo.
2. Change the line "- **Status:** proposed" to "- **Status:** active".
3. Commit and push. The journal's git history is the audit trail; this tower does not commit on your behalf.

006: All marketing lifecycle sends run growth-native; the comms automation engine stays untouched

  • Date: 2026-08-31
  • Decider: engine proposal (Claude), pending Daud approval
  • Status: proposed
  • Review by: 2026-10-31

Decision

The referral ask, pre-trip upsell, and win-back sends are implemented inside modules/growth on its own scheduler (growth.lifecycle_sends, populated at conversion time from express-consent checkout sessions, executed hourly with claim-before-send), not as new triggers in the comms automation engine. The earlier Phase A/B plan (comms hours_after_tour reuse, then comms code changes) is superseded. Comms keeps exactly what it has: transactional booking-lifecycle messages. One small outside addition is allowed: modules/promotions registers a promotions.createAutoReward cross-module handler so growth can mint per-booking referral codes through the registry convention instead of a direct import.

Evidence

  • Deep executor recon (2026-08-31): a new TIME_BASED_TRIGGERS member silently falls into the 'before'-direction branch in planTimeBasedSends (send-scheduler.service.ts:182-211, with a forced cast hiding the type hole), so after-tour triggers require touching the live production scheduler's dispatch logic. Risk without matching benefit.
  • Injecting a minted promo-code variable into resolveBookingVariables would also mint on every admin template-preview click (templates.controller.ts:87-97 calls the same resolver). Avoidable only with further comms surgery.
  • DEVELOPMENT_RULES.md §11.2: "comms must not become a CRM/marketing surface." Comms and promotions are not B-band (§11.1 list), but the narrative warning is explicit and this design honors it.
  • Consent correctness is the decisive argument: express marketing consent lives in growth (checkout_sessions.marketing_opt_in, subscribers.status), which comms cannot see; a comms-driven marketing send could gate only on the default-true bookings.guests.email_opt_in, which fails our own eligibility rule (lifecycle-flows.md, rule 2). Growth-native sends are express-consent-gated by construction.
  • Consequence accepted knowingly: audiences start at zero and grow only from bookings made through the new checkout with the box ticked. Historical guests have no recorded express consent, so excluding them is compliance, not a limitation.

Predicted effect

The three flows ship as inert code in the same activation envelope as the rest of growth (dry-run default). Within 60 days of activation plus checkout opt-in going live, the scheduler sends to 100 percent of eligible (opted-in, still-confirmed) bookings at the specced offsets with zero sends to non-consented or cancelled bookings, measured by growth.lifecycle_sends rows joined to consent fields.

Measured effect

(pending)