@openwop/openwop-conformance 2.46.9 → 2.46.11
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,3 +1,14 @@
|
|
|
1
|
+
## [2.46.11] — 2026-10-15 — a shared id reads the same on every run
|
|
2
|
+
|
|
3
|
+
- **Ledger reader: one requirement id recorded by two scenario files.** Each file runs in its own worker, and `readLedgerFile` kept whichever line came last, so the row's `assertions` and `scenario` belonged to the worker that finished last. openwop-app's `prompts.resolution-precedes-composition` read 9 then 5 assertions on identical results.
|
|
4
|
+
- The least certifiable file still decides the result and keeps its detail, so a failure in either file is never masked (unchanged).
|
|
5
|
+
- New: the files' assertion counts sum, as the in-worker fold already sums legs, and a tie names the first file by name.
|
|
6
|
+
- **What a host's next bundle shows:** rows witnessed by two files carry the summed count and a fixed scenario. No result changes.
|
|
7
|
+
|
|
8
|
+
## [2.46.10] — 2026-10-14 — RFC 0244 Accepted (provisional)
|
|
9
|
+
|
|
10
|
+
- **No assertion changes.** RFC 0244 flips to `Accepted` (provisional) on MyndHyve's certified 2.46.9 cut, so the packed `spec/v1/gaps.json` changes (G9, G10 and G11 close).
|
|
11
|
+
|
|
1
12
|
## [2.46.9] — 2026-10-14 — RFC 0244 §D: a fail-closed trial scores 0
|
|
2
13
|
|
|
3
14
|
- **`v2-eval-trajectory-trials` `0244.fixture-miss-fails`** also asserts `score: 0` on the missed task's summary entry and on each of its `eval.scored` events (RFC 0244 §D, amended in place). Both implementing hosts converged on the rule: without it, `passRule: "mean"` or the aggregate `passScore` could pass a suite whose trials all failed closed.
|
|
@@ -136,8 +136,12 @@ export function recordRequirement(requirementId, disposition, detail, extras) {
|
|
|
136
136
|
export function readLedgerFile(path) {
|
|
137
137
|
if (!existsSync(path))
|
|
138
138
|
return [];
|
|
139
|
-
const rank =
|
|
140
|
-
|
|
139
|
+
const rank = CERTIFIABILITY_RANK;
|
|
140
|
+
// Pass 1, per (id, scenario file). `<=`, not `<`: a per-`it` FOLD (2.37.0)
|
|
141
|
+
// appends the cumulative row after the leg rows it folded, so on an equal
|
|
142
|
+
// disposition the LAST line is the one carrying the summed `assertionCount`.
|
|
143
|
+
// For genuinely duplicate lines the two are identical and the choice is a no-op.
|
|
144
|
+
const perFile = new Map();
|
|
141
145
|
for (const line of readFileSync(path, 'utf8').split('\n')) {
|
|
142
146
|
if (line.trim() === '')
|
|
143
147
|
continue;
|
|
@@ -150,15 +154,32 @@ export function readLedgerFile(path) {
|
|
|
150
154
|
}
|
|
151
155
|
if (typeof e.requirementId !== 'string' || !DISPOSITIONS.includes(e.disposition))
|
|
152
156
|
continue;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
let files = perFile.get(e.requirementId);
|
|
158
|
+
if (files === undefined)
|
|
159
|
+
perFile.set(e.requirementId, (files = new Map()));
|
|
160
|
+
const file = e.scenarioFile ?? '';
|
|
161
|
+
const prior = files.get(file);
|
|
158
162
|
if (prior === undefined || rank[e.disposition] <= rank[prior.disposition])
|
|
159
|
-
|
|
163
|
+
files.set(file, e);
|
|
160
164
|
}
|
|
161
|
-
|
|
165
|
+
// Pass 2, across files (2.46.11). Two files that witness ONE id run in
|
|
166
|
+
// different workers, so "last line wins" made the row's `assertionCount` and
|
|
167
|
+
// `scenarioFile` whichever worker finished last: the same host read 9 then 5
|
|
168
|
+
// assertions for `prompts.resolution-precedes-composition` with no result
|
|
169
|
+
// change. The least certifiable file still decides the disposition and keeps
|
|
170
|
+
// its detail; counts sum, as the in-worker fold sums them; and a tie names
|
|
171
|
+
// the first file by name, so the row is the same on every run.
|
|
172
|
+
const merged = [];
|
|
173
|
+
for (const files of perFile.values()) {
|
|
174
|
+
const rows = [...files.values()].sort((a, b) => rank[a.disposition] - rank[b.disposition] || (a.scenarioFile ?? '').localeCompare(b.scenarioFile ?? ''));
|
|
175
|
+
const winner = rows[0];
|
|
176
|
+
if (rows.length === 1 || !rows.some((r) => r.assertionCount !== undefined)) {
|
|
177
|
+
merged.push(winner);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
merged.push({ ...winner, assertionCount: rows.reduce((n, r) => n + (r.assertionCount ?? 0), 0) });
|
|
181
|
+
}
|
|
182
|
+
return merged.sort((a, b) => a.requirementId.localeCompare(b.requirementId));
|
|
162
183
|
}
|
|
163
184
|
/**
|
|
164
185
|
* The disposition for a requirement. **Absent resolves to `blocked`, never to a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.46.
|
|
3
|
+
"version": "2.46.11",
|
|
4
4
|
"description": "Black-box conformance suite for OpenWOP hosts (v2 current; v1 scenarios retained for the frozen v1 tree).",
|
|
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.46.
|
|
59
|
+
"@openwop/spec-artifacts": "2.46.11"
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
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.46.
|
|
5
|
-
"corpusTag": "v2.46.
|
|
4
|
+
"version": "2.46.11",
|
|
5
|
+
"corpusTag": "v2.46.11",
|
|
6
6
|
"files": {
|
|
7
7
|
"api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
|
|
8
8
|
"api/asyncapi.yaml": "d5ecb9ee6114582be3b1f662c84bfac9ae96dae7bacb853e461168f70a8e1c7d",
|
|
9
9
|
"api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
|
|
10
10
|
"api/openapi.yaml": "ac6de5303872664b78ff419c035915593e01599e02835e777a0123de1baeb398",
|
|
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": "7722f9cf3dcf9e4288bf1ad0087f347fbc1ee53ccd1f27ebde4b01cd9dfe2ba2",
|
|
13
|
+
"api/v2/asyncapi.yaml": "2faef7d29e10478bfcde17e63f34b436cedc8b8f6aecb44ca8895bd93ad44ebe",
|
|
14
|
+
"api/v2/openapi.yaml": "78c72788d422b216286a874a2900674cde0222a80cb92b29b9427d15a7d220e7",
|
|
15
15
|
"api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
|
|
16
16
|
"schemas/README.md": "276fc1d51eb08e14e9127b9fd27761d7046ee33c12000f3a64a801322db8bf58",
|
|
17
17
|
"schemas/a2a-task-state.schema.json": "75d5049dea8bd873ff0e7546f1c60c8d36c219bec7084264360be54a8be30ae1",
|
|
@@ -208,14 +208,14 @@
|
|
|
208
208
|
"schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
|
|
209
209
|
"spec/v1/alias-detectors.json": "22444c22bb88c568339ef512553f9fc38146e22b566d11ab8608f655d688d19c",
|
|
210
210
|
"spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
|
|
211
|
-
"spec/v1/core-standard-manifest.json": "
|
|
211
|
+
"spec/v1/core-standard-manifest.json": "2a845db8a673c2f5c95ff752fc7765fb72779abf589595e7bf9989f36216ea39",
|
|
212
212
|
"spec/v1/deprecations.json": "e723bc11d7272c71789ad1303bb7f21809a8a024abf57594f9d5c35dc199ece9",
|
|
213
213
|
"spec/v1/deprecations.schema.json": "3e393c405d2a41b467d8c5e3c468549078df1ce6a6d2588fc488097b95d9b55b",
|
|
214
214
|
"spec/v1/end-of-support.json": "35f0bf3b70fe78b16e2a2fd81a153fc27e703f6c16376c6fe7cdf1f4f2c4e6d4",
|
|
215
215
|
"spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
|
|
216
216
|
"spec/v1/event-codemap.schema.json": "d05933b2e88103aff51a2f774df97b9bda065e0fc88dbd9b114cc47a32189174",
|
|
217
217
|
"spec/v1/extensions.json": "79a60754aa16cbdbdb604f8e5c00038af535a1690a4d07bd5ff7c38f0256a7bc",
|
|
218
|
-
"spec/v1/gaps.json": "
|
|
218
|
+
"spec/v1/gaps.json": "3bd864a64f6c9c69a3bfc4178d9c7df8dd625b682c1dbde1656b89a239c5a6f9",
|
|
219
219
|
"spec/v1/gaps.schema.json": "8fd83259f556553c9df0f53e7a82ca8c2a4771d471197f69b4e2ae0ceeacfd66",
|
|
220
220
|
"spec/v1/migrations.json": "4c50760be70cb644d02427bcaf5749606700edf4513f423903cf3b1d12f5c300",
|
|
221
221
|
"spec/v1/migrations.schema.json": "886779aa6c22e646db097f5df210adb018a4dd14a7b815465a18c8a7056c8f72",
|
|
@@ -313,9 +313,9 @@
|
|
|
313
313
|
"spec/v2/path-manifest.json": "7b5679a4dad98c80d855361d88a98c8a4e045af15e310862a05b285b815dc9fc",
|
|
314
314
|
"spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
|
|
315
315
|
"spec/v2/profiles.json": "b382b261c7844798575f7c1b37c934f0da19846016a2337d883d4f5ef6e05479",
|
|
316
|
-
"spec/v2/release.json": "
|
|
316
|
+
"spec/v2/release.json": "203adbfd38c222e739f8db654cf2bb453d61dcbdb74702949d933fa3dbad9baf",
|
|
317
317
|
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
|
|
318
|
-
"spec/v2/surface-baseline.json": "
|
|
318
|
+
"spec/v2/surface-baseline.json": "a566e5a039f75a076bde41640f4ecbea50fbae41bf4581aff69c2dad14b24b6a"
|
|
319
319
|
},
|
|
320
|
-
"corpusCommit": "
|
|
320
|
+
"corpusCommit": "398b842f0e19e8de6cd6b6c706b51bedcff77356"
|
|
321
321
|
}
|
|
@@ -221,8 +221,12 @@ export function recordRequirement(
|
|
|
221
221
|
*/
|
|
222
222
|
export function readLedgerFile(path: string): readonly LedgerEntry[] {
|
|
223
223
|
if (!existsSync(path)) return [];
|
|
224
|
-
const rank
|
|
225
|
-
|
|
224
|
+
const rank = CERTIFIABILITY_RANK;
|
|
225
|
+
// Pass 1, per (id, scenario file). `<=`, not `<`: a per-`it` FOLD (2.37.0)
|
|
226
|
+
// appends the cumulative row after the leg rows it folded, so on an equal
|
|
227
|
+
// disposition the LAST line is the one carrying the summed `assertionCount`.
|
|
228
|
+
// For genuinely duplicate lines the two are identical and the choice is a no-op.
|
|
229
|
+
const perFile = new Map<string, Map<string, LedgerEntry>>();
|
|
226
230
|
for (const line of readFileSync(path, 'utf8').split('\n')) {
|
|
227
231
|
if (line.trim() === '') continue;
|
|
228
232
|
let e: LedgerEntry;
|
|
@@ -232,14 +236,32 @@ export function readLedgerFile(path: string): readonly LedgerEntry[] {
|
|
|
232
236
|
continue;
|
|
233
237
|
}
|
|
234
238
|
if (typeof e.requirementId !== 'string' || !DISPOSITIONS.includes(e.disposition)) continue;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (prior === undefined || rank[e.disposition] <= rank[prior.disposition]) merged.set(e.requirementId, e);
|
|
239
|
+
let files = perFile.get(e.requirementId);
|
|
240
|
+
if (files === undefined) perFile.set(e.requirementId, (files = new Map()));
|
|
241
|
+
const file = e.scenarioFile ?? '';
|
|
242
|
+
const prior = files.get(file);
|
|
243
|
+
if (prior === undefined || rank[e.disposition] <= rank[prior.disposition]) files.set(file, e);
|
|
241
244
|
}
|
|
242
|
-
|
|
245
|
+
// Pass 2, across files (2.46.11). Two files that witness ONE id run in
|
|
246
|
+
// different workers, so "last line wins" made the row's `assertionCount` and
|
|
247
|
+
// `scenarioFile` whichever worker finished last: the same host read 9 then 5
|
|
248
|
+
// assertions for `prompts.resolution-precedes-composition` with no result
|
|
249
|
+
// change. The least certifiable file still decides the disposition and keeps
|
|
250
|
+
// its detail; counts sum, as the in-worker fold sums them; and a tie names
|
|
251
|
+
// the first file by name, so the row is the same on every run.
|
|
252
|
+
const merged: LedgerEntry[] = [];
|
|
253
|
+
for (const files of perFile.values()) {
|
|
254
|
+
const rows = [...files.values()].sort(
|
|
255
|
+
(a, b) => rank[a.disposition] - rank[b.disposition] || (a.scenarioFile ?? '').localeCompare(b.scenarioFile ?? ''),
|
|
256
|
+
);
|
|
257
|
+
const winner = rows[0]!;
|
|
258
|
+
if (rows.length === 1 || !rows.some((r) => r.assertionCount !== undefined)) {
|
|
259
|
+
merged.push(winner);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
merged.push({ ...winner, assertionCount: rows.reduce((n, r) => n + (r.assertionCount ?? 0), 0) });
|
|
263
|
+
}
|
|
264
|
+
return merged.sort((a, b) => a.requirementId.localeCompare(b.requirementId));
|
|
243
265
|
}
|
|
244
266
|
|
|
245
267
|
/**
|