@openwop/openwop-conformance 2.45.18 → 2.45.19
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.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [2.45.19] — 2026-10-05 — a minted tenant-bound id carries no `~`; RFC 0235's registers close
|
|
4
|
+
|
|
5
|
+
- **New leg `openwop.requirement.0184.mint-no-tilde`** in `v2-bound-id-path-projection`. RFC 0184 §A.2: a host MUST NOT mint a tenant-bound id containing `~`. Only the run this leg creates is checked, because ids minted earlier MUST still resolve.
|
|
6
|
+
- **It bites only under a non-clean tenant.** openwop-app minted `user~3A<hash>/<id>` for personal and org tenants (app ADR 0814). No leg saw it, because the suite's key sat in the clean tenant `default`. On a clean tenant the defect still mints a clean id.
|
|
7
|
+
- **RFC 0235 registers closed (packed `spec/v1/gaps.json`).** Gaps G1 (the v2 reference host's byte-exact comparison) and G2 (no certified witness) close on that host's certified 2.45.18 cut. No scenario changes.
|
|
8
|
+
|
|
3
9
|
## [2.45.18] — 2026-10-04 — `If-None-Match` per RFC 9110 (RFC 0235); corpus-only legs leave the host bundle; `.supported` leaves the v2 schemas
|
|
4
10
|
|
|
5
11
|
- **Seven `v2-*-static` scenarios move to `src/coherence/`.** They read only the corpus, and `conformance.md` §Two products says such a check MUST NOT appear in a host bundle. The bundle schema now excludes their ids.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.45.
|
|
3
|
+
"version": "2.45.19",
|
|
4
4
|
"description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@openwop/spec-artifacts": "file:../spec-artifacts"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@openwop/spec-artifacts": "2.45.
|
|
59
|
+
"@openwop/spec-artifacts": "2.45.19"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/requirements.json
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
"generatedFrom": "src/scenarios/*.test.ts",
|
|
4
4
|
"counts": {
|
|
5
5
|
"files": 726,
|
|
6
|
-
"tests":
|
|
7
|
-
"withStableId":
|
|
6
|
+
"tests": 2755,
|
|
7
|
+
"withStableId": 2755,
|
|
8
8
|
"interpolatedTitles": 0,
|
|
9
|
-
"explicitIds":
|
|
9
|
+
"explicitIds": 2621
|
|
10
10
|
},
|
|
11
11
|
"records": [
|
|
12
12
|
{
|
|
@@ -28969,7 +28969,7 @@
|
|
|
28969
28969
|
{
|
|
28970
28970
|
"id": "openwop.it.v2-bound-id-path-projection.a-tenant-bound-id-is-readable-at-its-escaped-path-segment-links-carry-that-form",
|
|
28971
28971
|
"file": "v2-bound-id-path-projection.test.ts",
|
|
28972
|
-
"line":
|
|
28972
|
+
"line": 69,
|
|
28973
28973
|
"title": "a tenant-bound id is readable at its ~-escaped path segment, links carry that form, and a malformed escape is refused",
|
|
28974
28974
|
"explicitId": "openwop.requirement.0184.bound-id-path-projection",
|
|
28975
28975
|
"citations": [
|
|
@@ -29013,6 +29013,20 @@
|
|
|
29013
29013
|
}
|
|
29014
29014
|
]
|
|
29015
29015
|
},
|
|
29016
|
+
{
|
|
29017
|
+
"id": "openwop.it.v2-bound-id-path-projection.a-tenant-bound-id-the-host-mints-for-this-run-contains-no-bites-only-when-the-cr",
|
|
29018
|
+
"file": "v2-bound-id-path-projection.test.ts",
|
|
29019
|
+
"line": 154,
|
|
29020
|
+
"title": "a tenant-bound id the host mints for this run contains no ~ (bites only when the credential tenant is not grammar-clean)",
|
|
29021
|
+
"explicitId": "openwop.requirement.0184.mint-no-tilde",
|
|
29022
|
+
"citations": [
|
|
29023
|
+
{
|
|
29024
|
+
"section": "spec/v2/core/identity.md §5",
|
|
29025
|
+
"requirement": null,
|
|
29026
|
+
"interpolated": true
|
|
29027
|
+
}
|
|
29028
|
+
]
|
|
29029
|
+
},
|
|
29016
29030
|
{
|
|
29017
29031
|
"id": "openwop.it.v2-budget-enforcement.a-budgeted-run-emits-budget-reserved-budget-threshold-crossed-and-budget-exhaust",
|
|
29018
29032
|
"file": "v2-budget-enforcement.test.ts",
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Provenance of @openwop/spec-artifacts (RFC 0168 §D.2). files: SHA-256 per file; the conformance suite compares the installed peer against dist/spec-artifacts.lock.json at start.",
|
|
3
3
|
"package": "@openwop/spec-artifacts",
|
|
4
|
-
"version": "2.45.
|
|
5
|
-
"corpusTag": "v2.45.
|
|
4
|
+
"version": "2.45.19",
|
|
5
|
+
"corpusTag": "v2.45.19",
|
|
6
6
|
"files": {
|
|
7
7
|
"api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
|
|
8
8
|
"api/asyncapi.yaml": "d5ecb9ee6114582be3b1f662c84bfac9ae96dae7bacb853e461168f70a8e1c7d",
|
|
9
9
|
"api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
|
|
10
10
|
"api/openapi.yaml": "ac6de5303872664b78ff419c035915593e01599e02835e777a0123de1baeb398",
|
|
11
11
|
"api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
|
|
12
|
-
"api/seams-v2.yaml": "
|
|
13
|
-
"api/v2/asyncapi.yaml": "
|
|
14
|
-
"api/v2/openapi.yaml": "
|
|
12
|
+
"api/seams-v2.yaml": "f240b4205e4f1205b80278806db17fff394e5b4ef21a7ad1d2c3bda8ee080b5a",
|
|
13
|
+
"api/v2/asyncapi.yaml": "525ed38e2e0c5c0cb0785fb940f97ee3335c837f5797351ee954c3e312174bdb",
|
|
14
|
+
"api/v2/openapi.yaml": "9971c6250f45f8ea6f8b16d3f3e1a86556d65968342e9ec370f23018c118c872",
|
|
15
15
|
"api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
|
|
16
16
|
"schemas/README.md": "bd1c00fae7b6fda506a75aff841bbdc438d4ce092642a72041203bee999b88de",
|
|
17
17
|
"schemas/a2a-task-state.schema.json": "75d5049dea8bd873ff0e7546f1c60c8d36c219bec7084264360be54a8be30ae1",
|
|
@@ -207,14 +207,14 @@
|
|
|
207
207
|
"schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
|
|
208
208
|
"spec/v1/alias-detectors.json": "0b2f28808ffe0b9d98a187775038c3406bb70919747a788a6e4f866e293ae6d3",
|
|
209
209
|
"spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
|
|
210
|
-
"spec/v1/core-standard-manifest.json": "
|
|
210
|
+
"spec/v1/core-standard-manifest.json": "806e07cd5de0684b09db910394d8713d0f6f45dc318803374a183cc57d07bf86",
|
|
211
211
|
"spec/v1/deprecations.json": "a3293072ea951857395d05f0437264e88965f1e9019ff61c55bacfa9c1aaa17c",
|
|
212
212
|
"spec/v1/deprecations.schema.json": "3e393c405d2a41b467d8c5e3c468549078df1ce6a6d2588fc488097b95d9b55b",
|
|
213
213
|
"spec/v1/end-of-support.json": "35f0bf3b70fe78b16e2a2fd81a153fc27e703f6c16376c6fe7cdf1f4f2c4e6d4",
|
|
214
214
|
"spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
|
|
215
215
|
"spec/v1/event-codemap.schema.json": "d05933b2e88103aff51a2f774df97b9bda065e0fc88dbd9b114cc47a32189174",
|
|
216
216
|
"spec/v1/extensions.json": "79a60754aa16cbdbdb604f8e5c00038af535a1690a4d07bd5ff7c38f0256a7bc",
|
|
217
|
-
"spec/v1/gaps.json": "
|
|
217
|
+
"spec/v1/gaps.json": "9271f9796be51dc5182ad7ed00445b50c67e1c3d33fc76b47f080a985dd647d7",
|
|
218
218
|
"spec/v1/gaps.schema.json": "8fd83259f556553c9df0f53e7a82ca8c2a4771d471197f69b4e2ae0ceeacfd66",
|
|
219
219
|
"spec/v1/migrations.json": "4c50760be70cb644d02427bcaf5749606700edf4513f423903cf3b1d12f5c300",
|
|
220
220
|
"spec/v1/migrations.schema.json": "886779aa6c22e646db097f5df210adb018a4dd14a7b815465a18c8a7056c8f72",
|
|
@@ -309,9 +309,9 @@
|
|
|
309
309
|
"spec/v2/path-manifest.json": "b84c7561f50c7df0cb61b202bd6595acad3ee7edca7a45f711949bea3c69bd27",
|
|
310
310
|
"spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
|
|
311
311
|
"spec/v2/profiles.json": "180beb9ef2d161766fa23b2987e7e829851e3d316273147cf6a4a3f324befd6b",
|
|
312
|
-
"spec/v2/release.json": "
|
|
312
|
+
"spec/v2/release.json": "9e25694dc4997c4291d86a3e65346a9db37af36cff411155de29b9619a169c90",
|
|
313
313
|
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
|
|
314
|
-
"spec/v2/surface-baseline.json": "
|
|
314
|
+
"spec/v2/surface-baseline.json": "97a0dc8dc715ed872d766aceb91f991e031b0bd160421037d6927fa21e9646b5"
|
|
315
315
|
},
|
|
316
|
-
"corpusCommit": "
|
|
316
|
+
"corpusCommit": "d1ece01b982dd1ad4eee4bd29b144e4a82b0db22"
|
|
317
317
|
}
|
|
@@ -22,12 +22,29 @@
|
|
|
22
22
|
* `v2-created-run-readable` already witnesses it. Duplicating it here would red
|
|
23
23
|
* two rows for one defect and tell a bundle reader nothing new.
|
|
24
24
|
*
|
|
25
|
+
* **Minting (RFC 0184 §A.2), a second `it`.** A host MUST NOT mint a
|
|
26
|
+
* tenant-bound id containing `~`; ids already minted MUST still resolve, so only
|
|
27
|
+
* an id this run mints is checked, never every id a body carries. Unescaped, a
|
|
28
|
+
* literal `~` is ambiguous with the codec's own marker. openwop-app minted
|
|
29
|
+
* `user~3A<hash>/<id>` for personal and org tenants (app ADR 0814: it projected
|
|
30
|
+
* the tenant key instead of mapping it), and no leg saw it, because the
|
|
31
|
+
* conformance key sat in the clean tenant `default`. **The leg bites only when
|
|
32
|
+
* the suite's credential sits in a tenant whose key is not already clean**: on a
|
|
33
|
+
* clean tenant a host with that defect still mints a clean id, so a green row is
|
|
34
|
+
* evidence only under a non-clean posture; the `it` title says so. Proven on
|
|
35
|
+
* openwop-app 800722836 (2026-10-05): under `acme@corp.example` the ADR 0814 map
|
|
36
|
+
* passes (`x-61636d65…/…`) and the reverted projection fails
|
|
37
|
+
* (`acme~40corp.example/…`); under `default` both builds pass. The in-process
|
|
38
|
+
* harness (`conformance/run.ts`) overwrites `OPENWOP_API_KEYS` with a `:*` key, so
|
|
39
|
+
* moving the tenant needs that line edited, not just the env var.
|
|
40
|
+
*
|
|
25
41
|
* The codec's own edge cases (marker escaping, UTF-8 vs UTF-16, malformed
|
|
26
42
|
* decode) are a unit concern and live in `src/lib/bound-id.test.ts`, which is
|
|
27
43
|
* sabotage-checked. This file asserts only what needs a HOST to answer.
|
|
28
44
|
*
|
|
29
45
|
* @see spec/v2/core/identity.md §5
|
|
30
46
|
* @see RFCS/0184-bound-id-path-projection.md §A.1
|
|
47
|
+
* @see RFCS/0184-bound-id-path-projection.md §A.2
|
|
31
48
|
*/
|
|
32
49
|
|
|
33
50
|
import { describe, it, expect } from 'vitest';
|
|
@@ -40,6 +57,7 @@ import { projectBoundId } from '../lib/bound-id.js';
|
|
|
40
57
|
import { BOUND_ID as BOUND } from '../lib/bound-id.js';
|
|
41
58
|
|
|
42
59
|
const ID = 'openwop.requirement.0184.bound-id-path-projection';
|
|
60
|
+
const ID_MINT = 'openwop.requirement.0184.mint-no-tilde';
|
|
43
61
|
const DOC = 'spec/v2/core/identity.md §5';
|
|
44
62
|
const NOOP_WORKFLOW_ID = 'conformance-noop';
|
|
45
63
|
|
|
@@ -132,4 +150,21 @@ describe('v2 bound-id path projection (identity.md §5)', () => {
|
|
|
132
150
|
req(ID, DOC, `a path segment whose '~' is not followed by two hex digits MUST be refused 400 validation_error — got ${malformed?.status ?? 'no response'} ${readErrorCode(malformed?.json) ?? ''}`.trim()),
|
|
133
151
|
).toBe(400);
|
|
134
152
|
});
|
|
153
|
+
|
|
154
|
+
it('a tenant-bound id the host mints for this run contains no ~ (bites only when the credential tenant is not grammar-clean)', async () => {
|
|
155
|
+
try { if (!(await v2Discovery())) return softSkip('blocked', 'v2 discovery unreachable'); } catch { return softSkip('blocked', 'v2 discovery unreachable'); }
|
|
156
|
+
const created = await http(() => driver.post('/runs', { workflowId: NOOP_WORKFLOW_ID }));
|
|
157
|
+
if (created === null) return softSkip('blocked', 'POST /runs unreachable (fetch failed)');
|
|
158
|
+
if (created.status === 429) return softSkip('blocked', 'POST /runs answered 429 — the run budget, not the wire');
|
|
159
|
+
const runId = (created.json as { runId?: unknown } | null)?.runId;
|
|
160
|
+
if (created.status !== 201 || typeof runId !== 'string') {
|
|
161
|
+
return softSkip('blocked', `POST /runs {workflowId: ${NOOP_WORKFLOW_ID}} answered ${created.status} ${readErrorCode(created.json) ?? ''} — the smallest valid create was refused (fixture not seeded?)`.trim());
|
|
162
|
+
}
|
|
163
|
+
// The body carries the bound id, never the projection (identity.md §5: ids in
|
|
164
|
+
// documents and bodies are bound). So a `~` here was minted, not escaped.
|
|
165
|
+
expect(
|
|
166
|
+
runId.includes('~'),
|
|
167
|
+
req(ID_MINT, DOC, `a host MUST NOT mint a tenant-bound id containing ~ (RFC 0184 §A.2) — the created runId is ${runId}. A literal ~ is ambiguous with the path projection's escape marker; map the tenant key to a clean segment instead of projecting it`),
|
|
168
|
+
).toBe(false);
|
|
169
|
+
});
|
|
135
170
|
});
|