@openwop/openwop-conformance 2.46.19 → 2.46.20
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,9 @@
|
|
|
1
|
+
## [2.46.20] — 2026-10-24 — RFC 0081 eval envelope legs; RFC 0249 Draft
|
|
2
|
+
|
|
3
|
+
- **Two new legs in `v2-eval-trajectory-trials` (RFC 0081 §C)**, on the existing `conformance-eval-trajectory` run, so no extra run: `0081.eval-envelope` (one `eval.started` and one `eval.completed` bracket every `eval.scored`, `eval.completed` precedes `run.completed`, and its counts equal the summary's) and `0081.summary-served` (the served `EvalSummary` validates and its counts match its rows). Judges in `lib/eval-envelope-witness.ts`, whose self-tests fail each wrong host answer. Before this, no v2 leg read `eval.completed`.
|
|
4
|
+
- **Host impact:** hosts that advertise `agents.evalSuite.trajectory` and list the fixture (openwop-app, MyndHyve) run both legs. A host that omits `eval.completed` fails `0081.eval-envelope`.
|
|
5
|
+
- RFC 0249 (v2 proposal operations and an install read-back for RFC 0096) is filed as `Draft`. Its gap register lands in the packed `spec/v1/gaps.json`, which opened this cycle.
|
|
6
|
+
|
|
1
7
|
## [2.46.19] — 2026-10-22 — RFC 0248: ctx.callAI attempt accounting and retry policy
|
|
2
8
|
|
|
3
9
|
- **New scenario `v2-callai-attempt-accounting`** with eight legs: `0248.attempts-count`, `output-tokens-sum`, `usage-incomplete`, `structured-output`, `attempts-replayed`, `max-attempts-cap`, `no-budget-growth` and `retry-malformed-refused`. They are gated on `aiProviders.callAccounting.attempts` / `.retryPolicy` and the fixture.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.46.
|
|
3
|
+
"version": "2.46.20",
|
|
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.20"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/requirements.json
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
"generatedFrom": "src/scenarios/*.test.ts",
|
|
4
4
|
"counts": {
|
|
5
5
|
"files": 747,
|
|
6
|
-
"tests":
|
|
7
|
-
"withStableId":
|
|
6
|
+
"tests": 2824,
|
|
7
|
+
"withStableId": 2824,
|
|
8
8
|
"interpolatedTitles": 0,
|
|
9
|
-
"explicitIds":
|
|
9
|
+
"explicitIds": 2697
|
|
10
10
|
},
|
|
11
11
|
"records": [
|
|
12
12
|
{
|
|
@@ -31092,7 +31092,7 @@
|
|
|
31092
31092
|
{
|
|
31093
31093
|
"id": "openwop.it.v2-eval-trajectory-trials.the-rfc-0244-suite-summary-and-event-fields-validate-and-the-negatives-are-refus",
|
|
31094
31094
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31095
|
-
"line":
|
|
31095
|
+
"line": 162,
|
|
31096
31096
|
"title": "the RFC 0244 suite, summary and event fields validate and the negatives are refused",
|
|
31097
31097
|
"explicitId": "openwop.requirement.0244.wire-shape",
|
|
31098
31098
|
"citations": [
|
|
@@ -31131,7 +31131,7 @@
|
|
|
31131
31131
|
{
|
|
31132
31132
|
"id": "openwop.it.v2-eval-trajectory-trials.the-rfc-0244-additions-are-content-free-eval-summary-no-content-leak",
|
|
31133
31133
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31134
|
-
"line":
|
|
31134
|
+
"line": 185,
|
|
31135
31135
|
"title": "the RFC 0244 additions are content-free (eval-summary-no-content-leak)",
|
|
31136
31136
|
"explicitId": "openwop.requirement.0244.content-free",
|
|
31137
31137
|
"citations": [
|
|
@@ -31148,7 +31148,7 @@
|
|
|
31148
31148
|
{
|
|
31149
31149
|
"id": "openwop.it.v2-eval-trajectory-trials.the-eval-suite-fixtures-validate-against-the-v2-suite-schema",
|
|
31150
31150
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31151
|
-
"line":
|
|
31151
|
+
"line": 192,
|
|
31152
31152
|
"title": "the eval-suite fixtures validate against the v2 suite schema",
|
|
31153
31153
|
"explicitId": "openwop.requirement.0244.fixtures-valid",
|
|
31154
31154
|
"citations": [
|
|
@@ -31162,7 +31162,7 @@
|
|
|
31162
31162
|
{
|
|
31163
31163
|
"id": "openwop.it.v2-eval-trajectory-trials.the-rfc-0246-gating-fields-validate-and-stay-in-0-1",
|
|
31164
31164
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31165
|
-
"line":
|
|
31165
|
+
"line": 199,
|
|
31166
31166
|
"title": "the RFC 0246 gating fields validate and stay in 0–1",
|
|
31167
31167
|
"explicitId": "openwop.requirement.0246.gated-fields-shape",
|
|
31168
31168
|
"citations": [
|
|
@@ -31184,7 +31184,7 @@
|
|
|
31184
31184
|
{
|
|
31185
31185
|
"id": "openwop.it.v2-eval-trajectory-trials.a-fixture-entry-may-be-marked-iserror-and-only-as-a-boolean-rfc-0245-a",
|
|
31186
31186
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31187
|
-
"line":
|
|
31187
|
+
"line": 207,
|
|
31188
31188
|
"title": "a fixture entry may be marked isError, and only as a boolean (RFC 0245 §A)",
|
|
31189
31189
|
"explicitId": "openwop.requirement.0245.fixture-error-shape",
|
|
31190
31190
|
"citations": [
|
|
@@ -31206,7 +31206,7 @@
|
|
|
31206
31206
|
{
|
|
31207
31207
|
"id": "openwop.it.v2-eval-trajectory-trials.a-trajectory-suite-is-graded-per-the-reference-grader",
|
|
31208
31208
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31209
|
-
"line":
|
|
31209
|
+
"line": 217,
|
|
31210
31210
|
"title": "a trajectory suite is graded per the reference grader",
|
|
31211
31211
|
"explicitId": "openwop.requirement.0244.trajectory-graded",
|
|
31212
31212
|
"citations": [
|
|
@@ -31237,10 +31237,38 @@
|
|
|
31237
31237
|
}
|
|
31238
31238
|
]
|
|
31239
31239
|
},
|
|
31240
|
+
{
|
|
31241
|
+
"id": "openwop.it.v2-eval-trajectory-trials.an-eval-run-brackets-its-scores-with-one-eval-started-and-one-eval-completed-rfc",
|
|
31242
|
+
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31243
|
+
"line": 251,
|
|
31244
|
+
"title": "an eval run brackets its scores with one eval.started and one eval.completed (RFC 0081 §C)",
|
|
31245
|
+
"explicitId": "openwop.requirement.0081.eval-envelope",
|
|
31246
|
+
"citations": [
|
|
31247
|
+
{
|
|
31248
|
+
"section": "run-event-payloads evalStarted / evalCompleted, eval-summary.schema.json (RFC 0081 §C)",
|
|
31249
|
+
"requirement": null,
|
|
31250
|
+
"interpolated": true
|
|
31251
|
+
}
|
|
31252
|
+
]
|
|
31253
|
+
},
|
|
31254
|
+
{
|
|
31255
|
+
"id": "openwop.it.v2-eval-trajectory-trials.the-served-evalsummary-validates-and-its-counts-match-its-rows-rfc-0081-c",
|
|
31256
|
+
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31257
|
+
"line": 259,
|
|
31258
|
+
"title": "the served EvalSummary validates and its counts match its rows (RFC 0081 §C)",
|
|
31259
|
+
"explicitId": "openwop.requirement.0081.summary-served",
|
|
31260
|
+
"citations": [
|
|
31261
|
+
{
|
|
31262
|
+
"section": "run-event-payloads evalStarted / evalCompleted, eval-summary.schema.json (RFC 0081 §C)",
|
|
31263
|
+
"requirement": null,
|
|
31264
|
+
"interpolated": true
|
|
31265
|
+
}
|
|
31266
|
+
]
|
|
31267
|
+
},
|
|
31240
31268
|
{
|
|
31241
31269
|
"id": "openwop.it.v2-eval-trajectory-trials.repeated-trials-emit-one-eval-scored-per-task-per-trial",
|
|
31242
31270
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31243
|
-
"line":
|
|
31271
|
+
"line": 280,
|
|
31244
31272
|
"title": "repeated trials emit one eval.scored per task per trial",
|
|
31245
31273
|
"explicitId": "openwop.requirement.0244.trials-per-task",
|
|
31246
31274
|
"citations": [
|
|
@@ -31258,7 +31286,7 @@
|
|
|
31258
31286
|
{
|
|
31259
31287
|
"id": "openwop.it.v2-eval-trajectory-trials.the-per-task-trials-block-and-trialstats-follow-the-b-formulas",
|
|
31260
31288
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31261
|
-
"line":
|
|
31289
|
+
"line": 291,
|
|
31262
31290
|
"title": "the per-task trials block and trialStats follow the §B formulas",
|
|
31263
31291
|
"explicitId": "openwop.requirement.0244.trial-stats-formula",
|
|
31264
31292
|
"citations": [
|
|
@@ -31297,7 +31325,7 @@
|
|
|
31297
31325
|
{
|
|
31298
31326
|
"id": "openwop.it.v2-eval-trajectory-trials.a-fixture-miss-under-onmiss-fail-fails-the-trial-and-is-counted",
|
|
31299
31327
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31300
|
-
"line":
|
|
31328
|
+
"line": 314,
|
|
31301
31329
|
"title": "a fixture miss under onMiss \"fail\" fails the trial and is counted",
|
|
31302
31330
|
"explicitId": "openwop.requirement.0244.fixture-miss-fails",
|
|
31303
31331
|
"citations": [
|
|
@@ -31334,7 +31362,7 @@
|
|
|
31334
31362
|
{
|
|
31335
31363
|
"id": "openwop.it.v2-eval-trajectory-trials.a-suite-using-an-unadvertised-rfc-0244-feature-is-refused-at-createrun",
|
|
31336
31364
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31337
|
-
"line":
|
|
31365
|
+
"line": 334,
|
|
31338
31366
|
"title": "a suite using an unadvertised RFC 0244 feature is refused at createRun",
|
|
31339
31367
|
"explicitId": "openwop.requirement.0244.unadvertised-feature-refused",
|
|
31340
31368
|
"citations": [
|
|
@@ -31352,7 +31380,7 @@
|
|
|
31352
31380
|
{
|
|
31353
31381
|
"id": "openwop.it.v2-eval-trajectory-trials.under-passrule-mean-a-task-whose-trials-failed-their-trajectory-does-not-pass-rf",
|
|
31354
31382
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31355
|
-
"line":
|
|
31383
|
+
"line": 350,
|
|
31356
31384
|
"title": "under passRule \"mean\" a task whose trials failed their trajectory does not pass (RFC 0246)",
|
|
31357
31385
|
"explicitId": "openwop.requirement.0246.mean-gated",
|
|
31358
31386
|
"citations": [
|
|
@@ -31366,7 +31394,7 @@
|
|
|
31366
31394
|
{
|
|
31367
31395
|
"id": "openwop.it.v2-eval-trajectory-trials.a-suite-whose-tasks-failed-their-trajectory-does-not-pass-on-the-output-scores-r",
|
|
31368
31396
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31369
|
-
"line":
|
|
31397
|
+
"line": 363,
|
|
31370
31398
|
"title": "a suite whose tasks failed their trajectory does not pass on the output scores (RFC 0246)",
|
|
31371
31399
|
"explicitId": "openwop.requirement.0246.suite-gated",
|
|
31372
31400
|
"citations": [
|
|
@@ -31380,7 +31408,7 @@
|
|
|
31380
31408
|
{
|
|
31381
31409
|
"id": "openwop.it.v2-eval-trajectory-trials.a-fixture-entry-marked-iserror-is-replayed-as-a-tool-error-not-a-success-rfc-024",
|
|
31382
31410
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31383
|
-
"line":
|
|
31411
|
+
"line": 374,
|
|
31384
31412
|
"title": "a fixture entry marked isError is replayed as a tool error, not a success (RFC 0245)",
|
|
31385
31413
|
"explicitId": "openwop.requirement.0245.fixture-error-replayed",
|
|
31386
31414
|
"citations": [
|
|
@@ -31394,7 +31422,7 @@
|
|
|
31394
31422
|
{
|
|
31395
31423
|
"id": "openwop.it.v2-eval-trajectory-trials.a-suite-using-iserror-is-refused-at-createrun-without-fixtureerrors-rfc-0245-c",
|
|
31396
31424
|
"file": "v2-eval-trajectory-trials.test.ts",
|
|
31397
|
-
"line":
|
|
31425
|
+
"line": 388,
|
|
31398
31426
|
"title": "a suite using isError is refused at createRun without fixtureErrors (RFC 0245 §C)",
|
|
31399
31427
|
"explicitId": "openwop.requirement.0245.unadvertised-refused",
|
|
31400
31428
|
"citations": [
|
|
@@ -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.20",
|
|
5
|
+
"corpusTag": "v2.46.20",
|
|
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": "14325981296aaf0ab2dcce8aa96527bd68935c1130bd9bf6103ee6b6c4df4f8e",
|
|
13
|
+
"api/v2/asyncapi.yaml": "b5f5369bbb35a2c3c75ff6c4f6c9281e77b141dd1d21e9495fef670d72b74a5b",
|
|
14
|
+
"api/v2/openapi.yaml": "3b17112c01e94987b0cef6a328cc9a6d3a0c0521bbafb14b1fc8abb4e10d9091",
|
|
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": "d70cc792bd36812bfcec84c6a8b0d2cd096a3fbed19967afbc8f1dd1a7d26d87",
|
|
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": "4655f3087d9917f3b6b7612af23c86a1b338c732a9c1a72ee4a705a1b4f4f7a9",
|
|
219
219
|
"spec/v1/gaps.schema.json": "8fd83259f556553c9df0f53e7a82ca8c2a4771d471197f69b4e2ae0ceeacfd66",
|
|
220
220
|
"spec/v1/migrations.json": "4c50760be70cb644d02427bcaf5749606700edf4513f423903cf3b1d12f5c300",
|
|
221
221
|
"spec/v1/migrations.schema.json": "886779aa6c22e646db097f5df210adb018a4dd14a7b815465a18c8a7056c8f72",
|
|
@@ -314,9 +314,9 @@
|
|
|
314
314
|
"spec/v2/path-manifest.json": "7b5679a4dad98c80d855361d88a98c8a4e045af15e310862a05b285b815dc9fc",
|
|
315
315
|
"spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
|
|
316
316
|
"spec/v2/profiles.json": "b382b261c7844798575f7c1b37c934f0da19846016a2337d883d4f5ef6e05479",
|
|
317
|
-
"spec/v2/release.json": "
|
|
317
|
+
"spec/v2/release.json": "a8b6d20a4ed90b21b4f9feb57a9c2ec5fdb13c74a74f857e5e3aec5ee8e75e40",
|
|
318
318
|
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
|
|
319
|
-
"spec/v2/surface-baseline.json": "
|
|
319
|
+
"spec/v2/surface-baseline.json": "c5aee6bbf8011e11351a4f9e0aafaf444d60af55116c543f04b55b88878cdf83"
|
|
320
320
|
},
|
|
321
|
-
"corpusCommit": "
|
|
321
|
+
"corpusCommit": "3ed6fc93890b4d00c44aafc0fe3ce75a24b8dcc7"
|
|
322
322
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 0081 §C — the `eval.*` envelope of an eval run, and the summary it
|
|
3
|
+
* serves. A pure judge over one eval run, for
|
|
4
|
+
* `v2-eval-trajectory-trials.test.ts`.
|
|
5
|
+
*
|
|
6
|
+
* The rules are the `run-event-payloads` descriptions, which the `agents`
|
|
7
|
+
* family lists as normative text:
|
|
8
|
+
* - `evalStarted` — emitted ONCE, at the start of the run;
|
|
9
|
+
* - `evalScored` — once per task (per trial under RFC 0244 §B);
|
|
10
|
+
* - `evalCompleted` — emitted ONCE, after all tasks and before
|
|
11
|
+
* `run.completed`; its aggregates describe the same run the summary does.
|
|
12
|
+
* The served `EvalSummary` validates against `eval-summary.schema.json`.
|
|
13
|
+
*
|
|
14
|
+
* Until 2.46.20 no v2 leg read `eval.completed`; the frozen v1
|
|
15
|
+
* `agent-eval-run.test.ts` did (RFC 0081 correction note, 2026-10-24).
|
|
16
|
+
*
|
|
17
|
+
* @see RFCS/0081-agent-evaluation-and-scorecards.md
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface EnvelopeFinding { readonly ok: boolean; readonly doc: string; readonly message: string }
|
|
21
|
+
|
|
22
|
+
type Rec = Record<string, unknown>;
|
|
23
|
+
interface Event { readonly type: string; readonly sequence: number; readonly payload: Rec }
|
|
24
|
+
|
|
25
|
+
const isRec = (v: unknown): v is Rec => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
26
|
+
const f = (ok: boolean, doc: string, message: string): EnvelopeFinding => ({ ok, doc, message });
|
|
27
|
+
|
|
28
|
+
const C = 'run-event-payloads evalStarted / evalScored / evalCompleted (RFC 0081 §C)';
|
|
29
|
+
|
|
30
|
+
export interface EnvelopeOptions {
|
|
31
|
+
/** Validates an `eval.completed` payload against `run-event-payloads#/$defs/evalCompleted`. */
|
|
32
|
+
readonly completedValid: (payload: unknown) => { ok: boolean; errors: string };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function judgeEvalEnvelope(events: readonly Event[], summary: Rec, opts: EnvelopeOptions): EnvelopeFinding[] {
|
|
36
|
+
const ordered = [...events].sort((a, b) => a.sequence - b.sequence);
|
|
37
|
+
const at = (type: string): number[] => ordered.flatMap((e, i) => (e.type === type ? [i] : []));
|
|
38
|
+
const started = at('eval.started');
|
|
39
|
+
const scored = at('eval.scored');
|
|
40
|
+
const completed = at('eval.completed');
|
|
41
|
+
const runCompleted = at('run.completed');
|
|
42
|
+
const out: EnvelopeFinding[] = [];
|
|
43
|
+
|
|
44
|
+
out.push(f(started.length === 1, C, `eval.started MUST be emitted once (got ${started.length})`));
|
|
45
|
+
out.push(f(completed.length === 1, C, `eval.completed MUST be emitted once (got ${completed.length})`));
|
|
46
|
+
out.push(f(scored.length > 0, C, 'the run MUST emit eval.scored for its tasks'));
|
|
47
|
+
if (started.length === 1 && scored.length > 0) {
|
|
48
|
+
out.push(f(started[0]! < scored[0]!, C, 'eval.started MUST precede every eval.scored'));
|
|
49
|
+
}
|
|
50
|
+
if (completed.length !== 1) return out;
|
|
51
|
+
const c = completed[0]!;
|
|
52
|
+
if (scored.length > 0) out.push(f(c > scored[scored.length - 1]!, C, 'eval.completed MUST follow every eval.scored ("after all tasks")'));
|
|
53
|
+
if (runCompleted.length > 0) out.push(f(c < runCompleted[0]!, C, 'eval.completed MUST precede run.completed'));
|
|
54
|
+
|
|
55
|
+
const payload = ordered[c]!.payload;
|
|
56
|
+
const v = opts.completedValid(payload);
|
|
57
|
+
out.push(f(v.ok, C, `eval.completed MUST validate: ${v.errors}`));
|
|
58
|
+
for (const k of ['taskCount', 'passedCount', 'passed'] as const) {
|
|
59
|
+
if (k in summary) out.push(f(payload[k] === summary[k], C, `eval.completed.${k} MUST equal the served summary's (event ${JSON.stringify(payload[k])}, summary ${JSON.stringify(summary[k])})`));
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The served summary validates, and its per-task rows agree with its own counts. */
|
|
65
|
+
export function judgeSummaryServed(summary: Rec, valid: (s: unknown) => { ok: boolean; errors: string }): EnvelopeFinding[] {
|
|
66
|
+
const out: EnvelopeFinding[] = [];
|
|
67
|
+
const v = valid(summary);
|
|
68
|
+
out.push(f(v.ok, 'eval-summary.schema.json (RFC 0081 §C)', `the served EvalSummary MUST validate: ${v.errors}`));
|
|
69
|
+
const tasks = Array.isArray(summary['tasks']) ? (summary['tasks'] as unknown[]).filter(isRec) : [];
|
|
70
|
+
out.push(f(summary['taskCount'] === tasks.length, 'eval-summary.schema.json (RFC 0081 §C)', `taskCount MUST equal the number of tasks (got ${JSON.stringify(summary['taskCount'])}, ${tasks.length} tasks)`));
|
|
71
|
+
const passed = tasks.filter((t) => t['passed'] === true).length;
|
|
72
|
+
out.push(f(summary['passedCount'] === passed, 'eval-summary.schema.json (RFC 0081 §C)', `passedCount MUST count the passed tasks (got ${JSON.stringify(summary['passedCount'])}, ${passed} passed)`));
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
@@ -32,6 +32,13 @@
|
|
|
32
32
|
* lists `conformance-eval-trials` refuses it at createRun with
|
|
33
33
|
* `400 validation_error`.
|
|
34
34
|
*
|
|
35
|
+
* RFC 0081 §C, on the `conformance-eval-trajectory` run (2.46.20). Judges in
|
|
36
|
+
* `lib/eval-envelope-witness.ts`.
|
|
37
|
+
* - `eval.started` and `eval.completed` are emitted once each, bracketing
|
|
38
|
+
* every `eval.scored`, and `eval.completed` precedes `run.completed`; its
|
|
39
|
+
* counts equal the served summary's.
|
|
40
|
+
* - The served `EvalSummary` validates, and its counts match its rows.
|
|
41
|
+
*
|
|
35
42
|
* RFC 0246 (safety fix): a trial that failed its trajectory counts 0 in the
|
|
36
43
|
* two pass decisions, while every reported score is unchanged. Judges in
|
|
37
44
|
* `lib/eval-gate-witness.ts`.
|
|
@@ -73,6 +80,7 @@ import { majorProfile } from '../lib/major-profile.js';
|
|
|
73
80
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
74
81
|
import { FIXTURES_DIR } from '../lib/paths.js';
|
|
75
82
|
import { pollTerminal, readEvents, isRecord, type Ev } from '../lib/fixture-run-observer.js';
|
|
83
|
+
import { judgeEvalEnvelope, judgeSummaryServed } from '../lib/eval-envelope-witness.js';
|
|
76
84
|
import { gradeTrajectory, passAtK, passHatK, scoreStderr, withinTolerance, type TrajectorySpec } from '../lib/eval-trajectory.js';
|
|
77
85
|
import { judgeMeanGated, judgeSuiteGated } from '../lib/eval-gate-witness.js';
|
|
78
86
|
import { judgeFixtureErrorReplayed } from '../lib/eval-fixture-error-witness.js';
|
|
@@ -97,6 +105,9 @@ const DOC_0246 = 'eval-summary.schema.json gatedScore / gatedAggregateScore (RFC
|
|
|
97
105
|
const ID_FIXTURE_ERROR_SHAPE = 'openwop.requirement.0245.fixture-error-shape';
|
|
98
106
|
const ID_FIXTURE_ERROR = 'openwop.requirement.0245.fixture-error-replayed';
|
|
99
107
|
const ID_FIXTURE_ERROR_REFUSED = 'openwop.requirement.0245.unadvertised-refused';
|
|
108
|
+
const ID_ENVELOPE = 'openwop.requirement.0081.eval-envelope';
|
|
109
|
+
const ID_SUMMARY = 'openwop.requirement.0081.summary-served';
|
|
110
|
+
const DOC_0081 = 'run-event-payloads evalStarted / evalCompleted, eval-summary.schema.json (RFC 0081 §C)';
|
|
100
111
|
const DOC_0245 = 'agents.schema.json §evalSuite.fixtureErrors (RFC 0245)';
|
|
101
112
|
|
|
102
113
|
interface Task { taskId: string; input: { script: Array<{ tool: string; arguments?: unknown }>; output: string }; expected: { kind: string; trajectory?: TrajectorySpec }; fixtures?: { toolResponses?: Array<Record<string, unknown>> } }
|
|
@@ -107,6 +118,7 @@ const suiteSchema = v2Validator('agent-eval-suite');
|
|
|
107
118
|
const summarySchema = v2Validator('eval-summary');
|
|
108
119
|
const scored = v2RefValidator('run-event-payloads.schema.json#/$defs/evalScored');
|
|
109
120
|
const started = v2RefValidator('run-event-payloads.schema.json#/$defs/evalStarted');
|
|
121
|
+
const completedPayload = v2RefValidator('run-event-payloads.schema.json#/$defs/evalCompleted');
|
|
110
122
|
|
|
111
123
|
async function http(fn: () => Promise<OpenWOPResponse>): Promise<OpenWOPResponse | null> {
|
|
112
124
|
try { return await fn(); } catch { return null; }
|
|
@@ -225,6 +237,33 @@ describe('v2 RFC 0244 — host behaviour', () => {
|
|
|
225
237
|
expect(calls, req(ID_TRAJECTORY, DOC, `the log MUST carry one agent.tool-called per scripted call (${scripted})`)).toBe(scripted);
|
|
226
238
|
});
|
|
227
239
|
|
|
240
|
+
async function trajectoryRun(): Promise<{ skip: [Parameters<typeof softSkip>[0], string] } | { o: Extract<Observed, { kind: 'ok' }> }> {
|
|
241
|
+
const { doc, facet } = await evalSuiteFacet();
|
|
242
|
+
if (!doc) return { skip: ['blocked', UNREADABLE] };
|
|
243
|
+
if (facet?.['trajectory'] !== true) return { skip: ['inapplicable', 'the host does not advertise agents.evalSuite.trajectory'] };
|
|
244
|
+
const id = 'conformance-eval-trajectory';
|
|
245
|
+
if (!isFixtureAdvertised(id)) return { skip: ['inapplicable', `the host does not advertise fixture ${id}`] };
|
|
246
|
+
const o = await runSuite(id);
|
|
247
|
+
if (o.kind === 'skip') return { skip: [o.disposition, o.reason] };
|
|
248
|
+
return { o };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
it('an eval run brackets its scores with one eval.started and one eval.completed (RFC 0081 §C)', async () => {
|
|
252
|
+
const r = await trajectoryRun();
|
|
253
|
+
if ('skip' in r) return softSkip(...r.skip);
|
|
254
|
+
for (const x of judgeEvalEnvelope(r.o.events, r.o.summary, { completedValid: completedPayload })) {
|
|
255
|
+
expect(x.ok, req(ID_ENVELOPE, DOC_0081, x.message)).toBe(true);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('the served EvalSummary validates and its counts match its rows (RFC 0081 §C)', async () => {
|
|
260
|
+
const r = await trajectoryRun();
|
|
261
|
+
if ('skip' in r) return softSkip(...r.skip);
|
|
262
|
+
for (const x of judgeSummaryServed(r.o.summary, summarySchema)) {
|
|
263
|
+
expect(x.ok, req(ID_SUMMARY, DOC_0081, x.message)).toBe(true);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
228
267
|
async function trialsRun(): Promise<{ skip: [Parameters<typeof softSkip>[0], string] } | { o: Extract<Observed, { kind: 'ok' }>; suite: Suite; n: number; k: number }> {
|
|
229
268
|
const { doc, facet } = await evalSuiteFacet();
|
|
230
269
|
if (!doc) return { skip: ['blocked', UNREADABLE] };
|