@openwop/openwop-conformance 1.1.0 → 1.2.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.
- package/CHANGELOG.md +25 -0
- package/README.md +2 -2
- package/coverage.md +29 -17
- package/fixtures/conformance-agent-low-confidence.json +7 -4
- package/fixtures/conformance-agent-pack-handoff-schema-validation.json +30 -0
- package/fixtures/conformance-agent-reasoning.json +23 -4
- package/fixtures/conformance-dispatch-cross-worker-handoff-child-a.json +27 -0
- package/fixtures/conformance-dispatch-cross-worker-handoff-child-b.json +25 -0
- package/fixtures/conformance-dispatch-cross-worker-handoff.json +60 -0
- package/fixtures/conformance-dispatch-input-mapping-child.json +25 -0
- package/fixtures/conformance-dispatch-input-mapping.json +49 -0
- package/fixtures/conformance-dispatch-output-mapping-child.json +27 -0
- package/fixtures/conformance-dispatch-output-mapping.json +49 -0
- package/fixtures/conformance-subworkflow-input-mapping-child.json +27 -0
- package/fixtures/conformance-subworkflow-input-mapping.json +33 -0
- package/fixtures.md +12 -2
- package/package.json +1 -1
- package/schemas/README.md +7 -0
- package/schemas/agent-ref.schema.json +1 -1
- package/schemas/ai-envelope.schema.json +106 -0
- package/schemas/capabilities.schema.json +300 -3
- package/schemas/core-conformance-mock-agent-config.schema.json +147 -0
- package/schemas/dispatch-config.schema.json +26 -0
- package/schemas/envelopes/clarification.request.schema.json +43 -0
- package/schemas/envelopes/error.schema.json +26 -0
- package/schemas/envelopes/schema.request.schema.json +22 -0
- package/schemas/envelopes/schema.response.schema.json +22 -0
- package/schemas/node-pack-manifest.schema.json +5 -0
- package/schemas/pack-lockfile.schema.json +16 -0
- package/schemas/run-event-payloads.schema.json +18 -2
- package/schemas/run-event.schema.json +2 -1
- package/schemas/workflow-chain-pack-manifest.schema.json +226 -0
- package/src/lib/behavior-gate.ts +44 -5
- package/src/lib/env.ts +27 -0
- package/src/lib/webhook-receiver.ts +137 -0
- package/src/lib/workflow-chain-expansion.ts +213 -0
- package/src/scenarios/agentPackCatalog.test.ts +216 -0
- package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +146 -0
- package/src/scenarios/agentReasoningEvents.test.ts +58 -7
- package/src/scenarios/agents-run-tool-allowlist.test.ts +182 -0
- package/src/scenarios/ai-envelope-shape.test.ts +362 -0
- package/src/scenarios/aiEnvelope.capBreached.test.ts +173 -0
- package/src/scenarios/aiEnvelope.contractRefusal.test.ts +150 -0
- package/src/scenarios/aiEnvelope.correlationReplay.test.ts +69 -0
- package/src/scenarios/aiEnvelope.redaction.test.ts +73 -0
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +87 -0
- package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +143 -0
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +176 -0
- package/src/scenarios/append-ordering.test.ts +44 -0
- package/src/scenarios/artifact-auth.test.ts +58 -0
- package/src/scenarios/blob-cross-tenant-isolation.test.ts +66 -0
- package/src/scenarios/blob-presign-expiry.test.ts +66 -0
- package/src/scenarios/blob-roundtrip.test.ts +48 -0
- package/src/scenarios/cache-cross-tenant-isolation.test.ts +61 -0
- package/src/scenarios/cache-ttl-expiry.test.ts +47 -0
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +98 -0
- package/src/scenarios/dispatch-input-mapping.test.ts +94 -0
- package/src/scenarios/dispatch-output-mapping.test.ts +65 -0
- package/src/scenarios/fs-path-traversal.test.ts +124 -0
- package/src/scenarios/idempotency-key-determinism.test.ts +230 -0
- package/src/scenarios/interrupt-token-matrix.test.ts +126 -0
- package/src/scenarios/kv-atomic-increment.test.ts +74 -0
- package/src/scenarios/kv-cas.test.ts +75 -0
- package/src/scenarios/kv-cross-tenant-isolation.test.ts +85 -0
- package/src/scenarios/kv-ttl-expiry.test.ts +47 -0
- package/src/scenarios/mcp-server-elicitation-bridge.test.ts +92 -0
- package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +80 -0
- package/src/scenarios/mcp-server-resource-roundtrip.test.ts +82 -0
- package/src/scenarios/mcp-server-sampling-bridge.test.ts +84 -0
- package/src/scenarios/mcp-server-tool-roundtrip.test.ts +107 -0
- package/src/scenarios/mcp-server-untrusted-args.test.ts +105 -0
- package/src/scenarios/mcp-tool-roundtrip.test.ts +13 -6
- package/src/scenarios/memory-compaction-event-emitted.test.ts +121 -0
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +116 -0
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +127 -0
- package/src/scenarios/multi-region-idempotency.test.ts +39 -4
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +139 -0
- package/src/scenarios/pause-resume.test.ts +43 -0
- package/src/scenarios/queue-ack-nack-dlq.test.ts +67 -0
- package/src/scenarios/queue-cross-tenant-isolation.test.ts +66 -0
- package/src/scenarios/queue-publish-consume-roundtrip.test.ts +48 -0
- package/src/scenarios/registry-public.test.ts +91 -0
- package/src/scenarios/search-bm25-roundtrip.test.ts +47 -0
- package/src/scenarios/spec-corpus-validity.test.ts +28 -7
- package/src/scenarios/sql-injection-rejection.test.ts +84 -0
- package/src/scenarios/sql-transaction-atomicity.test.ts +66 -0
- package/src/scenarios/stream-subscribe-from-beginning.test.ts +66 -0
- package/src/scenarios/subworkflow-input-mapping.test.ts +100 -0
- package/src/scenarios/table-cross-tenant-isolation.test.ts +65 -0
- package/src/scenarios/table-cursor-pagination.test.ts +47 -0
- package/src/scenarios/table-schema-enforcement.test.ts +47 -0
- package/src/scenarios/vector-knn-roundtrip.test.ts +48 -0
- package/src/scenarios/webhook-receiver-adversarial.test.ts +210 -0
- package/src/scenarios/workflow-chain-expansion.test.ts +366 -0
- package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +232 -0
- package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +138 -0
- package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +170 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [1.2.0] — 2026-05-18
|
|
4
|
+
|
|
5
|
+
Minor bump per `PUBLISHING.md` §"Versioning alignment" — conformance scenario additions land on a minor. Captures the RFC 0022 + RFC 0023 fixture/scenario surface that landed across `cf7df05`, `02a84e1`, `a8a8594`, `f94d2e1`, `87c5de7`, `22d9f92`, `a025a85`, and `a65ea0e`.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **RFC 0023 — Conformance agent-event emitters.** New conformance-only `core.conformance.mock-agent` typeId schema (`schemas/core-conformance-mock-agent-config.schema.json`) carrying five test hooks (`mockReasoning`, `mockToolCalls`, `mockHandoff`, `mockDecision`, `mockConfidence`) that drive deterministic `agent.*` event emission. New `capabilities.conformance.mockAgent: boolean` advertisement (RFC 0023 §B.2). The two affected fixtures (`conformance-agent-reasoning`, `conformance-agent-low-confidence`) re-pinned from `core.identity` (a passthrough primitive) to the new conformance-only typeId — removes the prior undocumented host-side `emitReasoningTrace` / `mockConfidence` hooks on `core.identity` that downstream hosts adopted by reading existing implementations. Authorized-Emitters table for the `agent.*` family added to `spec/v1/node-packs.md` (normative pointer to RFC 0023 §A).
|
|
10
|
+
- **RFC 0022 — `core.dispatch` + `core.subWorkflow` runtime variable mapping.** Four new behavioral scenarios graduated from `it.todo()`: HVMAP-1a (`dispatch.inputMapping` projection), HVMAP-1b (`dispatch.outputMapping` harvest with skip-on-failure semantics), HVMAP-1c (sequential cross-worker handoff via `perWorker{Input,Output}Mappings`), HVMAP-2 (`subWorkflow.inputMapping` seeding overriding `defaultValue`). Capability flags `capabilities.agents.dispatchMapping` + `capabilities.subWorkflow.inputMapping` added with normative refusal-at-registration semantics.
|
|
11
|
+
- **New fixtures.** `conformance-dispatch-{input,output,cross-worker-handoff}-mapping` (3 supervisor + dispatch parent topologies), `conformance-dispatch-{input,output}-mapping-child` (2 child fixtures), `conformance-dispatch-cross-worker-handoff-child-{a,b}` (2 child fixtures), `conformance-subworkflow-input-mapping{,-child}` (parent + child). Catalog in `conformance/fixtures.md` reflects all rows.
|
|
12
|
+
- **Supervisor conformance hooks.** `spec/v1/node-packs.md` §`core.orchestrator.supervisor` row documents three test-only config keys: `mockConfidence` (existing, normalized), `mockPendingDecision` (existing, normalized), `mockDispatchPlan` (new — `OrchestratorDecision[]` indexed by prior decision count; lets fixtures script multi-worker dispatch sequences without an LLM). All three are conformance-only and gated by `capabilities.conformance.mockAgent` when used outside conformance-prefixed workflow ids.
|
|
13
|
+
|
|
14
|
+
### Tightened
|
|
15
|
+
|
|
16
|
+
- **`agentReasoningEvents.test.ts` causationId chain.** Now asserts `agent.toolReturned.causationId === paired agent.toolCalled.eventId` per the normative MUST in RFC 0002 §B (`agentToolReturned`). Previously the scenario only validated callId pairing, masking impl deviations on the strict event-log identity chain that `spec/v1/replay.md` §"Determinism with non-deterministic agents" depends on. Gated on the matched `agent.toolCalled.eventId` actually surfacing in the host's `/events` projection — hosts that omit eventId from their projection skip-equivalent (and SHOULD add it).
|
|
17
|
+
- **`agentReasoningEvents.test.ts` per-event-type identity check.** Per-event-type branching in the `payload.agentId` assertion: `agent.handoff` is now checked against the canonical `fromAgentId` + `toAgentId` shape (per `run-event-payloads.schema.json` §`agentHandoff`); the other four events stay on the `agentId` field. Previously the blanket `payload.agentId` check was over-strict against the canonical handoff schema.
|
|
18
|
+
|
|
19
|
+
### Compatibility
|
|
20
|
+
|
|
21
|
+
Strictly additive at the scenario level; the causationId tightening is a behavioral assertion against a normative MUST that was previously under-tested. Hosts that already honor RFC 0002 §B (`causationId` MUST equal the paired `agent.toolCalled.eventId`) continue to pass. Hosts using callId-only pairing without setting `causationId` were previously passing despite a normative-MUST deviation; they now fail and need to ship the executor extension that returns eventId synchronously from `appendEvent` (the Postgres reference host pattern is the recommended migration path — see `examples/hosts/postgres/src/server.ts` `makeEventId(runId, calledEv.seq)`).
|
|
22
|
+
|
|
23
|
+
### Notes
|
|
24
|
+
|
|
25
|
+
- `@openwop/openwop@1.1.x` SDK + spec corpus surface are unchanged by this conformance bump — only the conformance package re-publishes per the `openwop-conformance/v*` tag → `publish-conformance` job in `PUBLISHING.md` §"Tag conventions."
|
|
26
|
+
- A handful of `it.todo()` cases remain in the dispatch + subWorkflow scenarios (unset-variable projection, capability-refusal, child-failed/cancelled outputMapping skip, per-worker override precedence, mid-run no-propagation). These are tracked as future work and require conformance-harness extensions (capability-toggle hook, deterministic-fail child fixture, cancellable child fixture, fixture variants omitting defaultValues) outside the scope of this release.
|
|
27
|
+
|
|
3
28
|
## [1.0.0] — 2026-05-10
|
|
4
29
|
|
|
5
30
|
Reset to the OpenWOP v1.0 production-release baseline.
|
package/README.md
CHANGED
|
@@ -92,7 +92,7 @@ Exit code is non-zero on any failed assertion.
|
|
|
92
92
|
|
|
93
93
|
## What's Covered
|
|
94
94
|
|
|
95
|
-
The current suite has
|
|
95
|
+
The current suite has 157 scenario files under `src/scenarios/`. 2026-05-18 (RFC 0022 `Draft` — runtime variable mapping) added four `it.todo()` placeholder scenarios covering the new mapping surfaces on `core.dispatch` (§A — `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`) and `core.subWorkflow` (§B — `subworkflow-input-mapping.test.ts`). Gated on `capabilities.agents.dispatchMapping` (dispatch trio) and `capabilities.subWorkflow.inputMapping` (subWorkflow). Promote to live assertions when RFC 0022 reaches `Active` + a reference host advertises the matching flags. 2026-05-17 (RFC 0003 §D handoff-schema enforcement, HV-1) added `agentPackHandoffSchemaValidation.test.ts` — verifies the host validates dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef` per RFC 0003 §D. Paired with the new `agent-pack-handoff-schema-enforcement` row in `SECURITY/invariants.yaml`. 2026-05-17 (AI Envelope gap-closure, DRAFT v1.x — `spec/v1/ai-envelope.md`) added 7 advertisement-shape scenarios with `it.todo()` behavioral placeholders gated on `capabilities.envelopeContracts.advertised: true`: `aiEnvelope.universalKinds.test.ts`, `aiEnvelope.schemaDrift.test.ts`, `aiEnvelope.correlationReplay.test.ts`, `aiEnvelope.contractRefusal.test.ts`, `aiEnvelope.trustBoundaryPropagation.test.ts`, `aiEnvelope.redaction.test.ts`, `aiEnvelope.capBreached.test.ts`. Paired with the new `envelope-redaction-sr-1-carry-forward` row in `SECURITY/invariants.yaml`. 2026-05-17 (post-publish hardening, deep audit of `core.openwop.agents`) added `agents-run-tool-allowlist.test.ts` — server-free scenario locking in the `core.openwop.agents@1.0.1` safety-fix that closes `OPENWOP-AUDIT-2026-003` (function-typed `tool.handler` properties rejected at `validateTools()` with `INVALID_TOOL_DECLARATION`; tool-driven runs require `ctx.agentRuntime`; tool-less safe fallback preserved). Paired with the new `agents-run-no-raw-handler` row in `SECURITY/invariants.yaml`. Same-day post-publish hardening added `idempotency-key-determinism.test.ts` — server-free scenario locking in the `core.openwop.http@1.1.2` determinism safety-fix (default `composite` mode produces deterministic keys in `(runId, nodeId, payload)`; removed `uuid` mode rejects with `CONFIG_INVALID`; cross-impl vector test lets third-party reimplementations verify wire agreement). Paired with the new `idempotency-key-deterministic` row in `SECURITY/invariants.yaml`. 2026-05-17 (Phase 3 of RFC 0013) added three server-free scenarios exercising the reference workflow-chain expansion library (`conformance/src/lib/workflow-chain-expansion.ts`): `workflow-chain-expansion.test.ts` (parameter substitution + node id collision avoidance + edge rewriting + capability propagation + runtime-invariance contract), `workflow-chain-unresolvable-typeid.test.ts` (rejection with `chain_unresolvable_typeid` when a chain references an unknown typeId), and `workflow-chain-pack-signature-verification.test.ts` (Ed25519 verification recipe reuse from `node-packs.md §Signing`). Earlier that day (Phase 1) added `workflow-chain-pack-manifest-validation.test.ts` — server-free schema-validation scenario covering the new `workflow-chain-pack-manifest.schema.json` (positive sample + two negatives: kind/contents mismatch and invalid `chainId`). Closes RFC 0013 (`Workflow-chain packs`, `Draft`) Phases 1 + 3 alongside the new `spec/v1/workflow-chain-packs.md`, the `Capabilities.workflowChainPacks` block, and the registry build-index/conformance-check `kind` routing from Phase 2. Earlier that day, the suite added 27 `it.todo()` placeholder scenarios paired with RFCs 0014-0020 (host capability surfaces — fs, kvStorage, tableStorage, queueBus, sql/vector/search, blob/cache, mcp.serverMount). These promote to live assertions when each RFC reaches `Active` + the matching capability block lands in `schemas/capabilities.schema.json` + a reference host advertises the capability. Earlier additions include 18 Multi-Agent Shift scenarios (Phases 1-5) added 2026-05-10, the `registry-public.test.ts` public-registry healthcheck added 2026-05-11 (opt-in via `OPENWOP_TEST_PUBLIC_REGISTRY=true`), the `replay-llm-cache-key.test.ts` placeholder added 2026-05-11 (three `it.todo()` cases for the cross-host LLM cache-key recipe per `replay.md` §"LLM cache-key recipe"), the two `production-*.test.ts` scenarios added 2026-05-11 for the `openwop-production` profile per RFC 0009 (`production-backpressure.test.ts`, `production-retention-expiry.test.ts`), the four `auth-*.test.ts` scenarios added 2026-05-11/12 for the production-auth profiles per RFC 0010 (`auth-api-key-rotation.test.ts`, `auth-oauth2-client-credentials.test.ts`, `auth-oidc-user-bearer.test.ts`, `auth-mtls.test.ts` (opt-in via `OPENWOP_TEST_MTLS=1`)), `replay-retention-expiry.test.ts` added 2026-05-12 (capability shape + 410/422 envelope per `replay.md` §"Retention and garbage collection"), `bulk-cancel.test.ts` added 2026-05-12 (Phase B close-out of R1 — `POST /v1/runs:bulk-cancel`), the two Phase H launch-blocker advertisement-contract scenarios added 2026-05-12 (`mcp-toolcall-redaction.test.ts` for the MCP-1 invariant per `host-capabilities.md §host.mcp` + `threat-model-prompt-injection.md §UNTRUSTED`, and `http-client-ssrf.test.ts` for the SSRF + body-size cap advertisement contract on `capabilities.httpClient`), the `wasm-pack-abi-version-rejection.test.ts` Track 7 scenario added 2026-05-12 for the ABI-mismatch positive path via the `vendor.openwop.misbehaving-abi` pack per RFC 0008 §H, the `otel-trace-propagation-subworkflow.test.ts` Track 11 close-out added 2026-05-13 (parent + child run spans share the inbound traceparent's traceId across the `core.subWorkflow` dispatch boundary), and the three RFC 0012 (Memory Compaction Profile, `Active`) scenarios added 2026-05-13/14: `memory-compaction-sr1-carry-forward.test.ts` (load-bearing SR-1 §D), `memory-compaction-event-emitted.test.ts` (canonical §B payload shape), and `memory-compaction-provenance-tag.test.ts` (soft assertion on §C `compacted-from:<id>` convention). All three gate on `capabilities.memory.compaction.supported` + the host's test seam at `/v1/test/memory/{seed,compact}` (Postgres reference host enables both via `OPENWOP_MEMORY_COMPACTION=true OPENWOP_TEST_TRIGGER_COMPACTION=true`). 2026-05-15 (gap-closure CF-3) added `interrupt-token-matrix.test.ts` (malformed / unknown / replay / cross-run-id paths on `GET|POST /v1/interrupts/{token}`). The maintained scenario-to-spec map lives in [`coverage.md`](./coverage.md); this README keeps the operator quickstart and the historical scenario notes below.
|
|
96
96
|
|
|
97
97
|
High-level coverage includes:
|
|
98
98
|
|
|
@@ -171,7 +171,7 @@ Server-required (added in 1.7.0):
|
|
|
171
171
|
|---|---|---|
|
|
172
172
|
| **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. |
|
|
173
173
|
|
|
174
|
-
Current source tree:
|
|
174
|
+
Current source tree: 157 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
|
|
175
175
|
|
|
176
176
|
## Remaining Gaps
|
|
177
177
|
|
package/coverage.md
CHANGED
|
@@ -20,18 +20,21 @@
|
|
|
20
20
|
| Capabilities and limits | `cap-breach.test.ts`, `dispatchLoop.test.ts` | B+ | Clarification/schema/envelope cap-breach fixtures beyond node-execution cap. |
|
|
21
21
|
| State channels and reducers | `channel-ttl.test.ts` | B+ | Cross-adapter reducer consistency and conflict cases. |
|
|
22
22
|
| Sub-workflows and dispatch | `subworkflow.test.ts`, `multi-node-ordering.test.ts` | B+ | Parallel fan-out floors by scale tier, parent/child cancellation. |
|
|
23
|
-
| Node packs and registry | `pack-registry.test.ts`, `pack-registry-publish.test.ts`, `maliciousManifest.test.ts`, `wasm-pack-load.test.ts`, `wasm-pack-invoke-completed.test.ts`, `wasm-pack-invoke-suspended.test.ts`, `wasm-pack-replay-determinism.test.ts`, `wasm-pack-memory-cap.test.ts`, `wasm-pack-abi-version-rejection.test.ts` | A | RFC 0008 WASM ABI scenarios landed 2026-05-10; gated on `capabilities.nodePackRuntimes.wasm.supported`. Memory-cap positive path closed 2026-05-12 via `examples/packs/rust-misbehaving-memory/` + in-memory loader's `memory.grow` probe + `capBreached.kind` schema extension. ABI-mismatch positive path closed 2026-05-12 via `examples/packs/rust-misbehaving-abi/` (declares ABI 999) + new `capabilities.nodePackRuntimes.wasm.loadedPacks[]` discovery field (rejected packs omitted). Remaining: hosted registry
|
|
23
|
+
| Node packs and registry | `pack-registry.test.ts`, `pack-registry-publish.test.ts`, `maliciousManifest.test.ts`, `wasm-pack-load.test.ts`, `wasm-pack-invoke-completed.test.ts`, `wasm-pack-invoke-suspended.test.ts`, `wasm-pack-replay-determinism.test.ts`, `wasm-pack-memory-cap.test.ts`, `wasm-pack-abi-version-rejection.test.ts` | A | RFC 0008 WASM ABI scenarios landed 2026-05-10; gated on `capabilities.nodePackRuntimes.wasm.supported`. Memory-cap positive path closed 2026-05-12 via `examples/packs/rust-misbehaving-memory/` + in-memory loader's `memory.grow` probe + `capBreached.kind` schema extension. ABI-mismatch positive path closed 2026-05-12 via `examples/packs/rust-misbehaving-abi/` (declares ABI 999) + new `capabilities.nodePackRuntimes.wasm.loadedPacks[]` discovery field (rejected packs omitted). Remaining: public hosted registry tarball-fetch + signature-verify roundtrip and host-side pack consumption proof. |
|
|
24
24
|
| Secrets and redaction | `redaction.test.ts`, `redactionAdversarial.test.ts`, `byok-roundtrip.test.ts` | A- | Cross-provider BYOK matrix and debug-bundle redaction under high volume. |
|
|
25
|
-
| Observability and diagnostics | `cost-attribution.test.ts`, `debugBundle.test.ts`, `otel-emission.test.ts`, `otel-trace-propagation.test.ts`, `metric-emission.test.ts`, `otel-emission-grpc.test.ts` | A | OTLP collector accepts all three OTLP transports: HTTP-JSON (2026-05-11), HTTP-protobuf (2026-05-12), gRPC over h2c HTTP/2 (2026-05-12 — hand-rolled framing at `conformance/src/lib/grpc-framing.ts`). Zero new npm deps for any of them. Opt-in via `OPENWOP_OTEL_COLLECTOR=true` (+ `OPENWOP_OTEL_COLLECTOR_GRPC=true` for the gRPC variant). Hosts advertise supported transports via `capabilities.observability.otel.exportProtocols ⊆ {http/json, http/protobuf, grpc}`; conformance scenario gates on the array. |
|
|
25
|
+
| Observability and diagnostics | `cost-attribution.test.ts`, `debugBundle.test.ts`, `otel-emission.test.ts`, `otel-trace-propagation.test.ts`, `otel-trace-propagation-subworkflow.test.ts`, `metric-emission.test.ts`, `otel-emission-grpc.test.ts` | A | OTLP collector accepts all three OTLP transports: HTTP-JSON (2026-05-11), HTTP-protobuf (2026-05-12), gRPC over h2c HTTP/2 (2026-05-12 — hand-rolled framing at `conformance/src/lib/grpc-framing.ts`). Zero new npm deps for any of them. Opt-in via `OPENWOP_OTEL_COLLECTOR=true` (+ `OPENWOP_OTEL_COLLECTOR_GRPC=true` for the gRPC variant). Hosts advertise supported transports via `capabilities.observability.otel.exportProtocols ⊆ {http/json, http/protobuf, grpc}`; conformance scenario gates on the array. Trace-context propagation closed 2026-05-13 with `otel-trace-propagation-subworkflow.test.ts` asserting parent + child spans share the inbound traceparent across the `core.subWorkflow` dispatch boundary. |
|
|
26
26
|
| Fixtures and corpus validity | `fixtures-valid.test.ts`, `fixtures-gating.test.ts`, `spec-corpus-validity.test.ts` | A | Keep fixture manifest synchronized as new optional profiles land. |
|
|
27
|
-
| Run control — pause/resume | `pause-resume.test.ts` |
|
|
28
|
-
| Rate-limit envelope | `rate-limit-envelope.test.ts` |
|
|
29
|
-
|
|
|
27
|
+
| Run control — pause/resume | `pause-resume.test.ts` | A− | Direct `pauseRun` / `resumeRun` route exercisers cover running → paused → resumed, terminal conflict, non-paused resume conflict, idempotent re-pause, and pause-during-suspend race. Remaining: explicit immediate-vs-drain-current-node policy assertion across hosts that advertise both drain policies. |
|
|
28
|
+
| Rate-limit envelope | `rate-limit-envelope.test.ts` | A− | Shape validation under deterministic 429 induction (CF-6 close-out 2026-05-15); Postgres reference host honors `OPENWOP_FORCE_RATE_LIMIT=true` to return canonical envelope (`rate_limited` + `Retry-After` + `details.scope: 'global'` + `details.retryAfterMs`) on every route. Live-verified: shape assertion passes against the seam. |
|
|
29
|
+
| SSE longevity (out-of-fast-CI soak) | `conformance/soak/sse-longevity.mjs` | A− | CF-10 close-out 2026-05-15. Documented soak runner exercises the SSE event stream for `OPENWOP_SOAK_DURATION_SECONDS` (default 300) creating runs at `OPENWOP_SOAK_RUN_INTERVAL_SECONDS` cadence; tracks reconnects, heartbeat cadence (min/max gaps), longest quiet period, total events. Emits a single JSON line on stdout for operator dashboards. NOT registered in `openwop:check`; deployer-invoked per `docs/PRODUCTION-RUNBOOK.md`. |
|
|
30
|
+
| Load profile (out-of-fast-CI throughput) | `conformance/soak/load-profile.mjs` | A− | OPS-2 close-out 2026-05-15. Throughput / latency runner across 5 canonical paths (`create` / `poll` / `sse` / `interrupt` / `webhook`). Configurable `OPENWOP_LOAD_SAMPLES` × `OPENWOP_LOAD_CONCURRENCY`. Emits per-path min/p50/p95/p99/max latency in milliseconds as a single JSON line. `interrupt` + `webhook` paths are honest-stubbed (require host-side test seams not yet stabilized in the reference). NOT registered in `openwop:check`. |
|
|
31
|
+
| Per-workflow `configurableSchema` | `configurable-schema.test.ts` | A− | Negative validation + positive accepted-overlay + `GET /v1/workflows/{id}` schema-surface assertion all covered (CF-7 close-out, 2026-05-15). Grade moves C+ → A−. |
|
|
30
32
|
| Append-reducer ordering | `append-ordering.test.ts` | B | Intra-engine sequence-order check; remaining: cross-engine ordering under a multi-engine fixture. |
|
|
31
|
-
| Webhook signature algorithms | `webhook-sig-algorithm.test.ts`, `webhook-signed-delivery.test.ts`, `webhook-negative.test.ts` | A
|
|
32
|
-
| Audit-log integrity profile | `audit-log-integrity.test.ts` | A
|
|
33
|
+
| Webhook signature algorithms | `webhook-sig-algorithm.test.ts`, `webhook-signed-delivery.test.ts`, `webhook-negative.test.ts`, `webhook-receiver-adversarial.test.ts` | A | Forward direction: discovery shape + end-to-end signed delivery with HMAC verification (`webhook-signed-delivery`); negative paths (SSRF guard / validation / unknown-unregister via `webhook-negative`). Reverse direction (CF-5 close-out 2026-05-15): `webhook-receiver-adversarial.test.ts` covers 6 paths — positive control + tampered body + tampered HMAC + stale timestamp + replayed signature + wrong algorithm + malformed signature header. Reference receiver implementation at `conformance/src/lib/webhook-receiver.ts` mirrors the SDK's `verifyWebhookSignature` helper. |
|
|
34
|
+
| Audit-log integrity profile | `audit-log-integrity.test.ts` | A | Profile claim + `/v1/audit/verify` shape + checkpoint-signature verification; chain re-walk with `chainValid` and `checkpointsValid` bits. Tamper detection covered host-internally at `examples/hosts/sqlite/test/audit-tamper.test.ts` (mutate-entry + forge-signature paths). CF-11 close-out 2026-05-15: cross-host checkpoint export via `examples/hosts/postgres/src/audit-export.ts` + standalone verifier at `scripts/verify-audit-checkpoints.mjs`; `examples/hosts/postgres/test/audit-checkpoint-export.test.ts` verifies 7 paths (positive + tampered-signature + non-monotonic-atSequence). |
|
|
33
35
|
| Multi-region idempotency capability | `multi-region-idempotency.test.ts` | C | Discovery enum coverage; remaining: cross-region partition simulation (requires multi-region harness). |
|
|
34
36
|
| Public hosted registry (`packs.openwop.dev`) | `registry-public.test.ts` | A− | Discovery, index, and per-pack manifest assertions against the public registry. Opt-in via `OPENWOP_TEST_PUBLIC_REGISTRY=true` so default conformance runs don't depend on outbound `packs.openwop.dev` reachability. Remaining: tarball-fetch + signature-verify roundtrip. |
|
|
37
|
+
| AI Envelope (FINAL v1.1 — `spec/v1/ai-envelope.md`, RFC 0021) | `aiEnvelope.universalKinds.test.ts`, `aiEnvelope.schemaDrift.test.ts`, `aiEnvelope.correlationReplay.test.ts`, `aiEnvelope.contractRefusal.test.ts`, `aiEnvelope.trustBoundaryPropagation.test.ts`, `aiEnvelope.redaction.test.ts`, `aiEnvelope.capBreached.test.ts`, `ai-envelope-shape.test.ts` | B (shape + 8 behavioral accept-pipeline assertions) | DRAFT v1.x gap-closure landed 2026-05-17; RFC 0021 promotion to FINAL v1.1 landed 2026-05-18. Closes the long-standing gap where 8 v1 surfaces already referenced AI Envelopes (`Capabilities.supportedEnvelopes` + `schemaVersions` + the three per-turn limits; `host.aiEnvelope.generate`; `envelopeType` on workflow-chain packs; `profiles.md` derivation; `host-extensions.md` namespacing; `positioning.md`; reference host discovery) but the envelope's own wire shape, universal kinds, schema discipline, and Envelope Contract gate were never specified. The 7 `aiEnvelope.*` advertisement-shape probes (gated on `capabilities.envelopeContracts.advertised: true`) cover the host's CAPABILITY claim. `ai-envelope-shape.test.ts` adds 8 BEHAVIORAL assertions through the workflow-engine sample's env-gated `POST /v1/host/sample/envelope/accept` seam: accepted / invalid (shape) / invalid (ISO 8601 timestamp) / gated (vendor kind not advertised) / breached (counter at cap) / universal-kind-always-allowed / normalizedMeta.contentTrust propagation from runTrustBoundary / envelope-supplied contentTrust precedence over runTrustBoundary. Behavior-unlock dependency for the remaining `aiEnvelope.*` `it.todo()` blocks: a reference host wires schema drift + correlationId-replay short-circuit + redaction-carry-forward + contract-refusal mappings + trust-boundary propagation onto RunEventDocs. |
|
|
35
38
|
|
|
36
39
|
---
|
|
37
40
|
|
|
@@ -42,14 +45,14 @@ Seventeen scenarios (or scenario groups) validate optional profiles where the ho
|
|
|
42
45
|
| Scenario | Profile / capability | Shape grade | Behavior grade | Behavior-unlock dependency |
|
|
43
46
|
|---|---|---|---|---|
|
|
44
47
|
| `audit-log-integrity.test.ts` | `openwop-audit-log-integrity` (`auth-profiles.md`) | A− (discovery + verify endpoint shape) | `host-pending` | Track 1.1 — SQLite host implements hash-chain + signed checkpoints |
|
|
45
|
-
| `rate-limit-envelope.test.ts` | normative `429` envelope (`rest-endpoints.md`) |
|
|
48
|
+
| `rate-limit-envelope.test.ts` | normative `429` envelope (`rest-endpoints.md`) | A− (deterministic via Postgres `OPENWOP_FORCE_RATE_LIMIT=true` seam, CF-6 close-out 2026-05-15) | host-claimed | — |
|
|
46
49
|
| `multi-region-idempotency.test.ts` | `capabilities.idempotency.crossRegion` (`idempotency.md`) | C (enum shape only) | `host-pending` | Multi-region host fixture; cross-region partition simulation |
|
|
47
|
-
| `configurable-schema.test.ts` | per-workflow `configurableSchema` (`run-options.md`) |
|
|
50
|
+
| `configurable-schema.test.ts` | per-workflow `configurableSchema` (`run-options.md`) | A− (negative validation + positive accepted-overlay + manifest-surface assertion, CF-7 close-out 2026-05-15) | host-claimed | — |
|
|
48
51
|
| `webhook-sig-algorithm.test.ts` | `X-openwop-Signature-Algorithm: v1` (`webhooks.md`) | C+ (discovery shape) | `host-pending` | End-to-end signed delivery against a test receiver |
|
|
49
52
|
| `pause-resume.test.ts` | `pauseRun` / `resumeRun` lifecycle (`rest-endpoints.md`) | B (lifecycle + 409-on-non-paused) | partial | Pause-during-suspend race; immediate-vs-drain policy assertion |
|
|
50
53
|
| `append-ordering.test.ts` | `append` reducer ordering (`channels-and-reducers.md`) | B (intra-engine) | partial | Cross-engine multi-engine fixture |
|
|
51
|
-
| `otel-emission.test.ts`, `otel-emission-grpc.test.ts` | `openwop.*` OTel spans (`observability.md`) | A (OTLP/HTTP-JSON + OTLP/HTTP-protobuf + OTLP/gRPC all accepted; collector content-type-routes JSON/protobuf and the gRPC HTTP/2 path frame-decodes via `grpc-framing.ts`) | full |
|
|
52
|
-
| `otel-trace-propagation.test.ts` | W3C trace-context propagation (`observability.md`) |
|
|
54
|
+
| `otel-emission.test.ts`, `otel-emission-grpc.test.ts` | `openwop.*` OTel spans (`observability.md`) | A (OTLP/HTTP-JSON + OTLP/HTTP-protobuf + OTLP/gRPC all accepted; collector content-type-routes JSON/protobuf and the gRPC HTTP/2 path frame-decodes via `grpc-framing.ts`) | full | — |
|
|
55
|
+
| `otel-trace-propagation.test.ts`, `otel-trace-propagation-subworkflow.test.ts` | W3C trace-context propagation (`observability.md`) | A (trace continuity across `runs:fork` + interrupt resolve + `core.subWorkflow` parent→child boundary; closed 2026-05-13 — subWorkflow scenario asserts both parent + child spans share the inbound traceparent's traceId) | full | — |
|
|
53
56
|
| `wasm-pack-*.test.ts` (six scenarios) | `capabilities.nodePackRuntimes.wasm` (`RFCS/0008`) | A (load + invoke + replay + memory-cap positive-path + ABI-mismatch positive-path) | full | Memory-cap positive path closed 2026-05-12 via misbehaving-memory pack + `memory.grow` probe in loader. ABI-mismatch positive path closed 2026-05-12 via misbehaving-abi pack + `loadedPacks[]` discovery field. |
|
|
54
57
|
| `production-backpressure.test.ts`, `production-retention-expiry.test.ts`, `restart-during-run.test.ts`, `staleClaim.test.ts`, `debug-bundle-truncation.test.ts`, `idempotency.test.ts`, `idempotencyRetry.test.ts` (seven scenarios) | `openwop-production` (`production-profile.md`, RFC 0009) | A− (capability shape + 503 envelope under saturation + discovery-exemption; durable-restart + debug-bundle-truncation predicates exercised end-to-end; retention-expiry envelope soft-skipped pending RFC 0009 Q#1) | host-pass | Postgres reference host advertises `capabilities.production.supported: true` since 2026-05-11 and passes all 11 assertions across the 5 non-opt-in scenarios under `OPENWOP_REQUIRE_BEHAVIOR=true` with `--no-file-parallelism` (the backpressure scenario saturates the inflight cap; parallel file execution collides with `idempotencyRetry.test.ts`'s burst). RFC 0009 unresolved questions #1 (force-expire endpoint normation) + #3 (inflightCap vs probing) gate the path to A. |
|
|
55
58
|
| `auth-api-key-rotation.test.ts` | `openwop-auth-api-key-rotation` (`auth-profiles.md`, RFC 0010) | B (capability shape + secondary-key overlap when env-supplied + canary-redaction) | `host-pending` | Reference host advertises the profile + supplies `OPENWOP_TEST_SECONDARY_API_KEY` for the overlap check. |
|
|
@@ -58,6 +61,13 @@ Seventeen scenarios (or scenario groups) validate optional profiles where the ho
|
|
|
58
61
|
| `auth-mtls.test.ts` | `openwop-auth-mtls` (`auth-profiles.md`, RFC 0010) | B (capability shape always; opt-in behavior assertions via `OPENWOP_TEST_MTLS=1` + cert paths; uses node:https.request for client-cert handshake — no new npm deps) | `host-pending` | Reference host advertises the profile + listens on HTTPS with mTLS enforcement; operator supplies `OPENWOP_TEST_MTLS_CLIENT_{CERT,KEY}_PATH` and (optionally) `OPENWOP_TEST_MTLS_CA_PATH`. |
|
|
59
62
|
| `replay-retention-expiry.test.ts` | `openwop-replay-fork` (`replay.md` §"Retention and garbage collection") | B (capability shape always; 410/422 envelope on expired-range fork gated on `OPENWOP_TEST_EXPIRED_REPLAY_RUN_ID`; details.{sourceRunId, fromSeq, retentionBoundary} soft-checks per spec SHOULD) | `host-pending` | Reference host advertises `replay.supported: true` + operator produces a known-expired run id (no standardized force-expire endpoint per RFC 0009 Q#1). |
|
|
60
63
|
| `discovery.test.ts` — auth-scoped subtests (3 of them) | `openwop-discovery-auth-scoped` (`capabilities-change-detection.md` §"Scoped capability views", RFC 0011) | B (capability shape + mode/endpointPath typing always; required-field-preservation in authenticated view always; authorization-oracle probe gated on `OPENWOP_TEST_UNAUTHORIZED_API_KEY`) | `host-pending` | Reference host advertises `capabilities.discovery.authScoped.supported: true` + serves an authenticated capability view that satisfies the base schema + a tenant-scoped key pair for the oracle probe. |
|
|
64
|
+
| `fs-path-traversal.test.ts` | `capabilities.fs` (RFC 0014, `host-fs-capability.md`) | A (advertisement shape + two path-escape probes asserting `path_outside_sandbox`) | host-pass (workflow-engine reference) | Reference host advertises `capabilities.fs.supported: true` with sandboxRoot under `<dataDir>/host-fs`. |
|
|
65
|
+
| `kv-cross-tenant-isolation.test.ts`, `kv-atomic-increment.test.ts`, `kv-cas.test.ts` (three scenarios) | `capabilities.kvStorage` (RFC 0015, `host-kv-storage-capability.md`) + `SECURITY/invariants.yaml` `kv-cross-tenant-isolation` | A (advertisement shape always; behavioral cross-tenant `set`/`get`, 50× concurrent atomic increment convergence, CAS matching/stale-expect) | host-pass via opt-in test seam | Reference host exposes `POST /v1/host/sample/test/surface` env-gated on `OPENWOP_TEST_SEAM_ENABLED=true`; hosts that don't expose the seam soft-skip the behavioral assertions and verify advertisement shape only. |
|
|
66
|
+
| `table-cross-tenant-isolation.test.ts` | `capabilities.tableStorage` (RFC 0016, `host-table-storage-capability.md`) | A (advertisement shape + behavioral cross-tenant insert/query proof) | host-pass via opt-in test seam | Same seam dependency as kv row. |
|
|
67
|
+
| `queue-cross-tenant-isolation.test.ts` | `capabilities.queueBus` (RFC 0017, `host-queue-bus-capability.md`) + `SECURITY/invariants.yaml` `queue-cross-tenant-isolation` | A (advertisement shape + behavioral cross-tenant publish/consume proof) | host-pass via opt-in test seam | Same seam dependency as kv row. |
|
|
68
|
+
| `blob-cross-tenant-isolation.test.ts`, `cache-cross-tenant-isolation.test.ts` (two scenarios) | `capabilities.blobStorage` + `capabilities.cache` (RFC 0019, `host-blob-cache-capability.md`) | A (advertisement shape + behavioral cross-tenant put/get isolation for both surfaces) | host-pass via opt-in test seam | Same seam dependency as kv row. |
|
|
69
|
+
| `sql-injection-rejection.test.ts` | `capabilities.sql` (RFC 0018, `host-sql-vector-search-capability.md`) + `SECURITY/invariants.yaml` `sql-parametric-only` | A (advertisement shape + parametric round-trip + injection-shape input bound as literal returns 0 rows) | host-pass via opt-in test seam | Same seam dependency as kv row. |
|
|
70
|
+
| `mcp-server-tool-roundtrip.test.ts`, `mcp-server-resource-roundtrip.test.ts`, `mcp-server-prompt-roundtrip.test.ts`, `mcp-server-sampling-bridge.test.ts`, `mcp-server-elicitation-bridge.test.ts`, `mcp-server-untrusted-args.test.ts` (six scenarios) | `capabilities.mcp.serverMount` (RFC 0020, `mcp-integration.md` §"OpenWOP host as MCP server") + `SECURITY/invariants.yaml` `mcp-server-untrusted-args` | A (advertisement shape + JSON-RPC tools/list+tools/call roundtrip, resources/list+read, prompts/list+get, sampling/elicitation bridge dispatch, Ajv2020 args validation rejecting with -32602 before workflow start) | host-pass via opt-in MCP server mount | Reference host exposes `POST /v1/host/sample/mcp` env-gated on `OPENWOP_MCP_SERVER_ENABLED=true`; hosts that don't expose the mount soft-skip the behavioral assertions and verify advertisement shape only. |
|
|
61
71
|
|
|
62
72
|
Strict-mode runner usage:
|
|
63
73
|
|
|
@@ -90,13 +100,13 @@ Every OpenAPI operation should have:
|
|
|
90
100
|
| `cancelRun` | `cancellation.test.ts` | Unknown/terminal idempotency cases partial | Add explicit already-terminal cancel behavior. |
|
|
91
101
|
| `bulkCancelRuns` | `bulk-cancel.test.ts` (Phase B close-out) | `bulk-cancel.test.ts` covers per-id error envelopes (`not_found`, `forbidden`, `run_terminal`), oversized-array `400 validation_error`, and 100-id cap | Add multi-tenant scope-narrowing scenario when host advertises per-key scope. |
|
|
92
102
|
| `verifyAuditLog` | `audit-log-integrity.test.ts` covers `/v1/audit/verify` shape end-to-end against the `openwop-audit-log-integrity` profile | `audit-log-integrity.test.ts` covers chain-valid + tamper detection (host-internal) | Add cross-host checkpoint export so an out-of-band verifier can re-anchor against the same chain. |
|
|
93
|
-
| `pauseRun` |
|
|
94
|
-
| `resumeRun` |
|
|
103
|
+
| `pauseRun` | `pause-resume.test.ts` covers direct route behavior for running → paused, idempotent re-pause, terminal conflict, and pause-during-suspend race | Conflict and race paths covered with `details.runStatus`; endpoint is no longer coverage-missing | Add explicit immediate-vs-drain-current-node policy assertion when a host advertises both drain policies. |
|
|
104
|
+
| `resumeRun` | `pause-resume.test.ts` covers direct route behavior for paused → running and non-paused conflict | Conflict path covered with `details.runStatus`; endpoint is no longer coverage-missing | Good. |
|
|
95
105
|
| `forkRun` | `replay-fork.test.ts`, `replayDeterminism.test.ts` | Negative `fromSeq`, past-end, unknown source, invalid overlay | Add arbitrary-event fork and retention-expired source. |
|
|
96
106
|
| `resolveInterruptByRun` | `interrupt-approval.test.ts`, `interrupt-clarification.test.ts`, `approval-payload.test.ts`, `interruptRace.test.ts` | Invalid action, unknown node, race cases | Add auth-required and quorum profile scenarios. |
|
|
97
|
-
| `inspectInterruptByToken` |
|
|
98
|
-
| `resolveInterruptByToken` |
|
|
99
|
-
| `getArtifact` | Indirect through approval payload fixtures | `route-coverage.test.ts` covers unknown artifact `404`/`403` envelope | Add positive artifact
|
|
107
|
+
| `inspectInterruptByToken` | `interrupt-token-matrix.test.ts` (CF-3, 2026-05-15) covers malformed + unknown token paths | Negative paths covered | Add explicit expired-token case when a host advertises a TTL seam. |
|
|
108
|
+
| `resolveInterruptByToken` | `interrupt-token-matrix.test.ts` covers replay (already-resolved) + unknown token; `interrupt-external-event-correlation.test.ts` covers positive path | Replay path + unknown-token path covered with explicit assertions | Add wrong-action case once the host advertises a typed allowed-actions vocabulary in the interrupt manifest. |
|
|
109
|
+
| `getArtifact` | Indirect through approval payload fixtures | `route-coverage.test.ts` covers unknown artifact `404`/`403` envelope; `artifact-auth.test.ts` (CF-4 close-out 2026-05-15) covers `401` unauthenticated path | Negative paths covered (401 + 404/403) | Add positive artifact-read scenario once a reference host implements `getArtifact` end-to-end. |
|
|
100
110
|
| `registerWebhook` | Webhook spec exists | `route-coverage.test.ts` covers invalid URL validation envelope | Add positive registration with a test receiver when harness support exists. |
|
|
101
111
|
| `unregisterWebhook` | Webhook spec exists | `route-coverage.test.ts` covers unknown subscription behavior | Add full register-then-unregister roundtrip with a test receiver. |
|
|
102
112
|
|
|
@@ -112,8 +122,10 @@ Every OpenAPI operation should have:
|
|
|
112
122
|
| P1 | Convert endpoint manifest into generated coverage evidence from `api/openapi.yaml` operation IDs. | `rest-endpoints.md` |
|
|
113
123
|
| ✅ done | MCP and A2A synthetic-peer roundtrip scenarios landed 2026-05-10 (`mcp-tool-roundtrip.test.ts`, `a2a-task-roundtrip.test.ts`); opt-in via `OPENWOP_MCP_FAKE_SERVER=true` / `OPENWOP_A2A_FAKE_PEER=true`. | `mcp-integration.md`, `a2a-integration.md` |
|
|
114
124
|
| P2 | Add replay retention and fork-from-arbitrary-event coverage. | `replay.md` |
|
|
115
|
-
| P1 | Deterministic 429-induction harness so `rate-limit-envelope.test.ts` triggers reliably under CI (currently observational)
|
|
125
|
+
| ~~P1~~ | ~~Deterministic 429-induction harness so `rate-limit-envelope.test.ts` triggers reliably under CI (currently observational).~~ ✅ Closed 2026-05-15 (CF-6): Postgres reference host honors `OPENWOP_FORCE_RATE_LIMIT=true`. | `rest-endpoints.md` |
|
|
116
126
|
| P1 | Add tamper-detection scenario for `audit-log-integrity.test.ts` — requires admin write access to the host's audit store. | `auth-profiles.md` |
|
|
117
127
|
| P2 | Cross-engine append-ordering scenario (multi-engine fixture). | `channels-and-reducers.md` |
|
|
118
128
|
| P2 | End-to-end webhook signed-delivery test exercising `X-openwop-Signature-Algorithm: v1`. | `webhooks.md` |
|
|
119
129
|
| P2 | Conformance scenarios that cite normative RFC docs (not just schemas) for the multi-agent surfaces. | RFCS/0002–0007 |
|
|
130
|
+
| ✅ Closed 2026-05-17 (HV-1) | `agentPackHandoffSchemaValidation.test.ts` verifies RFC 0003 §D — host MUST validate dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef`. Fixture `conformance-agent-pack-handoff-schema-validation` exercises 3 branches (valid-task / invalid-task / mock-return-violation). Capability-gated on `capabilities.agents.{supported,dispatch}`. | RFCS/0003-agent-packs.md §D |
|
|
131
|
+
| Placeholders 2026-05-18 (HVMAP-1/2) | RFC 0022 (`Draft`) ships 4 `it.todo()` placeholder scenarios: `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`, `subworkflow-input-mapping.test.ts`. Fixtures: `conformance-dispatch-input-mapping`, `-output-mapping`, `-cross-worker-handoff`, `conformance-subworkflow-input-mapping`. Promote to live assertions when RFC 0022 reaches `Active` AND a reference host advertises `capabilities.agents.dispatchMapping` and/or `capabilities.subWorkflow.inputMapping`. | RFCS/0022-dispatch-input-output-mapping.md §A + §B |
|
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
"id": "conformance-agent-low-confidence",
|
|
3
3
|
"name": "Conformance: Agent Low-Confidence Escalation",
|
|
4
4
|
"version": "1.0",
|
|
5
|
-
"description": "Phase 1 / CP-1 contract.
|
|
5
|
+
"description": "Phase 1 / CP-1 contract (RFC 0023). `core.conformance.mock-agent` emits `agent.decided` with confidence below the default 0.7 escalation threshold (mock confidence is 0.5). Host MUST follow with `node.suspended { reason: 'low-confidence', agentId, threshold, observed }` and transition run to `'waiting-approval'` per `interrupt.md` §`kind: \"low-confidence\"`. See agentConfidenceEscalation.test.ts.",
|
|
6
6
|
"nodes": [
|
|
7
7
|
{
|
|
8
8
|
"id": "low-conf-decider",
|
|
9
|
-
"typeId": "core.
|
|
9
|
+
"typeId": "core.conformance.mock-agent",
|
|
10
10
|
"name": "Low-Confidence Decider",
|
|
11
11
|
"position": { "x": 0, "y": 0 },
|
|
12
12
|
"config": {
|
|
13
|
-
"
|
|
13
|
+
"mockDecision": {
|
|
14
|
+
"decision": { "kind": "stub-low-conf" },
|
|
15
|
+
"confidence": 0.5
|
|
16
|
+
}
|
|
14
17
|
},
|
|
15
18
|
"inputs": {},
|
|
16
19
|
"agent": {
|
|
@@ -24,6 +27,6 @@
|
|
|
24
27
|
{ "id": "manual", "type": "manual", "enabled": true }
|
|
25
28
|
],
|
|
26
29
|
"variables": [],
|
|
27
|
-
"metadata": { "tags": ["conformance", "multi-agent", "phase-1", "low-confidence", "cp-1"] },
|
|
30
|
+
"metadata": { "tags": ["conformance", "multi-agent", "phase-1", "low-confidence", "cp-1", "rfc-0023"] },
|
|
28
31
|
"settings": { "timeout": 15000 }
|
|
29
32
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-agent-pack-handoff-schema-validation",
|
|
3
|
+
"name": "Conformance: Agent Pack Handoff Schema Validation",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "Phase 2 / HV-1. The fixture itself is a no-op workflow — the scenario verifies host behavior at the agent-dispatch surface for `core.openwop.agent-examples.structured-fixture` (the canonical handoff-schema fixture agent). The agent's manifest carries `handoff.taskSchemaRef` + `handoff.returnSchemaRef`; the host MUST validate dispatch payloads against the task schema (RFC 0003 §D) BEFORE invoking the agent, and return payloads against the return schema BEFORE persistence. The test drives the dispatch surface directly with three scenario branches (valid-task / invalid-task / mock-return-violation) per agentPackHandoffSchemaValidation.test.ts.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "noop",
|
|
9
|
+
"typeId": "core.identity",
|
|
10
|
+
"name": "Noop (handoff-validation fixture)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [
|
|
21
|
+
{ "name": "scenario", "type": "string" }
|
|
22
|
+
],
|
|
23
|
+
"metadata": {
|
|
24
|
+
"tags": ["conformance", "multi-agent", "phase-2", "handoff-validation"],
|
|
25
|
+
"requiresInstalledPack": "core.openwop.agent-examples",
|
|
26
|
+
"requiresAgentId": "core.openwop.agent-examples.structured-fixture",
|
|
27
|
+
"notes": "Test invokes the agent-dispatch surface directly with three scenarios per inputs.scenario; the workflow is a noop placeholder so it validates against workflow-definition.schema.json without requiring a dispatch typeId not yet in the in-tree node catalog."
|
|
28
|
+
},
|
|
29
|
+
"settings": { "timeout": 5000 }
|
|
30
|
+
}
|
|
@@ -2,15 +2,34 @@
|
|
|
2
2
|
"id": "conformance-agent-reasoning",
|
|
3
3
|
"name": "Conformance: Agent Reasoning Events",
|
|
4
4
|
"version": "1.0",
|
|
5
|
-
"description": "Phase 1. Drives
|
|
5
|
+
"description": "Phase 1 (RFC 0023). Drives the agent.* event family from a single `core.conformance.mock-agent` node: agent.reasoned → agent.toolCalled/Returned (paired by host-minted callId per RFC 0002 §B) → agent.handoff → agent.decided. Host MUST emit at least one event from the closed set {agent.reasoned, agent.toolCalled, agent.toolReturned, agent.handoff, agent.decided}, each carrying a non-empty `agentId`. See agentReasoningEvents.test.ts.",
|
|
6
6
|
"nodes": [
|
|
7
7
|
{
|
|
8
8
|
"id": "reasoner",
|
|
9
|
-
"typeId": "core.
|
|
9
|
+
"typeId": "core.conformance.mock-agent",
|
|
10
10
|
"name": "Reasoning Agent",
|
|
11
11
|
"position": { "x": 0, "y": 0 },
|
|
12
12
|
"config": {
|
|
13
|
-
"
|
|
13
|
+
"mockReasoning": {
|
|
14
|
+
"summary": "Decomposed query, decided to call a tool, then handed off.",
|
|
15
|
+
"tokenCount": 24
|
|
16
|
+
},
|
|
17
|
+
"mockToolCalls": [
|
|
18
|
+
{
|
|
19
|
+
"toolId": "openwop.echo:echo",
|
|
20
|
+
"arguments": { "x": 1 },
|
|
21
|
+
"result": { "x": 1 },
|
|
22
|
+
"durationMs": 1
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"mockHandoff": {
|
|
26
|
+
"toAgentId": "core.conformance.handoff-target",
|
|
27
|
+
"reason": "demo-handoff"
|
|
28
|
+
},
|
|
29
|
+
"mockDecision": {
|
|
30
|
+
"decision": { "next": "done" },
|
|
31
|
+
"confidence": 1
|
|
32
|
+
}
|
|
14
33
|
},
|
|
15
34
|
"inputs": {},
|
|
16
35
|
"agent": {
|
|
@@ -24,6 +43,6 @@
|
|
|
24
43
|
{ "id": "manual", "type": "manual", "enabled": true }
|
|
25
44
|
],
|
|
26
45
|
"variables": [],
|
|
27
|
-
"metadata": { "tags": ["conformance", "multi-agent", "phase-1", "reasoning"] },
|
|
46
|
+
"metadata": { "tags": ["conformance", "multi-agent", "phase-1", "reasoning", "rfc-0023"] },
|
|
28
47
|
"settings": { "timeout": 15000 }
|
|
29
48
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-cross-worker-handoff-child-a",
|
|
3
|
+
"name": "Conformance: Dispatch Cross-Worker Handoff (RFC 0022 §A) — child-a",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "First child of `conformance-dispatch-cross-worker-handoff`. Declares `output.defaultValue='hello'`; on terminal `completed`, parent's `perWorkerOutputMappings.child-a` harvests `output → sharedVar` per RFC 0022 §A. The shared parent variable bag is the handoff channel to child-b (RFC 0022 §D).",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "noop",
|
|
9
|
+
"typeId": "core.identity",
|
|
10
|
+
"name": "Noop (output seeded by defaultValue)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [
|
|
21
|
+
{ "name": "output", "type": "string", "defaultValue": "hello" }
|
|
22
|
+
],
|
|
23
|
+
"metadata": {
|
|
24
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "cross-worker-handoff", "child"]
|
|
25
|
+
},
|
|
26
|
+
"settings": { "timeout": 5000 }
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-cross-worker-handoff-child-b",
|
|
3
|
+
"name": "Conformance: Dispatch Cross-Worker Handoff (RFC 0022 §A) — child-b",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "Second child of `conformance-dispatch-cross-worker-handoff`. Sequential fan-out — runs AFTER child-a; child-a's outputMapping wrote `sharedVar='hello'` onto the parent variable bag. The dispatch node's `perWorkerInputMappings.child-b` projects parent's `sharedVar` onto this child's `input` input. The scenario reads this child's `inputs_json` via `GET /v1/runs/{childRunId}` and asserts `inputs.input === 'hello'` per RFC 0022 §A + §D.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "noop",
|
|
9
|
+
"typeId": "core.identity",
|
|
10
|
+
"name": "Noop (asserts via inputs)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [],
|
|
21
|
+
"metadata": {
|
|
22
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "cross-worker-handoff", "child"]
|
|
23
|
+
},
|
|
24
|
+
"settings": { "timeout": 5000 }
|
|
25
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-cross-worker-handoff",
|
|
3
|
+
"name": "Conformance: Dispatch Cross-Worker Handoff (RFC 0022 §A + §D)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §A + §D / HVMAP-1c — sequential fan-out across two children with cross-worker variable handoff via the shared parent variable bag. Supervisor plan: `next-worker: ['conformance-dispatch-cross-worker-handoff-child-a', 'conformance-dispatch-cross-worker-handoff-child-b']` → `terminate`. perWorkerOutputMappings.child-a maps `sharedVar ← output`; perWorkerInputMappings.child-b maps `input ← sharedVar`. Child-a declares `output.defaultValue='hello'`; on terminal, parent's `sharedVar` is set to `'hello'`. Child-b's `input` then receives parent's `sharedVar`. Test asserts child-b's `inputs.input === 'hello'`. See dispatch-cross-worker-handoff.test.ts.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "supervisor",
|
|
9
|
+
"typeId": "core.orchestrator.supervisor",
|
|
10
|
+
"name": "Supervisor (mock plan, multi-worker)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"mockDispatchPlan": [
|
|
14
|
+
{
|
|
15
|
+
"kind": "next-worker",
|
|
16
|
+
"nextWorkerIds": [
|
|
17
|
+
"conformance-dispatch-cross-worker-handoff-child-a",
|
|
18
|
+
"conformance-dispatch-cross-worker-handoff-child-b"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{ "kind": "terminate", "reason": "goal-reached" }
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"inputs": {}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "dispatch",
|
|
28
|
+
"typeId": "core.dispatch",
|
|
29
|
+
"name": "Dispatch with per-worker mappings",
|
|
30
|
+
"position": { "x": 200, "y": 0 },
|
|
31
|
+
"config": {
|
|
32
|
+
"askUserRouting": "auto",
|
|
33
|
+
"workerDispatchModel": "child-run",
|
|
34
|
+
"fanOutPolicy": "sequential",
|
|
35
|
+
"perWorkerOutputMappings": {
|
|
36
|
+
"conformance-dispatch-cross-worker-handoff-child-a": { "sharedVar": "output" }
|
|
37
|
+
},
|
|
38
|
+
"perWorkerInputMappings": {
|
|
39
|
+
"conformance-dispatch-cross-worker-handoff-child-b": { "input": "sharedVar" }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"inputs": {}
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"edges": [
|
|
46
|
+
{ "id": "e1", "sourceNodeId": "supervisor", "targetNodeId": "dispatch" },
|
|
47
|
+
{ "id": "e2", "sourceNodeId": "dispatch", "targetNodeId": "supervisor" }
|
|
48
|
+
],
|
|
49
|
+
"triggers": [
|
|
50
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
51
|
+
],
|
|
52
|
+
"variables": [
|
|
53
|
+
{ "name": "sharedVar", "type": "string", "defaultValue": "" }
|
|
54
|
+
],
|
|
55
|
+
"metadata": {
|
|
56
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "cross-worker-handoff"],
|
|
57
|
+
"requiresCapability": "capabilities.agents.dispatchMapping"
|
|
58
|
+
},
|
|
59
|
+
"settings": { "timeout": 30000 }
|
|
60
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-input-mapping-child",
|
|
3
|
+
"name": "Conformance: Dispatch Input Mapping (RFC 0022 §A) — child",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "Child fixture for `conformance-dispatch-input-mapping`. Noop body; the scenario reads this child's `inputs_json` (surfaced as `inputs` on `GET /v1/runs/{childRunId}`) and asserts `inputs.childGreeting === 'Alice'` per RFC 0022 §A.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "noop",
|
|
9
|
+
"typeId": "core.identity",
|
|
10
|
+
"name": "Noop (asserts via inputs)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [],
|
|
21
|
+
"metadata": {
|
|
22
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "input-mapping", "child"]
|
|
23
|
+
},
|
|
24
|
+
"settings": { "timeout": 5000 }
|
|
25
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-input-mapping",
|
|
3
|
+
"name": "Conformance: Dispatch Input Mapping (RFC 0022 §A)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §A / HVMAP-1a — host honors `inputMapping` on `core.dispatch` and projects parent variables into child inputs. Supervisor uses `mockDispatchPlan` (per the supervisor-mock extension landed 2026-05-18 — see RFC 0022 §\"Unresolved questions\" #6) to emit `next-worker: ['conformance-dispatch-input-mapping-child']`, then `terminate`. Dispatch's `inputMapping` projects parent's `parentName` onto the child's `childGreeting` input. Test reads the child run's `inputs` from `GET /v1/runs/{childRunId}` and asserts `inputs.childGreeting === 'Alice'`. See dispatch-input-mapping.test.ts.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "supervisor",
|
|
9
|
+
"typeId": "core.orchestrator.supervisor",
|
|
10
|
+
"name": "Supervisor (mock plan)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"mockDispatchPlan": [
|
|
14
|
+
{ "kind": "next-worker", "nextWorkerIds": ["conformance-dispatch-input-mapping-child"] },
|
|
15
|
+
{ "kind": "terminate", "reason": "goal-reached" }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"inputs": {}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "dispatch",
|
|
22
|
+
"typeId": "core.dispatch",
|
|
23
|
+
"name": "Dispatch with inputMapping",
|
|
24
|
+
"position": { "x": 200, "y": 0 },
|
|
25
|
+
"config": {
|
|
26
|
+
"askUserRouting": "auto",
|
|
27
|
+
"workerDispatchModel": "child-run",
|
|
28
|
+
"fanOutPolicy": "sequential",
|
|
29
|
+
"inputMapping": { "childGreeting": "parentName" }
|
|
30
|
+
},
|
|
31
|
+
"inputs": {}
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"edges": [
|
|
35
|
+
{ "id": "e1", "sourceNodeId": "supervisor", "targetNodeId": "dispatch" },
|
|
36
|
+
{ "id": "e2", "sourceNodeId": "dispatch", "targetNodeId": "supervisor" }
|
|
37
|
+
],
|
|
38
|
+
"triggers": [
|
|
39
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
40
|
+
],
|
|
41
|
+
"variables": [
|
|
42
|
+
{ "name": "parentName", "type": "string", "defaultValue": "Alice" }
|
|
43
|
+
],
|
|
44
|
+
"metadata": {
|
|
45
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "input-mapping"],
|
|
46
|
+
"requiresCapability": "capabilities.agents.dispatchMapping"
|
|
47
|
+
},
|
|
48
|
+
"settings": { "timeout": 30000 }
|
|
49
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-output-mapping-child",
|
|
3
|
+
"name": "Conformance: Dispatch Output Mapping (RFC 0022 §A) — child",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "Child fixture for `conformance-dispatch-output-mapping`. Declares `childOutcome.defaultValue='done'`; the variable is folded into the child's initial `variables_json` at run-create time. On terminal `completed`, the parent's `outputMapping` harvests `childOutcome` onto the parent's `parentResult` per RFC 0022 §A.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "noop",
|
|
9
|
+
"typeId": "core.identity",
|
|
10
|
+
"name": "Noop (childOutcome seeded by defaultValue)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [
|
|
21
|
+
{ "name": "childOutcome", "type": "string", "defaultValue": "done" }
|
|
22
|
+
],
|
|
23
|
+
"metadata": {
|
|
24
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "output-mapping", "child"]
|
|
25
|
+
},
|
|
26
|
+
"settings": { "timeout": 5000 }
|
|
27
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-output-mapping",
|
|
3
|
+
"name": "Conformance: Dispatch Output Mapping (RFC 0022 §A)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §A / HVMAP-1b — host harvests child variables back into parent variables via `outputMapping` on `core.dispatch`. Supervisor plan: `next-worker: ['conformance-dispatch-output-mapping-child']` → `terminate`. Child declares `childOutcome.defaultValue='done'`; on child terminal `completed`, the parent's outputMapping projects `childOutcome` onto `parentResult`. Test reads parent's final variables, asserts `parentResult === 'done'`. See dispatch-output-mapping.test.ts.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "supervisor",
|
|
9
|
+
"typeId": "core.orchestrator.supervisor",
|
|
10
|
+
"name": "Supervisor (mock plan)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"mockDispatchPlan": [
|
|
14
|
+
{ "kind": "next-worker", "nextWorkerIds": ["conformance-dispatch-output-mapping-child"] },
|
|
15
|
+
{ "kind": "terminate", "reason": "goal-reached" }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"inputs": {}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "dispatch",
|
|
22
|
+
"typeId": "core.dispatch",
|
|
23
|
+
"name": "Dispatch with outputMapping",
|
|
24
|
+
"position": { "x": 200, "y": 0 },
|
|
25
|
+
"config": {
|
|
26
|
+
"askUserRouting": "auto",
|
|
27
|
+
"workerDispatchModel": "child-run",
|
|
28
|
+
"fanOutPolicy": "sequential",
|
|
29
|
+
"outputMapping": { "parentResult": "childOutcome" }
|
|
30
|
+
},
|
|
31
|
+
"inputs": {}
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"edges": [
|
|
35
|
+
{ "id": "e1", "sourceNodeId": "supervisor", "targetNodeId": "dispatch" },
|
|
36
|
+
{ "id": "e2", "sourceNodeId": "dispatch", "targetNodeId": "supervisor" }
|
|
37
|
+
],
|
|
38
|
+
"triggers": [
|
|
39
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
40
|
+
],
|
|
41
|
+
"variables": [
|
|
42
|
+
{ "name": "parentResult", "type": "string", "defaultValue": "" }
|
|
43
|
+
],
|
|
44
|
+
"metadata": {
|
|
45
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "output-mapping"],
|
|
46
|
+
"requiresCapability": "capabilities.agents.dispatchMapping"
|
|
47
|
+
},
|
|
48
|
+
"settings": { "timeout": 30000 }
|
|
49
|
+
}
|