import type { Campaign, CampaignCounts, CampaignDelivery } from '../../../services/CampaignService'; // // S4e-1 - turning campaign counters into an HONEST report. // // THE WHOLE POINT OF THIS MODULE IS THAT ABSENT IS NOT ZERO. A campaign sent before S4e-1 shipped // carries no SES message tags and will never receive a delivery event. Rendering it "0 delivered" // asserts that its mail did not land, when the truth is that we never measured - the same false // assertion class as reference-authz-denial-never-renders-as-empty-data. // // NEVER write `counts.delivered ?? 0` anywhere in this file or its consumers. That single // expression is the bug this module exists to prevent, and it looks completely reasonable. // export type TrackingVerdict = | { kind: 'untracked' } | { kind: 'full' } | { kind: 'partial'; tracked: number; sent: number }; /** * How much of this campaign's delivery we can actually speak to. * * `partial` is not hypothetical: a campaign parked in `sending` across the S4e-1 deploy has some * recipients tagged and some not, so its delivery figures are a FLOOR. Presence of the counter * cannot detect that - only the denominator can. */ export function describeTracking(counts: CampaignCounts): TrackingVerdict { const tracked = counts.trackedSends; if (tracked === undefined || tracked === 0) return { kind: 'untracked' }; if (tracked >= counts.sent) return { kind: 'full' }; return { kind: 'partial', tracked, sent: counts.sent }; } const DELIVERY_ROWS: { label: string; key: keyof CampaignDelivery }[] = [ { label: 'Delivered', key: 'delivered' }, { label: 'Bounced', key: 'bounced' }, { label: 'Spam complaints', key: 'complained' }, { label: 'Unsubscribed', key: 'unsubscribed' }, // S4e-2 { label: 'Clicked', key: 'clicked' }, { label: 'Booked', key: 'booked' }, ]; export function reportRows( counts: CampaignCounts, delivery: CampaignDelivery | null | undefined, ): { label: string; value: number }[] { const rows = [ { label: 'Sent', value: counts.sent }, { label: 'Failed', value: counts.failed }, { label: 'Suppressed', value: counts.suppressed }, ]; // `null` MEANS NO DELIVERY ROW EXISTS (the campaign was never tracked); `undefined` means // THIS RESPONSE never carried the field at all (final fix wave, CRITICAL 2 - only `GET /{id}` // attaches `delivery`; send/schedule/cancel/list/post/put don't). Both honestly mean "no // measurement on this payload", and neither is zero, so they're deliberately handled alike here // with `==` rather than `===` - this is the one spot in this file where loose equality is // correct, not sloppy. Returning early with no delivery rows is the honest answer either way. // Never `delivery ?? {}`: that turns "never measured" into "measured, all absent", which // reads on screen as though the mail simply never arrived. if (delivery == null) return rows; for (const { label, key } of DELIVERY_ROWS) { const value = delivery[key]; // `!== undefined`, never `??`. A tracked campaign with genuinely zero deliveries MUST show // "Delivered 0"; a counter that never fired must show no row. `?? 0` collapses those two. if (value !== undefined) rows.push({ label, value }); } // SURFACED, NEVER CLAMPED (spec ยง3). More deliveries than sends is impossible and means a // real bug - most likely dedup failing. Clamping would destroy the only evidence, so the numbers // are reported exactly as stored and the anomaly is announced where a developer will find it. if (delivery.delivered !== undefined && delivery.delivered > counts.sent) { console.warn( `CAMPAIGN_REPORT_IMPOSSIBLE_COUNTS: delivered=${delivery.delivered} exceeds sent=${counts.sent}`, ); } return rows; } export function campaignReportRows(campaign: Campaign): { label: string; value: number | string }[] { if (campaign.protocolVersion !== 2) return reportRows(campaign.counts, campaign.delivery); const rows: { label: string; value: number | string }[] = []; const requested = campaign.channels.filter((channel): channel is 'email' | 'sms' => channel === 'email' || channel === 'sms'); let knownMessages = 0; let allKnown = true; for (const channel of requested) { const label = channel === 'email' ? 'Email' : 'SMS'; const counts = campaign.channelCounts?.[channel]; const delivery = campaign.channelDelivery?.[channel]; for (const [key, caption] of [ ['accepted', 'accepted'], ['failedBeforeAcceptance', 'failed before acceptance'], ['suppressed', 'suppressed'], ['unknown', 'send outcome unknown'], ['owed', 'dispatch owed'], ] as const) { rows.push({ label: `${label} ${caption}`, value: counts?.[key] ?? 'Unavailable' }); } if (counts?.accepted === undefined) allKnown = false; else knownMessages += counts.accepted; if (channel === 'sms') { for (const [key, caption] of [['delivered', 'delivery confirmed'], ['failed', 'terminal undelivered'], ['pending', 'delivery pending'], ['unknown', 'delivery unknown']] as const) { rows.push({ label: `SMS ${caption}`, value: delivery?.[key] ?? 'Unavailable' }); } } else { for (const [key, caption] of [['delivered', 'delivered'], ['bounced', 'bounced'], ['complained', 'spam complaints'], ['unsubscribed', 'unsubscribed']] as const) { if (delivery?.[key] !== undefined) rows.push({ label: `Email ${caption}`, value: delivery[key]! }); } rows.push({ label: 'Email delivery tracking coverage', value: counts?.accepted === undefined || counts.trackedSends === undefined ? 'Unavailable' : `${counts.trackedSends} of ${counts.accepted} accepted email messages` }); } } rows.push({ label: 'Accepted messages total', value: allKnown ? knownMessages : 'Unavailable' }); rows.push({ label: 'Matched people', value: campaign.execution?.matchedPeople ?? 'Unavailable' }); if (campaign.execution?.continuation && campaign.execution.legacyCounts) { for (const row of reportRows(campaign.execution.legacyCounts, undefined)) { rows.push({ label: `Historical email ${row.label.toLowerCase()}`, value: row.value }); } } for (const [key, label] of [['clicked', 'Campaign link clicks'], ['booked', 'Campaign bookings']] as const) { if (campaign.delivery?.[key] !== undefined) rows.push({ label, value: campaign.delivery[key]! }); } return rows; } export function campaignDispatchComplete(campaign: Campaign): boolean { if (campaign.protocolVersion !== 2) return campaign.status === 'sent'; return campaign.channels.length > 0 && campaign.channels.every((channel) => (channel === 'email' || channel === 'sms') && campaign.execution?.legs?.[channel]?.state === 'dispatch-complete' && campaign.channelCounts?.[channel]?.owed === 0 && campaign.channelCounts?.[channel]?.unknown === 0); } /** Dispatch evidence only; provider delivery remains a separate report. */ export function campaignDispatchSummary(campaign: Campaign): string { const requested = campaign.channels.filter((channel): channel is 'email' | 'sms' => channel === 'email' || channel === 'sms'); const details = requested.map(channel => { const counts = campaign.channelCounts?.[channel]; const values = [ ['accepted', 'accepted'], ['failedBeforeAcceptance', 'failed before acceptance'], ['suppressed', 'suppressed'], ['unknown', 'send outcome unknown'], ['owed', 'dispatch owed'], ] as const; const state = campaign.execution?.legs?.[channel]?.state; return `${channel === 'email' ? 'Email' : 'SMS'}${state && state !== 'dispatch-complete' ? ` (${state})` : ''}: ` + values.map(([key, label]) => `${counts?.[key] ?? 'unavailable'} ${label}`).join(', ') + '.'; }); if (campaign.execution?.continuation && campaign.execution.legacyCounts) { const counts = campaign.execution.legacyCounts; details.push(`Historical email: ${counts.sent} sent, ${counts.failed} failed, ${counts.suppressed} suppressed. Historical recipient outcomes remain unresolved.`); } return details.join(' '); }