Skip to content

Kept forwards: a taken-over forward rule keeps forwarding the original (ADR 47), and verified destinations are managed from Mailda - #325

Merged
wms2537 merged 4 commits into
mainfrom
kept-forward
Oct 3, 2026
Merged

wms2537 merged 4 commits into
mainfrom
kept-forward

Conversation

@wms2537

@wms2537 wms2537 commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Built on the live drill on mailda.site (2 Oct 2026, cleaned up): message.forward() keeps the original sender, body and Message-ID, works after the message is stored, carries up to the 24.4 MB measured, and fails loudly in the Worker for an unverified destination without bouncing the sender. Receipt: docs/receipts/email-worker-forward.md.

  • ADR 47: Mailda calls message.forward() for a forward a taken-over rule already had; §13/§14 amended.
  • Storage: the address keeps its destination (0074); one attempt row per receipt, written in the receipt's batch, settled as handed_over / refused / withheld (loop) / outcome_unknown. Never rejects or rethrows after accepting; a redelivery never forwards twice; X-Mailda-Forwarded-By carries this Node's claim id.
  • Take-over: a forward rule needs forward: keep|stop (contract, CLI --forward, the setup step's third choice, Setup screen); keep refused for an unverified destination; put-back clears it; removing an address that keeps a forward is refused.
  • Destinations: list (verified / waiting), register one (POST /api/provider/destination-addresses; Cloudflare mails the link), GET /api/forwards; CLI --destinations, --add-destination, --forwards. No address in audit or logs; nothing deletes a destination. MCP withheld.
  • Status: People shows each kept forward's state; doctor kept_forwards flags unanswered and refused forwards.

Token: the optional permission is now "Email Routing Addresses: Edit" (Read still lists). Not measured: non-refusal forward failures, larger forwards, a real end-to-end run on a Node. Not built: the "send a copy" fallback (PR 2).

Verified: full forced run (workerd 2,145, node 880, DOM 857), typecheck, lint, receipts/sdk/skill checks, dry-run deploy.

🤖 Generated with Claude Code

wms2537 and others added 4 commits October 3, 2026 02:06
…estination, one settled row per receipt

Migration 0074 gives an address the forward destination it keeps and adds kept_forward_attempts, written in the
receipt's own batch (only when the receipt row was inserted) and settled after forward() answers: handed_over,
refused with Cloudflare's words, withheld for this Node's own X-Mailda-Forwarded-By marker, or left
outcome_unknown. A redelivery is already_accepted and forwards nothing. The receipt for forward() is
docs/receipts/email-worker-forward.md, from the 2 October drill on mailda.site.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eople and doctor, ADR 47

A forward rule's take-over now names forward: keep or stop (E_ROUTING_FORWARD_NEEDS_CHOICE); keep records the
rule's own destination on the address, refused when the account lists it unverified or not at all, dropped when
the PUT is refused, cleared by a confirmed put-back, and removing the address is refused while it keeps one
(E_ADDRESS_KEEPS_A_FORWARD). POST /api/provider/verified-destinations counts the account's whole list, re-checks
each kept forward's destination and returns the addresses only when asked; POST /api/provider/destination-addresses
registers one (Email Routing Addresses: Edit, named in every refusal; the audit entry names Cloudflare's id, never
the address); GET /api/forwards lists kept forwards with their latest attempt. CLI (--forward, --forwards,
--destinations [--addresses], --add-destination, the setup step's third choice), Setup and People, doctor's
kept_forwards, SDK and Skill regenerated, MCP withheld. Blueprint ADR 47 amends §13, §14 and the journey.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t remeasured, docs

A put-back answering E_ROUTING_RULE_NOT_OURS_NOW now clears the address's kept forward, since that mail no longer
reaches the Node; before, the address could be neither removed nor put back. doctor-check-cost.md records the one
query kept_forwards adds (33 to 34 subrequests, measured). The forward receipt no longer points at a working file
outside the repository, and application-shell.md describes the new Setup and People lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e destination count reads as a plural-free sentence

The owner accepted 保留的转发 (kept forward), 等待验证 (waiting for
verification) and 登记 (register) in the working session on 3 October
2026; they are glossary rows bound to their keys, recorded as round five.
setup.verified.listed said "address(es)"; it now reads "Destination
addresses in the account: 1 verified, 1 waiting for verification."

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@wms2537
wms2537 merged commit eb0d7ae into main Oct 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant