@openwop/openwop-conformance 1.21.0 → 1.23.0

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +43 -2
  2. package/README.md +61 -63
  3. package/api/asyncapi.yaml +54 -38
  4. package/api/openapi.yaml +34 -6
  5. package/coverage.md +381 -202
  6. package/fixtures/connection-packs/connection-pack-github.json +31 -0
  7. package/fixtures.md +120 -101
  8. package/package.json +1 -1
  9. package/schemas/README.md +1 -0
  10. package/schemas/capabilities.schema.json +49 -0
  11. package/schemas/connection-pack-manifest.schema.json +161 -0
  12. package/schemas/run-event-payloads.schema.json +6 -5
  13. package/schemas/run-event.schema.json +11 -2
  14. package/schemas/run-options.schema.json +1 -2
  15. package/schemas/run-snapshot.schema.json +2 -1
  16. package/schemas/suspend-request.schema.json +5 -0
  17. package/src/scenarios/connection-pack-manifest-valid.test.ts +122 -0
  18. package/src/scenarios/connection-pack-no-credential-material.test.ts +125 -0
  19. package/src/scenarios/connection-pack-reach-exclusive.test.ts +85 -0
  20. package/src/scenarios/connection-pack-write-reconsent.test.ts +91 -0
  21. package/src/scenarios/connection-provider-resolution.test.ts +153 -0
  22. package/src/scenarios/cross-host-traceparent-propagation.test.ts +3 -3
  23. package/src/scenarios/fixtures-valid.test.ts +34 -0
  24. package/src/scenarios/grpc-transport.test.ts +108 -0
  25. package/src/scenarios/i18n-negotiation.test.ts +181 -0
  26. package/src/scenarios/interrupt-token-matrix.test.ts +2 -2
  27. package/src/scenarios/media-url-inline-cap.test.ts +5 -3
  28. package/src/scenarios/spec-corpus-validity.test.ts +107 -0
  29. package/src/scenarios/stream-text-fixture.test.ts +212 -0
  30. package/src/scenarios/version-fold.test.ts +193 -0
  31. package/src/scenarios/wasm-pack-memory-cap.test.ts +4 -2
  32. package/src/scenarios/webhook-tenant-isolation.test.ts +184 -0
package/api/asyncapi.yaml CHANGED
@@ -2,12 +2,12 @@ asyncapi: 3.1.0
2
2
 
3
3
  info:
4
4
  title: Workflow Orchestration Protocol (openwop) SSE Event Stream
5
- version: "1.0"
5
+ version: "1.1.0"
6
6
  externalDocs:
7
7
  description: openwop spec v1 corpus
8
8
  url: https://openwop.dev/spec/v1/
9
9
  description: |
10
- Canonical AsyncAPI 3.0 specification for the openwop server's
10
+ Canonical AsyncAPI 3.1.0 specification for the openwop server's
11
11
  Server-Sent Events surface. Formalizes `stream-modes.md`
12
12
  and references the run-event JSON Schema via `$ref` so external SDK
13
13
  authors can codegen typed consumers without re-reading the prose.
@@ -55,18 +55,27 @@ servers:
55
55
  channels:
56
56
 
57
57
  heartbeatEvents:
58
- address: /heartbeats/{heartbeatId}/events
58
+ # Logical channel — `address: null` per AsyncAPI 3.x ("address not
59
+ # applicable / host-defined"). RFC 0094 §I: host-capabilities.md
60
+ # §host.heartbeat defines the two heartbeat events but documents NO
61
+ # HTTP delivery path for them (they are heartbeat-scoped, NOT
62
+ # run-event-log entries, so they do not ride /runs/{runId}/events
63
+ # either). The previous `/heartbeats/{heartbeatId}/events` address
64
+ # implied an undocumented REST surface; the delivery transport is a
65
+ # host concern until an RFC specifies one.
66
+ address: null
59
67
  title: Heartbeat evaluation events (RFC 0060)
60
- summary: Per-tick heartbeat evaluation + state-change notifications.
68
+ summary: Per-tick heartbeat evaluation + state-change notifications (logical channel).
61
69
  description: |
62
70
  RFC 0060 `host.heartbeat`. Heartbeat-scoped (NOT a run-event
63
71
  stream): a host advertising `capabilities.heartbeat.supported: true`
64
72
  emits `heartbeat.evaluated` every tick and `heartbeat.stateChanged`
65
73
  only on a predicate-state transition. Both are observability-only;
66
74
  consumers MAY ignore them.
67
- parameters:
68
- heartbeatId:
69
- description: Host-assigned heartbeat identifier.
75
+
76
+ LOGICAL channel: `host-capabilities.md` §host.heartbeat documents
77
+ the event shapes but no HTTP address; how a host delivers them
78
+ (webhook, host-internal bus, vendor stream) is host-defined.
70
79
  messages:
71
80
  heartbeatEvaluated: { $ref: '#/components/messages/HeartbeatEvaluated' }
72
81
  heartbeatStateChanged: { $ref: '#/components/messages/HeartbeatStateChanged' }
@@ -200,6 +209,13 @@ operations:
200
209
  for resumption — server begins streaming from the sequence
201
210
  AFTER the supplied ID and MUST NOT re-emit the resumption
202
211
  point itself.
212
+
213
+ Mixed mode (RFC 0094 §I note): the binding's single-value
214
+ `streamMode` enum below describes THIS mode's pure subscription;
215
+ `streamMode` additionally accepts comma-separated combinations
216
+ (e.g. `updates,messages`) per `stream-modes.md` §"Mixed mode" —
217
+ union-of-filters semantics, per-event `event:` labels.
218
+ `values` MUST NOT combine with other modes.
203
219
  bindings:
204
220
  http:
205
221
  method: GET
@@ -217,6 +233,11 @@ operations:
217
233
  $ref: '#/channels/runEventsValues'
218
234
  title: Subscribe to values stream
219
235
  summary: Receive full state snapshots after every transition.
236
+ description: |
237
+ Mixed mode (RFC 0094 §I note): `values` is EXCLUSIVE — it MUST NOT
238
+ be combined in a comma-separated `streamMode` list
239
+ (`stream-modes.md` §"Mixed mode": state.snapshot semantics need
240
+ exclusive ownership). The binding's single-value enum is exact here.
220
241
  bindings:
221
242
  http:
222
243
  method: GET
@@ -234,6 +255,12 @@ operations:
234
255
  $ref: '#/channels/runEventsMessages'
235
256
  title: Subscribe to messages stream
236
257
  summary: Receive per-token AI chunks.
258
+ description: |
259
+ Mixed mode (RFC 0094 §I note): the binding's single-value
260
+ `streamMode` enum below describes the pure `messages` subscription;
261
+ `streamMode` additionally accepts comma-separated combinations
262
+ (e.g. `updates,messages`) per `stream-modes.md` §"Mixed mode".
263
+ `values` MUST NOT combine with other modes.
237
264
  bindings:
238
265
  http:
239
266
  method: GET
@@ -251,6 +278,12 @@ operations:
251
278
  $ref: '#/channels/runEventsDebug'
252
279
  title: Subscribe to debug stream
253
280
  summary: Receive every engine event including internal/log/lease.
281
+ description: |
282
+ Mixed mode (RFC 0094 §I note): the binding's single-value
283
+ `streamMode` enum below describes the pure `debug` subscription;
284
+ `streamMode` additionally accepts comma-separated combinations
285
+ (e.g. `updates,debug`) per `stream-modes.md` §"Mixed mode".
286
+ `values` MUST NOT combine with other modes.
254
287
  bindings:
255
288
  http:
256
289
  method: GET
@@ -496,7 +529,10 @@ components:
496
529
  name: interrupt.requested
497
530
  title: Interrupt requested (canonical HITL primitive)
498
531
  summary: |
499
- The discriminated-union form of approval/clarification/external-event/custom.
532
+ The discriminated-union form of the full `interrupt.md` kind union
533
+ (RFC 0094 §E): approval / clarification / external-event / custom /
534
+ conversation.start / conversation.exchange / conversation.close /
535
+ low-confidence.
500
536
  Servers emitting `interrupt.requested` SHOULD also emit the legacy
501
537
  kind-specific event (`approval.requested` etc) for backward compat
502
538
  until consumers migrate.
@@ -605,33 +641,13 @@ components:
605
641
  $ref: '../schemas/run-snapshot.schema.json'
606
642
 
607
643
  AiMessageChunkPayload:
