@openwop/openwop-conformance 2.42.7 → 2.42.9

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,5 +1,26 @@
1
1
  # `@openwop/openwop-conformance` Changelog
2
2
 
3
+ ## [2.42.9] — 2026-09-28 — a v2 delivery's workspaceId is checked, and two test-isolation and SHOULD-strength fixes
4
+
5
+ - **Scenario files that share a mock-AI node no longer race.** The mock-AI program hook is keyed by node id, and a node id belongs to a fixture. `envelope-completion-distinguishes-truncation` drives both envelope fixtures that `envelope-truncated` and `envelope-retry-attempted` also drive, so under the default parallel run one file could overwrite another's program. New `lib/mock-node-lock.ts` holds a cross-process lock per node id for the whole file, so files sharing a node run one after another. Serial runs (`--certify`, openwop-app's harness) are unchanged.
6
+ - **The RFC 0033 §B truncation budget legs compare real attempts and record the SHOULD.** Both legs asserted "retry budget > 50" (the fixture's value) as a MUST. §B makes the retry a MAY and the larger budget a SHOULD, so the old legs failed a conforming host that retried at the same budget and passed a host that ignored the fixture's `maxTokens`. They now read the first and retry budgets through the `dispatch-budgets` hook. A larger retry budget passes, and an unmet SHOULD is recorded as `inapplicable` with the observed values. An unserved hook is a partial witness. On openwop-app the rows are identical before and after, and the truncation leg passes with a real comparison.
7
+ - **`v2-webhook-delivery-shape` checks that `workspaceId` is present exactly when the run has a workspace.** `webhooks.md` §Delivery requires it and forbids substituting a value, but the leg only validated the schema, which cannot say "exactly when". It now compares the delivered `workspaceId` with the owner echo on the event. The v2 reference host sent `"default"` and fails without openwop-examples #99 (fixed there); openwop-app already conformed.
8
+ - **`--help` says `--bundle-version` defaults to 3** (#1693). The code has defaulted to 3 since 2.0.0-rc.1 and the deprecation note for `2` already said so; the help text still read `Default 2`.
9
+ - **Suite `2.42.9`**. `@openwop/spec-artifacts` moves in lockstep at the same exact pin.
10
+
11
+ ## [2.42.8] — 2026-09-27 — RFC 0221, a closed audit schema again, and a dispatch race fixed
12
+
13
+ - **`v2-preferred-version-default`: a header-less request on an unversioned operation path is served major 2.** This follows a Class 3 correction to `versioning.md` §1.3: the `preferredVersion` default applies to `/.well-known/openwop` only. The new leg reads `OpenWOP-Version` on a header-less `GET /runs/{unknown}`. It passes on the v2 reference host and fails when the host applies `preferredVersion` to every path.
14
+ - **RFC 0221: a webhook secret the host generates is returned once.** New `v2-webhook-generated-secret.test.ts` (target major 2, gated on the `webhooks` family and `conformance-noop`). It registers without a secret, and the `201` must carry the generated `secret`. A real `run.completed` delivery must then verify under it (`OpenWOP-Signature`, scheme `v1`), and a supplied secret must not be echoed. Witnessed on the v2 reference host with openwop-examples #98; its previous code, which withheld the secret, fails the row.
15
+ - **The 2.42.8 cycle opens.** RFC 0189 (#1675) changed the packed `@openwop/spec-artifacts` tree (`spec/v2/core/i18n.md`, `spec/v2/core/portability.md`, `declaration.json`) after `v2.42.7` was tagged. The published-identity gate correctly refused to call that tree 2.42.7.
16
+ - **RFC 0219 `Active`: `OpenWOP-Client-Version` is declared, and the floor's refusal has an input.** New `v2-client-version-header` (major 2, four legs, requirement ids `openwop.requirement.0219.*`). `floor-comparison` (gated on `minClientVersion`): `<floor>`, `<floor>.0` and `<floor>.99` are served, never `426`. `malformed-not-refused` (gated on a host that refuses `0.0.1` with `426`): `not-a-version`, `1`, `01.0` and `1.0-rc.1` are served, never `426` or `400`; a host that serves `0.0.1` records `inapplicable`. `absent-not-refused`: a header-less request is never `426` on any host, and is served on a host that refuses `0.0.1`. `no-floor-no-refusal`: a host advertising no `minClientVersion` serves `0.0.1`. Sabotage-proved against a stub host implementing `versioning.md` §1.5 exactly: malformed-read-as-`0.0`, malformed-`400`, at-floor refused, a patch-bearing value refused `400`, header-less refused and no-floor-`426` each turn their leg `executed-fail`. **The v2 reference host and openwop-app read a malformed value as `0.0` and refuse it today; the malformed leg fails on both until their fixes land** (RFC 0219 gap G1).
17
+ - **`v2-min-client-version`: a non-`2xx`, non-`426` answer to `0.0.1` is a failure, not `blocked`** (RFC 0219 decision 4), now that the header is declared. When a refusal carries `details.minClientVersion`, it must equal the advertised floor (decision 5). Sabotaged: a `403` refusal and a `details.minClientVersion` of `0.9` against a `1.0` floor each fail the leg; a `details.minClientVersion` outside the axis-1 grammar fails the envelope check.
18
+ - **The v2 error envelope binds a registered `details` schema to its own code.** `schemas/v2/error-envelope.schema.json` (generated by `scripts/generate-error-envelope.mjs`) put every registered `details` schema and an open fallback in one `oneOf`. A conforming body matched two branches, so every envelope carrying registered `details` (`run_state_conflict` with `details.runStatus`, `unsupported_stream_mode` with `details.supported`) failed validation. The envelope now uses `allOf` of `if error == <code> then details: <schema>`. `client_version_unsupported` registers OPTIONAL `details.minClientVersion` (RFC 0219 decision 5).
19
+ - **`audit-log-integrity` validates the verify body against the CLOSED `audit-verify-result.schema.json` again.** The in-test relaxation that stripped every `additionalProperties: false` is gone. It existed because the postgres and sqlite reference hosts put a per-checkpoint `verified` bit on the wire, which the schema's `Checkpoint` does not name. That bit is host-internal (the aggregate verdict is the schema's OPTIONAL `checkpointsValid`), and the hosts now drop it (openwop-examples#96). Sabotaged: a host that emits `verified` fails with `must NOT have additional properties`.
20
+ - **RFC 0033 §C's budget rule is witnessable per attempt.** New OPTIONAL seam `GET …/test/mock-ai/dispatch-budgets` (`host-sample-test-seams.md` §28; `api/seams-v2.yaml` `getMockDispatchBudgets`) returns every mock-provider call's `maxTokens` for a node, in call order. `last-dispatch-budget` kept only the latest call. The `conformance-envelope-retry-attempted` fixture now sets `maxTokens: 256`, so attempt 1 carries a budget. The schema-violation leg of `envelope-completion-distinguishes-truncation` now requires that no retry's budget exceeds the attempt before it; before, it only range-checked the last budget (`< 20000`). Dispositions: seam served → real assertion (a host that sized the retry from the run's accumulated budget, 256 → 512, records `executed-fail`); served but contract broken → `blocked`; not served → partial witness, never `blocked`.
21
+ - **`v2-id-grammar`'s events leg waits for an event instead of racing the dispatch.** It made one 1-second poll straight after creating the run, and recorded `blocked`, which is bundle-fatal, when the host had not yet recorded an event. A host that queues runs, as MyndHyve does through Cloud Tasks, legitimately has none at that instant. MyndHyve's cut 3 on 2.42.7 was denied certification by this row alone. The leg now polls until an event exists, within a scaled 20-second deadline.
22
+ - **Suite `2.42.8`**. `@openwop/spec-artifacts` moves in lockstep at the same exact pin.
23
+
3
24
  ## [2.42.7] — 2026-09-27 — audit residuals, and extension families can graduate on evidence
4
25
 
5
26
  - **`v2-sse-last-event-id-cursor` joins the core-standard floor.** It was held off until the three bundle hosts were measured. All three record it `executed-pass`: the v2 reference host on 2.42.2, MyndHyve on 2.42.0 and openwop-app on 2.42.2. Two carry `partial-witness` only on the SHOULD leg (a malformed `Last-Event-ID` is accepted, which is recorded rather than failed). No existing claim moves.
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  # --legacy-peer-deps is REQUIRED, not optional: the exact peer pin is what npm's
12
12
  # default resolver refuses. npm 10.9 fails outright with
13
13
  # "Cannot read properties of null (reading 'edgesOut')" — use npm >= 11.
14
- npm install --legacy-peer-deps @openwop/openwop-conformance@2.42.7 @openwop/spec-artifacts@2.42.7
14
+ npm install --legacy-peer-deps @openwop/openwop-conformance@2.42.9 @openwop/spec-artifacts@2.42.9
15
15
  # or run without install:
16
16
  npx @openwop/openwop-conformance --base-url https://api.example.com --api-key hk_test_...
17
17
  ```
@@ -135,7 +135,7 @@ Exit code is non-zero on any failed assertion. `--certify` distinguishes: `0`
135
135
 
136
136
  ## What's Covered
137
137
 
138
- The current suite has 565 scenario files under `src/scenarios/`.
138
+ The current suite has 567 scenario files under `src/scenarios/`.
139
139
  - 2026-09-23 (suite 2.37.0 cycle, RFC 0213): NEW `v2-sse-last-event-id-cursor.test.ts` (a `Last-Event-ID` past the log is an exclusive cursor; a malformed id, when refused, is `400 validation_error`; the cursor never changes the answer for an unknown or foreign-tenant run — public test of `event-cursor-after-authorization`), `v2-idempotency-in-flight.test.ts` (five concurrent same-key creates yield one run; each loser is a marked replay or `409 idempotency_in_flight` with no retry timing in `details`; `partial-witness` when no loser was refused in flight) and `v2-interrupt-resolve-terminal.test.ts` (a run-scoped resolve after cancel or completion is `409 interrupt_already_resolved`, never `interrupt_cancelled`). All three sit off the core-standard floor until measured on the three bundle hosts.
140
140
  - 2026-09-03 (suite `1.157.0 -> 1.158.0`, gap G17): NEW `idempotency-concurrent-claim.test.ts` — drives the new `host-sample-test-seams.md` §25 concurrent duplicate-delivery seam for the RFC 0150 §B / `idempotency.md` §"Concurrent duplicates (Layer 2)" atomic-claim MUST, which is unconditional and had no witness of any kind. Asserts every executor mints the SAME `logicalInvocationId` **before** asserting `delivered === 1` — without the identity check a host passes by minting different ids and never colliding, one effect because nothing raced. Not profile-gated and so not opt-out-able (the obligation is unconditional); an unmounted seam records `blocked`, which is not certifiable. Graduates `layer2-invocation-claim-atomic` reference-impl -> protocol.
141
141
  - 2026-08-19 (suite `1.137.0 → 1.138.0`): NEW `durability-poison-exhaustion.test.ts` — RFC 0158 §C.8, the FIRST row of that RFC's conformance table to land. Asserts what `failure-path.test.ts` cannot: not just that deterministically failing work reaches terminal, but that attempts STOP — counted on the log, re-counted after a scaled quiet window, asserted unchanged. A host still redelivering records more. Seam-gated on the existing event-log seam (`blocked` = unobservable, not unmet) and outside every profile floor.
@@ -481,7 +481,7 @@ Server-required (added in 1.7.0):
481
481
  | ------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
482
482
  | **Redaction** | [`capabilities.md`](../spec/v1/capabilities.md) §"Secrets" + NFR-7 + §"aiProviders" | Vendor-neutral assertions that the server doesn't leak secret material. Three scenario groups: (a) discovery shape contract — `secrets` + `aiProviders` advertisements are well-formed regardless of `secrets.supported`; when `supported === true`, scopes MUST be non-empty + `resolution === 'host-managed'`; `byok ⊆ supported`. (b) bearer-token redaction — invalid Bearer canary in `Authorization` header is not echoed in the 401 response body. (c) credentialRef echo control — gated on `secrets.supported === true`; canary planted in `configurable.ai.credentialRef` MUST NOT appear in any RunEvent payload (poll-based capture; transport-agnostic). Uses runtime-built canary fixtures (`lib/canaries.ts`) that defeat static secret scanners. 6 scenarios. |
483
483
 
484
- Current source tree: 565 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
484
+ Current source tree: 567 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
485
485
 
486
486
  ## Remaining Gaps
487
487
 
package/dist/cli.js CHANGED
@@ -60,9 +60,8 @@ function parseArgs(argv) {
60
60
  let impl;
61
61
  let implVersion;
62
62
  let certify;
63
- // Suite 1.152.0: bundle v2 (RFC 0148) is the default. v1 stays reachable via
64
- // `--bundle-version 1` through the RFC 0148 migration window (ends
65
- // 2026-11-10) and is removed at v2.0 (spec/v1/deprecations.json).
63
+ // Suite 2.0.0-rc.1: bundle v3 (RFC 0168 §E) is the default. v2 stays reachable
64
+ // via `--bundle-version 2`, deprecated (RFC 0168 §E.3); v1 is gone.
66
65
  let bundleVersion = '3';
67
66
  let hostBuild;
68
67
  let evidenceTier = 'self';
@@ -265,7 +264,7 @@ Certification (RFC 0089):
265
264
  --signing-key <pem> v3: Ed25519 private key (PKCS8 PEM) that signs the bundle, or OPENWOP_BUNDLE_SIGNING_KEY.
266
265
  --signing-key-id <id> v3: the keyId the host publishes for that key, or OPENWOP_BUNDLE_SIGNING_KEY_ID.
267
266
  --evidence-tier <t> v3: self | steward | independent (independent needs --verifier-key/--verifier-key-id).
268
- --bundle-version <2|3> Certification bundle format. Default 2 (corrected 2026-09-03, RFC 0168 §E.4; the text said 1 while the code set 2). Version 2 (RFC 0148
267
+ --bundle-version <2|3> Certification bundle format. Default 3 (since suite 2.0.0-rc.1; 2 is DEPRECATED, RFC 0168 §E.3). Version 2 (RFC 0148
269
268
  §C) records per-requirement DISPOSITIONS instead of pass/fail/skip
270
269
  file lists, so "we could not check" stops being indistinguishable
271
270
  from "checked and it holds". See the note it prints.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.42.7",
4
- "stampSha256": "8f82b45d0b4004faf11a49d998e0bebefd3ad7a89d82e67322aabafcd18544a1"
3
+ "version": "2.42.9",
4
+ "stampSha256": "e7d8fb98741be5d68706bbe33d3e4c1509af29bd13bfd0f7b241f93270b4af89"
5
5
  }
@@ -2,7 +2,7 @@
2
2
  "id": "conformance-envelope-retry-attempted",
3
3
  "name": "Conformance: envelope.retry.attempted (RFC 0032 §B.1)",
4
4
  "version": "1.0",
5
- "description": "Drives `core.ai.structuredOutput` against the conformance-only `mock` provider. The conformance scenario POSTs a 2-entry program to `/v1/host/sample/test/mock-ai/program` (keyed by `nodeId: 'retry-attempted-structured-call'`) BEFORE starting the run: attempt 1 returns invalid JSON, attempt 2 returns a valid envelope. The host's `dispatchStructured` retry loop MUST emit exactly one `envelope.retry.attempted` event with `attempt: 2` between the two provider calls (RFC 0032 §B.1). The run terminates `completed` after the second attempt succeeds.",
5
+ "description": "Drives `core.ai.structuredOutput` against the conformance-only `mock` provider. The conformance scenario POSTs a 2-entry program to `/v1/host/sample/test/mock-ai/program` (keyed by `nodeId: 'retry-attempted-structured-call'`) BEFORE starting the run: attempt 1 returns invalid JSON, attempt 2 returns a valid envelope. The host's `dispatchStructured` retry loop MUST emit exactly one `envelope.retry.attempted` event with `attempt: 2` between the two provider calls (RFC 0032 §B.1). The run terminates `completed` after the second attempt succeeds. `maxTokens: 256` gives attempt 1 a concrete output budget, so `envelope-completion-distinguishes-truncation` can compare each attempt's budget through the `mock-ai/dispatch-budgets` seam (host-sample-test-seams.md §28): a schema-violation retry MUST NOT carry a larger budget than the attempt before it (RFC 0033 §C).",
6
6
  "nodes": [
7
7
  {
8
8
  "id": "retry-attempted-structured-call",
@@ -12,6 +12,7 @@
12
12
  "config": {
13
13
  "provider": "mock",
14
14
  "model": "mock-mini",
15
+ "maxTokens": 256,
15
16
  "outputSchema": {
16
17
  "type": "object",
17
18
  "required": ["valid"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.42.7",
3
+ "version": "2.42.9",
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.42.7"
59
+ "@openwop/spec-artifacts": "2.42.9"
60
60
  }
61
61
  }
package/requirements.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "$comment": "GENERATED by conformance/scripts/generate-requirement-registry.mjs — do not edit. One record per it()/test() in src/scenarios. Ids: openwop.it.<file-stem>.<title-slug>[~n] (src/lib/requirement-ids.ts). A record with id null has an interpolated title; its run-time row is keyed by the rendered title and maps here by file+line only. Renamed ids need a row in requirement-aliases.json.",
3
3
  "generatedFrom": "src/scenarios/*.test.ts",
4
4
  "counts": {
5
- "files": 640,
6
- "tests": 2460,
7
- "withStableId": 2460,
5
+ "files": 642,
6
+ "tests": 2466,
7
+ "withStableId": 2466,
8
8
  "interpolatedTitles": 0,
9
- "explicitIds": 2350
9
+ "explicitIds": 2356
10
10
  },
11
11
  "records": [
12
12
  {
@@ -5534,7 +5534,7 @@
5534
5534
  {
5535
5535
  "id": "openwop.it.audit-log-integrity.host-that-claims-the-profile-advertises-required-capability-fields",
5536
5536
  "file": "audit-log-integrity.test.ts",
5537
- "line": 69,
5537
+ "line": 60,
5538
5538
  "title": "host that claims the profile advertises required capability fields",
5539
5539
  "explicitId": "openwop.it.audit-log-integrity.host-that-claims-the-profile-advertises-required-capability-fields",
5540
5540
  "citations": [
@@ -5551,7 +5551,7 @@
5551
5551
  {
5552
5552
  "id": "openwop.it.audit-log-integrity.get-v1-audit-verify-on-a-recent-range-reports-chainvalid-true",
5553
5553
  "file": "audit-log-integrity.test.ts",
5554
- "line": 92,
5554
+ "line": 83,
5555
5555
  "title": "GET /v1/audit/verify on a recent range reports chainValid: true",
5556
5556
  "explicitId": "openwop.it.audit-log-integrity.get-v1-audit-verify-on-a-recent-range-reports-chainvalid-true",
5557
5557
  "citations": [
@@ -11541,7 +11541,7 @@
11541
11541
  {
11542
11542
  "id": "openwop.it.envelope-completion-distinguishes-truncation.capabilities-envelopes-reliability-completion-when-present-conforms-to-rfc-0033",
11543
11543
  "file": "envelope-completion-distinguishes-truncation.test.ts",
11544
- "line": 103,
11544
+ "line": 108,
11545
11545
  "title": "capabilities.envelopes.reliability.completion (when present) conforms to RFC 0033 §E",
11546
11546
  "explicitId": "openwop.it.envelope-completion-distinguishes-truncation.capabilities-envelopes-reliability-completion-when-present-conforms-to-rfc-0033",
11547
11547
  "citations": [
@@ -11558,7 +11558,7 @@
11558
11558
  {
11559
11559
  "id": "openwop.it.envelope-completion-distinguishes-truncation.truncation-emits-envelope-truncated-envelope-retry-attempted-with-reason-truncat",
11560
11560
  "file": "envelope-completion-distinguishes-truncation.test.ts",
11561
- "line": 126,
11561
+ "line": 131,
11562
11562
  "title": "truncation: emits envelope.truncated + envelope.retry.attempted with reason: \"truncation\"",
11563
11563
  "explicitId": "openwop.it.envelope-completion-distinguishes-truncation.truncation-emits-envelope-truncated-envelope-retry-attempted-with-reason-truncat",
11564
11564
  "citations": [
@@ -11579,20 +11579,21 @@
11579
11579
  {
11580
11580
  "id": "openwop.it.envelope-completion-distinguishes-truncation.truncation-retry-budget-strictly-greater-than-initial-rfc-0033-b-truncationbudge",
11581
11581
  "file": "envelope-completion-distinguishes-truncation.test.ts",
11582
- "line": 151,
11582
+ "line": 156,
11583
11583
  "title": "truncation: retry budget strictly greater than initial (RFC 0033 §B truncationBudgetMultiplier)",
11584
11584
  "explicitId": "openwop.it.envelope-completion-distinguishes-truncation.truncation-retry-budget-strictly-greater-than-initial-rfc-0033-b-truncationbudge",
11585
11585
  "citations": [
11586
11586
  {
11587
11587
  "section": "RFCS/0033-envelope-completion-contract.md §B",
11588
- "requirement": "truncation retry MUST multiply maxTokens by truncationBudgetMultiplier — final budget > initial 50 fixture value"
11588
+ "requirement": null,
11589
+ "interpolated": true
11589
11590
  }
11590
11591
  ]
11591
11592
  },
11592
11593
  {
11593
11594
  "id": "openwop.it.envelope-completion-distinguishes-truncation.schema-violation-no-envelope-truncated-envelope-retry-attempted-reason-schema-vi",
11594
11595
  "file": "envelope-completion-distinguishes-truncation.test.ts",
11595
- "line": 175,
11596
+ "line": 185,
11596
11597
  "title": "schema-violation: NO envelope.truncated; envelope.retry.attempted reason ∈ {schema-violation, parse-error}",
11597
11598
  "explicitId": "openwop.it.envelope-completion-distinguishes-truncation.schema-violation-no-envelope-truncated-envelope-retry-attempted-reason-schema-vi",
11598
11599
  "citations": [
@@ -11609,13 +11610,18 @@
11609
11610
  {
11610
11611
  "id": "openwop.it.envelope-completion-distinguishes-truncation.schema-violation-retry-budget-unchanged-from-initial-no-budget-multiplication-on",
11611
11612
  "file": "envelope-completion-distinguishes-truncation.test.ts",
11612
- "line": 205,
11613
+ "line": 215,
11613
11614
  "title": "schema-violation: retry budget UNCHANGED from initial (no budget multiplication on this path)",
11614
11615
  "explicitId": "openwop.it.envelope-completion-distinguishes-truncation.schema-violation-retry-budget-unchanged-from-initial-no-budget-multiplication-on",
11615
11616
  "citations": [
11616
11617
  {
11617
11618
  "section": "RFCS/0033-envelope-completion-contract.md §C",
11618
11619
  "requirement": "schema-violation retry MUST NOT multiply maxTokens — budget stays at the original value (host default)"
11620
+ },
11621
+ {
11622
+ "section": "RFCS/0033-envelope-completion-contract.md §C",
11623
+ "requirement": null,
11624
+ "interpolated": true
11619
11625
  }
11620
11626
  ]
11621
11627
  },
@@ -12256,7 +12262,7 @@
12256
12262
  {
12257
12263
  "id": "openwop.it.envelope-retry-attempted.when-mock-llm-emits-invalid-envelope-on-attempt-1-then-valid-on-attempt-2-exactl",
12258
12264
  "file": "envelope-retry-attempted.test.ts",
12259
- "line": 158,
12265
+ "line": 162,
12260
12266
  "title": "when mock LLM emits invalid envelope on attempt 1 then valid on attempt 2, exactly one `envelope.retry.attempted` event fires before the second attempt",
12261
12267
  "explicitId": "openwop.it.envelope-retry-attempted.when-mock-llm-emits-invalid-envelope-on-attempt-1-then-valid-on-attempt-2-exactl",
12262
12268
  "citations": [
@@ -12269,7 +12275,7 @@
12269
12275
  {
12270
12276
  "id": "openwop.it.envelope-retry-attempted.event-payload-carries-attempt-2-1-indexed-first-attempt-does-not-emit",
12271
12277
  "file": "envelope-retry-attempted.test.ts",
12272
- "line": 179,
12278
+ "line": 183,
12273
12279
  "title": "event payload carries `attempt: 2` (1-indexed; first attempt does not emit)",
12274
12280
  "explicitId": "openwop.it.envelope-retry-attempted.event-payload-carries-attempt-2-1-indexed-first-attempt-does-not-emit",
12275
12281
  "citations": [
@@ -12286,7 +12292,7 @@
12286
12292
  {
12287
12293
  "id": "openwop.it.envelope-retry-attempted.reason-is-one-of-the-spec-reserved-closed-enum-values-or-matches-the-x-host-host",
12288
12294
  "file": "envelope-retry-attempted.test.ts",
12289
- "line": 197,
12295
+ "line": 201,
12290
12296
  "title": "`reason` is one of the spec-reserved closed-enum values OR matches the `x-host-<host>-<key>` extension pattern",
12291
12297
  "explicitId": "openwop.it.envelope-retry-attempted.reason-is-one-of-the-spec-reserved-closed-enum-values-or-matches-the-x-host-host",
12292
12298
  "citations": [
@@ -12299,7 +12305,7 @@
12299
12305
  {
12300
12306
  "id": "openwop.it.envelope-retry-attempted.eventual-success-records-normally-via-envelope-acceptance-downstream-runeventdoc",
12301
12307
  "file": "envelope-retry-attempted.test.ts",
12302
- "line": 217,
12308
+ "line": 221,
12303
12309
  "title": "eventual success records normally via envelope acceptance + downstream RunEventDoc",
12304
12310
  "explicitId": "openwop.it.envelope-retry-attempted.eventual-success-records-normally-via-envelope-acceptance-downstream-runeventdoc",
12305
12311
  "citations": [
@@ -12312,7 +12318,7 @@
12312
12318
  {
12313
12319
  "id": "openwop.it.envelope-retry-attempted.previouserror-when-populated-must-not-contain-prompt-or-response-substring-excer",
12314
12320
  "file": "envelope-retry-attempted.test.ts",
12315
- "line": 236,
12321
+ "line": 240,
12316
12322
  "title": "`previousError` (when populated) MUST NOT contain prompt or response substring excerpts — limit to validator output",
12317
12323
  "explicitId": "openwop.it.envelope-retry-attempted.previouserror-when-populated-must-not-contain-prompt-or-response-substring-excer",
12318
12324
  "citations": [
@@ -12423,7 +12429,7 @@
12423
12429
  {
12424
12430
  "id": "openwop.it.envelope-truncated.when-mock-returns-stopreason-max-tokens-on-attempt-1-exactly-one-envelope-trunca",
12425
12431
  "file": "envelope-truncated.test.ts",
12426
- "line": 60,
12432
+ "line": 59,
12427
12433
  "title": "when mock returns stopReason: max_tokens on attempt 1, exactly one envelope.truncated event fires with stopReason: max_tokens",
12428
12434
  "explicitId": "openwop.it.envelope-truncated.when-mock-returns-stopreason-max-tokens-on-attempt-1-exactly-one-envelope-trunca",
12429
12435
  "citations": [
@@ -12436,7 +12442,7 @@
12436
12442
  {
12437
12443
  "id": "openwop.it.envelope-truncated.payload-includes-nodeid-provider-model-partialpayloadavailable-boolean",
12438
12444
  "file": "envelope-truncated.test.ts",
12439
- "line": 86,
12445
+ "line": 85,
12440
12446
  "title": "payload includes nodeId + provider + model + partialPayloadAvailable boolean",
12441
12447
  "explicitId": "openwop.it.envelope-truncated.payload-includes-nodeid-provider-model-partialpayloadavailable-boolean",
12442
12448
  "citations": [
@@ -12449,13 +12455,14 @@
12449
12455
  {
12450
12456
  "id": "openwop.it.envelope-truncated.retry-attempt-receives-a-maxtokens-value-strictly-greater-than-the-previous-atte",
12451
12457
  "file": "envelope-truncated.test.ts",
12452
- "line": 105,
12458
+ "line": 104,
12453
12459
  "title": "retry attempt receives a maxTokens value strictly greater than the previous attempt (RFC 0033 §B truncationBudgetMultiplier)",
12454
12460
  "explicitId": "openwop.it.envelope-truncated.retry-attempt-receives-a-maxtokens-value-strictly-greater-than-the-previous-atte",
12455
12461
  "citations": [
12456
12462
  {
12457
12463
  "section": "RFCS/0033-envelope-completion-contract.md §B",
12458
- "requirement": "truncation retry MUST issue with a strictly-increased maxTokens budget (host multiplies by capabilities.envelopes.reliability.completion.truncationBudgetMultiplier)"
12464
+ "requirement": null,
12465
+ "interpolated": true
12459
12466
  }
12460
12467
  ]
12461
12468
  },
@@ -28349,6 +28356,86 @@
28349
28356
  }
28350
28357
  ]
28351
28358
  },
28359
+ {
28360
+ "id": "openwop.it.v2-client-version-header.a-client-at-the-floor-is-not-below-it-equal-on-major-minor-the-patch-never-decid",
28361
+ "file": "v2-client-version-header.test.ts",
28362
+ "line": 79,
28363
+ "title": "a client at the floor is not below it: equal on major.minor, the patch never decides",
28364
+ "explicitId": "openwop.requirement.0219.floor-comparison",
28365
+ "citations": [
28366
+ {
28367
+ "section": "spec/v2/core/versioning.md §1.5",
28368
+ "requirement": null,
28369
+ "interpolated": true
28370
+ },
28371
+ {
28372
+ "section": "spec/v2/core/versioning.md §1.5",
28373
+ "requirement": null,
28374
+ "interpolated": true
28375
+ }
28376
+ ]
28377
+ },
28378
+ {
28379
+ "id": "openwop.it.v2-client-version-header.a-malformed-openwop-client-version-is-treated-as-absent-never-426-never-400",
28380
+ "file": "v2-client-version-header.test.ts",
28381
+ "line": 90,
28382
+ "title": "a malformed OpenWOP-Client-Version is treated as absent: never 426, never 400",
28383
+ "explicitId": "openwop.requirement.0219.malformed-not-refused",
28384
+ "citations": [
28385
+ {
28386
+ "section": "spec/v2/core/versioning.md §1.5",
28387
+ "requirement": null,
28388
+ "interpolated": true
28389
+ },
28390
+ {
28391
+ "section": "spec/v2/core/versioning.md §1.5",
28392
+ "requirement": null,
28393
+ "interpolated": true
28394
+ },
28395
+ {
28396
+ "section": "spec/v2/core/versioning.md §1.5",
28397
+ "requirement": null,
28398
+ "interpolated": true
28399
+ }
28400
+ ]
28401
+ },
28402
+ {
28403
+ "id": "openwop.it.v2-client-version-header.a-request-without-openwop-client-version-is-served-where-a-below-floor-one-is-re",
28404
+ "file": "v2-client-version-header.test.ts",
28405
+ "line": 102,
28406
+ "title": "a request without OpenWOP-Client-Version is served where a below-floor one is refused",
28407
+ "explicitId": "openwop.requirement.0219.absent-not-refused",
28408
+ "citations": [
28409
+ {
28410
+ "section": "spec/v2/core/versioning.md §1.5",
28411
+ "requirement": "a host MUST NOT answer 426 client_version_unsupported to a request that carries no OpenWOP-Client-Version"
28412
+ },
28413
+ {
28414
+ "section": "spec/v2/core/versioning.md §1.5",
28415
+ "requirement": null,
28416
+ "interpolated": true
28417
+ }
28418
+ ]
28419
+ },
28420
+ {
28421
+ "id": "openwop.it.v2-client-version-header.a-host-that-advertises-no-minclientversion-refuses-no-client-on-version-grounds",
28422
+ "file": "v2-client-version-header.test.ts",
28423
+ "line": 115,
28424
+ "title": "a host that advertises no minClientVersion refuses no client on version grounds",
28425
+ "explicitId": "openwop.requirement.0219.no-floor-no-refusal",
28426
+ "citations": [
28427
+ {
28428
+ "section": "spec/v2/core/versioning.md §1.5",
28429
+ "requirement": null,
28430
+ "interpolated": true
28431
+ },
28432
+ {
28433
+ "section": "spec/v2/core/versioning.md §1.5",
28434
+ "requirement": null,
28435
+ "interpolated": true
28436
+ }
28437
+ ]
28438
+ },
28352
28439
  {
28353
28440
  "id": "openwop.it.v2-coherence-not-in-bundle.every-corpus-ledger-id-has-a-scenario-in-src-coherence-and-none-in-src-scenarios",
28354
28441
  "file": "v2-coherence-not-in-bundle.test.ts",
@@ -29690,7 +29777,7 @@
29690
29777
  {
29691
29778
  "id": "openwop.it.v2-id-grammar.every-id-on-the-run-snapshot-matches-its-ids-schema-json-kind",
29692
29779
  "file": "v2-id-grammar.test.ts",
29693
- "line": 53,
29780
+ "line": 55,
29694
29781
  "title": "every id on the run snapshot matches its ids.schema.json kind",
29695
29782
  "explicitId": "openwop.requirement.0170.id-grammar.snapshot",
29696
29783
  "citations": [
@@ -29709,7 +29796,7 @@
29709
29796
  {
29710
29797
  "id": "openwop.it.v2-id-grammar.every-id-on-the-run-events-matches-its-ids-schema-json-kind",
29711
29798
  "file": "v2-id-grammar.test.ts",
29712
- "line": 63,
29799
+ "line": 65,
29713
29800
  "title": "every id on the run events matches its ids.schema.json kind",
29714
29801
  "explicitId": "openwop.requirement.0170.id-grammar.events",
29715
29802
  "citations": [
@@ -29727,7 +29814,7 @@
29727
29814
  {
29728
29815
  "id": "openwop.it.v2-id-grammar.a-run-id-whose-tenant-segment-is-not-the-caller-s-is-refused",
29729
29816
  "file": "v2-id-grammar.test.ts",
29730
- "line": 78,
29817
+ "line": 90,
29731
29818
  "title": "a run id whose tenant segment is not the caller's is refused",
29732
29819
  "explicitId": "openwop.requirement.0170.id-grammar.tenant-binding",
29733
29820
  "citations": [
@@ -29750,7 +29837,7 @@
29750
29837
  {
29751
29838
  "id": "openwop.it.v2-id-grammar.a-bare-unbound-run-id-in-a-major-2-path-admitted-under-the-caller-s-tenant-throu",
29752
29839
  "file": "v2-id-grammar.test.ts",
29753
- "line": 88,
29840
+ "line": 100,
29754
29841
  "title": "a bare (unbound) run id in a major-2 path: admitted under the caller's tenant through the overlap, refused 400 validation_error after it",
29755
29842
  "explicitId": "openwop.requirement.0170.id-grammar.bare-id",
29756
29843
  "citations": [
@@ -31289,7 +31376,7 @@
31289
31376
  {
31290
31377
  "id": "openwop.it.v2-min-client-version.a-client-below-minclientversion-is-refused-with-426-client-version-unsupported",
31291
31378
  "file": "v2-min-client-version.test.ts",
31292
- "line": 35,
31379
+ "line": 38,
31293
31380
  "title": "a client below minClientVersion is refused with 426 client_version_unsupported",
31294
31381
  "explicitId": "openwop.requirement.0172.min-client-version",
31295
31382
  "citations": [
@@ -31297,6 +31384,11 @@
31297
31384
  "section": "spec/v2/core/versioning.md §1.5",
31298
31385
  "requirement": "minClientVersion MUST use the <major>.<minor> grammar (axis 15, as axis 1)"
31299
31386
  },
31387
+ {
31388
+ "section": "spec/v2/core/versioning.md §1.5",
31389
+ "requirement": null,
31390
+ "interpolated": true
31391
+ },
31300
31392
  {
31301
31393
  "section": "spec/v2/core/versioning.md §1.5",
31302
31394
  "requirement": "a 426 refusal MUST carry client_version_unsupported"
@@ -31305,6 +31397,11 @@
31305
31397
  "section": "spec/v2/core/errors.md §The envelope",
31306
31398
  "requirement": null,
31307
31399
  "interpolated": true
31400
+ },
31401
+ {
31402
+ "section": "spec/v2/core/versioning.md §1.5",
31403
+ "requirement": null,
31404
+ "interpolated": true
31308
31405
  }
31309
31406
  ]
31310
31407
  },
@@ -32238,7 +32335,7 @@
32238
32335
  {
32239
32336
  "id": "openwop.it.v2-preferred-version-default.preferredversion-is-a-member-of-protocolversions",
32240
32337
  "file": "v2-preferred-version-default.test.ts",
32241
- "line": 40,
32338
+ "line": 41,
32242
32339
  "title": "preferredVersion is a member of protocolVersions[]",
32243
32340
  "explicitId": "openwop.requirement.0172.preferred-version-default.member",
32244
32341
  "citations": [
@@ -32260,7 +32357,7 @@
32260
32357
  {
32261
32358
  "id": "openwop.it.v2-preferred-version-default.a-header-less-get-well-known-openwop-is-the-preferredversion-representation",
32262
32359
  "file": "v2-preferred-version-default.test.ts",
32263
- "line": 52,
32360
+ "line": 53,
32264
32361
  "title": "a header-less GET /.well-known/openwop is the preferredVersion representation",
32265
32362
  "explicitId": "openwop.requirement.0172.preferred-version-default.headerless",
32266
32363
  "citations": [
@@ -32288,10 +32385,24 @@
32288
32385
  }
32289
32386
  ]
32290
32387
  },
32388
+ {
32389
+ "id": "openwop.it.v2-preferred-version-default.a-header-less-request-on-any-other-unversioned-path-is-served-major-2",
32390
+ "file": "v2-preferred-version-default.test.ts",
32391
+ "line": 71,
32392
+ "title": "a header-less request on any other unversioned path is served major 2",
32393
+ "explicitId": "openwop.requirement.0172.preferred-version-default.unversioned-is-v2",
32394
+ "citations": [
32395
+ {
32396
+ "section": "spec/v2/core/versioning.md §1.2, §1.3",
32397
+ "requirement": null,
32398
+ "interpolated": true
32399
+ }
32400
+ ]
32401
+ },
32291
32402
  {
32292
32403
  "id": "openwop.it.v2-preferred-version-default.through-the-overlap-preferredversion-names-a-1-x-member",
32293
32404
  "file": "v2-preferred-version-default.test.ts",
32294
- "line": 70,
32405
+ "line": 88,
32295
32406
  "title": "through the overlap preferredVersion names a 1.x member",
32296
32407
  "explicitId": "openwop.requirement.0172.preferred-version-default.overlap",
32297
32408
  "citations": [
@@ -33760,13 +33871,18 @@
33760
33871
  {
33761
33872
  "section": "spec/v2/core/webhooks.md §Delivery",
33762
33873
  "requirement": "a major-2 owner echo carries tenant and subject"
33874
+ },
33875
+ {
33876
+ "section": "spec/v2/core/webhooks.md §Delivery",
33877
+ "requirement": null,
33878
+ "interpolated": true
33763
33879
  }
33764
33880
  ]
33765
33881
  },
33766
33882
  {
33767
33883
  "id": "openwop.it.v2-webhook-delivery-shape.a-major-1-subscriber-still-receives-the-v1-rendering-the-v1-wire-does-not-move-m",
33768
33884
  "file": "v2-webhook-delivery-shape.test.ts",
33769
- "line": 239,
33885
+ "line": 244,
33770
33886
  "title": "a major-1 subscriber still receives the v1 rendering — the v1 wire does not move mid-overlap",
33771
33887
  "explicitId": "openwop.requirement.0171.webhook-delivery-shape",
33772
33888
  "citations": [
@@ -33784,7 +33900,7 @@
33784
33900
  {
33785
33901
  "id": "openwop.it.v2-webhook-delivery-shape.a-seeded-era-2-run-is-delivered-projected-too-the-fan-out-branch-a-fresh-run-can",
33786
33902
  "file": "v2-webhook-delivery-shape.test.ts",
33787
- "line": 263,
33903
+ "line": 268,
33788
33904
  "title": "a seeded era-2 run is delivered projected too — the fan-out branch a fresh run cannot reach (seam-gated)",
33789
33905
  "explicitId": "openwop.requirement.0171.webhook-delivery-shape",
33790
33906
  "citations": [
@@ -34020,6 +34136,40 @@
34020
34136
  }
34021
34137
  ]
34022
34138
  },
34139
+ {
34140
+ "id": "openwop.it.v2-webhook-generated-secret.a-secret-less-registration-returns-the-generated-secret-and-deliveries-verify-un",
34141
+ "file": "v2-webhook-generated-secret.test.ts",
34142
+ "line": 44,
34143
+ "title": "a secret-less registration returns the generated secret, and deliveries verify under it; a supplied secret is never echoed",
34144
+ "explicitId": "openwop.requirement.0221.generated-secret-returned",
34145
+ "citations": [
34146
+ {
34147
+ "section": "RFC 0221 · webhooks.md §Surfaces",
34148
+ "requirement": "a registration that omits secret MUST get the host-generated secret back in the 201 as a non-empty string"
34149
+ },
34150
+ {
34151
+ "section": "runs.md §Create",
34152
+ "requirement": "POST /runs MUST answer 201 for the noop fixture"
34153
+ },
34154
+ {
34155
+ "section": "webhooks.md §Durability",
34156
+ "requirement": "the subscription MUST receive the run.completed delivery"
34157
+ },
34158
+ {
34159
+ "section": "RFC 0221 · webhooks.md §Surfaces",
34160
+ "requirement": "the delivery MUST verify (OpenWOP-Signature, scheme v1) under the secret the 201 returned"
34161
+ },
34162
+ {
34163
+ "section": "RFC 0221 · webhooks.md §Surfaces",
34164
+ "requirement": null,
34165
+ "interpolated": true
34166
+ },
34167
+ {
34168
+ "section": "RFC 0221 · RFC 0201 §B.6",
34169
+ "requirement": "the 201 MUST NOT echo a supplied secret"
34170
+ }
34171
+ ]
34172
+ },
34023
34173
  {
34024
34174
  "id": "openwop.it.v2-webhook-message-id-stable.every-attempt-of-one-delivery-carries-one-webhook-id-and-distinct-deliveries-car",
34025
34175
  "file": "v2-webhook-message-id-stable.test.ts",
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "$comment": "GENERATED by conformance/scripts/generate-scenario-majors.mjs (RFC 0168 §D.3). Do not edit; add a file to BOTH_MAJORS in the generator to target both majors.",
3
3
  "counts": {
4
- "files": 565,
4
+ "files": 567,
5
5
  "v1": 451,
6
- "v2": 126
6
+ "v2": 128
7
7
  },
8
8
  "majors": {
9
9
  "a2a-1-0-agent-card.test.ts": [
@@ -1317,6 +1317,9 @@
1317
1317
  "v2-chain-pin-exact.test.ts": [
1318
1318
  2
1319
1319
  ],
1320
+ "v2-client-version-header.test.ts": [
1321
+ 2
1322
+ ],
1320
1323
  "v2-coherence-not-in-bundle.test.ts": [
1321
1324
  2
1322
1325
  ],
@@ -1587,6 +1590,9 @@
1587
1590
  "v2-webhook-endpoint-verification.test.ts": [
1588
1591
  2
1589
1592
  ],
1593
+ "v2-webhook-generated-secret.test.ts": [
1594
+ 2
1595
+ ],
1590
1596
  "v2-webhook-message-id-stable.test.ts": [
1591
1597
  2
1592
1598
  ],