INTENT/SCOPE: mode reference implementation (handoff semantics for P2, email master/slave roles, callback stub, reuse surface)

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 10:35:56 +02:00
parent 0c7ed5f46f
commit 55ea04f65d
2 changed files with 146 additions and 14 deletions

147
INTENT.md
View file

@ -257,6 +257,10 @@ It does not imply:
The application decides whether and how to satisfy the request.
*(Phase 2: `!MODE` is a requested **handoff** from email to another mode.
The mode contract defines what can happen to it, including refusal. It
stays a request, never a command. See Mode reference implementation.)*
---
### 9. Economic syntax remains closed
@ -544,36 +548,151 @@ unchanged.
validates the corpus.
4. **Safe reference behavior.** The reference service demonstrates
principle 10.
5. **Email as a building block.** A mode reference implementation makes
MAS email a capable, reusable component of a larger multimodal
communication framework. That framework is yet to be designed and is not
built here. See below.
### Open question: the value of interaction (P2)
### Decided: interaction modes are handoffs (P2)
Phase 1 proved resource addressing strongly, and interaction only partly.
*Decided by the founder on 2026-10-19. This replaces the open question
from the first phase-2 draft.*
Phase 1 proved resource addressing strongly, and interaction only partly:
`!callback` states the intent, but the service still has to ask for a
number and a time. The link from the opaque intake target `ticket` to the
resource type `ticket` exists only through a statute registry entry.
Phase 2 must decide one of two things:
number and a time. The decision gives `!MODE` defined semantics, but at
the **mode-contract** layer, not in address syntax:
- define "type intake" semantics, so that an opaque target naming a
declared resource type has a specified meaning; or
- narrow P2 to a pure preference hint, and stop adding mechanism for it
(such as the `---` stand-in) until a use case needs it.
- `!MODE` requests a handoff of the conversation from email to `MODE`.
The address grammar and statute fields stay as they are. `intake_for`
still links an intake target such as `ticket` to its resource type.
- What a handoff does is defined in the mode contract (below): negotiate,
run, time out, complete, fail or be refused. These are statuses reported
back to email, not side effects of parsing.
- The P2 work is narrowed accordingly. No new address mechanism is added
for modes (beyond the existing `---` stand-in) unless the contract needs
it.
### Still not in phase 2
## Mode reference implementation
### Purpose
Make MAS email a **capable building block** for a multimodal
communication framework, which is yet to be designed. The framework will
combine email with other modes (callback, chat, video, SMS, web forms, and
so on). This repository supplies the email part, plus enough of an
interface landscape around it that the framework can be designed against
something that runs.
### Boundary
- **Email is the only real communication channel.** The repository sends
and receives real mail. It does not place calls, run chats, send SMS or
integrate with telephony or messaging providers.
- **Other modes exist only as test stubs.** A stub speaks the mode contract
and simulates how a mode develops. It never contacts a person or an
outside service.
- **Callback first.** One fully worked stub, callback. The contract is
generic, so other modes plug in the same way. A second, trivial stub may
exist only to prove that.
- The framework itself, orchestration beyond what email-as-master needs,
and connectors to real CMS, ticketing or support products are out of
scope.
### Two roles for email
Email takes one of two roles, **configured per resource type** and fixed
for the life of a case. One deployment can do both, for example `ticket`
mastered by email and `case` slaved to an external CMS.
**Email as master.** Email is the reference for the communication. It owns
the case and its durable thread. When a handoff is requested
(`ticket!callback@`), email negotiates the missing details by email,
hands off to the mode, and records every mode status in the thread. When
the other mode times out, fails or ends, email **picks the conversation
back up**. Email owns the timeouts in this role.
**Email as slave.** Email is one element in a control flow owned
elsewhere: a CMS, a ticketing or support system, or the future framework.
The email side provides case-based communication for that master:
- **The master issues the case identifier; email adopts it.** The case is
exposed as a resource address (for example `case=EXT-123@`) under the
statute. Email maps the identifier but never invents it. Intake mail
without a case is reported to the master, which answers with the
identifier to use.
- Inbound mail becomes events for the master.
- **The master configures whether email may send on its own,** per case:
for example acknowledgements, or negotiation questions. Otherwise email
sends only when the master instructs it.
- Mode transfers are **controlled from outside**. The master may block
them, or prime them with a mode webhook that email calls when a
`!MODE` request arrives.
- **Timeouts belong to the master.** Email reports, but does not
escalate on its own.
- Principle 10 holds in both roles. A send the master requests can still
be refused (unauthenticated sender, automated mail, cap reached). The
refusal is reported back to the master.
### Callback stub
The callback stub simulates the relevant ways a callback can develop. Its
scenarios are **scripted and deterministic**: chosen by a fixture or a
test header, and reproducible in pytest and as contract fixtures.
- **Negotiation over email.** The number or time is missing, so the service
asks by email. The customer replies, and the request becomes
schedulable. This is the gap phase 1 found.
- **Outcome lifecycle.** Scheduled; attempted with no answer; retried;
completed; failed; expired. Every status reaches the email thread
(master) or the outside master (slave).
- **Refusal paths.** The mode is unavailable or not enabled, the request
is declined, or it is out of hours. Email falls back and says why.
## Current scope and reuse surface
What the larger framework can build on. Each item is versioned and tested
on its own.
| Reuse surface | What it is | Status |
|---|---|---|
| MAS address spec | `mas-v0.1-spec/` (v0.1.1), `mas-v0.2-spec/` (draft): grammar, statute schema, conformance corpora | exists |
| `mas_core` | parse (no I/O), discover (exact host), resolve (pure), generate / `for_destination` | exists |
| Gateway event | `mas-gateway` pipe/webhook → normalized JSON event with parse, semantics and trusted sender authentication | exists; to be versioned with a schema |
| Postfix profile | `integrations/postfix/`: receiving setup that keeps MAS syntax intact | exists |
| **Mode contract** | Language-neutral, versioned, separate from the address spec. It defines handoff requests, mode statuses, timeouts, roles (master/slave), outside-master commands (send, block, prime webhook, assign case id) and refusals. Comes with JSON schemas and conformance fixtures | new |
| **Email mode reference** | Email side of the contract in both roles, built from the gateway and the reference ticket service | new |
| **Stub mode server** | Scriptable stub that speaks the contract, callback first | new |
| **Stub outside master** | Minimal fake CMS/ticketing master that drives email in slave mode end to end | new |
The reference ticket service and the stubs are **examples and test
fixtures, not products**. The contract and schemas, `mas_core` and the
address spec are the parts meant to be reused unchanged.
## Not in phase 2
Other language implementations (except one used to validate v0.2), a
policy daemon, a central registry, mail-client plugins, signed statutes,
implicit parent inheritance, and economic semantics. A web composer is out
until something asks for one.
until something asks for one. Real non-email modes, telephony or messaging
integrations, connectors to real CMS or ticketing products, and the
multimodal framework itself are out too.
### Phase 2 is done when
## Phase 2 is done when
1. a fresh Postfix install, using only `integrations/postfix/`, delivers
the full corpus unchanged and refuses relaying;
2. `mas compose` produces correct forms for every destination observed so
far, and refuses the rest;
3. v0.2 is declared final, or is withdrawn with recorded reasons;
4. the P2 question above is decided and recorded in the spec;
5. the live test environment is retired, with its evidence archived.
4. the handoff reading of P2 is recorded in the v0.2 spec text, and the
address spec points to the mode contract;
5. the live test environment is retired, with its evidence archived;
6. mode contract v0.1 is published with JSON schemas and fixtures;
7. the email mode reference passes them in both roles: as master against
the callback stub, and as slave under the stub outside master;
8. every callback scenario (negotiation, outcome lifecycle, refusals) runs
deterministically in the test suite.
---

