diff --git a/docs/spec-change-proposals.md b/docs/spec-change-proposals.md index 1413a99..ac18867 100644 --- a/docs/spec-change-proposals.md +++ b/docs/spec-change-proposals.md @@ -143,7 +143,7 @@ event-schema addition. --- -## SCP-6: statute-declared alternate resource separator (`--` for `=`) +## SCP-6: statute-declared stand-ins and destination transforms (`--` for `=`, `__` for `!`) **Sections:** §6 Resource semantics, §11 Statute document, §12. @@ -160,38 +160,66 @@ correctly could not attach it to the ticket. integrations are done through the statute when needed. Concrete integrations are not part of the normative text. -**Proposal, receiving side (normative):** a statute MAY declare an -alternate separator for resource targets: +- Similar endpoint behaviours are covered in the same mechanism: a stand-in + for `!`, plus case, facet, interaction, quoting, dot and length handling + (founder confirmed, 2026-10-18). + +**Proposal, receiving side (normative):** a statute MAY declare stand-ins +for MAS operators: ```json -"resource_syntax": { "alternate_separator": "--" } +"alternate_syntax": { "resource": "--", "interaction": "__" } ``` -- When it is declared, a target `TYPE--ID`, where `TYPE` is a resource type - declared in the same statute, is equivalent to `TYPE=ID`. The policy - resolver reports `target_syntax: "resource-alternate"` and the canonical - equivalence key `TYPE=ID`. Receivers store, correlate and reply using the - canonical form only. -- **Split rule:** together with SCP-2, resource-type names are lower-case - letters and digits with single hyphens and never contain `--`. The first - `--` therefore always ends the type: `ticket--RE--2026` is type `ticket`, - ID `RE--2026`. IDs may contain `--`, just as they may contain `=`. -- Only a declared type triggers the split. Without the declaration, or - with an undeclared type, `--` has no meaning (§6.1 still applies). -- The separator must be dot-atom-safe and must not contain `.` or `=`. A - namespace whose existing opaque names start with `TYPE--` must not - declare it. +- **Resource stand-in (`--` for `=`).** A target `TYPE--ID`, where `TYPE` is + a resource type declared in the same statute, is equivalent to + `TYPE=ID`. The policy resolver reports `target_syntax: + "resource-alternate"` and the canonical equivalence key `TYPE=ID`. +- **Interaction stand-in (`__` for `!`).** A local-part ending in + `__MODE`, where `MODE` is an interaction mode the statute enables, is + equivalent to `!MODE`: `ticket__callback` ≡ `ticket!callback`. The split + is at the **last** `__`, and only if the suffix is an enabled mode. + Anything else (`foo__bar` with no enabled mode `bar`) stays plain data. +- **No stand-in for `+`.** Every endpoint tested accepted `+`, and facets + already degrade safely when stripped (§12). Generators use the + `drop-facet` transform instead. +- **Split rule for types:** together with SCP-2, resource-type names are + lower-case letters and digits with single `-` or `_` separators. They + never contain `--` or `__`. The first `--` after the type always ends + it: `ticket--RE--2026` is type `ticket`, ID `RE--2026`. IDs may contain + `--`. +- Each stand-in applies only if the statute declares it, and the resource + stand-in only for a declared type. Otherwise `--` and `__` have no + meaning (§6.1 still applies). +- Receivers store, correlate and reply using the canonical form only. +- Stand-ins must be dot-atom-safe, must not contain `.`, `=`, `+` or `!`, + and must differ from each other. A namespace with existing opaque names + that match a stand-in pattern must not declare it. **Proposal, sending side (normative mechanism, informative integrations):** generators produce addresses for a *destination*, such as a forwarding form, a mailing list or a reply header. The spec defines a **destination transform**, the set of changes a generator may apply so that an address -fits a destination's constraints. For v0.1/v0.2 there are two: +fits a destination's constraints. The set is closed and covers the +endpoint behaviours seen or expected: -| Transform | Effect | Allowed only if the namespace's statute | +| Transform | Effect | Allowed only if | |---|---|---| -| `separator` | `TYPE=ID` → `TYPEID` | declares `alternate_separator` | -| `lowercase` | fold the whole local-part to lower case | declares case-insensitive identifiers (SCP-7) and lower-case types (SCP-2) | +| `resource-alternate` | `TYPE=ID` → `TYPE--ID` | statute declares `alternate_syntax.resource` | +| `interaction-alternate` | `!MODE` → `__MODE` | statute declares `alternate_syntax.interaction` and enables `MODE` | +| `lowercase` | fold the whole local-part to lower case | statute declares case-insensitive identifiers (SCP-7); types are lower-case (SCP-2) | +| `drop-facet` | remove `+FACET` (loses information) | always; only when explicitly requested | +| `drop-interaction` | remove `!MODE` (loses the requested mode; the mail still reaches intake) | always; only when explicitly requested, with a warning | + +Endpoint behaviours that need no transform: +- **Quoting:** generators never quote, and receivers treat quoted and + unquoted forms as equal (SCP-1). +- **Dots:** generators never insert dots. Dot handling is statute dot + folding (§8). +- **Length:** after all transforms, the 64-octet limit is checked again + (each stand-in adds one octet). A generator MUST refuse rather than + truncate. +- **`$` and `^`:** remain reserved; P3 is out of scope. A generator MUST emit the canonical form when the destination allows it. It MAY apply the transforms the destination needs, and only those the @@ -209,17 +237,14 @@ the procedure: generator's configuration. It uses IONOS forwarding as the worked example: `=` is refused and case is -folded, so the profile is `separator` + `lowercase`, and the result is +folded, so the profile is `resource-alternate` + `lowercase`, and the +result is `ticket--gs-85qj8wc09p+comments@`. Concrete profiles (e.g. `ionos-forward`) live in implementation configuration or a catalog, not in the spec. -**Open:** whether transforms beyond separator and case are needed, for -example for `!`. No endpoint has refused `!` so far, but none was tested -with it. Leave the transform list closed in v0.2 and extend it only on -evidence. - -**Impact:** additive: an optional schema field, a policy change, a -generator `destination` parameter, and new fixtures. Targets v0.2. The +**Impact:** additive: an optional schema object (`alternate_syntax`), +parser and policy support for both stand-ins, a generator `destination` +parameter with the five transforms, and new fixtures. Targets v0.2. The composer (MAS-WP-0006) is the first consumer of destination profiles. --- diff --git a/workplans/MAS-WP-0005-spec-errata-v0-1-1.md b/workplans/MAS-WP-0005-spec-errata-v0-1-1.md index 5397891..f840dd2 100644 --- a/workplans/MAS-WP-0005-spec-errata-v0-1-1.md +++ b/workplans/MAS-WP-0005-spec-errata-v0-1-1.md @@ -46,8 +46,15 @@ SCP-6 split rules), and record which proposals are accepted. 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. Remaining T01 items: confirm SCP-1, SCP-3, SCP-5 and - SCP-7 as written. + 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. Type names may not contain + `--` or `__`. Remaining T01 items: confirm SCP-1, SCP-3, SCP-5 and SCP-7 + as written. ## v0.1.1 errata @@ -98,6 +105,6 @@ priority: medium state_hub_task_id: "4ff67908-52c4-5106-b851-e1dec8274226" ``` -Draft the statute fields `resource_syntax.alternate_separator` (`--` for -`=`, endorsed by the operator after the IONOS refusal) and +Draft the statute object `alternate_syntax` (`--` for `=`, `__` for `!`), +the destination transforms (see SCP-6), and `equivalence.resource_id_case`, with policy semantics and fixtures.