Onboard a list

Produce a census, a versioned selection policy, and a private cohort manifest. Import or switch sending only within the task’s authority.ΒΆ

For routine broadcasts to an onboarded audience, use the project’s sending procedure.ΒΆ

This procedure defines a migration job. It does not install an importer.ΒΆ

Start with the source and authority

Identify the source account, destination tenant, email topics, available credentials, and approved operations. Reuse an approved cohort choice. Ask only for missing decisions that affect the result or authorize a new live action.ΒΆ

Name the facts and their writer:ΒΆ

Read contracts and policy when defining an adapter27 or import policy. Read the count-only example when explaining overlaps.ΒΆ

1. Capture a read-only inventory

Inventory broadcasts, journeys, welcome flows, transactional/API callers, scheduled jobs, and historical link services. Measure actual sends over an explicit window. Enabled does not mean sending. A welcome flow may be the only active sender.ΒΆ

Capture every page of contacts, addresses, topic/channel/global preferences, and permanent stops. Include stopped addresses without profiles.ΒΆ

Reconcile unique keys, terminal cursors, export row totals, and available before/after counts. Record observation times and concurrent-change gaps. Claim a transactional snapshot only when the source provides one.ΒΆ

Keep recipient rows, signed URLs, credentials, and source cursors private. Reports contain aggregates and safe source receipts. Limit read credentials to the source account.ΒΆ

Use read-only export/search jobs only when the task authorizes them. They must not alter customer state.ΒΆ

2. Establish the stop floor

Separate authoritative unsubscribes, complaints, hard-bounce stops, and provider denials from delivery events and heuristics. A bounced delivery alone does not prove a permanent hard-bounce stop.ΒΆ

Resolve identity conservatively. Preserve stops without profiles and their original reasons. Never rewrite typo addresses or collapse plus tags. Use only documented identity normalization. Report ambiguity.ΒΆ

Before enabling destination sends, durably import and read back the complete stop floor. Profile imports and consent defaults must not lift it. Keep later source and legacy-link stops flowing until continuity is proven.ΒΆ

3. Measure each proposed rule

Decode policy data with Effect29 Schema25. Pin external lists by source, revision/date, and digest. Store thresholds, domain/local-part sets, windows, and actions in that policy.ΒΆ

Measure each rule against each original pool. Report independent matches, pairwise overlaps, exclusive matches, the union, and an ordered waterfall. Show newly removed and remaining counts. Never add independent counts.ΒΆ

Keep observations separate from person-level conclusions:ΒΆ

Do not invent missing evidence or measured precision. Label any analyst precision guess unvalidated. Keep it separate from measurements.ΒΆ

4. Choose and pin the cohort

Present alternatives and one recommendation. Explain exact counts, bounds, gaps, and tradeoffs.ΒΆ

When engagement is required, use positive human evidence. Explain which readers first-event-only history can miss. Do not substitute raw opens when human evidence is unavailable.ΒΆ

Let the owner choose unresolved engagement windows and optional restrictions. Pin source receipts, base manifest, policy digest, cohort digest, and destination tenant.ΒΆ

Dry-run and apply use the same pure planner and policy bytes. Changed policy or widened eligibility needs a new selection. Newly discovered stops always narrow it.ΒΆ

Read verification properties before accepting the planner. Cover the deduplicated waterfall and the weak-signal boundary.ΒΆ

5. Dry-run and prepare the destination

Reuse owned destination contracts. When building automation, expose census, planning, and import as typed capabilities. Project CLI, HTTP, and agent tools from those contracts.ΒΆ

Dry-run exact identities, stop matches, ambiguous records, counts, and value-level readback. Use tenant-scoped idempotency keys9 and durable resume checkpoints.ΒΆ

For an authorized import, write stops first, then profiles. Do not discard rejected stop rows or mark partial work complete.ΒΆ

Prepare sender ownership, authentication, content, tenant-scoped routing, consent basis, unsubscribe handling, and historical-link continuity. Verify real bindings23 with authorized synthetic recipients. Preserve other mail systems on shared domains.ΒΆ

6. Make the authorized switch

For a hard switch, stop every old sending path. Prove that stop before enabling destination sends. Do not invent a parallel sending period.ΒΆ

Capture final contact, consent, and stop deltas through a recorded boundary. Describe and close consistency gaps before claiming completion.ΒΆ

Keep old unsubscribe/tracking links working when needed, with old sending disabled. Persist new stops before acknowledging them. Enforce stops at final dispatch. An eventually consistent cache alone cannot protect that boundary.ΒΆ

Enable only the approved cohort. Reconcile accepted, completed, failed, and unknown provider outcomes. Never blindly retry an uncertain send.ΒΆ

On harm, stop the affected destination path. Restart the old sender only when that recovery action is authorized.ΒΆ

Use a persisted lifecycle: capture β†’ measure β†’ choose β†’ prepare β†’ switch β†’ verify. Put retries, deferrals, cancellation, and resume in XState. Run work through Effect actors under the project’s pins. A delay proves neither failure nor completion.ΒΆ

7. Prove and report the result

Read back stops, exact profile values, cohort counts, and both dispatch controls. Prove a stopped synthetic address cannot regain eligibility through signup or profile import. Prove historical unsubscribe links durably stop later dispatch.ΒΆ

Verify topic behavior and tenant isolation. Use authorized delivery receipts for real-send claims.ΒΆ

After cutover, measure later eligibility from destination-owned human events. State which human events are recorded. A clock window passing does not justify widening the cohort.ΒΆ

Report analysis-ready, import-verified, and sending-verified separately. Include input digests, exact/bounded sections, overlaps, rejected records, checkpoints, gaps, and the next authorized move.ΒΆ

Keep raw manifests private. Scan shareable artifacts for recipient patterns.ΒΆ

Register an event watch for unfinished external work. Act when its result arrives. Reconciled receipts prove analysis. A report alone does not prove an import or send completed.ΒΆ


Last changed 2026-10-24 in d438f78. Source on GitHub. Change log.