{"id":"bumpgrade-audience-automation-source-data","updatedAt":"2026-05-22","status":"audience-sequence-delivery-readiness-ready","issue":351,"parentIssue":17,"generatedFrom":"src/lib/audience-automation.ts","routes":["/audience/source-data","/api/audience/opt-in","/api/audience/unsubscribe","/api/admin/audience/notes","/api/admin/audience/broadcasts/schedule-intents","/api/admin/audience/broadcasts/delivery-batches","/api/admin/audience/broadcasts/delivery-queue-messages","/api/admin/audience/broadcasts/dispatch-preflights","/api/admin/audience/broadcasts/dispatch-attempts","/api/admin/audience/import-intents","/api/admin/audience/import-preflights","/admin/audience","/audience/indie-launch-waitlist"],"stableIds":["subscriberId","subscriberInspectionId","subscriberSegmentId","optInFormId","leadMagnetId","subscriberTagId","emailSequenceId","sequenceEnrollmentPauseId","sequenceDeliveryReadinessId","automationRuleId","broadcastDraftId","consentRecordId","suppressionEntryId","timelineEntryId","broadcastReadinessId","broadcastScheduleIntentId","broadcastPreviewSafetyId","broadcastQueueReadinessId","broadcastDeliveryBatchId","broadcastDeliveryQueueMessageId","broadcastDispatchPreflightId","broadcastDispatchAttemptId","broadcastSenderDomainReadinessId","broadcastProviderEventReadinessId","broadcastProviderRateLimitReadinessId","broadcastProviderResponseReadinessId","broadcastSendPayloadReadinessId","broadcastQueueProducerReadinessId","broadcastQueueConsumerReadinessId","audienceImportIntentId","audienceImportPreflightId","audienceExportReadinessId","agentActionId"],"optInWrites":{"id":"audience-opt-in-consent-capture-contract","status":"subscriber-capture-ready","issue":103,"parentIssue":17,"apiRoute":"/api/audience/opt-in","tables":["audience_subscribers","audience_consent_events","audience_tag_assignments","audience_sequence_enrollments"],"publicSafeFields":["subscriberId","normalizedEmail","formId","tagIds","sequenceId","status","emailDeliveryEnabled"],"serverPrivateFields":["email","email_hash","first_name","ip_hash","user_agent_hash","metadata_json","raw request headers","unsubscribe tokens"],"writeBoundary":"Issue #103 can capture explicit-consent opt-ins, normalize subscriber email, assign seeded tags, and record draft sequence enrollment evidence. Issue #167 handles public-safe unsubscribe/suppression evidence separately. Email sending, imports, broadcasts, CRM notes, and direct agent writes require future confirmed-write APIs."},"unsubscribeWrites":{"id":"audience-unsubscribe-suppression-contract","status":"unsubscribe-sequence-pause-ready","issue":343,"suppressionIssue":167,"sequencePauseIssue":343,"parentIssue":17,"apiRoute":"/api/audience/unsubscribe","tables":["audience_subscribers","audience_suppression_entries","audience_sequence_enrollments"],"publicSafeFields":["suppressionEntryId","normalizedEmail","status","duplicate","emailDeliveryEnabled","subscriberExistenceRevealed","sequenceEnrollmentStateIncluded"],"serverPrivateFields":["email_hash","subscriber_id","reason","ip_hash","user_agent_hash","metadata_json","raw request headers"],"redaction":{"privateContactDataIncluded":false,"subscriberExistenceRevealed":false,"rawEmailIncludedInSourceData":false,"rawIpIncluded":false,"rawUserAgentIncluded":false},"writeBoundary":"Issue #167 can record unsubscribe/suppression evidence for a normalized email with idempotency and can mark known subscribers unsubscribed without revealing list membership. Issue #343 also pauses known draft sequence enrollments as aggregate owner evidence while keeping the public response membership-safe. Email sending, imports, broadcasts, CRM notes, private exports, and direct agent subscriber writes still require authenticated confirmed-write APIs with suppression checks."},"crmTimelineWrites":{"id":"audience-crm-timeline-note-contract","status":"owner-crm-timeline-ready","issue":169,"parentIssue":17,"apiRoute":"/api/admin/audience/notes","auth":"owner-session","tables":["audience_subscribers","audience_timeline_entries"],"confirmation":{"required":true,"text":"Create private Bumpgrade audience timeline note"},"publicSafeFields":["timelineEntryId","subscriberId","entryKind","status","duplicate","privateNoteBodyIncluded"],"serverPrivateFields":["body","body_hash","actor_email","metadata_json","raw subscriber email"],"redaction":{"publicNoteBodiesIncluded":false,"privateContactDataIncluded":false,"rawEmailIncludedInSourceData":false},"writeBoundary":"Issue #169 lets verified owners create private audience CRM timeline notes with exact confirmation, idempotency, and expected subscriber-status checks. Public source-data exposes aggregate note counts and redaction flags only; imports, email sends, broadcasts, private exports, and direct agent subscriber writes remain unavailable."},"writeBoundary":"Issue #103 can capture explicit-consent opt-ins, normalize subscriber email, assign seeded tags, and record draft sequence enrollment evidence. Issue #137 can inspect private subscriber rows behind owner auth and expose aggregate public redaction flags. Issue #167 can record unsubscribe/suppression evidence and mark known subscribers unsubscribed without revealing list membership. Issue #343 pauses known draft sequence enrollments after unsubscribe while public responses stay membership-safe and source-data exposes aggregate paused-sequence evidence only. Issue #351 exposes aggregate sequence delivery readiness counts without scheduling sequence steps, creating recipient payloads, personalized bodies, unsubscribe URLs, queue payloads, provider sends, or provider message IDs. Issue #169 can create owner-only CRM timeline notes with exact confirmation, idempotency, and expected subscriber-status checks. Issue #171 can inspect suppression-aware broadcast draft readiness without creating send queues. Issue #173 can record owner-confirmed dry-run broadcast schedule intents with idempotency, exact confirmation, draft revision checks, and expected readiness counts while still creating no send queue rows. Issue #175 can inspect broadcast preview and unsubscribe-footer safety without personalized bodies or provider sends. Issue #177 can inspect delivery queue readiness metadata without queue producers, recipient payloads, or provider sends. Issue #183 can record owner-confirmed delivery-batch dry runs after schedule-intent, queue, preview, suppression, and stale-state checks while still creating no recipient payloads, queue messages, or provider sends. Issue #189 can record owner-confirmed dry-run queue-message evidence from a delivery batch without Cloudflare Queue dispatch, recipient payloads, provider sends, or provider message IDs. Issue #191 can record owner-confirmed dispatch preflight evidence from a queue-message record without Cloudflare Queue dispatch, recipient payloads, provider sends, or provider message IDs. Issue #197 can record owner-confirmed dispatch attempt receipts from a dispatch preflight without Cloudflare Queue producers, queue payload bodies, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #199 can inspect sender-domain readiness gates without private DNS credentials, raw DNS records, provider secrets, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #201 can inspect provider-event readiness gates without provider secrets, raw provider payloads, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #203 can inspect provider rate-limit readiness gates without provider secrets, provider limit secrets, raw provider payloads, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #205 can inspect provider response readiness gates without provider secrets, raw response bodies, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #207 can inspect send-payload readiness gates without raw recipient identity, recipient payloads, personalized bodies, raw payload bodies, Cloudflare Queue producers, provider sends, provider responses, or provider message IDs. Issue #209 can inspect Queue producer readiness gates without enabling Cloudflare Queue producers, creating Queue messages, creating queue payload bodies, creating recipient payloads, sending through a provider, creating provider responses, or creating provider message IDs. Issue #211 can inspect Queue consumer readiness gates without enabling Cloudflare Queue consumers, consuming or acking Queue messages, creating retry/dead-letter rows, reading queue payload bodies, creating recipient payloads, sending through a provider, creating provider responses, or creating provider message IDs. Issue #253 can record owner-confirmed import intent metadata with exact confirmation, idempotency, workspace revision/status checks, aggregate counts, and hashed private notes while creating no subscribers, raw contact rows, sequence enrollments, or sends. Issue #259 can record owner-confirmed import preflight evidence against a selected import intent with exact confirmation, idempotency, workspace stale-state checks, source-label checks, aggregate eligibility/suppression/consent/malformed counts, and hashed private notes while creating no subscribers, raw contact rows, sequence enrollments, exports, or sends. Issue #347 exposes aggregate audience export readiness counts without export files, raw emails, subscriber IDs, or export URLs. Real contact imports, real email sends, private exports, CRM automation, and direct agent writes require actor identity, explicit consent or lawful basis, idempotency, audit correlation, stale-state checks, redaction, suppression-list checks, unsubscribe footers, sender-domain safety, provider-event safety, provider rate-limit safety, provider response safety, send-payload safety, Queue producer safety, Queue consumer safety, queue safety, and provider limits.","workspaces":[{"id":"audience-automation-workspace-indie-launch","slug":"indie-launch-waitlist","title":"Indie launch waitlist and nurture","status":"draft","issue":253,"parentIssue":17,"sourceDataRoute":"/audience/source-data","previewRoute":"/audience/indie-launch-waitlist","linkedFunnelRoute":"/funnels/indie-launch-sandbox","linkedOfferRoute":"/offers/indie-launch-stack","linkedProductRoute":"/products/indie-launch-library","revisionId":"audience-automation-revision-indie-launch-2026-05-20","summary":"An audience workspace for opt-ins, consent, tags, suppression, CRM notes, launch emails, campaign checks, import planning, and practical follow-up.","segments":[{"id":"segment-indie-launch-waitlist","title":"Indie launch waitlist","status":"draft","source":"Opt-in form submission after explicit consent","definition":"People who request the launch checklist and want follow-up about the launch offer.","privateDataExcluded":["Email address","name","IP address","user agent","consent timestamp"]},{"id":"segment-product-interested-publishers","title":"Product-interested publishers","status":"draft","source":"Tagged waitlist contact after product-access link click or manual import in a future confirmed workflow","definition":"Publishers interested in downloads, courses, memberships, or bundles.","privateDataExcluded":["Clickstream detail","subscriber identity","purchase intent score"]}],"tags":[{"id":"tag-lead-magnet-launch-checklist","label":"lead-magnet:launch-checklist","purpose":"Mark contacts who requested the launch checklist lead magnet."},{"id":"tag-source-funnel-indie-launch","label":"source:funnel-indie-launch","purpose":"Record the funnel/source context without exposing raw referral or UTM payloads."},{"id":"tag-intent-product-access","label":"intent:product-access","purpose":"Identify contacts who should receive product/access education later."}],"leadMagnets":[{"id":"lead-magnet-launch-checklist","title":"Launch checklist lead magnet","deliveryPromise":"Send a practical launch checklist after consent and email verification.","assetBoundary":"No private file, R2 object key, signed URL, or recipient email is exposed in this public source-data contract."}],"forms":[{"id":"opt-in-form-indie-launch-waitlist","slug":"indie-launch-waitlist","title":"Indie launch waitlist opt-in","status":"draft","routeAnchor":"indie-launch-waitlist-opt-in","sourceFunnelStepId":"funnel-step-indie-launch-opt-in","targetSegmentIds":["segment-indie-launch-waitlist"],"tagIds":["tag-lead-magnet-launch-checklist","tag-source-funnel-indie-launch"],"leadMagnetId":"lead-magnet-launch-checklist","fields":[{"id":"field-waitlist-email","label":"Email address","kind":"email","required":true,"storageBoundary":"The opt-in API trims and normalizes email before validation, then stores it server-side with consent evidence."},{"id":"field-waitlist-name","label":"First name","kind":"text","required":false,"storageBoundary":"Optional profile data must stay private and is not part of public source-data."},{"id":"field-waitlist-consent","label":"Consent to receive launch emails","kind":"checkbox","required":true,"storageBoundary":"Consent records include timestamp, source form, idempotency key, and hashed request evidence; unsubscribe/suppression evidence is recorded through a separate public-safe endpoint."}],"consentStatement":"I want the launch checklist and practical follow-up about Bumpgrade. I can unsubscribe later.","writeBoundary":"This form posts to /api/audience/opt-in. Unsubscribe preferences post to /api/audience/unsubscribe. Owner-only CRM notes, dry-run broadcast evidence, import intents, and import preflights now use separate confirmed-write APIs; export readiness is aggregate-only. Real contact imports, email delivery, broadcast sends, and private exports require future confirmed-write APIs with actor identity, explicit consent or lawful basis, idempotency, audit correlation, redaction, unsubscribe metadata, and spam-safe sending rules."}],"sequences":[{"id":"sequence-indie-launch-nurture","title":"Indie launch nurture sequence","status":"draft","trigger":"opt-in-form-indie-launch-waitlist submitted with confirmed consent","linkedFormId":"opt-in-form-indie-launch-waitlist","steps":[{"id":"email-step-deliver-checklist","subjectIntent":"Deliver the requested launch checklist","timing":"immediate","delayValue":0,"goal":"Fulfill the lead magnet promise with a clear checklist delivery.","agentEditable":true},{"id":"email-step-map-funnel","subjectIntent":"Show how the funnel, offer, and product records connect","timing":"delay_hours","delayValue":24,"goal":"Show subscribers how the funnel, offer, and product path connect.","agentEditable":true},{"id":"email-step-invite-sandbox-offer","subjectIntent":"Invite a safe checkout review","timing":"delay_days","delayValue":3,"goal":"Point to the checkout offer only after consent and clear buyer expectations.","agentEditable":true}],"writeBoundary":"Sequence drafts and issue #351 delivery-readiness counts are source-data only. Sending, scheduling, suppression checks, recipient payloads, unsubscribe URLs, and contact-specific personalization require future confirmed-write email infrastructure."}],"automations":[{"id":"automation-enroll-waitlist-nurture","title":"Enroll consenting waitlist contacts in nurture","status":"draft","triggerEvent":"audience.opt_in.created","conditions":["Consent checkbox is true.","Email passes normalization and validation.","Idempotency key has not already enrolled this email/form pair."],"actions":[{"id":"automation-action-tag-lead-magnet","kind":"tag_contact","targetId":"tag-lead-magnet-launch-checklist","summary":"Apply the launch-checklist tag after consent is recorded."},{"id":"automation-action-start-sequence","kind":"start_sequence","targetId":"sequence-indie-launch-nurture","summary":"Start the draft nurture sequence once safe delivery infrastructure exists."},{"id":"automation-action-record-event","kind":"record_event","targetId":"event-audience-opt-in-created","summary":"Record a future analytics event without exposing private subscriber fields."}],"writeBoundary":"Automation execution is disabled. Future runs need confirmed consent, unsubscribe checks, rate limiting, audit correlation, and failure handling before any email is sent."}],"broadcastDrafts":[{"id":"broadcast-draft-launch-window","title":"Launch window announcement","status":"draft","audienceScope":"Only subscribers who explicitly opted into the indie launch waitlist and are not unsubscribed.","approvalBoundary":"Issue #211 can inspect Queue consumer readiness for this draft, but real sending still requires verified sender alignment, provider event handling, provider rate-limit handling, provider response handling, send-payload creation, Queue producers/consumers, and audit correlation."}],"unsubscribeManagement":{"id":"audience-unsubscribe-suppression-contract","status":"unsubscribe-sequence-pause-ready","issue":343,"suppressionIssue":167,"sequencePauseIssue":343,"parentIssue":17,"apiRoute":"/api/audience/unsubscribe","tables":["audience_subscribers","audience_suppression_entries","audience_sequence_enrollments"],"publicSafeFields":["suppressionEntryId","normalizedEmail","status","duplicate","emailDeliveryEnabled","subscriberExistenceRevealed","sequenceEnrollmentStateIncluded"],"serverPrivateFields":["email_hash","subscriber_id","reason","ip_hash","user_agent_hash","metadata_json","raw request headers"],"redaction":{"privateContactDataIncluded":false,"subscriberExistenceRevealed":false,"rawEmailIncludedInSourceData":false,"rawIpIncluded":false,"rawUserAgentIncluded":false},"writeBoundary":"Issue #167 can record unsubscribe/suppression evidence for a normalized email with idempotency and can mark known subscribers unsubscribed without revealing list membership. Issue #343 also pauses known draft sequence enrollments as aggregate owner evidence while keeping the public response membership-safe. Email sending, imports, broadcasts, CRM notes, private exports, and direct agent subscriber writes still require authenticated confirmed-write APIs with suppression checks."},"crmTimeline":{"id":"audience-crm-timeline-note-contract","status":"owner-crm-timeline-ready","issue":169,"parentIssue":17,"apiRoute":"/api/admin/audience/notes","auth":"owner-session","tables":["audience_subscribers","audience_timeline_entries"],"confirmation":{"required":true,"text":"Create private Bumpgrade audience timeline note"},"publicSafeFields":["timelineEntryId","subscriberId","entryKind","status","duplicate","privateNoteBodyIncluded"],"serverPrivateFields":["body","body_hash","actor_email","metadata_json","raw subscriber email"],"redaction":{"publicNoteBodiesIncluded":false,"privateContactDataIncluded":false,"rawEmailIncludedInSourceData":false},"writeBoundary":"Issue #169 lets verified owners create private audience CRM timeline notes with exact confirmation, idempotency, and expected subscriber-status checks. Public source-data exposes aggregate note counts and redaction flags only; imports, email sends, broadcasts, private exports, and direct agent subscriber writes remain unavailable."},"broadcastScheduleIntentApiRoute":"/api/admin/audience/broadcasts/schedule-intents","broadcastDeliveryBatchApiRoute":"/api/admin/audience/broadcasts/delivery-batches","broadcastDeliveryQueueMessageApiRoute":"/api/admin/audience/broadcasts/delivery-queue-messages","broadcastDispatchPreflightApiRoute":"/api/admin/audience/broadcasts/dispatch-preflights","broadcastDispatchAttemptApiRoute":"/api/admin/audience/broadcasts/dispatch-attempts","audienceImportIntentApiRoute":"/api/admin/audience/import-intents","audienceImportPreflightApiRoute":"/api/admin/audience/import-preflights","writeBoundary":"Issue #103 can capture explicit-consent opt-ins, normalize subscriber email, assign seeded tags, and record draft sequence enrollment evidence. Issue #137 can inspect private subscriber rows behind owner auth and expose aggregate public redaction flags. Issue #167 can record unsubscribe/suppression evidence and mark known subscribers unsubscribed without revealing list membership. Issue #343 pauses known draft sequence enrollments after unsubscribe while public responses stay membership-safe and source-data exposes aggregate paused-sequence evidence only. Issue #351 exposes aggregate sequence delivery readiness counts without scheduling sequence steps, creating recipient payloads, personalized bodies, unsubscribe URLs, queue payloads, provider sends, or provider message IDs. Issue #169 can create owner-only CRM timeline notes with exact confirmation, idempotency, and expected subscriber-status checks. Issue #171 can inspect suppression-aware broadcast draft readiness without creating send queues. Issue #173 can record owner-confirmed dry-run broadcast schedule intents with idempotency, exact confirmation, draft revision checks, and expected readiness counts while still creating no send queue rows. Issue #175 can inspect broadcast preview and unsubscribe-footer safety without personalized bodies or provider sends. Issue #177 can inspect delivery queue readiness metadata without queue producers, recipient payloads, or provider sends. Issue #183 can record owner-confirmed delivery-batch dry runs after schedule-intent, queue, preview, suppression, and stale-state checks while still creating no recipient payloads, queue messages, or provider sends. Issue #189 can record owner-confirmed dry-run queue-message evidence from a delivery batch without Cloudflare Queue dispatch, recipient payloads, provider sends, or provider message IDs. Issue #191 can record owner-confirmed dispatch preflight evidence from a queue-message record without Cloudflare Queue dispatch, recipient payloads, provider sends, or provider message IDs. Issue #197 can record owner-confirmed dispatch attempt receipts from a dispatch preflight without Cloudflare Queue producers, queue payload bodies, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #199 can inspect sender-domain readiness gates without private DNS credentials, raw DNS records, provider secrets, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #201 can inspect provider-event readiness gates without provider secrets, raw provider payloads, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #203 can inspect provider rate-limit readiness gates without provider secrets, provider limit secrets, raw provider payloads, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #205 can inspect provider response readiness gates without provider secrets, raw response bodies, Cloudflare Queue producers, recipient payloads, provider sends, provider responses, or provider message IDs. Issue #207 can inspect send-payload readiness gates without raw recipient identity, recipient payloads, personalized bodies, raw payload bodies, Cloudflare Queue producers, provider sends, provider responses, or provider message IDs. Issue #209 can inspect Queue producer readiness gates without enabling Cloudflare Queue producers, creating Queue messages, creating queue payload bodies, creating recipient payloads, sending through a provider, creating provider responses, or creating provider message IDs. Issue #211 can inspect Queue consumer readiness gates without enabling Cloudflare Queue consumers, consuming or acking Queue messages, creating retry/dead-letter rows, reading queue payload bodies, creating recipient payloads, sending through a provider, creating provider responses, or creating provider message IDs. Issue #253 can record owner-confirmed import intent metadata with exact confirmation, idempotency, workspace revision/status checks, aggregate counts, and hashed private notes while creating no subscribers, raw contact rows, sequence enrollments, or sends. Issue #259 can record owner-confirmed import preflight evidence against a selected import intent with exact confirmation, idempotency, workspace stale-state checks, source-label checks, aggregate eligibility/suppression/consent/malformed counts, and hashed private notes while creating no subscribers, raw contact rows, sequence enrollments, exports, or sends. Issue #347 exposes aggregate audience export readiness counts without export files, raw emails, subscriber IDs, or export URLs. Real contact imports, real email sends, private exports, CRM automation, and direct agent writes require actor identity, explicit consent or lawful basis, idempotency, audit correlation, stale-state checks, redaction, suppression-list checks, unsubscribe footers, sender-domain safety, provider-event safety, provider rate-limit safety, provider response safety, send-payload safety, Queue producer safety, Queue consumer safety, queue safety, and provider limits.","validation":["/audience/source-data returns seeded audience segments, forms, tags, sequences, automations, and write boundaries.","/audience/indie-launch-waitlist renders the opt-in and nurture preview.","/api/audience/opt-in stores normalized subscriber, consent, tag, and draft sequence enrollment evidence.","/api/audience/unsubscribe stores suppression evidence without exposing list membership.","/audience/source-data exposes aggregate sequence delivery readiness without queue rows, recipient payloads, personalized bodies, unsubscribe URLs, provider sends, or provider message IDs.","/api/admin/audience/notes stores owner-only CRM timeline notes with public aggregate redaction.","Broadcast readiness is calculated from D1 subscriber, consent, and suppression evidence without creating send queue rows.","/api/admin/audience/broadcasts/schedule-intents stores owner-confirmed dry-run schedule intents without recipient payloads, queues, or provider message IDs.","Broadcast preview safety is stored from D1 without personalized bodies, recipient payloads, send queue rows, or provider message IDs.","Broadcast delivery queue readiness is stored from D1 without queue producer rows, recipient payloads, provider sends, or provider message IDs.","/api/admin/audience/broadcasts/delivery-batches stores owner-confirmed delivery-batch dry runs without recipient payloads, queue messages, provider sends, or provider message IDs.","/api/admin/audience/broadcasts/delivery-queue-messages stores owner-confirmed dry-run queue-message evidence without Cloudflare Queue dispatch, recipient payloads, provider sends, or provider message IDs.","/api/admin/audience/broadcasts/dispatch-preflights stores owner-confirmed dispatch preflight evidence without Cloudflare Queue dispatch, recipient payloads, provider sends, or provider message IDs.","/api/admin/audience/broadcasts/dispatch-attempts stores owner-confirmed dispatch attempt receipts without Cloudflare Queue producers, queue payload bodies, recipient payloads, provider sends, provider responses, or provider message IDs.","Sender-domain readiness records expose SPF, DKIM, DMARC, reply-path, bounce-handling, and provider-send gates without private DNS credentials, raw DNS records, provider secrets, queue producers, recipient payloads, provider responses, or provider message IDs.","Provider-event readiness records expose bounce, complaint, delivery-event, suppression-update, and raw-payload storage gates without provider secrets, raw provider payloads, recipient payloads, provider responses, or provider message IDs.","Provider rate-limit readiness records expose throttle windows, retry/backoff, queue backpressure, and provider-limit policies without provider secrets, provider limit secrets, raw provider payloads, recipient payloads, provider responses, or provider message IDs.","Provider response readiness records expose accepted/transient/permanent response handling, retry decision, message-id storage, and response-body storage policies without provider secrets, raw response bodies, recipient payloads, provider responses, or provider message IDs.","Send-payload readiness records expose payload scope, consent/suppression recheck, unsubscribe footer, personalization token, and audit policies without raw recipient identity, recipient payloads, personalized bodies, raw payload bodies, provider sends, provider responses, or provider message IDs.","Queue producer readiness records expose binding, producer mode, payload dependency, consumer dependency, idempotency, audit, and backpressure gates without enabling Cloudflare Queue producers, creating Queue messages, queue payload bodies, recipient payloads, provider sends, provider responses, or provider message IDs.","Queue consumer readiness records expose consumer mode, producer dependency, ack, retry, dead-letter, provider handoff, idempotency, and audit gates without enabling Cloudflare Queue consumers, consuming or acking Queue messages, reading queue payload bodies, creating recipient payloads, provider sends, provider responses, or provider message IDs.","/api/admin/audience/import-intents stores owner-confirmed import intent metadata without raw contact rows, raw emails, sequence enrollments, email delivery, or private note exposure.","/api/admin/audience/import-preflights stores owner-confirmed import preflight evidence without raw contact rows, raw emails, subscriber writes, sequence enrollments, exports, email delivery, or private note exposure.","/audience/source-data exposes aggregate export readiness without export files, raw emails, subscriber IDs, or export URLs.","/agent-docs/source-data lists the audience automation read contract for future MCP resources."]}],"caveat":"This contract proves audience, opt-in, email sequence, automation read/preview semantics, consent-backed subscriber capture, public-safe unsubscribe/suppression evidence, unsubscribe-paused sequence enrollment aggregates from issue #343, aggregate sequence delivery-readiness evidence from issue #351, owner-only CRM timeline note evidence, suppression-aware broadcast readiness, owner-confirmed dry-run schedule intent evidence, broadcast preview/footer safety evidence, delivery queue readiness evidence, delivery-batch dry-run evidence, dry-run queue-message evidence, dispatch preflight evidence, dispatch attempt receipts, sender-domain readiness gates, provider-event readiness gates, provider rate-limit readiness gates, provider response readiness gates, send-payload readiness gates, Queue producer readiness gates, Queue consumer readiness gates, owner-confirmed import intent evidence, owner-confirmed import preflight evidence, aggregate export-readiness evidence, and aggregate owner-inspection evidence. It does not import contacts, store raw import rows, store raw emails, create subscriber rows, create sequence enrollments from imports, export private contact data, create export files, expose export URLs, schedule sequence steps, send email, dispatch Cloudflare Queue messages, execute Queue producers or consumers, create queue payload bodies, read queue payload bodies, create retry/dead-letter rows, create recipient payloads, create personalized bodies, expose body templates, expose unsubscribe URLs, expose private DNS credentials, expose raw DNS records, expose provider secrets, expose provider limit secrets, expose raw provider payloads, expose raw provider response bodies, expose raw payload bodies, expose import private notes, publicly expose private contact data, automate CRM actions, or provide direct confirmed-write public agent APIs.","subscriberInspection":{"id":"audience-subscriber-inspection-contract","status":"owner-subscriber-inspection-ready","issue":137,"parentIssue":17,"ownerRoute":"/admin/audience","publicSourceDataRoute":"/audience/source-data","source":"d1","loadError":null,"counts":{"subscribers":5,"unsubscribedSubscribers":1,"consentEvents":5,"tagAssignments":10,"sequenceEnrollments":5,"pausedSequenceEnrollments":1,"suppressionEntries":2,"activeSuppressionEntries":2,"timelineEntries":0,"activeTimelineEntries":0},"lastSubscriberAt":"2026-05-22T13:51:15.000Z","lastConsentAt":"2026-05-22T13:51:15.000Z","lastSuppressionAt":"2026-05-22T13:51:16.000Z","lastTimelineAt":null,"formCounts":[{"id":"opt-in-form-indie-launch-waitlist","status":"subscribed","total":4},{"id":"opt-in-form-indie-launch-waitlist","status":"unsubscribed","total":1}],"tagCounts":[{"id":"tag-lead-magnet-launch-checklist","status":"active","total":5},{"id":"tag-source-funnel-indie-launch","status":"active","total":5}],"sequenceCounts":[{"id":"sequence-indie-launch-nurture","status":"draft_enrolled","total":4},{"id":"sequence-indie-launch-nurture","status":"unsubscribe_paused","total":1}],"suppressionCounts":[{"id":"unsubscribe","status":"active","total":2}],"timelineCounts":[],"redaction":{"privateContactDataIncluded":false,"rawEmailIncluded":false,"rawNameIncluded":false,"rawIpIncluded":false,"rawUserAgentIncluded":false,"rawSuppressionHashIncluded":false,"suppressionReasonIncluded":false,"privateTimelineNoteBodiesIncluded":false,"timelineActorEmailIncluded":false},"privateFieldsExcluded":["email","firstName","emailHash","ipHash","userAgentHash","suppressionReason","timelineNoteBody","timelineActorEmail","metadataJson"],"writeBoundary":"Issue #137 exposes owner-gated subscriber inspection and public aggregate source-data. Issue #167 records unsubscribe/suppression evidence and marks known subscribers unsubscribed without public list-membership leakage. Issue #169 lets owners create private CRM timeline notes while public source-data exposes aggregate counts only. Issue #171 calculates suppression-aware broadcast readiness without creating send queues. Issue #173 records owner-confirmed dry-run schedule intents without recipient payloads or provider message IDs. Issue #175 exposes preview and unsubscribe-footer safety without personalized bodies. Issue #177 exposes queue readiness metadata without producers, recipient payloads, or provider sends. Issue #189 exposes queue-message dry-run evidence without Cloudflare Queue dispatch, recipient payloads, or provider sends. Issue #191 exposes dispatch preflight evidence without Cloudflare Queue dispatch, recipient payloads, or provider sends. Imports, real sends, private subscriber exports, and direct agent writes still require future confirmed-write APIs with consent and suppression checks."},"broadcastReadiness":{"id":"audience-broadcast-readiness-contract","status":"broadcast-readiness-ready","issue":171,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"broadcastDrafts":1,"scopedSubscribers":5,"consentedSubscribers":5,"readyRecipients":4,"suppressedRecipients":0,"unsubscribedRecipients":1,"missingConsentRecipients":0,"activeSuppressionEntries":2},"lastReadinessAt":"2026-05-19T22:41:31.000Z","drafts":[{"id":"broadcast-draft-launch-window","workspaceId":"audience-automation-workspace-indie-launch","title":"Launch window announcement","status":"readiness_preview","subjectIntent":"Announce the launch checklist and invite subscribers to inspect the sandbox offer path","previewText":"A short publisher-safe launch note with source-linked product, offer, and unsubscribe context.","audienceScope":"Only subscribers who explicitly opted into the indie launch waitlist, still have consent, and are not suppressed or unsubscribed.","segmentId":"segment-indie-launch-waitlist","approvalBoundary":"Sending stays disabled until an owner confirms the final copy, unsubscribe footer, sender domain, suppression result, and audit correlation.","suppressionPolicy":"Exclude unsubscribed subscribers, active suppression hashes, missing-consent rows, and unknown imported contacts before any send queue can exist.","readyRecipientCount":4,"excludedBySuppressionCount":0,"excludedByUnsubscribeCount":1,"excludedByMissingConsentCount":0,"sendQueueRowsCreated":false,"providerMessageIdsIncluded":false,"updatedAt":"2026-05-19T22:41:31.000Z"}],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"suppressionHashesIncluded":false,"providerMessageIdsIncluded":false,"sendQueueRowsCreated":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","providerMessageId","sendQueuePayload","personalizedBody","metadataJson"],"writeBoundary":"Issue #171 exposes read-only broadcast draft readiness with suppression-aware aggregate counts. It does not send email, schedule broadcasts, create send queue rows, expose private recipients, or authorize direct agent broadcast writes."},"broadcastScheduleIntents":{"id":"audience-broadcast-schedule-intent-contract","status":"broadcast-schedule-intents-ready","issue":173,"parentIssue":17,"apiRoute":"/api/admin/audience/broadcasts/schedule-intents","ownerRoute":"/admin/audience","source":"d1","loadError":null,"confirmation":{"required":true,"text":"Create dry-run Bumpgrade broadcast schedule intent"},"counts":{"scheduleIntents":0,"activeDryRunIntents":0,"readyRecipientsReserved":0,"heldRecipientsSnapshotted":0},"latestIntents":[],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false,"providerMessageIdsIncluded":false,"sendQueueRowsCreated":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","actorEmail","providerMessageId","sendQueuePayload","personalizedBody","metadataJson"],"writeBoundary":"Issue #173 lets verified owners record a dry-run broadcast schedule intent after exact confirmation, idempotency, expected readiness count, and draft revision checks. It does not send email, create recipient payloads, dispatch queues, create provider message IDs, expose private recipients, or authorize direct public agent broadcast writes."},"broadcastPreviewSafety":{"id":"audience-broadcast-preview-safety-contract","status":"broadcast-preview-safety-ready","issue":175,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"previewSafetyRecords":1,"unsubscribeFooterRequiredRecords":1,"senderDomainsReady":0},"records":[{"id":"broadcast-preview-safety-launch-window","draftId":"broadcast-draft-launch-window","status":"preview_safety_ready","subjectLine":"Your Bumpgrade launch window is ready to preview","previewText":"A safe preview of the launch-window broadcast before any send queue exists.","bodyOutline":["Open with the launch checklist promise and reminder of consent.","Explain how the funnel, offer, and product access records now connect.","Invite the subscriber to review the sandbox offer path without implying live fulfillment.","Close with a required unsubscribe footer placeholder before any delivery queue can exist."],"unsubscribeFooterRequired":true,"unsubscribeFooterPolicy":"Required before delivery: every broadcast must include an unsubscribe footer tied to the suppression API and must re-check suppression state immediately before queueing.","senderDomainStatus":"sender_domain_pending","safetyNotes":["Sender-domain alignment is still pending for real customer email.","No recipient payloads, send queue rows, or provider message IDs exist in this preview slice.","Body copy is a reusable outline, not personalized subscriber content.","Agents may inspect this safety record but cannot send or queue broadcasts from public source-data."],"sendQueueRowsCreated":false,"providerMessageIdsIncluded":false,"updatedAt":"2026-05-19T23:29:18.000Z"}],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"personalizedBodyIncluded":false,"providerMessageIdsIncluded":false,"sendQueueRowsCreated":false},"privateFieldsExcluded":["recipientEmail","recipientName","personalizedBody","subscriberEmailHash","suppressionHash","providerMessageId","sendQueuePayload","metadataJson"],"writeBoundary":"Issue #175 exposes owner-visible broadcast preview and unsubscribe-footer safety metadata before delivery exists. It does not personalize messages, create recipient payloads, enqueue sends, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastQueueReadiness":{"id":"audience-broadcast-queue-readiness-contract","status":"broadcast-queue-readiness-ready","issue":177,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"queueReadinessRecords":1,"dryRunQueues":1,"providerSendEnabledRecords":0,"recipientPayloadsCreatedRecords":0},"records":[{"id":"broadcast-queue-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"queue_readiness_ready","queueName":"audience-broadcast-delivery-dry-run","queueMode":"dry_run_contract","retryPolicy":"Future queue workers must use bounded retry with audit correlation, recipient revalidation, and no provider retry before sender-domain verification.","suppressionCheckPolicy":"Future producer must re-check active suppression and subscriber status immediately before queue row creation.","unsubscribeFooterCheckPolicy":"Future producer must require an unsubscribe footer tied to /api/audience/unsubscribe before queue row creation.","senderDomainGate":"sender_domain_pending","auditCorrelationPolicy":"Future queue rows must carry owner action id, broadcast draft id, readiness snapshot id, and idempotency key.","providerSendEnabled":false,"recipientPayloadsCreated":false,"sendQueueRowsCreated":false,"providerMessageIdsIncluded":false,"updatedAt":"2026-05-20T00:33:59.000Z"}],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"recipientPayloadsIncluded":false,"providerMessageIdsIncluded":false,"sendQueueRowsCreated":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","recipientPayload","providerMessageId","sendQueuePayload","metadataJson"],"writeBoundary":"Issue #177 exposes broadcast delivery queue readiness metadata before producer or consumer code exists. It does not create queue rows, recipient payloads, provider message IDs, private exports, or public agent broadcast writes."},"broadcastDeliveryBatches":{"id":"audience-broadcast-delivery-batch-contract","status":"broadcast-delivery-batch-dry-run-ready","issue":183,"parentIssue":17,"apiRoute":"/api/admin/audience/broadcasts/delivery-batches","ownerRoute":"/admin/audience","source":"d1","loadError":null,"confirmation":{"required":true,"text":"Create dry-run Bumpgrade broadcast delivery batch"},"counts":{"deliveryBatches":0,"dryRunBatches":0,"readyRecipientsBatched":0,"heldRecipientsSnapshotted":0,"activeSuppressionsSnapshotted":0,"providerSendEnabledBatches":0,"recipientPayloadsCreatedBatches":0,"providerMessageIdsCreatedBatches":0},"latestBatches":[],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodyIncluded":false,"providerMessageIdsIncluded":false,"sendQueueRowsCreated":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","actorEmail","recipientPayload","providerMessageId","sendQueuePayload","personalizedBody","metadataJson"],"writeBoundary":"Issue #183 lets verified owners record a suppression-checked broadcast delivery-batch dry run after exact confirmation, idempotency, schedule-intent, draft revision, readiness count, preview safety, and queue readiness checks. It does not create recipient payloads, queue messages, provider sends, provider message IDs, private exports, or public agent broadcast writes."},"broadcastDeliveryQueueMessages":{"id":"audience-broadcast-delivery-queue-message-contract","status":"broadcast-delivery-queue-messages-dry-run-ready","issue":189,"parentIssue":17,"apiRoute":"/api/admin/audience/broadcasts/delivery-queue-messages","ownerRoute":"/admin/audience","source":"d1","loadError":null,"confirmation":{"required":true,"text":"Create dry-run Bumpgrade broadcast delivery queue messages"},"counts":{"dryRunRecords":0,"dryRunMessagesSnapshotted":0,"heldRecipientsSnapshotted":0,"providerSendEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"cloudflareQueueMessagesCreatedRecords":0,"providerMessageIdsCreatedRecords":0},"latestMessages":[],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodyIncluded":false,"providerMessageIdsIncluded":false,"cloudflareQueueMessagesCreated":false,"providerSendEnabled":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","actorEmail","recipientPayload","providerMessageId","personalizedBody","cloudflareQueueMessageBody","metadataJson"],"writeBoundary":"Issue #189 lets verified owners record aggregate delivery queue message dry-run evidence from a current delivery batch after exact confirmation, idempotency, draft revision, readiness count, and dry-run queue gates. It does not create Cloudflare Queue messages, recipient payloads, provider sends, provider message IDs, private exports, or public agent broadcast writes."},"broadcastDispatchPreflights":{"id":"audience-broadcast-dispatch-preflight-contract","status":"broadcast-dispatch-preflight-dry-run-ready","issue":191,"parentIssue":17,"apiRoute":"/api/admin/audience/broadcasts/dispatch-preflights","ownerRoute":"/admin/audience","source":"d1","loadError":null,"confirmation":{"required":true,"text":"Create dry-run Bumpgrade broadcast dispatch preflight"},"counts":{"dryRunPreflights":0,"dryRunMessagesSnapshotted":0,"heldRecipientsSnapshotted":0,"providerSendEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"cloudflareQueueMessagesCreatedRecords":0,"providerMessageIdsCreatedRecords":0},"latestPreflights":[],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodyIncluded":false,"providerMessageIdsIncluded":false,"cloudflareQueueMessagesCreated":false,"providerSendEnabled":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","actorEmail","recipientPayload","providerMessageId","personalizedBody","cloudflareQueueMessageBody","providerResponse","metadataJson"],"writeBoundary":"Issue #191 lets verified owners record aggregate dispatch preflight dry-run evidence from a current queue-message record after exact confirmation, idempotency, draft revision, readiness count, provider-limit policy, sender-domain gate, unsubscribe footer, suppression, audit correlation, and dry-run queue checks. It does not dispatch Cloudflare Queue messages, create recipient payloads, send through a provider, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastDispatchAttempts":{"id":"audience-broadcast-dispatch-attempt-contract","status":"broadcast-dispatch-attempts-dry-run-ready","issue":197,"parentIssue":17,"apiRoute":"/api/admin/audience/broadcasts/dispatch-attempts","ownerRoute":"/admin/audience","source":"d1","loadError":null,"confirmation":{"required":true,"text":"Create dry-run Bumpgrade broadcast dispatch attempt"},"counts":{"dryRunAttempts":0,"dryRunMessagesSnapshotted":0,"heldRecipientsSnapshotted":0,"providerSendEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"cloudflareQueueMessagesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"providerResponsesCreatedRecords":0},"latestAttempts":[],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"rawRecipientNamesIncluded":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodyIncluded":false,"providerMessageIdsIncluded":false,"providerResponsesIncluded":false,"cloudflareQueueMessagesCreated":false,"providerSendEnabled":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","suppressionHash","actorEmail","recipientPayload","providerMessageId","personalizedBody","cloudflareQueueMessageBody","providerResponse","metadataJson"],"writeBoundary":"Issue #197 lets verified owners record aggregate dispatch attempt receipts from a current dispatch preflight after exact confirmation, idempotency, draft revision, readiness count, queue producer mode, provider-limit policy, sender-domain gate, unsubscribe footer, suppression, audit correlation, and dry-run checks. It does not dispatch Cloudflare Queue messages, create queue payload bodies, create recipient payloads, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastSenderDomainReadiness":{"id":"audience-broadcast-sender-domain-readiness-contract","status":"broadcast-sender-domain-readiness-ready","issue":199,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"senderDomainReadinessRecords":1,"domainsPendingVerification":1,"domainsReady":0,"providerSendEnabledRecords":0,"cloudflareQueueProducerEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0},"records":[{"id":"broadcast-sender-domain-readiness-bumpgrade-com","draftId":"broadcast-draft-launch-window","status":"sender_domain_pending_verification","domain":"bumpgrade.com","intendedFromAddress":"updates@bumpgrade.com","fromAddressPolicy":"Future publisher broadcasts must use an aligned bumpgrade.com From address after SPF, DKIM, and DMARC evidence is recorded for the selected provider.","replyPathPolicy":"Future replies and bounces must route through an aligned, monitored path before provider sends are enabled.","bounceHandlingPolicy":"Future provider integration must capture bounce and complaint evidence before Cloudflare Queue producers can hand off live payloads.","spfAlignmentStatus":"pending_verification","dkimAlignmentStatus":"pending_verification","dmarcAlignmentStatus":"pending_verification","senderDomainGateStatus":"blocked_until_dns_and_provider_alignment_verified","verificationEvidenceStatus":"no_live_provider_send_evidence_recorded","providerSendEnabled":false,"cloudflareQueueProducersEnabled":false,"recipientPayloadsCreated":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"updatedAt":"2026-05-20T05:33:07.000Z"}],"redaction":{"privateDnsCredentialsIncluded":false,"rawDnsRecordsIncluded":false,"providerSecretsIncluded":false,"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"recipientPayloadsIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"providerSendEnabled":false,"cloudflareQueueProducersEnabled":false},"privateFieldsExcluded":["privateDnsCredential","rawDnsRecordValue","providerSecret","recipientEmail","recipientName","subscriberEmailHash","recipientPayload","providerResponse","providerMessageId","metadataJson"],"writeBoundary":"Issue #199 exposes sender-domain readiness metadata for audience broadcasts before any live delivery path exists. It does not verify DNS automatically, expose private DNS credentials, enable Cloudflare Queue producers, create recipient payloads, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastProviderEventReadiness":{"id":"audience-broadcast-provider-event-readiness-contract","status":"broadcast-provider-event-readiness-ready","issue":201,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"providerEventReadinessRecords":1,"bounceEventReadinessRecords":1,"complaintEventReadinessRecords":1,"deliveryEventReadinessRecords":1,"providerSendEnabledRecords":0,"cloudflareQueueProducerEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"rawProviderPayloadsStoredRecords":0},"records":[{"id":"broadcast-provider-event-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"provider_event_readiness_ready","providerName":"provider_pending","eventKinds":["bounce","complaint","delivered"],"providerEventBoundary":"Future provider webhooks must normalize event kind, provider timestamp, redacted correlation IDs, and suppression intent before any private payload is retained.","bounceHandlingPolicy":"Future hard bounces must create or update suppression evidence before another send attempt can be queued.","complaintHandlingPolicy":"Future spam complaints must create suppression evidence and mark the subscriber out of future sends before provider retry.","deliveryEventPolicy":"Future delivered/open/click event handling must stay aggregate-first until contact-specific analytics redaction is defined.","suppressionUpdatePolicy":"Future provider events may update suppression state through hashed subscriber evidence only; public source-data must never expose raw recipient identity.","auditCorrelationPolicy":"Future event rows must carry broadcast draft id, dispatch attempt id, provider event readiness id, and redacted audit correlation id.","rawProviderPayloadStorage":"raw_provider_payload_storage_disabled_redacted_events_only","providerSecretStatus":"not_configured_provider_secrets_absent","senderDomainGateStatus":"blocked_until_sender_domain_and_provider_event_alignment_verified","providerSendEnabled":false,"cloudflareQueueProducersEnabled":false,"recipientPayloadsCreated":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"rawProviderPayloadsStored":false,"updatedAt":"2026-05-20T05:55:17.000Z"}],"redaction":{"providerSecretsIncluded":false,"rawProviderPayloadsIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"recipientPayloadsIncluded":false,"providerSendEnabled":false,"cloudflareQueueProducersEnabled":false},"privateFieldsExcluded":["providerSecret","rawProviderPayload","providerResponse","providerMessageId","recipientEmail","recipientName","subscriberEmailHash","recipientPayload","suppressionHash","metadataJson"],"writeBoundary":"Issue #201 exposes provider-event readiness metadata for audience broadcasts before any live provider webhook or send path exists. It does not store raw provider payloads, expose provider secrets, enable Cloudflare Queue producers, create recipient payloads, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastProviderRateLimitReadiness":{"id":"audience-broadcast-provider-rate-limit-readiness-contract","status":"broadcast-provider-rate-limit-readiness-ready","issue":203,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"providerRateLimitReadinessRecords":1,"throttleWindowRecords":1,"retryBackoffPolicyRecords":1,"providerSendEnabledRecords":0,"cloudflareQueueProducerEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"rawProviderPayloadsStoredRecords":0},"records":[{"id":"broadcast-provider-rate-limit-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"provider_rate_limit_readiness_ready","providerName":"provider_pending","throttleWindow":"provider_rate_limit_window_pending","dailyLimitPolicy":"daily_provider_limit_required_before_live_sends","burstLimitPolicy":"burst_limit_required_before_live_sends","retryBackoffPolicy":"exponential_backoff_and_retry_budget_required_before_queue_dispatch","providerLimitPolicy":"provider_limit_required_before_live_sends","rateLimitSource":"provider_limits_pending_no_secret_or_plan_data","queueBackpressurePolicy":"queue_backpressure_required_before_cloudflare_queue_producers","auditCorrelationPolicy":"Future rate-limit rows must carry broadcast draft id, dispatch attempt id, provider rate-limit readiness id, provider-event readiness id, sender-domain readiness id, and redacted audit correlation id.","senderDomainGateStatus":"blocked_until_sender_domain_alignment_verified","providerEventGateStatus":"blocked_until_provider_event_alignment_verified","providerSendEnabled":false,"cloudflareQueueProducersEnabled":false,"recipientPayloadsCreated":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"rawProviderPayloadsStored":false,"updatedAt":"2026-05-20T06:21:23.000Z"}],"redaction":{"providerSecretsIncluded":false,"providerLimitSecretsIncluded":false,"rawProviderPayloadsIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"recipientPayloadsIncluded":false,"providerSendEnabled":false,"cloudflareQueueProducersEnabled":false},"privateFieldsExcluded":["providerSecret","providerLimitSecret","rawProviderPayload","providerResponse","providerMessageId","recipientEmail","recipientName","subscriberEmailHash","recipientPayload","suppressionHash","metadataJson"],"writeBoundary":"Issue #203 exposes provider rate-limit readiness metadata for audience broadcasts before any live provider send path exists. It does not expose provider secrets or limit secrets, store raw provider payloads, enable Cloudflare Queue producers, create recipient payloads, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastProviderResponseReadiness":{"id":"audience-broadcast-provider-response-readiness-contract","status":"broadcast-provider-response-readiness-ready","issue":205,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"providerResponseReadinessRecords":1,"successResponsePolicyRecords":1,"transientFailurePolicyRecords":1,"permanentFailurePolicyRecords":1,"retryDecisionPolicyRecords":1,"providerSendEnabledRecords":0,"cloudflareQueueProducerEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"rawProviderResponseBodiesStoredRecords":0},"records":[{"id":"broadcast-provider-response-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"provider_response_readiness_ready","providerName":"provider_pending","responseStatusClasses":["accepted","transient_failure","permanent_failure"],"providerResponseBoundary":"Future provider API responses must be classified into accepted, transient failure, or permanent failure before any retry or suppression decision is recorded.","successResponsePolicy":"Accepted responses may only store redacted delivery handoff evidence and must not expose provider message IDs publicly.","transientFailurePolicy":"Transient failures require retry budget, provider rate-limit, queue backpressure, and audit correlation checks before another attempt is allowed.","permanentFailurePolicy":"Permanent failures require provider-event and suppression handling review before future sends to the same subscriber can be queued.","retryDecisionPolicy":"Retry decisions must reference provider response readiness, provider rate-limit readiness, dispatch attempt, and redacted audit correlation ids.","messageIdStoragePolicy":"provider_message_id_storage_disabled_until_live_send_contract","responseBodyStorage":"raw_provider_response_body_storage_disabled_redacted_status_only","auditCorrelationPolicy":"Future response rows must carry broadcast draft id, dispatch attempt id, provider response readiness id, provider rate-limit readiness id, provider-event readiness id, sender-domain readiness id, and redacted audit correlation id.","senderDomainGateStatus":"blocked_until_sender_domain_alignment_verified","providerEventGateStatus":"blocked_until_provider_event_alignment_verified","providerRateLimitGateStatus":"blocked_until_provider_rate_limit_alignment_verified","providerSendEnabled":false,"cloudflareQueueProducersEnabled":false,"recipientPayloadsCreated":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"rawProviderResponseBodiesStored":false,"updatedAt":"2026-05-20T06:50:03.000Z"}],"redaction":{"providerSecretsIncluded":false,"rawProviderResponseBodiesIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"recipientPayloadsIncluded":false,"providerSendEnabled":false,"cloudflareQueueProducersEnabled":false},"privateFieldsExcluded":["providerSecret","providerAccessToken","rawProviderResponseBody","providerResponse","providerMessageId","recipientEmail","recipientName","subscriberEmailHash","recipientPayload","requestPayload","metadataJson"],"writeBoundary":"Issue #205 exposes provider response readiness metadata for audience broadcasts before any live provider send path exists. It does not expose provider secrets, store raw provider response bodies, enable Cloudflare Queue producers, create recipient payloads, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastSendPayloadReadiness":{"id":"audience-broadcast-send-payload-readiness-contract","status":"broadcast-send-payload-readiness-ready","issue":207,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"sendPayloadReadinessRecords":1,"unsubscribeFooterPolicyRecords":1,"consentRecheckPolicyRecords":1,"suppressionRecheckPolicyRecords":1,"cloudflareQueueProducerEnabledRecords":0,"recipientPayloadsCreatedRecords":0,"personalizedBodiesCreatedRecords":0,"providerSendEnabledRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"rawPayloadBodiesStoredRecords":0},"records":[{"id":"broadcast-send-payload-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"send_payload_readiness_ready","payloadScope":["recipient_identity","consent_state","suppression_state","unsubscribe_footer","personalization_tokens"],"personalizationBoundary":"Future payload creation must assemble only the minimum provider body after consent, suppression, unsubscribe footer, sender-domain, provider-event, rate-limit, response, and audit gates pass.","recipientIdentityPolicy":"Recipient identity must stay hashed or server-private until the final provider handoff and must never appear in public source-data.","unsubscribeFooterPolicy":"Every live payload must include the current unsubscribe footer contract and reject sends when the footer cannot be generated.","consentRecheckPolicy":"Consent must be rechecked at payload creation time against the latest subscriber and consent evidence.","suppressionRecheckPolicy":"Suppression must be rechecked at payload creation time against the latest unsubscribe and provider-event evidence.","personalizationTokenPolicy":"Personalization tokens must be allowlisted and rendered server-side only after stale-state checks pass.","payloadBodyStorage":"raw_payload_body_storage_disabled_until_live_send_contract","auditCorrelationPolicy":"Future payload rows must carry broadcast draft id, dispatch attempt id, send payload readiness id, sender-domain readiness id, provider-event readiness id, provider rate-limit readiness id, provider response readiness id, and redacted audit correlation id.","senderDomainGateStatus":"blocked_until_sender_domain_alignment_verified","providerEventGateStatus":"blocked_until_provider_event_alignment_verified","providerRateLimitGateStatus":"blocked_until_provider_rate_limit_alignment_verified","providerResponseGateStatus":"blocked_until_provider_response_alignment_verified","cloudflareQueueProducersEnabled":false,"recipientPayloadsCreated":false,"personalizedBodiesCreated":false,"providerSendEnabled":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"rawPayloadBodiesStored":false,"updatedAt":"2026-05-20T07:20:47.000Z"}],"redaction":{"rawRecipientEmailsIncluded":false,"privateContactDataIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodiesIncluded":false,"rawPayloadBodiesIncluded":false,"providerSecretsIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"cloudflareQueueProducersEnabled":false,"providerSendEnabled":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","recipientPayload","personalizedBody","rawPayloadBody","unsubscribeToken","providerSecret","providerResponse","providerMessageId","metadataJson"],"writeBoundary":"Issue #207 exposes send-payload readiness metadata for audience broadcasts before any live Queue producer or recipient payload path exists. It does not expose raw recipient identity, create recipient payloads, create personalized bodies, store raw payload bodies, enable Cloudflare Queue producers, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastQueueProducerReadiness":{"id":"audience-broadcast-queue-producer-readiness-contract","status":"broadcast-queue-producer-readiness-ready","issue":209,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"queueProducerReadinessRecords":1,"dryRunProducerContracts":1,"cloudflareQueueProducerEnabledRecords":0,"cloudflareQueueMessagesCreatedRecords":0,"queuePayloadBodiesCreatedRecords":0,"recipientPayloadsCreatedRecords":0,"personalizedBodiesCreatedRecords":0,"providerSendEnabledRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"rawPayloadBodiesStoredRecords":0},"records":[{"id":"broadcast-queue-producer-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"queue_producer_readiness_ready","queueName":"audience-broadcast-delivery","producerBinding":"AUDIENCE_BROADCAST_DELIVERY_QUEUE","producerMode":"dry_run_contract_only_no_worker_binding_send","producerGateStatus":"blocked_until_payload_and_consumer_contracts_verified","payloadDependencyStatus":"blocked_until_send_payload_readiness_verified_and_recipient_payloads_can_be_created","consumerDependencyStatus":"blocked_until_queue_consumer_idempotency_retry_and_dead_letter_contracts_exist","idempotencyPolicy":"Future producer writes must use broadcast draft id, dispatch attempt id, send payload readiness id, and recipient scope as the idempotency basis before any Queue message is created.","auditCorrelationPolicy":"Future producer writes must carry redacted audit correlation from schedule intent through delivery batch, queue-message evidence, dispatch preflight, dispatch attempt, send payload readiness, and Queue producer readiness.","retryBackpressurePolicy":"Producer backpressure must fail closed when provider rate-limit, Queue consumer, retry, or dead-letter capacity is not explicit.","sendPayloadGateStatus":"blocked_until_send_payload_readiness_issue_207_stays_current","senderDomainGateStatus":"blocked_until_sender_domain_alignment_verified","providerEventGateStatus":"blocked_until_provider_event_alignment_verified","providerRateLimitGateStatus":"blocked_until_provider_rate_limit_alignment_verified","providerResponseGateStatus":"blocked_until_provider_response_alignment_verified","cloudflareQueueProducersEnabled":false,"cloudflareQueueMessagesCreated":false,"queuePayloadBodiesCreated":false,"recipientPayloadsCreated":false,"personalizedBodiesCreated":false,"providerSendEnabled":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"rawPayloadBodiesStored":false,"updatedAt":"2026-05-20T07:50:00.000Z"}],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"queuePayloadBodiesIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodiesIncluded":false,"rawPayloadBodiesIncluded":false,"providerSecretsIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"cloudflareQueueProducersEnabled":false,"cloudflareQueueMessagesCreated":false,"providerSendEnabled":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","queueMessageBody","queuePayloadBody","recipientPayload","personalizedBody","rawPayloadBody","providerSecret","providerResponse","providerMessageId","metadataJson"],"writeBoundary":"Issue #209 exposes Queue producer readiness metadata for audience broadcasts before any live Cloudflare Queue producer path exists. It does not enable producers, create Queue messages, create queue payload bodies, create recipient payloads, create personalized bodies, store raw payload bodies, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"broadcastQueueConsumerReadiness":{"id":"audience-broadcast-queue-consumer-readiness-contract","status":"broadcast-queue-consumer-readiness-ready","issue":211,"parentIssue":17,"publicSourceDataRoute":"/audience/source-data","ownerRoute":"/admin/audience","source":"d1","loadError":null,"counts":{"queueConsumerReadinessRecords":1,"dryRunConsumerContracts":1,"cloudflareQueueConsumerEnabledRecords":0,"cloudflareQueueMessagesConsumedRecords":0,"cloudflareQueueMessagesAckedRecords":0,"queueRetryRecordsCreatedRecords":0,"queueDeadLetterRecordsCreatedRecords":0,"queuePayloadBodiesReadRecords":0,"recipientPayloadsCreatedRecords":0,"providerSendEnabledRecords":0,"providerResponsesCreatedRecords":0,"providerMessageIdsCreatedRecords":0,"rawPayloadBodiesStoredRecords":0},"records":[{"id":"broadcast-queue-consumer-readiness-launch-window","draftId":"broadcast-draft-launch-window","status":"queue_consumer_readiness_ready","queueName":"audience-broadcast-delivery","consumerName":"bumpgrade-audience-broadcast-delivery-consumer","consumerMode":"dry_run_contract_only_no_worker_queue_consumer","consumerGateStatus":"blocked_until_queue_payload_ack_retry_and_dead_letter_contracts_are_verified","producerDependencyStatus":"blocked_until_queue_producer_readiness_issue_209_stays_current","payloadDependencyStatus":"blocked_until_send_payload_readiness_verified_without_raw_payload_body_exposure","ackPolicy":"Future consumers must acknowledge only after idempotent provider handoff and audit correlation are recorded; no ack path exists in this contract.","retryPolicy":"Retries must preserve the original idempotency basis and fail closed when provider rate limits, sender-domain gates, or suppression rechecks are stale.","deadLetterPolicy":"Dead-letter handling must store aggregate failure evidence only; raw Queue payload bodies and private recipient identity stay excluded.","idempotencyPolicy":"Future consumers must key idempotency by Queue message id, dispatch attempt id, send payload readiness id, and recipient scope before any provider send is attempted.","auditCorrelationPolicy":"Future consumers must carry redacted audit correlation from schedule intent through Queue producer readiness, consumer readiness, provider response readiness, and provider-event processing.","providerHandoffPolicy":"Provider handoff stays blocked until queue consumer, sender-domain, provider-event, provider rate-limit, provider response, send-payload, suppression, and unsubscribe gates pass together.","queueProducerGateStatus":"blocked_until_queue_producer_readiness_issue_209_stays_current","sendPayloadGateStatus":"blocked_until_send_payload_readiness_issue_207_stays_current","senderDomainGateStatus":"blocked_until_sender_domain_alignment_verified","providerEventGateStatus":"blocked_until_provider_event_alignment_verified","providerRateLimitGateStatus":"blocked_until_provider_rate_limit_alignment_verified","providerResponseGateStatus":"blocked_until_provider_response_alignment_verified","cloudflareQueueConsumersEnabled":false,"cloudflareQueueMessagesConsumed":false,"cloudflareQueueMessagesAcked":false,"queueRetryRecordsCreated":false,"queueDeadLetterRecordsCreated":false,"queuePayloadBodiesRead":false,"recipientPayloadsCreated":false,"providerSendEnabled":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"rawPayloadBodiesStored":false,"updatedAt":"2026-05-20T08:14:56.000Z"}],"redaction":{"privateContactDataIncluded":false,"rawRecipientEmailsIncluded":false,"queuePayloadBodiesIncluded":false,"queueConsumerAckRowsIncluded":false,"queueRetryRowsIncluded":false,"queueDeadLetterRowsIncluded":false,"recipientPayloadsIncluded":false,"rawPayloadBodiesIncluded":false,"providerSecretsIncluded":false,"providerResponsesIncluded":false,"providerMessageIdsIncluded":false,"cloudflareQueueConsumersEnabled":false,"cloudflareQueueMessagesConsumed":false,"cloudflareQueueMessagesAcked":false,"providerSendEnabled":false},"privateFieldsExcluded":["recipientEmail","recipientName","subscriberEmailHash","queueMessageBody","queuePayloadBody","queueConsumerAckRow","queueRetryRow","queueDeadLetterRow","recipientPayload","rawPayloadBody","providerSecret","providerResponse","providerMessageId","metadataJson"],"writeBoundary":"Issue #211 exposes Queue consumer readiness metadata for audience broadcasts before any live Cloudflare Queue consumer path exists. It does not enable consumers, consume or ack Queue messages, create retry or dead-letter rows, read queue payload bodies, create recipient payloads, store raw payload bodies, send through a provider, create provider responses, create provider message IDs, expose private recipients, or authorize public agent broadcast writes."},"audienceSequenceDeliveryReadiness":{"id":"audience-sequence-delivery-readiness-contract","status":"audience-sequence-delivery-readiness-ready","issue":351,"parentIssue":17,"ownerRoute":"/admin/audience","publicSourceDataRoute":"/audience/source-data","source":"d1","loadError":null,"workspace":{"id":"audience-automation-workspace-indie-launch","title":"Indie launch waitlist and nurture","revisionId":"audience-automation-revision-indie-launch-2026-05-20","status":"draft"},"scheduleMode":"readiness_only","deliveryEnabled":false,"counts":{"sequences":1,"sequenceSteps":3,"immediateSteps":1,"delayedSteps":2,"draftEnrollments":4,"readyEnrollments":4,"pausedEnrollments":1,"unsubscribedEnrollments":1,"suppressedEnrollments":1,"missingConsentEnrollments":0,"subscribedSubscribers":4,"consentedSubscribers":5,"activeSuppressionEntries":2,"deliveryQueueRowsCreatedRecords":0,"recipientPayloadsCreatedRecords":0,"personalizedBodiesCreatedRecords":0,"emailSendEnabledRecords":0,"providerMessageIdsCreatedRecords":0,"unsubscribeUrlsCreatedRecords":0},"redaction":{"privateContactDataIncluded":false,"rawEmailsIncluded":false,"subscriberIdsIncluded":false,"recipientPayloadsIncluded":false,"personalizedBodiesIncluded":false,"bodyTemplatesIncluded":false,"unsubscribeUrlsIncluded":false,"providerMessageIdsIncluded":false,"queuePayloadsIncluded":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false},"records":[{"id":"sequence-indie-launch-nurture-delivery-readiness","sequenceId":"sequence-indie-launch-nurture","title":"Indie launch nurture sequence","linkedFormId":"opt-in-form-indie-launch-waitlist","status":"draft","stepCount":3,"immediateSteps":1,"delayedSteps":2,"agentEditableSteps":3,"deliveryEnabled":false,"recipientPayloadsCreated":false,"personalizedBodiesCreated":false,"queueMessagesCreated":false,"providerSendEnabled":false}],"privateFieldsExcluded":["subscriberId","email","firstName","emailHash","suppressionHash","recipientPayload","personalizedBody","bodyTemplate","unsubscribeUrl","queuePayload","providerMessageId","actorEmail"],"writeBoundary":"Issue #351 exposes aggregate audience sequence delivery readiness for draft nurture sequences without creating delivery queue rows, recipient payloads, personalized bodies, unsubscribe URLs, provider sends, provider message IDs, queue payloads, or direct public agent sequence writes. Real sequence scheduling and sending still require future owner-confirmed APIs with actor identity, exact confirmation, consent and suppression rechecks, unsubscribe footer safety, sender-domain and provider readiness, idempotency, audit correlation, rate limits, and redaction."},"audienceExportReadiness":{"id":"audience-export-readiness-contract","status":"audience-export-readiness-ready","issue":347,"parentIssue":17,"ownerRoute":"/admin/audience","publicSourceDataRoute":"/audience/source-data","source":"d1","loadError":null,"exportFormat":"csv_private_contact_export","exportEnabled":false,"counts":{"subscribers":5,"subscribedSubscribers":4,"consentedSubscribers":5,"exportEligibleSubscribers":4,"suppressedSubscribers":1,"activeSuppressionEntries":2,"unsubscribedSubscribers":1,"pausedSequenceSubscribers":1,"exportFilesCreatedRecords":0,"rawEmailsIncludedRecords":0,"exportUrlsCreatedRecords":0},"redaction":{"privateContactDataIncluded":false,"rawEmailsIncluded":false,"subscriberIdsIncluded":false,"exportFileUrlsIncluded":false,"exportFilesCreated":false,"actorEmailIncluded":false,"suppressionHashesIncluded":false,"privateNotesIncluded":false},"privateFieldsExcluded":["subscriberId","email","firstName","emailHash","suppressionHash","exportFileUrl","exportObjectKey","actorEmail","privateNote"],"writeBoundary":"Issue #347 exposes aggregate owner/public-safe audience export readiness for CSV-style private contact exports without creating export files, URLs, raw email payloads, subscriber-id lists, or direct public agent export writes. Real private exports still require a future owner-confirmed export API with actor identity, exact confirmation, consent and suppression checks, audit correlation, redaction, and time-limited delivery."},"importIntents":{"id":"audience-import-intent-contract","status":"audience-import-intents-ready","issue":253,"parentIssue":17,"apiRoute":"/api/admin/audience/import-intents","ownerRoute":"/admin/audience","source":"d1","loadError":null,"workspace":{"id":"audience-automation-workspace-indie-launch","title":"Indie launch waitlist and nurture","status":"draft","revisionId":"audience-automation-revision-indie-launch-2026-05-20"},"confirmation":{"required":true,"text":"Record Bumpgrade audience import intent"},"sourceKinds":["csv_upload","kit_export","manual_paste","api_migration"],"counts":{"importIntents":0,"ownerConfirmedIntents":0,"estimatedContacts":0,"estimatedNewContacts":0,"estimatedUpdates":0,"estimatedSuppressions":0,"importRowsStoredRecords":0,"rawEmailsStoredRecords":0,"sequenceEnrollmentsCreatedRecords":0,"emailDeliveryEnabledRecords":0},"latestIntents":[],"redaction":{"privateContactDataIncluded":false,"rawEmailsIncluded":false,"importRowsIncluded":false,"actorEmailIncluded":false,"actorEmailHashIncluded":false,"privateNoteIncluded":false,"sequenceEnrollmentsCreated":false,"emailDeliveryEnabled":false},"privateFieldsExcluded":["rawContactRows","rawEmails","rawNames","csvBody","providerPayload","actorEmail","actorEmailHash","privateNote","privateNoteSha256","metadataJson"],"writeBoundary":"Issue #253 lets verified owners record non-destructive audience import intent metadata after exact confirmation, idempotency, and workspace stale-state checks. It does not import contacts, store raw contact rows, store raw emails, create subscribers, create sequence enrollments, send email, expose actor identity, export private data, or authorize direct public agent subscriber writes."},"importPreflights":{"id":"audience-import-preflight-contract","status":"audience-import-preflights-ready","issue":259,"parentIssue":17,"apiRoute":"/api/admin/audience/import-preflights","ownerRoute":"/admin/audience","source":"d1","loadError":null,"workspace":{"id":"audience-automation-workspace-indie-launch","title":"Indie launch waitlist and nurture","status":"draft","revisionId":"audience-automation-revision-indie-launch-2026-05-20"},"confirmation":{"required":true,"text":"Record Bumpgrade audience import preflight"},"counts":{"importPreflights":0,"ownerConfirmedPreflights":0,"totalContactsChecked":0,"eligibleNewContacts":0,"eligibleUpdates":0,"duplicates":0,"suppressed":0,"missingConsent":0,"malformed":0,"lawfulBasisContacts":0,"importRowsStoredRecords":0,"rawEmailsStoredRecords":0,"subscriberRowsCreatedRecords":0,"sequenceEnrollmentsCreatedRecords":0,"emailDeliveryEnabledRecords":0,"exportEnabledRecords":0},"latestPreflights":[],"redaction":{"privateContactDataIncluded":false,"rawEmailsIncluded":false,"importRowsIncluded":false,"actorEmailIncluded":false,"actorEmailHashIncluded":false,"privateNoteIncluded":false,"subscriberRowsCreated":false,"sequenceEnrollmentsCreated":false,"emailDeliveryEnabled":false,"exportEnabled":false},"privateFieldsExcluded":["rawContactRows","rawEmails","rawNames","csvBody","providerPayload","actorEmail","actorEmailHash","privateNote","privateNoteSha256","metadataJson"],"writeBoundary":"Issue #259 lets verified owners record aggregate audience import preflight evidence after exact confirmation, idempotency, workspace stale-state checks, and selected import-intent source checks. It does not store raw contact rows, store raw emails, create subscriber rows, create sequence enrollments, enable delivery, export private data, expose actor identity, or authorize public agent subscriber writes."}}