AI-generated. Written by an automated system, checked by independent automated gates, and published without human editorial review. How we label and verify.
The surprise in the pipeline: building an email send gate
We built a gate in our production line that would accept or block business emails and internal updates based on one extractable ask, a binary send-or-block decision, and an evidence trail attached to the archived message.
An independent reviewer looked at the first version and passed it on form. We assumed it was safe.
Then a third checker ran it and found twelve logic faults. Twelve. Every single one got fixed the same day and the fixed version is what sits on the shelf now.
What failed — and how we watched it fail
First experiment. We put the gate in front of a batch of production drafts. The gate demanded an ask line on every message. Informational updates with no action required were blocked. Valid status notes never reached their recipients.
We replayed blocked messages. The ones meant only to inform had no ask line because there was nothing to ask. They were legitimate. The gate still refused them.
Second experiment. The gate required the writer to “verify” the ask by re-reading the draft. We let a writer run that check. The gate accepted the message. Later we tried a stricter check: give the verifier a copy with the ask line removed, and ask them to recover the ask from subject, opening and body only. The candidate failed. The earlier pass had been the writer grading its own line.
Third experiment. The evidence trail demanded a content hash. When we tried to verify the evidence from the archived message, the recomputed value never matched. Turns out the original design computed the hash over the entire message text including the evidence line that contains the hash itself — a paradox. No third party could ever recompute the same hash because the hash would change the input. It was obvious once we tried to recompute it: the archived file and the recorded hash couldn’t both be true.
The turning point came when the third checker said, “Try computing it from the message alone.” We did. It failed. The moment clicked. We could either accept an unverifiable claim or change the order of operations.
What we changed and why it fixed things
We changed three concrete behaviors in version 1.1.
1) The evidence hash is computed last, over everything except its own line. We archived a message, recomputed the hash from the archived content, and it matched. Third-party recomputation worked because the hash no longer mutated its own input.
2) Informational updates are allowed to carry an explicit “No action required” line that satisfies the gate. We replayed the earlier blocked batch after this change; the same status notes that had been blocked now passed. The gate recognized intentional no-ask messages instead of failing them.
3) Verification stopped being the writer re-reading their own draft. The gate now runs a read-back against a masked copy where the ask line is deleted. We forced several writers to recover the ask from the subject, opening and body alone. If the ask wasn’t recoverable, the gate blocks the send. That immediately removed our self-verification problem.
Those three changes closed the twelve faults the third checker found. We confirmed closure by re-running the same tests that had produced each fault; each test produced the expected pass. The fixed version moved to the shelf that day.
Why these fixes actually work
The hash fix restores external verifiability. If the evidence line is part of the hash input, verification becomes impossible because the proof alters what it proves. Computing the proof after excluding that line gives anyone with the archived message enough to check the claim.
The “No action required” line fixes a category error. A gate that assumes every message wants an action will force false negatives. Allowing an explicit no-action marker maps the check to the message’s intent instead of the writer’s omission.
Masked read-back removes the conflict of interest. A writer reading their own line will always confirm it; they can’t reliably be the sole check. Making the verification require recovery from other message fields turns the check into a test that can fail, which is the only kind of check that proves anything.
A fair counter-example
Someone suggested that a filled checklist appended to the message achieves the same assurance. We tried that. Writers completed a table from memory and appended it. The gate accepted the message. Later we audited the table against the archived content and found discrepancies. A self-filled table proved nothing. It was the classic illusion of control: a visible artifact that didn’t change the underlying verifiability. That myth led us to the masked copy and hash fixes instead.
One representative detail: during the masked read-back test, we removed the ask line and asked the writer to produce the ask from subject, opening and body only. Several failed. The gate blocked each of those. The blocked messages were previously accepted. That single step showed us both the vulnerability and the remedy in palpable terms.
The full runnable skill lives in our members’ library.
Questions we got
Why not just require a signer other than the writer?
That helps, but it’s brittle. We tried adding a second signer and the process slowed. The masked-copy check gives the same defect-detection without changing the workflow as drastically because it forces the message to stand on its own.
Won’t the “No action required” line be abused?
Maybe. We log and sample those messages. Abuse shows up quickly in audits when the body contradicts the “No action required” claim. The gate treats the line as a legitimate state, not a license to avoid accountability.
How do we know the twelve faults were actually fixed?
We reran the exact failure tests that produced each fault. For every failing case the third checker had recorded, the new behavior produced a pass or a justified block. An independent reviewer then spot-checked the fixes. All closures are recorded in the revision log.
Rule: never let the writer grade its own line; check a copy where the answer is missing — that discipline is what makes an email send gate trustworthy.
Sources: internal testing notes and the version 1.1 skill file from our production line, dated 2026-07-24.
What the standards and mailbox providers say about automated email
A pre-send check sits between a draft and a mail system that has its own rules. Three sets of documentation are worth knowing before you design one: the message format standard, the large mailbox providers’ sender rules, and the general advice on retrying requests safely.
The message format is defined in RFC 5322. It says the only required header fields are the origination date field and the originator address field(s). The Date field records when the creator considered the message complete and ready to enter the mail delivery system. Message-ID is not strictly required, yet the standard adds that every message SHOULD have a “Message-ID:” field, and that the generator of the message identifier MUST guarantee that the msg-id is unique. In other words, the identity of a message is the sender’s job, not the network’s.
Gmail publishes its own expectations. Its Email sender guidelines ask all senders to set up SPF or DKIM email authentication for your sending domains. For marketing mail, Google’s sender FAQ puts it in its own words: “mailto and URL unsubscribe links, don’t meet our one-click unsubscribe requirement“. Those are checks a machine can run on the final message, which is the point.
Retries are the third concern. An automated sender that times out does not know whether the first attempt went through. Stripe’s API documentation describes the standard answer, an idempotency key, which lets a client safely repeat the request without risk of creating a second object or performing the update twice. The same idea transfers to email: give each logical message a stable identity before the first attempt, and refuse a second send of that identity.
How this lines up with what our gate found
The documentation and our three fixes point in the same direction. Each fix replaced a check that could not fail with one that could.
The hash paradox is a format question at heart. Our first version hashed content that included the hash line itself, so no one could recompute it from the archived message. Version 1.1 computes the hash last, over everything except its own line. That is the same discipline the standards apply to identifiers: decide what the identity covers, then generate it once, from content that will not change afterwards.
The “No action required” line is about intent. The first version blocked legitimate status notes because it demanded an ask on every message. The lesson we took is narrower than it sounds: a gate has to know what kind of message it is looking at before it decides what that message must contain.
The masked read-back is the part the external sources do not cover. Authentication and format checks prove a message is well-formed. They say nothing about whether a reader can find the ask. Our gate only counts checks that can actually fail, and a writer re-reading their own draft was not one of them.
A pre-send checklist
- Confirm the message has a Date and a From field, and generate a unique Message-ID once per logical message.
- Store a send key for each message before the first attempt. On retry, look it up and stop if it was already sent.
- Check that the sending domain is authenticated before anything leaves the queue.
- Classify the message: action request, informational, or marketing. Apply only the rules for that type.
- For marketing mail, require one-click unsubscribe headers rather than a link alone.
- Run a masked read-back: delete the ask line and confirm the ask is still recoverable from subject, opening and body.
- Compute any evidence hash last, excluding its own line, then recompute it from the archived copy.
More questions
Is a Message-ID enough to stop duplicate sends?
Not on its own. RFC 5322 says the ID must be unique, but a retry that builds the message again will usually generate a new one. Keep your own send key, created before the first attempt, and check it before every retry.
Do these rules apply to internal updates too?
The format rules in RFC 5322 apply to every message. Gmail’s unsubscribe requirement is framed around marketing mail, so check the Email sender guidelines FAQ for which of your message types it covers. Our gate was built for business emails and internal updates alike, and the masked read-back applies to both.
How we know
The factual claims in this article come from our verification store — each with a source type, a confidence label and a reference. The method is documented on How we know.
– In the send gate’s first version, the same writer ‘verified’ the ask line it had just written by re-reading its own draft; version 1.1 requires a masked-copy read-back where the ask line is deleted and the ask must be recoverable from subject, opening and body alone, or the message blocks. | source: documented source | conf: verified | ref: EBZ skill-fabrikk 2026-07-24 + skillfil v1.1
– The first version of our email send gate demanded a hash over content that included the hash itself — a paradox that could never be verified by anyone; version 1.1 computes the evidence hash last, over everything except its own line, so a third party can recompute it from the archived message alone. | source: documented source | conf: verified | ref: EBZ skill-fabrikk 2026-07-24 + skillfil v1.1
– A mandatory third checker found 12 logic faults in the send gate’s first version after an independent reviewer had already passed it on form; every one was closed in version 1.1 on the same day, and the fixed version is what sits on the shelf. | source: documented source | conf: observed | ref: EBZ skill-fabrikk 2026-07-24 + skillfil v1.1
– Myth: a checklist appended to an email proves the email was checked. A table the writer fills in from memory proves nothing; our gate only counts checks that can actually fail — a read-back against a masked copy, and a hash anyone can recompute from the archived message. | source: documented source | conf: mythbuster | ref: EBZ skill-fabrikk 2026-07-24 + skillfil v1.1
