Lifecycle tool, mockup

Four screens, the four questions. Every row is real: journeys are catalogue rows, the audience is win-back's actual 150-address pilot, the blocks are the eight that exist. Control is three verbs, pause, resume and drain, because authoring stays a file and a review.

1. Journeys, what exists and what is stopped

Journeys

7 defined, 3 live, 1 paused pause resumedrain
JourneyNameStateAudienceIn flightGate
winback-2026Dormant win-backpaused1500blocked, domain unauthenticated
reconversionReconversionlivelive queryunknownok
nurture-productProduct nurturelive22 listsunknownok
welcome-smsWelcome SMSlivelist 68unknownok
dist-receiptDistributor receiptbuilton upload0ok
sms-drip-2-4SMS drip 2 to 4builtnon-converters0held
c13-tradeshowTrade show re-engagedraftnot defined0no audience

2. One journey, node by node

winback-2026

paused, 150 in audience, 0 in flight pause resumedrain
entryentry
gate1_pilot, 150 people, limit 150, reentry never
audience + volume
touch-1messagewinback-2026.touch-1
blocks/winback/touch-1
GATE: suppression, consent, frequency
wait-5dwait
5 days
did-they-opendecision
opened touch-1 within 5d, yes or no
touch-2amessagewinback-2026.touch-2a
blocks/winback/touch-2a
GATE: re-checked, not inherited
touch-2bmessagewinback-2026.touch-2b
blocks/winback/touch-2b
GATE: re-checked, not inherited
doneexit
The gate runs before EVERY message. Not once at entry. Somebody can unsubscribe between step two and step three, so an eligibility answer from five days ago is a guess about today. Njui raised this and the vendors agree: Braze rechecks the cap at the actual send.

Launch preflight, re-run on every refresh

CheckNowRead
Audience pinnedpass150 rows
Suppression freshpass18,390, read now
Consent opt-inpassper person
Frequencypasspromo 30d, 3 in 30
Domain authenticatedfailno SPF, no DKIM
Domain warmfailno history
Stranded checkmissingsensor built, needs DSN

3. Audiences, computed in the warehouse

Audiences

5 defined pause resumedrain
AudienceSizeComputedUsed byNote
aud.winback.gate1-pilot15002:30 todaywinback-2026pinned
aud.winback.gate1-rest1,64802:30 todaywave 2not released
aud.winback.gate2no sizenevernothingno SQL exists
aud.reconversion.returninglive queryon triggerreconversion90d rule
aud.nurture.by-product7 to 38 eachunknownnurture-product22 lists
Segments are computed in the warehouse, nightly, and the tools consume them. Not defined in Brevo, not defined twice. Two definitions of dormant that disagree is the documented failure, and we already have three rival eligibility functions.

4. Compose, what is being built

Messages

2 approved, 2 draft, 1 not started pause resumedrain
MessageStageBlocksNeedsIf absentVariants
msg.winback.touch-1approvedplain2 attrsabort1
msg.winback.touch-2aapprovedplain1 attrabort1
msg.cart.abandoneddraft7 blocks3 attrsomit6
msg.ambassador.invitedraft6 blocks2 attrsrefuse2
msg.seasonal.roundupnot startedlist shapeunknownomitunknown
Variants is the column that earns this screen. An attribute-driven message is a different body per person, so the defect that ships is in the variant nobody rendered. Six defects passed every automated check on Labor Day and were caught by eye.

Naming, which is load-bearing rather than tidy

Three measured reasons this is not housekeeping. Brevo rewrites utm_campaign from the campaign name, so the name is the analytics key. Braze block names are permanent and cannot be reused even after archiving. An untagged message is permanently unattributable.

Naming

applies to every client
ThingPatternExampleWhy
Journey<program>-<year>winback-2026Lowercase, no spaces. It becomes the Brevo campaign name, and Brevo rewrites utm_campaign from that name verbatim, so the name IS the analytics key.
Node<journey>.<node>winback-2026.touch-1Also the send tag. An untagged message is permanently unattributable, and Brevo reports per campaign, so without this nobody can say which STEP earned an open.
Audienceaud.<program>.<cut>aud.winback.gate1-pilotSorts together, and the prefix says what it is when it appears in a list beside 22 Brevo lists nobody named carefully.
Messagemsg.<program>.<role>msg.cart.abandonedRole, not draft state. A name chosen as a label becomes permanent: Braze will not let a block name be reused even after archiving.
Block<role>masthead, item_row, ctaSemantic role only. Never a visual description, because 'blue-box' survives the day somebody makes it green.
Brevo list<program>.<segment>nurture.boat-liftsThe 22 nurture lists are a trigger mechanism, not 22 contents, and their names should say that.