608
- # S2 closure (2026-04-27): tiered metadata. Bare {nodeId, runId,
609
- # chunk, isLast} is the minimum compliant payload; `meta`
610
- # adds Tier 1 typed slots (finishReason / logprobs / toolCalls /
611
- # model / usage) and a Tier 2 provider-pass-through escape hatch.
612
- # Schema definition lives at run-event-payloads.schema.json#$defs.outputChunk
613
- # referenced here verbatim so the SSE consumer + run-event log
614
- # share a single shape contract.
615
- type: object
616
- required: [nodeId, runId, chunk, isLast]
617
- properties:
618
- nodeId: { type: string }
619
- runId: { type: string }
620
- chunk:
621
- type: string
622
- description: The new token(s) since the previous chunk.
623
- isLast:
624
- type: boolean
625
- description: True for the final chunk of a given AI node call.
626
- meta:
627
- type: object
628
- description: |
629
- Tiered metadata. Tier 1: typed slots — `finishReason`
630
- ("stop"|"length"|"tool_calls"|"content_filter"), `logprobs`,
631
- `toolCalls`, `model`, `usage` ({promptTokens,
632
- completionTokens, totalTokens}). Tier 2: provider-pass-through
633
- via `provider` + `providerExtensions`. Consumers SHOULD prefer
634
- Tier 1; Tier 2 is the escape hatch for fields the spec hasn't
635
- typed yet. See run-event-payloads.schema.json#$defs._chunkMeta
636
- for the full definition + per-field constraints.
637
- additionalProperties: true
644
+ # S2 closure (2026-04-27) + RFC 0094 §D single-sourcing: the payload
645
+ # is the canonical `outputChunk` definition in
646
+ # run-event-payloads.schema.json referenced (not hand-copied, the
647
+ # prior inline copy was one of the three drifting definitions) so the
648
+ # SSE consumer + run-event log share exactly one shape contract.
649
+ # Minimum compliant payload: {nodeId, runId, chunk, isLast} per
650
+ # stream-modes.md §messages; `meta` adds Tier 1 typed slots
651
+ # (finishReason / logprobs / toolCalls / model / usage) and a Tier 2
652
+ # provider-pass-through escape hatch (see #$defs/_chunkMeta).
653
+ $ref: '../schemas/run-event-payloads.schema.json#/$defs/outputChunk'
package/api/openapi.yaml CHANGED
@@ -2,7 +2,7 @@ openapi: 3.1.0
2
2
 
3
3
  info:
4
4
  title: Workflow Orchestration Protocol (openwop) API
5
- version: "1.0"
5
+ version: "1.1.0"
6
6
  summary: REST surface for declaring, executing, suspending, resuming, and observing multi-step workflows.
7
7
  description: |
8
8
  Canonical OpenAPI 3.1 specification for openwop-compliant servers. Generated from `rest-endpoints.md` and references the JSON Schemas in `schemas/`.
@@ -16,6 +16,16 @@ info:
16
16
  - `run-options.md` — `configurable`/`tags`/`metadata`
17
17
  - `interrupt.md` — HITL primitive
18
18
  - `replay.md` — `:fork` endpoint
19
+
20
+ **Registry scope (RFC 0094 §I).** This document specifies the HOST
21
+ surface. The production node-pack registry surface (`/v1/packs/*` —
22
+ publish/get/delete/sig, deprecation, yank, key rotation) is specified in
23
+ `spec/v1/node-packs.md` §"Registry HTTP API" + `spec/v1/registry-operations.md`
24
+ and is served by a registry service (e.g. the planned hosted reference
25
+ registry `packs.openwop.dev`, or a third-party/private registry
26
+ implementation) — a distinct deployable, out of scope for this host
27
+ OpenAPI document. Only the test-mode mirror (`/v1/packs-test/*`, RFC 0025)
28
+ is host-mounted and documented here.
19
29
  contact:
20
30
  name: openwop spec working group
21
31
  url: https://openwop.dev/spec/v1/
@@ -75,6 +85,11 @@ tags:
75
85
  19-code publish error catalog without `packs:publish` scope on the real registry. Hosts that haven't
76
86
  mounted this surface MUST return `404 Not Found` for every path under `/v1/packs-test/`.
77
87
 
