@openwop/openwop-conformance 2.0.0-rc.53 → 2.0.0-rc.55

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/dist/cli.js CHANGED
@@ -430,6 +430,16 @@ async function resolveTargetMajor(args, baseUrl, apiKey, conformanceRoot) {
430
430
  // Say so, or an operator reads a v1 run as the host's only option.
431
431
  if (major === 1 && dualStack)
432
432
  source += ' (the host also serves 2.x — pass --target-major 2 to measure it)';
433
+ // The RUNNER's own process must see the target major, not only the vitest
434
+ // child (rc.55). `requirementIdForFile()` decides "is this file a floor?"
435
+ // through `targetMajor()` = process.env; until rc.55 `--target-major 2` set
436
+ // the env on the child alone, so the worker recorded every v2 floor file
437
+ // under `openwop.floor.<stem>` while the runner looked it up as
438
+ // `openwop.scenario.<stem>`, found nothing, emitted a report-derived pass
439
+ // with no assertion count, and its own verifier rejected the bundle as a
440
+ // `vacuous-pass` emitter defect (exit 2, nothing written). The child env is
441
+ // spread from process.env after this, so one assignment covers both.
442
+ process.env['OPENWOP_TARGET_MAJOR'] = String(major);
433
443
  const manifest = JSON.parse(readFileSync(resolvePath(conformanceRoot, 'scenario-majors.json'), 'utf8'));
434
444
  const files = Object.entries(manifest.majors).filter(([, m]) => m.includes(major)).map(([f]) => `src/scenarios/${f}`);
435
445
  return { major, files, source };
@@ -49,7 +49,13 @@ export function floorScenarioFiles() {
49
49
  // minted `openwop.scenario.*` and looked up as `openwop.floor.*` — which is
50
50
  // exactly what refused a tier-1 host's first production bundle over 101
51
51
  // executed-pass rows (see v2ProfileFloorFiles).
52
- if (targetMajor() === 2) {
52
+ //
53
+ // rc.55: the runner installs the v2 floor map (`setV2ProfileFloors`) but
54
+ // reads `targetMajor()` from ITS OWN process.env, which `--target-major 2`
55
+ // never set — so the worker (env set) minted `openwop.floor.v2-…` and the
56
+ // runner (env unset) looked up `openwop.scenario.v2-…`. Either signal is
57
+ // the same fact; honour both so the two halves cannot disagree again.
58
+ if (targetMajor() === 2 || v2FloorsActive()) {
53
59
  for (const files of Object.values(v2ProfileFloorFiles(PKG_ROOT_PATH)))
54
60
  for (const f of files)
55
61
  out.add(f);
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.0.0-rc.53",
4
- "stampSha256": "c922f572cdf72529a1d3daca8a6c16b5c4a2e12165f5c7cee3b04638912f414c"
3
+ "version": "2.0.0-rc.55",
4
+ "stampSha256": "b0248029d9d1f2892661fa3addada15a500ecbe9a58a09a72102cc9867be6a68"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.0.0-rc.53",
3
+ "version": "2.0.0-rc.55",
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.53"
59
+ "@openwop/spec-artifacts": "2.0.0-rc.55"
60
60
  }
61
61
  }
package/requirements.json CHANGED
@@ -18746,7 +18746,7 @@
18746
18746
  {
18747
18747
  "id": "openwop.it.pause-resume.resuming-a-running-not-paused-run-returns-409-with-details-runstatus",
18748
18748
  "file": "pause-resume.test.ts",
18749
- "line": 104,
18749
+ "line": 110,
18750
18750
  "title": "resuming a running (not paused) run returns 409 with details.runStatus",
18751
18751
  "explicitId": "openwop.it.pause-resume.resuming-a-running-not-paused-run-returns-409-with-details-runstatus",
18752
18752
  "citations": [
@@ -18765,7 +18765,7 @@
18765
18765
  {
18766
18766
  "id": "openwop.it.pause-resume.pause-on-an-already-paused-run-returns-409-with-details-runstatus-paused-unless",
18767
18767
  "file": "pause-resume.test.ts",
18768
- "line": 138,
18768
+ "line": 144,
18769
18769
  "title": ":pause on an already-paused run returns 409 with details.runStatus paused, unless the request carries the original Idempotency-Key",
18770
18770
  "explicitId": "openwop.it.pause-resume.pause-on-an-already-paused-run-returns-409-with-details-runstatus-paused-unless",
18771
18771
  "citations": [
@@ -18799,7 +18799,7 @@
18799
18799
  {
18800
18800
  "id": "openwop.it.pause-resume.pause-on-a-completed-cancelled-failed-run-must-return-409",
18801
18801
  "file": "pause-resume.test.ts",
18802
- "line": 199,
18802
+ "line": 205,
18803
18803
  "title": ":pause on a completed/cancelled/failed run MUST return 409",
18804
18804
  "explicitId": "openwop.it.pause-resume.pause-on-a-completed-cancelled-failed-run-must-return-409",
18805
18805
  "citations": [
@@ -18813,7 +18813,7 @@
18813
18813
  {
18814
18814
  "id": "openwop.it.pause-resume.under-drain-current-node-node-completed-precedes-run-paused-in-the-log",
18815
18815
  "file": "pause-resume.test.ts",
18816
- "line": 223,
18816
+ "line": 229,
18817
18817
  "title": "under drain-current-node node.completed precedes run.paused in the log",
18818
18818
  "explicitId": "openwop.it.pause-resume.under-drain-current-node-node-completed-precedes-run-paused-in-the-log",
18819
18819
  "citations": [
@@ -18832,7 +18832,7 @@
18832
18832
  {
18833
18833
  "id": "openwop.it.pause-resume.pause-must-not-silently-override-an-active-interrupt-suspend",
18834
18834
  "file": "pause-resume.test.ts",
18835
- "line": 262,
18835
+ "line": 268,
18836
18836
  "title": ":pause MUST NOT silently override an active interrupt suspend",
18837
18837
  "explicitId": "openwop.it.pause-resume.pause-must-not-silently-override-an-active-interrupt-suspend",
18838
18838
  "citations": [
@@ -18851,7 +18851,7 @@
18851
18851
  {
18852
18852
  "id": "openwop.it.pause-resume.every-drainpolicy-advertised-by-the-host-is-accepted-on-pause",
18853
18853
  "file": "pause-resume.test.ts",
18854
- "line": 318,
18854
+ "line": 324,
18855
18855
  "title": "every drainPolicy advertised by the host is accepted on :pause",
18856
18856
  "explicitId": "openwop.it.pause-resume.every-drainpolicy-advertised-by-the-host-is-accepted-on-pause",
18857
18857
  "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.0.0-rc.53",
4
+ "version": "2.0.0-rc.55",
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": "44b449eba2eb915b84aadf3c3d0f06bdf7e0b8ade2952b6a17711459d7b3999e",
13
- "api/v2/asyncapi.yaml": "6e4ad967752e5c6e87c48f656f4f4cbe3f85423faebc69ab60bd3bf9bf2b329e",
14
- "api/v2/openapi.yaml": "aa8ee2c55604517ac9b2ac7923ad8a957f9fa4bc331bf1b91cdd5236933d6921",
12
+ "api/seams-v2.yaml": "6f00017b7c5b238f1d2fa67d38e4e2877767a9a723148dbec27c9848916b7a1d",
13
+ "api/v2/asyncapi.yaml": "bb08bba189e7a5554faa8ee4f7cee338e22a2caf1b97f136feee7e53a2df68ca",
14
+ "api/v2/openapi.yaml": "a55411c772643be1974acb69e340d306f8b6b00b85bcaac6bb5df0b9f667a297",
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": "c7f3665189cd982747f26b98dfa977293c0c359a1fb986a3a5a3b8b95f9edd83",
202
+ "spec/v1/core-standard-manifest.json": "7d9ab29be97a94750aa1a345205e23f4b3672c426d8f53a0af3203be2edeb4e3",
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": "6be17bd4ee80838e3ee85dd7372a88532835448832fccd6b7834a5f1f0c6b326",
233
+ "spec/v2/release.json": "d6c6cf65c949713644ff9ee19acc824b8956135fa2492a1a795181dc96db7da5",
234
234
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
235
235
  },
236
- "corpusCommit": "693550295565e5f6072c9a852a3ea499275396fb"
236
+ "corpusCommit": "4b603d6f0d24d1df7b7f2f94c544a37e41048ff0"
237
237
  }
package/src/cli.ts CHANGED
@@ -451,6 +451,16 @@ async function resolveTargetMajor(args: ParsedArgs, baseUrl: string | undefined,
451
451
  // §1.1), so auto-detection on a dual-stack host resolves to major 1 by design.
452
452
  // Say so, or an operator reads a v1 run as the host's only option.
453
453
  if (major === 1 && dualStack) source += ' (the host also serves 2.x — pass --target-major 2 to measure it)';
454
+ // The RUNNER's own process must see the target major, not only the vitest
455
+ // child (rc.55). `requirementIdForFile()` decides "is this file a floor?"
456
+ // through `targetMajor()` = process.env; until rc.55 `--target-major 2` set
457
+ // the env on the child alone, so the worker recorded every v2 floor file
458
+ // under `openwop.floor.<stem>` while the runner looked it up as
459
+ // `openwop.scenario.<stem>`, found nothing, emitted a report-derived pass
460
+ // with no assertion count, and its own verifier rejected the bundle as a
461
+ // `vacuous-pass` emitter defect (exit 2, nothing written). The child env is
462
+ // spread from process.env after this, so one assignment covers both.
463
+ process.env['OPENWOP_TARGET_MAJOR'] = String(major);
454
464
  const manifest = JSON.parse(readFileSync(resolvePath(conformanceRoot, 'scenario-majors.json'), 'utf8')) as { majors: Record<string, number[]> };
455
465
  const files = Object.entries(manifest.majors).filter(([, m]) => m.includes(major as number)).map(([f]) => `src/scenarios/${f}`);
456
466
  return { major, files, source };
@@ -48,7 +48,13 @@ export function floorScenarioFiles(): ReadonlySet<string> {
48
48
  // minted `openwop.scenario.*` and looked up as `openwop.floor.*` — which is
49
49
  // exactly what refused a tier-1 host's first production bundle over 101
50
50
  // executed-pass rows (see v2ProfileFloorFiles).
51
- if (targetMajor() === 2) {
51
+ //
52
+ // rc.55: the runner installs the v2 floor map (`setV2ProfileFloors`) but
53
+ // reads `targetMajor()` from ITS OWN process.env, which `--target-major 2`
54
+ // never set — so the worker (env set) minted `openwop.floor.v2-…` and the
55
+ // runner (env unset) looked up `openwop.scenario.v2-…`. Either signal is
56
+ // the same fact; honour both so the two halves cannot disagree again.
57
+ if (targetMajor() === 2 || v2FloorsActive()) {
52
58
  for (const files of Object.values(v2ProfileFloorFiles(PKG_ROOT_PATH))) for (const f of files) out.add(f);
53
59
  }
54
60
  return out;
@@ -62,7 +62,13 @@ describe.skipIf(SKIP)('pause/resume: running → paused → running → terminal
62
62
  it('pause transitions to paused; resume returns the run to running', async () => {
63
63
  const create = await driver.post('/v1/runs', {
64
64
  workflowId: FIXTURE!,
65
- inputs: { delayMs: 30_000 },
65
+ // 3 s, not 30 s: the resumed node.started is a FRESH attempt (runs.md
66
+ // §Pause and resume; rc.52), so a 30 s node resumed at ~60 ms completes
67
+ // at ~30.2 s — past the suite's 30 s test timeout by construction on
68
+ // any conforming host. rc.53 shipped 30 s and a tier-1 host measured
69
+ // exactly that. The pause is `immediate`, issued within ~60 ms of
70
+ // `running`, so 3 s is ample for the pause to land first.
71
+ inputs: { delayMs: 3_000 },
66
72
  });
67
73
  expect(create.status).toBe(201);
68
74
  const runId = (create.json as { runId: string }).runId;
@@ -70,7 +76,7 @@ describe.skipIf(SKIP)('pause/resume: running → paused → running → terminal
70
76
  await pollUntilStatus(runId, 'running', { timeoutMs: 10_000 });
71
77
 
72
78
  // `immediate` snapshots between events, so `paused` is observable within
73
- // seconds. Under drain-current-node this 30 s node would finish first
79
+ // milliseconds. Under drain-current-node the node would finish first
74
80
  // (rest-endpoints.md); that semantic is witnessed by the drain leg below.
75
81
  const pause = await driver.post(`/v1/runs/${encodeURIComponent(runId)}:pause`, {
76
82
  reason: 'conformance-test',