@openwop/openwop-conformance 2.45.23 → 2.45.24
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 +8 -0
- package/README.md +227 -608
- package/coverage.md +118 -90
- package/dist/spec-artifacts.lock.json +2 -2
- package/fixtures.md +77 -55
- package/package.json +3 -3
- package/requirements.json +68 -68
- package/schemas/CORPUS-STAMP.json +15 -15
- package/src/lib/effect-receiver.ts +12 -1
package/fixtures.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenWOP Conformance Suite — Fixture Workflow Contract
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Defines the fixture workflows a host seeds so the conformance suite can exercise run lifecycle, idempotency, streaming, interrupts, replay and the other fixture-gated scenarios. RFC 2119 keywords (MUST, SHOULD, MAY) apply to hosts that seed these fixtures. Paths are written in v2 form (unversioned, [`spec/v2/core/versioning.md`](../spec/v2/core/versioning.md)); a v1 host serves the same operations under `/v1/`. `/v1/host/sample/...` paths below are the v1 host test seams; the v2 seams are in [`api/seams-v2.yaml`](../api/seams-v2.yaml).
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
Run-lifecycle conformance tests need a stable target — a workflow whose `workflowId`, expected events, and terminal status are agreed in advance. Without this, every implementation defines its own test workflows and the conformance suite can't run cross-implementation.
|
|
10
10
|
|
|
11
|
-
This document defines
|
|
11
|
+
This document defines the fixture workflows whose canonical definitions live alongside the conformance suite (`fixtures/*.json`). A host MUST seed the fixtures its advertised scenarios need into its workflow store before running the suite against itself.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
## Seeding contract
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
A host that seeds the fixtures MUST:
|
|
18
18
|
|
|
19
19
|
1. Accept the canonical JSON fixture definitions in `fixtures/*.json` verbatim (they validate against `../schemas/workflow-definition.schema.json`).
|
|
20
|
-
2. Persist each fixture under its declared `id` so that subsequent `GET /
|
|
20
|
+
2. Persist each fixture under its declared `id` so that a subsequent `GET /workflows/{workflowId}` (`getWorkflow`) returns the seeded definition.
|
|
21
21
|
3. Treat seeding as idempotent — running the seeder repeatedly MUST NOT produce duplicate runs, error states, or version drift.
|
|
22
22
|
4. Expose the seeded fixtures to runs created with the conformance suite's API key.
|
|
23
23
|
|
|
@@ -36,7 +36,7 @@ Servers MUST NOT require fixtures to be re-uploaded on every conformance run —
|
|
|
36
36
|
All fixtures MUST advertise:
|
|
37
37
|
|
|
38
38
|
- **`workflowId`** — exact string clients use to start runs
|
|
39
|
-
- **Trigger** — must be `manual` so the conformance suite can call `POST /
|
|
39
|
+
- **Trigger** — must be `manual` so the conformance suite can call `POST /runs` (`createRun`) without channel-specific setup
|
|
40
40
|
- **Inputs** — schema declared via `variables[]`
|
|
41
41
|
- **Expected behavior** — terminal status, expected event types, timing bounds
|
|
42
42
|
|
|
@@ -81,13 +81,13 @@ All fixtures MUST advertise:
|
|
|
81
81
|
| Agent Pack Export | `conformance-agent-pack-export` | Phase 2 — workspace agents project to AgentManifest at `GET /v1/packs/export` | `completed` | ≤ 5s |
|
|
82
82
|
| Agent Pack Provenance | `conformance-agent-pack-provenance` | Phase 2 — `sourceManifestId` provenance round-trip | `completed` | ≤ 10s |
|
|
83
83
|
| Agent Pack Handoff Schema Validation | `conformance-agent-pack-handoff-schema-validation` | Phase 2 / HV-1 — host validates dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef` per RFC 0003 §D. Three branches: valid-task → `completed`; invalid-task → `failed` with structured violation; mock-return-violation → violation surfaced before persistence. | varies by scenario | ≤ 5s |
|
|
84
|
-
| WorkflowVariable format advisory | `conformance-workflow-variable-format-advisory` | RFC 0136 req 3 — a variable declares `format: "email"` with an off-format `defaultValue`; `format` is advisory, so the run MUST complete (a value/format mismatch MUST NOT fail the run). Run via `POST /
|
|
84
|
+
| WorkflowVariable format advisory | `conformance-workflow-variable-format-advisory` | RFC 0136 req 3 — a variable declares `format: "email"` with an off-format `defaultValue`; `format` is advisory, so the run MUST complete (a value/format mismatch MUST NOT fail the run). Run via `POST /runs` (portable pre-registered pattern). `workflow-variable-format.test.ts` leg B2. | `completed` | ≤ 5s |
|
|
85
85
|
| Dispatch Input Mapping | `conformance-dispatch-input-mapping` | RFC 0022 §A / HVMAP-1a — host honors `inputMapping` on `core.dispatch`. Capability-gated on `capabilities.agents.dispatchMapping`. | `completed` | ≤ 5s |
|
|
86
86
|
| Dispatch Output Mapping | `conformance-dispatch-output-mapping` | RFC 0022 §A / HVMAP-1b — host harvests child variables via `outputMapping` on `core.dispatch`. Capability-gated on `capabilities.agents.dispatchMapping`. | `completed` | ≤ 5s |
|
|
87
87
|
| Dispatch Cross-Worker Handoff | `conformance-dispatch-cross-worker-handoff` | RFC 0022 §A / HVMAP-1c — sequential fan-out: child-a writes via `perWorkerOutputMappings`, child-b reads via `perWorkerInputMappings`. Capability-gated on `capabilities.agents.dispatchMapping`. | `completed` | ≤ 10s |
|
|
88
88
|
| subWorkflow Input Mapping | `conformance-subworkflow-input-mapping` | RFC 0022 §B / HVMAP-2 — host honors `inputMapping` on `core.subWorkflow`; overrides matching `defaultValue` declarations on the child. Capability-gated on `capabilities.subWorkflow.inputMapping`. | `completed` | ≤ 10s |
|
|
89
|
-
| subWorkflow Input Mapping (child) | `conformance-subworkflow-input-mapping-child` | RFC 0022 §B / HVMAP-2 — child workflow for the input-mapping scenario. Declares `receivedPrdId.defaultValue='baked-in'`; parent's `inputMapping` MUST override that default. Single noop node; final variables read via `GET /
|
|
90
|
-
| Dispatch Input Mapping (child) | `conformance-dispatch-input-mapping-child` | RFC 0022 §A / HVMAP-1a — child workflow for the dispatch input-mapping scenario. Single noop node; the scenario reads this child's `inputs_json` via `GET /
|
|
89
|
+
| subWorkflow Input Mapping (child) | `conformance-subworkflow-input-mapping-child` | RFC 0022 §B / HVMAP-2 — child workflow for the input-mapping scenario. Declares `receivedPrdId.defaultValue='baked-in'`; parent's `inputMapping` MUST override that default. Single noop node; final variables read via `GET /runs/{runId}` for the assertion. | `completed` | ≤ 5s |
|
|
90
|
+
| Dispatch Input Mapping (child) | `conformance-dispatch-input-mapping-child` | RFC 0022 §A / HVMAP-1a — child workflow for the dispatch input-mapping scenario. Single noop node; the scenario reads this child's `inputs_json` via `GET /runs/{childRunId}` and asserts `inputs.childGreeting === 'Alice'`. | `completed` | ≤ 5s |
|
|
91
91
|
| Dispatch Output Mapping (child) | `conformance-dispatch-output-mapping-child` | RFC 0022 §A / HVMAP-1b — child workflow for the dispatch output-mapping scenario. Declares `childOutcome.defaultValue='done'`; on terminal, parent's `outputMapping` harvests `childOutcome → parentResult`. | `completed` | ≤ 5s |
|
|
92
92
|
| Dispatch Cross-Worker Handoff (child-a) | `conformance-dispatch-cross-worker-handoff-child-a` | RFC 0022 §A / HVMAP-1c — first child of the cross-worker-handoff scenario. Declares `output.defaultValue='hello'`; on terminal, parent's `perWorkerOutputMappings.child-a` harvests `output → sharedVar`. | `completed` | ≤ 5s |
|
|
93
93
|
| Dispatch Cross-Worker Handoff (child-b) | `conformance-dispatch-cross-worker-handoff-child-b` | RFC 0022 §A + §D / HVMAP-1c — second child of the cross-worker-handoff scenario. Sequential fan-out — runs after child-a; receives parent's `sharedVar` via `perWorkerInputMappings.child-b` onto its `input` input. Scenario reads child-b's `inputs_json` to assert `inputs.input === 'hello'`. | `completed` | ≤ 5s |
|
|
@@ -97,7 +97,7 @@ All fixtures MUST advertise:
|
|
|
97
97
|
| subWorkflow Mid-Run Mutation (child) | `conformance-subworkflow-mid-run-mutation-child` | RFC 0022 §B / HVMAP-2-no-midrun-propagation — child workflow with a `core.approvalGate` that suspends so the parent can mutate its variable bag mid-run. Declares `receivedPrdId.defaultValue='baked-in'` (overridden at dispatch by inputMapping). | `completed` | ≤ 30s |
|
|
98
98
|
| Dispatch Per-Worker Mapping Override | `conformance-dispatch-per-worker-override` | RFC 0022 §A / HVMAP-1c-override — parent with BOTH a default `inputMapping` (`{ input: 'defaultX' }`) AND `perWorkerInputMappings.child-b: { input: 'sharedVar' }`. Verifies `effectiveInputMapping` precedence per §A: child-a receives the default, child-b receives the override. Reuses `conformance-dispatch-cross-worker-handoff-child-a` + `-child-b`. | `completed` | ≤ 30s |
|
|
99
99
|
| Dispatch deterministic-fail child | `conformance-dispatch-deterministic-fail-child` | RFC 0022 §B / HVMAP-1b-failed — child workflow that ALWAYS terminates `failed` via `core.fail`. Used by `conformance-dispatch-output-mapping` to verify the parent's `outputMapping` is SKIPPED when the child fails terminally. | `failed` | ≤ 5s |
|
|
100
|
-
| Dispatch cancellable child | `conformance-dispatch-cancellable-child` | RFC 0022 §B / HVMAP-1b-cancelled — child workflow with a long `core.delay` so the test cancels it externally via `POST /
|
|
100
|
+
| Dispatch cancellable child | `conformance-dispatch-cancellable-child` | RFC 0022 §B / HVMAP-1b-cancelled — child workflow with a long `core.delay` so the test cancels it externally via `POST /runs/{childRunId}/cancel`. Verifies the parent's `outputMapping` is SKIPPED when the child terminates `cancelled`. | `cancelled` | ≤ 60s |
|
|
101
101
|
| Multi-Agent Handoff (parent) | `conformance-multi-agent-handoff` | RFC 0037 (`version: 1`) — exercises the planner→worker handoff state machine. Supervisor decides one `next-worker`, dispatch spawns the child, harvests outputMapping. Conformance reads the event log for the 4 `core.workflowChain.event` transition records in causation-chained order (`dispatch.began → dispatch.succeeded → child.completed → output.harvested`). Capability-gated on `capabilities.multiAgent.executionModel.supported`. | `completed` | ≤ 30s |
|
|
102
102
|
| Multi-Agent Handoff (child) | `conformance-multi-agent-handoff-child` | RFC 0037 (`version: 1`) — child for `conformance-multi-agent-handoff`. Declares `childOutcome.defaultValue='handoff-complete'`; the parent's outputMapping harvests it onto `parentResult`, triggering the `output.harvested` transition event. | `completed` | ≤ 5s |
|
|
103
103
|
| Multi-Agent Confidence Escalation | `conformance-multi-agent-confidence-escalation` | RFC 0039 §A (`version: 2`) — exercises the confidence-floor escalation contract. Supervisor's `mockDispatchPlan` carries ONE decision with `confidence: 0.3` (below the 0.5 spec floor). The host MUST emit `core.workflowChain.confidence-escalated` AND suspend with a clarification interrupt BEFORE any dispatch.began fires; conformance asserts zero `core.workflowChain.event` records (no dispatch). Capability-gated on `capabilities.multiAgent.executionModel.version >= 2`. | `waiting-clarification` | ≤ 30s |
|
|
@@ -126,7 +126,7 @@ All fixtures MUST advertise:
|
|
|
126
126
|
| A2A Task Roundtrip | `conformance-a2a-task-roundtrip` | Track 6 — host consumes the conformance suite's synthetic A2A peer; covers drift points #3 (`AUTH_REQUIRED`) and #4 (`REJECTED`). Node `core.conformance.a2a-invoke` is a **conformance-RESERVED** typeId (renamed 2026-08-16 from `core.a2a.invoke`, a multi-segment `core.*` id no host shipped and the corpus never defined): a host that consumes A2A peers MUST map it to its A2A bridge node (a host-extension node — `a2a-integration.md` §"State projection"); a host that does not consume A2A MUST NOT advertise this fixture | `failed` or `waiting-input` (per `driftScenario` input) | ≤ 30s |
|
|
127
127
|
| WASM Pack Roundtrip | `conformance-wasm-pack-roundtrip` | RFC 0008 — invokes `vendor.openwop.rust-hello.greet` (loaded WASM pack); exercises required exports + at least one import | `completed` | ≤ 10s |
|
|
128
128
|
| WASM Pack Memory-Cap Breach | `conformance-wasm-pack-memory-cap-breach` | RFC 0008 §K — invokes the deliberately-misbehaving `vendor.openwop.misbehaving.memory-bomb` pack (allocates 1 GiB beyond the host's `memoryPagesMax`). Host MUST emit `cap.breached` with `kind: "wasm-memory"` and drive the run to terminal `failed`. Misbehaving pack lives at `openwop-examples:examples/packs/rust-misbehaving-memory/` (repo-qualified per the 2026-06 monorepo split — the `openwop-examples` sibling repo) and is fixture-only (NOT signed for registry publication). | `failed` (with `cap.breached`) | ≤ 10s |
|
|
129
|
-
| Configurable Schema | `conformance-configurable-schema` | Track 13 — workflow declares `configurableSchema` (`additionalProperties: false`, `recursionLimit: integer ≥ 1`). Suite verifies `GET /
|
|
129
|
+
| Configurable Schema | `conformance-configurable-schema` | Track 13 — workflow declares `configurableSchema` (`additionalProperties: false`, `recursionLimit: integer ≥ 1`). Suite verifies `GET /workflows/{id}` surfaces the schema AND `POST /runs` with a mismatched `configurable` returns `validation_error`. | `completed` (with accepted overlay) | ≤ 5s |
|
|
130
130
|
| Smoke — BYOK Roundtrip | `openwop-smoke-byok-roundtrip` | End-to-end BYOK secret-resolution smoke. Single `conformance.secret.echo` node fetches the host-provisioned canary secret `openwop-conformance-canary-secret`, emits SHA-256 hex + byte length to variables — never the raw value. Spec: `run-options.md` §"Credential references" + `auth.md` §"Secret resolution" + `observability.md` §"Redaction". | `completed` | ≤ 10s |
|
|
131
131
|
| Secrets — Run Witness | `openwop-secrets-run-witness` | RFC 0229 §C — one `core.secret.witness` node. The client supplies a value with the run (`runSecrets`, a `run:` ref) and its SHA-256 as an input; the node outputs only `{ matched }`. It can confirm only a value the caller already holds, so it is safe to advertise in production. Advertised by every host that advertises `secrets.runSecrets`. | `completed` (`matched: true` or `false`); `failed` (`credential_forbidden` / `credential_not_found`) on the scope legs | ≤ 10s |
|
|
132
132
|
| Secret — resolve then fail | `conformance-secret-resolve-then-fail` | `host-services.md` §`secrets` — resolves the byok canary exactly as `openwop-smoke-byok-roundtrip`, then `core.fail` fails the run; the canary MUST appear on no surface of the failed run | `failed` | ≤ 10s |
|
|
@@ -145,7 +145,7 @@ All fixtures MUST advertise:
|
|
|
145
145
|
| Phase 4 Replay Divergence | `conformance-phase4-replay-divergence` | RFC 0041 §B — single `core.ai.structuredOutput` node against mock provider. Conformance scenario pre-seeds a 2-entry program via the existing mock-AI program seam: entry [0] returns a valid envelope (original run consumes); entry [1] returns `stopReason: 'safety'` + `refusalText` (`:fork mode: replay` consumes). Phase 4 hosts advertising `multiAgent.executionModel.replayDeterminism.refusalDivergenceEmission: true` MUST emit `replay.divergedAtRefusal` + fail replay with `error.code: 'replay_diverged_at_refusal'`. Silent substitution is non-conformant. Pairs with `replay-divergence-at-refusal.test.ts`. | original: `completed`; replay: `failed` (`error.code='replay_diverged_at_refusal'`) | ≤ 10s |
|
|
146
146
|
| Phase 4 Nondeterministic Tool | `conformance-phase4-nondet-tool` | RFC 0041 §C — two-node workflow (`core.noop` proxied as a nondeterministic tool → `core.ai.structuredOutput`). Used by `replay-observable-sequence-determinism.test.ts` to verify that across original + replay runs, the observable `RunEventDoc` sequence prefix is identical up to and including the nondeterministic-tool node's `node.completed` event. The host's replay path MUST replay the original event log entries (rather than re-executing the tool) for nodes whose `core.tool.*` config carries `nondeterministic: true`. Phase 4 hosts advertising `multiAgent.executionModel.replayDeterminism.supported: true` honor this contract. | original + replay: `completed`; observable prefixes equal up to the nondet boundary | ≤ 10s |
|
|
147
147
|
|
|
148
|
-
The `messages`-mode stream fixture (AI token streaming) is covered by the deterministic mock-provider surface
|
|
148
|
+
The `messages`-mode stream fixture (AI token streaming) is covered by the deterministic mock-provider surface (`spec/v1/run-options.md` at v1; `testing.mockProviders` in [`spec/v2/core/runs.md`](../spec/v2/core/runs.md) at v2). Hosts that do not advertise `Capabilities.testing.mockProviders` skip-equivalent on those scenarios.
|
|
149
149
|
|
|
150
150
|
---
|
|
151
151
|
|
|
@@ -161,7 +161,7 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
|
|
|
161
161
|
|
|
162
162
|
### `conformance-noop`
|
|
163
163
|
|
|
164
|
-
- **Purpose**: cheapest run-lifecycle test. Used by
|
|
164
|
+
- **Purpose**: cheapest run-lifecycle test. Used by `runs-lifecycle.test.ts` (v1) and `v2-created-run-readable.test.ts` (v2), and by most run-surface scenarios, to verify create, read and the terminal event end-to-end.
|
|
165
165
|
- **Inputs**: none.
|
|
166
166
|
- **Expected events** (in order, `updates` mode):
|
|
167
167
|
1. `run.started`
|
|
@@ -183,7 +183,7 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
|
|
|
183
183
|
- **Purpose**: verify the engine handles in-flight runs (status transitions over time, SSE keep-alives, poll fallback).
|
|
184
184
|
- **Inputs**:
|
|
185
185
|
- `delayMs` (integer, required, 0 ≤ value ≤ 30000) — server MUST sleep for this duration before completing.
|
|
186
|
-
- **Expected behavior**: `GET /
|
|
186
|
+
- **Expected behavior**: `GET /runs/{runId}` MUST return `status: "running"` while the delay is in flight; `status: "completed"` after.
|
|
187
187
|
- **Terminal status**: `completed`.
|
|
188
188
|
|
|
189
189
|
### `conformance-failure`
|
|
@@ -205,7 +205,7 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
|
|
|
205
205
|
1. Run starts and reaches an `approvalGate` node that calls `ctx.interrupt({kind: 'approval', ...})`.
|
|
206
206
|
2. Server emits `interrupt.requested` (and SHOULD also emit `approval.requested` for back-compat).
|
|
207
207
|
3. Run status MUST be `waiting-approval`.
|
|
208
|
-
4. After client POSTs `{action: 'accept'}` to `/
|
|
208
|
+
4. After the client POSTs `{action: 'accept'}` to `/runs/{runId}/interrupts/{nodeId}` (`resolveInterruptByRun`), server emits `approval.received` and resumes.
|
|
209
209
|
5. Run reaches `completed`.
|
|
210
210
|
- **Terminal status (after accept)**: `completed`.
|
|
211
211
|
- **Terminal status (after reject, major 2)**: `failed`, with `error.code` `approval_rejected` on the snapshot and on `run.failed`, and `failedNodeId: "gate"`. The fixture has no edges, so nothing routes the failure (`spec/v2/core/interrupt.md` §Rejection, RFC 0223; `v2-approval-reject-disposition.test.ts`).
|
|
@@ -310,20 +310,20 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
|
|
|
310
310
|
- **Inputs**:
|
|
311
311
|
- `nonce` (string, required) — caller-supplied; server MUST NOT use this for any side effect, only for de-duplication semantics tests.
|
|
312
312
|
- **Expected behavior**:
|
|
313
|
-
- `POST /
|
|
313
|
+
- `POST /runs` with the same `Idempotency-Key` and same body twice → second response MUST replay the first (`openwop-Idempotent-Replay: true` header) and MUST NOT create a second run.
|
|
314
314
|
- Same `Idempotency-Key` with a different body → 409.
|
|
315
315
|
- **Terminal status**: `completed`.
|
|
316
316
|
|
|
317
317
|
### `conformance-cancellable`
|
|
318
318
|
|
|
319
|
-
- **Purpose**: verify
|
|
319
|
+
- **Purpose**: verify cancellation mid-run.
|
|
320
320
|
- **Inputs**:
|
|
321
321
|
- `delayMs` (integer, required, 1 ≤ value ≤ 60000) — wait long enough for the conformance test to issue cancel.
|
|
322
322
|
- **Expected behavior**:
|
|
323
323
|
1. Run reaches `running`.
|
|
324
|
-
2. Client posts `POST /
|
|
324
|
+
2. Client posts `POST /runs/{runId}/cancel` (`cancelRun`).
|
|
325
325
|
3. Server emits `run.cancelled` within 5s.
|
|
326
|
-
4. Subsequent `GET /
|
|
326
|
+
4. Subsequent `GET /runs/{runId}` MUST return `status: "cancelled"`.
|
|
327
327
|
|
|
328
328
|
### `conformance-replay-ordinal-loop`
|
|
329
329
|
|
|
@@ -374,7 +374,7 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
|
|
|
374
374
|
- **Topology**: two nodes: `core.orchestrator.supervisor` and `core.dispatch`, looping back to each other.
|
|
375
375
|
- **Inputs**: none.
|
|
376
376
|
- **Conformance test driver**:
|
|
377
|
-
1. POST `/
|
|
377
|
+
1. POST `/runs` with `{workflowId: "conformance-dispatch-loop"}`.
|
|
378
378
|
2. The orchestrator node must emit `runOrchestrator.decided` with `next-worker` then `terminate`.
|
|
379
379
|
3. Poll until terminal.
|
|
380
380
|
4. **Assert** terminal status is `completed`.
|
|
@@ -396,18 +396,18 @@ The `messages`-mode stream fixture (AI token streaming) is covered by the determ
|
|
|
396
396
|
|
|
397
397
|
## `conformance-version-fold` (closes F5)
|
|
398
398
|
|
|
399
|
-
- **Consuming scenario**: `conformance/src/scenarios/version-fold.test.ts
|
|
399
|
+
- **Consuming scenario**: `conformance/src/scenarios/version-fold.test.ts`. **v1 only**: `X-Force-Engine-Version` is not a v2 header ([`spec/v2/core/headers.md`](../spec/v2/core/headers.md)).
|
|
400
400
|
- **Purpose**: verify forward-compat fold-best-effort tolerance across the spec's engine-version cross-version interop matrix (`version-negotiation.md` §Cross-version interop matrix). Uses the test-keys-only `X-Force-Engine-Version` header to drive the same workflow at three different engine versions from a single deployed server — no multi-version fleet needed.
|
|
401
401
|
- **Fixture topology**: a single `core.noop` node. The workflow itself is trivial; the test exercises the server's READ path (projection, event-log fold) under each forced engine version.
|
|
402
402
|
- **Inputs**: none.
|
|
403
403
|
- **Conformance test driver**:
|
|
404
404
|
1. Read the server's `Capabilities.testing.forceEngineVersionRange = { min, max }`.
|
|
405
405
|
2. For each version `v` in `[min, current, max]` (deduped):
|
|
406
|
-
- POST `/
|
|
406
|
+
- POST `/runs` with body `{workflowId: "conformance-version-fold"}` AND header `X-Force-Engine-Version: v`. Use a test API key.
|
|
407
407
|
- Poll until terminal.
|
|
408
408
|
- **Assert** terminal status is `completed`.
|
|
409
|
-
- **Assert** `GET /
|
|
410
|
-
- **Assert** `GET /
|
|
409
|
+
- **Assert** `GET /runs/{runId}` returns a valid `RunSnapshot` (the projection tolerates the version mismatch via fold-best-effort).
|
|
410
|
+
- **Assert** `GET /runs/{runId}/events/poll?lastSequence=0&timeout=1` returns a non-empty `events[]` array (event log is readable).
|
|
411
411
|
- **Negative paths**:
|
|
412
412
|
- Same fixture with a production API key returns `403 force_engine_version_forbidden`.
|
|
413
413
|
- Same fixture with `X-Force-Engine-Version: <out-of-range>` returns `400 unsupported_force_engine_version`.
|
|
@@ -424,7 +424,7 @@ This fixture closes F5 without requiring any new server-side test infrastructure
|
|
|
424
424
|
- **Fixture topology**: a single `core.ai.callPrompt` (or similar AI-bearing typeId) node. The node's actual prompt content is irrelevant — the conformance driver intercepts the AI dispatch via `configurable.mockProvider`.
|
|
425
425
|
- **Inputs**: none.
|
|
426
426
|
- **Conformance test driver**:
|
|
427
|
-
1. POST `/
|
|
427
|
+
1. POST `/runs` with body:
|
|
428
428
|
|
|
429
429
|
```jsonc
|
|
430
430
|
{
|
|
@@ -445,7 +445,7 @@ This fixture closes F5 without requiring any new server-side test infrastructure
|
|
|
445
445
|
|
|
446
446
|
Use a test API key (server returns 403 on production keys per `run-options.md` §Authorization).
|
|
447
447
|
|
|
448
|
-
2. Subscribe to `/
|
|
448
|
+
2. Subscribe to `/runs/{runId}/events?streamMode=messages`.
|
|
449
449
|
3. **Assert** chunk arrival order: `["Hello", " ", "world", "!"]` — same order as `tokens`.
|
|
450
450
|
4. **Assert** the final chunk has `isLast: true`, `meta.finishReason === "stop"`, `meta.usage.completionTokens === 4`.
|
|
451
451
|
5. **Assert** SSE stream closes on terminal — server-closed, not timeout.
|
|
@@ -495,7 +495,7 @@ The fixture JSONs and matching `subworkflow.test.ts` are part of the current con
|
|
|
495
495
|
- **Topology**: 10 sequential `core.noop` nodes (`a → b → c → … → j`). A run completes naturally if no per-run override is supplied. With `configurable.recursionLimit = 5`, the run MUST trip after the 5th node.
|
|
496
496
|
- **Inputs**: none.
|
|
497
497
|
- **Conformance test driver**:
|
|
498
|
-
1. POST `/
|
|
498
|
+
1. POST `/runs` with `{workflowId: "conformance-cap-breach", configurable: {recursionLimit: 5}}`.
|
|
499
499
|
2. Server SHOULD validate `recursionLimit ≤ Capabilities.limits.maxNodeExecutions`. If `maxNodeExecutions` is `100` (default), `5` is fine.
|
|
500
500
|
3. Poll until terminal.
|
|
501
501
|
4. **Assert** terminal status is `failed`.
|
|
@@ -520,7 +520,7 @@ Both items are tracked as v1.x conformance expansion work.
|
|
|
520
520
|
- **Topology**: single `core.delay` node that sleeps `input.delayMs` (default `30000`) — far longer than the small `runTimeoutMs` the test supplies.
|
|
521
521
|
- **Inputs**: `delayMs` (number, default `30000`).
|
|
522
522
|
- **Conformance test driver**:
|
|
523
|
-
1. POST `/
|
|
523
|
+
1. POST `/runs` with `{workflowId: "conformance-run-duration-breach", configurable: {runTimeoutMs: 1000}}`.
|
|
524
524
|
2. Poll until terminal.
|
|
525
525
|
3. **Assert** terminal status is `failed`.
|
|
526
526
|
4. **Assert** `RunSnapshot.error.code === "run_timeout"`.
|
|
@@ -538,7 +538,7 @@ This fixture is unblocked when a host exposes a wall-clock deadline enforcer adv
|
|
|
538
538
|
- **Purpose**: verify the BYOK secret-resolution roundtrip end-to-end. A host that advertises `capabilities.secrets.supported: true` MUST resolve the canary `openwop-conformance-canary-secret` via its `SecretResolver` and surface only the SHA-256 hex + byte length on every observable channel (variables, events, debug bundle, logs). The raw value MUST NOT leak per `observability.md` §"Redaction" + `threat-model-secret-leakage.md` §SR-1.
|
|
539
539
|
- **Topology**: single node `resolve-secret` with `typeId: conformance.secret.echo`, `config.secretId: "openwop-conformance-canary-secret"`. Resolves the canary, hashes it, and writes `{secretSha256, secretLength}` to the run's `variables.resolve-secret`.
|
|
540
540
|
- **Conformance test driver**:
|
|
541
|
-
1. POST `/
|
|
541
|
+
1. POST `/runs` with `{workflowId: "openwop-smoke-byok-roundtrip"}`.
|
|
542
542
|
2. Poll until terminal.
|
|
543
543
|
3. **Assert** terminal status is `completed`.
|
|
544
544
|
4. **Assert** `variables['resolve-secret'].secretSha256` matches `^[0-9a-f]{64}$`.
|
|
@@ -615,7 +615,7 @@ Hosts that don't ship a BYOK SecretResolver MAY return `404` / `422` on the star
|
|
|
615
615
|
- **Topology**: 4 sequential `core.channelWrite` nodes targeting channel `events` with `ttlMs: 200`, separated by a `core.delay` of 300ms between writes 3 and 4. The 4th write fires after the TTL window has elapsed.
|
|
616
616
|
- **Inputs**: none. Each node carries a static `value` in its `config` (`a`, `b`, `c`, `d` respectively).
|
|
617
617
|
- **Conformance test driver**:
|
|
618
|
-
1. POST `/
|
|
618
|
+
1. POST `/runs` with `{workflowId: "conformance-channel-ttl"}`.
|
|
619
619
|
2. Poll until terminal.
|
|
620
620
|
3. **Assert** terminal status is `completed`.
|
|
621
621
|
4. **Assert** `RunSnapshot.variables.events.length === 1` — the 3 priors aged out at the 4th write.
|
|
@@ -632,9 +632,9 @@ Hosts that don't ship a BYOK SecretResolver MAY return `404` / `422` on the star
|
|
|
632
632
|
- **Topology**: a single `core.identity` node whose `agent` binding is `{ "agentId": "core.conformance.channel-agent", "channel": "stable" }` (no `version`). The host MUST have an active deployment of `core.conformance.channel-agent` on the `stable` channel.
|
|
633
633
|
- **Inputs**: none. Trigger `manual`.
|
|
634
634
|
- **Conformance test driver**:
|
|
635
|
-
1. POST `/
|
|
635
|
+
1. POST `/runs` with `{workflowId: "conformance-agent-channel-dispatch"}`; poll until terminal.
|
|
636
636
|
2. **Assert** the first `agent.invocation.started` carries `resolvedChannel: "stable"` and a concrete non-empty `resolvedAgentVersion` (the recorded fact, RFC 0077).
|
|
637
|
-
3. **Replay** via `POST /
|
|
637
|
+
3. **Replay** via `POST /runs/{runId}:fork {mode:"replay"}`; **assert** the fork's `agent.invocation.started` re-reads the SAME `resolvedAgentVersion`.
|
|
638
638
|
4. **(Seam-guarded)** Move the `stable` channel via the deployment seam; **assert** a replay of the original run STILL carries the original pin — never re-resolving the moved channel.
|
|
639
639
|
|
|
640
640
|
---
|
|
@@ -685,7 +685,7 @@ The fixtures reference these typeIds:
|
|
|
685
685
|
| `conformance.artifact.emit` | artifact-emit | Opt-in (RFC 0205). Produce one artifact of `config.artifactType` with payload `config.data`; emit `artifact.created` naming it; readable through `getArtifact`. |
|
|
686
686
|
| `conformance.oauth.use` | credential | Opt-in (RFC 0199). Resolve the credential `config.auth` names for the run's Subject, refreshing host-side; no credential ⇒ a `credential` interrupt (with the facet) or a failed node. Never carries token material on any surface. |
|
|
687
687
|
|
|
688
|
-
|
|
688
|
+
A host's NodeModule registry MUST include implementations for all six core typeIds before seeding fixtures. The `conformance.requiresMissing` fixture node is opt-in — see the row above.
|
|
689
689
|
|
|
690
690
|
---
|
|
691
691
|
|
|
@@ -782,7 +782,7 @@ A host MUST NOT advertise the fixture unless it advertises `httpClient.safeFetch
|
|
|
782
782
|
|
|
783
783
|
## Versioning
|
|
784
784
|
|
|
785
|
-
Each fixture's JSON has its own `version` field. The
|
|
785
|
+
Each fixture's JSON has its own `version` field. The suite targets fixture version 1.x. Fixture spec breaking changes MUST bump the major; the suite MUST refuse to run against an unrecognized fixture version with a clear error message.
|
|
786
786
|
|
|
787
787
|
---
|
|
788
788
|
|
|
@@ -790,26 +790,24 @@ Each fixture's JSON has its own `version` field. The OpenWOP v1.0 conformance su
|
|
|
790
790
|
|
|
791
791
|
```text
|
|
792
792
|
conformance/
|
|
793
|
-
fixtures.md
|
|
793
|
+
fixtures.md this file
|
|
794
794
|
fixtures/
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
conformance-idempotent.json
|
|
809
|
-
conformance-cancellable.json
|
|
795
|
+
*.json workflow fixtures (WorkflowDefinition), seeded by the host
|
|
796
|
+
a2ui-v09/ A2UI v0.9 surface payloads (not seeded)
|
|
797
|
+
connection-packs/ connection-pack manifests
|
|
798
|
+
frontend-plugin-packs/ front-end plugin packs
|
|
799
|
+
interrupt-payloads/ InterruptPayload documents (not seeded)
|
|
800
|
+
node-pack-runtime/ node-pack runtime fixtures
|
|
801
|
+
oauth-providers/ synthetic OAuth provider definitions
|
|
802
|
+
pack-manifests/ pack manifests
|
|
803
|
+
prompt-templates/ prompt templates
|
|
804
|
+
trigger-events/ trigger-event payloads
|
|
805
|
+
upstream/ upstream schemas vendored byte for byte (a2a-v1.0.1/, a2ui-v0.9/)
|
|
806
|
+
wasm-packs/ installable WASM node packs
|
|
807
|
+
wasm-sandbox/ WASM modules for the server-free sandbox probe (not seeded)
|
|
810
808
|
```
|
|
811
809
|
|
|
812
|
-
Each JSON is a valid `WorkflowDefinition` per `../schemas/workflow-definition.schema.json`.
|
|
810
|
+
Each top-level JSON is a valid `WorkflowDefinition` per `../schemas/workflow-definition.schema.json`, checked by `fixtures-valid.test.ts`. Hosts MUST seed them verbatim, as opaque blobs: do not transform field names or strip fields. The sub-directories are described in the sections below.
|
|
813
811
|
|
|
814
812
|
---
|
|
815
813
|
|
|
@@ -847,6 +845,24 @@ The `fixtures/wasm-packs/` sub-directory holds two node packs (`language: "wasm"
|
|
|
847
845
|
|
|
848
846
|
---
|
|
849
847
|
|
|
848
|
+
## WASM sandbox probe fixtures
|
|
849
|
+
|
|
850
|
+
The `fixtures/wasm-sandbox/` sub-directory holds small WebAssembly modules, each a hand-written text module (`<name>.wat`) with its built `<name>.wasm`. They are NOT packs and are NOT seeded into a server: the server-free probe in `src/lib/wasm-sandbox-probe.ts` loads them directly to witness the sandbox isolation invariants (RFC 0035 §B; `SECURITY/invariants.yaml` `node-pack-sandbox-*`). Escape attempts and the capability gate are checked by inspecting each module's declared imports before instantiation; the memory bound by instantiating under a capped memory; isolated context by instantiating twice.
|
|
851
|
+
|
|
852
|
+
| Module | Expect | Consumed by |
|
|
853
|
+
| --- | --- | --- |
|
|
854
|
+
| `well-behaved-echo` | runs and returns its input | `sandbox-wasm-isolation.test.ts` |
|
|
855
|
+
| `well-behaved-host-fetch` | callable when `host-fetch` is granted; denied without the grant | `sandbox-wasm-isolation.test.ts` |
|
|
856
|
+
| `misbehaving-fs`, `misbehaving-env`, `misbehaving-network`, `misbehaving-process` | `sandbox_escape_attempt` with the matching escape kind | `sandbox-wasm-isolation.test.ts` |
|
|
857
|
+
| `misbehaving-capability-gate` | `sandbox_capability_denied`, naming the capability | `sandbox-wasm-isolation.test.ts` |
|
|
858
|
+
| `misbehaving-memory` | `sandbox_memory_exceeded` on access past the bound | `sandbox-wasm-isolation.test.ts` |
|
|
859
|
+
| `isolation-global` | no state shared between two instances | `sandbox-wasm-isolation.test.ts` |
|
|
860
|
+
| `misbehaving-timeout` | killed with `sandbox_timeout` by a worker-thread kill timer | `sandbox-wasm-timeout.test.ts` |
|
|
861
|
+
|
|
862
|
+
Both scenarios run at major 1 only and need no host.
|
|
863
|
+
|
|
864
|
+
---
|
|
865
|
+
|
|
850
866
|
## Connection pack fixtures
|
|
851
867
|
|
|
852
868
|
The `fixtures/connection-packs/` sub-directory holds canonical connection-pack manifests (RFC 0095, `kind: "connection"`) used as schema-level proof points (validated server-free against `../schemas/connection-pack-manifest.schema.json`) AND as the install payloads the capability-gated behavioral scenarios POST to the `POST /v1/host/sample/connection-packs/install` seam. They are NOT seeded into a server.
|
|
@@ -979,12 +995,18 @@ The `fixtures/a2ui-v09/` sub-directory (suite 2.36.0) holds `ui.a2ui-surface` pa
|
|
|
979
995
|
|
|
980
996
|
The `fixtures/upstream/a2ui-v0.9/` sub-directory vendors `server_to_client.json`, `catalogs/basic/catalog.json` and `common_types.json` from a2ui.org byte for byte, pinned by SHA-256 (RFC 0209 §References; its `README.md` records the URLs, fetch date and the Apache-2.0 notice). They are read only by the corpus gate.
|
|
981
997
|
|
|
998
|
+
## Upstream A2A v1.0.1 schema source (RFC 0205)
|
|
999
|
+
|
|
1000
|
+
The `fixtures/upstream/a2a-v1.0.1/` sub-directory vendors `a2a.proto` from the A2A repository at tag `v1.0.1`, byte for byte, pinned by SHA-256 (`e195bf96ab630c69797851970203e1b2b6b19528f2e9803b7d904b91a5104016`). A2A publishes no normative JSON Schema of its own, so `schemas/v2/part.schema.json` and `schemas/v2/artifact.schema.json` are transcribed from this file. The corpus gate `src/coherence/a2a-parts-schemas.test.ts` checks the digest and compares each schema's member names with the fields of `message Part` and `message Artifact`, so a transcription slip fails the gate. Its `README.md` records the source URL, fetch date and the Apache-2.0 notice. Do not edit it; moving to a later A2A minor re-vendors the file and re-transcribes both schemas. It is read only by the corpus gate and is not seeded.
|
|
1001
|
+
|
|
982
1002
|
---
|
|
983
1003
|
|
|
984
1004
|
## References
|
|
985
1005
|
|
|
986
|
-
- `README.md` —
|
|
987
|
-
-
|
|
988
|
-
- `../
|
|
989
|
-
-
|
|
990
|
-
-
|
|
1006
|
+
- [`README.md`](./README.md) — running the suite
|
|
1007
|
+
- [`coverage.md`](./coverage.md) — which scenarios consume which fixtures
|
|
1008
|
+
- `../schemas/workflow-definition.schema.json` — every top-level fixture validates against this
|
|
1009
|
+
- [`spec/v2/core/runs.md`](../spec/v2/core/runs.md) — the run operations the fixtures exercise
|
|
1010
|
+
- [`spec/v2/core/interrupt.md`](../spec/v2/core/interrupt.md) — approval, clarification and credential interrupts
|
|
1011
|
+
- [`spec/v2/core/idempotency.md`](../spec/v2/core/idempotency.md) — the semantics the idempotent fixture exercises
|
|
1012
|
+
- [`spec/v2/core/replay.md`](../spec/v2/core/replay.md) — replay and fork, used by the replay fixtures
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.45.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.45.24",
|
|
4
|
+
"description": "Black-box conformance suite for OpenWOP hosts (v2 current; v1 scenarios retained for the frozen v1 tree).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/openwop/openwop.git",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@openwop/spec-artifacts": "file:../spec-artifacts"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@openwop/spec-artifacts": "2.45.
|
|
59
|
+
"@openwop/spec-artifacts": "2.45.24"
|
|
60
60
|
}
|
|
61
61
|
}
|