@openwop/openwop-conformance 1.2.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 (144) hide show
  1. package/CHANGELOG.md +156 -1
  2. package/README.md +3 -2
  3. package/api/asyncapi.yaml +8 -0
  4. package/api/openapi.yaml +371 -1
  5. package/api/redocly.yaml +15 -0
  6. package/coverage.md +26 -5
  7. package/fixtures/conformance-agent-reasoning-streaming.json +37 -0
  8. package/fixtures/conformance-dispatch-cancellable-child.json +27 -0
  9. package/fixtures/conformance-dispatch-deterministic-fail-child.json +30 -0
  10. package/fixtures/conformance-dispatch-input-mapping-no-default.json +49 -0
  11. package/fixtures/conformance-dispatch-per-worker-override.json +59 -0
  12. package/fixtures/conformance-envelope-nl-to-format-engaged.json +41 -0
  13. package/fixtures/conformance-envelope-recovery-applied.json +39 -0
  14. package/fixtures/conformance-envelope-refusal.json +38 -0
  15. package/fixtures/conformance-envelope-retry-attempted.json +39 -0
  16. package/fixtures/conformance-envelope-retry-exhausted.json +38 -0
  17. package/fixtures/conformance-envelope-truncated.json +39 -0
  18. package/fixtures/conformance-envelope-truncation-cap-exhaustion.json +39 -0
  19. package/fixtures/conformance-model-capability-insufficient.json +25 -0
  20. package/fixtures/conformance-multi-agent-confidence-escalation.json +49 -0
  21. package/fixtures/conformance-multi-agent-handoff-child.json +27 -0
  22. package/fixtures/conformance-multi-agent-handoff.json +49 -0
  23. package/fixtures/conformance-prompt-all-four-kinds.json +39 -0
  24. package/fixtures/conformance-prompt-end-to-end.json +33 -0
  25. package/fixtures/conformance-subworkflow-input-mapping-no-default.json +33 -0
  26. package/fixtures/conformance-subworkflow-mid-run-mutation-child.json +31 -0
  27. package/fixtures/conformance-subworkflow-mid-run-mutation.json +33 -0
  28. package/fixtures/openwop-smoke-cost-emit.json +37 -0
  29. package/fixtures/prompt-templates/conformance-prompt-few-shot-2.json +14 -0
  30. package/fixtures/prompt-templates/conformance-prompt-few-shot.json +14 -0
  31. package/fixtures/prompt-templates/conformance-prompt-schema-hint.json +14 -0
  32. package/fixtures/prompt-templates/conformance-prompt-secret-redaction.json +23 -0
  33. package/fixtures/prompt-templates/conformance-prompt-trust-marker.json +23 -0
  34. package/fixtures/prompt-templates/conformance-prompt-writer-system.json +15 -0
  35. package/fixtures/prompt-templates/conformance-prompt-writer-user.json +15 -0
  36. package/fixtures.md +45 -0
  37. package/package.json +1 -1
  38. package/schemas/README.md +5 -0
  39. package/schemas/agent-manifest.schema.json +16 -0
  40. package/schemas/capabilities.schema.json +390 -0
  41. package/schemas/core-conformance-mock-agent-config.schema.json +5 -0
  42. package/schemas/envelopes/clarification.request.schema.json +9 -0
  43. package/schemas/envelopes/error.schema.json +4 -0
  44. package/schemas/envelopes/schema.request.schema.json +4 -0
  45. package/schemas/envelopes/schema.response.schema.json +1 -1
  46. package/schemas/node-pack-manifest.schema.json +28 -0
  47. package/schemas/orchestrator-decision.schema.json +12 -0
  48. package/schemas/prompt-kind.schema.json +8 -0
  49. package/schemas/prompt-pack-manifest.schema.json +80 -0
  50. package/schemas/prompt-ref.schema.json +40 -0
  51. package/schemas/prompt-template.schema.json +149 -0
  52. package/schemas/registry-version-manifest.schema.json +5 -0
  53. package/schemas/run-ancestry-response.schema.json +54 -0
  54. package/schemas/run-event-payloads.schema.json +513 -11
  55. package/schemas/run-event.schema.json +17 -1
  56. package/schemas/run-snapshot.schema.json +3 -2
  57. package/schemas/workflow-definition.schema.json +19 -1
  58. package/src/lib/driver.ts +15 -0
  59. package/src/lib/env.ts +51 -0
  60. package/src/lib/event-log-query.ts +62 -0
  61. package/src/lib/fixtures.ts +38 -1
  62. package/src/lib/host-toggle.ts +54 -0
  63. package/src/lib/llm-cache-key-recipe.ts +68 -0
  64. package/src/lib/multi-agent-capabilities.ts +10 -0
  65. package/src/lib/otel-scrape.ts +59 -0
  66. package/src/scenarios/agentReasoningStreaming.test.ts +193 -0
  67. package/src/scenarios/aiEnvelope.capBreached.test.ts +97 -9
  68. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +224 -15
  69. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +257 -25
  70. package/src/scenarios/aiEnvelope.redaction.test.ts +210 -29
  71. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +163 -24
  72. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +262 -12
  73. package/src/scenarios/aiEnvelope.universalKinds.test.ts +107 -16
  74. package/src/scenarios/blob-presign-expiry.test.ts +42 -9
  75. package/src/scenarios/blob-roundtrip.test.ts +0 -0
  76. package/src/scenarios/cache-ttl-expiry.test.ts +34 -8
  77. package/src/scenarios/cost-attribution.test.ts +124 -11
  78. package/src/scenarios/cross-engine-append-ordering.test.ts +99 -0
  79. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +136 -0
  80. package/src/scenarios/cross-host-causation-shape.test.ts +117 -0
  81. package/src/scenarios/cross-host-traceparent-propagation.test.ts +60 -0
  82. package/src/scenarios/dispatch-cross-worker-handoff.test.ts +34 -3
  83. package/src/scenarios/dispatch-input-mapping.test.ts +75 -6
  84. package/src/scenarios/dispatch-output-mapping.test.ts +96 -6
  85. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +223 -0
  86. package/src/scenarios/envelope-nl-to-format-engaged.test.ts +152 -0
  87. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +343 -0
  88. package/src/scenarios/envelope-reasoning-shape.test.ts +190 -0
  89. package/src/scenarios/envelope-recovery-applied.test.ts +229 -0
  90. package/src/scenarios/envelope-refusal-shape.test.ts +289 -0
  91. package/src/scenarios/envelope-retry-attempted.test.ts +258 -0
  92. package/src/scenarios/envelope-retry-exhausted.test.ts +168 -0
  93. package/src/scenarios/envelope-tier-one-subset-static.test.ts +229 -0
  94. package/src/scenarios/envelope-truncated.test.ts +136 -0
  95. package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +144 -0
  96. package/src/scenarios/envelope-variant-discriminator-static.test.ts +152 -0
  97. package/src/scenarios/fixtures-gating.test.ts +139 -1
  98. package/src/scenarios/fixtures-valid.test.ts +123 -15
  99. package/src/scenarios/kv-ttl-expiry.test.ts +40 -9
  100. package/src/scenarios/model-capability-insufficient.test.ts +221 -0
  101. package/src/scenarios/model-capability-substituted.test.ts +203 -0
  102. package/src/scenarios/multi-agent-confidence-escalation.test.ts +164 -0
  103. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +167 -0
  104. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +124 -0
  105. package/src/scenarios/multi-region-idempotency.test.ts +58 -0
  106. package/src/scenarios/node-module-required-capabilities-shape.test.ts +185 -0
  107. package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +19 -0
  108. package/src/scenarios/pack-registry-publish.test.ts +231 -51
  109. package/src/scenarios/prompt-all-four-kinds-events.test.ts +198 -0
  110. package/src/scenarios/prompt-composed-secret-redaction.test.ts +178 -0
  111. package/src/scenarios/prompt-composed-trust-marker.test.ts +165 -0
  112. package/src/scenarios/prompt-end-to-end-events.test.ts +202 -0
  113. package/src/scenarios/prompt-list-and-fetch.test.ts +207 -0
  114. package/src/scenarios/prompt-mutable-lifecycle.test.ts +216 -0
  115. package/src/scenarios/prompt-pack-install.test.ts +187 -0
  116. package/src/scenarios/prompt-render-deterministic.test.ts +240 -0
  117. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +140 -0
  118. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +172 -0
  119. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +144 -0
  120. package/src/scenarios/prompt-template-shape.test.ts +359 -0
  121. package/src/scenarios/provider-usage.test.ts +185 -0
  122. package/src/scenarios/queue-ack-nack-dlq.test.ts +64 -10
  123. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +50 -10
  124. package/src/scenarios/replay-divergence-at-refusal.test.ts +134 -0
  125. package/src/scenarios/replay-llm-cache-key-portable.test.ts +197 -0
  126. package/src/scenarios/replay-llm-cache-key.test.ts +127 -25
  127. package/src/scenarios/replay-observable-sequence-determinism.test.ts +80 -0
  128. package/src/scenarios/sandbox-capability-gate-respected.test.ts +31 -0
  129. package/src/scenarios/sandbox-memory-cap.test.ts +61 -0
  130. package/src/scenarios/sandbox-no-cross-pack-mutation.test.ts +35 -0
  131. package/src/scenarios/sandbox-no-host-env-leak.test.ts +38 -0
  132. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +91 -0
  133. package/src/scenarios/sandbox-no-host-process-escape.test.ts +30 -0
  134. package/src/scenarios/sandbox-no-network-escape.test.ts +49 -0
  135. package/src/scenarios/sandbox-timeout-cap.test.ts +61 -0
  136. package/src/scenarios/search-bm25-roundtrip.test.ts +54 -9
  137. package/src/scenarios/spec-corpus-validity.test.ts +34 -6
  138. package/src/scenarios/sql-transaction-atomicity.test.ts +37 -8
  139. package/src/scenarios/stream-subscribe-from-beginning.test.ts +46 -9
  140. package/src/scenarios/subworkflow-input-mapping.test.ts +146 -10
  141. package/src/scenarios/table-cursor-pagination.test.ts +47 -9
  142. package/src/scenarios/table-schema-enforcement.test.ts +46 -9
  143. package/src/scenarios/vector-knn-roundtrip.test.ts +50 -10
  144. package/src/scenarios/workflow-chain-host-expansion.test.ts +202 -0
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
 
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,13 +34,22 @@
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
- | 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. |
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 Accepted 2026-05-18 once the live-host gate (`workflow-chain-host-expansion.test.ts`) passed against the reference in-memory host. The 4 server-free scenarios exercise the pure-library algorithm; the live-host scenario exercises the 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. The matching spec doc `workflow-chain-packs.md` remains at `DRAFT v1.x` pending Phase B/C closure (parameter schema validation + cross-host expansion equivalence). |
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` | A− (shape + ~84 live behavioral assertions across all 8 files via the envelope-accept seam) | 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. All 8 files now also run behavioral assertions through the workflow-engine sample's env-gated `POST /v1/host/sample/envelope/accept` seam (drained 2026-05-19): schema-drift refusal under strict mode; correlationId-replay short-circuit + persisted `priorCorrelations` store survives process restart; BYOK redaction-carry-forward returning `redactedPayload` + `redactionCount`; contract-refusal mappings via the capability-toggle seam; trust-boundary propagation from MCP/A2A; cap-breached counters; universal-kind always-allowed; `ai-envelope-shape` end-to-end accept-pipeline. Path to `Accepted` (host-side): live downstream-projection coverage on a published host (OTel scrape + debug-bundle export currently soft-skip on hosts that don't expose those seams). |
39
+ | Envelope `reasoning` field + Tier-1 subset (RFC 0030 — `spec/v1/ai-envelope.md` §"Reasoning field (normative)", `spec/v1/structured-output-subset.md`) | `envelope-reasoning-shape.test.ts`, `envelope-reasoning-secret-redaction.test.ts`, `envelope-tier-one-subset-static.test.ts` | A (shape + load-bearing Tier-1 static checks always-on; 8 live behavioral assertions in `envelope-reasoning-secret-redaction` via the envelope-accept seam, including the OTel + debug-bundle downstream projections) | RFC 0030 promoted Draft → Active 2026-05-20. `envelope-reasoning-shape` (always-on) asserts the OPTIONAL `reasoning` property posture on the three universal-kind schemas + the `schema.response` deliberate omission + with/without backward-compat round-trips + `capabilities.envelopes.reasoning.{supported,promptDirective}` + `tierOneSubsetCompliance` advertisement shape. `envelope-tier-one-subset-static` enforces the load-bearing Tier-1 subset (no `oneOf` / `allOf` / `not` / `prefixItems` / `propertyNames` anywhere — Gemini silently drops these) on every universal-kind schema as always-on; the OpenAI-strict-only constraints (`minLength` / `maxLength` / `minItems` etc.) are checked only under host-advertised `tierOneSubsetCompliance: "strict"` to honor the universal-kind schemas' pre-RFC-0030 open-bag design. `envelope-reasoning-secret-redaction` (capability-gated on `reasoning.supported` + `secrets.supported`) carries 8 live behavioral assertions for SECURITY invariant `envelope-reasoning-secret-redaction`: BYOK canary substitution with the canonical `[REDACTED:<secretId>]` marker on `reasoning`; recursive walk across `reasoning` + sibling fields; passthrough when no canary matches; canary detection inside `clarification.request.reasoning`; downstream OTel-span scrape + debug-bundle export both confirm no canary plaintext leaks (soft-skip on hosts that don't expose those seams); non-routing-on-reasoning invariant (acceptor's routing decision MUST NOT depend on `reasoning` contents). Reference host advertises `capabilities.envelopes.reasoning: { supported: true, promptDirective: "off" }` + `tierOneSubsetCompliance: "warn"`. Path to `Accepted`: reference host injects the system-prompt directive instructing the model to populate `reasoning` (promotes `promptDirective` → `"advisory"`). |
40
+ | Envelope variant discrimination + model capabilities (RFC 0031 — `spec/v1/ai-envelope.md` §"Variant payload discrimination (normative)", `spec/v1/host-capabilities.md` §"Model-capability declarations", `spec/v1/node-packs.md` §"Model-capability declarations on NodeModules") | `envelope-variant-discriminator-static.test.ts`, `model-capability-substituted.test.ts`, `model-capability-insufficient.test.ts`, `node-module-required-capabilities-shape.test.ts` | B+ (discriminator-static + advertisement-shape always-on; 14 live behavioral assertions across substitution + insufficient + authoring-convention, capability-gated) | RFC 0031 promoted Draft → Active 2026-05-20. `envelope-variant-discriminator-static` (always-on) walks every `schemas/envelopes/*.schema.json` asserting no `oneOf` at any nesting depth (Gemini silently drops `oneOf`, producing looser-than-declared schemas — a silent correctness bug) AND every `anyOf` branch declares a single-string-`enum` discriminator in `required` per RFC 0031 §A. `model-capability-substituted` (capability-gated on `capabilities.modelCapabilities.supported` + `substitutionSupported`) carries advertisement-shape check on the `advertised: string[]` pattern (each identifier matches the spec-reserved set OR `^x-host-<host>-<key>$` per RFC 0031 §C) + 4 live behavioral assertions covering substitution emission + SECURITY invariant `model-capability-substituted-no-credential-disclosure`'s all-or-nothing `"[REDACTED]"` redaction option. `model-capability-insufficient` (capability-gated on `modelCapabilities.supported`) carries 6 live behavioral assertions covering refusal emission paths + the no-recursive-fallback constraint (RFC 0031 §"Unresolved questions" #3 — `fallbackAttempted: true` when the declared fallback itself fails; NO chaining). `node-module-required-capabilities-shape` (SHOULD-tier authoring convention check) carries 4 live assertions for the `core.ai.*` typeId-pattern recommendation. Path to `Accepted`: reference host implements `executor/modelCapabilityGate.ts` end-to-end + advertises `capabilities.modelCapabilities: { supported: true, advertised: [...], substitutionSupported: true }` (the live behavioral assertions soft-skip cleanly on hosts that haven't wired the executor yet). |
41
+ | Envelope-reliability run-event vocabulary (RFC 0032 — `spec/v1/ai-envelope.md` §"Envelope-reliability events" + line-448 scope clarification, `spec/v1/observability.md` §"Envelope-reliability events (RFC 0032)") | `envelope-retry-attempted.test.ts`, `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` | B (1 shared advertisement-shape probe with MUST-events enforcement; 34 live behavioral assertions across the six events, all capability- + fixture-gated) | RFC 0032 promoted Draft → Active 2026-05-20. Carries the central `ai-envelope.md` line-448 scope clarification (per-kind routing events forbidden; cross-kind operational events permitted via RFC). `envelope-retry-attempted` carries the shared advertisement-shape probe: when `capabilities.envelopes.reliability.supported: true`, the host MUST list both `envelope.retry.exhausted` AND `envelope.refusal` in `events[]` (the two MUST-tier events per RFC 0032 §C); `maxRetryAttempts` MUST be in `[1, 16]`. The six scenarios collectively carry 34 live behavioral assertions (drained 2026-05-19 via the conformance `mock` provider + `POST /v1/host/sample/test/mock-ai/program` seam): retry on schema-violation + retry on truncation + retry-exhausted terminal failure + provider refusal (no-retry MUST per RFC 0032 §B.3 + RFC 0033 §D) + truncation cut-off + NL-to-Format escalation (Tam et al. mitigation per arXiv 2408.02442) + lenient-parsing recovery + SECURITY invariants `envelope-refusal-no-prompt-leak` (BYOK + prompt-content redaction on `refusalText`) and `envelope-recovery-no-content-leak` (no pre-recovery substrings in the event payload). Path to `Accepted`: reference host implements `executor/envelopeReliability.ts` end-to-end + advertises `capabilities.envelopes.reliability: { supported: true, events: [...], maxRetryAttempts: <n> }` (the behavioral assertions already pass against the reference host's end-to-end emission path under `OPENWOP_ENVELOPE_RELIABILITY_END_TO_END=true`; the no-flag default still soft-skips). |
42
+ | Envelope-completion retry routing (RFC 0033 — `spec/v1/ai-envelope.md` §"Envelope-completion criteria", `spec/v1/observability.md` §"Envelope-completion retry routing (RFC 0033)") | `envelope-completion-distinguishes-truncation.test.ts`, `envelope-truncation-cap-exhaustion.test.ts` | B− (1 advertisement-shape probe on `completion.{distinguishesTruncation, truncationBudgetMultiplier}`; 9 live behavioral assertions across the two retry paths + the DoS-bound assertion) | RFC 0033 promoted Draft → Active 2026-05-20. Closes `spec/v1/ai-envelope.md` §"Open spec gaps" E5 (refusal-mode + retry-policy interaction). Reuses RFC 0032's event vocabulary; introduces NO new event types. `envelope-completion-distinguishes-truncation` (capability-gated on `completion.distinguishesTruncation: true`) carries 5 live behavioral assertions covering both retry paths — truncation MUST increase output budget (RECOMMENDED 2× per `truncationBudgetMultiplier`) WITHOUT a corrective fragment; schema-violation MUST add a corrective fragment WITHOUT a budget change. `envelope-truncation-cap-exhaustion` carries 4 live behavioral assertions covering the DoS-bound assertion (truncation retries count against `Capabilities.limits.schemaRounds`; exhaustion → `envelope.retry.exhausted { finalReason: "truncation" }` + `cap.breached { kind: "schema" }` + node fails with NEW error code `envelope_truncation_unrecoverable` per RFC 0033 §F). All 9 assertions are fixture- + capability-gated against the conformance `mock` provider via `POST /v1/host/sample/test/mock-ai/program`. Path to `Accepted`: reference host implements the truncation-vs-schema-violation retry-routing branch end-to-end (`executor/envelopeReliability.ts` + `stop_reason` inspection in `aiProviders/aiProvidersHost.ts`) + advertises `capabilities.envelopes.reliability.completion.distinguishesTruncation: true`. |
43
+ | Multi-agent execution model + handoff state machine (RFC 0037 Phase 1 — `spec/v1/multi-agent-execution.md`) | `multi-agent-handoff-state-machine.test.ts` | B (1 advertisement-shape probe + 1 behavioral 4-event causation-chain assertion against the parent+child fixture pair) | RFC 0037 Phase 1 filed Draft → promoted Active 2026-05-21 after spec + schema + scenario landed atomically. Advertisement-shape probe asserts `capabilities.multiAgent.executionModel.{supported, version ∈ [1,4]}` when present. Behavioral assertion drives the `conformance-multi-agent-handoff` parent + `conformance-multi-agent-handoff-child` fixture pair: runs the supervisor → next-worker → child completed loop and asserts the 4 `core.workflowChain.event` records appear in the exact phase sequence `dispatch.began → dispatch.succeeded → child.completed → output.harvested` with each event's `causationId === prior.eventId` and `dispatch.began.causationId === runOrchestrator.decided.eventId`, plus `output.harvested.harvestedKeys === ['parentResult']` (proves the spec §"Transition events" table on real wire). Reference workflow-engine advertises + emits end-to-end when `OPENWOP_MULTI_AGENT_EXECUTION_MODEL=true`; the no-flag default soft-skips honestly. Path to `Accepted`: non-steward host advertises + the behavioral assertion passes against it. |
44
+ | Multi-agent Phase 2 confidence-floor escalation (RFC 0039 — `spec/v1/multi-agent-execution.md` §"Confidence escalation") | `multi-agent-confidence-escalation.test.ts` | B (1 advertisement-shape probe on `confidenceEscalationFloor` + 1 behavioral assertion against the low-confidence fixture) | RFC 0039 Phase 2 filed Draft → promoted Active 2026-05-22 after the confidence-floor half landed end-to-end. Advertisement-shape probe asserts `capabilities.multiAgent.executionModel.confidenceEscalationFloor` (when present) is a number in `[0.5, 1.0]`; values below the spec floor are non-conformant. Behavioral assertion drives the `conformance-multi-agent-confidence-escalation` fixture (supervisor `mockDispatchPlan` carries one decision with `confidence: 0.3`) and asserts: parent reaches `waiting-clarification` (NOT `completed` because no dispatch fired); exactly ONE `core.workflowChain.confidence-escalated` event with `payload.confidence === 0.3`, `payload.floor ∈ [0.5, 1.0]`, `payload.escalationKind ∈ {clarify, escalate}`; causationId chains back to the `runOrchestrator.decided` event; ZERO `core.workflowChain.event` records (the load-bearing distinction from Phase 1 — confidence floor MUST fire BEFORE any dispatch.began). Reference workflow-engine advertises `version: 2` + `confidenceEscalationFloor: 0.5` when both `OPENWOP_MULTI_AGENT_EXECUTION_MODEL=true` AND `OPENWOP_MULTI_AGENT_EXECUTION_MODEL_PHASE_2=true` are set; floor tunable via `OPENWOP_MULTI_AGENT_CONFIDENCE_FLOOR`. Path to `Accepted`: non-steward host advertises `version: 2` + the behavioral assertion passes against it. Memory-lifecycle half of RFC 0039 (MAE-2/3) remains explicit follow-up: `crossChildMemoryConcurrency` capability field is schema-landed but the host's MemoryAdapter doesn't yet implement either contract. |
45
+ | Sandbox execution contract (RFC 0035 — `spec/v1/host-capabilities.md` §"Sandbox execution contract") | `sandbox-no-host-fs-escape.test.ts`, `sandbox-no-host-env-leak.test.ts`, `sandbox-no-network-escape.test.ts`, `sandbox-no-host-process-escape.test.ts`, `sandbox-memory-cap.test.ts`, `sandbox-timeout-cap.test.ts`, `sandbox-capability-gate-respected.test.ts`, `sandbox-no-cross-pack-mutation.test.ts` | C+ (advertisement-shape probes always-on; 8 capability-gated behavioral stubs scaffolded; soft-skip on hosts that don't advertise `capabilities.sandbox.supported`) | RFC 0035 promoted Draft → Active 2026-05-21. 8 scenarios, one per `node-pack-sandbox-*` invariant in `SECURITY/invariants.yaml`. Behavioral assertions remain stubbed with `expect(true).toBe(true)` + docstring expected-wire-shape pending the synthetic `vendor.openwop.misbehaving-sandbox` pack + a first sandbox-executing reference host. Path to `Accepted`: first sandbox-executing host advertises + implements the 8 failure-mode invariants + the 8 scenarios pass; at that point the 8 `node-pack-sandbox-*` SECURITY rows graduate from `reference-impl` → `protocol` tier per RFC 0035 §"Acceptance criteria." |
46
+ | Multi-region idempotency + cross-engine append-ordering (RFC 0036 — `spec/v1/idempotency.md` §"`multiRegion` sub-block", `spec/v1/replay.md` §"Cross-region replay") | `multi-region-idempotency.test.ts`, `cross-engine-append-ordering.test.ts` | C+ (2 categorical-shape probes always-on + 1 granular `multiRegion` shape probe + 1 `crossEngineOrdering` shape probe; behavioral assertions deferred to simulator landing per RFC 0036 §C) | RFC 0036 promoted Draft → Active 2026-05-21. The existing `multi-region-idempotency.test.ts` covers the categorical `capabilities.idempotency.crossRegion ∈ {single-region, best-effort, strict}` claim plus the matching operator-tier metric names; a third describe block added 2026-05-21 covers the granular `capabilities.idempotency.multiRegion.{supported, replicationLagBoundMs, partitionRecoveryStrategy}` advertisement shape (`replicationLagBoundMs ∈ [0, 60000]`; `partitionRecoveryStrategy ∈ {last-writer-wins, first-writer-wins}` OR `^x-host-<host>-<key>$`). NEW `cross-engine-append-ordering.test.ts` covers `capabilities.eventLog.crossEngineOrdering.{supported, orderingModel ∈ {lamport, vector-clock, global-sequencer}}` shape. Behavioral two-engine-append-then-cross-read assertion deferred until the Postgres reference host's multi-region simulator lands per RFC 0036 §C. Path to `Accepted`: simulator + behavioral conformance pass against the reference host; non-steward host advertises the same. |
38
47
 
39
48
  ---
40
49
 
41
50
  ## Capability-gated scenarios: shape vs behavior
42
51
 
43
- Seventeen scenarios (or scenario groups) validate optional profiles where the host's discovery advertisement is well-formed (shape grade) but no reference host yet implements the profile end-to-end (behavior grade is `host-pending`). Default suite runs skip these with a warning; set `OPENWOP_REQUIRE_BEHAVIOR=true` to convert skips into hard failures.
52
+ Twenty-two scenario groups validate optional profiles where the host's discovery advertisement is well-formed (shape grade) but no reference host yet implements the profile end-to-end (behavior grade is `host-pending`). Default suite runs skip these with a warning; set `OPENWOP_REQUIRE_BEHAVIOR=true` to convert skips into hard failures.
44
53
 
45
54
  | Scenario | Profile / capability | Shape grade | Behavior grade | Behavior-unlock dependency |
46
55
  |---|---|---|---|---|
@@ -68,6 +77,11 @@ Seventeen scenarios (or scenario groups) validate optional profiles where the ho
68
77
  | `blob-cross-tenant-isolation.test.ts`, `cache-cross-tenant-isolation.test.ts` (two scenarios) | `capabilities.blobStorage` + `capabilities.cache` (RFC 0019, `host-blob-cache-capability.md`) | A (advertisement shape + behavioral cross-tenant put/get isolation for both surfaces) | host-pass via opt-in test seam | Same seam dependency as kv row. |
69
78
  | `sql-injection-rejection.test.ts` | `capabilities.sql` (RFC 0018, `host-sql-vector-search-capability.md`) + `SECURITY/invariants.yaml` `sql-parametric-only` | A (advertisement shape + parametric round-trip + injection-shape input bound as literal returns 0 rows) | host-pass via opt-in test seam | Same seam dependency as kv row. |
70
79
  | `mcp-server-tool-roundtrip.test.ts`, `mcp-server-resource-roundtrip.test.ts`, `mcp-server-prompt-roundtrip.test.ts`, `mcp-server-sampling-bridge.test.ts`, `mcp-server-elicitation-bridge.test.ts`, `mcp-server-untrusted-args.test.ts` (six scenarios) | `capabilities.mcp.serverMount` (RFC 0020, `mcp-integration.md` §"OpenWOP host as MCP server") + `SECURITY/invariants.yaml` `mcp-server-untrusted-args` | A (advertisement shape + JSON-RPC tools/list+tools/call roundtrip, resources/list+read, prompts/list+get, sampling/elicitation bridge dispatch, Ajv2020 args validation rejecting with -32602 before workflow start) | host-pass via opt-in MCP server mount | Reference host exposes `POST /v1/host/sample/mcp` env-gated on `OPENWOP_MCP_SERVER_ENABLED=true`; hosts that don't expose the mount soft-skip the behavioral assertions and verify advertisement shape only. |
80
+ | `prompt-end-to-end-events.test.ts`, `prompt-resolution-chain-node-wins.test.ts`, `prompt-resolution-chain-fallback-cascade.test.ts` (three scenarios) | `prompts-supported` profile — gates on `capabilities.prompts.supported: true` (RFC 0027 + RFC 0029, `spec/v1/prompts.md`) | A (advertisement shape always + end-to-end resolve + emit during real workflow dispatch; resolution chain Layers 1, 3, 4 exercised) | host-pass (workflow-engine reference) | Reference host advertises `capabilities.prompts.supported: true` since RFC 0027 ref-impl landed; dispatch wiring in `bootstrap/nodes.ts` walks the resolution chain and emits `agent.promptResolved` + `prompt.composed` per spec/v1/prompts.md §"Composition + observability". |
81
+ | `prompt-pack-install.test.ts`, `prompt-list-and-fetch.test.ts`, `prompt-render-deterministic.test.ts` (three scenarios) | `prompts-endpoints` profile — gates on `capabilities.prompts.endpointsSupported: true` (RFC 0028 §A, `spec/v1/prompts.md` §"Discovery & distribution") | A (advertisement shape always + list/get/render contract + pack-source provenance stamps + ETag honoring when supported) | host-pass (workflow-engine reference) | Reference host serves the six `/v1/prompts*` routes via `routes/prompts.ts` against the in-memory `PromptStore`. Pack-install existence claim opt-in via `OPENWOP_TEST_PROMPT_PACK_INSTALLED=true` (the in-tree `vendor.openwop.prompt-sample` pack auto-installs via `promptPackLoader.ts`). |
82
+ | `prompt-mutable-lifecycle.test.ts` | `prompts-mutable` profile — gates on `capabilities.prompts.mutableLibrary: true` (RFC 0028 §C) | A (advertisement shape + CRUD lifecycle + pack/host source 403-on-mutation) | host-pass (workflow-engine reference) | Reference host advertises `mutableLibrary: true`; user-source templates accepted, pack + host-built-in templates return 403 on POST/PUT/DELETE. |
83
+ | `prompt-resolution-chain-agent-intrinsic.test.ts` | `prompts-agent-bindings` profile — gates on `capabilities.prompts.agentBindings: true` (RFC 0029 §A Layer 2) | A (advertisement shape + Layer 2 agent intrinsic / overrides / library-default precedence over Layers 3-4) | host-pass (workflow-engine reference) | Reference host advertises `agentBindings: true` so Layer 2 sub-layers (agent-intrinsic / agent-overrides / agent-library-default) walk per RFC 0029 §B. |
84
+ | `prompt-composed-secret-redaction.test.ts`, `prompt-composed-trust-marker.test.ts` (two scenarios) | `prompts-observability-full` profile — gates on `prompts.supported + observability: "full"` (RFC 0027 §E + RFC 0020 §D) + `SECURITY/invariants.yaml` `prompt-composed-secret-redaction` + `prompt-composed-trust-marker` | A (advertisement shape + `[REDACTED:<credentialRef>]` markers for secret-source bindings + `<UNTRUSTED>...</UNTRUSTED>` wrapping + `contentTrust: "untrusted"` propagation) | host-pass (workflow-engine reference) | Reference host advertises `observability: "full"` (sourced from `host/promptHostConfig.ts`). Composition pipeline in `host/promptCompose.ts` enforces SR-1 carry-forward + untrusted-content marker per `SECURITY/threat-model-secret-leakage.md` §SR-1. |
71
85
 
72
86
  Strict-mode runner usage:
73
87
 
@@ -75,7 +89,7 @@ Strict-mode runner usage:
75
89
  OPENWOP_REQUIRE_BEHAVIOR=true npx vitest run
76
90
  ```
77
91
 
78
- The flag is read at scenario startup via `conformance/src/lib/env.ts` → `loadEnv().requireBehavior`. Scenarios use the `behaviorGate(profileName, advertised)` helper from `conformance/src/lib/behavior-gate.ts` so the strict-mode failure message cites the relevant spec section. `audit-log-integrity.test.ts` is the worked example as of 2026-05-11; the remaining nine scenarios will adopt the helper as their host-side profiles land (tracked in `docs/PROTOCOL-GAP-CLOSURE-PLAN.md` Phase-1 tracks T1.1 onward).
92
+ The flag is read at scenario startup via `conformance/src/lib/env.ts` → `loadEnv().requireBehavior`. Scenarios use the `behaviorGate(profileName, advertised)` helper from `conformance/src/lib/behavior-gate.ts` so the strict-mode failure message cites the relevant spec section. The wired-and-passing examples (host-pass behavior grade) include `audit-log-integrity.test.ts` (landed 2026-05-11), the 5 host-capability-surface families gated on the `OPENWOP_TEST_SEAM_ENABLED=true` test seam, and the prompt-* family of 10 scenarios across the five `prompts-*` profile names (landed 2026-05-20). The remaining `host-pending` rows in the table above adopt the helper as their host-side profiles land (tracked in `docs/PROTOCOL-GAP-CLOSURE-PLAN.md` Phase-1 tracks T1.1 onward). Hosts that deliberately don't implement a profile can list it in `OPENWOP_OPTED_OUT_PROFILES=name1,name2,...` to skip even in strict mode — minimal hosts can claim full strict-mode coverage without falsifying advertisements.
79
93
 
80
94
  ---
81
95
 
@@ -95,6 +109,7 @@ Every OpenAPI operation should have:
95
109
  | `getWorkflow` | `route-coverage.test.ts`; fixture-dependent lifecycle tests indirectly require seeded workflow IDs | `route-coverage.test.ts` covers unknown workflow `404`/`403` envelope | Good. |
96
110
  | `createRun` | `runs-lifecycle.test.ts`, `identity-passthrough.test.ts`, `failure-path.test.ts`, fixture scenarios | `auth.test.ts`, `errors.test.ts`, `idempotency.test.ts`, `idempotencyRetry.test.ts` | Strong baseline; add per-field validation matrix. |
97
111
  | `getRun` | Lifecycle, cancellation, interrupt, replay, and subworkflow tests poll snapshots | `failure-path.test.ts`, `errors.test.ts` | Add explicit unknown-run `404` scenario if not already covered through helper assertions. |
112
+ | `getRunAncestry` | `cross-host-ancestry-endpoint.test.ts`, `cross-host-causation-shape.test.ts` (RFC 0040 §C); capability-gated on `capabilities.multiAgent.executionModel.crossHostCausation.ancestryEndpointSupported` | Unadvertised-host 404 path + top-level `parent: null` shape covered | Add positive multi-hop traversal once a reference host implements end-to-end cross-host composition. |
98
113
  | `streamRunEvents` | `stream-modes.test.ts`, `stream-modes-buffer.test.ts`, `stream-modes-mixed.test.ts`, `streamReconnect.test.ts` | Unsupported mode and invalid buffer assertions | Add long-running proxy timeout soak outside fast CI. |
99
114
  | `pollRunEvents` | `multi-node-ordering.test.ts`, `version-negotiation.test.ts`, redaction tests | Past-end and validation assertions | Good. Add malformed `lastSequence` if missing. |
100
115
  | `cancelRun` | `cancellation.test.ts` | Unknown/terminal idempotency cases partial | Add explicit already-terminal cancel behavior. |
@@ -106,9 +121,15 @@ Every OpenAPI operation should have:
106
121
  | `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
122
  | `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
123
  | `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. |
124
+ | `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
125
  | `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
126
  | `unregisterWebhook` | Webhook spec exists | `route-coverage.test.ts` covers unknown subscription behavior | Add full register-then-unregister roundtrip with a test receiver. |
127
+ | `listPromptTemplates` | `prompt-template-shape.test.ts` covers schema shape + advertisement contract for `capabilities.prompts.*`; capability-gated behavioral list-with-filter scenarios deferred to RFC 0028 acceptance gate | n/a yet — endpoint surface in spec only (RFC 0028 Draft); reference host hasn't implemented the route yet | Add positive list-with-filter scenario + auth-failure + invalid-cursor scenarios once a reference host implements the route. |
128
+ | `createPromptTemplate` | None — endpoint surface in spec only (RFC 0028 Draft) | n/a yet | Add positive create + `409` duplicate + `501` not-mutable-library + auth/scope scenarios once a reference host implements the route. |
129
+ | `getPromptTemplate` | None — endpoint surface in spec only | n/a yet | Add positive fetch + `404` unknown + `400` ambiguous-libraryId + `ETag` revalidation scenarios. |
130
+ | `updatePromptTemplate` | None — endpoint surface in spec only | n/a yet | Add positive update + `409` non-monotonic-version + `403` pack-sourced-readonly + `501` not-mutable-library scenarios. |
131
+ | `deletePromptTemplate` | None — endpoint surface in spec only | n/a yet | Add positive delete + `403` pack-sourced-readonly + `404` unknown + `501` not-mutable-library scenarios. |
132
+ | `renderPromptTemplate` | `prompt-composed-secret-redaction.test.ts` + `prompt-composed-trust-marker.test.ts` exercise the compose pipeline via the `/v1/host/sample/prompt/compose` host-extension seam; capability-gated. The spec'd `POST /v1/prompts:render` endpoint shares the same composition pipeline (RFC 0028 §A deterministic-render invariant matches RFC 0027 §F replay invariant). | Composition redaction + trust-marker invariants covered via the seam | Add positive `:render` via the spec'd endpoint + `400 prompt_variable_unresolved` + `404 template_not_found` once a reference host implements the route. |
112
133
 
113
134
  ---
114
135
 
@@ -128,4 +149,4 @@ Every OpenAPI operation should have:
128
149
  | P2 | End-to-end webhook signed-delivery test exercising `X-openwop-Signature-Algorithm: v1`. | `webhooks.md` |
129
150
  | P2 | Conformance scenarios that cite normative RFC docs (not just schemas) for the multi-agent surfaces. | RFCS/0002–0007 |
130
151
  | ✅ Closed 2026-05-17 (HV-1) | `agentPackHandoffSchemaValidation.test.ts` verifies RFC 0003 §D — host MUST validate dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef`. Fixture `conformance-agent-pack-handoff-schema-validation` exercises 3 branches (valid-task / invalid-task / mock-return-violation). Capability-gated on `capabilities.agents.{supported,dispatch}`. | RFCS/0003-agent-packs.md §D |
131
- | Placeholders 2026-05-18 (HVMAP-1/2) | RFC 0022 (`Draft`) ships 4 `it.todo()` placeholder scenarios: `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`, `subworkflow-input-mapping.test.ts`. Fixtures: `conformance-dispatch-input-mapping`, `-output-mapping`, `-cross-worker-handoff`, `conformance-subworkflow-input-mapping`. Promote to live assertions when RFC 0022 reaches `Active` AND a reference host advertises `capabilities.agents.dispatchMapping` and/or `capabilities.subWorkflow.inputMapping`. | RFCS/0022-dispatch-input-output-mapping.md §A + §B |
152
+ | Closed 2026-05-19 (HVMAP-1/2) | RFC 0022 conformance fully landed across two cycles: 2026-05-18 promoted HVMAP-1a/1b/1c/2 happy paths from `it.todo()` to live behavioral tests against the Postgres reference host (advertising `capabilities.agents.dispatchMapping: true` + `capabilities.subWorkflow.inputMapping: true`); 2026-05-19 promoted all remaining negative-path cases — HVMAP-1a-null, HVMAP-1a-refusal, HVMAP-1b-failed, HVMAP-1b-cancelled, HVMAP-1c-override, HVMAP-2-unset, HVMAP-2-no-midrun-propagation, HVMAP-2-refusal via the new capability-toggle seam (`conformance/src/lib/host-toggle.ts` + `POST /v1/host/sample/test/capability-toggle`) and 5 new fixtures (`-no-default` variants, `-per-worker-override`, `-deterministic-fail-child`, `-cancellable-child`). Republished as `@openwop/openwop-conformance@1.3.0`. | RFCS/0022-dispatch-input-output-mapping.md §A + §B + §C |
@@ -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
+ }