docs(campaign): distinguish worker process evidence

This commit is contained in:
2026-07-22 18:26:42 +02:00
parent 2fa91bb943
commit 6fda123fc3
3 changed files with 39 additions and 18 deletions

View File

@@ -67,10 +67,23 @@ set +a
The default run also uses controlled loopback protocol endpoints to prove that The default run also uses controlled loopback protocol endpoints to prove that
an SMTP connection loss before transmission is temporary, an explicit SMTP an SMTP connection loss before transmission is temporary, an explicit SMTP
authentication rejection is permanent, and an IMAP authentication rejection authentication rejection is permanent, a final `451` response after DATA is
after SMTP acceptance leaves the send accepted while the append fails. A 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. 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, The bounded JSON contains no endpoint, account, address, credential, profile,
campaign, version, or job identifiers. It records module versions, the fixture campaign, version, or job identifiers. It records module versions, the fixture
hash, normalized classifications/counts, the Mail-profile boundary, required 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 Campaign delivery mode. Hostnames such as `localhost` and every non-loopback
address fail before profile creation, avoiding a DNS change between validation address fail before profile creation, avoiding a DNS change between validation
and connection. It is local target-like evidence, not approval of an and connection. It is local target-like evidence, not approval of an
institution's SMTP/IMAP service. A post-DATA connection loss institution's SMTP/IMAP service. The controlled post-DATA, temporary-response,
with ambiguous SMTP outcome, an explicit temporary SMTP response, partial partial-refusal, and task-process interruption drills are local effect-level
recipient refusal, and a real worker restart remain separate drills and are proof, not proof of a target provider's behavior or Redis/Celery broker
explicitly `false` in the coverage projection. Use `--success-only` only when redelivery. Use `--success-only` only when testing the success journey without
testing the success journey without the local failure endpoints. the local failure endpoints.
Starting the maintained test bed requires a working Docker CLI, Compose plugin, 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 daemon/socket access, and permission to pull `greenmail/standalone:2.1.9`. The

View File

@@ -107,15 +107,20 @@ bed where possible:
For the maintained loopback baseline, run For the maintained loopback baseline, run
`dev/mail-testbed/run_campaign_acceptance.py`. It proves the public Campaign `dev/mail-testbed/run_campaign_acceptance.py`. It proves the public Campaign
path for SMTP acceptance, IMAP append, repeat-send blocking, an SMTP connection path for SMTP acceptance, IMAP append, repeat-send blocking, an SMTP connection
failure before transmission, an explicit SMTP authentication rejection, and an failure before transmission, an explicit SMTP authentication rejection, an
IMAP authentication rejection after SMTP acceptance. Its evidence is an explicit temporary `451` response after DATA, partial RCPT refusal, a
allowlisted classification/count projection; raw provider diagnostics and connection loss after complete DATA, and an IMAP authentication rejection
transport/account identifiers are deliberately excluded. 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 The runner also terminates a dedicated OS process executing the registered
restart a real worker. Keep those two checklist items open until a controlled Campaign send task after complete DATA, then invokes the task in a fresh
fault proxy/target provider and supervised worker environment can produce the process. The unfinished durable attempt must become `outcome_unknown` and the
corresponding `outcome_unknown`, restart, retry, and reconciliation evidence. 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 ## Reporting Checks

View File

@@ -59,9 +59,12 @@ Before tagging a campaign release:
projection. It must show one SMTP acceptance, one IMAP append, no duplicate projection. It must show one SMTP acceptance, one IMAP append, no duplicate
effect from a repeated ordinary send, matching Campaign report/audit state, effect from a repeated ordinary send, matching Campaign report/audit state,
and no resolved transport material in Campaign JSON or its execution and no resolved transport material in Campaign JSON or its execution
snapshot. snapshot. Its controlled endpoint evidence must also show explicit SMTP 451,
- Do not interpret the local failure drills as post-DATA ambiguity or worker partial RCPT refusal, post-DATA ambiguity, and task-process interruption
restart proof; the evidence coverage flags must keep those gaps explicit. 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 - Confirm reusable mail profile selection is revalidated after campaign owner
transfer. transfer.
- Confirm every inline SMTP/IMAP field is rejected on import/write, omitted - Confirm every inline SMTP/IMAP field is rejected on import/write, omitted