mail-address-semantics/workplans/MAS-WP-0002-reference-experiment.md
tegwick 1c0fcce69d MAS-WP-0003: finished; MAS-WP-0002 gate decided; residuals MAS-WP-0004..0007
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
2026-10-18 14:09:21 +02:00

915 lines
13 KiB
Markdown

---
id: MAS-WP-0002
type: workplan
title: "MAS v0.1 reference experiment"
domain: communication
repo: mail-address-semantics
status: done
owner: claude
topic_slug: coulomb-social
created: "2026-10-08"
updated: "2026-10-18"
state_hub_workstream_id: "17d1228a-bfd1-5fed-ac90-a314b64f6f5b"
---
# MAS v0.1 reference experiment
### Objective
Build one runnable reference experiment for MAS v0.1.
The experiment should validate the full path:
```text
address
→ parse
→ discovery
→ policy
→ mail gateway
→ ticket resource
→ subsequent resource-addressed mail
```
The plan deliberately avoids parallel language implementations and infrastructure-specific integrations until the model has survived one complete implementation.
---
## Milestone 0 — Establish the implementation baseline
```task
id: MAS-WP-0002-T01
status: done
priority: high
state_hub_task_id: "4cd7534b-0175-5213-851b-1416cabc4366"
```
### Goal
Turn the specification bundle into executable project inputs.
### Work
Import or vendor:
```text
SPECIFICATION.md
grammar/mas-v0.1.abnf
schema/mas-statute-v0.1.schema.json
conformance/addresses.json
```
Establish the repository structure.
Define Python package boundaries:
```text
mas_core.model
mas_core.parser
mas_core.discovery
mas_core.policy
mas_core.statute
mas_core.lint
```
Define an explicit version:
```text
MAS 0.1
implementation 0.1.0-dev
```
### Deliverable
A repository where:
```text
pytest
```
runs the existing fixture corpus.
---
## Milestone 1 — Core parser and model
```task
id: MAS-WP-0002-T02
status: done
priority: high
state_hub_task_id: "099c957c-1598-5888-b1f5-74e8e90d38fc"
```
### Goal
Implement the specification without network or namespace policy.
### Core model
Define immutable objects such as:
```text
MasAddress
Target
OpaqueTarget
ResourceTarget
Facet
Interaction
RequiredProfile
```
Example:
```text
ticket=PR42+comments!callback
```
should parse to approximately:
```text
MasAddress
target:
ResourceTarget
type = ticket
id = PR42
facet = comments
interaction = callback
required_profile = P2
```
Critically:
```text
ticket!callback
```
must parse successfully in the maximal parser and report:
```text
required_profile = P2
```
The parser must not require knowledge of whether a particular namespace enables P2.
### Parser APIs
Recommended:
```python
parse_local_part(value) -> ParsedLocalPart
parse_address(value) -> ParsedAddress
validate_profile(parsed, profile) -> ValidationResult
```
Avoid coupling syntax parsing to statute policy.
### Property cases to add
Extend beyond the existing fixtures.
#### Length boundaries
Test:
```text
63 octets
64 octets
65 octets
```
The transport limit applies after encoding.
#### Additional `=`
Validate:
```text
ticket==PR42
```
as:
```text
resource_type = ticket
resource_id = =PR42
```
because only the first `=` is structural.
#### Reserved operators
Ensure:
```text
$
^
```
always fail canonical v0.1 parsing.
#### Registry independence
Ensure a registry key such as:
```text
support
```
is legal while:
```text
support+foo
```
is not interpreted as a registry key lookup for the full faceted address.
Registry lookup should operate on the base target.
### Exit criteria
- all existing fixtures pass;
- new property cases pass;
- parser performs zero I/O;
- parser does not infer person/actor/function kind.
---
## Milestone 2 — Statute model and linting
```task
id: MAS-WP-0002-T03
status: done
priority: high
state_hub_task_id: "90f803d5-9956-5a67-9100-629c5c1a1376"
```
### Goal
Make namespace semantics explicit and verifiable.
### Work
Implement statute loading and JSON Schema validation.
Add semantic validation beyond the schema.
Checks should include:
#### Namespace consistency
A statute fetched for:
```text
acme.coulomb.social
```
must declare:
```text
namespace = acme.coulomb.social
```
or fail with:
```text
NamespaceMismatch
```
#### P2 consistency
Reject or lint:
```text
profiles.p2 = false
```
together with enabled interaction modes.
#### Resource type validity
Resource type names must themselves satisfy MAS resource-type syntax.
#### Registry key validity
Explicit address registry keys must refer to base opaque targets only.
For v0.1, registry keys should not contain:
```text
+
!
$
^
```
#### Inheritance cycles
Detect:
```text
A → B → A
```
and longer cycles.
#### Child precedence
Where inheritance is supported:
```text
child overrides inherited defaults
```
Explicit address registry entries must not inherit.
### CLI
Implement:
```text
mas lint-statute FILE
```
Output should distinguish:
```text
schema error
semantic error
warning
```
### Exit criteria
A malformed but schema-valid statute can still be rejected by semantic linting.
---
## Milestone 3 — Exact-host discovery
```task
id: MAS-WP-0002-T04
status: done
priority: high
state_hub_task_id: "c220fde2-3f6f-5d32-9dd8-dfdadf2f636a"
```
### Goal
Resolve namespace metadata without contaminating parsing or policy.
### API
Recommended:
```python
discover(host) -> DiscoveryResult
```
with successful result:
```text
ValidatedStatute
```
and typed failures such as:
```text
NotFound
TransportFailure
InvalidContentType
SchemaInvalid
NamespaceMismatch
CrossHostRedirect
InheritanceCycle
UnsupportedVersion
```
### Redirect rule
Before adding caching, define redirect semantics precisely.
Initial rule:
> **Follow same-host HTTPS redirects only. Reject cross-host redirects.**
A redirect must not transfer MAS authority to another hostname.
Scheme downgrade to HTTP must be rejected.
### Parent domains
Never perform implicit lookup such as:
```text
acme.coulomb.social
→ coulomb.social
```
Inheritance occurs only through an explicit statute declaration.
### Caching
Add only minimal caching after behavior is correct.
Cache successful statutes separately from failures.
Do not let cache behavior hide typed discovery failures.
### Exit criteria
Discovery is deterministic enough to test against a local HTTP fixture server.
---
## Milestone 4 — Policy resolver
```task
id: MAS-WP-0002-T05
status: done
priority: high
state_hub_task_id: "940a1636-a0de-5697-8e8e-cb4181cf9b76"
```
### Goal
Combine syntax and validated metadata without network access.
### API
Conceptually:
```python
resolve(
parsed_address,
statute,
local_registry=None,
) -> AddressSemantics
```
Policy must remain pure.
### Resolution examples
With no statute:
```text
bernd.worsch@example.org
```
resolves only to syntactic information:
```text
target = bernd.worsch
kind = opaque
```
It must not become:
```text
kind = person
```
from punctuation.
With statute registry:
```text
addresses:
bernd.worsch:
kind: person
```
the resolver may produce:
```text
kind = person
```
For:
```text
ticket=PR42
```
and a statute declaring `ticket`:
```text
kind = resource
resource_type = ticket
resource_id = PR42
```
### Profile validation
For:
```text
ticket!callback
```
if statute says:
```text
p2 = false
```
policy should return a typed semantic failure such as:
```text
ProfileNotEnabled
```
The syntax remains valid.
### Exit criteria
The complete policy test suite runs with network disabled.
---
## Milestone 5 — `mas` CLI
```task
id: MAS-WP-0002-T06
status: done
priority: high
state_hub_task_id: "6aedba08-4220-599e-8ad3-01fa99cf3c16"
```
### Goal
Provide the main inspection surface for developers and operators.
### Commands
#### Parse
```text
mas parse ADDRESS
```
Shows syntax only.
#### Discover
```text
mas discover HOST
```
Shows validated statute or typed failure.
#### Explain
```text
mas explain ADDRESS
```
Shows three distinct layers:
```text
Syntax
Namespace discovery
Semantic resolution
```
Example failure:
```text
Address:
bernd.worsch@example.org
Syntax:
target: bernd.worsch
required profile: P1
Discovery:
no valid MAS statute found
Semantics:
kind: opaque
```
This is preferable to displaying a guessed “person”.
#### Lint statute
```text
mas lint-statute FILE
```
#### Run conformance suite
```text
mas test
```
### Exit criteria
A human can understand exactly why an address received its interpretation.
---
## Milestone 6 — Static statute deployment
```task
id: MAS-WP-0002-T07
status: done
priority: medium
state_hub_task_id: "bb1e8e08-83a8-5122-a556-26b3d7ac6017"
```
### Goal
Test real exact-host discovery.
Serve one validated static statute at:
```text
/.well-known/mas
```
No framework-specific statute server should be built yet.
The deployment should advertise only the features needed by the reference service.
Example:
```text
P1 = enabled
P2 = enabled
resource_types:
ticket
interaction_modes:
callback
```
### Exit criteria
`mas discover` retrieves the live/local test statute and validates namespace consistency.
---
## Milestone 7 — Generic mail-to-HTTP gateway
```task
id: MAS-WP-0002-T08
status: done
priority: medium
state_hub_task_id: "896df692-3b8d-50ea-bdee-262e4e4854b7"
```
### Goal
Bridge ordinary inbound mail into an application-neutral MAS event.
### Input
Either:
```text
SMTP
```
or:
```text
provider inbound webhook
```
Choose whichever produces the smallest reliable prototype.
### Gateway behavior
For each inbound recipient:
1. parse address;
2. discover statute;
3. resolve policy;
4. produce normalized event;
5. POST event to configured HTTP application endpoint.
Example event:
```json
{
"recipient": "ticket=GS-41872@example.org",
"mas": {
"profile": "P1",
"kind": "resource",
"resource_type": "ticket",
"resource_id": "GS-41872"
},
"message": {
"from": "customer@example.net",
"subject": "The problem happened again"
}
}
```
The gateway must not contain ticket-specific logic.
### Exit criteria
The same gateway could theoretically route another MAS resource type without code changes.
---
## Milestone 8 — Reference ticket service
```task
id: MAS-WP-0002-T09
status: done
priority: medium
state_hub_task_id: "35069786-a79f-5256-a8c9-a0637bcebd51"
```
### Goal
Prove the canonical lifecycle.
### Flow A — create
Customer sends:
```text
ticket!callback@great-service.example
```
The service:
1. receives a normalized MAS event;
2. verifies P2 is enabled;
3. creates ticket;
4. records callback as requested interaction mode;
5. generates resource address:
```text
ticket=GS-41872@great-service.example
```
6. replies using that resource address.
The subject does not require a ticket prefix.
---
### Flow B — correlate
Customer later sends or replies to:
```text
ticket=GS-41872@great-service.example
```
The service:
1. resolves resource type and id;
2. locates GS-41872;
3. associates the new message with that resource.
No subject-line parsing is required.
---
### Flow C — closed resource
Ticket GS-41872 is closed.
Mail later arrives at:
```text
ticket=GS-41872@great-service.example
```
The address remains valid.
The service must apply explicit lifecycle policy.
For the prototype, choose one behavior such as:
```text
archive message
+
return "ticket closed" response
```
It must not silently mutate or reopen the ticket.
---
### Flow D — unknown resource
Mail arrives at:
```text
ticket=DOES-NOT-EXIST@great-service.example
```
The service must handle this deliberately and without generating abusive backscatter.
---
## Milestone 9 — Experiment review
> Findings: `docs/experiment-review.md`. MTA half tested against real Postfix (`experiments/postfix-probe/`); provider half continues in MAS-WP-0003.
```task
id: MAS-WP-0002-T10
status: done
priority: medium
state_hub_task_id: "31bbfb56-5541-5ace-aff7-94ed6f1df57a"
```
### Goal
Decide whether MAS v0.1 survives contact with implementation.
Review:
#### Syntax
Did the parser remain simple?
#### Discovery
Was exact-host metadata sufficient?
#### Policy
Could all inference remain explicit?
#### Email infrastructure
Which characters or address forms were rewritten or rejected?
#### Resource addressing
Did resource addresses actually improve correlation?
#### Subject lines
Could application identifiers genuinely disappear from subjects?
#### Lifecycle
Did closed resources remain understandable?
#### Interaction
Was `!callback` useful or did it require more negotiation semantics?
#### Security
Did any address accidentally start behaving like a capability?
---
## Decision gate
Only after the reference experiment should the project decide whether to build:
```text
TypeScript implementation
Go implementation
Postfix/Exim integration
mail-client inspector
address composer
signed statutes
P3 economic profile
```
Each addition should answer a demonstrated need from the experiment.
**Decided 2026-10-18 (founder)** on the evidence of this workplan and
MAS-WP-0003 (`docs/experiment-review.md`, `docs/spec-change-proposals.md`):
- **Build:** the Postfix integration profile (MAS-WP-0004); spec v0.1.1
errata plus v0.2 drafts for SCP-6/SCP-7 (MAS-WP-0005); and the address
composer (MAS-WP-0006), pulled forward because provider forms refuse `=`
and lower-case addresses.
- **Defer:** the TypeScript and Go implementations, the mail-client
inspector, signed statutes, and the P3 economic profile. None of them
had a demonstrated need.
---
## Initial execution order
The shortest path is:
```text
1. mas-core parser/model
2. expanded conformance corpus
3. statute validator/linter
4. exact-host discovery
5. pure policy resolver
6. mas CLI
7. static statute
8. generic inbound gateway
9. reference ticket service
10. experiment review
```
The governing rule for this phase is:
> **One implementation, one lifecycle, one real email path.**