View file

@ -41,12 +41,22 @@ delivery stays external.
tested against a real Postfix by `experiments/postfix-probe/` and
`tests/test_postfix_profile.py` (needs Docker). Exim: notes only
(`integrations/exim/NOTES.md`).
- **Mode reference implementation** (new; INTENT.md, *Mode reference
implementation*). A language-neutral mode contract (handoffs, statuses,
timeouts, master/slave roles, outside-master commands) with JSON schemas
and fixtures. The email side implements both roles: master per resource
type, or slave to an outside master that issues case ids. Test stubs: a
scripted callback mode and a fake outside master. Email is the only real
channel.
- **Live test environment.** `deploy/railiance/`: the MX for
`mas.coulomb.social`, with replies through Scaleway TEM capped at 300.
It is temporary; MAS-WP-0007 retires it.
## Out of Scope
- Real non-email modes (telephony, chat, SMS, video), connectors to real
CMS or ticketing products, and the multimodal framework itself. Other
modes exist here only as contract-speaking test stubs.
- Implementations in other languages (TypeScript, Go), until a second
consumer exists. That is also the gate for declaring v0.2 final
(MAS-WP-0009).
@ -72,6 +82,9 @@ delivery stays external.
MAS-WP-0009 (declare v0.2 final; waits for a second implementation or
deployment).
- v0.2 stays a draft (founder, 2026-10-19).
- P2 is decided: `!MODE` requests a handoff, defined by the mode contract
(founder, 2026-10-19). The mode contract and stubs are not started yet;
they need a workplan.
- The live `mas-mx` pod runs an image built before the profile refactor.
- Tests: `.venv/bin/pytest` runs 199 tests, offline apart from loopback
fixtures and the Docker probe.