@openwop/openwop-conformance 2.45.3 → 2.45.5

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,37 @@
1
1
  # `@openwop/openwop-conformance` Changelog
2
2
 
3
+ ## [2.45.5] — 2026-10-01 — a prefix floor row is written only for a claimed profile
4
+
5
+ - **The 2.45.5 cycle opens.** A runner change alters the packed content.
6
+ - **Fix: an unclaimed prefix floor no longer blocks a major-1 bundle.** The runner wrote `openwop.floor.any.interrupt-` for every floor in the v1 table. On a major-1 host that does not claim `openwop-interrupts`, no `interrupt-*` file passes, so the row was `blocked`, and a v3 bundle with any `blocked` row certifies nothing (RFC 0168 §E.1). The row is now written only when the profile is claimed, as the any-of rows have been since 2.45.4. A claimed profile is unchanged.
7
+ - **Who is affected:** a major-1 host that cuts a v3 bundle without claiming `openwop-interrupts`. No such host is known. Major-2 bundles never carried the row.
8
+ - **Proof.** `floor-prefix-claimed.test.ts`: the same evidence yields no row unclaimed and a `blocked` row claimed; a witnessed `interrupt-*` pass still satisfies a claimed floor.
9
+
10
+ ## [2.45.4] — 2026-10-01 — v2 ports of production-backpressure and budget-enforcement, on a per-major profile
11
+
12
+ - **The gate runs every host-free scenario** (not packed; no scenario changes). New `scripts/list-host-free-scenarios.mjs` lists the scenarios whose import closure never reaches `lib/driver`, `lib/sse` or `lib/env` and never calls `fetch(`: 70 files today. `scripts/openwop-check.sh` runs them with `OPENWOP_BASE_URL` and `OPENWOP_API_KEY` unset, after the nine hand-listed files.
13
+ - **Why.** `host-callback-declaration` and `runner-ledger` failed on every host in the 2.45.3 candidate and nothing in CI said so (#1835).
14
+ - **Proof.** Clean tree: 66 files pass and 4 skip, no failure. With `REQUIRES_HOST_CALLBACK` removed from `v2-tool-authorization-fail-closed`, the step fails on `host-callback-declaration`.
15
+ - **Limits.** The walk reads static relative imports. `--check` fails if the set is empty or loses a known member. `ai-envelope-shape` is on the hand list and outside the derived set, so the hand list stays.
16
+ - **The 2.45.4 cycle opens.** Two new scenarios and one new fixture change the packed content.
17
+ - **Fix: an unclaimed any-of floor no longer blocks a major-1 bundle** (a 2.45.3 defect). The runner wrote the `openwop.floor.anyof.byok-roundtrip+secrets-run-witness` summary row for every floor in the v1 table, claimed or not. A host that does not advertise secrets records both members `inapplicable`, so it got one `blocked` row for `openwop-secrets`, a profile it never claimed, and a v3 bundle with any `blocked` row certifies nothing (RFC 0168 §E.1). The row is now written only when the profile is claimed. A claimed profile is unchanged: unwitnessed members still record `blocked` and deny it.
18
+ - **Who was affected:** a major-1 host cutting a v3 bundle on 2.45.3 without claiming `openwop-secrets`. Major-2 bundles never carried the row.
19
+ - **Proof.** `floor-any-of.test.ts`: the same evidence yields no row unclaimed and a `blocked` row claimed. Found by running the derivation, after reading the code had suggested the row was harmless.
20
+ - **What differs between majors is now data** (`src/lib/major-profile.ts`). One table row per major holds the run path, the version headers, the event names (from the codemap), where retry timing lives, how a family is advertised, and how a run budget rides on `createRun`. A shared witness takes a profile and never names a major, so a port to a later major is one row plus a thin scenario file. A major with no row throws; it never falls back to an older major's rules.
21
+ - **New scenario `v2-production-backpressure`** (major 2, unaided; `conformance.md` §Production profile). Gated on `production.backpressure.inflightCap`. The suite holds that many event streams open, waits for each to open, and sends one more request.
22
+ - `openwop.requirement.production.backpressure-refusal`: the extra request answers `503 service_unavailable` with `Retry-After`, equal to `retryAfterSeconds` where advertised.
23
+ - `openwop.requirement.0171.error-registry.no-retry-details`: the refusal carries no `details.retryAfter*`. v1 required `details.retryAfter`; v2 forbids it.
24
+ - **Dispositions.** No `production`, `backpressure` or `inflightCap`, a cap above 64, or an unadvertised hold or probe fixture: `inapplicable`. A slot that cannot be held, or a probe with no response: `blocked`.
25
+ - **Not ported:** v1's "discovery is exempt from the cap" leg. No v2 document states it.
26
+ - **New scenario `v2-budget-enforcement`** (major 2, unaided; `runs.md` §`budget` section). At major 2 a budget rides on `createRun` (`configurable.budget`), so no seam is needed. The suite runs the new fixture with `{ maxToolCalls: 2, thresholdPercent: 50, onExhaustion: "fail" }` and reads the log through the poll.
27
+ - `openwop.requirement.runs.budget-lifecycle`: `budget.reserved`, `budget.threshold-crossed` and `budget.exhausted`, in order.
28
+ - `openwop.requirement.runs.budget-enforcement`: a `hard` host emits `cap.breached` (`budget-tool-calls`) and fails the run `budget_exhausted`; an `advisory` host does not stop it.
29
+ - `openwop.requirement.runs.budget-content-free`: no `budget.*` or `cap.breached` payload carries pricing or a credential.
30
+ - **Dispositions.** No `budget`, no `toolCalls` dimension, or the fixture unadvertised: `inapplicable`. The fixture is the opt-in, so a host that advertises `budget` without seeding it is unwitnessed, not blocked. A refused valid create: `executed-fail`.
31
+ - **Not ported:** v1's `budget_model_denied` leg. It needs a fixture that resolves a model without a seam.
32
+ - **New fixture `conformance-budget-tool-calls`**: one `core.conformance.mock-agent` with three scripted tool calls.
33
+ - **Proof.** No host serves either family unaided at major 2, so both witnesses are proven against `src/lib/scratch-host.ts`, a profile-driven test double: 29 self-tests, one defect each (`backpressure-witness.test.ts`, `budget-witness.test.ts`, `major-profile.test.ts`). The scenario files were also run end to end against a conforming and a defective scratch host.
34
+
3
35
  ## [2.45.3] — 2026-10-01 — RFC 0229 (Active): a production host can witness secret resolution without an oracle; v2 tenant-isolation witnesses for storage, fs, memory, workspace, queues and secrets
4
36
 
5
37
  - **Two self-checks that failed on every host are fixed before the cut.** Found by running the candidate on openwop-app at major 1 against 2.45.2: four rows went `executed-pass` → `executed-fail`, and both files failed the same way with no host.
package/README.md CHANGED
@@ -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 587 scenario files under `src/scenarios/`.
138
+ The current suite has 589 scenario files under `src/scenarios/`.
139
139
  - 2026-09-29 (suite 2.45.0, openwop#1763): NEW `v2-cors-preflight.test.ts` — `headers.md` §Cross-origin preflight. For every operation it preflights with `Origin`, the method, and the operation's declared request headers (plus `authorization` / `content-type` where they apply, from `spec/v2/path-manifest.json`), and reads the answer as the Fetch standard's CORS-preflight check does. Self-gated: `inapplicable` when no operation's preflight grants `OPENWOP_CORS_ORIGIN` (default `https://conformance.invalid`).
140
140
  - 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.
141
141
  - 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.
@@ -482,7 +482,7 @@ Server-required (added in 1.7.0):
482
482
  | ------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
483
483
  | **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. |
484
484
 
485
- Current source tree: 587 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
485
+ Current source tree: 589 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
486
486
 
487
487
  ## Remaining Gaps
488
488
 
@@ -26,7 +26,7 @@
26
26
  * host or a vitest subprocess.
27
27
  */
28
28
  import { scenarioFileOfItId } from './requirement-ids.js';
29
- import { PROFILE_FLOOR_SCENARIOS, floorMemberFiles } from './profiles.js';
29
+ import { DEPRECATED_PROFILE_ALIASES, PROFILE_FLOOR_SCENARIOS, floorMemberFiles } from './profiles.js';
30
30
  import { targetMajor } from './seams.js';
31
31
  import { PKG_ROOT_PATH } from './paths.js';
32
32
  import { v2ProfileFloorFiles } from './requirement-registry.js';
@@ -366,11 +366,21 @@ document) {
366
366
  // `openwop.floor.any.interrupt-` row recorded `blocked` ("no interrupt-*
367
367
  // scenario ran"), which by RFC 0168 §E.1 denied certification to every
368
368
  // profile on every major-2 bundle. The fifth unjoined floor site.
369
+ //
370
+ // Only for a CLAIMED profile's floor (2.45.5), as the any-of rows below have
371
+ // been since 2.45.4, and for the same reason: a floor nobody claims is not a
372
+ // requirement on this host, and its summary row is `blocked` whenever no
373
+ // matching file passed. A major-1 host that does not claim
374
+ // `openwop-interrupts` got an `openwop.floor.any.interrupt-` row it could
375
+ // only satisfy by passing a scenario of a profile it never claimed, and a v3
376
+ // bundle with any `blocked` row certifies nothing (RFC 0168 §E.1).
377
+ const claimed = new Set(claimedProfiles.map((p) => DEPRECATED_PROFILE_ALIASES[p] ?? p));
369
378
  const prefixIds = new Set();
370
379
  if (!v2FloorsActive())
371
- for (const floor of Object.values(PROFILE_FLOOR_SCENARIOS))
372
- for (const p of floor.requiredAnyPrefix ?? [])
373
- prefixIds.add(p);
380
+ for (const [profile, floor] of Object.entries(PROFILE_FLOOR_SCENARIOS))
381
+ if (claimed.has(profile))
382
+ for (const p of floor.requiredAnyPrefix ?? [])
383
+ prefixIds.add(p);
374
384
  for (const prefix of [...prefixIds].sort()) {
375
385
  const matching = [...perFile.entries()].filter(([f]) => f.startsWith(prefix)).map(([, r]) => r);
376
386
  const id = requirementIdForPrefix(prefix);
@@ -399,10 +409,19 @@ document) {
399
409
  // no member failing; `inapplicable`/`skipped` members never satisfy it. v1
400
410
  // hand table only, like the prefix groups (the major-2 floors have none).
401
411
  const groups = new Map();
412
+ //
413
+ // Only for a CLAIMED profile's floor (2.45.4). The row is `blocked` when no
414
+ // member was witnessed, and a v1 floor reads `inapplicable` as certifiable, so
415
+ // the row cannot simply say `inapplicable`. But 2.45.3 wrote it for every
416
+ // floor in the table: a host that does not advertise secrets records both
417
+ // members `inapplicable`, got one `blocked` row for a profile it never
418
+ // claimed, and a bundle with any `blocked` row certifies nothing (RFC 0168
419
+ // §E.1). A group nobody claims is not a requirement on this host.
402
420
  if (!v2FloorsActive())
403
- for (const floor of Object.values(PROFILE_FLOOR_SCENARIOS))
404
- for (const g of floor.requiredAnyOf ?? [])
405
- groups.set(requirementIdForAnyOf(g), g);
421
+ for (const [profile, floor] of Object.entries(PROFILE_FLOOR_SCENARIOS))
422
+ if (claimed.has(profile))
423
+ for (const g of floor.requiredAnyOf ?? [])
424
+ groups.set(requirementIdForAnyOf(g), g);
406
425
  for (const [id, members] of [...groups.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
407
426
  const scenarioId = `anyof:${members.join('|')}`;
408
427
  const matching = members.map((f) => perFile.get(f)).filter((r) => r !== undefined);
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.45.3",
4
- "stampSha256": "2b7ce94326d2cb0fa88b311a7d6d89c0a0b68f03e66934ad49a19722904a75e7"
3
+ "version": "2.45.5",
4
+ "stampSha256": "cdc1ddd3b7638a291b2179ef220c96c8d8e67179e005c7650ac9d913f73dd179"
5
5
  }
@@ -0,0 +1,81 @@
1
+ {
2
+ "id": "conformance-budget-tool-calls",
3
+ "name": "Conformance: Budget (tool calls)",
4
+ "version": "1.0",
5
+ "description": "Spends a run budget without a model or a seam. One `core.conformance.mock-agent` node makes three scripted tool calls, so a run created with `budget.maxToolCalls: 2` crosses its threshold on the first call and is exhausted before the third. See v2-budget-enforcement.test.ts.",
6
+ "nodes": [
7
+ {
8
+ "id": "spender",
9
+ "typeId": "core.conformance.mock-agent",
10
+ "name": "Budget Spender",
11
+ "position": {
12
+ "x": 0,
13
+ "y": 0
14
+ },
15
+ "config": {
16
+ "mockToolCalls": [
17
+ {
18
+ "toolId": "openwop.echo:echo",
19
+ "arguments": {
20
+ "x": 1
21
+ },
22
+ "result": {
23
+ "x": 1
24
+ },
25
+ "durationMs": 1
26
+ },
27
+ {
28
+ "toolId": "openwop.echo:echo",
29
+ "arguments": {
30
+ "x": 2
31
+ },
32
+ "result": {
33
+ "x": 2
34
+ },
35
+ "durationMs": 1
36
+ },
37
+ {
38
+ "toolId": "openwop.echo:echo",
39
+ "arguments": {
40
+ "x": 3
41
+ },
42
+ "result": {
43
+ "x": 3
44
+ },
45
+ "durationMs": 1
46
+ }
47
+ ],
48
+ "mockDecision": {
49
+ "decision": {
50
+ "next": "done"
51
+ },
52
+ "confidence": 1
53
+ }
54
+ },
55
+ "inputs": {},
56
+ "agent": {
57
+ "agentId": "core.conformance.budget-spender",
58
+ "modelClass": "reasoning"
59
+ }
60
+ }
61
+ ],
62
+ "edges": [],
63
+ "triggers": [
64
+ {
65
+ "id": "manual",
66
+ "type": "manual",
67
+ "enabled": true
68
+ }
69
+ ],
70
+ "variables": [],
71
+ "metadata": {
72
+ "tags": [
73
+ "conformance",
74
+ "budget",
75
+ "rfc-0084"
76
+ ]
77
+ },
78
+ "settings": {
79
+ "timeout": 15000
80
+ }
81
+ }
package/fixtures.md CHANGED
@@ -73,6 +73,7 @@ All fixtures MUST advertise:
73
73
  | Agent Identity | `conformance-agent-identity` | Phase 1 — `RunSnapshot.agent` / `runOrchestrator` AgentRef wire-shape | `completed` | ≤ 10s |
74
74
  | Agent Reasoning | `conformance-agent-reasoning` | Phase 1 / RFC 0023 — `agent.*` event family emission + `callId` pairing on `core.conformance.mock-agent` | `completed` | ≤ 15s |
75
75
  | Agent Reasoning Streaming | `conformance-agent-reasoning-streaming` | RFC 0024 — `core.conformance.mock-agent` with `mockReasoning.streamChunks` drives incremental `agent.reasoning.delta` events (sequence 0..N-1) followed by exactly one closing `agent.reasoned` whose `reasoning` equals the concatenation. Gated on `capabilities.agents.reasoning.streaming: true`. | `completed` | ≤ 15s |
76
+ | Budget (tool calls) | `conformance-budget-tool-calls` | `runs.md` §`budget` section — one `core.conformance.mock-agent` makes three scripted tool calls, so a run budget is spent with no model and no seam. Seeding it opts the host in to `v2-budget-enforcement` | `completed`; `failed` (`budget_exhausted`) under a hard budget below 3 calls | ≤ 15s |
76
77
  | Agent Low-Confidence | `conformance-agent-low-confidence` | Phase 1 / CP-1 / RFC 0023 — `core.conformance.mock-agent` emits `agent.decided` with confidence < threshold; host MUST follow with `node.suspended { reason: 'low-confidence' }` | `waiting-approval` (suspends) | unbounded (suspends) |
77
78
  | Message Reducer | `conformance-message-reducer` | Phase 1 — `message` reducer idempotency on duplicate `messageId` | `completed` | ≤ 10s |
78
79
  | Agent Pack Install | `conformance-agent-pack-install` | Phase 2 — pack `agents[]` surface as AgentManifest at `GET /v1/packs` | `completed` | ≤ 5s |
@@ -371,6 +372,16 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
371
372
 
372
373
  ---
373
374
 
375
+
376
+ ### `conformance-budget-tool-calls`
377
+
378
+ - **Purpose**: spend a run budget unaided, so `budget` can be witnessed without a model or a seam (`v2-budget-enforcement`).
379
+ - **Shape**: one `core.conformance.mock-agent` node with three `mockToolCalls`. Each call counts once against the `toolCalls` dimension.
380
+ - **Inputs**: none.
381
+ - **Expected behavior**: created with `configurable.budget = { maxToolCalls: 2, thresholdPercent: 50, onExhaustion: "fail" }`, the run emits `budget.reserved`, then `budget.threshold-crossed`, then `budget.exhausted`. A host advertising `enforce: "hard"` then emits `cap.breached` (`kind: "budget-tool-calls"`) and fails the run `budget_exhausted`; an `advisory` host lets it complete.
382
+ - **Terminal status**: `completed` with no budget; `failed` under a hard budget below three calls.
383
+ - **Opt-in**: a host that advertises `budget` without seeding this fixture records `inapplicable` for the witness.
384
+
374
385
  ## `conformance-version-fold` (closes F5)
375
386
 
376
387
  - **Consuming scenario**: `conformance/src/scenarios/version-fold.test.ts` (added 2026-06-11; previously this fixture had no consuming scenario).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.45.3",
3
+ "version": "2.45.5",
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.45.3"
59
+ "@openwop/spec-artifacts": "2.45.5"
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": 662,
6
- "tests": 2535,
7
- "withStableId": 2535,
5
+ "files": 664,
6
+ "tests": 2540,
7
+ "withStableId": 2540,
8
8
  "interpolatedTitles": 0,
9
- "explicitIds": 2411
9
+ "explicitIds": 2416
10
10
  },
11
11
  "records": [
12
12
  {
@@ -23601,7 +23601,7 @@
23601
23601
  {
23602
23602
  "id": "openwop.it.runner-ledger.a-floor-file-that-vitest-passed-but-that-recorded-nothing-is-unclassified-when-a",
23603
23603
  "file": "runner-ledger.test.ts",
23604
- "line": 146,
23604
+ "line": 143,
23605
23605
  "title": "a floor file that vitest passed but that recorded NOTHING is unclassified when a ledger exists — silence is not a witness",
23606
23606
  "explicitId": "openwop.it.runner-ledger.a-floor-file-that-vitest-passed-but-that-recorded-nothing-is-unclassified-when-a",
23607
23607
  "citations": [
@@ -23614,7 +23614,7 @@
23614
23614
  {
23615
23615
  "id": "openwop.it.runner-ledger.a-vacuous-pass-executed-pass-with-assertioncount-0-on-a-claimed-floor-is-unclass",
23616
23616
  "file": "runner-ledger.test.ts",
23617
- "line": 158,
23617
+ "line": 155,
23618
23618
  "title": "a VACUOUS pass (executed-pass with assertionCount 0) on a claimed floor is unclassified and REJECTS certification",
23619
23619
  "explicitId": "openwop.it.runner-ledger.a-vacuous-pass-executed-pass-with-assertioncount-0-on-a-claimed-floor-is-unclass",
23620
23620
  "citations": [
@@ -23627,7 +23627,7 @@
23627
23627
  {
23628
23628
  "id": "openwop.it.runner-ledger.a-skipped-file-with-no-ledger-entry-is-blocked-unclassified-and-it-never-reads-a",
23629
23629
  "file": "runner-ledger.test.ts",
23630
- "line": 167,
23630
+ "line": 164,
23631
23631
  "title": "a skipped file with no ledger entry is blocked (unclassified) — and it never reads as skipped/inapplicable",
23632
23632
  "explicitId": "openwop.it.runner-ledger.a-skipped-file-with-no-ledger-entry-is-blocked-unclassified-and-it-never-reads-a",
23633
23633
  "citations": [
@@ -23640,7 +23640,7 @@
23640
23640
  {
23641
23641
  "id": "openwop.it.runner-ledger.a-recorded-inapplicable-skipped-is-certifiable-and-not-unclassified-a-recorded-e",
23642
23642
  "file": "runner-ledger.test.ts",
23643
- "line": 179,
23643
+ "line": 176,
23644
23644
  "title": "a recorded inapplicable/skipped is certifiable and NOT unclassified; a recorded executed-fail blocks but is classified",
23645
23645
  "explicitId": "openwop.it.runner-ledger.a-recorded-inapplicable-skipped-is-certifiable-and-not-unclassified-a-recorded-e",
23646
23646
  "citations": [
@@ -23653,7 +23653,7 @@
23653
23653
  {
23654
23654
  "id": "openwop.it.runner-ledger.a-discoveryonly-profile-certifies-with-an-empty-floor-an-unknown-profile-does-no",
23655
23655
  "file": "runner-ledger.test.ts",
23656
- "line": 192,
23656
+ "line": 189,
23657
23657
  "title": "a discoveryOnly profile certifies with an empty floor; an unknown profile does not",
23658
23658
  "explicitId": "openwop.it.runner-ledger.a-discoveryonly-profile-certifies-with-an-empty-floor-an-unknown-profile-does-no",
23659
23659
  "citations": [
@@ -23666,7 +23666,7 @@
23666
23666
  {
23667
23667
  "id": "openwop.it.runner-ledger.a-runtime-derived-profile-openwop-node-packs-is-held-only-when-every-floor-row-i",
23668
23668
  "file": "runner-ledger.test.ts",
23669
- "line": 199,
23669
+ "line": 196,
23670
23670
  "title": "a RUNTIME-DERIVED profile (openwop-node-packs) is HELD only when every floor row is a witnessed pass; otherwise it is not held — not rejected, not blocked",
23671
23671
  "explicitId": "openwop.it.runner-ledger.a-runtime-derived-profile-openwop-node-packs-is-held-only-when-every-floor-row-i",
23672
23672
  "citations": [
@@ -23683,7 +23683,7 @@
23683
23683
  {
23684
23684
  "id": "openwop.it.runner-ledger.the-runner-s-a-resolution-of-a-silent-zero-assertion-file-blocked-marker-is-stil",
23685
23685
  "file": "runner-ledger.test.ts",
23686
- "line": 234,
23686
+ "line": 231,
23687
23687
  "title": "the runner's §A resolution of a silent zero-assertion file (blocked + marker) is STILL unclassified for a claimed floor",
23688
23688
  "explicitId": "openwop.it.runner-ledger.the-runner-s-a-resolution-of-a-silent-zero-assertion-file-blocked-marker-is-stil",
23689
23689
  "citations": [
@@ -23696,7 +23696,7 @@
23696
23696
  {
23697
23697
  "id": "openwop.it.runner-ledger.with-no-ledger-at-all-every-skipped-file-is-blocked-and-the-runner-says-so-the-p",
23698
23698
  "file": "runner-ledger.test.ts",
23699
- "line": 247,
23699
+ "line": 244,
23700
23700
  "title": "with no ledger at all, every skipped file is blocked and the runner says so (the pre-S6 honest reading)",
23701
23701
  "explicitId": "openwop.it.runner-ledger.with-no-ledger-at-all-every-skipped-file-is-blocked-and-the-runner-says-so-the-p",
23702
23702
  "citations": [
@@ -23709,7 +23709,7 @@
23709
23709
  {
23710
23710
  "id": "openwop.it.runner-ledger.notes-are-keyed-to-the-current-test-file-worst-first-when-mixed-and-read-back-wi",
23711
23711
  "file": "runner-ledger.test.ts",
23712
- "line": 257,
23712
+ "line": 254,
23713
23713
  "title": "notes are keyed to the current test file, worst-first when mixed, and read back with joined reasons",
23714
23714
  "explicitId": "openwop.it.runner-ledger.notes-are-keyed-to-the-current-test-file-worst-first-when-mixed-and-read-back-wi",
23715
23715
  "citations": [
@@ -23722,7 +23722,7 @@
23722
23722
  {
23723
23723
  "id": "openwop.it.runner-ledger.files-that-finished-before-this-one-appear-in-the-ledger-file-with-an-assertion",
23724
23724
  "file": "runner-ledger.test.ts",
23725
- "line": 279,
23725
+ "line": 276,
23726
23726
  "title": "files that finished before this one appear in the ledger file with an assertion count",
23727
23727
  "explicitId": "openwop.it.runner-ledger.files-that-finished-before-this-one-appear-in-the-ledger-file-with-an-assertion",
23728
23728
  "citations": [
@@ -28618,6 +28618,48 @@
28618
28618
  }
28619
28619
  ]
28620
28620
  },
28621
+ {
28622
+ "id": "openwop.it.v2-budget-enforcement.a-budgeted-run-emits-budget-reserved-budget-threshold-crossed-and-budget-exhaust",
28623
+ "file": "v2-budget-enforcement.test.ts",
28624
+ "line": 76,
28625
+ "title": "a budgeted run emits budget.reserved, budget.threshold-crossed and budget.exhausted in order",
28626
+ "explicitId": "openwop.requirement.runs.budget-lifecycle",
28627
+ "citations": [
28628
+ {
28629
+ "section": null,
28630
+ "requirement": null,
28631
+ "interpolated": true
28632
+ }
28633
+ ]
28634
+ },
28635
+ {
28636
+ "id": "openwop.it.v2-budget-enforcement.a-hard-host-stops-the-run-budget-exhausted-after-cap-breached-and-an-advisory-ho",
28637
+ "file": "v2-budget-enforcement.test.ts",
28638
+ "line": 82,
28639
+ "title": "a hard host stops the run budget_exhausted after cap.breached, and an advisory host does not stop it",
28640
+ "explicitId": "openwop.requirement.runs.budget-enforcement",
28641
+ "citations": [
28642
+ {
28643
+ "section": null,
28644
+ "requirement": null,
28645
+ "interpolated": true
28646
+ }
28647
+ ]
28648
+ },
28649
+ {
28650
+ "id": "openwop.it.v2-budget-enforcement.no-budget-or-cap-breached-payload-carries-pricing-or-a-credential",
28651
+ "file": "v2-budget-enforcement.test.ts",
28652
+ "line": 89,
28653
+ "title": "no budget.* or cap.breached payload carries pricing or a credential",
28654
+ "explicitId": "openwop.requirement.runs.budget-content-free",
28655
+ "citations": [
28656
+ {
28657
+ "section": null,
28658
+ "requirement": null,
28659
+ "interpolated": true
28660
+ }
28661
+ ]
28662
+ },
28621
28663
  {
28622
28664
  "id": "openwop.it.v2-bundle-v3-signed.a-signed-v3-bundle-validates-against-the-closed-root-schema-an-extra-root-key-is",
28623
28665
  "file": "v2-bundle-v3-signed.test.ts",
@@ -33153,6 +33195,34 @@
33153
33195
  }
33154
33196
  ]
33155
33197
  },
33198
+ {
33199
+ "id": "openwop.it.v2-production-backpressure.with-inflightcap-slots-held-the-next-request-is-refused-503-service-unavailable",
33200
+ "file": "v2-production-backpressure.test.ts",
33201
+ "line": 58,
33202
+ "title": "with inflightCap slots held, the next request is refused 503 service_unavailable with Retry-After",
33203
+ "explicitId": "openwop.requirement.production.backpressure-refusal",
33204
+ "citations": [
33205
+ {
33206
+ "section": null,
33207
+ "requirement": null,
33208
+ "interpolated": true
33209
+ }
33210
+ ]
33211
+ },
33212
+ {
33213
+ "id": "openwop.it.v2-production-backpressure.the-refusal-carries-its-retry-timing-in-the-retry-after-header-only",
33214
+ "file": "v2-production-backpressure.test.ts",
33215
+ "line": 66,
33216
+ "title": "the refusal carries its retry timing in the Retry-After header only",
33217
+ "explicitId": "openwop.requirement.0171.error-registry.no-retry-details",
33218
+ "citations": [
33219
+ {
33220
+ "section": null,
33221
+ "requirement": null,
33222
+ "interpolated": true
33223
+ }
33224
+ ]
33225
+ },
33156
33226
  {
33157
33227
  "id": "openwop.it.v2-profiles-derived-only.the-v2-document-carries-no-root-profiles",
33158
33228
  "file": "v2-profiles-derived-only.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": 587,
4
+ "files": 589,
5
5
  "v1": 454,
6
- "v2": 148
6
+ "v2": 150
7
7
  },
8
8
  "majors": {
9
9
  "a2a-1-0-agent-card.test.ts": [
@@ -1317,6 +1317,9 @@
1317
1317
  "v2-bound-id-path-projection.test.ts": [
1318
1318
  2
1319
1319
  ],
1320
+ "v2-budget-enforcement.test.ts": [
1321
+ 2
1322
+ ],
1320
1323
  "v2-bundle-v3-signed.test.ts": [
1321
1324
  2
1322
1325
  ],
@@ -1521,6 +1524,9 @@
1521
1524
  "v2-preferred-version-default.test.ts": [
1522
1525
  2
1523
1526
  ],
1527
+ "v2-production-backpressure.test.ts": [
1528
+ 2
1529
+ ],
1524
1530
  "v2-profiles-derived-only.test.ts": [
1525
1531
  2
1526
1532
  ],
@@ -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.45.3",
5
- "corpusTag": "v2.45.3",
4
+ "version": "2.45.5",
5
+ "corpusTag": "v2.45.5",
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": "ad37a5a5c732ad46100fc03c3f4243fdd4f2976e330f02a8791b6b5b10a8a0c1",
11
11
  "api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
12
- "api/seams-v2.yaml": "1f22ab7223019080332312b0fc9f7eb4c97bca2eebd57cab886acd1d6e3081d0",
13
- "api/v2/asyncapi.yaml": "5b74151b1867c3c234203aa1f2dfb1ceeea216e013395e8696da02d4a8630412",
14
- "api/v2/openapi.yaml": "05a07d9cd1e7f80da1e7044aace1073bf4ab584186cdd67979ba2664f90a80d0",
12
+ "api/seams-v2.yaml": "8ecb968c18b03fde88e807855cfbe761db387e9a51550f8a9c525348c224fef1",
13
+ "api/v2/asyncapi.yaml": "0f2fd3ea79ca0c3964d7e81881c371bde8006ca0e23a32aaf37f4c201ab0ebbe",
14
+ "api/v2/openapi.yaml": "910a3e2cc53ae10251cf6b3e82317adc76923aa94c13438cbb50c7197a2f5487",
15
15
  "api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
16
16
  "schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
17
17
  "schemas/a2a-task-state.schema.json": "75d5049dea8bd873ff0e7546f1c60c8d36c219bec7084264360be54a8be30ae1",
@@ -204,7 +204,7 @@
204
204
  "schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
205
205
  "spec/v1/alias-detectors.json": "0b2f28808ffe0b9d98a187775038c3406bb70919747a788a6e4f866e293ae6d3",
206
206
  "spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
207
- "spec/v1/core-standard-manifest.json": "746278bbf9cf46840ba3bd5a85683251ddbc379466585f54e582754ce684d637",
207
+ "spec/v1/core-standard-manifest.json": "ca151601427c2887b0c3ecc9498f5f0de1c4f6d1724b7e06eb7043be20eef1b1",
208
208
  "spec/v1/deprecations.json": "a3293072ea951857395d05f0437264e88965f1e9019ff61c55bacfa9c1aaa17c",
209
209
  "spec/v1/deprecations.schema.json": "3e393c405d2a41b467d8c5e3c468549078df1ce6a6d2588fc488097b95d9b55b",
210
210
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
@@ -303,9 +303,9 @@
303
303
  "spec/v2/path-manifest.json": "27c2307b84376b2f22bea4e2213fc7e33ef3bf8fd1d18039f7955edb00dc9c9a",
304
304
  "spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
305
305
  "spec/v2/profiles.json": "180beb9ef2d161766fa23b2987e7e829851e3d316273147cf6a4a3f324befd6b",
306
- "spec/v2/release.json": "0befa21e6634c82cd3d6be9e487f79b7bf77fd3143ce3e0aed301230753b21bc",
306
+ "spec/v2/release.json": "5eb3b4b185365381f4bbe0443bf08c231af3001ebc5393b8fcc28f1d93b01a8f",
307
307
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
308
- "spec/v2/surface-baseline.json": "fd44c977c6646c0bcbd85f9f5c4dce620bba29ee56b10cd077e3f71437e0276a"
308
+ "spec/v2/surface-baseline.json": "20fa0652d150e712e5403d2635d4ff5b53c0123d5af25e45c060582835f7cb35"
309
309
  },
310
- "corpusCommit": "f84011f0ce7ba068e53c1aa2b92d17fa97f5df5f"
310
+ "corpusCommit": "b18ad74419ad18353685a28306424865a5d09f90"
311
311
  }