rttp 1.2.8__tar.gz → 1.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,238 +1,287 @@
1
- # Changelog -- `rttp` (Python)
2
-
3
- All notable changes to the `rttp` package. Format follows
4
- [Keep a Changelog](https://keepachangelog.com/); versioning is
5
- [Semantic Versioning](https://semver.org/).
6
-
7
- ---
8
-
9
- ## [1.2.8] -- 2026-09-21
10
-
11
- **Version-only re-publish.** The code, the vector file and every self-test result
12
- are identical to `1.2.7`; only the version string moves, so the final PyPI release
13
- carries the stack number. `1.2.7` stays installable -- pin `1.2.8` for new work.
14
-
15
- * No wire-format, URI-grammar, public-API or vector change.
16
- * `python -m rttp.selftest` still reports 83 checks in full, and 80 passed with
17
- 3 skipped on a zero-dependency install.
18
-
19
- ## [1.2.7] -- 2026-09-21
20
-
21
- **Conformance surface grown; wire format untouched.** The shipped
22
- `rttp/vectors/rttp-conformance-v1.2.6.json` is now 13,460 bytes
23
- (`sha256 4b743e63...`) and the self-test replays every added case: **83 checks**
24
- in full, and **80 passed with 3 skipped** on a zero-dependency install -- a check
25
- that cannot be performed is reported as skipped, never as passed.
26
-
27
- ### Added
28
-
29
- * **Nine fail-closed frame cases, one positive frame.** Each of the nine frames
30
- must be rejected; the positive frame must be accepted with an empty action.
31
- * **The published Ed25519 envelope vector**, replayed three ways: the canonical
32
- signing input byte for byte, `AID == SHA-256(public key)`, and the signature
33
- itself (the third one skips without the optional primitive).
34
-
35
- ### Changed
36
-
37
- * **Skipped checks are now counted and printed**, so a default install can no
38
- longer look like a full pass.
39
- * Per-section counts are reported: 38 conformance, 16 envelope rules, 22 envelope
40
- flow, 2 RFC 8032, 5 zero-dependency.
41
-
42
- ### Note
43
-
44
- * PyPI and npm carry `1.2.7`; crates.io carries the same code as the pre-release
45
- `1.2.8-alpha`. The registry version strings differ by publishing policy, not by
46
- code -- the vectors and their `sha256` are identical everywhere.
47
-
48
- ## [1.2.6] -- 2026-09-19
49
-
50
- **Version alignment -- no code change.** Every module, byte layout and
51
- conformance vector is identical to 0.1.2, and the self-test still reports the
52
- the same 53 checks (full set, i.e. with the optional Ed25519 backend). Only the version string and the maturity classifier change.
53
-
54
- ### Changed
55
-
56
- * **The version number now mirrors the stack version.** PyPI and npm carry
57
- `1.2.6`, so a single number identifies this code on every distribution
58
- channel; crates.io carries the same code as the pre-release `1.2.6-alpha`.
59
- The old `0.1.x` line was a package-maturity number that corresponded to
60
- nothing in the specification, and it made the same package look like two
61
- different releases on two registries.
62
- * **`Development Status` classifier: `3 - Alpha` -> `4 - Beta`.** A
63
- non-pre-release version must not ship with an "Alpha" classifier; leaving
64
- the two in conflict invites the question "which one is true?".
65
- * Install command note: on crates.io every published version of this crate is
66
- a pre-release, so Cargo will not select it from a plain `rttp` requirement.
67
- Write `cargo add rttp@1.2.6-alpha` (or pin `rttp = "1.2.6-alpha"`).
68
-
69
- ## [0.1.2] -- 2026-09-18
70
-
71
- **Metadata correction -- no code change.** Every module, byte layout and
72
- conformance vector is identical to 0.1.1, and the self-test still reports the
73
- the same 53 checks (full set, i.e. with the optional Ed25519 backend).
74
-
75
- ### Fixed
76
-
77
- * **The distribution identity now matches the IANA registration.** The package
78
- was authored as `RTTP Working Group` -- a name that appears in no filing. The
79
- `rttp` URI-scheme registration on file with IANA (ticket `[IANA #1459939]`)
80
- names **`RTTP.COM Organization`** as the `Author/Change controller`, and every
81
- other public surface uses that same name. Both package manifests now say it
82
- too:
83
-
84
- | Field | Before | After |
85
- |:---|:---|:---|
86
- | `pyproject.toml` -> `authors` (PyPI) | `RTTP Working Group` | **`RTTP.COM Organization`** |
87
- | `package.json` -> `author` (npm) | `RTTP Working Group` | **`RTTP.COM Organization`** |
88
-
89
- Package metadata cannot be edited after publication, so 0.1.0 and 0.1.1 keep
90
- the old string inside their own metadata; this is the version that carries the
91
- correction. Project pages display the latest version, so the visible author
92
- name becomes correct once this release is out.
93
-
94
- ## [0.1.1] -- 2026-09-18
95
-
96
- **Documentation only -- no code change.** Every module, byte layout and
97
- conformance vector is identical to 0.1.0, and the self-test still reports the
98
- the same 53 checks (full set, i.e. with the optional Ed25519 backend).
99
-
100
- ### Fixed
101
-
102
- * **A distribution claim that was wrong, not merely outdated.** The 0.1.0 entry
103
- below said the JavaScript side "will publish under the `@rttp` scope". That
104
- scope **cannot be created at all**: npm already has a personal account named
105
- `rttp`, and an organization name may not collide with a user name. The
106
- JavaScript side is published as **`@aicent/rttp`** -- this project's own
107
- organization, with the package name itself still just `rttp`.
108
- * **README distribution table** now names the npm package exactly
109
- (`@aicent/rttp`), and gives `pip install rttp` for this package, matching the
110
- table in the JavaScript package's README.
111
-
112
- ### Distribution status at this release
113
-
114
- | Registry | Name | State |
115
- |:---|:---|:---|
116
- | PyPI | `rttp` | this package -- `pip install rttp` |
117
- | npm | `@aicent/rttp` | **published 0.1.1** -- 2026-09-18 |
118
- | crates.io | `rttp` | held by this project |
119
-
120
- ## [0.1.0] -- 2026-09-17
121
-
122
- First release. Scope is deliberately narrow: **framing, addressing and sealing**,
123
- with zero dependencies and no transport.
124
-
125
- ### Added
126
-
127
- * **`rttp.pulse_header`** -- `PulseHeader128` codec for the 128-byte
128
- hardware-aligned frame header (RFC-002 sec. 4.1), including the v1.2.6 extension
129
- block:
130
- * `SPEC_REV` `0x66` - `FLAGS` `0x67` - `ACTION_LEN` `0x68` - `ACTION` `0x69`(16B)
131
- - `RESERVED` `0x79`(7B)
132
- * bytes `0x00`-`0x65` are **not touched**, `VERSION_ID` stays 130 -- readers
133
- that only understand the original layout remain conformant
134
- * `build()` - `build_for_uri()` - `parse()` - `verify()` - `to_hex()` /
135
- `from_hex()`
136
- * strict verification (R1-R7): unknown `SPEC_REV` rejected, `SPEC_REV=0` with a
137
- non-zero block rejected, non-zero `RESERVED` rejected, unknown `FLAGS` bits
138
- rejected, `ACTION` padding must be zero, `ACTION_LEN` must agree with the
139
- payload
140
- * **`rttp.rttp_uri`** -- validation, canonicalisation and `ROUTE_SHARD`
141
- derivation for `rttp://` URIs (RFC-002 sec. 10.2 / sec. 10.3):
142
- * `ROUTE_SHARD = SHA-256(ASCII(canonical_authority))[0:16]` -- deterministic,
143
- pure computation, **no DNS** (sec. 10.5)
144
- * hash-intent (`8lowhex`) and name-intent forms; open-set `action` vocabulary
145
- * fail-closed rejection of uppercase, `userinfo`, `port`, `query`,
146
- `fragment`, multi-segment paths, wrong segment counts, leading/trailing `-`,
147
- whitespace, and non-`rttp` schemes
148
- * accepts both `rttp://` and `web+rttp://` -- the second as a **tolerance** for
149
- the browser protocol-handler form, which RFC-002 no longer defines
150
- (2026-09-17). Not a conformance claim; see "Known gaps" below.
151
- * **`rttp.seal`** -- managed profile: HMAC-SHA256 over a pre-shared key table,
152
- bidirectional switch<->agent signing, `ts|nonce` with a 120-second skew window.
153
- * **`rttp.seal_asym`** -- **sovereign profile**: Ed25519 seals with
154
- `AID = SHA-256(public_key)`.
155
- * self-certifying: the envelope carries the public key, so a verifier
156
- recomputes the identity instead of trusting a claim -- **no issuance, no
157
- registry, no directory**
158
- * `ts` and `nonce` are **inside** the signed input, so they cannot be rewritten
159
- without breaking the signature
160
- * freshness enforced by default (`|now - ts| <= 120 s`); archival verification
161
- available explicitly via `check_freshness=False`
162
- * lowercase-hex only -- a case variant is rejected, not normalised
163
- * `generate_keypair()` - `seal()` - `unseal()` - `verify_envelope()` -
164
- `verify_claims()` - `public_bundle()` - `signing_input()`
165
- * requires the `ed25519` extra; without it every call raises `SealError` with
166
- the install instruction rather than degrading to an unsigned path
167
- * **`rttp.aid`** -- Autonomous Identity derivation (RFC-001), shared by both
168
- profiles so an AID means one thing across the stack.
169
- * **`rttp.selftest`** -- `python -m rttp.selftest`, **53 checks with the optional Ed25519 backend (29 by default)**:
170
- * 25 conformance vectors (6 positive URIs - 15 rejections - 3 deterministic
171
- frames - 1 `SPEC_REV=0` compatibility vector)
172
- * RFC 8032 sec. 7.1 TEST 1 / TEST 2, proving the signature backend is standard
173
- Ed25519 -- so a failure identifies *which* half broke
174
- * 22 envelope checks, including a 14-case tamper matrix in which every single
175
- alteration must be rejected, and an explicit replay-window test
176
- * 4 static-scan checks proving the core modules import nothing outside the
177
- standard library
178
- * `--vectors` prints the deterministic envelope vector for the specification;
179
- `--quiet` prints the summary line only
180
- * **`rttp/vectors/rttp-conformance-v1.2.6.json`** -- the published vectors, shipped
181
- as package data so the self-test runs from an installed wheel, offline.
182
- * Console entry point `rttp-selftest`.
183
- * **`MANIFEST.in`** -- the source distribution carries `README.md`,
184
- `CHANGELOG.md`, `LICENSE`, `pyproject.toml` and the published vectors, and
185
- excludes virtual environments and build noise. Both the wheel and the sdist
186
- pass `twine check`.
187
-
188
- ### Notes
189
-
190
- * **Zero dependencies** in the core, and that is a machine-checked claim rather
191
- than a promise -- see the static-scan section of the self-test.
192
- * The reference implementation evaluates the
193
- **`iqa`** namespace nowhere: this package is the `rttp` protocol only.
194
- * ~~Distribution: PyPI `rttp`. The npm name `rttp` is held by an unrelated,
195
- unmaintained project, so the JavaScript side will publish under the `@rttp`
196
- scope.~~ -- **corrected 2026-09-18.** PyPI `rttp` is now **published** (0.1.0,
197
- 2026-09-17). The npm name `rttp` is indeed held by an unrelated, unmaintained
198
- project -- but the **`@rttp` scope cannot be created at all**, because a
199
- personal account already holds that name. The JavaScript side is therefore
200
- published as **`@aicent/rttp`**: this project's own organization, with the
201
- package name still just `rttp`.
202
-
203
- ### Known gaps
204
-
205
- Tracked in `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` sec. 8 and sec. 10. Deliberately listed
206
- here so nobody has to discover them:
207
-
208
- * No transport and no client. The core encodes, addresses and seals; sending is a
209
- separate package's job.
210
- * No revocation, and no key rotation story. Both belong to RFC-003.
211
- * No replay **cache**: freshness (sec. 3.4) bounds the window, but within it a replayed
212
- envelope still verifies unless the verifier keeps a short-lived nonce store.
213
- * No transport-origin binding: the seal proves who signed, not which connection
214
- delivered it.
215
- * Rust parity: the published `rttp` crate has no transport layer and no envelope.
216
- Python and Node are the conforming implementations so far.
217
- * ~~the browser-registration prefix is accepted because RFC-002 sec. 10.6 requires
218
- it...~~ -- **superseded 2026-09-17.** That form was removed from both
219
- specifications and will never be submitted to IANA. `rttp_uri` still accepts it
220
- as a **tolerance** -- a browser hands the handler that string, and refusing it
221
- would break the protocol-handler path -- but the specification defines no such
222
- form, so the acceptance is **outside the specification** and a conforming
223
- third-party implementation is not required to reproduce it.
224
- * ~~**Open, and ours to fix:** the published vectors asserted things the
225
- specification no longer said.~~ -- **resolved 2026-09-18.** The generator now
226
- classifies every forward case explicitly:
227
- * `positive_uris` -- each entry carries `tolerance` (boolean) and `note`. The
228
- case whose `uri` carries the browser-registration prefix is `tolerance: true`,
229
- with its reason recorded: it is accepted only because that is the scheme name
230
- under which a handler is registered (RFC-002 sec. 10.6) -- never because the
231
- specification defines it. It is **not** a conformance claim, and the 25-check
232
- total is unchanged.
233
- * `negative_uris` -- the two case-clause citations were corrected from
234
- `(RFC-002 sec. 10.2)` to **`sec. 10.3`**, the clause that actually carries the
235
- lowercase rule. sec. 10.2 now appears nowhere in the vector set.
236
- Regenerated (`SPEC/tools/conformance.py --generate`), replayed (`--check`,
237
- 25/25), and mirrored byte-identically into both packages. After the change:
238
- Python self-test 53/53, Node runner 25/25.
1
+ # Changelog -- `rttp` (Python)
2
+
3
+ All notable changes to the `rttp` package. Format follows
4
+ [Keep a Changelog](https://keepachangelog.com/); versioning is
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ---
8
+
9
+ ## [1.3.2] -- 2026-11-09
10
+
11
+ **Vector re-anchoring release -- no code change.** The published conformance
12
+ vectors are re-anchored to `draft-li-rttp-iqa-addressing-02` (TXT sha256
13
+ `02491c5a...`, 40 pp., 2026-11-01): every `applies_to`, `spec_ref`, `reason`
14
+ and `expected` field now cites the I-D sections directly (`§§4, 7.1` set-level;
15
+ per-row `§4.1` / `§4.2` / `§4.5.2` / `§7.1.1` / `§4.3`; the seal envelope stays
16
+ under `AICENT-002 (RTTP-SEAL-ENVELOPE-v1.2.6 sec. 7)`, beyond -02). Vector
17
+ bytes are unchanged -- only anchor metadata and citation text moved; every
18
+ replay is byte-identical.
19
+
20
+ * **New vector-set digest:** `sha256 8640e390...` (13,874 bytes, was
21
+ `4b743e63...` at 13,460 bytes). Shipped byte-identically in all three
22
+ packages; manifest regenerated.
23
+ * **Documented annotations:** the `-lead` rejection vector carries a CONFLICT
24
+ note against the -02 ABNF (the I-D ABNF literally allows a leading hyphen;
25
+ the implementation is stricter and -03 will tighten it); the JS metadata
26
+ test now asserts the re-anchored `applies_to`.
27
+ * **Docs:** specification status updated to revision -02 with the TXT digest;
28
+ conformance records now point at https://iqa.org/conformance/ and
29
+ https://iqa.org/challenge/ .
30
+ * Self-test counts unchanged: **80 passed with 3 skipped** (83 with
31
+ `[ed25519]`); node --test all pass; the independent JS replay stays at 35.
32
+
33
+ ---
34
+
35
+ ## [1.3.1] -- 2026-10-05
36
+
37
+ **Synchronization release -- no code change.** The codec, the pulse frame, the
38
+ seal envelopes, the conformance vector file and every self-test result are
39
+ identical to `1.2.8` (80 passed with 3 skipped; 83 with the `[ed25519]`
40
+ extra). What moved:
41
+
42
+ ### Changed
43
+
44
+ * **Version alignment:** the PyPI, npm and crates.io lines of the dual pillars
45
+ now all read 1.3.1. This release rides the crates.io side's first formal
46
+ (non-pre-release) publication of the `rttp` crate.
47
+ * **Series designation:** `RFC-002` is now `AICENT-002` throughout the docs,
48
+ docstrings and error messages, aligning with the public specification line
49
+ (`rttp.com/AICENT-002/`). Historical entries below keep the designation they
50
+ were written with. The shipped conformance vector file is byte-frozen (its
51
+ sha256 is published) and still carries the old designation inside its labels;
52
+ renaming those labels is a coordinated vector-set regeneration, not an edit.
53
+ * **Specification status refreshed:** the `rttp` URI scheme **is registered** --
54
+ IANA "URI Schemes" registry, Provisional, CRI 27 (2026-09-22) -- and the
55
+ combined Internet-Draft `draft-li-rttp-iqa-addressing` (both schemes, one
56
+ document) is under IETF review.
57
+
58
+ ## [1.2.8] -- 2026-09-21
59
+
60
+ **Version-only re-publish.** The code, the vector file and every self-test result
61
+ are identical to `1.2.7`; only the version string moves, so the final PyPI release
62
+ carries the stack number. `1.2.7` stays installable -- pin `1.2.8` for new work.
63
+
64
+ * No wire-format, URI-grammar, public-API or vector change.
65
+ * `python -m rttp.selftest` still reports 83 checks in full, and 80 passed with
66
+ 3 skipped on a zero-dependency install.
67
+
68
+ ## [1.2.7] -- 2026-09-21
69
+
70
+ **Conformance surface grown; wire format untouched.** The shipped
71
+ `rttp/vectors/rttp-conformance-v1.2.6.json` is now 13,460 bytes
72
+ (`sha256 4b743e63...`) and the self-test replays every added case: **83 checks**
73
+ in full, and **80 passed with 3 skipped** on a zero-dependency install -- a check
74
+ that cannot be performed is reported as skipped, never as passed.
75
+
76
+ ### Added
77
+
78
+ * **Nine fail-closed frame cases, one positive frame.** Each of the nine frames
79
+ must be rejected; the positive frame must be accepted with an empty action.
80
+ * **The published Ed25519 envelope vector**, replayed three ways: the canonical
81
+ signing input byte for byte, `AID == SHA-256(public key)`, and the signature
82
+ itself (the third one skips without the optional primitive).
83
+
84
+ ### Changed
85
+
86
+ * **Skipped checks are now counted and printed**, so a default install can no
87
+ longer look like a full pass.
88
+ * Per-section counts are reported: 38 conformance, 16 envelope rules, 22 envelope
89
+ flow, 2 RFC 8032, 5 zero-dependency.
90
+
91
+ ### Note
92
+
93
+ * PyPI and npm carry `1.2.7`; crates.io carries the same code as the pre-release
94
+ `1.2.8-alpha`. The registry version strings differ by publishing policy, not by
95
+ code -- the vectors and their `sha256` are identical everywhere.
96
+
97
+ ## [1.2.6] -- 2026-09-19
98
+
99
+ **Version alignment -- no code change.** Every module, byte layout and
100
+ conformance vector is identical to 0.1.2, and the self-test still reports the
101
+ the same 53 checks (full set, i.e. with the optional Ed25519 backend). Only the version string and the maturity classifier change.
102
+
103
+ ### Changed
104
+
105
+ * **The version number now mirrors the stack version.** PyPI and npm carry
106
+ `1.2.6`, so a single number identifies this code on every distribution
107
+ channel; crates.io carries the same code as the pre-release `1.2.6-alpha`.
108
+ The old `0.1.x` line was a package-maturity number that corresponded to
109
+ nothing in the specification, and it made the same package look like two
110
+ different releases on two registries.
111
+ * **`Development Status` classifier: `3 - Alpha` -> `4 - Beta`.** A
112
+ non-pre-release version must not ship with an "Alpha" classifier; leaving
113
+ the two in conflict invites the question "which one is true?".
114
+ * Install command note: on crates.io every published version of this crate is
115
+ a pre-release, so Cargo will not select it from a plain `rttp` requirement.
116
+ Write `cargo add rttp@1.2.6-alpha` (or pin `rttp = "1.2.6-alpha"`).
117
+
118
+ ## [0.1.2] -- 2026-09-18
119
+
120
+ **Metadata correction -- no code change.** Every module, byte layout and
121
+ conformance vector is identical to 0.1.1, and the self-test still reports the
122
+ the same 53 checks (full set, i.e. with the optional Ed25519 backend).
123
+
124
+ ### Fixed
125
+
126
+ * **The distribution identity now matches the IANA registration.** The package
127
+ was authored as `RTTP Working Group` -- a name that appears in no filing. The
128
+ `rttp` URI-scheme registration on file with IANA (ticket `[IANA #1459939]`)
129
+ names **`RTTP.COM Organization`** as the `Author/Change controller`, and every
130
+ other public surface uses that same name. Both package manifests now say it
131
+ too:
132
+
133
+ | Field | Before | After |
134
+ |:---|:---|:---|
135
+ | `pyproject.toml` -> `authors` (PyPI) | `RTTP Working Group` | **`RTTP.COM Organization`** |
136
+ | `package.json` -> `author` (npm) | `RTTP Working Group` | **`RTTP.COM Organization`** |
137
+
138
+ Package metadata cannot be edited after publication, so 0.1.0 and 0.1.1 keep
139
+ the old string inside their own metadata; this is the version that carries the
140
+ correction. Project pages display the latest version, so the visible author
141
+ name becomes correct once this release is out.
142
+
143
+ ## [0.1.1] -- 2026-09-18
144
+
145
+ **Documentation only -- no code change.** Every module, byte layout and
146
+ conformance vector is identical to 0.1.0, and the self-test still reports the
147
+ the same 53 checks (full set, i.e. with the optional Ed25519 backend).
148
+
149
+ ### Fixed
150
+
151
+ * **A distribution claim that was wrong, not merely outdated.** The 0.1.0 entry
152
+ below said the JavaScript side "will publish under the `@rttp` scope". That
153
+ scope **cannot be created at all**: npm already has a personal account named
154
+ `rttp`, and an organization name may not collide with a user name. The
155
+ JavaScript side is published as **`@aicent/rttp`** -- this project's own
156
+ organization, with the package name itself still just `rttp`.
157
+ * **README distribution table** now names the npm package exactly
158
+ (`@aicent/rttp`), and gives `pip install rttp` for this package, matching the
159
+ table in the JavaScript package's README.
160
+
161
+ ### Distribution status at this release
162
+
163
+ | Registry | Name | State |
164
+ |:---|:---|:---|
165
+ | PyPI | `rttp` | this package -- `pip install rttp` |
166
+ | npm | `@aicent/rttp` | **published 0.1.1** -- 2026-09-18 |
167
+ | crates.io | `rttp` | held by this project |
168
+
169
+ ## [0.1.0] -- 2026-09-17
170
+
171
+ First release. Scope is deliberately narrow: **framing, addressing and sealing**,
172
+ with zero dependencies and no transport.
173
+
174
+ ### Added
175
+
176
+ * **`rttp.pulse_header`** -- `PulseHeader128` codec for the 128-byte
177
+ hardware-aligned frame header (RFC-002 sec. 4.1), including the v1.2.6 extension
178
+ block:
179
+ * `SPEC_REV` `0x66` - `FLAGS` `0x67` - `ACTION_LEN` `0x68` - `ACTION` `0x69`(16B)
180
+ - `RESERVED` `0x79`(7B)
181
+ * bytes `0x00`-`0x65` are **not touched**, `VERSION_ID` stays 130 -- readers
182
+ that only understand the original layout remain conformant
183
+ * `build()` - `build_for_uri()` - `parse()` - `verify()` - `to_hex()` /
184
+ `from_hex()`
185
+ * strict verification (R1-R7): unknown `SPEC_REV` rejected, `SPEC_REV=0` with a
186
+ non-zero block rejected, non-zero `RESERVED` rejected, unknown `FLAGS` bits
187
+ rejected, `ACTION` padding must be zero, `ACTION_LEN` must agree with the
188
+ payload
189
+ * **`rttp.rttp_uri`** -- validation, canonicalisation and `ROUTE_SHARD`
190
+ derivation for `rttp://` URIs (RFC-002 sec. 10.2 / sec. 10.3):
191
+ * `ROUTE_SHARD = SHA-256(ASCII(canonical_authority))[0:16]` -- deterministic,
192
+ pure computation, **no DNS** (sec. 10.5)
193
+ * hash-intent (`8lowhex`) and name-intent forms; open-set `action` vocabulary
194
+ * fail-closed rejection of uppercase, `userinfo`, `port`, `query`,
195
+ `fragment`, multi-segment paths, wrong segment counts, leading/trailing `-`,
196
+ whitespace, and non-`rttp` schemes
197
+ * accepts both `rttp://` and `web+rttp://` -- the second as a **tolerance** for
198
+ the browser protocol-handler form, which RFC-002 no longer defines
199
+ (2026-09-17). Not a conformance claim; see "Known gaps" below.
200
+ * **`rttp.seal`** -- managed profile: HMAC-SHA256 over a pre-shared key table,
201
+ bidirectional switch<->agent signing, `ts|nonce` with a 120-second skew window.
202
+ * **`rttp.seal_asym`** -- **sovereign profile**: Ed25519 seals with
203
+ `AID = SHA-256(public_key)`.
204
+ * self-certifying: the envelope carries the public key, so a verifier
205
+ recomputes the identity instead of trusting a claim -- **no issuance, no
206
+ registry, no directory**
207
+ * `ts` and `nonce` are **inside** the signed input, so they cannot be rewritten
208
+ without breaking the signature
209
+ * freshness enforced by default (`|now - ts| <= 120 s`); archival verification
210
+ available explicitly via `check_freshness=False`
211
+ * lowercase-hex only -- a case variant is rejected, not normalised
212
+ * `generate_keypair()` - `seal()` - `unseal()` - `verify_envelope()` -
213
+ `verify_claims()` - `public_bundle()` - `signing_input()`
214
+ * requires the `ed25519` extra; without it every call raises `SealError` with
215
+ the install instruction rather than degrading to an unsigned path
216
+ * **`rttp.aid`** -- Autonomous Identity derivation (RFC-001), shared by both
217
+ profiles so an AID means one thing across the stack.
218
+ * **`rttp.selftest`** -- `python -m rttp.selftest`, **53 checks with the optional Ed25519 backend (29 by default)**:
219
+ * 25 conformance vectors (6 positive URIs - 15 rejections - 3 deterministic
220
+ frames - 1 `SPEC_REV=0` compatibility vector)
221
+ * RFC 8032 sec. 7.1 TEST 1 / TEST 2, proving the signature backend is standard
222
+ Ed25519 -- so a failure identifies *which* half broke
223
+ * 22 envelope checks, including a 14-case tamper matrix in which every single
224
+ alteration must be rejected, and an explicit replay-window test
225
+ * 4 static-scan checks proving the core modules import nothing outside the
226
+ standard library
227
+ * `--vectors` prints the deterministic envelope vector for the specification;
228
+ `--quiet` prints the summary line only
229
+ * **`rttp/vectors/rttp-conformance-v1.2.6.json`** -- the published vectors, shipped
230
+ as package data so the self-test runs from an installed wheel, offline.
231
+ * Console entry point `rttp-selftest`.
232
+ * **`MANIFEST.in`** -- the source distribution carries `README.md`,
233
+ `CHANGELOG.md`, `LICENSE`, `pyproject.toml` and the published vectors, and
234
+ excludes virtual environments and build noise. Both the wheel and the sdist
235
+ pass `twine check`.
236
+
237
+ ### Notes
238
+
239
+ * **Zero dependencies** in the core, and that is a machine-checked claim rather
240
+ than a promise -- see the static-scan section of the self-test.
241
+ * The reference implementation evaluates the
242
+ **`iqa`** namespace nowhere: this package is the `rttp` protocol only.
243
+ * ~~Distribution: PyPI `rttp`. The npm name `rttp` is held by an unrelated,
244
+ unmaintained project, so the JavaScript side will publish under the `@rttp`
245
+ scope.~~ -- **corrected 2026-09-18.** PyPI `rttp` is now **published** (0.1.0,
246
+ 2026-09-17). The npm name `rttp` is indeed held by an unrelated, unmaintained
247
+ project -- but the **`@rttp` scope cannot be created at all**, because a
248
+ personal account already holds that name. The JavaScript side is therefore
249
+ published as **`@aicent/rttp`**: this project's own organization, with the
250
+ package name still just `rttp`.
251
+
252
+ ### Known gaps
253
+
254
+ Tracked in `SPEC/RTTP-SEAL-ENVELOPE-v1.2.6.md` sec. 8 and sec. 10. Deliberately listed
255
+ here so nobody has to discover them:
256
+
257
+ * No transport and no client. The core encodes, addresses and seals; sending is a
258
+ separate package's job.
259
+ * No revocation, and no key rotation story. Both belong to RFC-003.
260
+ * No replay **cache**: freshness (sec. 3.4) bounds the window, but within it a replayed
261
+ envelope still verifies unless the verifier keeps a short-lived nonce store.
262
+ * No transport-origin binding: the seal proves who signed, not which connection
263
+ delivered it.
264
+ * Rust parity: the published `rttp` crate has no transport layer and no envelope.
265
+ Python and Node are the conforming implementations so far.
266
+ * ~~the browser-registration prefix is accepted because RFC-002 sec. 10.6 requires
267
+ it...~~ -- **superseded 2026-09-17.** That form was removed from both
268
+ specifications and will never be submitted to IANA. `rttp_uri` still accepts it
269
+ as a **tolerance** -- a browser hands the handler that string, and refusing it
270
+ would break the protocol-handler path -- but the specification defines no such
271
+ form, so the acceptance is **outside the specification** and a conforming
272
+ third-party implementation is not required to reproduce it.
273
+ * ~~**Open, and ours to fix:** the published vectors asserted things the
274
+ specification no longer said.~~ -- **resolved 2026-09-18.** The generator now
275
+ classifies every forward case explicitly:
276
+ * `positive_uris` -- each entry carries `tolerance` (boolean) and `note`. The
277
+ case whose `uri` carries the browser-registration prefix is `tolerance: true`,
278
+ with its reason recorded: it is accepted only because that is the scheme name
279
+ under which a handler is registered (RFC-002 sec. 10.6) -- never because the
280
+ specification defines it. It is **not** a conformance claim, and the 25-check
281
+ total is unchanged.
282
+ * `negative_uris` -- the two case-clause citations were corrected from
283
+ `(RFC-002 sec. 10.2)` to **`sec. 10.3`**, the clause that actually carries the
284
+ lowercase rule. sec. 10.2 now appears nowhere in the vector set.
285
+ Regenerated (`SPEC/tools/conformance.py --generate`), replayed (`--check`,
286
+ 25/25), and mirrored byte-identically into both packages. After the change:
287
+ Python self-test 53/53, Node runner 25/25.