MAS-WP-0003-T05: provider results in review, spec change proposals, gate recommendation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 252470@bnt-lap001
Assistant-Session: ad628c8f-4be2-4979-94c9-76c7ed6f8241
This commit is contained in:
tegwick 2026-10-18 13:34:21 +02:00
parent d4585eb542
commit d7264e7ec5
3 changed files with 237 additions and 17 deletions

View file

@ -1,4 +1,4 @@
# MAS v0.1 experiment review (first pass, 2026-10-08)
# MAS v0.1 experiment review (2026-10-08, provider pass 2026-10-18)
Status of MAS-WP-0002, Milestone 9. The answers below come from building
`mas_core`, the `mas` CLI, `mas-gateway` and the reference ticket service,
@ -8,9 +8,15 @@ loopback fixture servers).
**Scope:** the MTA half of the email path was tested against a real
Postfix (3.7.11, Debian bookworm, in Docker). The setup was SMTP → Postfix
→ `pipe` transport → `mas-gateway` → reference ticket service
(`experiments/postfix-probe/`). Mailbox providers (Gmail, Outlook,
corporate gateways) and public DNS/MX were not involved. That half moves
to **MAS-WP-0003**.
(`experiments/postfix-probe/`).
**Provider pass (MAS-WP-0003, 2026-10-18):** the same stack ran as a live MX
for `mas.coulomb.social` on railiance01 (`deploy/railiance/`), with the
statute at `https://mas.coulomb.social/.well-known/mas`. Real mail came from
Gmail and Microsoft 365, and replies went out through Scaleway TEM. The
evidence is the gateway's JSONL event log plus the Postfix log. Forwarding
and mailing-list paths (T04) are still pending. Spec consequences are
collected in `docs/spec-change-proposals.md`.
## Answers to the review questions
@ -95,11 +101,56 @@ The results:
decision. The gateway forwarded it as `valid: false`, and the app
ignored it.
**Still untested (MAS-WP-0003):**
- whether senders' providers and web forms accept `!` and `=` in recipient
addresses;
- overlap with SRS (`SRS0=...`) and VERP when forwarding;
- facet stripping by providers.
**Providers (tested, MAS-WP-0003):** four address forms were sent from
four sender setups:
- forms: `ticket!callback@`, `ticket=ID@`, `ticket=ID+comments@`,
`ticket=RE=2026-4711@`;
- sender setups: Gmail web, the Gmail mobile app, and a Microsoft 365 tenant via
both Outlook mobile and Outlook desktop.
| Sender | Compose form | Envelope recipient and To header | Transport |
|---|---|---|---|
| Gmail web | accepted all 4 unquoted | byte-identical | 209.85.x, STARTTLS, BDAT |
| Gmail mobile | accepted all 4 unquoted | byte-identical | same |
| M365, Outlook mobile | accepted all 4 unquoted | byte-identical | EOP 40.107.149.x |
| M365, Outlook desktop | accepted all 4 unquoted | byte-identical | EOP 52.101.171.x |
- **Nothing was rewritten, quoted, rejected or stripped.** That covers `!`,
a doubled `=` and the `+comments` facet. The gateway classified every
message as the probe predicted: P2 function with `callback` → 201
created; P1 resource → 202; the facet was recognised.
- **The reply direction also holds.** The service replied From
`ticket=GS-85QJ8WC09P@mas.coulomb.social` through Scaleway TEM. Gmail
showed the `=` From address as sent, with SPF, DKIM
(d=mas.coulomb.social) and DMARC all passing. A plain Gmail "Reply" went
back to that address byte-identical, with correct `In-Reply-To` and
`References`, and was correlated to the ticket (200).
- **Not covered:** consumer Outlook.com (the operator has no account; it
uses the same Exchange Online path as M365), the Outlook-on-the-web
compose form, and other providers such as Apple, Yahoo and GMX. Two
providers is evidence that `!` and `=` work in practice; it is not a
survey.
**Operational findings from the live run:**
- **Stock Postfix kills P2.** `smtpd_relay_restrictions` must contain a
reject-class entry, or smtpd refuses to start. Also, unless
`allow_untrusted_routing = yes`, Postfix ignores access-map results for
local-parts containing `!` or `%` (it treats them as sender-specified
routing). `reject_unauth_destination` then refuses every P2 address. The
working MAS host config relays only `@DOMAIN` through an explicit
regexp, turns off `swap_bangpath` and `allow_percent_hack`, and ends the
list in `reject`. A host that "just enables MAS" on a default Postfix
will silently lose all `!` mail.
- **A TEM "blackhole" MX swallowed inbound mail.** Scaleway TEM's domain
setup suggests `MX 10 blackhole.tem.scaleway.com`. Added next to the real
MX at the same priority, it sent about half of all inbound mail to a
discard host, and nobody got a bounce. Sending providers' setup wizards
are a deliverability risk for MAS subdomains that receive mail.
- **Outbound port 25 was blocked** at the hosting provider (and on a
second host). Replies need an authenticated submission relay.
**Still untested (T04):** overlap with SRS (`SRS0=...`) and VERP when
forwarding, and facet stripping by forwarders and lists.
### Resource addressing: did it improve correlation?
Yes. The service replies *from* `ticket=GS-…@great-service.example`, so an
@ -133,6 +184,12 @@ should either say this explicitly, or define "type intake" semantics for
an opaque target that names a declared resource type.
### Security: did any address start acting like a capability?
(Addendum from the live run: an intake address such as `ticket!callback@`
that auto-replies turns any forged `From:` into outbound mail to a third
party. That is a backscatter/reflection vector at the application layer.
The live deployment therefore caps all replies sent (300 in total, T06)
and discards Postfix's own bounces. See SCP-5.)
Not for reading or control. Knowing a ticket address grants no read access
and no admin action. It does let anyone **append correspondence** to an
open ticket, which is the intended function of a communication endpoint.
@ -140,10 +197,20 @@ That is also an injection and spam vector. Ticket ids are non-guessable
(10 Crockford base32 characters), but sender policy belongs to the
application, not to MAS.
## Next step (MAS-WP-0003, before the decision gate)
Run the provider half on a real subdomain:
- an MX pointing to a Postfix configured like the probe;
- the statute served at `https://<sub>/.well-known/mas`;
- test mail from Gmail, Outlook and one corporate gateway to
`ticket!callback@`, `ticket=ID@` and `ticket=ID+comments@`, plus replies
to the service's `ticket=ID@` From address.
## Decision gate (MAS-WP-0002), recommendation
The gate asks which additions answer a need the experiment demonstrated.
This is a recommendation; the decision is the founder's.
| Candidate | Demonstrated need? | Recommendation |
|---|---|---|
| Postfix/Exim integration | **Yes.** Default Postfix drops every P2 address, and the correct relay config is non-obvious | Build first: a documented, tested Postfix profile (later Exim) based on `deploy/railiance/entrypoint.sh` |
| Spec v0.1.1 errata | **Yes**, SCP-1 to SCP-5 | Do alongside the integration |
| Address composer | Weak. Providers accepted hand-typed addresses; the 64-octet budget and facet/interaction exclusivity are the only traps | Defer; `mas generate` in the CLI covers it |
| Mail-client inspector | Not shown; nothing was rewritten that a user would need to see | Defer |
| TypeScript / Go implementations | Not shown; no consumer outside Python yet | Defer until a second consumer exists |
| Signed statutes | Not shown; pinned local statutes covered the operator case (see Discovery) | Defer |
| P3 economic profile | Not exercised | Defer |
T04 (SRS/VERP) could change the `!`/`=` row for forwarded mail. Revisit
this table once T04 is done.