@openwop/openwop-conformance 1.2.0 → 1.3.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 +65 -0
- package/README.md +2 -2
- package/api/redocly.yaml +15 -0
- package/coverage.md +2 -1
- package/fixtures/conformance-agent-reasoning-streaming.json +37 -0
- package/fixtures/conformance-dispatch-cancellable-child.json +27 -0
- package/fixtures/conformance-dispatch-deterministic-fail-child.json +30 -0
- package/fixtures/conformance-dispatch-input-mapping-no-default.json +49 -0
- package/fixtures/conformance-dispatch-per-worker-override.json +59 -0
- package/fixtures/conformance-subworkflow-input-mapping-no-default.json +33 -0
- package/fixtures.md +6 -0
- package/package.json +1 -1
- package/schemas/capabilities.schema.json +16 -0
- package/schemas/core-conformance-mock-agent-config.schema.json +5 -0
- package/schemas/run-event-payloads.schema.json +35 -1
- package/schemas/run-event.schema.json +2 -0
- package/src/lib/driver.ts +15 -0
- package/src/lib/env.ts +51 -0
- package/src/lib/event-log-query.ts +62 -0
- package/src/lib/fixtures.ts +38 -1
- package/src/lib/host-toggle.ts +54 -0
- package/src/lib/multi-agent-capabilities.ts +10 -0
- package/src/lib/otel-scrape.ts +59 -0
- package/src/scenarios/agentReasoningStreaming.test.ts +193 -0
- package/src/scenarios/aiEnvelope.capBreached.test.ts +97 -9
- package/src/scenarios/aiEnvelope.contractRefusal.test.ts +128 -10
- package/src/scenarios/aiEnvelope.correlationReplay.test.ts +236 -21
- package/src/scenarios/aiEnvelope.redaction.test.ts +204 -24
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +158 -19
- package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +59 -8
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +100 -9
- package/src/scenarios/blob-presign-expiry.test.ts +35 -2
- package/src/scenarios/blob-roundtrip.test.ts +0 -0
- package/src/scenarios/cache-ttl-expiry.test.ts +28 -2
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +34 -3
- package/src/scenarios/dispatch-input-mapping.test.ts +75 -6
- package/src/scenarios/dispatch-output-mapping.test.ts +96 -6
- package/src/scenarios/fixtures-gating.test.ts +139 -1
- package/src/scenarios/kv-ttl-expiry.test.ts +33 -2
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +19 -0
- package/src/scenarios/pack-registry-publish.test.ts +231 -51
- package/src/scenarios/provider-usage.test.ts +185 -0
- package/src/scenarios/queue-ack-nack-dlq.test.ts +57 -3
- package/src/scenarios/queue-publish-consume-roundtrip.test.ts +43 -3
- package/src/scenarios/replay-llm-cache-key.test.ts +166 -25
- package/src/scenarios/search-bm25-roundtrip.test.ts +47 -2
- package/src/scenarios/sql-transaction-atomicity.test.ts +31 -2
- package/src/scenarios/stream-subscribe-from-beginning.test.ts +39 -2
- package/src/scenarios/subworkflow-input-mapping.test.ts +77 -7
- package/src/scenarios/table-cursor-pagination.test.ts +40 -2
- package/src/scenarios/table-schema-enforcement.test.ts +39 -2
- package/src/scenarios/vector-knn-roundtrip.test.ts +43 -3
- package/src/scenarios/workflow-chain-host-expansion.test.ts +202 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,70 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.0] — 2026-05-19
|
|
4
|
+
|
|
5
|
+
Minor bump per `PUBLISHING.md` §"Versioning alignment" — conformance scenario + fixture additions land on a minor. Closes the conformance-republish acceptance gate on RFC 0024 (§"Active → Accepted" criterion b) and bundles the wider behavioral-coverage push that converted ~50 `it.todo()` placeholders into live behavioral assertions across the RFC 0013 / 0016 / 0017 / 0022 / 0023 / 0024 surface.
|
|
6
|
+
|
|
7
|
+
### Added — RFC 0024 streaming reasoning (headline)
|
|
8
|
+
|
|
9
|
+
- **`conformance/fixtures/conformance-agent-reasoning-streaming.json`** — new RFC 0024 fixture. Drives the `core.conformance.mock-agent` typeId via `mockReasoning.streamChunks` (extended schema entry per RFC 0024 §"Conformance") to emit a deterministic sequence of `agent.reasoning.delta` events followed by exactly one closing `agent.reasoned`. The closing event's `reasoning` field MUST equal the concatenation of all chunks; deltas MUST carry monotonically-increasing `sequence` starting at 0 and MUST all precede the closing event in the event log.
|
|
10
|
+
- **`conformance/src/scenarios/agentReasoningStreaming.test.ts`** — new scenario gating on `capabilities.agents.supported: true` AND `capabilities.agents.reasoning.streaming: true` AND `getReasoningVerbosity() !== 'off'`. Asserts: (a) at least one `agent.reasoning.delta` event surfaces; (b) deltas appear in monotonic sequence order; (c) concatenated deltas equal the closing `agent.reasoned.reasoning` byte-for-byte; (d) the last delta's `eventLogIdx` strictly precedes the closing event's `eventLogIdx`; (e) the closing `agent.reasoned.causationId` chains correctly per `replay.md` §"Determinism with non-deterministic agents". Hosts without the streaming flag skip cleanly.
|
|
11
|
+
- **`schemas/core-conformance-mock-agent-config.schema.json`** updated with the `streamChunks` field on `mockReasoning` per RFC 0024 §"Conformance".
|
|
12
|
+
- **`spec/v1/node-packs.md`** Authorized-Emitters table for the `agent.*` family extended with `agent.reasoning.delta` (RFC 0024 addendum).
|
|
13
|
+
- **`spec/v1/capabilities.md`** §`agents.reasoning` documents the `streaming: boolean` field (default `false`); spec text + JSON Schema additions in `schemas/capabilities.schema.json`.
|
|
14
|
+
|
|
15
|
+
### Added — RFC 0022 §C variable-mapping refusal contract
|
|
16
|
+
|
|
17
|
+
- **3 new fixture variants** for the unset-default + per-worker-override + subWorkflow-unset edges: `conformance-dispatch-input-mapping-no-default.json`, `conformance-dispatch-per-worker-override.json`, `conformance-subworkflow-input-mapping-no-default.json`. Catalog rows added to `conformance/fixtures.md`.
|
|
18
|
+
- **`dispatch-input-mapping.test.ts`** + **`subworkflow-input-mapping.test.ts`** + **`dispatch-cross-worker-handoff.test.ts`** behavioral assertions for HVMAP-1a-null + HVMAP-1a-refusal + HVMAP-1c-override + HVMAP-2-unset + HVMAP-2-refusal — exercising both the projection paths and the `validation_error` refusal contract from RFC 0022 §C when a host does NOT advertise the gating capability.
|
|
19
|
+
|
|
20
|
+
### Added — Thread C: child-lifecycle fixtures
|
|
21
|
+
|
|
22
|
+
- **`conformance-dispatch-cancellable-child.json`** + **`conformance-dispatch-deterministic-fail-child.json`** support `dispatch-cross-worker-handoff` outputMapping skip-on-failure semantics and child-cancellation propagation tests. 2 new behavioral assertions in `dispatch-output-mapping.test.ts`.
|
|
23
|
+
|
|
24
|
+
### Added — Threads E.1 / E.2 / E.3: event-log query + OTel + debug-bundle seams
|
|
25
|
+
|
|
26
|
+
- **`event-log-query.test.ts`** — `eventLogQuery({fromSeq, toSeq, types[], causationId})` projection seam exercised via 12 behavioral assertions previously `it.todo()`. Gates on the host's advertisement of `host.eventLog.query.supported: true`.
|
|
27
|
+
- **`otel-trace-propagation-subworkflow.test.ts`** — W3C traceparent propagation across the dispatch boundary; reads context from the closing `runOrchestrator.decided`'s tracecontext and asserts the child `core.subWorkflow` inherits the parent trace.
|
|
28
|
+
- **`debug-bundle.test.ts`** + **`debug-bundle-redaction.test.ts`** — assert the host's debug-bundle endpoint surfaces the redacted event projection per SR-1 (no BYOK credential material in the bundle's event-log slice).
|
|
29
|
+
|
|
30
|
+
### Added — Thread F: stream/search/blob/queue/table/cache
|
|
31
|
+
|
|
32
|
+
- **`stream.test.ts`** + **`search-knn.test.ts`** + **`blob-presign.test.ts`** — 3 todos converted to behavioral via the `/v1/host/sample/test/surface` seam.
|
|
33
|
+
- **`queue-publish-consume-roundtrip.test.ts`** + **`queue-ack-nack-dlq.test.ts`** — full RFC 0017 §B point 2 ack/nack/DLQ state machine asserted end-to-end (consume → ack drop, consume → nack(requeue=true) re-queues at head with incremented deliveryCount, consume → deadLetter routes to `<subject>.dlq` with `{ original, deadLetterReason }` wrapper).
|
|
34
|
+
- **`table-cursor-pagination.test.ts`** + **`table-schema-enforcement.test.ts`** — RFC 0016 §B points 2+3: first-insert declares per-column types, divergent-type insert throws `table_schema_violation`; opaque base64 cursor pagination with `nextCursor: null` on the final page.
|
|
35
|
+
- **`cache-ttl-expiry.test.ts`** + **`kv-ttl-expiry.test.ts`** — TTL expiry assertions via the host-side test seam.
|
|
36
|
+
- **`sql-transaction-atomicity.test.ts`** + **`vector-knn-roundtrip.test.ts`** — round-trip + atomicity assertions on the SQL + vector surfaces.
|
|
37
|
+
- **`replay-llm-cache-key.test.ts`** — `replay.md` §"LLM cache-key recipe" §B asserted via the new `llm-cache-key` host seam (`POST /v1/host/sample/test/llm-cache-key`). Cross-host parity (B-suffixed runs against `OPENWOP_BASE_URL_B`) stays deferred awaiting cross-host plumbing.
|
|
38
|
+
|
|
39
|
+
### Added — AI envelope behavioral assertions
|
|
40
|
+
|
|
41
|
+
- **`aiEnvelope.{schemaDrift,redaction,correlationReplay}.test.ts`** — 9 todos converted to behavioral via the extended `host/envelopeAcceptor.ts` seam: (1) `schemaVersionFloor` + `envelopeStrictness` for below-floor refusal under `strict`; (2) `priorCorrelations` for same-correlationId re-emission returning the cached outcome AND same-correlationId-different-type refusing with `envelope_correlation_conflict`; (3) `byokCanaries` for recursive deep substitution of canary values with the canonical SR-1 `[REDACTED:<secretId>]` marker per `agent-memory.md:66`.
|
|
42
|
+
|
|
43
|
+
### Added — Driver helpers + opt-out axes
|
|
44
|
+
|
|
45
|
+
- **`conformance/src/lib/host-toggle.ts`** (NEW) — driver helpers `setHostCapability(name, value)`, `resetHostCapabilities()`, `isToggleAvailable()`. All operations soft-skip on HTTP 404 so non-seam hosts keep advertisement-shape coverage intact; scenarios MUST reset in `finally{}`. Backed by `POST /v1/host/sample/test/capability-toggle` on the reference workflow-engine.
|
|
46
|
+
- **`OPENWOP_OPTED_OUT_FIXTURES`** + **`OPENWOP_OPTED_OUT_SCENARIOS`** — two new operator-side env axes (CSV + trailing-`*` glob support) for hosts that auto-load every `conformance-*.json` on disk but do NOT implement the gated feature for some of them. Symmetric to the existing `OPENWOP_OPTED_OUT_PROFILES`. `conformance/src/lib/env.ts` + `conformance/src/lib/fixtures.ts` carry the helpers; `fixtures-gating.test.ts` adds 12 parser-edge-case tests covering CSV + glob semantics.
|
|
47
|
+
|
|
48
|
+
### Added — RFC 0013 Phase 3 reference host expansion
|
|
49
|
+
|
|
50
|
+
- **`host-in-memory`** gains the Phase 3 surface; new scenarios assert the in-memory host now passes the same Phase 3 advertisement-shape suite as the SQLite host. Per `INTEROP-MATRIX.md`, both reference hosts now advertise Phase 3.
|
|
51
|
+
|
|
52
|
+
### Tightened
|
|
53
|
+
|
|
54
|
+
- **Persisted envelope-correlation dedup seam** (`be89f4d`) — `priorCorrelations` now reads from a real persisted store on the reference workflow-engine, not just an in-flight map. Scenario assertions strengthened to survive a process restart between the original `accept` and the replay.
|
|
55
|
+
- **`apps/workflow-engine/.../host/capabilityOverlay.ts`** (NEW reference-host file) — process-local overlay over advertised capability flags, consulted by `validateDefinition` at workflow-register time. Defaults `agents.dispatchMapping` and `subWorkflow.inputMapping` to `false` per the honest-advertisement principle (the reference workflow-engine implements the RFC 0022 §C refusal contract but does NOT yet execute the mapping itself).
|
|
56
|
+
- **`examples/hosts/sqlite/src/server.ts` artifact-route stub** — `checkAuth` now runs BEFORE any 404 across HEAD/POST/PUT/DELETE; non-GET → 405 method_not_allowed (per `rest-endpoints.md §getArtifact` advertising GET only); GET → 404 not_found. Closes an unauthenticated runId/artifactId probe surface that the prior catch-all 404 left open.
|
|
57
|
+
|
|
58
|
+
### Compatibility
|
|
59
|
+
|
|
60
|
+
**Additive** per `COMPATIBILITY.md §2.1`. New fixtures, new scenarios, new driver helpers, new env axes — no existing scenario was relaxed; no existing fixture was renamed or its semantics changed; no existing host-side contract changed. RFC 0024's new event type `agent.reasoning.delta` is gated on `capabilities.agents.reasoning.streaming: true` (default `false`); hosts that omit it advertise the existing non-streaming contract and skip the new scenario cleanly. The capability-overlay toggle endpoint and the new sample-namespaced test seams live under the sample-namespaced test-seam prefix per `host-extensions.md` §"Canonical prefixes" — explicitly not part of the v1 wire contract.
|
|
61
|
+
|
|
62
|
+
### Notes
|
|
63
|
+
|
|
64
|
+
- This bump does NOT change the v1.0 spec corpus surface; `@openwop/openwop@1.1.x`, `openwop-client@1.1.x`, and the Go SDK stay locked to their current versions per `PUBLISHING.md` §"Versioning alignment" ("Conformance scenario addition | @openwop/openwop-conformance minor bump; other artifacts unaffected").
|
|
65
|
+
- Trigger: push `openwop-conformance/v1.3.0` per `.github/workflows/openwop-publish.yml` (only the `publish-conformance` job runs).
|
|
66
|
+
- RFC 0024 §"Active → Accepted" — this republish resolves criterion (b) ("next `@openwop/openwop-conformance` republish carrying the new fixture+scenario to downstream consumers"). Criterion (a) (external host advertisement evidence) remains open.
|
|
67
|
+
|
|
3
68
|
## [1.2.0] — 2026-05-18
|
|
4
69
|
|
|
5
70
|
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`.
|
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 160 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: 160 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
|
|
175
175
|
|
|
176
176
|
## Remaining Gaps
|
|
177
177
|
|
package/api/redocly.yaml
CHANGED
|
@@ -6,3 +6,18 @@ rules:
|
|
|
6
6
|
# and take no input — they have no meaningful 4XX response surface. 5XX is the
|
|
7
7
|
# only honest failure mode and is documented inline.
|
|
8
8
|
operation-4xx-response: off
|
|
9
|
+
|
|
10
|
+
# The rule flags `then: { required: [<name>] }` clauses where <name> is not
|
|
11
|
+
# defined in the `then` clause's OWN `properties` block — but in the standard
|
|
12
|
+
# JSON Schema 2020-12 `if/then` conditional-requirement idiom (used by
|
|
13
|
+
# `capabilities.schema.json` to tighten required-fields when `supported: true`),
|
|
14
|
+
# the property IS defined in the parent's `properties` block. Redocly's rule
|
|
15
|
+
# doesn't walk to parent scope, so it false-positives on every valid use of
|
|
16
|
+
# the idiom. Disabling globally is safe because:
|
|
17
|
+
#
|
|
18
|
+
# - the typo-in-required protection the rule provides is also covered by
|
|
19
|
+
# `scripts/check-required-properties-defined.mjs` (which walks parent
|
|
20
|
+
# scope correctly), wired into `openwop-check.sh` step [7/9];
|
|
21
|
+
# - our only `then/required` sites are the two in `capabilities.schema.json`,
|
|
22
|
+
# both of which are well-formed.
|
|
23
|
+
no-required-schema-properties-undefined: off
|
package/coverage.md
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
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). |
|
|
35
35
|
| Multi-region idempotency capability | `multi-region-idempotency.test.ts` | C | Discovery enum coverage; remaining: cross-region partition simulation (requires multi-region harness). |
|
|
36
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
|
+
| Workflow-chain packs (RFC 0013 — `spec/v1/workflow-chain-packs.md`) | `workflow-chain-pack-manifest-validation.test.ts`, `workflow-chain-pack-signature-verification.test.ts`, `workflow-chain-expansion.test.ts`, `workflow-chain-unresolvable-typeid.test.ts`, `workflow-chain-host-expansion.test.ts` | A (4 server-free + 1 live-host) | RFC 0013 promoted Draft → Active 2026-05-18; live-host gate (`workflow-chain-host-expansion.test.ts`) added 2026-05-18 closing the Phase 3 acceptance criterion. The 4 server-free scenarios exercise the pure-library algorithm; the new live-host scenario exercises the reference in-memory host's HTTP wrapper (`POST /v1/host/sample/workflow-chain:expand`) under `OPENWOP_REQUIRE_BEHAVIOR=true`, gated on `capabilities.workflowChainPacks.supported: true`. 6 cases — discovery advertisement / 1-node positive / 2-node positive with edges / unknown-pack 404 / unknown-chain 404 / malformed-body 422. RFC promotes to `Accepted` once the live-host scenario passes against a published host run. |
|
|
37
38
|
| 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. |
|
|
38
39
|
|
|
39
40
|
---
|
|
@@ -106,7 +107,7 @@ Every OpenAPI operation should have:
|
|
|
106
107
|
| `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. |
|
|
107
108
|
| `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
109
|
| `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. |
|
|
110
|
+
| `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; SQLite host 401-before-404 stub landed 2026-05-19, closes the info-leak surface for every HTTP method) covers `401` unauthenticated path | Negative paths covered (401 + 405 non-GET + 404/403) | Add positive artifact-read scenario once a reference host implements `getArtifact` end-to-end. |
|
|
110
111
|
| `registerWebhook` | Webhook spec exists | `route-coverage.test.ts` covers invalid URL validation envelope | Add positive registration with a test receiver when harness support exists. |
|
|
111
112
|
| `unregisterWebhook` | Webhook spec exists | `route-coverage.test.ts` covers unknown subscription behavior | Add full register-then-unregister roundtrip with a test receiver. |
|
|
112
113
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-agent-reasoning-streaming",
|
|
3
|
+
"name": "Conformance: Streaming agent.reasoning.delta (RFC 0024)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0024. Drives the `core.conformance.mock-agent` node to emit incremental `agent.reasoning.delta` events (one per `mockReasoning.streamChunks` entry, sequence 0..N-1) followed by exactly one closing `agent.reasoned` whose `reasoning` equals the concatenation of all chunks. Gated on `capabilities.agents.reasoning.streaming: true`. See agentReasoningStreaming.test.ts.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "streaming-reasoner",
|
|
9
|
+
"typeId": "core.conformance.mock-agent",
|
|
10
|
+
"name": "Streaming Reasoning Agent",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"mockReasoning": {
|
|
14
|
+
"summary": "Streamed reasoning trace for RFC 0024 conformance.",
|
|
15
|
+
"tokenCount": 12,
|
|
16
|
+
"streamChunks": [
|
|
17
|
+
"Let me think about this. ",
|
|
18
|
+
"First, the user is asking a question. ",
|
|
19
|
+
"Therefore, I should respond clearly."
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"inputs": {},
|
|
24
|
+
"agent": {
|
|
25
|
+
"agentId": "core.conformance.streaming-reasoner",
|
|
26
|
+
"modelClass": "reasoning"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"edges": [],
|
|
31
|
+
"triggers": [
|
|
32
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
33
|
+
],
|
|
34
|
+
"variables": [],
|
|
35
|
+
"metadata": { "tags": ["conformance", "multi-agent", "phase-1", "reasoning", "streaming", "rfc-0024"] },
|
|
36
|
+
"settings": { "timeout": 15000 }
|
|
37
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-cancellable-child",
|
|
3
|
+
"name": "Conformance: Dispatch cancellable child (RFC 0022 §B HVMAP-1b-cancelled)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §B / HVMAP-1b-cancelled — child workflow with a long-running `core.delay` so the test can externally cancel it via `POST /v1/runs/{childRunId}/cancel`. Used by `conformance-dispatch-output-mapping` (parent) to verify that the parent's `outputMapping` MUST be SKIPPED when the child terminates `cancelled`; the parent's `parentResult` variable MUST remain at its pre-dispatch state.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "wait",
|
|
9
|
+
"typeId": "core.delay",
|
|
10
|
+
"name": "Long delay (cancelled externally)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": { "durationMs": 30000 },
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [
|
|
21
|
+
{ "name": "childOutcome", "type": "string", "defaultValue": "this-should-not-be-harvested" }
|
|
22
|
+
],
|
|
23
|
+
"metadata": {
|
|
24
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "output-mapping", "hvmap-1b-cancelled", "child"]
|
|
25
|
+
},
|
|
26
|
+
"settings": { "timeout": 60000, "maxRetries": 0 }
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-deterministic-fail-child",
|
|
3
|
+
"name": "Conformance: Dispatch deterministic-fail child (RFC 0022 §B HVMAP-1b-failed)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §B / HVMAP-1b-failed — child workflow that ALWAYS terminates `failed` via the host's `core.fail` node. Used by `conformance-dispatch-output-mapping` (parent) to verify that the parent's `outputMapping` MUST be SKIPPED when the child terminates non-completed; the parent's `parentResult` variable MUST remain at its pre-dispatch state.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "fail",
|
|
9
|
+
"typeId": "core.fail",
|
|
10
|
+
"name": "Deterministic fail",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"code": "hvmap_1b_failed_fixture",
|
|
14
|
+
"message": "intentional terminal failure for outputMapping-skip assertion"
|
|
15
|
+
},
|
|
16
|
+
"inputs": {}
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"edges": [],
|
|
20
|
+
"triggers": [
|
|
21
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
22
|
+
],
|
|
23
|
+
"variables": [
|
|
24
|
+
{ "name": "childOutcome", "type": "string", "defaultValue": "this-should-not-be-harvested" }
|
|
25
|
+
],
|
|
26
|
+
"metadata": {
|
|
27
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "output-mapping", "hvmap-1b-failed", "child"]
|
|
28
|
+
},
|
|
29
|
+
"settings": { "timeout": 5000, "maxRetries": 0 }
|
|
30
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-input-mapping-no-default",
|
|
3
|
+
"name": "Conformance: Dispatch Input Mapping — parentName unset (RFC 0022 §A HVMAP-1a-null)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §A / HVMAP-1a-null — parent variant of `conformance-dispatch-input-mapping` that DECLARES `parentName` in `variables[]` but OMITS its `defaultValue`. The dispatch's `inputMapping: { childGreeting: 'parentName' }` projects an unset parent variable. Per RFC 0022 §A normative bullet: child `inputs.childGreeting` MUST surface as `undefined` (NOT `null`, NOT omitted). Same supervisor + dispatch shape as the base fixture; only the `variables[].parentName.defaultValue` is removed. See dispatch-input-mapping.test.ts § HVMAP-1a-null.",
|
|
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 (parent var unset)",
|
|
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" }
|
|
43
|
+
],
|
|
44
|
+
"metadata": {
|
|
45
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "input-mapping", "hvmap-1a-null"],
|
|
46
|
+
"requiresCapability": "capabilities.agents.dispatchMapping"
|
|
47
|
+
},
|
|
48
|
+
"settings": { "timeout": 30000 }
|
|
49
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-dispatch-per-worker-override",
|
|
3
|
+
"name": "Conformance: Dispatch Per-Worker Mapping Override (RFC 0022 §A HVMAP-1c-override)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §A / HVMAP-1c-override — verifies that `perWorkerInputMappings[childId]` OVERRIDES the default `inputMapping` for the named child, while OTHER children continue to use the default. Supervisor plan: `next-worker: ['conformance-dispatch-cross-worker-handoff-child-a', 'conformance-dispatch-cross-worker-handoff-child-b']` → `terminate`. Default `inputMapping: { input: 'defaultX' }`; `perWorkerInputMappings.conformance-dispatch-cross-worker-handoff-child-b: { input: 'sharedVar' }`. child-a receives `input: <defaultX-value>`; child-b receives `input: <sharedVar-value>` (NOT defaultX) per RFC 0022 §A `effectiveInputMapping` precedence. See dispatch-cross-worker-handoff.test.ts § HVMAP-1c-override.",
|
|
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 default + per-worker override",
|
|
30
|
+
"position": { "x": 200, "y": 0 },
|
|
31
|
+
"config": {
|
|
32
|
+
"askUserRouting": "auto",
|
|
33
|
+
"workerDispatchModel": "child-run",
|
|
34
|
+
"fanOutPolicy": "sequential",
|
|
35
|
+
"inputMapping": { "input": "defaultX" },
|
|
36
|
+
"perWorkerInputMappings": {
|
|
37
|
+
"conformance-dispatch-cross-worker-handoff-child-b": { "input": "sharedVar" }
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"inputs": {}
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"edges": [
|
|
44
|
+
{ "id": "e1", "sourceNodeId": "supervisor", "targetNodeId": "dispatch" },
|
|
45
|
+
{ "id": "e2", "sourceNodeId": "dispatch", "targetNodeId": "supervisor" }
|
|
46
|
+
],
|
|
47
|
+
"triggers": [
|
|
48
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
49
|
+
],
|
|
50
|
+
"variables": [
|
|
51
|
+
{ "name": "defaultX", "type": "string", "defaultValue": "default-x-value" },
|
|
52
|
+
{ "name": "sharedVar", "type": "string", "defaultValue": "shared-value" }
|
|
53
|
+
],
|
|
54
|
+
"metadata": {
|
|
55
|
+
"tags": ["conformance", "rfc-0022", "dispatch", "per-worker-mapping", "hvmap-1c-override"],
|
|
56
|
+
"requiresCapability": "capabilities.agents.dispatchMapping"
|
|
57
|
+
},
|
|
58
|
+
"settings": { "timeout": 30000 }
|
|
59
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-subworkflow-input-mapping-no-default",
|
|
3
|
+
"name": "Conformance: subWorkflow Input Mapping — currentPrdId unset (RFC 0022 §B HVMAP-2-unset)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0022 §B / HVMAP-2-unset — parent variant of `conformance-subworkflow-input-mapping` that DECLARES `currentPrdId` in `variables[]` but OMITS its `defaultValue`. The `core.subWorkflow` node's `inputMapping: { receivedPrdId: 'currentPrdId' }` projects an unset parent variable. Per RFC 0022 §B normative bullet: child `receivedPrdId` MUST surface as `undefined` (NOT `null`, NOT omitted) — distinct from the child's own `defaultValue` fold. Same shape as the base fixture; only `currentPrdId.defaultValue` is removed. See subworkflow-input-mapping.test.ts § HVMAP-2-unset.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "subwf-call",
|
|
9
|
+
"typeId": "core.subWorkflow",
|
|
10
|
+
"name": "Invoke child with inputMapping (parent var unset)",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"workflowId": "conformance-subworkflow-input-mapping-child",
|
|
14
|
+
"waitForCompletion": true,
|
|
15
|
+
"onChildFailure": "fail-parent",
|
|
16
|
+
"inputMapping": { "receivedPrdId": "currentPrdId" }
|
|
17
|
+
},
|
|
18
|
+
"inputs": {}
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"edges": [],
|
|
22
|
+
"triggers": [
|
|
23
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
24
|
+
],
|
|
25
|
+
"variables": [
|
|
26
|
+
{ "name": "currentPrdId", "type": "string" }
|
|
27
|
+
],
|
|
28
|
+
"metadata": {
|
|
29
|
+
"tags": ["conformance", "rfc-0022", "subworkflow", "input-mapping", "hvmap-2-unset"],
|
|
30
|
+
"requiresCapability": "capabilities.subWorkflow.inputMapping"
|
|
31
|
+
},
|
|
32
|
+
"settings": { "timeout": 10000 }
|
|
33
|
+
}
|
package/fixtures.md
CHANGED
|
@@ -59,6 +59,7 @@ All fixtures MUST advertise:
|
|
|
59
59
|
| Interrupt — Parent/Child Cancel | `conformance-interrupt-parent-child-cancel` + `conformance-interrupt-parent-child-cancel-child` | Verifies `openwop-interrupt-parent-child` cancel cascade | `cancelled` (both runs) | ≤ 30s |
|
|
60
60
|
| Agent Identity | `conformance-agent-identity` | Phase 1 — `RunSnapshot.agent` / `runOrchestrator` AgentRef wire-shape | `completed` | ≤ 10s |
|
|
61
61
|
| Agent Reasoning | `conformance-agent-reasoning` | Phase 1 / RFC 0023 — `agent.*` event family emission + `callId` pairing on `core.conformance.mock-agent` | `completed` | ≤ 15s |
|
|
62
|
+
| Agent Reasoning Streaming | `conformance-agent-reasoning-streaming` | RFC 0024 — `core.conformance.mock-agent` with `mockReasoning.streamChunks` drives incremental `agent.reasoning.delta` events (sequence 0..N-1) followed by exactly one closing `agent.reasoned` whose `reasoning` equals the concatenation. Gated on `capabilities.agents.reasoning.streaming: true`. | `completed` | ≤ 15s |
|
|
62
63
|
| Agent Low-Confidence | `conformance-agent-low-confidence` | Phase 1 / CP-1 / RFC 0023 — `core.conformance.mock-agent` emits `agent.decided` with confidence < threshold; host MUST follow with `node.suspended { reason: 'low-confidence' }` | `waiting-approval` (suspends) | unbounded (suspends) |
|
|
63
64
|
| Message Reducer | `conformance-message-reducer` | Phase 1 — `message` reducer idempotency on duplicate `messageId` | `completed` | ≤ 10s |
|
|
64
65
|
| Agent Pack Install | `conformance-agent-pack-install` | Phase 2 — pack `agents[]` surface as AgentManifest at `GET /v1/packs` | `completed` | ≤ 5s |
|
|
@@ -74,6 +75,11 @@ All fixtures MUST advertise:
|
|
|
74
75
|
| 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 |
|
|
75
76
|
| 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 |
|
|
76
77
|
| 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 |
|
|
78
|
+
| Dispatch Input Mapping — unset variant | `conformance-dispatch-input-mapping-no-default` | RFC 0022 §A / HVMAP-1a-null — parent variant that DECLARES `parentName` but OMITS its `defaultValue`. The dispatch's `inputMapping` projects an unset parent variable; per §A normative bullet, child `inputs.childGreeting` MUST surface as `undefined` (NOT `null`, NOT omitted). Reuses `conformance-dispatch-input-mapping-child`. | `completed` | ≤ 30s |
|
|
79
|
+
| subWorkflow Input Mapping — unset variant | `conformance-subworkflow-input-mapping-no-default` | RFC 0022 §B / HVMAP-2-unset — parent variant that DECLARES `currentPrdId` but OMITS its `defaultValue`. Per §B, the unset projection MUST surface as `undefined` (NOT `null`) — distinct from the child's own `defaultValue` fold. Reuses `conformance-subworkflow-input-mapping-child`. | `completed` | ≤ 10s |
|
|
80
|
+
| 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 |
|
|
81
|
+
| 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 |
|
|
82
|
+
| 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 /v1/runs/{childRunId}/cancel`. Verifies the parent's `outputMapping` is SKIPPED when the child terminates `cancelled`. | `cancelled` | ≤ 60s |
|
|
77
83
|
| Agent Memory Round-Trip | `conformance-agent-memory-roundtrip` | Phase 3 — `MemoryAdapter.list/get` write → read | `completed` | ≤ 15s |
|
|
78
84
|
| Agent Memory Cross-Tenant | `conformance-agent-memory-cross-tenant` | Phase 3 / CTI-1 — cross-tenant probe MUST return `[]` / `null` | `completed` | ≤ 10s |
|
|
79
85
|
| Agent Memory Redaction | `conformance-agent-memory-redaction` | Phase 3 / SR-1 — BYOK plaintext surfaces as `[REDACTED:<id>]` on read | `completed` | ≤ 15s |
|
package/package.json
CHANGED
|
@@ -210,6 +210,17 @@
|
|
|
210
210
|
"uniqueItems": true,
|
|
211
211
|
"description": "Optional v1 host-advertised opaque capability ids that NodeModules may declare in `NodeModule.requires`. Naming convention: dotted, domain-scoped (`chat.sendPrompt`, `canvas.write`, `secrets.byok`). Provider value shapes are documented per-capability alongside consumers, NOT in the protocol package — the protocol owns the *check*, not domain provider contracts. A client that submits a workflow whose nodes declare a `requires` entry SHOULD first verify the host advertises that capability; a host that lacks a capability MUST refuse to dispatch nodes that declare it, terminating the run with `RunSnapshot.error.code = 'capability_not_provided'`. See `capabilities.md` §\"Runtime capabilities\"."
|
|
212
212
|
},
|
|
213
|
+
"providerUsage": {
|
|
214
|
+
"type": "object",
|
|
215
|
+
"description": "RFC 0026 (Draft). Hosts that emit `provider.usage` events after every LLM provider invocation per RFC 0026 §B. The event carries per-call token counts in the durable event log; cost rollup remains in `RunSnapshot.metrics.openwopCost`. Old hosts ignore.",
|
|
216
|
+
"properties": {
|
|
217
|
+
"supported": { "type": "boolean", "description": "Host emits one `provider.usage` event per LLM provider call." },
|
|
218
|
+
"costEstimates": { "type": "boolean", "description": "When true, the host includes `costEstimateUsd` on `provider.usage` events using its internal rate table. When false/absent, only token counts are emitted." },
|
|
219
|
+
"currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "Default ISO 4217 currency for `costEstimateUsd` values. When absent, USD is assumed." }
|
|
220
|
+
},
|
|
221
|
+
"required": ["supported"],
|
|
222
|
+
"additionalProperties": false
|
|
223
|
+
},
|
|
213
224
|
"aiProviders": {
|
|
214
225
|
"type": "object",
|
|
215
226
|
"description": "Optional v1 companion to `secrets`. Advertises which AI providers the host's AI-proxy can route to and which permit BYOK.",
|
|
@@ -357,6 +368,11 @@
|
|
|
357
368
|
"type": "integer",
|
|
358
369
|
"minimum": 0,
|
|
359
370
|
"description": "Effective cap on reasoning trace length when verbosity is `summary`. Default 512 tokens."
|
|
371
|
+
},
|
|
372
|
+
"streaming": {
|
|
373
|
+
"type": "boolean",
|
|
374
|
+
"default": false,
|
|
375
|
+
"description": "RFC 0024. When `true`, the host MAY emit `agent.reasoning.delta` events while a reasoning block is still open, in addition to the final `agent.reasoned`. Hosts that omit / `false` this flag emit only the final `agent.reasoned`. Consumers MUST tolerate both modes."
|
|
360
376
|
}
|
|
361
377
|
},
|
|
362
378
|
"additionalProperties": false
|
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
"type": "integer",
|
|
32
32
|
"minimum": 0,
|
|
33
33
|
"description": "Optional reasoning-token count for observability/cost attribution."
|
|
34
|
+
},
|
|
35
|
+
"streamChunks": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": { "type": "string" },
|
|
38
|
+
"description": "RFC 0024. When present, the host MUST emit one `agent.reasoning.delta` event per array entry (in order; `sequence` starts at 0 and increments by 1), THEN emit the closing `agent.reasoned` event whose `reasoning` field equals the concatenation of all `streamChunks`. When absent, only the closing `agent.reasoned` event fires (the pre-RFC-0024 behavior). Gated at conformance test time on `capabilities.agents.reasoning.streaming: true`."
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openwop.dev/spec/v1/run-event-payloads.schema.json",
|
|
4
4
|
"title": "RunEventPayloads",
|
|
5
|
-
"description": "Per-RunEventType payload schemas. The base RunEventDoc shape (run-event.schema.json) leaves `payload` permissive for forward-compat. This schema defines the canonical payload contract for each known RunEventType. Consumers MAY pin strict payload validation via `$defs.<typeId>` and `ajv.validate(schema.$defs[event.type], event.payload)`. Unknown event types MUST be tolerated (no $defs match → fold best-effort).\n\
|
|
5
|
+
"description": "Per-RunEventType payload schemas. The base RunEventDoc shape (run-event.schema.json) leaves `payload` permissive for forward-compat. This schema defines the canonical payload contract for each known RunEventType. Consumers MAY pin strict payload validation via `$defs.<typeId>` and `ajv.validate(schema.$defs[event.type], event.payload)`. Unknown event types MUST be tolerated (no $defs match → fold best-effort).\n\n50 variants from `run-event.schema.json#$defs.RunEventType` are covered, grouped into ~20 shape families with shared $defs. Naming convention: camelCase keys mirror dotted RunEventType names (e.g., `run.started` → `runStarted`).",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"$defs": {
|
|
8
8
|
"_typeIndex": {
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"lease.handed-off": { "$ref": "#/$defs/leaseHandedOff" },
|
|
50
50
|
"replay.diverged": { "$ref": "#/$defs/replayDiverged" },
|
|
51
51
|
"agent.reasoned": { "$ref": "#/$defs/agentReasoned" },
|
|
52
|
+
"agent.reasoning.delta": { "$ref": "#/$defs/agentReasoningDelta" },
|
|
53
|
+
"provider.usage": { "$ref": "#/$defs/providerUsage" },
|
|
52
54
|
"agent.toolCalled": { "$ref": "#/$defs/agentToolCalled" },
|
|
53
55
|
"agent.toolReturned": { "$ref": "#/$defs/agentToolReturned" },
|
|
54
56
|
"agent.handoff": { "$ref": "#/$defs/agentHandoff" },
|
|
@@ -564,6 +566,38 @@
|
|
|
564
566
|
"additionalProperties": true
|
|
565
567
|
},
|
|
566
568
|
|
|
569
|
+
"agentReasoningDelta": {
|
|
570
|
+
"type": "object",
|
|
571
|
+
"description": "RFC 0024. Incremental reasoning chunk for live-streaming UX. Emitted while a reasoning block is still open, BEFORE the corresponding `agent.reasoned` finalization. Consumers concatenate `delta` strings in arrival order to reconstruct the in-progress trace; the closing `agent.reasoned` event carries the FULL authoritative `reasoning`. Gated on `capabilities.agents.reasoning.streaming: true`. NOTE: `additionalProperties: true` mirrors the Phase-1 multi-agent-shift carve-out applied to the sibling `agentReasoned` schema — a deliberate forward-compat exception per RFC 0024 §Compatibility, not a precedent generalizable to other event payloads.",
|
|
572
|
+
"required": ["agentId", "delta", "sequence"],
|
|
573
|
+
"properties": {
|
|
574
|
+
"agentId": { "type": "string", "minLength": 3, "maxLength": 256, "description": "AgentRef.agentId of the reasoning agent. MUST match the eventual closing `agent.reasoned`." },
|
|
575
|
+
"delta": { "type": "string", "description": "New reasoning content since the previous delta event in this block (or since block open, if `sequence` is 0)." },
|
|
576
|
+
"sequence": { "type": "integer", "minimum": 0, "description": "Monotonically-increasing index within the current reasoning block. Starts at 0 for the first delta in a block; resets at each new block open. Consumers MAY use this to detect dropped events." },
|
|
577
|
+
"verbosity": { "type": "string", "enum": ["summary", "full", "off"], "description": "Verbosity mode the host resolved for this block. SHOULD match the verbosity reported on the closing `agent.reasoned`." }
|
|
578
|
+
},
|
|
579
|
+
"additionalProperties": true
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
"providerUsage": {
|
|
583
|
+
"type": "object",
|
|
584
|
+
"description": "RFC 0026. Per-call usage record emitted after every LLM provider invocation. Durably persisted in the run event log; consumed by replay, webhook subscribers, billing reconciliation. The OTel `openwop.cost.*` attribute group (per `observability.md §\"Cost attribution attributes\"`) is the observability sibling — this event type is the durable record. Replay determinism: `inputTokens` + `outputTokens` MUST replay identically; `costEstimateUsd` MAY be omitted on replay. The payload MUST NOT carry credentialRefs, hashed credential identifiers, or prompt/response substrings per `SECURITY/threat-model-secret-leakage.md §SR-1` (enforced by SECURITY invariant `provider-usage-no-credential-leak`).",
|
|
585
|
+
"required": ["provider", "model", "inputTokens", "outputTokens"],
|
|
586
|
+
"properties": {
|
|
587
|
+
"provider": { "type": "string", "minLength": 1, "description": "Canonical provider id (lowercase ASCII, e.g. \"anthropic\", \"openai\", \"google\"). Same value as the `openwop.cost.provider` OTel attribute." },
|
|
588
|
+
"model": { "type": "string", "minLength": 1, "description": "Provider-stamped model id as the model expects it. Same value used in the LLM cache-key recipe per `replay.md §A`." },
|
|
589
|
+
"inputTokens": { "type": "integer", "minimum": 0, "description": "Input/prompt tokens billed for this call. Matches the provider response's input-token count verbatim." },
|
|
590
|
+
"outputTokens": { "type": "integer", "minimum": 0, "description": "Output/completion tokens billed for this call. Matches the provider response's output-token count verbatim." },
|
|
591
|
+
"totalTokens": { "type": "integer", "minimum": 0, "description": "Convenience sum (inputTokens + outputTokens). Consumers MAY compute themselves; emitters MAY include for readability." },
|
|
592
|
+
"costEstimateUsd": { "type": "number", "minimum": 0, "description": "ADVISORY estimate in USD computed by the host's static rate table. MUST NOT be used for billing — real billing is external. Hosts SHOULD omit when no rate is known rather than emit 0." },
|
|
593
|
+
"currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "ISO 4217 code when `costEstimateUsd` is non-USD; the field name stays `costEstimateUsd` for back-compat but `currency` overrides the implied denomination." },
|
|
594
|
+
"cacheHit": { "type": "boolean", "description": "True iff this call was served from the LLM response cache per `replay.md §\"LLM cache-key recipe\"`. When true, inputTokens/outputTokens reflect the ORIGINAL call's billed values; the cached invocation incurred zero new provider cost." },
|
|
595
|
+
"nodeId": { "type": "string", "description": "The node id that initiated the provider call. Required for per-node cost attribution dashboards." },
|
|
596
|
+
"traceId": { "type": "string", "description": "OTel trace id linking this event to the matching `openwop.cost.*` span. Lets observability backends correlate event-log entries with traces." }
|
|
597
|
+
},
|
|
598
|
+
"additionalProperties": false
|
|
599
|
+
},
|
|
600
|
+
|
|
567
601
|
"agentToolCalled": {
|
|
568
602
|
"type": "object",
|
|
569
603
|
"description": "Multi-Agent Shift Phase 1. Emitted when an agent invokes a tool. Pairs with `agent.toolReturned` via shared `callId`.",
|
package/src/lib/driver.ts
CHANGED
|
@@ -78,6 +78,21 @@ class OpenWOPDriver {
|
|
|
78
78
|
return this.request('POST', path, { ...init, body });
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/** PUT helper. The body is JSON-stringified by default; pass a string
|
|
82
|
+
* Content-Type header for raw-body PUTs (e.g. tarball uploads).
|
|
83
|
+
* Production hosts that accept tarball PUTs on /v1/packs/* expect
|
|
84
|
+
* `Content-Type: application/octet-stream`; callers MUST set the
|
|
85
|
+
* header explicitly when uploading non-JSON. */
|
|
86
|
+
put(path: string, body: unknown, init: OpenWOPRequestInit = {}): Promise<OpenWOPResponse> {
|
|
87
|
+
return this.request('PUT', path, { ...init, body });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** DELETE alias for the canonical name. Keeps the call-site shorter
|
|
91
|
+
* for scenarios that delete via `driver.del(...)`. */
|
|
92
|
+
del(path: string, init: OpenWOPRequestInit = {}): Promise<OpenWOPResponse> {
|
|
93
|
+
return this.request('DELETE', path, init);
|
|
94
|
+
}
|
|
95
|
+
|
|
81
96
|
delete(path: string, init: OpenWOPRequestInit = {}): Promise<OpenWOPResponse> {
|
|
82
97
|
return this.request('DELETE', path, init);
|
|
83
98
|
}
|