@openwop/openwop-conformance 2.0.0-rc.41 → 2.0.0-rc.43

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,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.0.0-rc.41",
4
- "stampSha256": "b4aa6e89d6e4d71a5ca619dee2c15686c65905be382d5af2dfe6c795f2b1267f"
3
+ "version": "2.0.0-rc.43",
4
+ "stampSha256": "2737f8a4be23de309638fc248b80422ac094007293d0ffddf17776071114e5c5"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.0.0-rc.41",
3
+ "version": "2.0.0-rc.43",
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.0.0-rc.41"
59
+ "@openwop/spec-artifacts": "2.0.0-rc.43"
60
60
  }
61
61
  }
@@ -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.0.0-rc.41",
4
+ "version": "2.0.0-rc.43",
5
5
  "corpusTag": null,
6
6
  "files": {
7
7
  "api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
@@ -9,9 +9,9 @@
9
9
  "api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
10
10
  "api/openapi.yaml": "39081c59fb696159806b0f2f9a42e7e9ff830d622fcf2ad4159b21357580a955",
11
11
  "api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
12
- "api/seams-v2.yaml": "5c2747b24a9c156586a322ee5356edb16c1a6c2f4483c940232ef1ecfeb1e633",
13
- "api/v2/asyncapi.yaml": "be7fd6fd4721f77e3c6559a81e9d63e617db08cd730e9ec1dba72c5394c74814",
14
- "api/v2/openapi.yaml": "495048ee348c60ddd3e522adcb900b0725d06b65a34de0dbcda5233973041997",
12
+ "api/seams-v2.yaml": "b8320186a24fb2749bcbed7e9d5c34677ea0fc5c4b83dbbcf31b263dd7a1c714",
13
+ "api/v2/asyncapi.yaml": "2ee29b26799ea1d180fb7b5726d968bec2f05c707dc863917011e8fd815372bf",
14
+ "api/v2/openapi.yaml": "895f43f227f50056104feeb680ddb5c950d61f39744076cac673b9d9c95b9ce3",
15
15
  "api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
16
16
  "schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
17
17
  "schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
@@ -141,7 +141,7 @@
141
141
  "schemas/v2/envelopes/schema.request.schema.json": "be2c5f7aa881cdd252ccff47ac02193659e1393633a1541f4297383205d384a2",
142
142
  "schemas/v2/envelopes/schema.response.schema.json": "d049a081267c06c28879c331b147f3ed821b14ccfd93005c67aff64db0a8c68e",
143
143
  "schemas/v2/envelopes/ui.a2ui-surface.schema.json": "0a06fbbdc8ba797a6818c79336a98e211ac5ba5747945b4e4098072cd3974d79",
144
- "schemas/v2/error-envelope.schema.json": "d550beeab958b528c8734fd32e74c438006b99172c5c586f9e0af20ef4b2bee7",
144
+ "schemas/v2/error-envelope.schema.json": "c08241b74e41f4e3524c25f1c611195ed0e79b49a8ecf63e304add67070bdce5",
145
145
  "schemas/v2/eval-summary.schema.json": "bcb165148531d33b7dc01de83da3a049d19ebbef6d12300b17a234c7b03d77d9",
146
146
  "schemas/v2/export-bundle.schema.json": "bd28905a7729437ab7f2ad8bb33e13a371b2bf5605a7eb2962a0d246de312d69",
147
147
  "schemas/v2/form-content-pack-manifest.schema.json": "307884e57946703b6f86ec283034bf56beb68bea4a000743ebbc9eebeed31b07",
@@ -199,7 +199,7 @@
199
199
  "schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
200
200
  "spec/v1/alias-detectors.json": "fee4594ef49953953ffcd0b3813300067d16b3e65ebff2aac722034ac9b3f545",
201
201
  "spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
202
- "spec/v1/core-standard-manifest.json": "30301847d9c9c862aee054f78e9b599ac3ed6482ea5153704102d8d8ac3ca940",
202
+ "spec/v1/core-standard-manifest.json": "efae7332938c2977bf10e780061d16f33b029390c1023fe5418d6421c115d35b",
203
203
  "spec/v1/deprecations.json": "1d5acb69a9b8ccb57275a95605f74aef1d920685f8407c9d382a46b59dc803bb",
204
204
  "spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
205
205
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
@@ -213,7 +213,7 @@
213
213
  "spec/v1/spec-gaps.json": "6cc9962c6b969f632e07a78b52a4f61447ff579e2990cbae989866f584a86042",
214
214
  "spec/v2/declaration.json": "52b8c24a2dd463d44086129bf792ad108746f5102778cbbf0ff469fa534eca48",
215
215
  "spec/v2/declaration.schema.json": "b0881a76228dfbd1b85a2ec7b7259a60197f768344535cdb475db6ff719b0e54",
216
- "spec/v2/errors.json": "ad1725dc7c11002450e8abc682858eb5c11952a0718ea8ef6bdb2fb5ae6e7e21",
216
+ "spec/v2/errors.json": "c2dd3fa0401efa0dc78da3b21e32b58a89ed5114cebdde96d3eb999a702118f0",
217
217
  "spec/v2/event-codemap.json": "37869a03cdfd8758b57e6f350641a6ebbd383231cebda51f5473ad85f94ab74c",
218
218
  "spec/v2/event-codemap.schema.json": "ce2d0ca085d7668d7ef745d2560b385ec6881d24a6d4b47c49931986b2ba642d",
219
219
  "spec/v2/ext/provider-idempotency/registry.json": "5b5fecad604fb4ab38da39f5abe697a4e57b05406c398f8afeb377331b2bd965",
@@ -230,7 +230,7 @@
230
230
  "spec/v2/path-manifest.json": "034152e09b1458c66810d4050e20a273b2b9b8fe2d92b66e8b819477de58a1be",
231
231
  "spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
232
232
  "spec/v2/profiles.json": "1f0ee40491131cf561ef19a0394c47ba476b4567514fe16befb6cada4a10a5a4",
233
- "spec/v2/release.json": "4fbed389582b0bcc1a4f72ab87480ff7426b03a5830c2b937b955582993455bf"
233
+ "spec/v2/release.json": "2013f8d8387352a99c425038cbc98688e8b2f9de1b410b60f25478e09d05f8c0"
234
234
  },
