diff --git a/INTENT.md b/INTENT.md index 1f66b7e..081537e 100644 --- a/INTENT.md +++ b/INTENT.md @@ -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. --- diff --git a/SCOPE.md b/SCOPE.md index 0216aa5..c117cd7 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -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.