@openwop/openwop-conformance 2.44.9 → 2.45.1
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 +37 -0
- package/README.md +3 -2
- package/dist/spec-artifacts.lock.json +2 -2
- package/package.json +2 -2
- package/requirements.json +150 -131
- package/scenario-majors.json +5 -2
- package/schemas/CORPUS-STAMP.json +12 -12
- package/src/lib/run-list-walk.ts +65 -0
- package/src/scenarios/agentConfidenceEscalation.test.ts +8 -1
- package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +8 -1
- package/src/scenarios/agentMemoryRedactionContract.test.ts +8 -1
- package/src/scenarios/agentMemoryRoundTrip.test.ts +8 -1
- package/src/scenarios/agentMemoryTtlExpiry.test.ts +8 -1
- package/src/scenarios/agentMessageReducer.test.ts +8 -1
- package/src/scenarios/agentMetadata.test.ts +8 -1
- package/src/scenarios/agentPackCatalog.test.ts +13 -5
- package/src/scenarios/agentPackExport.test.ts +8 -2
- package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +17 -2
- package/src/scenarios/agentPackInstall.test.ts +8 -2
- package/src/scenarios/agentPackProvenance.test.ts +8 -1
- package/src/scenarios/agentReasoningEvents.test.ts +9 -1
- package/src/scenarios/agentReasoningStreaming.test.ts +14 -1
- package/src/scenarios/append-ordering.test.ts +7 -2
- package/src/scenarios/bulk-cancel.test.ts +11 -1
- package/src/scenarios/cap-breach.test.ts +8 -1
- package/src/scenarios/channel-ttl.test.ts +7 -1
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +8 -1
- package/src/scenarios/conversationLifecycle.test.ts +8 -1
- package/src/scenarios/conversationReplayDeterminism.test.ts +8 -2
- package/src/scenarios/conversationVsLegacySuspend.test.ts +8 -1
- package/src/scenarios/cost-attribution.test.ts +17 -4
- package/src/scenarios/debugBundle.test.ts +16 -5
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -2
- package/src/scenarios/dispatch-output-mapping.test.ts +20 -4
- package/src/scenarios/dispatchLoop.test.ts +7 -1
- package/src/scenarios/durability-poison-exhaustion.test.ts +7 -2
- package/src/scenarios/highConcurrency.test.ts +11 -1
- package/src/scenarios/host-callback-declaration.test.ts +10 -1
- package/src/scenarios/identity-passthrough.test.ts +7 -1
- package/src/scenarios/interrupt-approval.test.ts +25 -5
- package/src/scenarios/interrupt-auth-required-resume.test.ts +9 -3
- package/src/scenarios/interrupt-external-event-correlation.test.ts +9 -2
- package/src/scenarios/interrupt-parent-child-cascade.test.ts +10 -2
- package/src/scenarios/interrupt-quorum-resolution.test.ts +9 -2
- package/src/scenarios/interrupt-token-matrix.test.ts +11 -3
- package/src/scenarios/interruptRace.test.ts +13 -3
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +14 -3
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +15 -3
- package/src/scenarios/multi-node-ordering.test.ts +7 -1
- package/src/scenarios/node-failed-payload-shape.test.ts +7 -1
- package/src/scenarios/orchestratorConservativePath.test.ts +8 -1
- package/src/scenarios/orchestratorDispatch.test.ts +9 -1
- package/src/scenarios/orchestratorTermination.test.ts +8 -1
- package/src/scenarios/owner-subject-echo.test.ts +9 -2
- package/src/scenarios/pause-resume.test.ts +19 -8
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +9 -2
- package/src/scenarios/prompt-end-to-end-events.test.ts +10 -2
- package/src/scenarios/replay-fork-arbitrary.test.ts +11 -4
- package/src/scenarios/restart-during-run.test.ts +7 -1
- package/src/scenarios/secret-leakage-otel-attribute.test.ts +14 -5
- package/src/scenarios/stream-text-fixture.test.ts +8 -2
- package/src/scenarios/streamReconnect.test.ts +8 -2
- package/src/scenarios/subworkflow.test.ts +9 -1
- package/src/scenarios/v2-cors-preflight.test.ts +141 -0
- package/src/scenarios/v2-run-list.test.ts +14 -16
- package/src/scenarios/version-fold.test.ts +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [2.45.1] — 2026-09-29 — the run-list legs stop walking once they find their runs, and no scenario skips every test at describe level
|
|
4
|
+
|
|
5
|
+
- **No scenario file skips every test at describe level any more, and the guard is a hard rule** (patch; no requirement added or removed; the gates are identical, and only their placement moves).
|
|
6
|
+
- **Background.** `describe-level-skip.test.ts` (2.44.9, #1686) ratcheted 56 non-floor files in which every test sat under `describe.skipIf`. vitest runs no setup hook for such a file, so it recorded no disposition when its gate held, and the runner resolved it to a report-derived `blocked` naming no reason.
|
|
7
|
+
- **The conversion.** Each file now un-gates its `describe`s and opens every test with `if (GATE) return softSkip(...GATE_WHY)`, done by an AST codemod over the unchanged predicates. `GATE_WHY` is a module constant naming the RFC 0148 §A disposition, checked in this order:
|
|
8
|
+
- `inapplicable` for a capability the host does not advertise (`isAgentSupported()`, `hasLongTermMemory()`, `isConversationPrimitiveSupported()`, `isOrchestratorSupported()`, reasoning verbosity `off`, and the like), and for no target or a published package without the scenario sources;
|
|
9
|
+
- `skipped` for an operator opt-in that is not set (`OPENWOP_RUN_RESTART_DURING_RUN`, `OPENWOP_SKIP_SCALE_PRODUCTION`);
|
|
10
|
+
- `blocked` for a withheld fixture, naming it.
|
|
11
|
+
|
|
12
|
+
A capability that is absent wins over a missing fixture, because then the requirement does not apply at all. `durability-poison-exhaustion` keeps the `inapplicable` its module-scope record already gives a missing fixture. `agentPackHandoffSchemaValidation`'s nested `describe.skipIf(!hasHandoffValidation())` is converted too.
|
|
13
|
+
- **Measured.** Against a stub host that advertises no fixtures and no capabilities, with the ledger on: before, 4 of the 56 files wrote a row; after, all 56 do, and none carries the unclassified-return detail (31 `blocked`, 23 `inapplicable`, 1 `skipped`, and 1 `executed-pass` for the corpus check `host-callback-declaration`, which passes both before and after).
|
|
14
|
+
- **The guard.** The ratchet (ceiling 56) is replaced by a hard rule: no scenario file, floor or not, may skip every test at describe level. Adding such a file fails with the offender named.
|
|
15
|
+
|
|
16
|
+
- **`v2-run-list`: a bounded walk instead of a full-history walk** (patch; no requirement added or removed).
|
|
17
|
+
- **Defect.** `walk()` followed `nextCursor` to the end of the list or `MAX_PAGES` (50), although the list is newest first (`runs.md` §List) and the two runs the leg had just created sit on page 1. A long-lived host's conformance tenant gains hundreds of runs per cut, so the walk grew with the tenant's age. On openwop-app's b29427fef major-2 cut it outran the 30 s test timeout, and `0182.run-list.tenant-scoped` failed on the tenant's history, not on host behaviour.
|
|
18
|
+
- **Fix.** New pure helper `lib/run-list-walk.ts` (`walkRunList`). It stops once every created id is seen, then follows a two-page tail, so a host-minted cursor is still exercised. A created id that never appears within the 50-page cap fails the leg; it is never a silent pass.
|
|
19
|
+
- **Unchanged checks.** Every page walked is still validated against `run-list-response.schema.json`, checked against `maxPageSize`, and every id seen is checked for the caller's tenant (identity.md §5).
|
|
20
|
+
- **New check.** The unfiltered leg asserts newest-first: the second created run is listed before the first. The filtered leg uses the same walk.
|
|
21
|
+
- **Proof.**
|
|
22
|
+
- Server-free self-test `run-list-walk.test.ts` (6). Removing the early stop fails it (51 fetches, not 3), and so does dropping the tail.
|
|
23
|
+
- Measured on a stub host with 40 prior runs, 3 per page:
|
|
24
|
+
- created runs on page 1: pass.
|
|
25
|
+
- created runs on pages 3–4: pass (the walk finds them).
|
|
26
|
+
- one created run omitted: fail.
|
|
27
|
+
- another tenant's run interleaved: fail on the tenant check.
|
|
28
|
+
- created runs listed oldest first: fail on the new order check.
|
|
29
|
+
|
|
30
|
+
## [2.45.0] — 2026-09-29 — a host that grants an origin admits the contract's request headers in preflight
|
|
31
|
+
|
|
32
|
+
- **New scenario `v2-cors-preflight`: `openwop.requirement.headers.cors-preflight-admits`** (#1763; minor, since a scenario is added). It witnesses the new `headers.md` §Cross-origin preflight (Class 3).
|
|
33
|
+
- **Probe.** For every operation in `spec/v2/path-manifest.json` it sends `OPTIONS <path>` with `Origin`, `Access-Control-Request-Method`, and `Access-Control-Request-Headers`. The headers requested are that operation's declared request headers, plus `authorization` when authenticated and `content-type` with a body.
|
|
34
|
+
- **Reading.** It reads the answer as the Fetch standard's CORS-preflight check does. A CORS-safelisted method needs no listing. `*` admits nothing once credentials are allowed, and never admits `authorization`.
|
|
35
|
+
- **Gate.** It is self-gated on the host's grant: an operation whose preflight does not grant the origin is not judged, and the row is `inapplicable` when none is. The origin is `OPENWOP_CORS_ORIGIN` (default `https://conformance.invalid`), so an allowlisting host's operator can name an allowed one.
|
|
36
|
+
- **Verdicts.** Fails naming each granted operation and the missing names. Passes with an `observed:` detail (granted count).
|
|
37
|
+
- **Measured on stub hosts.** A copy of openwop-app's current middleware (reflect any origin, explicit list) records `executed-fail` on four operations: `getCapabilities` and `getRun` (`If-None-Match`), `createRun` (`OpenWOP-Force-Engine-Version`), `getContentPage` (`Accept-Language`). A host that reflects the request headers passes. A host that answers no CORS is `inapplicable`.
|
|
38
|
+
- **The per-operation sets come from the manifest.** `spec/v2/path-manifest.json` now carries `requestHeaders`, `authenticated` and `requestBody` per operation, written by `derive-v2-api.py` from `api/v2/openapi.yaml`, so the suite reads them without a YAML parser.
|
|
39
|
+
|
|
3
40
|
## [2.44.9] — 2026-09-29 — a floor gated on a withheld fixture records `blocked`, not nothing
|
|
4
41
|
|
|
5
42
|
- **Nine v1 floor files no longer skip at describe level** (#1686). Each of the following gated every test with `describe.skipIf(!isFixtureAdvertised(…))`: `eventOrdering`, `failure-path`, `idempotency`, `interrupt-clarification`, `replay-fork`, `runs-lifecycle`, `stream-modes`, `stream-modes-buffer` and `stream-modes-mixed`. When every test in a file is describe-skipped, vitest runs none of `setup.ts`'s hooks for it, so the file's floor requirement got no ledger row. `--certify` then counted the floor unclassified and rejected the whole certification, not just the profile. `byok-roundtrip` hit this on openwop-app's 2026-09-28 major-1 cut (`certified: none`) and was fixed in #1708. Each test in the nine files now opens with `if (SKIP) return softSkip('blocked', NO_FIXTURE_REASON)`, so a withheld fixture records `blocked` with the fixture named. That denies only the affected profile. It is `blocked`, not `inapplicable`: the host advertises the capability the floor witnesses, so the requirement applies to the captured discovery, and a withheld fixture is exactly RFC 0148 §A's `blocked` ("a required seam, fixture … was unavailable"). `byok-roundtrip`'s `blocked` (#1708) stands for the same reason. Measured against a stub host that advertises no fixtures, with the ledger on: before, `runs-lifecycle` wrote no ledger row; after, `openwop.floor.runs-lifecycle` is `blocked` with the reason. A test that passed before still passes: the gates are unchanged, only where they sit.
|
package/README.md
CHANGED
|
@@ -135,7 +135,8 @@ 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
|
|
138
|
+
The current suite has 575 scenario files under `src/scenarios/`.
|
|
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`).
|
|
139
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.
|
|
140
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.
|
|
141
142
|
- 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 +482,7 @@ Server-required (added in 1.7.0):
|
|
|
481
482
|
| ------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
482
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. |
|
|
483
484
|
|
|
484
|
-
Current source tree:
|
|
485
|
+
Current source tree: 575 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
|
|
485
486
|
|
|
486
487
|
## Remaining Gaps
|
|
487
488
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.45.1",
|
|
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.
|
|
59
|
+
"@openwop/spec-artifacts": "2.45.1"
|
|
60
60
|
}
|
|
61
61
|
}
|