From 6fda123fc32732db2987e685e6b1d0b7277445b2 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Wed, 22 Jul 2026 18:26:42 +0200 Subject: [PATCH] docs(campaign): distinguish worker process evidence --- dev/mail-testbed/README.md | 27 ++++++++++++++----- docs/CAMPAIGN_DELIVERY_RUNBOOK.md | 21 +++++++++------ ...EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md | 9 ++++--- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/dev/mail-testbed/README.md b/dev/mail-testbed/README.md index 096ee18..22ae159 100644 --- a/dev/mail-testbed/README.md +++ b/dev/mail-testbed/README.md @@ -67,10 +67,23 @@ set +a The default run also uses controlled loopback protocol endpoints to prove that an SMTP connection loss before transmission is temporary, an explicit SMTP -authentication rejection is permanent, and an IMAP authentication rejection -after SMTP acceptance leaves the send accepted while the append fails. A +authentication rejection is permanent, a final `451` response after DATA is +temporary, one accepted and one refused RCPT command is retained as partial +envelope acceptance, a connection loss after complete DATA is frozen as +`outcome_unknown`, and an IMAP authentication rejection after SMTP acceptance +leaves the send accepted while the append fails. A second ordinary send must be rejected before another provider effect. +The worker drill queues one job, starts the registered +`govoplan.campaigns.send_email` task body in a dedicated OS process, waits until +the controlled endpoint has received complete DATA, terminates that process, +and starts the same task body in a fresh process. It proves the durable +`sending`/unfinished-attempt boundary is recovered as `outcome_unknown` +without a second SMTP connection or DATA transaction. This is a real process +and task-boundary interruption, but it does not start a Celery daemon, Redis +broker, or broker redelivery; `celery_broker_redelivery` therefore remains +`false` in the evidence. + The bounded JSON contains no endpoint, account, address, credential, profile, campaign, version, or job identifiers. It records module versions, the fixture hash, normalized classifications/counts, the Mail-profile boundary, required @@ -84,11 +97,11 @@ This runner is restricted to literal loopback IP addresses and the synchronous Campaign delivery mode. Hostnames such as `localhost` and every non-loopback address fail before profile creation, avoiding a DNS change between validation and connection. It is local target-like evidence, not approval of an -institution's SMTP/IMAP service. A post-DATA connection loss -with ambiguous SMTP outcome, an explicit temporary SMTP response, partial -recipient refusal, and a real worker restart remain separate drills and are -explicitly `false` in the coverage projection. Use `--success-only` only when -testing the success journey without the local failure endpoints. +institution's SMTP/IMAP service. The controlled post-DATA, temporary-response, +partial-refusal, and task-process interruption drills are local effect-level +proof, not proof of a target provider's behavior or Redis/Celery broker +redelivery. Use `--success-only` only when testing the success journey without +the local failure endpoints. Starting the maintained test bed requires a working Docker CLI, Compose plugin, daemon/socket access, and permission to pull `greenmail/standalone:2.1.9`. The diff --git a/docs/CAMPAIGN_DELIVERY_RUNBOOK.md b/docs/CAMPAIGN_DELIVERY_RUNBOOK.md index 2c99a43..f4eeb7b 100644 --- a/docs/CAMPAIGN_DELIVERY_RUNBOOK.md +++ b/docs/CAMPAIGN_DELIVERY_RUNBOOK.md @@ -107,15 +107,20 @@ bed where possible: For the maintained loopback baseline, run `dev/mail-testbed/run_campaign_acceptance.py`. It proves the public Campaign path for SMTP acceptance, IMAP append, repeat-send blocking, an SMTP connection -failure before transmission, an explicit SMTP authentication rejection, and an -IMAP authentication rejection after SMTP acceptance. Its evidence is an -allowlisted classification/count projection; raw provider diagnostics and -transport/account identifiers are deliberately excluded. +failure before transmission, an explicit SMTP authentication rejection, an +explicit temporary `451` response after DATA, partial RCPT refusal, a +connection loss after complete DATA, and an IMAP authentication rejection +after SMTP acceptance. Its evidence is an allowlisted classification/count +projection; raw provider diagnostics and transport/account identifiers are +deliberately excluded. -The runner does not simulate a connection loss after SMTP DATA and does not -restart a real worker. Keep those two checklist items open until a controlled -fault proxy/target provider and supervised worker environment can produce the -corresponding `outcome_unknown`, restart, retry, and reconciliation evidence. +The runner also terminates a dedicated OS process executing the registered +Campaign send task after complete DATA, then invokes the task in a fresh +process. The unfinished durable attempt must become `outcome_unknown` and the +endpoint must observe no second connection or DATA transaction. This covers +the worker task/process boundary. It does not cover Redis/Celery delivery, +acknowledgement, broker redelivery, or daemon supervision; repeat the drill in +that infrastructure before approving a production worker deployment. ## Reporting Checks diff --git a/docs/EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md b/docs/EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md index 273ddab..8437a01 100644 --- a/docs/EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md +++ b/docs/EXAMPLE_CAMPAIGNS_AND_RELEASE_CHECKLIST.md @@ -59,9 +59,12 @@ Before tagging a campaign release: projection. It must show one SMTP acceptance, one IMAP append, no duplicate effect from a repeated ordinary send, matching Campaign report/audit state, and no resolved transport material in Campaign JSON or its execution - snapshot. -- Do not interpret the local failure drills as post-DATA ambiguity or worker - restart proof; the evidence coverage flags must keep those gaps explicit. + snapshot. Its controlled endpoint evidence must also show explicit SMTP 451, + partial RCPT refusal, post-DATA ambiguity, and task-process interruption + classifications without retaining addresses or provider diagnostics. +- Treat the task-process restart proof separately from the still-open + Redis/Celery broker redelivery and daemon-supervision check; the coverage + projection must keep `celery_broker_redelivery` false. - Confirm reusable mail profile selection is revalidated after campaign owner transfer. - Confirm every inline SMTP/IMAP field is rejected on import/write, omitted