docs(engagement): Phase 9 as built — deliverability, suppression and bounces #191
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/engagement-deliverability"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Records what Phase 9 shipped (RunicGateway/website#176) and what building it settled. Operator docs: RunicGateway/runicgateway.com#25
ENGAGEMENT.mdPhase 9 "As built", covering the four decisions taken before any code, the defect the phase exists to have avoided, and the seven-rung live-rig walk.
Two corrections to the plan's own text:
RCPT TOthrows synchronously with the reply code intact — the highest-value deliverability signal there is, andmailer.jswas already catching it and discarding it. So the phase reads it and ships no API transport.PERMANENT_CODESis not a bounce classifier. It answers "is retrying pointless?" and containsEAUTHand554. Suppressing on it would have emptied the mailing list the first time an SMTP password expired — silently, with a clean send log.§4.5's DDL gains
address_maskedandcreated_by, with the reasoning: a hash-only table cannot be operated, the domain survives so a domain-wide failure is visible, and the local part is destroyed rather than shortened so the column can never be read back as an address book.§7.1 Q1's narrower half is now answered — an unverified address is excluded at enqueue, and only from the email channel, because a rule spanning channels must still reach that person's in-app inbox.
Also the one thing only the live rig could find:
engagement_sendshas carried abouncedstatus since §4.5 and nothing had ever written it, so the Send Log's "Bounced" filter matched nothing and always would have.BACKEND_DESIGN.mdengagement_suppressions— including why writes areINSERT IGNORE(the first reason an address was suppressed is the one that survives; an upsert would let a later manual re-add overwrite abouncediagnosis) and whycreated_bybeing NULL is what separates an automatic row from an admin's.Note for the reviewer
BACKEND_DESIGN.mdis stored CRLF in this repo while this machine hascore.autocrlf=true, which silently rewrote every line on the firstgit add. Re-staged with-c core.autocrlf=false, so the diff is 227 insertions / 9 deletions rather than 1939/1721.AI disclosure
Written with Claude Code (Claude Opus 5); the commit carries
Co-Authored-By: Claude.