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
462 lines
20 KiB
Markdown
462 lines
20 KiB
Markdown
---
|
|
id: MAS-WP-0005
|
|
type: workplan
|
|
title: "MAS spec v0.1.1 errata and v0.2 proposals"
|
|
domain: communication
|
|
repo: mail-address-semantics
|
|
status: finished
|
|
owner: claude
|
|
topic_slug: coulomb-social
|
|
created: "2026-10-18"
|
|
updated: "2026-10-18"
|
|
origin: residual
|
|
origin_ref: MAS-WP-0003
|
|
state_hub_workstream_id: "e9ae68c7-b960-51c0-b697-f05278384a82"
|
|
---
|
|
|
|
# MAS spec v0.1.1 errata and v0.2 proposals
|
|
|
|
Decision-gate outcome of MAS-WP-0002 (founder, 2026-10-18). Turn
|
|
`docs/spec-change-proposals.md` into spec text. The `mas-v0.1-spec/` bundle
|
|
is normative, and `mas_conformance/` plus `mas_core/schema/` are vendored
|
|
copies checked for drift, so each change updates the bundle, the vendored
|
|
copies, the fixtures and the implementation together.
|
|
|
|
## Review the proposals with the founder
|
|
|
|
```task
|
|
id: MAS-WP-0005-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "10c0433a-9b25-5b62-987f-2be7e9d49df2"
|
|
```
|
|
|
|
Walk through SCP-1 to SCP-7, settle the open options (SCP-2 (a) or (b),
|
|
SCP-6 split rules), and record which proposals are accepted.
|
|
|
|
- 2026-10-18: SCP-2 decided as option (a): resource types are lower-case
|
|
in the grammar. SCP-6 is under discussion. Founder direction: `=` stays
|
|
canonical and `--` is accepted as a replacement only for endpoints that
|
|
refuse `=`. A transform profile per recipient/destination may be needed
|
|
when something we send out must match that destination's requirements.
|
|
- 2026-10-18: SCP-6 decided. The statute opts in (option A) to
|
|
`alternate_separator`. The split is at the first `--` after a declared
|
|
type, and type names may not contain `--`. The sending side gets a
|
|
normative "destination transform" mechanism (`separator`, `lowercase`)
|
|
plus an informative integration section with IONOS as the example.
|
|
Concrete destination profiles live in implementation config, not the
|
|
spec. Still open: transforms beyond separator and case, to be added
|
|
only on evidence.
|
|
- 2026-10-18: SCP-6 extended at the founder's request to cover similar
|
|
cases. `alternate_syntax` holds `resource: "--"` and `interaction: "__"`
|
|
(split at the last `__`, only when the suffix is an enabled mode). There
|
|
is no stand-in for `+`. The closed transform set is resource-alternate,
|
|
interaction-alternate, lowercase, drop-facet and drop-interaction.
|
|
Quoting, dots and length need no transform.
|
|
- 2026-10-18: revised by the founder. Stand-ins use dashes only: `---`
|
|
replaces `__` for `!`, and no other stand-in characters are added. `+` is
|
|
functional by default with no stand-in. The stand-ins are now fixed by
|
|
the spec; the statute only enables them
|
|
(`alternate_syntax: {resource: true, interaction: true}`). Matching
|
|
order: interaction (`---MODE` at the end, enabled mode) first, then
|
|
resource (`TYPE--ID`). IDs must not contain `---` when the interaction
|
|
stand-in is enabled.
|
|
- 2026-10-18: SCP-1, SCP-3, SCP-5 and SCP-7 confirmed as written. All seven
|
|
proposals are accepted, so T01 is done. T02 implements the v0.1.1
|
|
errata (SCP-1, SCP-2 (a), SCP-3, SCP-5, and the SCP-7 recommendation);
|
|
T04 implements SCP-6 and the SCP-7 statute field for v0.2.
|
|
|
|
## v0.1.1 errata
|
|
|
|
```task
|
|
id: MAS-WP-0005-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "eb4c83d0-5b2c-5b7c-a6e3-57b85fe78334"
|
|
```
|
|
|
|
Apply the accepted errata: SCP-1 (quoted equivalence), SCP-2 (lower-case
|
|
types), SCP-3 (type intake, `intake_for`), SCP-5 (intake auto-reply
|
|
bounds), and the SCP-7 recommendation (case-robust identifiers). Add
|
|
fixtures and update the parser, policy and schema.
|
|
|
|
Decisions (founder, 2026-10-18): keep the folder `mas-v0.1-spec/` and mark
|
|
the revision v0.1.1 inside it (SPECIFICATION §1, README, new CHANGELOG).
|
|
For SCP-5, write the spec text now and track the DMARC-gated reply code as
|
|
its own task.
|
|
|
|
- 2026-10-18 SCP-2 done:
|
|
- grammar `resource-type = type-word *(("-" / "_") type-word)`;
|
|
- statute schema key pattern `^[a-z0-9]+([_-][a-z0-9]+)*$` (bundle and
|
|
vendored copy);
|
|
- `mas_core.parser.is_resource_type`, also used by statute lint;
|
|
- the bundle's reference parser;
|
|
- §6.1 text and the CHANGELOG;
|
|
- fixtures p1-042 to p1-045, and prop-case-001 flipped to invalid.
|
|
|
|
141 tests pass, and the reference parser agrees with all 35 bundle
|
|
fixtures. SCP-2 text corrected: `Ticket=PR42` becomes non-canonical,
|
|
not opaque.
|
|
- 2026-10-18 SCP-1 done: §4 text; `mas_core.parser.unquote_local_part` and
|
|
`parse_received_address` (receiver side; the canonical parser stays
|
|
strict); the gateway now parses with them; fixture p1-040 note and
|
|
CHANGELOG. The end-to-end test now uses a real non-MAS recipient,
|
|
because `"quoted"@` is equivalent to `quoted@`. 148 tests pass.
|
|
- 2026-10-18 SCP-3 done:
|
|
- §7 text and the CHANGELOG;
|
|
- statute schema `addresses.*.intake_for`, with the resource-type
|
|
pattern (bundle and vendored copy);
|
|
- lint `intake-not-function` (error) and `intake-unknown-type` (error,
|
|
or warning when the statute inherits);
|
|
- the policy reports `intake_for`, and it reaches gateway events;
|
|
- the ticket service creates tickets only for
|
|
`intake_for == "ticket"`, not for a hard-coded target name;
|
|
- example statutes (great-service, mas.coulomb.social) and the
|
|
conformance statute declare the intake.
|
|
|
|
151 tests pass. The live statute needs a redeploy to carry
|
|
`intake_for`; until then the new ticket service would not recognise
|
|
the intake.
|
|
- 2026-10-18 SCP-5 (§14 item 10) and SCP-7 (§6.2 recommendation) spec text
|
|
done. The reference service already meets the SCP-5 MUSTs (cap, no
|
|
replies to automated mail); the SHOULD (authenticated sender) is T05.
|
|
CHANGELOG marked v0.1.1. T02 done.
|
|
|
|
## Reference service: case-robust ticket ids
|
|
|
|
```task
|
|
id: MAS-WP-0005-T03
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "7c19e951-7ab4-580c-9e4c-9fead9ee946e"
|
|
```
|
|
|
|
SCP-7 evidence: IONOS and Google Groups both lower-cased the recipient,
|
|
and a list post was lost to its ticket. Make the reference ticket service
|
|
issue and match ids case-insensitively. Crockford base32 is case-insensitive
|
|
by design. Verify on the live MX by repeating the Google Groups post.
|
|
|
|
- 2026-10-18: implemented. Ticket lookup uses `COLLATE NOCASE` (also in the
|
|
`ticket()`/`close()` admin calls). Once found, the service stores,
|
|
replies and reports under the id as issued, so replies keep coming From
|
|
`ticket=GS-…@`. Test `test_lower_cased_id_correlates` passes, as do all
|
|
137 tests. Deployed as `mas-live:wp0005-20261018`. A dry check on a copy
|
|
of the live DB resolves `gs-85qj8wc09p` to `GS-85QJ8WC09P`.
|
|
- 2026-10-18 15:38Z: verified live. A Google Groups post arrived for
|
|
`ticket=gs-85qj8wc09p+comments@` and was **correlated** (200) to
|
|
GS-85QJ8WC09P with facet `comments`. The identical post at 12:05Z had
|
|
been quarantined. No reply was sent (Precedence: list); still 1/300
|
|
sent.
|
|
|
|
## v0.2 drafts: SCP-6 and the SCP-7 statute field
|
|
|
|
```task
|
|
id: MAS-WP-0005-T04
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "4ff67908-52c4-5106-b851-e1dec8274226"
|
|
```
|
|
|
|
Draft the statute object `alternate_syntax` (enables the fixed stand-ins
|
|
`--` for `=` and `---` for `!`),
|
|
the destination transforms (see SCP-6), and
|
|
`equivalence.resource_id_case`, with policy semantics and fixtures.
|
|
|
|
Split into T07 to T10 on 2026-10-18 (token budget). Stand-in recognition
|
|
lives in the policy layer, not the parser: the parser stays statute-blind,
|
|
and only a statute that enables the stand-ins gives `--`/`---` meaning.
|
|
v0.2 is a separate draft bundle `mas-v0.2-spec/`, because it adds features
|
|
rather than errata.
|
|
|
|
## SCP-5: reply only to authenticated senders
|
|
|
|
```task
|
|
id: MAS-WP-0005-T05
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "8d3bc09e-6f8d-5125-b10c-45b9aa5643a2"
|
|
```
|
|
|
|
Implement the SHOULD part of spec §14 item 10 in the reference stack:
|
|
- Postfix adds `Authentication-Results` (e.g. via OpenDMARC or rspamd
|
|
milter) on the live MX;
|
|
- `mas-gateway` passes the DMARC verdict into the event (event schema
|
|
addition);
|
|
- the ticket service sends intake auto-replies only on DMARC pass and
|
|
records unauthenticated requests without replying.
|
|
|
|
Decided 2026-10-18 to keep this out of the v0.1.1 errata code.
|
|
|
|
Split 2026-10-18 into T11 to T13. Authentication runs in the MTA
|
|
(OpenDKIM + OpenDMARC milters), because SPF, DKIM and DMARC need DNS and
|
|
only `mas_core/discovery.py` may touch the network. The gateway only
|
|
reads the `Authentication-Results` header carrying our own authserv-id,
|
|
and the MTA strips incoming headers that claim it.
|
|
|
|
## Redeploy the live MX with v0.1.1
|
|
|
|
```task
|
|
id: MAS-WP-0005-T06
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "f9bbfc03-e611-573f-8017-91cd18472ba9"
|
|
```
|
|
|
|
Build and deploy an image with the v0.1.1 parser, the `intake_for`
|
|
statute and the case-insensitive ticket service. Then re-run a smoke test
|
|
(intake create, resource correlate, lower-case correlate).
|
|
|
|
- 2026-10-18: before the deploy, the ticket service was changed to issue
|
|
lower-case ids (`gs-` + lower-case Crockford base32), at the founder's
|
|
request after a reply showed `ticket=GS-6KDSB1BA11@`. Existing upper-case
|
|
tickets still match. Deployed `mas-live:v0.1.1-f78939a`. The live statute
|
|
serves `intake_for: "ticket"`, `mas discover` is valid, `--max-sent 300`
|
|
and the TEM relay are intact, and EHLO answers 250. `mas explain` now
|
|
shows `intake_for`.
|
|
- 2026-10-18 smoke test (founder, Gmail):
|
|
- `ticket!callback@` (16:34Z) created ticket `gs-8b72wz9tye` via
|
|
`intake_for`, and the reply was sent through TEM;
|
|
- the answer to `ticket=gs-8b72wz9tye@` was correlated (In-Reply-To
|
|
set);
|
|
- `ticket=GS-8B72WZ9TYE@` (20:14Z) arrived upper-case, because Gmail does
|
|
not fold, and was correlated to the same ticket;
|
|
- two typo sends to `ticket=GW-8B72WZ9TYE@` (Gmail autocomplete) were
|
|
quarantined with no reply.
|
|
|
|
Sends: 3/300. Done.
|
|
|
|
## v0.2 draft bundle and version support
|
|
|
|
```task
|
|
id: MAS-WP-0005-T07
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "908688e6-559b-5d44-a8bc-284e3bbc9366"
|
|
```
|
|
|
|
Create `mas-v0.2-spec/` (draft): the specification with SCP-6
|
|
(`alternate_syntax`, matching order, destination transforms, informative
|
|
integration section) and the SCP-7 statute field
|
|
`equivalence.resource_id_case`, the v0.2 statute schema, and a CHANGELOG.
|
|
`mas_core` accepts statutes with `mas_version` 0.1 and 0.2, each validated
|
|
against its own schema. Discovery accepts both.
|
|
|
|
- 2026-10-18 done:
|
|
- `mas-v0.2-spec/` draft: §6.3 stand-ins with the matching order, §8
|
|
`resource_id_case`, §11 fields, §12.1 destination transforms, §12.2
|
|
informative integrations (IONOS, Google Groups), and §13 length after
|
|
transforms;
|
|
- schema v0.2 (`mas_version` 0.2, `alternate_syntax`,
|
|
`equivalence.resource_id_case`), an example statute and the CHANGELOG.
|
|
The grammar is unchanged; stand-ins are not canonical syntax.
|
|
- `mas_core`: one schema validator per version (`SUPPORTED_VERSIONS`);
|
|
`Statute` carries `mas_version`, `alt_resource`, `alt_interaction`
|
|
and `resource_id_case`; inheritance uses `dataclasses.replace`;
|
|
discovery accepts 0.1 and 0.2.
|
|
- Tests that used 0.2 as the "unsupported" example now use 0.3. 155
|
|
tests pass.
|
|
- The draft keeps 25 "v0.1" mentions for rules that are unchanged; align
|
|
the wording when v0.2 is finalized.
|
|
|
|
## v0.2 receiving side: stand-ins and resource_id_case in policy
|
|
|
|
```task
|
|
id: MAS-WP-0005-T08
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "a345e073-04ca-54e1-bac7-837fe7955e4e"
|
|
```
|
|
|
|
The policy interprets `---MODE` (interaction first, enabled mode only) and
|
|
`TYPE--ID` (declared type only) when the statute enables them, and applies
|
|
`resource_id_case: insensitive` in the equivalence key. Statute lint covers
|
|
the stand-in constraints. Statute-aware fixtures.
|
|
|
|
- 2026-10-18 done:
|
|
- `mas_core.policy.apply_stand_ins` runs first in `resolve()`. It
|
|
matches the interaction (`---MODE`, enabled mode, last `---`; in the
|
|
facet or the target) and then the resource (`TYPE--ID`, declared type,
|
|
first `--`). Everything later (classification, registry,
|
|
`intake_for`, equivalence) sees the canonical parse, and the parser
|
|
stays statute-blind.
|
|
- `AddressSemantics` gains `stand_ins` and `canonical_local_part`; the
|
|
equivalence key lower-cases resource ids under
|
|
`resource_id_case: insensitive`.
|
|
- The gateway event reports the canonical target and base, plus
|
|
`target_syntax: resource-alternate` when `--` was used, while
|
|
`local_part` keeps what arrived.
|
|
- Lint: `stand-in-collision` (registry keys that would change meaning),
|
|
`stand-in-mode-name`, and `stand-in-without-p2` (warning).
|
|
- Tests: the spec §6.3 example table, correlation of
|
|
`ticket--GS-…+comments` with `ticket=gs-…`, intake via `---`, the
|
|
switch requirement (v0.1, off, no statute), exact id case, and lint.
|
|
168 tests pass.
|
|
- A v0.2 statute for mas.coulomb.social lints clean, and the gateway
|
|
turns `ticket--gs-85qj8wc09p+comments@` into resource
|
|
`ticket=gs-85qj8wc09p` with facet `comments`.
|
|
|
|
## v0.2 sending side: destination transforms in the generator
|
|
|
|
```task
|
|
id: MAS-WP-0005-T09
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "853d1b76-8b7f-5234-aacc-dc1fb5d155c2"
|
|
```
|
|
|
|
Add a generator `destination` parameter with the five transforms. Emit the
|
|
canonical form when allowed; refuse when the namespace would not accept the
|
|
result; re-check the length after transforms. Include an example destination
|
|
profile `ionos-forward`. This is the base for the composer (MAS-WP-0006).
|
|
|
|
- 2026-10-18 done: `mas_core.generator.for_destination(local_part, statute,
|
|
needs, allow_lossy=False)` returns `DestinationAddress(local_part, applied,
|
|
warnings)`.
|
|
- It applies only the transforms that change something.
|
|
- Lossy transforms need `allow_lossy`; `drop-interaction` adds a warning.
|
|
- Refusals raise `CannotExpress`: `transform-not-permitted` (statute
|
|
switch off, or a v0.1 statute), `cannot-express` (id contains `=`),
|
|
`too-long` (after transforms) and `would-be-misread`.
|
|
- Safety is a round trip: the result is resolved with the receiving
|
|
policy and must give the same equivalence key, facet and interaction.
|
|
This catches lower-casing under `resource_id_case: exact` and case
|
|
changes in facets.
|
|
- Example profiles: `canonical`, `ionos-forward` (resource-alternate +
|
|
lowercase), `google-groups` (lowercase).
|
|
- 11 new tests; 179 pass.
|
|
- Correction: there is no `mas generate` CLI command. The review's gate
|
|
table and MAS-WP-0006 now point to `for_destination`; the CLI/UI is
|
|
MAS-WP-0006.
|
|
|
|
## v0.2 live check: IONOS forward with stand-ins
|
|
|
|
```task
|
|
id: MAS-WP-0005-T10
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "6431ae1e-c449-5732-a40f-99b0644da44a"
|
|
```
|
|
|
|
Switch `mas.coulomb.social` to a v0.2 statute that enables both stand-ins
|
|
and case-insensitive ids. Repeat the IONOS forward test with
|
|
`ticket--gs-…+comments@`. It must now be correlated to the ticket.
|
|
|
|
- 2026-10-18 done. The live statute is v0.2 (`alternate_syntax`
|
|
resource+interaction, `resource_id_case: insensitive`), deployed as image
|
|
`mas-live:v0.2-51bf87c`. The operator sent to `mas-fwd@coulomb.social`
|
|
(IONOS forward, unchanged since MAS-WP-0003). It arrived at 20:29:57Z
|
|
for `ticket--gs-85qj8wc09p+comments@` (envelope sender SRS0 from IONOS)
|
|
and was read as `ticket=gs-85qj8wc09p+comments`
|
|
(`target_syntax: resource-alternate`). It was **correlated** (200) to
|
|
GS-85QJ8WC09P with facet `comments`; in MAS-WP-0003 the same forward was
|
|
404 not-handled. The ticket now holds mail via all four paths: direct,
|
|
reply, Google Groups (lower-cased) and IONOS forward (stand-in). T04 is
|
|
complete. `mas explain` also shows "read as … (v0.2 stand-in)".
|
|
|
|
## MTA authentication: OpenDKIM + OpenDMARC milters
|
|
|
|
```task
|
|
id: MAS-WP-0005-T11
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "5c4eddfd-a371-59d2-a4f1-3915a675f639"
|
|
```
|
|
|
|
In the live image, OpenDKIM (verify only) and OpenDMARC (SPF
|
|
self-validation) run as Postfix smtpd milters. Both add
|
|
`Authentication-Results: mas.coulomb.social; …`. Incoming A-R headers
|
|
claiming that authserv-id are removed (`RemoveARFrom`). Annotate only;
|
|
never reject on DMARC failure. Milter failure means accept
|
|
(`milter_default_action = accept`).
|
|
|
|
- 2026-10-18 done (verified in a local container; live in T13):
|
|
- Image packages: opendkim, opendmarc, publicsuffix. OpenDKIM runs in
|
|
verify mode; OpenDMARC with `SPFSelfValidate`, `RejectFailures false`
|
|
and `TrustedAuthservIDs` set to the domain.
|
|
- **Forged A-R stripping is done by Postfix, not OpenDKIM.**
|
|
`RemoveARFrom` and `RemoveARAll` did not remove forged
|
|
`Authentication-Results: mas.coulomb.social; dmarc=pass` headers. A
|
|
`header_checks` regexp IGNORE rule does, and it leaves the milters'
|
|
own headers alone, because header_checks do not apply to
|
|
milter-added headers. Verified for a forged pass, an upper-case
|
|
variant and a foreign id (foreign ids are kept; the gateway ignores
|
|
them).
|
|
- Daemonized, OpenDKIM died on its first connection ("can't read
|
|
SMFIC_OPTNEG reply"), so both milters now run with `-f` in the
|
|
background.
|
|
- Result for a spoofed `From: test@coulomb.social` sent directly:
|
|
`spf=fail`, `dmarc=fail (p=none)`. Our A-R headers sit above our
|
|
`Received:` line; anything forged sits below it.
|
|
- Note for MAS-WP-0004: use header_checks for A-R stripping and
|
|
foreground milters.
|
|
|
|
## Gateway verdict and reply gating
|
|
|
|
```task
|
|
id: MAS-WP-0005-T12
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "5a3b7356-37c0-5292-8936-492946c6b211"
|
|
```
|
|
|
|
`mas-gateway` takes `--trusted-authserv-id`. It parses only A-R headers
|
|
from that id and puts `message.authentication = {dmarc, spf, dkim,
|
|
header_from}` into the event. The ticket service gets
|
|
`--require-dmarc-pass`: it still creates tickets and attaches mail, but
|
|
sends auto-replies (intake confirmation, closed notice) only when
|
|
`dmarc == pass`. Unit tests cover forged A-R headers from other ids.
|
|
|
|
- 2026-10-18 done:
|
|
- `mas_gateway.core.authentication_from_headers` reads only A-R headers
|
|
with the trusted authserv-id **above the first Received header**
|
|
(RFC 8601 §5). Forged copies below our hop are ignored even if the
|
|
MTA did not strip them. Several DKIM results count as pass if any one
|
|
passes.
|
|
- The event gets `message.authentication = {dmarc, spf, dkim,
|
|
header_from}` or null. `--trusted-authserv-id` works on both pipe and
|
|
webhook; a JSON webhook passes the provider's verdict through.
|
|
- Ticket service `--require-dmarc-pass`: tickets are still created and
|
|
mail attached, but replies go out only on `dmarc == pass`.
|
|
- Entrypoint: gateway `--trusted-authserv-id $DOMAIN`, ticket service
|
|
`--require-dmarc-pass`.
|
|
- Tests: own header read; forged (below Received) and foreign ids
|
|
ignored; no trusted id gives no verdict; reply gated off without a
|
|
verdict and sent on pass. 183 tests pass.
|
|
|
|
## Live check: authenticated vs forged sender
|
|
|
|
```task
|
|
id: MAS-WP-0005-T13
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "8a1f1fc4-f300-5e60-8714-5a47c39d88a1"
|
|
```
|
|
|
|
Deploy. A Gmail intake (DMARC pass) gets a reply. A mail with a
|
|
`From:` in the operator's own domain sent directly from the workstation
|
|
(SPF/DKIM fail, so DMARC fail) creates a ticket but gets no reply. Check
|
|
the send counter.
|
|
|
|
- 2026-10-18 done (image `mas-live:v0.2-a45f1a1`; both milters listening,
|
|
gateway `--trusted-authserv-id`, ticket service `--require-dmarc-pass`):
|
|
- **Forged:** sent from the workstation with `From: test@coulomb.social`
|
|
and a forged `Authentication-Results: mas.coulomb.social; dmarc=pass`.
|
|
The event verdict was `dmarc: fail, spf: fail`: the forgery was
|
|
stripped and the real verdict used. Ticket `gs-mt1hcg3tae` was created
|
|
and **no reply** sent (no outbox row; sends stayed at 3/300).
|
|
- **Gmail (founder):** the verdict was `dkim: pass, spf: pass,
|
|
dmarc: pass` (header.from gmail.com), the first live DKIM verification
|
|
by OpenDKIM. Ticket `gs-rcce2nne4k` was created and the reply sent
|
|
through TEM (sends 4/300).
|
|
- T05 is complete. The reference stack now meets all of spec §14
|
|
item 10.
|
|
|
|
## Residuals
|
|
|
|
Handed off as live work records (origin: residual, origin_ref MAS-WP-0005):
|
|
- MAS-WP-0008: finalize v0.2 (wording pass, bundle conformance cases for
|
|
v0.2, release decision).
|
|
- MAS-WP-0004 (existing) carries the milter/header_checks lessons for the
|
|
Postfix profile; MAS-WP-0006 (existing) builds on
|
|
`generator.for_destination`.
|
|
|