@openwop/openwop-conformance 2.0.0-rc.49 → 2.0.0-rc.50

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.49",
4
- "stampSha256": "7e65e852ca8df98dbfd604c7da903894a0cbd15feec6fe88f2e0879f88187f22"
3
+ "version": "2.0.0-rc.50",
4
+ "stampSha256": "9047f5b272c57e56d3bae6ed8df7c6544b01b67533e069da34a1c5c4a33d3295"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.0.0-rc.49",
3
+ "version": "2.0.0-rc.50",
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.49"
59
+ "@openwop/spec-artifacts": "2.0.0-rc.50"
60
60
  }
61
61
  }
package/requirements.json CHANGED
@@ -28147,7 +28147,7 @@
28147
28147
  {
28148
28148
  "id": "openwop.it.v2-run-bulk-cancel.results-come-back-in-request-order-each-id-processed-independently-a-foreign-id",
28149
28149
  "file": "v2-run-bulk-cancel.test.ts",
28150
- "line": 60,
28150
+ "line": 63,
28151
28151
  "title": "results[] come back in request order, each id processed independently, a foreign id refused in its entry and never as a top-level 403",
28152
28152
  "explicitId": null,
28153
28153
  "citations": [
@@ -28171,6 +28171,11 @@
28171
28171
  "requirement": "the foreign-tenant entry MUST be ok: false",
28172
28172
  "interpolated": true
28173
28173
  },
28174
+ {
28175
+ "section": "api/v2/openapi.yaml bulkCancelRuns results[].error",
28176
+ "requirement": null,
28177
+ "interpolated": true
28178
+ },
28174
28179
  {
28175
28180
  "section": "spec/v2/core/identity.md §5",
28176
28181
  "requirement": null,
@@ -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.49",
4
+ "version": "2.0.0-rc.50",
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": "93ecc218d08555eeac0d652768b78050ae7a4847301ddc6664c7415ab12e038a",
13
- "api/v2/asyncapi.yaml": "bec2259c5ce9ea7c0935093bdae856570b83d2242d5e298b0b6a8684424a7a83",
14
- "api/v2/openapi.yaml": "fc4ee6fdf254f2b414038be709acaeaa6f283505ad8545d1ec6b53d83d1bea25",
12
+ "api/seams-v2.yaml": "cf2510ff1fa3f7f7b37221115261e7db1121cdfaa8cdc8d5a651ba367c9cf263",
13
+ "api/v2/asyncapi.yaml": "9488e843f433ac656d1984819dbdddfcbb95c099a57afbfe1d33ce8b039c3199",
14
+ "api/v2/openapi.yaml": "7b8bdf41af39f3662c90cca68e270ac9bc12318f398af0b2083a0235380ede4b",
15
15
  "api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
16
16
  "schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
17
17
  "schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
@@ -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": "790bd9d6f00c2d258c0d66d56ed1aea0e0edf8d3b8d1ca7aa70db393b252ee48",
202
+ "spec/v1/core-standard-manifest.json": "418d5aea57422fc9b1d66b5373632c2bcbecf8687940cde32692bc5d6541c233",
203
203
  "spec/v1/deprecations.json": "1d5acb69a9b8ccb57275a95605f74aef1d920685f8407c9d382a46b59dc803bb",
204
204
  "spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
205
205
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
@@ -230,8 +230,8 @@
230
230
  "spec/v2/path-manifest.json": "034152e09b1458c66810d4050e20a273b2b9b8fe2d92b66e8b819477de58a1be",
231
231
  "spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
232
232
  "spec/v2/profiles.json": "5019ac8209540bfbeee9c3232530d4e599be0ab926d817ff48edcec8419eb209",
233
- "spec/v2/release.json": "0c1e10938fd53b0b4798e9ac7c92727c3d5c83643847cbb1da91a6920800f27f",
233
+ "spec/v2/release.json": "7b0a86de05e0890ccaaeb4319d2b8201d08c09b5019c1cde8814295ba9967323",
234
234
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
235
235
  },
236
- "corpusCommit": "67da501622b8d75dff385cb7f20ff8b96f6dd311"
236
+ "corpusCommit": "fa29c2ba4251e780acebbe199555b02d8cfa9c92"
237
237
  }
@@ -23,7 +23,7 @@
23
23
 
24
24
  import { describe, it, expect } from 'vitest';
25
25
  import { driver, type OpenWOPResponse } from '../lib/driver.js';
26
- import { v2Discovery } from '../lib/v2.js';
26
+ import { v2Discovery, v2Validator } from '../lib/v2.js';
27
27
  import { readErrorCode } from '../lib/error-envelope.js';
28
28
  import { softSkip } from '../lib/soft-skip.js';
29
29
  import { req } from '../lib/requirement-ids.js';
@@ -42,7 +42,7 @@ async function create(): Promise<{ runId: string } | { reason: string }> {
42
42
  if (res.status !== 201 || typeof runId !== 'string') return { reason: `POST /runs answered ${res.status} ${readErrorCode(res.json) ?? ''} — create refused`.trim() };
43
43
  return { runId };
44
44
  }
45
- interface Entry { runId?: unknown; ok?: unknown; status?: unknown; error?: { code?: unknown } | null }
45
+ interface Entry { runId?: unknown; ok?: unknown; status?: unknown; error?: unknown }
46
46
 
