@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 +10 -0
- package/dist/lib/scenario-disposition.js +7 -1
- package/dist/spec-artifacts.lock.json +2 -2
- package/package.json +2 -2
- package/requirements.json +6 -6
- package/schemas/CORPUS-STAMP.json +7 -7
- package/src/cli.ts +10 -0
- package/src/lib/scenario-disposition.ts +7 -1
- package/src/scenarios/pause-resume.test.ts +8 -2
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
|
-
|
|
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.
|
|
4
|
-
"stampSha256": "
|
|
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.
|
|
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.
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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.
|
|
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": "
|
|
13
|
-
"api/v2/asyncapi.yaml": "
|
|
14
|
-
"api/v2/openapi.yaml": "
|
|
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": "
|
|
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": "
|
|
233
|
+
"spec/v2/release.json": "d6c6cf65c949713644ff9ee19acc824b8956135fa2492a1a795181dc96db7da5",
|
|
234
234
|
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
|
|
235
235
|
},
|
|
236
|
-
"corpusCommit": "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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',
|