@openwop/openwop-conformance 1.6.0 → 1.10.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 +18 -0
- package/README.md +2 -2
- package/api/asyncapi.yaml +74 -1
- package/api/openapi.yaml +316 -0
- package/coverage.md +16 -0
- package/fixtures/conformance-run-duration-breach.json +33 -0
- package/fixtures.md +19 -0
- package/package.json +1 -1
- package/schemas/README.md +12 -0
- package/schemas/agent-inventory-response.schema.json +90 -0
- package/schemas/ai-envelope.schema.json +28 -0
- package/schemas/annotation-create.schema.json +37 -0
- package/schemas/annotation.schema.json +56 -0
- package/schemas/artifact-type-pack-manifest.schema.json +160 -0
- package/schemas/capabilities.schema.json +195 -4
- package/schemas/chat-card-pack-manifest.schema.json +158 -0
- package/schemas/envelopes/media.audio.schema.json +38 -0
- package/schemas/envelopes/media.file.schema.json +37 -0
- package/schemas/envelopes/media.image.schema.json +33 -0
- package/schemas/heartbeat-evaluated.schema.json +14 -0
- package/schemas/heartbeat-state-changed.schema.json +14 -0
- package/schemas/node-pack-manifest.schema.json +16 -1
- package/schemas/run-event-payloads.schema.json +96 -5
- package/schemas/run-event.schema.json +4 -0
- package/schemas/workflow-definition.schema.json +5 -0
- package/schemas/workspace-file-create.schema.json +20 -0
- package/schemas/workspace-file.schema.json +39 -0
- package/src/lib/agentLoop.ts +44 -0
- package/src/lib/agentRuntime.ts +45 -0
- package/src/lib/artifactTypes.ts +96 -0
- package/src/lib/cardPacks.ts +52 -0
- package/src/lib/discovery-capabilities.ts +50 -0
- package/src/lib/distillation.ts +38 -0
- package/src/lib/feedback.ts +31 -0
- package/src/lib/heartbeat.ts +31 -0
- package/src/lib/memoryAttribution.ts +48 -0
- package/src/lib/subRunAttestation.ts +35 -0
- package/src/lib/toolHooks.ts +33 -0
- package/src/scenarios/agent-loop-iteration-monotonic.test.ts +33 -0
- package/src/scenarios/agent-loop-stateful-resume.test.ts +28 -0
- package/src/scenarios/agent-loop-version5-shape.test.ts +41 -0
- package/src/scenarios/agent-loop-workspace-snapshot.test.ts +33 -0
- package/src/scenarios/agent-manifest-runtime.test.ts +85 -0
- package/src/scenarios/ai-envelope-shape.test.ts +14 -18
- package/src/scenarios/aiEnvelope.capBreached.test.ts +2 -1
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +2 -1
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +2 -1
- package/src/scenarios/approval-gate-flow.test.ts +4 -6
- package/src/scenarios/artifact-schema-compile-bounded.test.ts +126 -0
- package/src/scenarios/artifact-type-pack-install.test.ts +78 -0
- package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +140 -0
- package/src/scenarios/artifact-type-store-without-render.test.ts +54 -0
- package/src/scenarios/audit-log-integrity.test.ts +3 -2
- package/src/scenarios/auth-api-key-rotation.test.ts +2 -1
- package/src/scenarios/auth-mtls.test.ts +2 -1
- package/src/scenarios/auth-oauth2-client-credentials.test.ts +2 -1
- package/src/scenarios/auth-oidc-user-bearer.test.ts +2 -1
- package/src/scenarios/auth-saml-profile.test.ts +2 -1
- package/src/scenarios/auth-scim-profile.test.ts +2 -1
- package/src/scenarios/authorization-fail-closed.test.ts +2 -1
- package/src/scenarios/authorization-roles-shape.test.ts +2 -1
- package/src/scenarios/byok-auth-modes.test.ts +141 -0
- package/src/scenarios/chat-card-pack-execution.test.ts +56 -0
- package/src/scenarios/chat-card-pack-manifest-validation.test.ts +128 -0
- package/src/scenarios/commitment-fired.test.ts +83 -0
- package/src/scenarios/credential-payload-redaction.test.ts +2 -1
- package/src/scenarios/credentials-capability-shape.test.ts +2 -1
- package/src/scenarios/cross-engine-append-ordering.test.ts +2 -1
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +3 -2
- package/src/scenarios/cross-host-causation-shape.test.ts +3 -2
- package/src/scenarios/deadletter-capability-shape.test.ts +2 -1
- package/src/scenarios/deadletter-retry-exhaustion.test.ts +2 -1
- package/src/scenarios/distillation-index-roundtrip.test.ts +35 -0
- package/src/scenarios/distillation-secret-carryforward.test.ts +35 -0
- package/src/scenarios/distillation-shape.test.ts +41 -0
- package/src/scenarios/distillation-stable-archive.test.ts +37 -0
- package/src/scenarios/distillation-token-budget.test.ts +45 -0
- package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +4 -3
- package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +5 -4
- package/src/scenarios/envelope-reasoning-shape.test.ts +3 -2
- package/src/scenarios/envelope-refusal-shape.test.ts +3 -2
- package/src/scenarios/envelope-rendering-hint.test.ts +95 -0
- package/src/scenarios/envelope-retry-attempted.test.ts +2 -1
- package/src/scenarios/envelope-tier-one-subset-static.test.ts +3 -2
- package/src/scenarios/exec-not-protocol-tier.test.ts +137 -0
- package/src/scenarios/experimental-tier-shape.test.ts +5 -4
- package/src/scenarios/feedback-capability-shape.test.ts +35 -0
- package/src/scenarios/feedback-correction-redaction.test.ts +35 -0
- package/src/scenarios/feedback-cross-tenant-isolation.test.ts +37 -0
- package/src/scenarios/feedback-fork-not-copied.test.ts +40 -0
- package/src/scenarios/feedback-on-terminal-run.test.ts +32 -0
- package/src/scenarios/feedback-record-and-list.test.ts +32 -0
- package/src/scenarios/feedback-unsupported-501.test.ts +32 -0
- package/src/scenarios/fs-path-traversal.test.ts +2 -1
- package/src/scenarios/heartbeat-capability-shape.test.ts +35 -0
- package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +28 -0
- package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +43 -0
- package/src/scenarios/heartbeat-runtime-bound.test.ts +30 -0
- package/src/scenarios/http-client-ssrf.test.ts +10 -13
- package/src/scenarios/mcp-toolcall-redaction.test.ts +3 -2
- package/src/scenarios/media-url-inline-cap.test.ts +167 -0
- package/src/scenarios/memory-attribution-emits-on-write.test.ts +54 -0
- package/src/scenarios/memory-attribution-no-content.test.ts +45 -0
- package/src/scenarios/memory-attribution-replay-stable.test.ts +60 -0
- package/src/scenarios/memory-attribution-shape.test.ts +28 -0
- package/src/scenarios/memory-attribution-tenant-scoped.test.ts +44 -0
- package/src/scenarios/memory-compaction-event-emitted.test.ts +2 -1
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +2 -1
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +2 -1
- package/src/scenarios/memory-consolidation-idempotent.test.ts +77 -0
- package/src/scenarios/memory-consolidation-shape.test.ts +90 -0
- package/src/scenarios/model-capability-substituted.test.ts +2 -1
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +5 -4
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +6 -5
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +4 -3
- package/src/scenarios/multi-region-idempotency.test.ts +10 -10
- package/src/scenarios/oauth-capability-shape.test.ts +2 -1
- package/src/scenarios/oauth-connector-redaction.test.ts +2 -1
- package/src/scenarios/pause-resume.test.ts +3 -3
- package/src/scenarios/production-backpressure.test.ts +2 -2
- package/src/scenarios/production-retention-expiry.test.ts +2 -2
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +2 -1
- package/src/scenarios/prompt-composed-secret-redaction.test.ts +2 -1
- package/src/scenarios/prompt-composed-trust-marker.test.ts +2 -1
- package/src/scenarios/prompt-end-to-end-events.test.ts +2 -1
- package/src/scenarios/prompt-list-and-fetch.test.ts +2 -1
- package/src/scenarios/prompt-mutable-lifecycle.test.ts +2 -1
- package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +2 -1
- package/src/scenarios/prompt-pack-install.test.ts +2 -1
- package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +2 -1
- package/src/scenarios/prompt-render-deterministic.test.ts +2 -1
- package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +2 -1
- package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +2 -1
- package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +2 -1
- package/src/scenarios/prompt-template-shape.test.ts +2 -1
- package/src/scenarios/provider-usage.test.ts +2 -1
- package/src/scenarios/redaction.test.ts +4 -1
- package/src/scenarios/replay-divergence-at-refusal.test.ts +4 -3
- package/src/scenarios/replay-fork-arbitrary.test.ts +3 -1
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +2 -1
- package/src/scenarios/replayDeterminism.test.ts +3 -1
- package/src/scenarios/run-execution-bounds-shape.test.ts +133 -0
- package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
- package/src/scenarios/sandbox-mvp-behavior.test.ts +2 -1
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +2 -1
- package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
- package/src/scenarios/scheduling-capability-shape.test.ts +2 -1
- package/src/scenarios/scheduling-cron-fires-once.test.ts +2 -1
- package/src/scenarios/secret-leakage-otel-attribute.test.ts +7 -6
- package/src/scenarios/spec-corpus-validity.test.ts +4 -1
- package/src/scenarios/subrun-approval-fail-closed.test.ts +33 -0
- package/src/scenarios/subrun-approval-gate.test.ts +35 -0
- package/src/scenarios/subrun-attestation-shape.test.ts +30 -0
- package/src/scenarios/subrun-checksum-stable.test.ts +43 -0
- package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +39 -0
- package/src/scenarios/tool-hooks-content-free.test.ts +40 -0
- package/src/scenarios/tool-hooks-rate-limit.test.ts +32 -0
- package/src/scenarios/tool-hooks-secret-redaction.test.ts +34 -0
- package/src/scenarios/tool-hooks-shape.test.ts +34 -0
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -10
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +2 -2
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +2 -2
- package/src/scenarios/wasm-pack-load.test.ts +2 -2
- package/src/scenarios/wasm-pack-memory-cap.test.ts +3 -6
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -2
- package/src/scenarios/workflow-primary-output-annotation.test.ts +142 -0
- package/src/scenarios/workspace-behavior.test.ts +134 -0
- package/src/scenarios/workspace-capability-shape.test.ts +73 -0
- package/src/scenarios/workspace-cross-tenant-isolation.test.ts +84 -0
package/coverage.md
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
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
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
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
|
+
| Multimodal envelope variants (RFC 0055 — `spec/v1/ai-envelope.md` §"Rendering hints" + §"Media reference payloads") | `envelope-rendering-hint.test.ts`, `media-url-inline-cap.test.ts` | A (always-on schema shape across §B + §C; live media store→serve→tenant-scoping behavioral assertions against the reference-host seam, soft-skip offline) | **RFC 0055 promoted Draft → Active 2026-05-25.** §B: `envelope-rendering-hint` (always-on, server-free Ajv) asserts the optional `meta.rendering` hint on the `EnvelopeMeta` $def — well-formed hint validates; omitting it still validates (optionality); unknown `display` rejected by the closed enum; unknown property rejected (additionalProperties:false). Consumer-fallback rendering is exercised app-side (`chat/MessageRenderer.tsx`). §C: `media-url-inline-cap` compiles + round-trips the three `media.{image,audio,file}` payload schemas, asserts `aiProviders.maxInlineMediaBytes` shape, and (live, vs. the reference host's `POST /v1/host/sample/media/put` + public token-authed `GET /v1/host/sample/assets/{token}` seam) verifies a stored asset is served by a tenant-scoped URL and an unminted/guessed token does not resolve — the `media-asset-url-tenant-scoped` SECURITY invariant. §A capability vocabulary (`vision-input`/`audio-input`/`audio-output`/`image-output`) is registered in the open `modelCapabilities.advertised` prose registry; a host advertises a given identifier only when its model supports it (the reference mock model advertises none). Reference host advertises `media.*` in `supportedEnvelopes`/`schemaVersions` + `maxInlineMediaBytes` + serves assets. `Active → Accepted` awaits a non-steward host. |
|
|
41
42
|
| 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
43
|
| 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
44
|
| Multi-agent execution model + handoff state machine (RFC 0037 — `spec/v1/multi-agent-execution.md`, `version: 1`) | `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 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. |
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
| Experimental capability tier (RFC 0042 — `schemas/capabilities.schema.json` §`multiAgent.executionModel.tier`) | **`experimental-tier-shape.test.ts` (2026-05-22)** | A (6 server-free + helper-routing assertions across §A schema discipline + §D experimentalGate routing; always-on for hosts that advertise tier='experimental' on any capability sub-block; helper-level behavioral probes for the `experimentalGate()` routing under both default + OPENWOP_REQUIRE_EXPERIMENTAL modes) | RFC 0042 (Draft) lands the audit's "Active RFC → carve-out" pattern. Schema diff lands on `multiAgent.executionModel` with optional `tier ∈ {stable, experimental}` + `experimentalUntil` (ISO-8601 sunset) + `if/then` conditional enforcing §B sunset MUST mechanically. New `experimentalGate()` helper in `conformance/src/lib/behavior-gate.ts` routes scenarios under default mode + `OPENWOP_REQUIRE_EXPERIMENTAL=true` strict-mode. |
|
|
49
50
|
| Sandbox MVP behavioral close-out (RFC 0035 §B) | **`sandbox-mvp-behavior.test.ts` (2026-05-22)** | A (10 capability-gated behavioral assertions covering 7 of 8 §B failure-mode invariants — 5 escape kinds + timeout + memory-exceeded + cross-pack-mutation isolation + capability-gate-violation + 2 well-behaved baselines; all 10 PASS against the workflow-engine's node:vm-based sandbox MVP) | Companion to the existing 8 advertisement-shape sandbox scenarios (`sandbox-no-host-fs-escape.test.ts` et al.). Exercises the canonical 4-code error catalog at `spec/v1/host-capabilities.md` §"Error codes" (`sandbox_escape_attempt` + `sandbox_capability_denied` + `sandbox_memory_exceeded` + `sandbox_timeout`) with spec-mandated `details.{escapeKind, requestedCapability, requestedBytes}` populated. Wire-shape per `spec/v1/host-sample-test-seams.md §8`. Production adopters use wasmtime/nsjail behind the same HTTP test-seam contract. |
|
|
50
51
|
| RFC 0041 §B replay-divergence-at-refusal behavioral (`version: 4`) | `replay-divergence-at-refusal.test.ts` (advertisement-shape + behavioral; 3 assertions PASS against workflow-engine when the `multiAgent.executionModel.version: 4` advertisement is enabled) | A (was `it.todo` until 2026-05-23 when the executor wiring landed — see commit `1fce55a` + `bba3b4a`. Behavioral assertions cover both divergence directions: original=valid + replay=refusal AND original=refusal + replay=valid) | Closes Track #4 of the 2026-05-22 multi-agent behavioral-harness close-out. Reference workflow-engine emits `replay.divergedAtRefusal` event + fails run with `error.code: 'replay_diverged_at_refusal'` when source vs replay envelope kinds differ at the same nodeId. Gated on `OPENWOP_MULTI_AGENT_EXECUTION_MODEL_PHASE_4=true` AND `run.forkMode === 'replay'`. Path-to-Accepted for RFC 0041: non-steward host advertises `multiAgent.executionModel.version: 4` end-to-end. |
|
|
52
|
+
| Agent-manifest runtime floor (RFC 0070 — `capabilities.agents.manifestRuntime`) | `agent-manifest-runtime.test.ts` | B (capability-gated; lists ≥1 installed manifest agent + dispatches one with attributed `agent.reasoned`+`agent.decided` events, plus a §F sub-threshold-escalation assertion) | RFC 0070 filed Draft 2026-05-26. Gated on `capabilities.agents.manifestRuntime.supported` + the host dispatch seam (`POST /v1/host/sample/agents/{agentId}/dispatch`); soft-skips when either is absent. The reference **workflow-engine** host advertises `manifestRuntime: { supported: true, handoffValidation: true }`, loads pack `agents[]` (RFC 0003 `installAgents`) into an AgentRegistry at boot, and dispatches end-to-end (toolAllowlist-filtered per RFC 0002 §A14, handoff-validated per RFC 0003 §D, confidence-escalating per §F) — see `apps/workflow-engine/backend/typescript/test/agent-dispatch-route.test.ts` (6 HTTP assertions, incl. the normative inventory). **RFC 0072 (`Draft`):** the scenario's inventory leg now drives the NORMATIVE `GET /v1/agents` (§A) so it runs black-box against any conformant host; the dispatch leg stays on the sample seam (soft-skips off-steward) pending the executor-integration tier. RFC 0072 §C `peerDependenciesMeta` disposition + `degraded[]` are unit-tested in `agent-loader.test.ts`. Path to `Active → Accepted` (RFC 0070): a non-steward host advertises `manifestRuntime` + serves `GET /v1/agents`. |
|
|
51
53
|
|
|
52
54
|
---
|
|
53
55
|
|
|
@@ -91,7 +93,17 @@ Twenty-two scenario groups validate optional profiles where the host's discovery
|
|
|
91
93
|
| `scheduling-capability-shape.test.ts` | `capabilities.scheduling` (RFC 0052 §A, `host-capabilities.md` §host.scheduling) | A (advertisement shape always — `supported` boolean; `cron`/`delayed`/`calendar` booleans; `maxFutureHorizon` ISO-8601 duration) | `host-pending` | Always runs; asserts the block is absent or well-formed. |
|
|
92
94
|
| `scheduling-cron-fires-once.test.ts` | `capabilities.scheduling` (RFC 0052 §B) | A (once-per-tick + missed-tick MUST-NOT via optional `POST /v1/host/sample/scheduling/tick` seam — single tick fires exactly one run; missed window never floods) | `host-pending` | Capability-gated on `scheduling.supported` + `cron`; soft-skips on 404. Delayed-horizon + calendar scenarios deferred. |
|
|
93
95
|
| `deadletter-capability-shape.test.ts` | `capabilities.deadLetter` (RFC 0053 §A, `host-capabilities.md` §host.deadLetter) | A (advertisement shape always — `supported` boolean; `retentionDays` integer ≥ 1) | `host-pending` | Always runs; asserts the block is absent or well-formed. |
|
|
96
|
+
| `run-execution-bounds-shape.test.ts` | `capabilities.limits.{maxRunDurationMs,maxLoopIterations}` + `cap.breached` kinds `run-duration` / `loop-iterations` (RFC 0058, `run-options.md` §Reserved keys) | A (advertisement shape always — `maxRunDurationMs` integer ≥ 1000; `maxLoopIterations` integer ≥ 1; run-duration breach gated on the `conformance-run-duration-breach` fixture) | `host-pending` | Shape always runs; the run-duration breach behavior soft-skips until a host enforces wall-clock timeouts (mirrors RFC 0052 scheduling). |
|
|
97
|
+
| `workspace-capability-shape.test.ts` | `capabilities.workspace` (RFC 0059 §A, `agent-workspace.md` §"Capability advertisement") + the four workspace operations `listWorkspaceFiles` / `getWorkspaceFile` / `putWorkspaceFile` / `deleteWorkspaceFile` (`/v1/host/workspace/files[/{path}]`) | A (advertisement shape always — `supported` boolean; `maxFileBytes`/`maxFiles`/`maxVersions` integers ≥ 1 when present) | in-memory ✅ | Always runs; asserts the block is absent or well-formed. The in-memory reference host advertises `capabilities.workspace.supported` (RFC 0059 M2). |
|
|
98
|
+
| `workspace-behavior.test.ts` | RFC 0059 §C/§D (`agent-workspace.md` §"§C — Endpoints" / §"§D — Run-time exposure") — `/v1/host/workspace/files[/{path}]` | B (capability-gated on `workspace.supported`: CRUD round-trip + `If-Match` 409 `workspace_conflict` with `details.currentVersion` + `workspace_too_large` over `maxFileBytes` + the run-start workspace snapshot on the run snapshot) | in-memory ✅ | Soft-skips when `workspace.supported` is unadvertised. |
|
|
99
|
+
| `workspace-cross-tenant-isolation.test.ts` | RFC 0059 §E WCT-1 (`agent-workspace.md` §"§E — Invariants") + `SECURITY/invariants.yaml` `workspace-cross-tenant-isolation` | B (capability-gated + seam-gated: a file owned by `{tenant, workspace}` MUST NOT be readable via `get`/`list` under a different owner — drives `POST /v1/host/sample/workspace/op`) | in-memory ✅ | Public test for the `workspace-cross-tenant-isolation` invariant; soft-skips when the seam is unwired (404). |
|
|
94
100
|
| `deadletter-retry-exhaustion.test.ts` | `capabilities.deadLetter` (RFC 0053 §C) + `run.dead_lettered` event | A (retry-exhaustion → `run.dead_lettered` with `attempts` + dead-lettered run fork-eligible, via optional `POST /v1/host/sample/deadletter/exhaust` seam) | `host-pending` | Capability-gated on `deadLetter.supported`; soft-skips on 404. Retention-purge scenario deferred (needs clock seam). |
|
|
101
|
+
| `artifact-type-pack-manifest-validation.test.ts` | `artifact-type-pack-manifest.schema.json` (RFC 0071 Phase 1, `artifact-type-packs.md` §"Manifest format") | Server-free (positive + 5 negatives: mixed-kind / empty `artifactTypes` / bad `artifactTypeId` pattern / unknown `rendering.display` / non-conforming `exportFormats`) | host-pass (server-free) | Always runs; no host needed. |
|
|
102
|
+
| `artifact-schema-compile-bounded.test.ts` | RFC 0071 §"Bounded schema compilation" + `SECURITY/invariants.yaml` `artifact-schema-compile-bounded` | Server-free (contract-present in corpus + a reference finite bound rejects `$ref`-depth / keyword-count / size bombs, admits benign schemas) | host-pass (server-free floor) | Public test for the `artifact-schema-compile-bounded` invariant. Behavioral form (host rejects an over-bounds pack at registry `PUT` with `pack_validation_failed`) gated on `host.artifactTypes.supported`. |
|
|
103
|
+
| `artifact-type-pack-install.test.ts` | `host.artifactTypes` (RFC 0071 Phase 1, `host-capabilities.md` §host.artifactTypes) | A (install + produce → `artifact.created { registered: true }` after schema validation; schema-violating payload rejected, via the `POST /v1/host/sample/artifacttypes/{install,produce}` seam) | MyndHyve ✅ · in-memory ✅ | Capability-gated on `host.artifactTypes.supported`. PASS against MyndHyve `workflow-runtime-00396-cuj` (production) AND the in-memory reference host (store-only seam, RFC 0075 P2-1); soft-skips on hosts that don't advertise. |
|
|
104
|
+
| `artifact-type-store-without-render.test.ts` | `host.artifactTypes` (RFC 0071 §host.artifactTypes — store/render negotiation) | A (a `store:true,render:false` host stores the artifact + completes the run; never fails for lack of a renderer) | in-memory ✅ | **Exercised end-to-end (RFC 0075 P2-1):** the in-memory reference host advertises `host.artifactTypes { store:true, render:false }` and implements the produce seam — a registered, schema-valid artifact is stored and the run completes with `rendered:false`. MyndHyve (`render:true`) honestly soft-skips this path; the in-memory store-only host is the one that actually verifies the negotiation. |
|
|
105
|
+
| `chat-card-pack-manifest-validation.test.ts` | `chat-card-pack-manifest.schema.json` (RFC 0071 Phase 2, `chat-card-packs.md` §"Manifest format") | Server-free (positive + 5 negatives: mixed-kind / empty `cards` / bad `cardTypeId` / missing `prompt` / non-portable `inputs[].type`; + positive `vendor.*` extension + the full portable `inputs[].type` subset incl. `multiselect`/`file`, G9) | host-pass (server-free) | Always runs; no host needed. Behavioral execution lives in the sibling scenario below. |
|
|
106
|
+
| `chat-card-pack-execution.test.ts` | `host.chat.cardPacks` (RFC 0071 Phase 2, `chat-card-packs.md` §"Card execution" / §"Trust boundary") + `SECURITY/invariants.yaml` `chat-card-input-trust-boundary` | A (output validated against the linked `outputArtifactType` → `artifact.created { registered: true }`; **card-input-derived prompt content propagates `contentTrust:"untrusted"`** — the R2 proof, via `POST /v1/host/sample/cardpacks/execute` seam) | MyndHyve ✅ | **Phase 2 `Accepted` 2026-05-27.** PASS against MyndHyve `workflow-runtime-00402-bey` (real `core.chat.cardExecute` → `ctx.aiEnvelope.generate`; `host.chat.cardPacks` + `host.aiEnvelope` advertised unconditionally on production, steward-curl-verified). Capability-gated on `host.chat.cardPacks.supported`; soft-skips on hosts that don't advertise. |
|
|
95
107
|
| `kv-cross-tenant-isolation.test.ts`, `kv-atomic-increment.test.ts`, `kv-cas.test.ts` (three scenarios) | `capabilities.kvStorage` (RFC 0015, `host-kv-storage-capability.md`) + `SECURITY/invariants.yaml` `kv-cross-tenant-isolation` | A (advertisement shape always; behavioral cross-tenant `set`/`get`, 50× concurrent atomic increment convergence, CAS matching/stale-expect) | host-pass via opt-in test seam | Reference host exposes `POST /v1/host/sample/test/surface` env-gated on `OPENWOP_TEST_SEAM_ENABLED=true`; hosts that don't expose the seam soft-skip the behavioral assertions and verify advertisement shape only. |
|
|
96
108
|
| `table-cross-tenant-isolation.test.ts` | `capabilities.tableStorage` (RFC 0016, `host-table-storage-capability.md`) | A (advertisement shape + behavioral cross-tenant insert/query proof) | host-pass via opt-in test seam | Same seam dependency as kv row. |
|
|
97
109
|
| `queue-cross-tenant-isolation.test.ts` | `capabilities.queueBus` (RFC 0017, `host-queue-bus-capability.md`) + `SECURITY/invariants.yaml` `queue-cross-tenant-isolation` | A (advertisement shape + behavioral cross-tenant publish/consume proof) | host-pass via opt-in test seam | Same seam dependency as kv row. |
|
|
@@ -133,6 +145,8 @@ Every OpenAPI operation should have:
|
|
|
133
145
|
| `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. |
|
|
134
146
|
| `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. |
|
|
135
147
|
| `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. |
|
|
148
|
+
| `listAgents` | `agent-manifest-runtime.test.ts` (RFC 0072 §A); capability-gated on `capabilities.agents.manifestRuntime.supported` | Normative `GET /v1/agents` inventory leg — lists ≥1 installed manifest agent; soft-skips (404) when unadvertised | Black-box across hosts; dispatch leg via sample seam pending the executor-integration tier. |
|
|
149
|
+
| `getAgent` | `agent-manifest-runtime.test.ts` (RFC 0072 §A) + `agent-dispatch-route.test.ts` (reference host) | One manifest agent's inventory entry + 404 for unknown | Covered against the workflow-engine reference host. |
|
|
136
150
|
| `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. |
|
|
137
151
|
| `pollRunEvents` | `multi-node-ordering.test.ts`, `version-negotiation.test.ts`, redaction tests | Past-end and validation assertions | Good. Add malformed `lastSequence` if missing. |
|
|
138
152
|
| `cancelRun` | `cancellation.test.ts` | Unknown/terminal idempotency cases partial | Add explicit already-terminal cancel behavior. |
|
|
@@ -141,6 +155,8 @@ Every OpenAPI operation should have:
|
|
|
141
155
|
| `pauseRun` | `pause-resume.test.ts` covers direct route behavior for running → paused, idempotent re-pause, terminal conflict, and pause-during-suspend race | Conflict and race paths covered with `details.runStatus`; endpoint is no longer coverage-missing | Add explicit immediate-vs-drain-current-node policy assertion when a host advertises both drain policies. |
|
|
142
156
|
| `resumeRun` | `pause-resume.test.ts` covers direct route behavior for paused → running and non-paused conflict | Conflict path covered with `details.runStatus`; endpoint is no longer coverage-missing | Good. |
|
|
143
157
|
| `forkRun` | `replay-fork.test.ts`, `replayDeterminism.test.ts` | Negative `fromSeq`, past-end, unknown source, invalid overlay | Add arbitrary-event fork and retention-expired source. |
|
|
158
|
+
| `createAnnotation` | `feedback-record-and-list.test.ts`, `feedback-on-terminal-run.test.ts`, `feedback-correction-redaction.test.ts` (RFC 0056); gated on `capabilities.feedback.supported`, soft-skip on `501` | `feedback-unsupported-501.test.ts` (501 when unadvertised), `feedback-cross-tenant-isolation.test.ts`, `feedback-fork-not-copied.test.ts` | Capability-gated; full cross-tenant proof needs a multi-tenant auth seam (soft-skips, like `kv-cross-tenant-isolation`). |
|
|
159
|
+
| `listAnnotations` | `feedback-record-and-list.test.ts`, `feedback-cross-tenant-isolation.test.ts` (RFC 0056) | `feedback-correction-redaction.test.ts` (redacted listing), `feedback-fork-not-copied.test.ts` (fork list empty) | Gated on `capabilities.feedback.supported`. |
|
|
144
160
|
| `diffRun` | `run-diff.test.ts` (RFC 0054); soft-skips on 404 when the endpoint is unimplemented | Self-diff `divergedAtSeq: null`/empty (determinism floor), two-fixture divergence with `eventDiffs[0].seq === divergedAtSeq`, response-shape + `stateDiff` redaction-safety, `400` (missing `against`) + `404` (nonexistent `against`) | Add a bespoke deterministically-divergent fork fixture for `divergedAtSeq === N`-at-a-chosen-seq; full cross-principal `403` needs a multi-principal harness. |
|
|
145
161
|
| `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. |
|
|
146
162
|
| `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. |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-run-duration-breach",
|
|
3
|
+
"name": "Conformance: Run-Duration Breach (RFC 0058)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "Single delay node that sleeps far longer than a small `RunOptions.configurable.runTimeoutMs`. Run with `runTimeoutMs: 1000` on a host advertising `capabilities.limits.maxRunDurationMs` to trigger the wall-clock breach — verifies `cap.breached {kind: 'run-duration'}` emission (observed > limit) + terminal `failed` with `error.code = 'run_timeout'`. Spec: run-options.md §runTimeoutMs + capabilities.md §'Engine-enforced limits' + RFC 0058.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "wait",
|
|
9
|
+
"typeId": "core.delay",
|
|
10
|
+
"name": "Wait",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {
|
|
14
|
+
"delayMs": { "type": "variable", "variableName": "delayMs" }
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"edges": [],
|
|
19
|
+
"triggers": [
|
|
20
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
21
|
+
],
|
|
22
|
+
"variables": [
|
|
23
|
+
{
|
|
24
|
+
"name": "delayMs",
|
|
25
|
+
"type": "number",
|
|
26
|
+
"description": "Milliseconds to sleep. Defaulted well above any small runTimeoutMs so the wall-clock bound trips first.",
|
|
27
|
+
"required": true,
|
|
28
|
+
"defaultValue": 30000
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"metadata": { "tags": ["conformance", "run-duration", "rfc-0058"] },
|
|
32
|
+
"settings": { "timeout": 60000, "maxRetries": 0 }
|
|
33
|
+
}
|
package/fixtures.md
CHANGED
|
@@ -358,6 +358,25 @@ Both items are tracked as v1.x conformance expansion work.
|
|
|
358
358
|
|
|
359
359
|
---
|
|
360
360
|
|
|
361
|
+
## `conformance-run-duration-breach` (RFC 0058 — wall-clock run timeout)
|
|
362
|
+
|
|
363
|
+
> **Status: RFC 0058 `Draft`.** Exercises the `run-duration` `cap.breached` kind. Soft-skips until a host advertises `capabilities.limits.maxRunDurationMs` AND enforces the wall-clock bound; gated in `run-execution-bounds-shape.test.ts` via `isFixtureAdvertised`.
|
|
364
|
+
|
|
365
|
+
- **Purpose**: verify that `RunOptions.configurable.runTimeoutMs` (clamped to `Capabilities.limits.maxRunDurationMs`) terminates a run that overruns its deadline, emitting `cap.breached {kind: 'run-duration'}` + terminal `failed` with `error.code = 'run_timeout'` per `run-options.md` §runTimeoutMs + `capabilities.md` §"Engine-enforced limits".
|
|
366
|
+
- **Topology**: single `core.delay` node that sleeps `input.delayMs` (default `30000`) — far longer than the small `runTimeoutMs` the test supplies.
|
|
367
|
+
- **Inputs**: `delayMs` (number, default `30000`).
|
|
368
|
+
- **Conformance test driver**:
|
|
369
|
+
1. POST `/v1/runs` with `{workflowId: "conformance-run-duration-breach", configurable: {runTimeoutMs: 1000}}`.
|
|
370
|
+
2. Poll until terminal.
|
|
371
|
+
3. **Assert** terminal status is `failed`.
|
|
372
|
+
4. **Assert** `RunSnapshot.error.code === "run_timeout"`.
|
|
373
|
+
5. **Assert** the event log contains a `cap.breached` event with `payload: {kind: "run-duration", limit: 1000, observed: <elapsedMs > 1000>}` — `observed` recorded in the event, not recomputed at replay (`replay.md`).
|
|
374
|
+
- **Negative path**: same fixture with `runTimeoutMs` above the (short) `delayMs`, or no override, completes normally.
|
|
375
|
+
|
|
376
|
+
This fixture is unblocked when a host exposes a wall-clock deadline enforcer advertising `capabilities.limits.maxRunDurationMs`. Tracked as v1.x conformance expansion work (RFC 0058 acceptance criteria).
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
361
380
|
## `openwop-smoke-byok-roundtrip` (BYOK end-to-end smoke fixture)
|
|
362
381
|
|
|
363
382
|
> **Status: included in the v1.0 conformance baseline.** Server-side `conformance.secret.echo` support is exercised by `src/scenarios/byok-roundtrip.test.ts`.
|
package/package.json
CHANGED
package/schemas/README.md
CHANGED
|
@@ -4,16 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
| Schema | Source spec | Coverage |
|
|
6
6
|
|---|---|---|
|
|
7
|
+
| `agent-inventory-response.schema.json` | `node-packs.md` + RFC 0072 | RFC 0072 §A — read projection of installed manifest agents (`GET /v1/agents` body + `$defs.AgentInventoryEntry`); no system prompt / handoff schemas / credentials (SR-1) |
|
|
7
8
|
| `agent-manifest.schema.json` | `node-packs.md` + agent-pack RFCs | Agent manifest entries distributed alongside node-pack manifests |
|
|
8
9
|
| `agent-ref.schema.json` | `agent-memory.md` + agent-identity RFC | Multi-Agent Shift Phase 1 — slim runtime AgentRef projection carried on `RunSnapshot.agent` / `runOrchestrator`, `WorkflowNode.agent?`, and `agent.*` event payloads |
|
|
9
10
|
| `ai-envelope.schema.json` | `ai-envelope.md` | FINAL v1.1 — inbound LLM-emission envelope. Top-level shape (`type` / `schemaVersion` / `envelopeId` / `correlationId` / `payload` / `meta` / `partial`). Per-kind payload schemas under `envelopes/`. Distinct from `RunEventDoc` (outbound) and `error-envelope.schema.json` (host HTTP errors). |
|
|
11
|
+
| `artifact-type-pack-manifest.schema.json` | `artifact-type-packs.md` + RFC 0071 | DRAFT — manifest for `kind: "artifact-type"` registry packs. Peer to `node-pack-manifest.schema.json` (RFC 0003), `workflow-chain-pack-manifest.schema.json` (RFC 0013), and `prompt-pack-manifest.schema.json` (RFC 0028); disjoint via the `kind` discriminator. Distributes typed artifact definitions (schema + advisory rendering hint + lifecycle + export-format hints) via the same signed-tarball + Ed25519 + SRI pipeline. |
|
|
10
12
|
| `envelopes/clarification.request.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — payload for the universal `clarification.request` kind; engine lifts to `kind: "clarification"` `InterruptPayload`. |
|
|
11
13
|
| `envelopes/schema.request.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — LLM asks the engine for a kind's JSON Schema. Counts against `Capabilities.limits.schemaRounds`. |
|
|
12
14
|
| `envelopes/schema.response.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — side-channel ack for `schema.request`. Never surfaces to users. |
|
|
13
15
|
| `envelopes/error.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — LLM's deliberate error report. Distinct from `error-envelope.schema.json` (host HTTP errors). |
|
|
16
|
+
| `envelopes/media.image.schema.json` | `ai-envelope.md` §"Media reference payloads" | RFC 0055 §C — optional `media.image` payload; tenant-scoped URL ref or inline base64 below `maxInlineMediaBytes`. |
|
|
17
|
+
| `envelopes/media.audio.schema.json` | `ai-envelope.md` §"Media reference payloads" | RFC 0055 §C — optional `media.audio` payload; URL ref or inline base64 + optional `durationSeconds`. |
|
|
18
|
+
| `envelopes/media.file.schema.json` | `ai-envelope.md` §"Media reference payloads" | RFC 0055 §C — optional `media.file` payload; downloadable asset by URL ref or inline base64 + optional `name`. |
|
|
19
|
+
| `annotation.schema.json` | `RFCS/0056` + `observability.md` | RFC 0056 (`Draft`) — a non-blocking human/agent quality signal (rating / correction / label / flag) attached to a run, event, or node. A side-resource (not a replayable run-event-log entry); response of `POST/GET /v1/runs/{runId}/annotations` + payload of the `run.annotated` SSE notification. |
|
|
20
|
+
| `annotation-create.schema.json` | `RFCS/0056` | RFC 0056 (`Draft`) — request body for `POST /v1/runs/{runId}/annotations` (host assigns `annotationId`/`createdAt`/`actor`; binds `target.runId` to the path). |
|
|
21
|
+
| `heartbeat-evaluated.schema.json` | `RFCS/0060` + `host-capabilities.md` | RFC 0060 (`Active`) — payload of the heartbeat-scoped `heartbeat.evaluated` AsyncAPI event (`{ heartbeatId, status, changed }`); emitted every tick by a host advertising `capabilities.heartbeat`. Not a run-event-log entry. |
|
|
22
|
+
| `heartbeat-state-changed.schema.json` | `RFCS/0060` + `host-capabilities.md` | RFC 0060 (`Active`) — payload of the `heartbeat.stateChanged` AsyncAPI event (`{ heartbeatId, from, to }`); emitted only on a predicate-state transition. Not a run-event-log entry. |
|
|
14
23
|
| `audit-verify-result.schema.json` | `auth-profiles.md` §`openwop-audit-log-integrity` | Response payload from `GET /v1/audit/verify` — chain-validity verdict + checkpoints + anomalies |
|
|
15
24
|
| `capabilities.schema.json` | `capabilities.md` | `/.well-known/openwop` response — protocolVersion + supportedEnvelopes + schemaVersions + limits + optional v1 discovery surface |
|
|
16
25
|
| `channel-written-payload.schema.json` | `channels-and-reducers.md` §Channel write event | Payload of the `channel.written` RunEvent — write input + reducer name |
|
|
26
|
+
| `chat-card-pack-manifest.schema.json` | `chat-card-packs.md` + RFC 0071 | DRAFT — manifest for `kind: "card"` registry packs (RFC 0071 Phase 2). Peer to the node/workflow-chain/prompt/artifact-type pack manifests; disjoint via the `kind` discriminator. Distributes AI chat cards: a prompt template + typed input subset bound to a typed `outputArtifactType`. |
|
|
17
27
|
| `conversation-event.schema.json` | `channels-and-reducers.md` + conversation RFC | Multi-turn conversation event shape for orchestrator-driven HITL flows |
|
|
18
28
|
| `conversation-turn.schema.json` | `channels-and-reducers.md` + conversation RFC | Conversation turn shape for user/agent/system messages |
|
|
19
29
|
| `core-conformance-mock-agent-config.schema.json` | `node-packs.md` + RFC 0023 | Config shape for the conformance-only `core.conformance.mock-agent` typeId — drives `agent.*` event emission on cue (`mockReasoning` / `mockToolCalls` / `mockHandoff` / `mockDecision` / `mockConfidence`). Hosts MUST refuse this typeId for production tenants unless `capabilities.conformance.mockAgent` is advertised. |
|
|
@@ -42,6 +52,8 @@
|
|
|
42
52
|
| `suspend-request.schema.json` | `interrupt.md` | `InterruptPayload` with 8 `kind` discriminators (approval, clarification, external-event, custom, conversation.start, conversation.exchange, conversation.close, low-confidence) |
|
|
43
53
|
| `workflow-chain-pack-manifest.schema.json` | `workflow-chain-packs.md` + RFC 0013 | Manifest for workflow-chain packs (`kind: "workflow-chain"`) — pre-configured DAG fragments expanded inline at workflow-author time. Peer to `node-pack-manifest.schema.json`; disjoint via the `kind` discriminator. |
|
|
44
54
|
| `workflow-definition.schema.json` | `channels-and-reducers.md` + `node-packs.md` | DAG of nodes + edges + triggers + variables + channels |
|
|
55
|
+
| `workspace-file.schema.json` | `agent-workspace.md` + `RFCS/0059` | RFC 0059 — a versioned workspace file (`{path, content, version, etag, updatedAt}`); response of `GET/PUT /v1/host/workspace/files/{path}`. |
|
|
56
|
+
| `workspace-file-create.schema.json` | `agent-workspace.md` + `RFCS/0059` | RFC 0059 — `PUT /v1/host/workspace/files/{path}` request body (content + optional contentType; path from the URL, version/etag host-assigned). |
|
|
45
57
|
|
|
46
58
|
## Validating against the schemas
|
|
47
59
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/agent-inventory-response.schema.json",
|
|
4
|
+
"title": "AgentInventoryResponse",
|
|
5
|
+
"description": "Response body for `GET /v1/agents` (RFC 0072 §A). A read-only projection of the manifest agents a host has installed into its AgentRegistry (RFC 0003 / RFC 0070). Served only when the host advertises `capabilities.agents.manifestRuntime.supported: true`. Each entry MUST NOT carry the agent's system-prompt body, resolved handoff schemas, or any credential material (SR-1).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["agents", "total"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"agents": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": { "$ref": "#/$defs/AgentInventoryEntry" },
|
|
13
|
+
"description": "Installed manifest agents, in a stable (agentId-sorted) order."
|
|
14
|
+
},
|
|
15
|
+
"total": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"minimum": 0,
|
|
18
|
+
"description": "Count of installed manifest agents (== agents.length)."
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"$defs": {
|
|
22
|
+
"AgentInventoryEntry": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"title": "AgentInventoryEntry",
|
|
25
|
+
"description": "Read projection of an installed `AgentManifest` (agent-manifest.schema.json). Also the body of `GET /v1/agents/{agentId}`.",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"required": ["agentId", "persona", "label", "modelClass", "packName", "packVersion", "toolAllowlist", "hasHandoffSchemas"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"agentId": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "The manifest agentId (matches `AgentManifest.agentId` / `AgentRef.agentId`)."
|
|
32
|
+
},
|
|
33
|
+
"persona": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Human-readable agent name from the manifest."
|
|
36
|
+
},
|
|
37
|
+
"label": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "Short UI label; falls back to `persona` when the manifest omits `label`."
|
|
40
|
+
},
|
|
41
|
+
"description": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "Optional one-line catalog summary from the manifest."
|
|
44
|
+
},
|
|
45
|
+
"modelClass": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "The manifest's `modelClass` (see agent-manifest.schema.json)."
|
|
48
|
+
},
|
|
49
|
+
"packName": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"description": "The pack this agent was installed from."
|
|
52
|
+
},
|
|
53
|
+
"packVersion": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "The installed pack version."
|
|
56
|
+
},
|
|
57
|
+
"toolAllowlist": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": { "type": "string" },
|
|
60
|
+
"description": "Tool identifiers the agent MAY invoke (RFC 0002 §A14). The host MUST enforce this at dispatch; an empty array means no tools."
|
|
61
|
+
},
|
|
62
|
+
"hasHandoffSchemas": {
|
|
63
|
+
"type": "boolean",
|
|
64
|
+
"description": "Whether the manifest declares handoff task/return schemas (the host validates dispatch payloads against them when it advertises `agents.manifestRuntime.handoffValidation`). The schemas themselves are NOT exposed here."
|
|
65
|
+
},
|
|
66
|
+
"memoryShape": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"description": "The manifest's declared memory shape, when present.",
|
|
70
|
+
"properties": {
|
|
71
|
+
"scratchpad": { "type": "boolean" },
|
|
72
|
+
"conversation": { "type": "boolean" },
|
|
73
|
+
"longTerm": { "type": "boolean" }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"confidenceThreshold": {
|
|
77
|
+
"type": "number",
|
|
78
|
+
"minimum": 0,
|
|
79
|
+
"maximum": 1,
|
|
80
|
+
"description": "The manifest's `confidence.defaultThreshold`, when present (RFC 0002 §F)."
|
|
81
|
+
},
|
|
82
|
+
"degraded": {
|
|
83
|
+
"type": "array",
|
|
84
|
+
"items": { "type": "string" },
|
|
85
|
+
"description": "Capability keys this agent declared as `peerDependenciesMeta.optional` that this host does NOT satisfy, and which are therefore inert for this installation (RFC 0072 §C). Absent or empty means the agent runs at full declared capability here."
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -75,6 +75,34 @@
|
|
|
75
75
|
"type": "string",
|
|
76
76
|
"maxLength": 256,
|
|
77
77
|
"description": "Optional human-readable label for ops dashboards (e.g., `\"Draft PRD #2\"`). Never used for routing; never persisted into event payloads in a security-relevant way. (in-flight)"
|
|
78
|
+
},
|
|
79
|
+
"rendering": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"description": "RFC 0055. Optional hint for how a consumer SHOULD render this envelope's payload. Non-normative w.r.t. payload validation; a consumer that doesn't recognize the hint (or a `display` value) MUST fall back to its default rendering (text / raw JSON). Carries no secret material (SR-1 applies as for the rest of `meta`).",
|
|
82
|
+
"properties": {
|
|
83
|
+
"display": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"enum": ["markdown", "code", "card", "image", "audio", "file"],
|
|
86
|
+
"description": "Renderer family the producer suggests."
|
|
87
|
+
},
|
|
88
|
+
"mimeType": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"description": "IANA media type when `display` is `image`/`audio`/`file`."
|
|
91
|
+
},
|
|
92
|
+
"lang": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"description": "Language tag when `display` is `code` (e.g. `ts`, `python`)."
|
|
95
|
+
},
|
|
96
|
+
"alt": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"description": "Text alternative for accessibility when `display` is `image`/`audio`/`file`. SHOULD be present for those families."
|
|
99
|
+
},
|
|
100
|
+
"title": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"description": "Optional caption / card header."
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"additionalProperties": false
|
|
78
106
|
}
|
|
79
107
|
},
|
|
80
108
|
"additionalProperties": false,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/annotation-create.schema.json",
|
|
4
|
+
"title": "AnnotationCreate",
|
|
5
|
+
"description": "RFC 0056. Request body for `POST /v1/runs/{runId}/annotations`. The host assigns `annotationId` + `createdAt`, derives `actor.principalRef` from the authenticated principal, and binds `target.runId` to the path `runId` — so the client supplies only the target anchor (event/node), the signal, and an optional note. The response is a full `annotation.schema.json`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["signal"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"target": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"description": "Optional finer-grained anchor within the run. `runId` is taken from the path and MUST NOT be supplied here.",
|
|
12
|
+
"properties": {
|
|
13
|
+
"eventId": { "type": "string", "description": "Anchor the annotation to one RunEvent." },
|
|
14
|
+
"nodeId": { "type": "string", "description": "Anchor the annotation to one node." }
|
|
15
|
+
},
|
|
16
|
+
"additionalProperties": false
|
|
17
|
+
},
|
|
18
|
+
"signal": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"required": ["kind"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"kind": { "type": "string", "enum": ["rating", "correction", "label", "flag"] },
|
|
23
|
+
"rating": { "type": "integer", "minimum": 1, "maximum": 5, "description": "Required iff `kind` is `rating`." },
|
|
24
|
+
"label": { "type": "string", "description": "Required iff `kind` is `label`." },
|
|
25
|
+
"correction": { "type": "string", "description": "Corrected text/value iff `kind` is `correction`. Untrusted user content." }
|
|
26
|
+
},
|
|
27
|
+
"additionalProperties": false,
|
|
28
|
+
"allOf": [
|
|
29
|
+
{ "if": { "properties": { "kind": { "const": "rating" } } }, "then": { "required": ["rating"] } },
|
|
30
|
+
{ "if": { "properties": { "kind": { "const": "label" } } }, "then": { "required": ["label"] } },
|
|
31
|
+
{ "if": { "properties": { "kind": { "const": "correction" } } }, "then": { "required": ["correction"] } }
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"note": { "type": "string", "description": "Optional free-text reviewer note. Untrusted user content." }
|
|
35
|
+
},
|
|
36
|
+
"additionalProperties": false
|
|
37
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/annotation.schema.json",
|
|
4
|
+
"title": "Annotation",
|
|
5
|
+
"description": "RFC 0056. A non-blocking human/agent quality signal attached to a run, event, or node — a side-resource, NOT a replayable run-event-log entry. Recorded via `POST /v1/runs/{runId}/annotations`, listed via `GET`, and surfaced live via the `run.annotated` SSE notification. `signal.correction` and `note` are untrusted user content (SECURITY invariant `annotation-content-redaction`).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["annotationId", "target", "signal", "actor", "createdAt"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"annotationId": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"minLength": 1,
|
|
12
|
+
"description": "Host-assigned unique identifier for this annotation."
|
|
13
|
+
},
|
|
14
|
+
"target": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["runId"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"runId": { "type": "string", "minLength": 1 },
|
|
19
|
+
"eventId": { "type": "string", "description": "Optional — anchors the annotation to one RunEvent." },
|
|
20
|
+
"nodeId": { "type": "string", "description": "Optional — anchors the annotation to one node." }
|
|
21
|
+
},
|
|
22
|
+
"additionalProperties": false
|
|
23
|
+
},
|
|
24
|
+
"signal": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["kind"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"kind": { "type": "string", "enum": ["rating", "correction", "label", "flag"] },
|
|
29
|
+
"rating": { "type": "integer", "minimum": 1, "maximum": 5, "description": "Required iff `kind` is `rating`." },
|
|
30
|
+
"label": { "type": "string", "description": "Required iff `kind` is `label`." },
|
|
31
|
+
"correction": { "type": "string", "description": "Corrected text/value iff `kind` is `correction`. Untrusted user content." }
|
|
32
|
+
},
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"allOf": [
|
|
35
|
+
{ "if": { "properties": { "kind": { "const": "rating" } } }, "then": { "required": ["rating"] } },
|
|
36
|
+
{ "if": { "properties": { "kind": { "const": "label" } } }, "then": { "required": ["label"] } },
|
|
37
|
+
{ "if": { "properties": { "kind": { "const": "correction" } } }, "then": { "required": ["correction"] } }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"actor": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"required": ["principalRef"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"principalRef": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"minLength": 1,
|
|
47
|
+
"description": "Opaque principal identifier — a principal per RFC 0048 (Draft, referenced non-normatively) or an AgentRef per RFC 0002 when a supervisor agent annotates. String-typed so RFC 0056 does not depend on RFC 0048 reaching Accepted."
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"additionalProperties": false
|
|
51
|
+
},
|
|
52
|
+
"note": { "type": "string", "description": "Optional free-text reviewer note. Untrusted user content." },
|
|
53
|
+
"createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 timestamp the host recorded the annotation." }
|
|
54
|
+
},
|
|
55
|
+
"additionalProperties": false
|
|
56
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/artifact-type-pack-manifest.schema.json",
|
|
4
|
+
"title": "ArtifactTypePackManifest",
|
|
5
|
+
"description": "Manifest for a published OpenWOP artifact-type pack — `pack.json` at the pack root with `kind: \"artifact-type\"`. Peer to `node-pack-manifest.schema.json` (RFC 0003), `workflow-chain-pack-manifest.schema.json` (RFC 0013), and `prompt-pack-manifest.schema.json` (RFC 0028); disjoint from all three via the `kind` discriminator. See `spec/v1/artifact-type-packs.md` for the canonical contract and RFC 0071 for the rationale.\n\nArtifact-type packs distribute typed artifact definitions — the JSON Schema, rendering hint, lifecycle, and export-format hints for the rich outputs workflow nodes produce — via the same signed-tarball + Ed25519 + SRI pipeline that already serves node, workflow-chain, and prompt packs. When a host installs an artifact-type pack and advertises `host.artifactTypes: { supported: true }`, it validates produced artifacts of the declared `artifactTypeId`s against their `schemaRef` before emitting `artifact.created`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "version", "kind", "engines", "artifactTypes"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"kind": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"const": "artifact-type",
|
|
13
|
+
"description": "Pack kind discriminator. MUST be the literal string `\"artifact-type\"`. Manifests carrying any other `kind` value validate against a different pack-manifest schema."
|
|
14
|
+
},
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Reverse-DNS pack name per `node-packs.md` §Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`). Mirror of `prompt-pack-manifest.schema.json#/properties/name`.",
|
|
18
|
+
"pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
|
|
19
|
+
"minLength": 1,
|
|
20
|
+
"maxLength": 256
|
|
21
|
+
},
|
|
22
|
+
"version": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Pack-level SemVer 2.0.0.",
|
|
25
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$"
|
|
26
|
+
},
|
|
27
|
+
"description": { "type": "string", "maxLength": 1024 },
|
|
28
|
+
"author": { "type": "string" },
|
|
29
|
+
"license": { "type": "string", "description": "SPDX license identifier (e.g., `Apache-2.0`, `MIT`)." },
|
|
30
|
+
"homepage": { "type": "string", "format": "uri" },
|
|
31
|
+
"repository": { "type": "string", "format": "uri" },
|
|
32
|
+
"keywords": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "type": "string", "maxLength": 64 },
|
|
35
|
+
"maxItems": 50
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": ["openwop"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"openwop": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "Semver range — which openwop protocol versions this pack works against. Example: `>=1.1 <2.0.0`."
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"additionalProperties": true
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"additionalProperties": { "type": "string" },
|
|
51
|
+
"description": "Other packs this pack depends on. Map of pack name → semver range. Resolved transitively at workflow-register time."
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": { "type": "string" },
|
|
56
|
+
"description": "Engine-supplied capabilities the pack consumes (e.g., `{ \"host.artifactTypes\": \"supported\" }`). Resolved against the host's advertised capabilities at register time."
|
|
57
|
+
},
|
|
58
|
+
"artifactTypes": {
|
|
59
|
+
"type": "array",
|
|
60
|
+
"minItems": 1,
|
|
61
|
+
"items": { "$ref": "#/$defs/ArtifactType" },
|
|
62
|
+
"description": "Typed artifact definitions this pack contributes. Each MUST have a unique `artifactTypeId` within the pack."
|
|
63
|
+
},
|
|
64
|
+
"signing": { "$ref": "#/$defs/Signing" }
|
|
65
|
+
},
|
|
66
|
+
"$defs": {
|
|
67
|
+
"ArtifactType": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"required": ["artifactTypeId", "schemaRef"],
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"properties": {
|
|
72
|
+
"artifactTypeId": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"description": "Reverse-DNS artifact-type identifier. Same pattern and reserved scopes as a pack `name`. This is the value `WorkflowNode.artifactType`, `nodes[].artifact.typeId`, and `artifact.created.artifactType` reference. Third parties MUST NOT publish under `core.*`.",
|
|
75
|
+
"pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
|
|
76
|
+
"minLength": 1,
|
|
77
|
+
"maxLength": 256
|
|
78
|
+
},
|
|
79
|
+
"schemaRef": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"minLength": 1,
|
|
82
|
+
"description": "Path inside the pack tarball to the artifact's JSON Schema (Draft 2020-12). The target schema MUST set `additionalProperties: false` at its top level and declare an `$id` under `{HostBase}/schemas/artifacts/{artifactTypeId}.schema.json`, mirroring the envelope convention in `ai-envelope.md` §\"Canonical schema location\"."
|
|
83
|
+
},
|
|
84
|
+
"schemaVersion": {
|
|
85
|
+
"type": "integer",
|
|
86
|
+
"minimum": 0,
|
|
87
|
+
"description": "Non-negative integer artifact-schema version, parallel to the per-kind integer in `capabilities.schemaVersions`. Absent ⇒ treated as 0. Bumped when the artifact schema changes shape. A version *declaration*, not a validation guarantee (RFC 0075 / P1-2)."
|
|
88
|
+
},
|
|
89
|
+
"validation": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"enum": ["open", "closed"],
|
|
92
|
+
"description": "RFC 0075. Strictness contract of the artifact's `schemaRef` schema. `closed` ⇒ closed-world (`additionalProperties: false`); a consumer MAY rely on the absence of unknown fields. `open` (recommended for AI/LLM-produced artifacts) ⇒ the schema tolerates extra fields to absorb model drift; consumers MUST ignore unknown fields per COMPATIBILITY.md §2.1. Absent ⇒ `open` (the forward-compatible default). The `additionalProperties:false` requirement on `schemaRef` was relaxed MUST → SHOULD by RFC 0075: a closed-world artifact contract contradicts the protocol's own forward-compat mandate and the first AI-native adopter cannot meet it."
|
|
93
|
+
},
|
|
94
|
+
"displayName": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"description": "Human-readable label for artifact-management UIs. Non-normative."
|
|
97
|
+
},
|
|
98
|
+
"rendering": { "$ref": "#/$defs/RenderingHint" },
|
|
99
|
+
"exportFormats": {
|
|
100
|
+
"type": "array",
|
|
101
|
+
"items": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"minLength": 1,
|
|
104
|
+
"maxLength": 64,
|
|
105
|
+
"pattern": "^([a-z][a-z0-9]*|vendor\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*|x-[a-z][a-z0-9-]*)$"
|
|
106
|
+
},
|
|
107
|
+
"uniqueItems": true,
|
|
108
|
+
"description": "Export-format identifiers (hints) a renderer MAY offer. Spec-reserved core identifiers carry interoperable meaning (the lowercase file-extension / common name): `pdf`, `pptx`, `docx`, `xlsx`, `md`, `html`, `txt`, `csv`, `json`, `png`, `svg`, `jpeg`, `step`, `stl`, `dxf`. Domain-specific formats outside the core set MUST be `vendor.<org>.<format>`- or `x-<format>`-prefixed (mirrors the `requiredModelCapabilities` reserved-core + extension idiom). Advisory: this spec assigns no byte-level production semantics to any identifier — it standardizes the identifier so two hosts agree what `pptx` names, not how the bytes are produced."
|
|
109
|
+
},
|
|
110
|
+
"syncOn": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"enum": ["completion", "approval", "manual"],
|
|
113
|
+
"description": "When the host registers the artifact as durable. Mirrors `node-pack-manifest.schema.json#/$defs/PackNode/properties/artifact/properties/syncOn`. Default `completion`."
|
|
114
|
+
},
|
|
115
|
+
"supportsCheckpoint": {
|
|
116
|
+
"type": "boolean",
|
|
117
|
+
"description": "True if the artifact participates in checkpoint/resume. Mirrors the `PackNode.artifact.supportsCheckpoint` field."
|
|
118
|
+
},
|
|
119
|
+
"versionable": {
|
|
120
|
+
"type": "boolean",
|
|
121
|
+
"description": "True if the host SHOULD retain prior versions of the artifact. Non-normative storage hint."
|
|
122
|
+
},
|
|
123
|
+
"diffable": {
|
|
124
|
+
"type": "boolean",
|
|
125
|
+
"description": "True if the artifact's schema supports structural diffing (informs run-diff tooling per rest-endpoints.md §:diff). Non-normative."
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"RenderingHint": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"additionalProperties": false,
|
|
132
|
+
"description": "Advisory rendering hint. Reuses the closed vocabulary defined in ai-envelope.md §\"Rendering hints\" (RFC 0055). Advisory only — consumers MUST degrade gracefully and MUST NOT treat this as a validation input. The `card` display value is reserved for envelopes and is excluded here (durable artifacts are not transient chat cards).",
|
|
133
|
+
"properties": {
|
|
134
|
+
"display": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"enum": ["markdown", "code", "image", "audio", "file"],
|
|
137
|
+
"description": "How a consumer SHOULD render the artifact when it recognizes the value."
|
|
138
|
+
},
|
|
139
|
+
"mimeType": { "type": "string", "maxLength": 255 },
|
|
140
|
+
"lang": { "type": "string", "maxLength": 64, "description": "Language hint for `display: code`." },
|
|
141
|
+
"alt": { "type": "string", "maxLength": 1024, "description": "Accessibility text for image/audio/file." },
|
|
142
|
+
"title": { "type": "string", "maxLength": 255 }
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"Signing": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"description": "Optional signing metadata. See node-packs.md §signing.",
|
|
148
|
+
"additionalProperties": false,
|
|
149
|
+
"properties": {
|
|
150
|
+
"publicKeyRef": { "type": "string", "description": "Path inside the tarball to the Ed25519 public key (PEM-encoded)." },
|
|
151
|
+
"signatureRef": { "type": "string", "description": "Path to the detached signature over `pack.json`." },
|
|
152
|
+
"method": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"enum": ["manual", "sigstore"],
|
|
155
|
+
"description": "Signing method. `manual` uses publicKeyRef + signatureRef; `sigstore` uses a Sigstore bundle at `pack.json.sigstore`."
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|