47
47
  describe('v2 run-bulk-cancel (runs.md §Cancel)', () => {
48
48
  it('101 ids are refused 400 validation_error with details.maxRunIds', async () => {
@@ -53,7 +53,10 @@ describe('v2 run-bulk-cancel (runs.md §Cancel)', () => {
53
53
  if (res.status === 404) return softSkip('blocked', 'POST /runs:bulk-cancel answered 404 — bulkCancelRuns is a core operation (runs.md §Surface) and is not mounted');
54
54
  expect(res.status, req(ID, DOC, `over the cap (RECOMMENDED 100) the host MUST answer 400 — got ${res.status}`)).toBe(400);
55
55
  expect(readErrorCode(res.json), req(ID, DOC, 'the refusal MUST be validation_error')).toBe('validation_error');
56
- const max = (res.json as { error?: { details?: { maxRunIds?: unknown } } } | null)?.error?.details?.maxRunIds;
56
+ // The v2 envelope is { error: <code>, message, details? } `details` at the ROOT
57
+ // (schemas/v2/error-envelope.schema.json). rc.48/rc.49 read `error.details`
58
+ // and reported a host defect that was this reader's; retracted in rc.50.
59
+ const max = (res.json as { details?: { maxRunIds?: unknown } } | null)?.details?.maxRunIds;
57
60
  expect(typeof max === 'number' && max >= 1 && max <= 100, req(ID, DOC, `details.maxRunIds MUST state the cap (got ${String(max)})`)).toBe(true);
58
61
  });
59
62
 
@@ -72,11 +75,16 @@ describe('v2 run-bulk-cancel (runs.md §Cancel)', () => {
72
75
  expect(entries.map((e) => e.runId), req(ID, DOC, 'results[] MUST be in request order')).toEqual(runIds);
73
76
  const foreign = entries[1]!;
74
77
  expect(foreign.ok, req(ID, DOC, 'the foreign-tenant entry MUST be ok: false')).toBe(false);
75
- const fcode = String(foreign.error?.code);
78
+ // An entry's `error` IS the error envelope (api/v2/openapi.yaml: `$ref error-envelope`):
79
+ // { error: <code>, message, details? } nested under the entry — so the code is
80
+ // `entry.error.error`, read the same way as a top-level envelope.
81
+ const env = v2Validator('error-envelope')(foreign.error);
82
+ expect(env.ok, req(ID, 'api/v2/openapi.yaml bulkCancelRuns results[].error', `an ok: false entry's error MUST be the error envelope { error: <code>, message, details? } (schemas/v2/error-envelope.schema.json; the OpenAPI $refs it for results[].error) — got ${JSON.stringify(foreign.error)}: ${env.errors}`)).toBe(true);
83
+ const fcode = String(readErrorCode(foreign.error));
76
84
  expect(['id_tenant_mismatch', 'not_found'].includes(fcode), req(ID, 'spec/v2/core/identity.md §5', `an id whose tenant segment is not the caller's MUST be refused inside the entry with id_tenant_mismatch (or not_found where existence is not leaked) — identity.md §5 applies inside a bulk entry exactly as on a path; run_forbidden is for a same-tenant run the caller may not cancel — got ${fcode}`)).toBe(true);
77
85
  for (const own of [entries[0]!, entries[2]!]) {
78
86
  const okShape = own.ok === true && ['cancelling', 'cancelled'].includes(String(own.status));
79
- const terminalShape = own.ok === false && String(own.error?.code) === 'run_terminal';
87
+ const terminalShape = own.ok === false && readErrorCode(own.error) === 'run_terminal';
80
88
  expect(okShape || terminalShape, req(ID, DOC, `an own entry MUST be ok: true with cancelling|cancelled, or ok: false run_terminal when the noop already completed — got ${JSON.stringify(own)}`)).toBe(true);
81
89
  }
82
90
  });
@@ -92,7 +92,8 @@ describe('v2 run-pause-resume (runs.md §Pause and resume)', () => {
92
92
  const again = await http(() => driver.post(`/runs/${enc(c.runId)}:pause`, {}));
93
93
  expect(again?.status ?? null, req(ID, DOC, `a second pause on a paused run MUST answer 409 — got ${again?.status ?? 'no response'}`)).toBe(409);
94
94
  expect(readErrorCode(again?.json), req(ID, DOC, `a pause refused on a non-terminal run MUST carry run_state_conflict (got ${String(readErrorCode(again?.json))})`)).toBe('run_state_conflict');
95
- const runStatus = (again?.json as { error?: { details?: { runStatus?: unknown } } } | null)?.error?.details?.runStatus;
95
+ // `details` sits at the envelope ROOT (schemas/v2/error-envelope.schema.json), not under `error`.
96
+ const runStatus = (again?.json as { details?: { runStatus?: unknown } } | null)?.details?.runStatus;
96
97
  expect(runStatus, req(ID, DOC, `run_state_conflict MUST carry details.runStatus naming the status that refused it (got ${String(runStatus)})`)).toBe('paused');
97
98
  const resume = await http(() => driver.post(`/runs/${enc(c.runId)}:resume`, { reason: 'conformance' }));
98
99
  expect(resume?.status ?? null, req(ID, DOC, `resumeRun on a paused run MUST answer 202 — got ${resume?.status ?? 'no response'} ${readErrorCode(resume?.json) ?? ''}`.trim())).toBe(202);