MAS-WP-0010 finished: email slave role, stub outside master, contract flows, SCP-8

- EmailMode slave role: master-issued case ids, events to the master,
  sends only on instruction or autonomous policy, transfers blocked or to
  a primed webhook, timeouts left to the master; principle 10 refusals
  reported back.
- conformance/flows.json (13 flows) + mas_modes.runner; mas test runs the
  mode corpus (172/172).
- SCP-8 / v0.2 section 7.1: !MODE requests a handoff defined by the mode
  contract. docs/reuse-surface.md.
- Deploy image copies mas_modes (ticket service imports its mailer).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5787@bnt-lap001
Assistant-Session: 5db26b82-138b-40cc-9856-4d5eb0f752fd
This commit is contained in:
tegwick 2026-10-19 11:03:16 +02:00
parent e91cd01a02
commit 87be0d1da3
16 changed files with 1396 additions and 17 deletions

49
docs/reuse-surface.md Normal file
View file

@ -0,0 +1,49 @@
# Reuse surface
This repository is the email building block for a multimodal communication
framework that is yet to be designed (INTENT.md, *Mode reference
implementation*). This page says what such a framework can depend on, and
how stable each part is.
## Depend on these
| Part | Where | Stability |
|---|---|---|
| MAS address spec | `mas-v0.1-spec/` (v0.1.1), `mas-v0.2-spec/` (draft) | v0.1.1 stable. v0.2 draft until a second implementation passes its corpus (MAS-WP-0009) |
| Mode contract | `mas-modes-v0.1-spec/` | v0.1 draft. Changes are versioned; messages carry `mas_modes_version` |
| Gateway event | `mas-modes-v0.1-spec/schema/mas-event-v0.1.schema.json` | v0.1. Events carry `mas_event_version` |
| Conformance corpora | the bundles' `conformance/` | Normative for their version. Consume them unchanged |
| `mas_core` | parse (no I/O), discover (exact host), resolve (pure), generate / `for_destination` | Python reference library |
| `mas_gateway` | MTA `pipe` and provider `webhook` → event | Reference adapter. The event is the interface, not the code |
| Postfix profile | `integrations/postfix/` | Tested against Postfix 3.7 (`tests/test_postfix_profile.py`) |
## Integrating as an outside master
Configure the resource type as `slave` (`mas_modes.email_mode.RoleConfig`)
and point `master_url` at your system. You then:
- receive `case.intake` and `case.message`, each carrying a gateway event;
- answer `case.assign` with your own case id; email adopts it as
`TYPE=ID@domain`;
- send replies with `mail.send` (`in_reply_to` a recorded message);
principle 10 can refuse them;
- decide per case on `autonomous_send` and `transfers` (`block`, or your
mode webhook);
- own every timeout; end a handoff with `handoff.cancel`.
## Integrating a mode
Implement the mode endpoint in CONTRACT.md: accept `handoff.request`,
`handoff.update` and `handoff.cancel`, and post `handoff.status` to
`status_url` with an increasing `seq`. Never send `timed-out`.
`mas_modes/stubs/callback.py` is a complete example.
## Examples only, not products
- `examples/ticket_service/`: the reference ticket service, used as the
store for email-mastered cases.
- `mas_modes/stubs/`: the callback stub and the stub outside master.
They never contact a person or a service.
- `mas_modes/email_mode.py`: the reference email side. It is
single-process, with SQLite and no authentication on its HTTP endpoints,
so it is fit for loopback and tests. The contract is the interface.

View file

@ -299,6 +299,34 @@ case-insensitive by design.
---
## SCP-8: `!MODE` requests a handoff, defined by the mode contract
**Section:** §7 Interaction semantics.
**Evidence:** phase 1 showed that `!callback` expresses intent, but that a
callback still needs a number and a time, so it starts a negotiation. The
founder decided on 2026-10-19 (INTENT.md, phase 2) that `!MODE` requests a
*handoff* from email to `MODE`. MAS-WP-0010 implements this as a separate
contract (`mas-modes-v0.1-spec/`), with email as master or as slave per
resource type.
**Proposed text (§7, appended):**
> A receiver that acts on an interaction request treats it as a request
> to hand the conversation over to `MODE`. What can happen to that request
> (negotiation, scheduling, completion, failure, refusal, timeout) and
> who owns the conversation meanwhile is defined by the MAS mode
> contract, which is versioned separately (`mas-modes-v0.1-spec/`).
> Email remains the durable thread when it is the master. The handoff
> stays a request: refusal is a normal outcome, and the address grants
> nothing.
**Impact:** informative for parsers and generators: there is no change to
the grammar, the statute or the conformance corpus. Receivers that
implement handoffs get a contract to conform to.
---
## Lower-priority gaps (no proposal yet)
Recorded in the review, not urgent: