@openwop/openwop-conformance 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +91 -1
  2. package/README.md +3 -2
  3. package/api/asyncapi.yaml +8 -0
  4. package/api/openapi.yaml +371 -1
  5. package/coverage.md +25 -5
  6. package/fixtures/conformance-envelope-nl-to-format-engaged.json +41 -0
  7. package/fixtures/conformance-envelope-recovery-applied.json +39 -0
  8. package/fixtures/conformance-envelope-refusal.json +38 -0
  9. package/fixtures/conformance-envelope-retry-attempted.json +39 -0
  10. package/fixtures/conformance-envelope-retry-exhausted.json +38 -0
  11. package/fixtures/conformance-envelope-truncated.json +39 -0
  12. package/fixtures/conformance-envelope-truncation-cap-exhaustion.json +39 -0
  13. package/fixtures/conformance-model-capability-insufficient.json +25 -0
  14. package/fixtures/conformance-multi-agent-confidence-escalation.json +49 -0
  15. package/fixtures/conformance-multi-agent-handoff-child.json +27 -0
  16. package/fixtures/conformance-multi-agent-handoff.json +49 -0
  17. package/fixtures/conformance-prompt-all-four-kinds.json +39 -0
  18. package/fixtures/conformance-prompt-end-to-end.json +33 -0
  19. package/fixtures/conformance-subworkflow-mid-run-mutation-child.json +31 -0
  20. package/fixtures/conformance-subworkflow-mid-run-mutation.json +33 -0
  21. package/fixtures/openwop-smoke-cost-emit.json +37 -0
  22. package/fixtures/prompt-templates/conformance-prompt-few-shot-2.json +14 -0
  23. package/fixtures/prompt-templates/conformance-prompt-few-shot.json +14 -0
  24. package/fixtures/prompt-templates/conformance-prompt-schema-hint.json +14 -0
  25. package/fixtures/prompt-templates/conformance-prompt-secret-redaction.json +23 -0
  26. package/fixtures/prompt-templates/conformance-prompt-trust-marker.json +23 -0
  27. package/fixtures/prompt-templates/conformance-prompt-writer-system.json +15 -0
  28. package/fixtures/prompt-templates/conformance-prompt-writer-user.json +15 -0
  29. package/fixtures.md +39 -0
  30. package/package.json +1 -1
  31. package/schemas/README.md +5 -0
  32. package/schemas/agent-manifest.schema.json +16 -0
  33. package/schemas/capabilities.schema.json +375 -1
  34. package/schemas/envelopes/clarification.request.schema.json +9 -0
  35. package/schemas/envelopes/error.schema.json +4 -0
  36. package/schemas/envelopes/schema.request.schema.json +4 -0
  37. package/schemas/envelopes/schema.response.schema.json +1 -1
  38. package/schemas/node-pack-manifest.schema.json +28 -0
  39. package/schemas/orchestrator-decision.schema.json +12 -0
  40. package/schemas/prompt-kind.schema.json +8 -0
  41. package/schemas/prompt-pack-manifest.schema.json +80 -0
  42. package/schemas/prompt-ref.schema.json +40 -0
  43. package/schemas/prompt-template.schema.json +149 -0
  44. package/schemas/registry-version-manifest.schema.json +5 -0
  45. package/schemas/run-ancestry-response.schema.json +54 -0
  46. package/schemas/run-event-payloads.schema.json +479 -11
  47. package/schemas/run-event.schema.json +15 -1
  48. package/schemas/run-snapshot.schema.json +3 -2
  49. package/schemas/workflow-definition.schema.json +19 -1
  50. package/src/lib/llm-cache-key-recipe.ts +68 -0
  51. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +104 -13
  52. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +32 -15
  53. package/src/scenarios/aiEnvelope.redaction.test.ts +6 -5
  54. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +5 -5
  55. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +211 -12
  56. package/src/scenarios/aiEnvelope.universalKinds.test.ts +7 -7
  57. package/src/scenarios/blob-presign-expiry.test.ts +7 -7
  58. package/src/scenarios/cache-ttl-expiry.test.ts +6 -6
  59. package/src/scenarios/cost-attribution.test.ts +124 -11
  60. package/src/scenarios/cross-engine-append-ordering.test.ts +99 -0
  61. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +136 -0
  62. package/src/scenarios/cross-host-causation-shape.test.ts +117 -0
  63. package/src/scenarios/cross-host-traceparent-propagation.test.ts +60 -0
  64. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +223 -0
  65. package/src/scenarios/envelope-nl-to-format-engaged.test.ts +152 -0
  66. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +343 -0
  67. package/src/scenarios/envelope-reasoning-shape.test.ts +190 -0
  68. package/src/scenarios/envelope-recovery-applied.test.ts +229 -0
  69. package/src/scenarios/envelope-refusal-shape.test.ts +289 -0
  70. package/src/scenarios/envelope-retry-attempted.test.ts +258 -0
  71. package/src/scenarios/envelope-retry-exhausted.test.ts +168 -0
  72. package/src/scenarios/envelope-tier-one-subset-static.test.ts +229 -0
  73. package/src/scenarios/envelope-truncated.test.ts +136 -0
  74. package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +144 -0
  75. package/src/scenarios/envelope-variant-discriminator-static.test.ts +152 -0
  76. package/src/scenarios/fixtures-valid.test.ts +123 -15
  77. package/src/scenarios/kv-ttl-expiry.test.ts +7 -7
  78. package/src/scenarios/model-capability-insufficient.test.ts +221 -0
  79. package/src/scenarios/model-capability-substituted.test.ts +203 -0
  80. package/src/scenarios/multi-agent-confidence-escalation.test.ts +164 -0
  81. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +167 -0
  82. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +124 -0
  83. package/src/scenarios/multi-region-idempotency.test.ts +58 -0
  84. package/src/scenarios/node-module-required-capabilities-shape.test.ts +185 -0
  85. package/src/scenarios/prompt-all-four-kinds-events.test.ts +198 -0
  86. package/src/scenarios/prompt-composed-secret-redaction.test.ts +178 -0
  87. package/src/scenarios/prompt-composed-trust-marker.test.ts +165 -0
  88. package/src/scenarios/prompt-end-to-end-events.test.ts +202 -0
  89. package/src/scenarios/prompt-list-and-fetch.test.ts +207 -0
  90. package/src/scenarios/prompt-mutable-lifecycle.test.ts +216 -0
  91. package/src/scenarios/prompt-pack-install.test.ts +187 -0
  92. package/src/scenarios/prompt-render-deterministic.test.ts +240 -0
  93. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +140 -0
  94. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +172 -0
  95. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +144 -0
  96. package/src/scenarios/prompt-template-shape.test.ts +359 -0
  97. package/src/scenarios/queue-ack-nack-dlq.test.ts +7 -7
  98. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +7 -7
  99. package/src/scenarios/replay-divergence-at-refusal.test.ts +134 -0
  100. package/src/scenarios/replay-llm-cache-key-portable.test.ts +197 -0
  101. package/src/scenarios/replay-llm-cache-key.test.ts +1 -40
  102. package/src/scenarios/replay-observable-sequence-determinism.test.ts +80 -0
  103. package/src/scenarios/sandbox-capability-gate-respected.test.ts +31 -0
  104. package/src/scenarios/sandbox-memory-cap.test.ts +61 -0
  105. package/src/scenarios/sandbox-no-cross-pack-mutation.test.ts +35 -0
  106. package/src/scenarios/sandbox-no-host-env-leak.test.ts +38 -0
  107. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +91 -0
  108. package/src/scenarios/sandbox-no-host-process-escape.test.ts +30 -0
  109. package/src/scenarios/sandbox-no-network-escape.test.ts +49 -0
  110. package/src/scenarios/sandbox-timeout-cap.test.ts +61 -0
  111. package/src/scenarios/search-bm25-roundtrip.test.ts +7 -7
  112. package/src/scenarios/spec-corpus-validity.test.ts +34 -6
  113. package/src/scenarios/sql-transaction-atomicity.test.ts +6 -6
  114. package/src/scenarios/stream-subscribe-from-beginning.test.ts +7 -7
  115. package/src/scenarios/subworkflow-input-mapping.test.ts +70 -4
  116. package/src/scenarios/table-cursor-pagination.test.ts +7 -7
  117. package/src/scenarios/table-schema-enforcement.test.ts +7 -7
  118. package/src/scenarios/vector-knn-roundtrip.test.ts +7 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,95 @@
1
1
  # `@openwop/openwop-conformance` Changelog
2
2
 
3
+ ## [1.4.0] — 2026-05-22
4
+
5
+ Minor bump per `PUBLISHING.md` §"Versioning alignment" — bundles 45 new conformance scenarios + 23 new fixtures landing since the 1.3.0 publish (2026-05-19). Unblocks non-steward host adoption of RFCs 0027 + 0028 + 0029 + 0030 + 0031 + 0032 + 0033 + 0034 + 0035 + 0036 + 0037 + 0039 + 0040 + 0041 against a single suite version.
6
+
7
+ ### Added — RFC 0030-0033 envelope LLM-contract-hardening (Accepted 2026-05-21)
8
+
9
+ 12 new scenarios + 7 new fixtures covering the envelope-reliability surface:
10
+ - **Reasoning** — `envelope-reasoning-shape.test.ts` (always-on; OPTIONAL `reasoning` property on the 3 universal-kind schemas), `envelope-reasoning-secret-redaction.test.ts` (RFC 0034 OTel-seam-gated; SR-1 redaction probe).
11
+ - **Tier-1 subset** — `envelope-tier-one-subset-static.test.ts` (always-on for the no-`oneOf`/`allOf`/`not`/`prefixItems`/`propertyNames` rule; strict-mode gated for OpenAI-only constraints).
12
+ - **Variant discriminator** — `envelope-variant-discriminator-static.test.ts` (always-on; every `anyOf` branch declares a single-string-enum discriminator in `required`).
13
+ - **Model capability gating** — `model-capability-substituted.test.ts` (advertisement-shape probe on `capabilities.modelCapabilities.advertised[]`), `model-capability-insufficient.test.ts`, `node-module-required-capabilities-shape.test.ts`.
14
+ - **Envelope reliability events** — `envelope-retry-attempted.test.ts` (shared advertisement-shape probe for both MUST-tier events per RFC 0032 §C), `envelope-retry-exhausted.test.ts`, `envelope-refusal-shape.test.ts`, `envelope-truncated.test.ts`, `envelope-nl-to-format-engaged.test.ts`, `envelope-recovery-applied.test.ts`. Paired with SECURITY invariants `envelope-refusal-no-prompt-leak` + `envelope-recovery-no-content-leak`.
15
+ - **RFC 0033 truncation-vs-schema-violation** — `envelope-completion-distinguishes-truncation.test.ts`, `envelope-truncation-cap-exhaustion.test.ts`.
16
+
17
+ Fixtures: `conformance-envelope-{retry-attempted, retry-exhausted, refusal, truncated, truncation-cap-exhaustion, nl-to-format-engaged, recovery-applied}.json`.
18
+
19
+ ### Added — RFC 0027 + 0028 + 0029 prompts track (Active; path-to-Accepted is non-steward adoption)
20
+
21
+ 11 new scenarios + 9 new fixtures covering the prompts surface:
22
+ - **Wire shape (RFC 0027)** — `prompt-template-shape.test.ts` (always-on Ajv compile + round-trip), `prompt-composed-secret-redaction.test.ts` (capability-gated SR-1 probe), `prompt-composed-trust-marker.test.ts` (RFC 0020 §D `<UNTRUSTED>...</UNTRUSTED>` propagation), `prompt-all-four-kinds-events.test.ts` (system/user/schema-hint/few-shot end-to-end), `prompt-end-to-end-events.test.ts` (full prompt lifecycle through `core.openwop.local.sample.demo.mock-ai`).
23
+ - **Library endpoints (RFC 0028)** — `prompt-list-and-fetch.test.ts` (`GET /v1/prompts` + `GET /v1/prompts/:templateId`), `prompt-mutable-lifecycle.test.ts` (`POST`/`PATCH`/`DELETE`), `prompt-render-deterministic.test.ts` (`POST /v1/prompts/:templateId:render` deterministic output), `prompt-pack-install.test.ts` (`kind: "prompt"` pack boot-time install + `?source=pack` filter).
24
+ - **Resolution chain (RFC 0029)** — `prompt-resolution-chain-node-wins.test.ts` (layer 1 supersedes 2-4), `prompt-resolution-chain-agent-intrinsic.test.ts` (layer 2 wins when no layer 1), `prompt-resolution-chain-fallback-cascade.test.ts` (layer 3 → 4 → null cascade; chain[] always lists every attempted layer).
25
+
26
+ Fixtures: `conformance-prompt-{all-four-kinds, end-to-end}.json` plus the per-template directory at `fixtures/prompt-templates/` (`conformance-prompt-{writer-system, writer-user, schema-hint, few-shot, few-shot-2, secret-redaction, trust-marker}.json`).
27
+
28
+ ### Added — RFC 0035 sandbox execution contract (Active; reference-impl-tier today, protocol-tier on first sandbox host)
29
+
30
+ 8 new scenarios — one per failure-mode invariant in `host-capabilities.md` §"Sandbox execution contract (RFC 0035)":
31
+ - `sandbox-capability-gate-respected.test.ts` — `sandbox_capability_denied` envelope when a sandbox call hits a capability not in `allowedHostCalls`.
32
+ - `sandbox-memory-cap.test.ts` — `sandbox_memory_exceeded` envelope when memory cap breached.
33
+ - `sandbox-timeout-cap.test.ts` — `sandbox_timeout` envelope when wall-clock cap breached.
34
+ - `sandbox-no-cross-pack-mutation.test.ts` — sandboxed pack A cannot mutate state owned by sandboxed pack B.
35
+ - `sandbox-no-host-env-leak.test.ts` — host environment variables MUST NOT be visible inside the sandbox.
36
+ - `sandbox-no-host-fs-escape.test.ts` — `sandbox_escape_attempt` with `escapeKind: "host-fs-escape"` envelope.
37
+ - `sandbox-no-host-process-escape.test.ts` — `sandbox_escape_attempt` with `escapeKind: "host-process-escape"` envelope.
38
+ - `sandbox-no-network-escape.test.ts` — sandboxed code MUST NOT egress to networks not in `allowedHostCalls`.
39
+
40
+ (Canonical scenario naming is `sandbox-*`; RFC 0035 prose that names them `node-pack-sandbox-*` will reconcile in a follow-up edit.)
41
+
42
+ ### Added — RFC 0036 multi-region + cross-engine ordering (Active; path-to-Accepted is Postgres-host simulator + non-steward host)
43
+
44
+ 1 new scenario:
45
+ - `cross-engine-append-ordering.test.ts` — capability-gated on `eventLog.crossEngineOrdering.supported: true`; asserts append-ordering invariants across `core.engine.append` calls from concurrent engines.
46
+
47
+ (`multi-region-idempotency.test.ts` remains shape-only pending multi-region simulator or deployment; tracked in `docs/KNOWN-LIMITS.md`.)
48
+
49
+ ### Added — RFC 0037 multi-agent execution model Phase 1 (Active; reference workflow-engine advertises)
50
+
51
+ 1 new scenario + 2 fixtures:
52
+ - `multi-agent-handoff-state-machine.test.ts` — advertisement-shape probe (always-on) + behavioral assertion (capability-gated on `multiAgent.executionModel.supported: true`) covering the 7 handoff state-machine transition events with chained `causationId`.
53
+
54
+ Fixtures: `conformance-multi-agent-handoff.json` (parent workflow) + `conformance-multi-agent-handoff-child.json` (child workflow). Reference workflow-engine advertises under `OPENWOP_MULTI_AGENT_EXECUTION_MODEL=true`.
55
+
56
+ ### Added — RFC 0039 multi-agent Phase 2 (confidence + memory lifecycle; Active)
57
+
58
+ 2 new scenarios + 1 fixture:
59
+ - `multi-agent-confidence-escalation.test.ts` — gated on `multiAgent.executionModel.version >= 2`; asserts decisions with `confidence < confidenceEscalationFloor` MUST emit `core.workflowChain.confidence-escalated` event + suspend with `interrupt.kind: 'clarification'` + NOT execute the worker dispatch.
60
+ - `multi-agent-memory-lifecycle.test.ts` — advertisement-shape probe + 2 `it.todo` behavioral assertions for MAE-2 cross-run TTL + MAE-3 replay snapshot (lights up when a memory-advertising Phase 2 host wires the test seam).
61
+
62
+ Fixture: `conformance-multi-agent-confidence-escalation.json`.
63
+
64
+ ### Added — RFC 0040 multi-agent Phase 3 (cross-host causation; Active)
65
+
66
+ 3 new scenarios:
67
+ - `cross-host-causation-shape.test.ts` — always-on when discovery reachable; asserts the shape of `multiAgent.executionModel.crossHostCausation.{supported, hostId, ancestryEndpointSupported}` + `version >= 3` when advertised.
68
+ - `cross-host-ancestry-endpoint.test.ts` — capability-gated on `crossHostCausation.ancestryEndpointSupported: true`; covers `GET /v1/runs/{runId}/ancestry` top-level-run path (`parent: null`) + the 404 contract when the capability is not advertised.
69
+ - `cross-host-traceparent-propagation.test.ts` — capability-gated behavioral; 2 `it.todo` assertions for outbound MCP + A2A `traceparent` injection (lights up when `OPENWOP_MCP_REAL_SERVER_URL` / `OPENWOP_A2A_REAL_PEER_URL` env harness ships).
70
+
71
+ ### Added — RFC 0041 multi-agent Phase 4 (replay determinism; Active)
72
+
73
+ 3 new scenarios:
74
+ - `replay-llm-cache-key-portable.test.ts` — RFC 0041 §E SECURITY-invariant probe (intra-host reproducibility + non-recipe-field invariance + Phase 4 advertisement alignment). Reuses the existing `POST /v1/host/sample/test/llm-cache-key` seam from `replay-llm-cache-key.test.ts`.
75
+ - `replay-divergence-at-refusal.test.ts` — advertisement-shape probe + 2 `it.todo` for the dual-direction refusal-divergence case (original=valid + replay=refusal AND original=refusal + replay=valid).
76
+ - `replay-observable-sequence-determinism.test.ts` — 2 `it.todo` for §C boundary byte-equivalence + observable-result caching (lights up when a `conformance-phase4-nondet-tool` fixture ships).
77
+
78
+ ### Changed
79
+
80
+ - `conformance/coverage.md` updated with the 45 new scenarios mapped to RFC + invariant tier.
81
+ - `conformance/fixtures.md` catalog updated with the 23 new fixture rows + per-fixture contracts.
82
+ - Shared helper extraction: `conformance/src/lib/llm-cache-key-recipe.ts` exports `canonicalize`, `projectRecipe`, `expectedCacheKey`, `callCacheKeySeam` — consumed by both `replay-llm-cache-key.test.ts` (existing) and `replay-llm-cache-key-portable.test.ts` (new).
83
+
84
+ ### Fixed
85
+
86
+ - `replay-llm-cache-key-portable.test.ts` Phase 4 advertisement-alignment test guards against `undefined < 4 === false` fall-through (`typeof version !== 'number'` check before comparison).
87
+ - Soft-skip patterns across the new Phase 4 + RFC 0040 scenarios converted from bare `return` to `ctx.skip()` so test reporters surface skipped capability gates as `skipped` rather than vacuous `passed`.
88
+
89
+ ### Known limits (light up when host wires the matching test seam)
90
+
91
+ - 6 `it.todo` behavioral assertions across the RFC 0034 OTel-seam-gated, RFC 0040 traceparent-propagation, RFC 0041 refusal-divergence + observable-sequence scenarios. All scenarios soft-skip cleanly when their gating capability is unset.
92
+
3
93
  ## [1.3.0] — 2026-05-19
4
94
 
5
95
  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.
@@ -88,7 +178,7 @@ Strictly additive at the scenario level; the causationId tightening is a behavio
88
178
  ### Notes
89
179
 
90
180
  - `@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."
91
- - 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.
181
+ - 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. (**Closed in 1.3.0 (2026-05-19)** — all deferred cases promoted to live behavioral tests; see the 1.3.0 entries for "RFC 0022 §C variable-mapping refusal contract", "Thread C: child-lifecycle fixtures", and "Driver helpers + opt-out axes" above.)
92
182
 
93
183
  ## [1.0.0] — 2026-05-10
94
184
 
package/README.md CHANGED
@@ -85,6 +85,7 @@ Run `npm run test` for normal CI cadence; `npm run test:strict` when claiming fu
85
85
  | `OPENWOP_A2A_FAKE_PEER=true` | Boots the synthetic A2A peer for `a2a-task-roundtrip.test.ts`. |
86
86
  | `OPENWOP_A2A_REAL_PEER_URL=<base-url>` | Points the A2A AgentCard + task-lifecycle probe at a real reference A2A peer. Drift-point subtests (AUTH_REQUIRED / REJECTED) stay fake-peer-only — real peers don't expose a state-forcing API. Phase 3 T3.4 interop-evidence path. |
87
87
  | `OPENWOP_FORCE_RATE_LIMIT=true` | Signals the host (test-only key) to fabricate a 429 so `rate-limit-envelope.test.ts` can exercise envelope shape deterministically. |
88
+ | `OPENWOP_TEST_PROMPT_PACK_INSTALLED=true` | Promotes the `prompt-pack-install.test.ts` existence claim from soft-skip to hard assertion (RFC 0028 §B). Set when the target host is known to have at least one prompt pack installed at boot — RFC 0028 §B does NOT require any host with `endpointsSupported: true` to have packs installed, so the suite stays conformant against a fresh production host with no pack subscriptions when the flag is unset. The in-tree workflow-engine sample auto-installs `vendor.openwop.prompt-sample` via `promptPackLoader.ts`, so operators running against it should set the flag. |
88
89
 
89
90
  Exit code is non-zero on any failed assertion.
90
91
 
@@ -92,7 +93,7 @@ Exit code is non-zero on any failed assertion.
92
93
 
93
94
  ## What's Covered
94
95
 
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
+ The current suite has 205 scenario files under `src/scenarios/`. 2026-05-22 (RFC 0041 Phase 4 — replay determinism under nondeterministic models) added three scenarios: `replay-divergence-at-refusal.test.ts` (advertisement-shape probe on `replayDeterminism.refusalDivergenceEmission` + 2 `it.todo` for the dual-direction refusal-divergence case), `replay-observable-sequence-determinism.test.ts` (capability-gated; behavioral assertion soft-skipped until a `conformance-phase4-nondet-tool` fixture ships), `replay-llm-cache-key-portable.test.ts` (intra-host reproducibility + non-recipe-field invariance + Phase 4 advertisement alignment — reuses the existing `POST /v1/host/sample/test/llm-cache-key` seam from the sibling `replay-llm-cache-key.test.ts`). 2026-05-20 (RFC 0027 §A templateKinds-coverage follow-up — paired with `prompt-end-to-end-events.test.ts`) added `prompt-all-four-kinds-events.test.ts` exercising all four `PromptKind` values (`system`, `user`, `schema-hint`, `few-shot`) end-to-end through the reference workflow-engine sample's `local.sample.demo.mock-ai` dispatch path; capability-gated via `behaviorGate('prompts-supported', ...)`. Closes the credibility gap where the host advertised `templateKinds: ["system", "user", "few-shot", "schema-hint"]` but only the system+user pair was actually wired into dispatch. 2026-05-20 (RFCs 0030–0033 — envelope LLM-contract-hardening track) added 15 scenarios across four `Active` RFCs: `envelope-reasoning-shape.test.ts` (RFC 0030, always-on; asserts the OPTIONAL `reasoning` property on the three universal-kind schemas + the `schema.response` deliberate omission), `envelope-reasoning-secret-redaction.test.ts` (RFC 0030, capability-gated on `capabilities.envelopes.reasoning.supported` + `secrets.supported`; 5 `it.todo()` placeholders for SECURITY invariant `envelope-reasoning-secret-redaction`), `envelope-tier-one-subset-static.test.ts` (RFC 0030, always-on for load-bearing rules — no `oneOf` / `allOf` / `not` / `prefixItems` / `propertyNames` anywhere; gated on `tierOneSubsetCompliance: "strict"` for OpenAI-strict-only constraints), `envelope-variant-discriminator-static.test.ts` (RFC 0031, always-on; asserts no `oneOf` + every `anyOf` branch declares a single-string-enum discriminator in `required` on every `schemas/envelopes/*.schema.json`), `model-capability-substituted.test.ts` (RFC 0031, advertisement-shape probe on `capabilities.modelCapabilities.advertised[]` identifier pattern + 5 `it.todo()` placeholders for SECURITY invariant `model-capability-substituted-no-credential-disclosure`), `model-capability-insufficient.test.ts` (RFC 0031, 6 `it.todo()` placeholders for refusal + no-recursive-fallback), `node-module-required-capabilities-shape.test.ts` (RFC 0031 SHOULD-tier authoring-convention; 4 `it.todo()` placeholders), and the six envelope-reliability events from RFC 0032 (`envelope-retry-attempted` carrying the shared advertisement-shape probe enforcing both MUST-tier events in `events[]` per RFC 0032 §C, plus `envelope-retry-exhausted`, `envelope-refusal-shape`, `envelope-truncated`, `envelope-nl-to-format-engaged`, `envelope-recovery-applied` — collectively 39 `it.todo()` placeholders covering retry/refusal/truncation/recovery + SECURITY invariants `envelope-refusal-no-prompt-leak` and `envelope-recovery-no-content-leak`), plus RFC 0033's two scenarios (`envelope-completion-distinguishes-truncation.test.ts` + `envelope-truncation-cap-exhaustion.test.ts` — 12 `it.todo()` placeholders covering the truncation-vs-schema-violation retry-routing distinction + the DoS-bound assertion). Reference workflow-engine sample advertises `capabilities.envelopes.reasoning: { supported: true, promptDirective: "off" }` + `tierOneSubsetCompliance: "warn"` honestly (schemas accept the field; host doesn't yet inject the directive); the other three RFCs' capability blocks defer to reference-host emission code per the staged RFC 0027 §G precedent. 2026-05-20 (RFC 0028 §B Phase B — prompt-pack boot-time install) added `prompt-pack-install.test.ts` (capability-gated on `capabilities.prompts.endpointsSupported: true`; asserts a host that ran the boot-time pack loader surfaces ≥ 1 pack-source template under `GET /v1/prompts?source=pack` carrying the canonical `meta.source: "pack"` + `meta.packName` + `meta.packVersion` stamps; positively identifies the in-tree `vendor.openwop.prompt-sample` reference pack's `writer-system` template when present). Pairs with the new `host/promptPackLoader.ts` boot-time entry on the reference workflow-engine sample, which scans `examples/packs/*` plus `OPENWOP_PROMPT_PACKS_DIR` and calls `installPackTemplates()` for each `kind: "prompt"` pack found. 2026-05-20 (RFC 0029 Phase C — prompt resolution chain wire shape) added three more scenarios: `prompt-resolution-chain-node-wins.test.ts` (capability-gated on `capabilities.prompts.supported: true`; asserts layer-1 node-config supersedes lower layers per `spec/v1/prompts.md` §"Resolution chain (normative)"), `prompt-resolution-chain-agent-intrinsic.test.ts` (additionally gated on `capabilities.prompts.agentBindings: true`; asserts agent intrinsic `systemPromptRef` wins over `promptOverrides` AND lower layers when the node has no layer-1 ref), `prompt-resolution-chain-fallback-cascade.test.ts` (asserts layer 3 workflow-defaults wins over layer 4 host-defaults; layer 4 host-defaults wins when 1-3 yield null; resolved is null when all four yield null but chain[] still lists every attempted layer). The scenarios drive the host's `POST /v1/host/sample/prompt/resolve` test seam (reference-host implementation deferred to follow-up slice per RFC 0021 staging precedent). 2026-05-20 (RFC 0027 Phase A — prompt templates wire shape) added three scenarios: `prompt-template-shape.test.ts` (always-on; Ajv compileability + positive/negative round-trip for PromptTemplate + PromptRef + PromptKind), `prompt-composed-secret-redaction.test.ts` (capability-gated on `capabilities.prompts.supported: true` + `observability: "full"`; asserts `[REDACTED:<secretId>]` markers in `prompt.composed` payloads for `source: "secret"` variable bindings per SECURITY/threat-model-secret-leakage.md §SR-1), `prompt-composed-trust-marker.test.ts` (same capability gates; asserts `<UNTRUSTED>...</UNTRUSTED>` wrapping + `contentTrust: "untrusted"` propagation per RFC 0020 §D). Paired with new `fixtures/prompt-templates/` sub-directory + per-fixture schema-validity describe block + future SECURITY invariants `prompt-composed-secret-redaction` and `prompt-composed-trust-marker` (lands alongside reference-host emission per RFC 0021 staging precedent). 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
97
 
97
98
  High-level coverage includes:
98
99
 
@@ -171,7 +172,7 @@ Server-required (added in 1.7.0):
171
172
  |---|---|---|
172
173
  | **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
174
 
174
- Current source tree: 160 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
175
+ Current source tree: 205 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
175
176
 
176
177
  ## Remaining Gaps
177
178
 
package/api/asyncapi.yaml CHANGED
@@ -83,6 +83,7 @@ channels:
83
83
  nodeFailed: { $ref: '#/components/messages/NodeFailed' }
84
84
  nodeSkipped: { $ref: '#/components/messages/NodeSkipped' }
85
85
  nodeSuspended: { $ref: '#/components/messages/NodeSuspended' }
86
+ nodeDispatched: { $ref: '#/components/messages/NodeDispatched' }
86
87
  approvalRequested: { $ref: '#/components/messages/ApprovalRequested' }
87
88
  approvalReceived: { $ref: '#/components/messages/ApprovalReceived' }
88
89
  clarificationRequested: { $ref: '#/components/messages/ClarificationRequested' }
@@ -338,6 +339,13 @@ components:
338
339
  payload:
339
340
  $ref: '#/components/schemas/RunEventDoc'
340
341
 
342
+ NodeDispatched:
343
+ name: node.dispatched
344
+ title: core.dispatch spawned a child workflow (RFC 0007 §D + RFC 0022 §A)
345
+ contentType: application/json
346
+ payload:
347
+ $ref: '#/components/schemas/RunEventDoc'
348
+
341
349
  # ── HITL ─────────────────────────────────────────────────────────────
342
350
  ApprovalRequested:
343
351
  name: approval.requested
package/api/openapi.yaml CHANGED
@@ -59,6 +59,8 @@ tags:
59
59
  description: Subscribe to run events via outbound HTTP.
60
60
  - name: audit
61
61
  description: Audit-log integrity verification (gated on the `openwop-audit-log-integrity` profile).
62
+ - name: prompts
63
+ description: Prompt-template library — list, fetch, render, mutate (RFC 0028; gated on `capabilities.prompts.*`).
62
64
 
63
65
  # ─────────────────────────────────────────────────────────────────────────────
64
66
  # PATHS
@@ -200,7 +202,7 @@ paths:
200
202
  runId: { type: string }
201
203
  status:
202
204
  type: string
203
- enum: [pending, running, waiting-approval, waiting-input]
205
+ enum: [pending, running, waiting-approval, waiting-input, waiting-external]
204
206
  eventsUrl: { type: string, format: uri }
205
207
  statusUrl: { type: string, format: uri }
206
208
  '400': { $ref: '#/components/responses/ValidationError' }
@@ -467,6 +469,38 @@ paths:
467
469
  content:
468
470
  application/json:
469
471
  schema: { $ref: '#/components/schemas/Error' }
472
+ /v1/runs/{runId}/ancestry:
473
+ get:
474
+ tags: [runs]
475
+ summary: |
476
+ RFC 0040 §C — return the run's immediate parent in the cross-host
477
+ composition chain. Capability-gated on
478
+ `capabilities.multiAgent.executionModel.crossHostCausation.ancestryEndpointSupported: true`;
479
+ hosts that don't advertise return 404 not_found. Clients walk the full
480
+ chain by following `parent.wellKnownUrl` per response, one hop at a
481
+ time.
482
+ operationId: getRunAncestry
483
+ parameters:
484
+ - $ref: '#/components/parameters/RunId'
485
+ responses:
486
+ '200':
487
+ description: |
488
+ Run's immediate parent (or `parent: null` for top-level runs).
489
+ content:
490
+ application/json:
491
+ schema:
492
+ $ref: '../schemas/run-ancestry-response.schema.json'
493
+ '401': { $ref: '#/components/responses/Unauthenticated' }
494
+ '403': { $ref: '#/components/responses/Forbidden' }
495
+ '404':
496
+ description: |
497
+ Either the run doesn't exist, OR the host doesn't advertise
498
+ `crossHostCausation.ancestryEndpointSupported: true` and treats
499
+ the endpoint as absent. Clients can disambiguate by inspecting
500
+ the host's discovery doc.
501
+ content:
502
+ application/json:
503
+ schema: { $ref: '#/components/schemas/Error' }
470
504
 
471
505
  /v1/runs/{runId}:pause:
472
506
  post:
@@ -790,6 +824,328 @@ paths:
790
824
  schema:
791
825
  $ref: '../schemas/error-envelope.schema.json'
792
826
 
827
+ # ── Prompt library (RFC 0028) ────────────────────────────────────────
828
+ # Surface gated on `capabilities.prompts.supported: true`. Mutating
829
+ # endpoints (POST / PUT / DELETE) are additionally gated on
830
+ # `capabilities.prompts.mutableLibrary: true`. Hosts without the
831
+ # advertised capability return `501 capability_not_provided`.
832
+ /v1/prompts:
833
+ get:
834
+ tags: [prompts]
835
+ summary: List prompt templates available to the caller.
836
+ operationId: listPromptTemplates
837
+ parameters:
838
+ - in: query
839
+ name: kind
840
+ schema: { type: string, enum: [system, user, few-shot, schema-hint] }
841
+ description: Filter by `PromptTemplate.kind`.
842
+ - in: query
843
+ name: tag
844
+ schema: { type: string }
845
+ description: |
846
+ Filter to templates whose `tags[]` contains this exact tag.
847
+ Hosts MAY accept the parameter multiple times; the semantic
848
+ when repeated is AND (every named tag must be present).
849
+ - in: query
850
+ name: modelClass
851
+ schema: { type: string }
852
+ description: Filter to templates whose `modelHints.modelClass` matches.
853
+ - in: query
854
+ name: source
855
+ schema: { type: string, enum: [host, pack, user] }
856
+ description: Filter by `meta.source` provenance.
857
+ - in: query
858
+ name: cursor
859
+ schema: { type: string }
860
+ description: Opaque pagination cursor.
861
+ - in: query
862
+ name: limit
863
+ schema: { type: integer, minimum: 1, maximum: 200, default: 50 }
864
+ description: Maximum entries per page.
865
+ responses:
866
+ '200':
867
+ description: Paginated list of templates.
868
+ content:
869
+ application/json:
870
+ schema:
871
+ type: object
872
+ required: [items]
873
+ properties:
874
+ items:
875
+ type: array
876
+ items:
877
+ $ref: '../schemas/prompt-template.schema.json'
878
+ nextCursor:
879
+ type: string
880
+ description: Opaque cursor; absent on the final page.
881
+ '401': { $ref: '#/components/responses/Unauthenticated' }
882
+ '403': { $ref: '#/components/responses/Forbidden' }
883
+ '501':
884
+ description: 'Host does not advertise capabilities.prompts.endpointsSupported. (RFC 0028 §A — supported gates Phase A node-execution composition; endpointsSupported gates this REST surface independently.)'
885
+ content:
886
+ application/json:
887
+ schema:
888
+ $ref: '../schemas/error-envelope.schema.json'
889
+ post:
890
+ tags: [prompts]
891
+ summary: Create a new prompt template (mutable libraries only).
892
+ operationId: createPromptTemplate
893
+ parameters:
894
+ - $ref: '#/components/parameters/IdempotencyKey'
895
+ requestBody:
896
+ required: true
897
+ content:
898
+ application/json:
899
+ schema:
900
+ $ref: '../schemas/prompt-template.schema.json'
901
+ responses:
902
+ '201':
903
+ description: Template created. `Location` header carries the canonical URI.
904
+ headers:
905
+ Location:
906
+ schema: { type: string }
907
+ description: 'Canonical URI of the new template.'
908
+ '400': { $ref: '#/components/responses/ValidationError' }
909
+ '401': { $ref: '#/components/responses/Unauthenticated' }
910
+ '403': { $ref: '#/components/responses/Forbidden' }
911
+ '409':
912
+ description: A template with this `(templateId, version)` pair already exists.
913
+ content:
914
+ application/json:
915
+ schema:
916
+ $ref: '../schemas/error-envelope.schema.json'
917
+ '501':
918
+ description: 'Host does not advertise capabilities.prompts.mutableLibrary.'
919
+ content:
920
+ application/json:
921
+ schema:
922
+ $ref: '../schemas/error-envelope.schema.json'
923
+
924
+ /v1/prompts/{templateId}:
925
+ parameters:
926
+ - in: path
927
+ name: templateId
928
+ required: true
929
+ schema:
930
+ type: string
931
+ pattern: '^[a-z0-9][a-z0-9._-]{0,127}$'
932
+ description: PromptTemplate.templateId per RFC 0027.
933
+ - in: query
934
+ name: version
935
+ schema:
936
+ type: string
937
+ pattern: '^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$'
938
+ description: Pin to a specific SemVer version; latest when omitted.
939
+ - in: query
940
+ name: libraryId
941
+ schema:
942
+ type: string
943
+ pattern: '^[a-z0-9][a-z0-9._-]{0,127}$'
944
+ description: |
945
+ Disambiguate when multiple installed packs ship the same
946
+ templateId. Hosts MUST return `prompt_ref_ambiguous` if
947
+ ambiguous and libraryId is omitted.
948
+ get:
949
+ tags: [prompts]
950
+ summary: Fetch a single prompt template.
951
+ operationId: getPromptTemplate
952
+ responses:
953
+ '200':
954
+ description: The PromptTemplate.
955
+ headers:
956
+ ETag:
957
+ schema: { type: string }
958
+ description: SHA-256 of the canonical body.
959
+ Cache-Control:
960
+ schema: { type: string }
961
+ description: Honors immutable semantics when version was pinned.
962
+ content:
963
+ application/json:
964
+ schema:
965
+ $ref: '../schemas/prompt-template.schema.json'
966
+ '304':
967
+ description: Conditional revalidation succeeded.
968
+ '400':
969
+ description: '`prompt_ref_ambiguous` when libraryId disambiguation is required.'
970
+ content:
971
+ application/json:
972
+ schema:
973
+ $ref: '../schemas/error-envelope.schema.json'
974
+ '401': { $ref: '#/components/responses/Unauthenticated' }
975
+ '403': { $ref: '#/components/responses/Forbidden' }
976
+ '404':
977
+ description: No such template (or version).
978
+ content:
979
+ application/json:
980
+ schema:
981
+ $ref: '../schemas/error-envelope.schema.json'
982
+ '501':
983
+ description: 'Host does not advertise capabilities.prompts.endpointsSupported. (RFC 0028 §A — supported gates Phase A node-execution composition; endpointsSupported gates this REST surface independently.)'
984
+ content:
985
+ application/json:
986
+ schema:
987
+ $ref: '../schemas/error-envelope.schema.json'
988
+ put:
989
+ tags: [prompts]
990
+ summary: Replace a prompt template (mutable libraries; user-source only).
991
+ operationId: updatePromptTemplate
992
+ parameters:
993
+ - $ref: '#/components/parameters/IdempotencyKey'
994
+ requestBody:
995
+ required: true
996
+ content:
997
+ application/json:
998
+ schema:
999
+ $ref: '../schemas/prompt-template.schema.json'
1000
+ responses:
1001
+ '200':
1002
+ description: Template updated.
1003
+ content:
1004
+ application/json:
1005
+ schema:
1006
+ $ref: '../schemas/prompt-template.schema.json'
1007
+ '400': { $ref: '#/components/responses/ValidationError' }
1008
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1009
+ '403':
1010
+ description: Template is pack-sourced or host-built-in (read-only).
1011
+ content:
1012
+ application/json:
1013
+ schema:
1014
+ $ref: '../schemas/error-envelope.schema.json'
1015
+ '404':
1016
+ description: No such template.
1017
+ content:
1018
+ application/json:
1019
+ schema:
1020
+ $ref: '../schemas/error-envelope.schema.json'
1021
+ '409':
1022
+ description: Submitted version does not exceed stored version (SemVer).
1023
+ content:
1024
+ application/json:
1025
+ schema:
1026
+ $ref: '../schemas/error-envelope.schema.json'
1027
+ '501':
1028
+ description: 'Host does not advertise capabilities.prompts.mutableLibrary.'
1029
+ content:
1030
+ application/json:
1031
+ schema:
1032
+ $ref: '../schemas/error-envelope.schema.json'
1033
+ delete:
1034
+ tags: [prompts]
1035
+ summary: Delete a prompt template (mutable libraries; user-source only).
1036
+ operationId: deletePromptTemplate
1037
+ responses:
1038
+ '204':
1039
+ description: Template deleted.
1040
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1041
+ '403':
1042
+ description: Template is pack-sourced or host-built-in (read-only).
1043
+ content:
1044
+ application/json:
1045
+ schema:
1046
+ $ref: '../schemas/error-envelope.schema.json'
1047
+ '404':
1048
+ description: No such template.
1049
+ content:
1050
+ application/json:
1051
+ schema:
1052
+ $ref: '../schemas/error-envelope.schema.json'
1053
+ '501':
1054
+ description: 'Host does not advertise capabilities.prompts.mutableLibrary.'
1055
+ content:
1056
+ application/json:
1057
+ schema:
1058
+ $ref: '../schemas/error-envelope.schema.json'
1059
+
1060
+ /v1/prompts:render:
1061
+ post:
1062
+ tags: [prompts]
1063
+ summary: Render a prompt template with supplied variable bindings.
1064
+ description: |
1065
+ Returns the composed body + sha256 hash + per-variable hashes.
1066
+ The response's `hash` MUST equal the `hash` that a matching
1067
+ `prompt.composed` event would carry at dispatch time for the
1068
+ same `(ref, variables, contentTrust)` inputs (RFC 0028 §A
1069
+ deterministic-render invariant; RFC 0027 §F replay invariant).
1070
+ Does NOT dispatch an LLM call. Secret-source variable values
1071
+ MUST be supplied as `[REDACTED:<credentialRef>]` markers; the
1072
+ host resolves the plaintext internally and never echoes it in
1073
+ the `composed` response field per SR-1.
1074
+ operationId: renderPromptTemplate
1075
+ requestBody:
1076
+ required: true
1077
+ content:
1078
+ application/json:
1079
+ schema:
1080
+ type: object
1081
+ required: [ref, variables]
1082
+ properties:
1083
+ ref:
1084
+ $ref: '../schemas/prompt-ref.schema.json'
1085
+ variables:
1086
+ type: object
1087
+ description: |
1088
+ Variable bindings keyed by `PromptVariable.name`.
1089
+ Secret-source bindings carry `[REDACTED:<credentialRef>]`
1090
+ markers; the host resolves the real value internally.
1091
+ additionalProperties: true
1092
+ contentTrust:
1093
+ type: string
1094
+ enum: [trusted, untrusted]
1095
+ description: |
1096
+ Aggregate trust marker for the supplied bindings,
1097
+ propagated through composition per RFC 0027 §E.
1098
+ responses:
1099
+ '200':
1100
+ description: Composed result.
1101
+ content:
1102
+ application/json:
1103
+ schema:
1104
+ type: object
1105
+ required: [hash, refs, variableHashes]
1106
+ properties:
1107
+ composed:
1108
+ type: string
1109
+ description: Full composed body. Present only when observability is `full`.
1110
+ hash:
1111
+ type: string
1112
+ pattern: '^sha256:[0-9a-f]{64}$'
1113
+ refs:
1114
+ type: array
1115
+ items:
1116
+ type: string
1117
+ variableHashes:
1118
+ type: object
1119
+ additionalProperties:
1120
+ type: string
1121
+ pattern: '^sha256:[0-9a-f]{64}$'
1122
+ contentTrust:
1123
+ type: string
1124
+ enum: [trusted, untrusted]
1125
+ '400':
1126
+ description: |
1127
+ `prompt_variable_unresolved` (required variable missing),
1128
+ `prompt_variable_type_mismatch` (bound type vs. declared type),
1129
+ or `prompt_ref_invalid` (malformed PromptRef).
1130
+ content:
1131
+ application/json:
1132
+ schema:
1133
+ $ref: '../schemas/error-envelope.schema.json'
1134
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1135
+ '403': { $ref: '#/components/responses/Forbidden' }
1136
+ '404':
1137
+ description: Referenced template does not exist.
1138
+ content:
1139
+ application/json:
1140
+ schema:
1141
+ $ref: '../schemas/error-envelope.schema.json'
1142
+ '501':
1143
+ description: 'Host does not advertise capabilities.prompts.endpointsSupported. (RFC 0028 §A — supported gates Phase A node-execution composition; endpointsSupported gates this REST surface independently.)'
1144
+ content:
1145
+ application/json:
1146
+ schema:
1147
+ $ref: '../schemas/error-envelope.schema.json'
1148
+
793
1149
  # ─────────────────────────────────────────────────────────────────────────────
794
1150
  # COMPONENTS
795
1151
  # ─────────────────────────────────────────────────────────────────────────────
@@ -880,6 +1236,20 @@ components:
880
1236
  Capabilities:
881
1237
  $ref: '../schemas/capabilities.schema.json'
882
1238
 
1239
+ # Pre-loaded so redocly's $ref resolver registers them at lint time.
1240
+ # capabilities.schema.json `$ref`s prompt-kind.schema.json by its
1241
+ # canonical openwop.dev URL — redocly resolves absolute URIs against
1242
+ # already-loaded `$id`s, so the schema must be pulled in here even
1243
+ # though no operation references it directly. See RFC 0027 §A.
1244
+ PromptKind:
1245
+ $ref: '../schemas/prompt-kind.schema.json'
1246
+
1247
+ PromptTemplate:
1248
+ $ref: '../schemas/prompt-template.schema.json'
1249
+
1250
+ PromptRef:
1251
+ $ref: '../schemas/prompt-ref.schema.json'
1252
+
883
1253
  RunSnapshot:
884
1254
  $ref: '../schemas/run-snapshot.schema.json'
885
1255