- mas_core: P2-maximal parser with required_profile, generator, statute schema + semantic lint + defaults-only inheritance, exact-host discovery with typed failures and same-origin redirects, pure policy resolver - mas_conformance: vendored spec fixtures (drift-tested) + property and statute cases - mas CLI: parse / explain / discover / lint-statute / test - mas-gateway: generic mail -> MAS event -> HTTP (MTA pipe + webhook) - examples: static great-service.example statute, reference ticket service - docs/experiment-review.md: first-pass findings; live MTA test still open Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 623586@bnt-lap001 Assistant-Session: 10b30928-5b3b-4c11-9934-5ecca07367d8
116 lines
6 KiB
Markdown
116 lines
6 KiB
Markdown
# MAS v0.1 experiment review (first pass, 2026-10-08)
|
|
|
|
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,
|
|
and from running the test suite (135 tests, all offline except the
|
|
loopback fixture servers).
|
|
|
|
**Scope caveat:** every "email path" here is simulated. Raw RFC 5322
|
|
messages go through the real `mas-gateway pipe` entrypoint, but no
|
|
production MTA or mailbox provider was involved. The *Email infrastructure*
|
|
question is therefore still open and needs the live test described at the
|
|
end.
|
|
|
|
## Answers to the review questions
|
|
|
|
### Syntax: did the parser stay simple?
|
|
Yes. The parser is about 100 lines with no I/O. It always uses the maximal
|
|
(P2) grammar and records `required_profile`, so `ticket!callback` parses
|
|
without knowing anything about the namespace. All 31 spec fixtures and 27
|
|
added property cases pass.
|
|
|
|
Gaps found in the spec:
|
|
- **Resource-type case.** The ABNF allows `Ticket=PR42`, but the statute
|
|
schema only registers lower-case type names. Such an address parses, but
|
|
it can never match a declared type, even when the statute says
|
|
`ascii-insensitive`. The spec should either make resource types
|
|
lower-case in the grammar, or state that the equivalence policy also
|
|
applies to the type name.
|
|
- **Interaction-mode names.** The value grammar allows `call.back` and
|
|
`a=b`. The schema's mode-name pattern does not. Those modes parse but can
|
|
never be enabled. This is harmless, but it should be documented.
|
|
- **Registry keys.** The schema pattern already blocks `+ ! $ ^`, but it
|
|
still allows `=` and leading or trailing dots. Semantic lint is needed to
|
|
reject a key like `ticket=GS-1` (`registry-key-resource`).
|
|
|
|
### Discovery: was exact-host metadata sufficient?
|
|
For this experiment, yes. Implementation choices the spec does not settle:
|
|
- `application/json` (or `+json`) is required as the content type
|
|
(`InvalidContentType`). The spec only asks for 2xx plus the schema. It
|
|
should say whether the content type is checked.
|
|
- Redirects are followed only when scheme, host and port all match. That
|
|
is stricter than "same host". A port change counts as `CrossHostRedirect`
|
|
and an https→http change as `SchemeDowngrade`.
|
|
- `mas_version` is checked before the schema runs, so a future version is
|
|
reported as `UnsupportedVersion` and not as a schema error.
|
|
- **Operational finding:** a service must not depend on discovering *its
|
|
own* statute. If the statute endpoint is down, the ticket service sees
|
|
`namespace_confirmed = false` and correctly refuses to act. The mail is
|
|
then declined. Operators should pin their own statute in local
|
|
configuration (`mas-gateway --statute`). Discovery is for third-party
|
|
namespaces.
|
|
|
|
### Policy: could all inference stay explicit?
|
|
Yes. Policy is a pure function. Without a statute, `kind` is always
|
|
`opaque`, `=` alone gives no resource semantics, and `!` stays
|
|
"unconfirmed". `mas explain` lists each of these as an *unknown*.
|
|
Folding is applied only when a statute declares it, and dot folding never
|
|
touches resource identifiers.
|
|
|
|
Facets have no statute declaration at all, so they are always reported as
|
|
"application-defined". A later version could let statutes list the facets
|
|
they recognise.
|
|
|
|
### Email infrastructure: which forms were rewritten or rejected?
|
|
**Not yet tested.** Known risks to check:
|
|
- `=` overlaps with SRS (`SRS0=...`) and VERP encodings.
|
|
- `!` is UUCP bang-path syntax. Some validators and web forms reject it.
|
|
- Postfix `recipient_delimiter = +` strips the facet for lookups. That fits
|
|
the facet-degradation design.
|
|
|
|
### Resource addressing: did it improve correlation?
|
|
Yes. The service replies *from* `ticket=GS-…@great-service.example`, so an
|
|
ordinary reply lands on the resource address. Correlation uses the address
|
|
only. The tests send an unrelated subject and a facet-stripped address,
|
|
and both correlate.
|
|
|
|
### Subject lines: could identifiers disappear?
|
|
Yes. Replies use the customer's own subject, and no ticket id is ever put
|
|
in it (asserted in the tests).
|
|
|
|
### Lifecycle: did closed resources stay understandable?
|
|
Yes. A closed ticket stays addressable. Mail to it is archived separately
|
|
and the ticket is not changed. A single notice goes only to the original
|
|
requester, and never to automated senders (`Auto-Submitted`,
|
|
`Precedence`). Mail to an unknown resource is quarantined with no reply.
|
|
For an MTA pipe, the gateway exits 0 when the app declines and 75 when the
|
|
app is unreachable, so it never generates a bounce (no backscatter).
|
|
|
|
### Interaction: was `!callback` useful?
|
|
Partly. It expresses intent cleanly, but the service still needs a phone
|
|
number and a time. The address cannot carry those, so the first reply has
|
|
to ask by email. `!callback` therefore starts a negotiation; it does not
|
|
replace one.
|
|
|
|
The bare `ticket` in `ticket!callback` is an **opaque** target. It has no
|
|
defined link to the resource type `ticket`. The spec's canonical example
|
|
(§7) implies such a link. The statute has to register `ticket` as an
|
|
intake function, and the service has to know what that means. The spec
|
|
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?
|
|
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.
|
|
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.
|
|
|
|
## Recommended next step (before the decision gate)
|
|
Run the live path: a real domain, the static statute served at
|
|
`/.well-known/mas`, Postfix with the `mas-gateway pipe` transport, and test
|
|
mail sent from Gmail, Outlook and one corporate gateway to
|
|
`ticket!callback@`, `ticket=ID@` and `ticket=ID+comments@`. Record which
|
|
addresses arrive unchanged. That evidence answers the open
|
|
*Email infrastructure* question.
|