@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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.45.18",
4
- "stampSha256": "ebbae5f7e2d21d3cceb270610d2c4e808e9fe98ab7b6e282960281b36fb60d1b"
3
+ "version": "2.45.19",
4
+ "stampSha256": "a9d31bb3f312bb79740e2318e39b831d1666753b2d87d6cec5d6cfa11c292117"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.45.18",
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.18"
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": 2754,
7
- "withStableId": 2754,
6
+ "tests": 2755,
7
+ "withStableId": 2755,
8
8
  "interpolatedTitles": 0,
9
- "explicitIds": 2620
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": 51,
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.18",
5
- "corpusTag": "v2.45.18",
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": "56dabe76a0104e27ec5db429d10130c710fd6cc77f9e8c83060ac8642e1bf296",
13
- "api/v2/asyncapi.yaml": "99cf46de7c1009d6a7f317a69d1746d8664db94602a3936140f5a51ad0647293",
14
- "api/v2/openapi.yaml": "03618b3e70be4a916a88b344f40090e8c0477925c0a40f1447d87872f6772281",
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": "62c1d7adc81e42adb7ec62f634f86e8812835ba07bda83c4ce2e5b67d27d87d5",
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": "7fb75c8cceaa8aa6893aa9dc68ae83e57fe0178225a23f376b6de54e74b15ead",
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": "74d260237e39bc6e3ffd8740a263e9dbe2fc6e75866b51a6d900dffe32b75ad4",
312
+ "spec/v2/release.json": "9e25694dc4997c4291d86a3e65346a9db37af36cff411155de29b9619a169c90",
313
313
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
314
- "spec/v2/surface-baseline.json": "4bc82b54af36b5f7611668523349a9bfcc370c4d86812cef8d11dd54f1f14405"
314
+ "spec/v2/surface-baseline.json": "97a0dc8dc715ed872d766aceb91f991e031b0bd160421037d6927fa21e9646b5"
315
315
  },
316
- "corpusCommit": "332098b793ec36500833b99f40bab66ec5573d77"
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
  });