235
- "corpusCommit": "ae59e85fd2e28e352b31c7bd8bdedc2fa4b10f23"
235
+ "corpusCommit": "c671cc08657877c3e26316ad8e9849670555f07a"
236
236
  }
@@ -41,6 +41,7 @@
41
41
  * @see RFCS/0003-fixture-gating.md
42
42
  */
43
43
 
44
+ import { softSkip } from './soft-skip.js';
44
45
  import type { DiscoveryPayload } from './profiles.js';
45
46
 
46
47
  let _advertisedFixtures: ReadonlySet<string> | null = null;
@@ -76,7 +77,29 @@ function loadOptedOutPredicate(): (id: string) => boolean {
76
77
  * filtered out of the cache before storage so downstream lookups can
77
78
  * stay a single sync set-membership test.
78
79
  */
80
+ let _discoveryUnreadable: string | null = null;
81
+
82
+ /**
83
+ * Suite init could not READ the discovery document. This is not "the host
84
+ * advertises no fixtures" and MUST NOT be recorded as such: with 311
85
+ * fixture-gated sites, an empty cache turns an entire lane into `inapplicable`
86
+ * rows that read exactly like a host that advertises nothing. Measured
87
+ * 2026-09-05: all four workers hit the 5 s init abort against a host that
88
+ * answers `/.well-known/openwop` in 120–200 ms (a Cloud Run cold start), and
89
+ * every fixture-gated scenario skipped as "not advertised". The cache stays
90
+ * null; every gate that consults it records `blocked` with this reason.
91
+ */
92
+ export function setDiscoveryUnreadable(reason: string): void {
93
+ _advertisedFixtures = null;
94
+ _discoveryUnreadable = reason;
95
+ }
96
+
97
+ export function discoveryUnreadableReason(): string | null {
98
+ return _discoveryUnreadable;
99
+ }
100
+
79
101
  export function setAdvertisedFixtures(c: DiscoveryPayload | null | undefined): void {
102
+ _discoveryUnreadable = null;
80
103
  if (c == null || !Array.isArray(c.fixtures)) {
81
104
  _advertisedFixtures = new Set();
82
105
  return;
@@ -103,6 +126,13 @@ export function setAdvertisedFixtures(c: DiscoveryPayload | null | undefined): v
103
126
  * );
104
127
  */
105
128
  export function isFixtureAdvertised(id: string): boolean {
129
+ if (_advertisedFixtures === null && _discoveryUnreadable !== null) {
130
+ // Evidence went unread, on the suite's side. `blocked` outranks the
131
+ // `inapplicable` the caller is about to record (soft-skip.ts RANK), so the
132
+ // file resolves to the honest word instead of the vacuous one.
133
+ softSkip('blocked', `suite init could not read /.well-known/openwop (${_discoveryUnreadable}) — fixture ${id} is UNKNOWN, not unadvertised`);
134
+ return false;
135
+ }
106
136
  return _advertisedFixtures?.has(id) ?? false;
107
137
  }
108
138
 
@@ -127,4 +157,5 @@ export function isFixtureCacheReady(): boolean {
127
157
  /** Test-only: reset the module-level cache. */
128
158
  export function __resetForTests(): void {
129
159
  _advertisedFixtures = null;
160
+ _discoveryUnreadable = null;
130
161
  }
package/src/setup.ts CHANGED
@@ -25,7 +25,7 @@
25
25
  * `it` here; vitest treats setupFiles differently from scenario files.
26
26
  */
27
27
 
28
- import { setAdvertisedFixtures } from './lib/fixtures.js';
28
+ import { setAdvertisedFixtures, setDiscoveryUnreadable } from './lib/fixtures.js';
29
29
  import { setMultiAgentCapabilities } from './lib/multi-agent-capabilities.js';
30
30
  import { OtelCollector, setCollector } from './lib/otel-collector.js';
31
31
  import { McpFakeServer, setMcpFakeServer } from './lib/mcp-fake-server.js';
@@ -43,13 +43,15 @@ import type { DiscoveryPayload } from './lib/profiles.js';
43
43
  import { targetMajor } from './lib/seams.js';
44
44
  import { softSkip } from './lib/soft-skip.js';
45
45
 
46
- const SUITE_INIT_TIMEOUT_MS = 5_000;
46
+ // 20 s, not 5: a Cloud Run cold start routinely exceeds 5 s, and a discovery
47
+ // fetch that aborted at init used to turn every fixture-gated scenario into a
48
+ // vacuous `inapplicable`. Measured 2026-09-05 on a host answering in 200 ms.
49
+ const SUITE_INIT_TIMEOUT_MS = 20_000;
50
+ const SUITE_INIT_ATTEMPTS = 2;
47
51
 
48
52
  async function loadHostFixtures(): Promise<void> {
49
53
  const baseUrl = process.env.OPENWOP_BASE_URL?.trim();
50
54
  if (!baseUrl) {
51
- // Offline / fixture-stub-only run. No host to ask; treat as "host
52
- // advertises no fixtures" so all fixture-dependent scenarios skip.
53
55
  setAdvertisedFixtures(null);
54
56
  setMultiAgentCapabilities(null);
55
57
  return;
@@ -57,39 +59,36 @@ async function loadHostFixtures(): Promise<void> {
57
59
 
58
60
  const normalizedBase = baseUrl.replace(/\/$/, '');
59
61
  const url = `${normalizedBase}/.well-known/openwop`;
62
+ // The representation the header selects is the one whose fixtures[] this
63
+ // lane is held to (versioning.md §5): read it under the lane's major.
64
+ const headers: Record<string, string> = { Accept: 'application/json' };
65
+ if (targetMajor() === 2) headers['OpenWOP-Version'] = '2.0';
60
66
 
61
- const controller = new AbortController();
62
- const timer = setTimeout(() => controller.abort(), SUITE_INIT_TIMEOUT_MS);
63
- try {
64
- const res = await fetch(url, {
65
- method: 'GET',
66
- headers: { Accept: 'application/json' },
67
- signal: controller.signal,
68
- });
69
- if (!res.ok) {
70
- // eslint-disable-next-line no-console
71
- console.warn(
72
- `[openwop-conformance setup] discovery fetch returned ${res.status}; ` +
73
- `treating host as advertising no fixtures. Fixture-dependent scenarios will skip.`,
74
- );
75
- setAdvertisedFixtures(null);
76
- setMultiAgentCapabilities(null);
67
+ let lastFailure = 'unknown';
68
+ for (let attempt = 1; attempt <= SUITE_INIT_ATTEMPTS; attempt += 1) {
69
+ const controller = new AbortController();
70
+ const timer = setTimeout(() => controller.abort(), SUITE_INIT_TIMEOUT_MS);
71
+ try {
72
+ const res = await fetch(url, { method: 'GET', headers, signal: controller.signal });
73
+ if (!res.ok) {
74
+ lastFailure = `HTTP ${res.status} on attempt ${attempt}`;
75
+ continue;
76
+ }
77
+ const body = (await res.json()) as DiscoveryPayload;
78
+ setAdvertisedFixtures(body);
79
+ setMultiAgentCapabilities(body);
77
80
  return;
81
+ } catch (err) {
82
+ lastFailure = `${(err as Error).message ?? 'unknown'} on attempt ${attempt}`;
83
+ } finally {
84
+ clearTimeout(timer);
78
85
  }
79
- const body = (await res.json()) as DiscoveryPayload;
80
- setAdvertisedFixtures(body);
81
- setMultiAgentCapabilities(body);
82
- } catch (err) {
83
- // eslint-disable-next-line no-console
84
- console.warn(
85
- `[openwop-conformance setup] discovery fetch failed (${(err as Error).message ?? 'unknown'}); ` +
86
- `treating host as advertising no fixtures. Fixture-dependent scenarios will skip.`,
87
- );
88
- setAdvertisedFixtures(null);
89
- setMultiAgentCapabilities(null);
90
- } finally {
91
- clearTimeout(timer);
92
86
  }
87
+ // Not "the host advertises no fixtures". The document went UNREAD, and every
88
+ // fixture gate will say so as `blocked` rather than `inapplicable`.
89
+ console.warn(`[openwop-conformance setup] discovery unreadable after ${SUITE_INIT_ATTEMPTS} attempt(s) (${lastFailure}); fixture-gated scenarios will record blocked, not inapplicable.`);
90
+ setDiscoveryUnreadable(lastFailure);
91
+ setMultiAgentCapabilities(null);
93
92
  }
94
93
 
95
94
  /**