@openwop/openwop-conformance 2.36.0 → 2.36.1

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,9 @@
1
1
  # `@openwop/openwop-conformance` Changelog
2
2
 
3
+ ## [2.36.1] — 2026-09-23 — a leg that convicted every host of a rule the spec does not have
4
+
5
+ - **`mcp-2026-07-28-discover` asserted the opposite of `mcp-integration.md` §D, and a fixture that no longer existed.** 2.36.0 repaged the suite's own fake MCP server — "`tools/list` paged 3 + 3 over six tools with `cacheScope: \"private\"` (was one unpaged `public` page)", as that release's own RFC 0204 entry records — and both halves of the `tools/list` leg were left describing the old fixture. The first asserted `cacheScope === 'public'`; §D says `cacheScope` MUST be `private` whenever a result depends on the caller's tenant, workspace, principal or authorization, "which for `tools/list` on a multi-tenant host is always", and permits `public` ONLY when the result is byte-identical for every caller. So the leg required the one value the spec forbids here, and **every** certify run went red on it — the fixture is suite-owned, so the failure is deterministic and host-independent: it was a false `executed-fail` on the record of any host that ran it. The second asserted a three-name catalogue (`echo`, `needs_input`, `needs_input_loop`) against a six-tool paged one whose first page is `echo`, `structured-echo`, `always-error` — the MRTR tool the leg is *named for* is on page two, so the leg no longer reached the thing it exists to check. It now asserts the deterministic first page, follows `nextCursor`, and asserts page two carries the read-only-claim tool plus both MRTR tools and advertises no further cursor. Sabotage: setting the fixture back to `cacheScope: 'public'` turns the row `executed-fail` again. Found by the Conformance Soak on the 2.36.0 tree, not by a host — the corpus gate had quarantined the leg locally, which is exactly how an assertion drifts from its fixture for a full release. No spec text, schema or host obligation changed; only the suite's reading of one it already had.
6
+
3
7
  ## [2.36.0] — 2026-09-23 — the MCP/A2A alignment program, measured: thirteen RFCs, thirty-seven new scenario and coherence files
4
8
 
5
9
  - **RFC 0210 `Active` — the `exp-only` lane's window is a bound the host enforces, and the two corpus rows that keep the member honest.** New `src/scenarios/v2-lane-exp-only-bound.test.ts` (major 2), gated on an advertised `auth.lanes[]` member with `revocation: "exp-only"` (`inapplicable`, naming what IS advertised, otherwise) **and** `OPENWOP_TEST_OIDC_ISSUER_URL` naming a synthetic issuer the operator configured that lane to trust (`blocked` otherwise — without a token the host would ever accept, "it refused a string" witnesses nothing; a window under 120 s is also `blocked`, because the control token needs room inside it). Three legs, one issuer, one key, one token shape: a control credential at `exp − iat = window − 60` that MUST NOT be refused, a credential at `exp − iat = window + 60` (still unexpired) and one with no `iat` at all that MUST be refused `401 credential_lifetime_exceeded`, and a clock-skewed credential whose total lifetime is inside the window while its remaining lifetime is outside it — the only shape that separates the two bounds, and the one a host enforcing `exp − iat` alone serves. The control is what makes the refusals evidence; a host that refuses every token fails it. New `src/coherence/v2-lane-exp-only-schema.test.ts` (corpus gate, never reaches a bundle) mints `openwop.requirement.0210.exp-only-lane-restricted` — `exp-only` validates on `oauth2` and `oidc`, is refused on `api-key` and `session`, and **each negative is re-validated against a facet copy with only the §C.8 `if`/`then` removed, where it MUST pass**, so it cannot be failing for an unrelated defect in the fixture — and `openwop.requirement.0210.lane-rule-surfaces-agree`, which drives `scripts/check-lane-revocation-rules.mjs` red once per surface in a throwaway corpus copy (an enum member with no §2.2 row; a `LANE_RULES` entry the table does not license) rather than asserting exit 0 on a clean tree. `v2-lane-issuer-advertised.test.ts` gains `exp-only` in its `REVOCATION`, `WINDOWED` and `LANE_RULES` maps, in lockstep with §2.2's table and the facet enum.
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  # --legacy-peer-deps is REQUIRED, not optional: the exact peer pin is what npm's
12
12
  # default resolver refuses. npm 10.9 fails outright with
13
13
  # "Cannot read properties of null (reading 'edgesOut')" — use npm >= 11.
