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
915 lines
13 KiB
Markdown
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.**
|