@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.
- package/CHANGELOG.md +156 -1
- package/README.md +3 -2
- package/api/asyncapi.yaml +8 -0
- package/api/openapi.yaml +371 -1
- package/api/redocly.yaml +15 -0
- package/coverage.md +26 -5
- package/fixtures/conformance-agent-reasoning-streaming.json +37 -0
- package/fixtures/conformance-dispatch-cancellable-child.json +27 -0
- package/fixtures/conformance-dispatch-deterministic-fail-child.json +30 -0
- package/fixtures/conformance-dispatch-input-mapping-no-default.json +49 -0
- package/fixtures/conformance-dispatch-per-worker-override.json +59 -0
- package/fixtures/conformance-envelope-nl-to-format-engaged.json +41 -0
- package/fixtures/conformance-envelope-recovery-applied.json +39 -0
- package/fixtures/conformance-envelope-refusal.json +38 -0
- package/fixtures/conformance-envelope-retry-attempted.json +39 -0
- package/fixtures/conformance-envelope-retry-exhausted.json +38 -0
- package/fixtures/conformance-envelope-truncated.json +39 -0
- package/fixtures/conformance-envelope-truncation-cap-exhaustion.json +39 -0
- package/fixtures/conformance-model-capability-insufficient.json +25 -0
- package/fixtures/conformance-multi-agent-confidence-escalation.json +49 -0
- package/fixtures/conformance-multi-agent-handoff-child.json +27 -0
- package/fixtures/conformance-multi-agent-handoff.json +49 -0
- package/fixtures/conformance-prompt-all-four-kinds.json +39 -0
- package/fixtures/conformance-prompt-end-to-end.json +33 -0
- package/fixtures/conformance-subworkflow-input-mapping-no-default.json +33 -0
- package/fixtures/conformance-subworkflow-mid-run-mutation-child.json +31 -0
- package/fixtures/conformance-subworkflow-mid-run-mutation.json +33 -0
- package/fixtures/openwop-smoke-cost-emit.json +37 -0
- package/fixtures/prompt-templates/conformance-prompt-few-shot-2.json +14 -0
- package/fixtures/prompt-templates/conformance-prompt-few-shot.json +14 -0
- package/fixtures/prompt-templates/conformance-prompt-schema-hint.json +14 -0
- package/fixtures/prompt-templates/conformance-prompt-secret-redaction.json +23 -0
- package/fixtures/prompt-templates/conformance-prompt-trust-marker.json +23 -0
- package/fixtures/prompt-templates/conformance-prompt-writer-system.json +15 -0
- package/fixtures/prompt-templates/conformance-prompt-writer-user.json +15 -0
- package/fixtures.md +45 -0
- package/package.json +1 -1
- package/schemas/README.md +5 -0
- package/schemas/agent-manifest.schema.json +16 -0
- package/schemas/capabilities.schema.json +390 -0
- package/schemas/core-conformance-mock-agent-config.schema.json +5 -0
- package/schemas/envelopes/clarification.request.schema.json +9 -0
- package/schemas/envelopes/error.schema.json +4 -0
- package/schemas/envelopes/schema.request.schema.json +4 -0
- package/schemas/envelopes/schema.response.schema.json +1 -1
- package/schemas/node-pack-manifest.schema.json +28 -0
- package/schemas/orchestrator-decision.schema.json +12 -0
- package/schemas/prompt-kind.schema.json +8 -0
- package/schemas/prompt-pack-manifest.schema.json +80 -0
- package/schemas/prompt-ref.schema.json +40 -0
- package/schemas/prompt-template.schema.json +149 -0
- package/schemas/registry-version-manifest.schema.json +5 -0
- package/schemas/run-ancestry-response.schema.json +54 -0
- package/schemas/run-event-payloads.schema.json +513 -11
- package/schemas/run-event.schema.json +17 -1
- package/schemas/run-snapshot.schema.json +3 -2
- package/schemas/workflow-definition.schema.json +19 -1
- package/src/lib/driver.ts +15 -0
- package/src/lib/env.ts +51 -0
- package/src/lib/event-log-query.ts +62 -0
- package/src/lib/fixtures.ts +38 -1
- package/src/lib/host-toggle.ts +54 -0
- package/src/lib/llm-cache-key-recipe.ts +68 -0
- package/src/lib/multi-agent-capabilities.ts +10 -0
- package/src/lib/otel-scrape.ts +59 -0
- package/src/scenarios/agentReasoningStreaming.test.ts +193 -0
- package/src/scenarios/aiEnvelope.capBreached.test.ts +97 -9
- package/src/scenarios/aiEnvelope.contractRefusal.test.ts +224 -15
- package/src/scenarios/aiEnvelope.correlationReplay.test.ts +257 -25
- package/src/scenarios/aiEnvelope.redaction.test.ts +210 -29
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +163 -24
- package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +262 -12
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +107 -16
- package/src/scenarios/blob-presign-expiry.test.ts +42 -9
- package/src/scenarios/blob-roundtrip.test.ts +0 -0
- package/src/scenarios/cache-ttl-expiry.test.ts +34 -8
- package/src/scenarios/cost-attribution.test.ts +124 -11
- package/src/scenarios/cross-engine-append-ordering.test.ts +99 -0
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +136 -0
- package/src/scenarios/cross-host-causation-shape.test.ts +117 -0
- package/src/scenarios/cross-host-traceparent-propagation.test.ts +60 -0
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +34 -3
- package/src/scenarios/dispatch-input-mapping.test.ts +75 -6
- package/src/scenarios/dispatch-output-mapping.test.ts +96 -6
- package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +223 -0
- package/src/scenarios/envelope-nl-to-format-engaged.test.ts +152 -0
- package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +343 -0
- package/src/scenarios/envelope-reasoning-shape.test.ts +190 -0
- package/src/scenarios/envelope-recovery-applied.test.ts +229 -0
- package/src/scenarios/envelope-refusal-shape.test.ts +289 -0
- package/src/scenarios/envelope-retry-attempted.test.ts +258 -0
- package/src/scenarios/envelope-retry-exhausted.test.ts +168 -0
- package/src/scenarios/envelope-tier-one-subset-static.test.ts +229 -0
- package/src/scenarios/envelope-truncated.test.ts +136 -0
- package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +144 -0
- package/src/scenarios/envelope-variant-discriminator-static.test.ts +152 -0
- package/src/scenarios/fixtures-gating.test.ts +139 -1
- package/src/scenarios/fixtures-valid.test.ts +123 -15
- package/src/scenarios/kv-ttl-expiry.test.ts +40 -9
- package/src/scenarios/model-capability-insufficient.test.ts +221 -0
- package/src/scenarios/model-capability-substituted.test.ts +203 -0
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +164 -0
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +167 -0
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +124 -0
- package/src/scenarios/multi-region-idempotency.test.ts +58 -0
- package/src/scenarios/node-module-required-capabilities-shape.test.ts +185 -0
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +19 -0
- package/src/scenarios/pack-registry-publish.test.ts +231 -51
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +198 -0
- package/src/scenarios/prompt-composed-secret-redaction.test.ts +178 -0
- package/src/scenarios/prompt-composed-trust-marker.test.ts +165 -0
- package/src/scenarios/prompt-end-to-end-events.test.ts +202 -0
- package/src/scenarios/prompt-list-and-fetch.test.ts +207 -0
- package/src/scenarios/prompt-mutable-lifecycle.test.ts +216 -0
- package/src/scenarios/prompt-pack-install.test.ts +187 -0
- package/src/scenarios/prompt-render-deterministic.test.ts +240 -0
- package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +140 -0
- package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +172 -0
- package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +144 -0
- package/src/scenarios/prompt-template-shape.test.ts +359 -0
- package/src/scenarios/provider-usage.test.ts +185 -0
- package/src/scenarios/queue-ack-nack-dlq.test.ts +64 -10
- package/src/scenarios/queue-publish-consume-roundtrip.test.ts +50 -10
- package/src/scenarios/replay-divergence-at-refusal.test.ts +134 -0
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +197 -0
- package/src/scenarios/replay-llm-cache-key.test.ts +127 -25
- package/src/scenarios/replay-observable-sequence-determinism.test.ts +80 -0
- package/src/scenarios/sandbox-capability-gate-respected.test.ts +31 -0
- package/src/scenarios/sandbox-memory-cap.test.ts +61 -0
- package/src/scenarios/sandbox-no-cross-pack-mutation.test.ts +35 -0
- package/src/scenarios/sandbox-no-host-env-leak.test.ts +38 -0
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +91 -0
- package/src/scenarios/sandbox-no-host-process-escape.test.ts +30 -0
- package/src/scenarios/sandbox-no-network-escape.test.ts +49 -0
- package/src/scenarios/sandbox-timeout-cap.test.ts +61 -0
- package/src/scenarios/search-bm25-roundtrip.test.ts +54 -9
- package/src/scenarios/spec-corpus-validity.test.ts +34 -6
- package/src/scenarios/sql-transaction-atomicity.test.ts +37 -8
- package/src/scenarios/stream-subscribe-from-beginning.test.ts +46 -9
- package/src/scenarios/subworkflow-input-mapping.test.ts +146 -10
- package/src/scenarios/table-cursor-pagination.test.ts +47 -9
- package/src/scenarios/table-schema-enforcement.test.ts +46 -9
- package/src/scenarios/vector-knn-roundtrip.test.ts +50 -10
- 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
|
-
|
|
|
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
|
-
|
|
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`
|
|
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
|
-
|
|
|
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
|
+
}
|