also looking at this
RFC 0006: classify every SHOULD and MAY in Protocol 1.0 Part I
#7
1 file
+174
-0
| @@ -0,0 +1,174 @@ | ||
| 1 | --- | |
| 2 | number: "0006" | |
| 3 | title: Classify every SHOULD and MAY statement in Protocol 1.0 Part I | |
| 4 | status: Draft | |
| 5 | authors: | |
| 6 | - chrisbbreuer | |
| 7 | sponsor: unassigned | |
| 8 | created: 2026-10-07 | |
| 9 | review-start: null | |
| 10 | review-end: null | |
| 11 | decision-date: null | |
| 12 | protocol-version: "1.0-draft" | |
| 13 | requires: | |
| 14 | - "0002" | |
| 15 | - "0004" | |
| 16 | supersedes: [] | |
| 17 | superseded-by: [] | |
| 18 | implementation-issues: | |
| 19 | - https://github.com/stacksjs/stacks/issues/2050 | |
| 20 | --- | |
| 21 | ||
| 22 | # Summary | |
| 23 | ||
| 24 | Every SHOULD, SHOULD NOT and MAY in Part I of the whitepaper becomes either a | |
| 25 | catalog requirement with a stable ID or an entry in a new `informative` list, | |
| 26 | each with a written reason. Six become SHOULD requirements, one is raised to | |
| 27 | the MUST that RFC 0004's report schema already enforces, and sixteen are | |
| 28 | recorded as informative. A SHOULD result is reported but never gates a profile. | |
| 29 | ||
| 30 | # Motivation | |
| 31 | ||
| 32 | Catalog revision 1 carries 47 requirements, all MUST or MUST NOT. Part I uses | |
| 33 | the RFC 2119 keywords 90 times: 55 MUST, 12 MUST NOT, 10 SHOULD, 1 SHOULD NOT | |
| 34 | and 12 MAY (white-paper `bun run normative`, which counts every keyword on a | |
| 35 | line since white-paper 086a4bf; it previously counted only the first and | |
| 36 | reported 65 uses and no SHOULD NOT). The 23 SHOULD/SHOULD NOT/MAY uses are | |
| 37 | neither catalogued nor marked informative, so the first acceptance criterion of | |
| 38 | stacksjs/stacks#2050 - "every normative statement is mapped to a stable ID or | |
| 39 | made informative" - cannot be met, and two conforming implementations can read | |
| 40 | the same SHOULD differently. | |
| 41 | ||
| 42 | One of them also contradicts the machine contract: Part I §16 says reports | |
| 43 | SHOULD link to CI logs and the exact suite revision, while RFC 0004's report | |
| 44 | schema already requires `execution.ci.runUrl`, `protocol.suiteVersion` and | |
| 45 | `protocol.rfcsRevision`. | |
| 46 | ||
| 47 | # Normative specification | |
| 48 | ||
| 49 | ## Result semantics for SHOULD | |
| 50 | ||
| 51 | A SHOULD or SHOULD NOT requirement is run and reported like any other, with the | |
| 52 | same `pass`, `fail`, `skipped`, `unsupported`, `exception` and `experimental` | |
| 53 | results. Its result never gates a profile claim: a profile is satisfied by its | |
| 54 | MUST and MUST NOT requirements alone. A report MUST still list every SHOULD | |
| 55 | requirement of the claimed profile with its result, so an unmet | |
| 56 | recommendation is visible rather than absent. `unsupported` is the expected | |
| 57 | result for a statically-typed-host SHOULD in a dynamic host, with its reason. | |
| 58 | ||
| 59 | ## New requirements | |
| 60 | ||
| 61 | | ID | Profile | Level | Area | Evidence | Statement | Part I | | |
| 62 | | --- | --- | --- | --- | --- | --- | --- | | |
| 63 | | `CORE-ROUTE-03` | Core | SHOULD | routing | behavior | Resource-route expansion and route parameter constraints are supported. | §4.1, line 412 | | |
| 64 | | `STD-GEN-01` | Standard | SHOULD | generation | inspection | A typed or schema-bearing Model definition drives at least one related artifact: migrations, validation, types, or an API description. | §2.2, line 290 | | |
| 65 | | `STD-TYPE-02` | Standard | SHOULD | types | inspection | In a statically typed host, a validation schema exposes an inferred type. | §4.3, line 448 | | |
| 66 | | `STD-TYPE-03` | Standard | SHOULD | types | inspection | In a statically typed host, configuration is checked against declared types. | §4.5, line 475 | | |
| 67 | | `STD-API-02` | Standard | SHOULD | api | behavior | A machine-readable description such as OpenAPI is generated from registered routes and schemas. | §4.8, line 516 | | |
| 68 | | `STD-QUEUE-02` | Standard | SHOULD | queue | behavior | Delayed dispatch and recurring schedules are supported. | §5.1, line 524 | | |
| 69 | ||
| 70 | `STD-API-02` sits below `COMP-API-01`, which already requires a generated | |
| 71 | description, when there is one, to be fresh and non-placeholder at Complete. | |
| 72 | Standard recommends generating one; Complete requires what is generated to be | |
| 73 | real. | |
| 74 | ||
| 75 | ## Raised to MUST | |
| 76 | ||
| 77 | | ID | Profile | Level | Area | Evidence | Statement | Part I | | |
| 78 | | --- | --- | --- | --- | --- | --- | --- | | |
| 79 | | `CORE-REPORT-01` | Core | MUST | reporting | inspection | A conformance report links its CI run and names the exact suite and RFC revisions it ran. | §16, line 1412 | | |
| 80 | ||
| 81 | This adds no obligation: RFC 0004's schema already rejects a report without | |
| 82 | those fields. The prose is aligned with the schema, and §16's bullet changes | |
| 83 | from SHOULD to MUST. A `reporting` source section pointing at §16 is added to | |
| 84 | `sourceSections`. | |
| 85 | ||
| 86 | ## Informative | |
| 87 | ||
| 88 | Each is recorded in a new `informative` array in the catalog, with the Part I | |
| 89 | line, the keyword, and the reason. Where a statement carries a condition, the | |
| 90 | condition's requirement is named, so the permission is informative and the | |
| 91 | constraint is not. | |
| 92 | ||
| 93 | | Part I | Keyword | Statement | Why informative | | |
| 94 | | --- | --- | --- | --- | | |
| 95 | | §2.1, line 259 | MAY | A Model MAY declare capabilities such as generated CRUD routes, search indexing, ... | Defines what a Model can contain; constrains nothing. | | |
| 96 | | §2.1, line 265 | MAY | A View MAY contain presentation logic | Defines what a View can contain. | | |
| 97 | | §2.1, line 265 | SHOULD NOT | A View SHOULD NOT own authorization, persistence, or multi-step business rules | Architecture guidance an outside observer cannot test. Its observable part, that rendering preserves authorization boundaries, is `COMP-VIEW-01`. | | |
| 98 | | §2.1, line 271 | MAY | An implementation MAY support inline handlers and controllers | A permission. | | |
| 99 | | §2.1, line 271 | SHOULD | Behavior reused across transports SHOULD live in an Action | Placement guidance; the observable part is `CORE-MVA-01`. | | |
| 100 | | §3.1, line 329 | MAY | Language-idiomatic casing or extensions MAY be used | A permission; the documented mapping it requires is `CORE-CONV-01`. | | |
| 101 | | §3.1, line 353 | MAY | Controllers, resources, policies, broadcasts and notifications MAY be additional roles | Defines optional roles. | | |
| 102 | | §3.3, line 368 | MAY | An implementation MAY ship default application behavior | A permission; the precedence it requires is `CORE-CONV-02`. | | |
| 103 | | §3.4, line 389 | MAY | Defaults MAY be overridden explicitly | A permission; override precedence is `CORE-CONFIG-01`. | | |
| 104 | | §4.1, line 412 | MAY | Action references MAY be strings, functions, objects or symbols | A permission; deterministic resolution is `CORE-ROUTE-01` and `CORE-CONV-03`. | | |
| 105 | | §4.2, line 433 | MAY | An implementation MAY combine internal phases | A permission; the preserved guarantees are `CORE-LIFE-01`. | | |
| 106 | | §5.3, line 542 | MAY | One notification channel MAY be database storage | Clarifies `COMP-NOTIFY-01`. | | |
| 107 | | §5.7, line 578 | MAY | Shape evidence MAY use the listed forms | Lists acceptable evidence for `STD-TYPE-01`. | | |
| 108 | | §5.8, line 591 | MAY | An implementation MAY report extension badges | Badges are governed by the catalog's `extensions` block. | | |
| 109 | | §15, line 1334 | SHOULD | The conformance suite SHOULD encode at least the following requirements | An obligation on the protocol project, not on implementations. Met by the catalog. | | |
| 110 | | §15, line 1366 | SHOULD | The protocol repository SHOULD publish fixtures, expected outputs and a runner-neutral description | An obligation on the protocol project. Met by stacksjs/protocol. | | |
| 111 | ||
| 112 | That is 16 keyword uses on 14 lines: lines 265 and 271 each permit one thing | |
| 113 | and recommend another in the same sentence. | |
| 114 | ||
| 115 | ## Traceability both ways | |
| 116 | ||
| 117 | Each catalog requirement gains an optional `sourceLines` array, and each | |
| 118 | `informative` entry carries its line. White-paper's `normative:check` then | |
| 119 | fails unless every keyword use in Part I is accounted for by exactly one | |
| 120 | requirement or informative entry, replacing the bare count it checks today. | |
| 121 | ||
| 122 | # Profiles and compatibility | |
| 123 | ||
| 124 | Behavioral, under RFC 0001: it adds SHOULD requirements and defines their | |
| 125 | result semantics. It adds no MUST that a conforming implementation can fail, | |
| 126 | since `CORE-REPORT-01` restates the report schema. No existing profile claim | |
| 127 | changes. | |
| 128 | ||
| 129 | # Conformance evidence | |
| 130 | ||
| 131 | - Fixtures for `CORE-ROUTE-03`, `STD-API-02` and `STD-QUEUE-02`, which are | |
| 132 | behavioral. The others are inspection, reported from the implementation's | |
| 133 | evidence. | |
| 134 | - Stacks evidence: resource routes and parameter constraints in its router; | |
| 135 | models driving migrations, validation and the OpenAPI document; `buddy | |
| 136 | generate:openapi`; typed config; delayed and scheduled jobs. | |
| 137 | - The catalog schema gains `informative` and `sourceLines`, and `check` | |
| 138 | validates that informative lines and requirement source lines do not overlap. | |
| 139 | ||
| 140 | # Migration and rollback | |
| 141 | ||
| 142 | Existing reports stay valid: SHOULD results are new entries, and the report | |
| 143 | schema is unchanged. An implementation adds the new SHOULD results the next | |
| 144 | time it runs the suite. Rolling back removes the seven entries and the | |
| 145 | `informative` array with no effect on any profile claim. | |
| 146 | ||
| 147 | # Security and privacy | |
| 148 | ||
| 149 | None of the new requirements touch a trust boundary. Classifying a SHOULD NOT | |
| 150 | as informative does not weaken security: the observable authorization | |
| 151 | boundary it describes is already the MUST `COMP-VIEW-01`. | |
| 152 | ||
| 153 | # Alternatives | |
| 154 | ||
| 155 | - **Every SHOULD becomes a requirement.** Lines 1334 and 1366 bind the protocol | |
| 156 | project, not implementations, and lines 265 and 271 cannot be observed from | |
| 157 | outside an implementation. | |
| 158 | - **SHOULD failures gate profiles.** That would make a SHOULD a MUST in all but | |
| 159 | name. | |
| 160 | - **Leave SHOULD and MAY uncatalogued.** That fails #2050's first acceptance | |
| 161 | criterion, and leaves the §16 prose contradicting the report schema. | |
| 162 | ||
| 163 | # Unresolved questions | |
| 164 | ||
| 165 | - Whether `STD-GEN-01` belongs at Core. A dynamic host may have no | |
| 166 | schema-bearing Model at all, which argues for Standard. | |
| 167 | - Whether the 55 MUST and 12 MUST NOT uses should get the same line-level | |
| 168 | traceability in this RFC or a follow-up. 67 keyword uses map onto 47 | |
| 169 | requirements, because a list's lead-in MUST covers its items; `sourceLines` | |
| 170 | makes that explicit. | |
| 171 | ||
| 172 | # Decision record | |
| 173 | ||
| 174 | Not yet reviewed. | |