88
+ Scope note (RFC 0094 §I): the PRODUCTION `/v1/packs/*` surface these paths mirror is specified in
89
+ `spec/v1/registry-operations.md` + `node-packs.md` §"Registry HTTP API" and is served by a registry
90
+ service (a distinct deployable from the host), so it is intentionally NOT defined in this host
91
+ OpenAPI document.
92
+
78
93
  # ─────────────────────────────────────────────────────────────────────────────
79
94
  # PATHS
80
95
  # ─────────────────────────────────────────────────────────────────────────────
@@ -178,7 +193,13 @@ paths:
178
193
  # routing fields, plus the openwop RunOptions overlay (configurable,
179
194
  # tags, metadata) hoisted into a first-class JSON Schema at
180
195
  # ../schemas/run-options.schema.json. allOf composes the two
181
- # so callers see one unified body shape.
196
+ # so callers see one unified body shape. RFC 0094 §A: neither
197
+ # allOf branch is closed via additionalProperties (two closed
198
+ # branches inside one allOf made every documented body
199
+ # unsatisfiable); the composed request is closed here with
200
+ # `unevaluatedProperties: false` (JSON Schema 2020-12), so
201
+ # undeclared properties still fail at the composition level.
202
+ unevaluatedProperties: false
182
203
  allOf:
183
204
  - type: object
184
205
  properties:
@@ -215,7 +236,6 @@ paths:
215
236
  type: string
216
237
  minLength: 1
217
238
  description: RFC 0081 — the manifest agent the eval suite targets. Required when mode is `eval`.
218
- additionalProperties: false
219
239
  if:
220
240
  properties: { mode: { const: eval } }
221
241
  required: [mode]
@@ -1843,6 +1863,9 @@ paths:
1843
1863
  `conflict`/`version_conflict`) MUST be served verbatim. The
1844
1864
  test catalog MUST be isolated per RFC 0025 §C — a pack PUT'd
1845
1865
  here MUST NOT appear in `GET /v1/packs/{name}` listings.
1866
+ The mirrored production path is registry-service surface
1867
+ (`registry-operations.md`), not defined in this host document
1868
+ (see the `packs-test` tag scope note).
1846
1869
  operationId: putTestPackTarball
1847
1870
  parameters:
1848
1871
  - in: header
@@ -1914,7 +1937,7 @@ paths:
1914
1937
  get:
1915
1938
  tags: [packs-test]
1916
1939
  summary: Fetch a published test-catalog tarball.
1917
- description: 'Mirror of `GET /v1/packs/{name}/-/{version}.tgz`. Returns the gzipped tarball bytes with `Content-Type: application/tar+gzip` and an `ETag: "sha256-..."` matching the manifest''s `tarballSha256`.'
1940
+ description: 'Mirror of `GET /v1/packs/{name}/-/{version}.tgz`. Returns the gzipped tarball bytes with `Content-Type: application/tar+gzip` and an `ETag: "sha256-..."` matching the manifest''s `tarballSha256`. The mirrored production path is registry-service surface (`registry-operations.md`), not defined in this host document (see the `packs-test` tag scope note).'
1918
1941
  operationId: getTestPackTarball
1919
1942
  responses:
1920
1943
  '200':
@@ -1951,7 +1974,10 @@ paths:
1951
1974
  for versions older than the registry's unpublish window
1952
1975
  (default 72h). Test-mode implementations MAY shorten the
1953
1976
  window for tractable conformance fixtures but MUST surface
1954
- the same error code.
1977
+ the same error code. The mirrored production path is
1978
+ registry-service surface (`registry-operations.md`), not
1979
+ defined in this host document (see the `packs-test` tag
1980
+ scope note).
1955
1981
  operationId: deleteTestPackVersion
1956
1982
  responses:
1957
1983
  '204':
@@ -1983,7 +2009,9 @@ paths:
1983
2009
  description: |
1984
2010
  Mirror of `GET /v1/packs/{name}/-/{version}.sig`. Returns the
1985
2011
  signature blob over `pack.json` for this version. MAY 302-redirect
1986
- to a storage-backend signed URL.
2012
+ to a storage-backend signed URL. The mirrored production path is
2013
+ registry-service surface (`registry-operations.md`), not defined
2014
+ in this host document (see the `packs-test` tag scope note).
1987
2015
  operationId: getTestPackSignature
1988
2016
  responses:
1989
2017
  '200':