14
- npm install --legacy-peer-deps @openwop/openwop-conformance@2.36.0 @openwop/spec-artifacts@2.36.0
14
+ npm install --legacy-peer-deps @openwop/openwop-conformance@2.36.1 @openwop/spec-artifacts@2.36.1
15
15
  # or run without install:
16
16
  npx @openwop/openwop-conformance --base-url https://api.example.com --api-key hk_test_...
17
17
  ```
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.36.0",
4
- "stampSha256": "95ebfa7aa43f4aee5036088bc1bba2be8dbba4d1a93e331181d941b49fcfd9a3"
3
+ "version": "2.36.1",
4
+ "stampSha256": "8cccf11a7baf5e5c0b8c1edcc72b473c2107786fb460b6e014fd0d5bce37f262"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.36.0",
3
+ "version": "2.36.1",
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.36.0"
59
+ "@openwop/spec-artifacts": "2.36.1"
60
60
  }
61
61
  }
package/requirements.json CHANGED
@@ -15860,13 +15860,21 @@
15860
15860
  {
15861
15861
  "section": "RFC 0153 §B",
15862
15862
  "requirement": "tools/list @2026-07-28 carries resultType + CacheableResult hints and lists the MRTR tool"
15863
+ },
15864
+ {
15865
+ "section": "mcp-integration.md §D",
15866
+ "requirement": "a truncated tools/list MUST carry a pagination cursor"
15867
+ },
15868
+ {
15869
+ "section": "mcp-integration.md §D",
15870
+ "requirement": "the last page of tools/list MUST NOT advertise a further cursor"
15863
15871
  }
15864
15872
  ]
15865
15873
  },
15866
15874
  {
15867
15875
  "id": "openwop.it.mcp-2026-07-28-discover.mrtr-needs-input-answers-input-required-elicitation-opaque-requeststate-and-comp",
15868
15876
  "file": "mcp-2026-07-28-discover.test.ts",
15869
- "line": 130,
15877
+ "line": 145,
15870
15878
  "title": "MRTR: needs_input answers input_required (elicitation + opaque requestState) and completes on the retry; missing capability ⇒ -32021",
15871
15879
  "explicitId": "openwop.it.mcp-2026-07-28-discover.mrtr-needs-input-answers-input-required-elicitation-opaque-requeststate-and-comp",
15872
15880
  "citations": [
@@ -15879,7 +15887,7 @@
15879
15887
  {
15880
15888
  "id": "openwop.it.mcp-2026-07-28-discover.server-discover-reports-supportedversions-equal-to-capabilities-mcp-protocolvers",
15881
15889
  "file": "mcp-2026-07-28-discover.test.ts",
15882
- "line": 186,
15890
+ "line": 201,
15883
15891
  "title": "server/discover reports supportedVersions equal to capabilities.mcp.protocolVersions, with resultType + cache hints",
15884
15892
  "explicitId": "openwop.it.mcp-2026-07-28-discover.server-discover-reports-supportedversions-equal-to-capabilities-mcp-protocolvers",
15885
15893
  "citations": [
@@ -15900,7 +15908,7 @@
15900
15908
  {
15901
15909
  "id": "openwop.it.mcp-2026-07-28-discover.a-header-body-revision-mismatch-is-refused-400-32020-an-unsupported-revision-400",
15902
15910
  "file": "mcp-2026-07-28-discover.test.ts",
15903
- "line": 198,
15911
+ "line": 213,
15904
15912
  "title": "a header/body revision mismatch is refused 400 + -32020; an unsupported revision 400 + -32022",
15905
15913
  "explicitId": "openwop.it.mcp-2026-07-28-discover.a-header-body-revision-mismatch-is-refused-400-32020-an-unsupported-revision-400",
15906
15914
  "citations": [
@@ -1,7 +1,7 @@
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.36.0",
4
+ "version": "2.36.1",
5
5
  "corpusTag": "v2.36.0",
6
6
  "files": {
7
7
  "api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
@@ -204,7 +204,7 @@
204
204
  "schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
205
205
  "spec/v1/alias-detectors.json": "2401fcb1c18cdd688c018b3d716ae6bca85c5e356220ee2b793bd9d81872412d",
206
206
  "spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
207
- "spec/v1/core-standard-manifest.json": "f08b1cd57e065fe1f10499ce2b3452d326dc70c3f64fbc68d2795ca16103d7a6",
207
+ "spec/v1/core-standard-manifest.json": "99e982c47f276fd0acd7791ed80bedf815c13ec2b9ca74a4e97b53e30d77f7d7",
208
208
  "spec/v1/deprecations.json": "2d03f4729810280147ea08c630ea65434f2dc5370567d0aac41c3595f8337d40",
209
209
  "spec/v1/deprecations.schema.json": "3e393c405d2a41b467d8c5e3c468549078df1ce6a6d2588fc488097b95d9b55b",
210
210
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
@@ -296,5 +296,5 @@
296
296
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
297
297
  "spec/v2/surface-baseline.json": "efdb4e5e0eb16689e20dea2be6f326971bb5707990c31896ca4cf24c6a5bbfed"
298
298
  },
299
- "corpusCommit": "a427fd35ec19058b6c7dcbf418e89d03798d20b8"
299
+ "corpusCommit": "21f518e4e2af1d10280fc121789bc97837a3b009"
300
300
  }
@@ -114,14 +114,29 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
114
114
  const r = await call(server.endpoint(), 'tools/list', {}, { version: '2026-07-28', mcpMethod: 'tools/list' });
115
115
  expect(r.result?.['resultType'], req('openwop.it.mcp-2026-07-28-discover.tools-list-2026-07-28-carries-resulttype-cacheableresult-hints-and-lists-the-mrt', 'RFC 0153 §B', 'tools/list @2026-07-28 carries resultType + CacheableResult hints and lists the MRTR tool')).toBe('complete');
116
116
  expect(typeof r.result?.['ttlMs']).toBe('number');
117
- expect(r.result?.['cacheScope']).toBe('public');
117
+ // `private`, not `public`, and the difference is normative: mcp-integration.md §D
118
+ // says `cacheScope` MUST be `private` whenever a result depends on the caller's
119
+ // tenant, workspace, principal or authorization — "which for `tools/list` on a
120
+ // multi-tenant host is always" — and permits `public` ONLY when the result is
121
+ // byte-identical for every caller. The fake server was corrected to `private` in
122
+ // 2.36.0 (RFC 0204, #1497); this assertion was left demanding `public`, so the leg
123
+ // convicted every host of a rule the spec does not have. Same drift the note below
124
+ // records for `needs_input_loop`: the fixture moved, the assertion did not.
125
+ expect(r.result?.['cacheScope']).toBe('private');
118
126
  const names = (r.result?.['tools'] as Array<{ name: string }>).map((t) => t.name);
119
- // `needs_input_loop` is the MRTR tool this `it` is named for — it was added to the
120
- // fake server in 2.4.0 so the mrtr-rounds-ceiling leg could reach a ceiling >= 1,
121
- // and this assertion was never moved with it. A host that proxies the fake server
122
- // faithfully returns all three, so the leg red on every certify run while the
123
- // corpus gate quarantined it locally.
124
- expect(names).toEqual(['echo', 'needs_input', 'needs_input_loop']);
127
+ // The MRTR tool this `it` is named for is `needs_input`, and it is NOT on page one.
128
+ // The fixture grew to six tools and paginates at TOOLS_PAGE_SIZE (RFC 0204 added
129
+ // `structured-echo`, `always-error` and the read-only-claim tool), so an assertion
130
+ // naming three tools in one page had been describing a fixture that no longer
131
+ // existed. Follow the cursor and assert what the leg is actually for: the catalogue
132
+ // is paged deterministically and the MRTR tool is reachable through it.
133
+ expect(names).toEqual(['echo', 'structured-echo', 'always-error']);
134
+ const cursor = r.result?.['nextCursor'];
135
+ expect(typeof cursor, req('openwop.it.mcp-2026-07-28-discover.tools-list-2026-07-28-carries-resulttype-cacheableresult-hints-and-lists-the-mrt', 'mcp-integration.md §D', 'a truncated tools/list MUST carry a pagination cursor')).toBe('string');
136
+ const page2 = await call(server.endpoint(), 'tools/list', { cursor }, { version: '2026-07-28', mcpMethod: 'tools/list' });
137
+ const rest = (page2.result?.['tools'] as Array<{ name: string }>).map((t) => t.name);
138
+ expect(rest).toEqual([server.readonlyClaimToolName(), 'needs_input', 'needs_input_loop']);
139
+ expect(page2.result?.['nextCursor'], req('openwop.it.mcp-2026-07-28-discover.tools-list-2026-07-28-carries-resulttype-cacheableresult-hints-and-lists-the-mrt', 'mcp-integration.md §D', 'the last page of tools/list MUST NOT advertise a further cursor')).toBeUndefined();
125
140
  // legacy list does NOT carry the current-revision fields
126
141
  const legacy = await call(server.endpoint(), 'tools/list', {});
127
142
  expect(legacy.result?.['ttlMs']).toBeUndefined();