email-connect/docs/sender-transition-protocol-2026-10-31.md
tegwick 422590934b
Some checks failed
Transactional mail acceptance / mail (push) Failing after 1m11s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Prepare durable sender transition and current-ledger recovery protocol
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
2026-10-31 16:41:30 +01:00

5.5 KiB

Sender transition protocol preparation

EMAIL-WP-0010-T02 is in progress. scripts/sender_transition.py is a tested protocol core, with no production CLI or Kubernetes credentials. It does not establish native fencing, credential admission or an execution-ready release.

Concrete behavior

The proposed delta is derived from the observed configuration rather than accepting arbitrary patches: retain the exact receiver image and every unrelated field, replace the old runtime envFrom Secret with explicit platform SMTP username and password projection references, and change only the configured sender. A different image, existing environment shape or sender refuses preparation.

Before every effect the protocol fsyncs an append-only private journal. The first entry binds the complete before/after proposal. The directory must be operator owned and 0700; the journal is 0600, exclusively locked, and refuses symlinks and hardlinks. A truncated final line is retained for inspection, never silently discarded. A completed or interrupted forward attempt cannot be blindly replayed.

The forward sequence is admission, pause, fence, fresh capture, outcome review, configuration change, deployment environment change, resume, native verification, postflight capture, continuity comparison and helper cleanup. The protocol checks that the receiver is still paused before configuration and environment changes. Captured baseline bytes are hash-bound and must remain unchanged during the attempt. Unknown outcomes before a switch stop the sequence without clearing reservations.

Failures leave an inspection record; no finally block guesses a rollback or resumes an uncertain receiver. Explicit recovery observes actual configuration, recognizes only the reviewed old/new/mixed states, pauses again, captures the current ledger and restores only the old configuration. It retains all earlier journal entries and snapshots. It never copies an old ledger over current data, clears reservations, sends mail or re-enables retired legacy caller authentication. Rollback restores the previous SMTP environment references while retaining the scoped callers-file configuration and its precedence over the legacy environment. An additional interruption during recovery can be handled by observing the same attempt again. Unknown outcomes remain unknown and preserve non-retryability.

Data comparison and limits

The comparator reads all six tables and requires unchanged schema and preservation of every pre-existing primary key. Accepted delivery receipts and suppression decisions cannot be rewritten. Verification identity/handle/binding fields remain exact; terminal consumption/cancellation may only advance from unset and cannot be reversed or both set. Caller quota counters may advance without losing their identity or reversing time. Attempt transitions retain their idempotency binding; only a definitive retryable failure permits a new verification request handle. New rows are reported, allowing legitimate traffic after receiver resume.

This is structural continuity evidence, not independent proof that every new application request was authorized or delivered. The unchanged image and caller policy, actual runtime checks and productive mail evidence remain separate gates. An unexpected deletion/change fails comparison; it never triggers a data restore.

Test evidence

Twenty-seven new synthetic cases pass. Ten use real abrupt process exits around pause, capture, configuration/deployment changes, resume, postflight, cleanup, completion and lost configuration/scale replies. Cluster API effects are modeled as durable file-backed state; the database and SQLite reopen/retry behavior are real. Subsequent accepted and uncertain sends survive explicit recovery byte for byte, and the old configuration is restored. Other cases cover a second recovery interruption, foreign drift, absent admission, journal truncation/private modes, writer resumption during capture, a broken snapshot before configuration change, schema/row loss, ambiguous nullable SQLite primary keys and reversed consumption.

Owner default suite: 219 passed, 21 skipped in 16.90s. The 21 existing skipped tests require the optional container mail harness; none of the new cases is skipped. Ruff passes for both new Python files. Log: /tmp/email-sender-transition-protocol-check-20261031.log.

Required native completion

The adapter must implement complete UID/spec compare-and-swap operations, verify the RPF-WP-0068 custody return and current projection, hold the existing capture lock, prove the absence of other PVC writers, and bind each helper creation and deletion to durable identity evidence. Snapshots must use the existing read-only SQLite backup path and remain private. Runtime verification must inspect actual sender/credential references, health and scoped denial behavior without sending.

The final capsule must bind all executable dependencies, proposal and preimages; the attended entry point must require the exact reviewed digest. Native server dry-runs, source review and independent return checks must precede execution. No production execution instruction is supplied by this protocol-only document. T02 remains open until these obligations are implemented and verified; T03/T04 remain attended execution and independent native acceptance.

Technical decision72341ab6-dc25-4974-a3d0-80186acb47f9 records the configuration-only recovery design. It is not credential admission or production execution approval. Source hashes and validation scope: sender-transition-protocol-2026-10-31.json.