@openwop/spec-artifacts 2.0.0-rc.38 → 2.0.0-rc.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CORPUS-STAMP.json +31 -33
  2. package/api/seams-v2.yaml +1 -1
  3. package/api/v2/asyncapi.yaml +1 -1
  4. package/api/v2/openapi.yaml +10 -9
  5. package/package.json +5 -18
  6. package/schemas/capabilities.schema.json +1 -40
  7. package/schemas/run-snapshot.schema.json +33 -103
  8. package/schemas/v2/agent-deployment-transition.schema.json +6 -5
  9. package/schemas/v2/agent-deployment.schema.json +9 -8
  10. package/schemas/v2/agent-eval-suite.schema.json +12 -11
  11. package/schemas/v2/artifact-type-pack-manifest.schema.json +18 -22
  12. package/schemas/v2/capabilities.schema.json +0 -39
  13. package/schemas/v2/certification-bundle.schema.json +1 -1
  14. package/schemas/v2/chat-card-pack-manifest.schema.json +15 -19
  15. package/schemas/v2/debug-bundle.schema.json +6 -6
  16. package/schemas/v2/eval-summary.schema.json +10 -17
  17. package/schemas/v2/goal.schema.json +5 -5
  18. package/schemas/v2/ids.schema.json +22 -120
  19. package/schemas/v2/node-pack-manifest.schema.json +31 -27
  20. package/schemas/v2/proposal.schema.json +8 -7
  21. package/schemas/v2/run-event-payloads.schema.json +242 -246
  22. package/schemas/v2/run-event.schema.json +126 -2
  23. package/schemas/v2/run-snapshot.schema.json +13 -34
  24. package/schemas/v2/workflow-chain-pack-manifest.schema.json +45 -41
  25. package/schemas/v2/workflow-definition.schema.json +36 -31
  26. package/spec/v1/core-standard-manifest.json +2 -2
  27. package/spec/v1/deprecations.json +67 -79
  28. package/spec/v1/deprecations.schema.json +7 -23
  29. package/spec/v1/extensions.json +2 -3
  30. package/spec/v2/declaration.json +0 -7
  31. package/spec/v2/release.json +2 -2
  32. package/schemas/v2/webhook-delivery.schema.json +0 -26
  33. package/spec/v2/id-field-bindings.json +0 -104
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/agent-deployment.schema.json",
4
4
  "title": "AgentDeployment",
5
- "description": "RFC 0082 \u00a7C. A per-(agentId, version) deployment record: the host-runtime lifecycle state of one version of a manifest agent (RFC 0003/0070), distinct from the immutable AgentManifest (which is the pack-distribution descriptor) and from the registry's published semver tags (which version EXISTS, not which version SERVES). Holds the deployment `state`, the named `channels` that resolve to this version, the canary traffic share, the rollback pointer, and the provenance (`evalRunId`/`approvalGateId`) of the last transition. Content-free of any manifest body or credential material (SR-1). The record itself is host-internal; this schema is the canonical wire shape a host exposes via GET /v1/agents/{agentId}/deployments (the endpoint lands at Active \u2192 Accepted per RFC 0082 \u00a7Conformance).",
5
+ "description": "RFC 0082 §C. A per-(agentId, version) deployment record: the host-runtime lifecycle state of one version of a manifest agent (RFC 0003/0070), distinct from the immutable AgentManifest (which is the pack-distribution descriptor) and from the registry's published semver tags (which version EXISTS, not which version SERVES). Holds the deployment `state`, the named `channels` that resolve to this version, the canary traffic share, the rollback pointer, and the provenance (`evalRunId`/`approvalGateId`) of the last transition. Content-free of any manifest body or credential material (SR-1). The record itself is host-internal; this schema is the canonical wire shape a host exposes via GET /v1/agents/{agentId}/deployments (the endpoint lands at Active Accepted per RFC 0082 §Conformance).",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -18,7 +18,7 @@
18
18
  "version": {
19
19
  "type": "string",
20
20
  "maxLength": 64,
21
- "description": "The concrete agent-definition version this record governs (matches `AgentManifest.version`). A deployment record is per-(agentId, version); a `@channel` reference resolves to exactly one such version per the RFC 0082 \u00a7B pin."
21
+ "description": "The concrete agent-definition version this record governs (matches `AgentManifest.version`). A deployment record is per-(agentId, version); a `@channel` reference resolves to exactly one such version per the RFC 0082 §B pin."
22
22
  },
23
23
  "state": {
24
24
  "type": "string",
@@ -31,13 +31,13 @@
31
31
  "deprecated",
32
32
  "rolled-back"
33
33
  ],
34
- "description": "RFC 0082 \u00a7C lifecycle state. `draft`: authored, not yet evaluated. `test`: undergoing eval (RFC 0081). `staged`: eval-passed, awaiting production promotion. `active`: serving (optionally at `canaryPercent < 100`). `paused`: temporarily withdrawn, recoverable. `deprecated`: sunset \u2014 no new traffic, existing pins honored. `rolled-back`: superseded; `rollbackPointer` names the version that replaced it. Legal transitions: draft\u2192test\u2192staged\u2192active (promotion); active\u2194paused (operational); active\u2192deprecated (terminal); active\u2192rolled-back (recovery, with `rollbackPointer`)."
34
+ "description": "RFC 0082 §C lifecycle state. `draft`: authored, not yet evaluated. `test`: undergoing eval (RFC 0081). `staged`: eval-passed, awaiting production promotion. `active`: serving (optionally at `canaryPercent < 100`). `paused`: temporarily withdrawn, recoverable. `deprecated`: sunset no new traffic, existing pins honored. `rolled-back`: superseded; `rollbackPointer` names the version that replaced it. Legal transitions: draft→test→staged→active (promotion); active↔paused (operational); active→deprecated (terminal); active→rolled-back (recovery, with `rollbackPointer`)."
35
35
  },
36
36
  "canaryPercent": {
37
37
  "type": "integer",
38
38
  "minimum": 0,
39
39
  "maximum": 100,
40
- "description": "MAY. For an `active` version, the share (0\u2013100) of channel traffic the \u00a7B pin draw assigns to THIS version; the remainder goes to the prior `active` version on the same channel. Absent \u21d2 100 (full traffic). A host advertising `agents.deployment.canary: false` MUST reject any value < 100. The per-run draw outcome is the recorded-fact `resolvedAgentVersion` (RFC 0082 \u00a7B) \u2014 never re-rolled on replay."
40
+ "description": "MAY. For an `active` version, the share (0–100) of channel traffic the §B pin draw assigns to THIS version; the remainder goes to the prior `active` version on the same channel. Absent 100 (full traffic). A host advertising `agents.deployment.canary: false` MUST reject any value < 100. The per-run draw outcome is the recorded-fact `resolvedAgentVersion` (RFC 0082 §B) never re-rolled on replay."
41
41
  },
42
42
  "rollbackPointer": {
43
43
  "type": "string",
@@ -51,16 +51,17 @@
51
51
  "type": "string",
52
52
  "minLength": 1
53
53
  },
54
- "description": "MAY. The named deployment channels (e.g. `stable`, `canary`) that resolve to this version. A version MAY be on more than one channel (RFC 0082 UQ#4 \u2014 a promoted-to-`stable` version is also resolvable by the reserved `latest` channel = highest active semver). Channel names are host-advertised in `capabilities.agents.deployment.channels`."
54
+ "description": "MAY. The named deployment channels (e.g. `stable`, `canary`) that resolve to this version. A version MAY be on more than one channel (RFC 0082 UQ#4 a promoted-to-`stable` version is also resolvable by the reserved `latest` channel = highest active semver). Channel names are host-advertised in `capabilities.agents.deployment.channels`."
55
55
  },
56
56
  "evalRunId": {
57
- "$ref": "ids.schema.json#/$defs/runId",
58
- "description": "MAY. The RFC 0081 eval run whose `EvalSummary.passed` gated the last promotion into this state (the \u00a7E evidence). Content-free reference, not the eval body."
57
+ "type": "string",
58
+ "minLength": 1,
59
+ "description": "MAY. The RFC 0081 eval run whose `EvalSummary.passed` gated the last promotion into this state (the §E evidence). Content-free reference, not the eval body."
59
60
  },
60
61
  "approvalGateId": {
61
62
  "type": "string",
62
63
  "minLength": 1,
63
- "description": "MAY. The RFC 0051 `approvalGate` that authorized the last transition (the \u00a7E human gate). Content-free reference."
64
+ "description": "MAY. The RFC 0051 `approvalGate` that authorized the last transition (the §E human gate). Content-free reference."
64
65
  }
65
66
  },
66
67
  "x-openwop-seeded-from": "v1"
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/agent-eval-suite.schema.json",
4
4
  "title": "AgentEvalSuite",
5
- "description": "RFC 0081 \u00a7A. A portable, host-agnostic evaluation suite for a manifest agent (RFC 0003/0070): the tasks, the expected outputs or rubrics, the deterministic tool/memory fixtures, the allowed model classes, and the pass/fail thresholds that answer \"is this agent good enough to deploy?\". Distributed inside a pack tarball and referenced by URI exactly like `systemPromptRef` / `handoff.*SchemaRef` (RFC 0003 \u00a7C/\u00a7D) \u2014 NOT embedded in `AgentManifest`. A host advertising `capabilities.agents.evalSuite.supported: true` executes a suite as an eval run (a `mode: \"eval\"` projection over `POST /v1/runs`, RFC 0081 \u00a7B) and terminates with an `eval-summary.schema.json` scorecard. The suite carries NO secret material and NO host-internal identifiers (it is authored offline and shipped in a signed pack).",
5
+ "description": "RFC 0081 §A. A portable, host-agnostic evaluation suite for a manifest agent (RFC 0003/0070): the tasks, the expected outputs or rubrics, the deterministic tool/memory fixtures, the allowed model classes, and the pass/fail thresholds that answer \"is this agent good enough to deploy?\". Distributed inside a pack tarball and referenced by URI exactly like `systemPromptRef` / `handoff.*SchemaRef` (RFC 0003 §C/§D) NOT embedded in `AgentManifest`. A host advertising `capabilities.agents.evalSuite.supported: true` executes a suite as an eval run (a `mode: \"eval\"` projection over `POST /v1/runs`, RFC 0081 §B) and terminates with an `eval-summary.schema.json` scorecard. The suite carries NO secret material and NO host-internal identifiers (it is authored offline and shipped in a signed pack).",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -20,11 +20,12 @@
20
20
  "version": {
21
21
  "type": "string",
22
22
  "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
23
- "description": "SemVer of the suite. A suite version is pinned on an eval run (carried on `eval.started.suiteVersion` and `eval-summary.suiteVersion`) so a regression comparison (\u00a7D `regression` mode) is between like versions."
23
+ "description": "SemVer of the suite. A suite version is pinned on an eval run (carried on `eval.started.suiteVersion` and `eval-summary.suiteVersion`) so a regression comparison (§D `regression` mode) is between like versions."
24
24
  },
25
25
  "targetAgentId": {
26
- "$ref": "ids.schema.json#/$defs/agentId",
27
- "description": "MAY. The `AgentManifest.id` this suite is authored for. Absent \u21d2 the suite is agent-agnostic and MAY be pointed at any `agentId` at run time (the run request carries the `agentId`). When present, a host SHOULD reject an eval run whose target `agentId` differs, unless the caller explicitly overrides."
26
+ "type": "string",
27
+ "minLength": 1,
28
+ "description": "MAY. The `AgentManifest.id` this suite is authored for. Absent ⇒ the suite is agent-agnostic and MAY be pointed at any `agentId` at run time (the run request carries the `agentId`). When present, a host SHOULD reject an eval run whose target `agentId` differs, unless the caller explicitly overrides."
28
29
  },
29
30
  "modes": {
30
31
  "type": "array",
@@ -40,7 +41,7 @@
40
41
  "live-shadow"
41
42
  ]
42
43
  },
43
- "description": "The eval modes this suite exercises (RFC 0081 \u00a7D closed vocabulary). `golden`: exact / contains / json-match against each task's `expected`. `rubric`: a host-chosen judge scores against weighted criteria (nondeterministic \u2014 a recorded-fact score). `adversarial`: tasks probe for unsafe / jailbreak behavior; `safetyFindings` is the primary output. `regression`: re-run against a new agent/model/prompt version and diff scores vs a `baselineRunId` (composes RFC 0054 `:diff`). `live-shadow`: run against LIVE tools/memory instead of `fixtures` \u2014 the only mode that bypasses fixture injection; explicitly nondeterministic. A run MUST request only modes the suite declares here AND the host advertises (`capabilities.agents.evalSuite.modes`); an unadvertised mode is rejected at run-create with `400 validation_error`."
44
+ "description": "The eval modes this suite exercises (RFC 0081 §D closed vocabulary). `golden`: exact / contains / json-match against each task's `expected`. `rubric`: a host-chosen judge scores against weighted criteria (nondeterministic a recorded-fact score). `adversarial`: tasks probe for unsafe / jailbreak behavior; `safetyFindings` is the primary output. `regression`: re-run against a new agent/model/prompt version and diff scores vs a `baselineRunId` (composes RFC 0054 `:diff`). `live-shadow`: run against LIVE tools/memory instead of `fixtures` the only mode that bypasses fixture injection; explicitly nondeterministic. A run MUST request only modes the suite declares here AND the host advertises (`capabilities.agents.evalSuite.modes`); an unadvertised mode is rejected at run-create with `400 validation_error`."
44
45
  },
45
46
  "allowedModels": {
46
47
  "type": "array",
@@ -56,18 +57,18 @@
56
57
  "general"
57
58
  ]
58
59
  },
59
- "description": "MAY. The `AgentManifest.modelClass` values (RFC 0002) the suite is valid for. Absent \u21d2 valid for any class. A host SHOULD record the `evaluatedModelClass` on the summary so a score is interpreted against the model it was produced with."
60
+ "description": "MAY. The `AgentManifest.modelClass` values (RFC 0002) the suite is valid for. Absent valid for any class. A host SHOULD record the `evaluatedModelClass` on the summary so a score is interpreted against the model it was produced with."
60
61
  },
61
62
  "thresholds": {
62
63
  "type": "object",
63
64
  "additionalProperties": false,
64
- "description": "MAY. The pass/fail bar for the suite. A task or the aggregate `passed` flag is computed against these. Absent \u21d2 the host's default bar (the summary still carries raw scores).",
65
+ "description": "MAY. The pass/fail bar for the suite. A task or the aggregate `passed` flag is computed against these. Absent the host's default bar (the summary still carries raw scores).",
65
66
  "properties": {
66
67
  "passScore": {
67
68
  "type": "number",
68
69
  "minimum": 0,
69
70
  "maximum": 1,
70
- "description": "The minimum aggregate score (0.0\u20131.0) for `EvalSummary.passed: true`."
71
+ "description": "The minimum aggregate score (0.0–1.0) for `EvalSummary.passed: true`."
71
72
  },
72
73
  "maxCostUsd": {
73
74
  "type": "number",
@@ -100,7 +101,7 @@
100
101
  "description": "Suite-unique task identifier (kebab-case). Carried verbatim on `eval.scored.taskId` and the per-task summary entry."
101
102
  },
102
103
  "input": {
103
- "description": "The run input for the task, validated against the agent's input schema by the host. An opaque object/value \u2014 content is task-defined."
104
+ "description": "The run input for the task, validated against the agent's input schema by the host. An opaque object/value content is task-defined."
104
105
  },
105
106
  "expected": {
106
107
  "type": "object",
@@ -144,7 +145,7 @@
144
145
  "rubric": {
145
146
  "type": "array",
146
147
  "minItems": 1,
147
- "description": "Present when `kind: \"rubric\"`. Weighted criteria a judge scores the output against; the task score is the weighted sum of met criteria, normalized to 0.0\u20131.0. Judge selection + scoring is host-internal (nondeterministic \u2014 the score is a recorded fact).",
148
+ "description": "Present when `kind: \"rubric\"`. Weighted criteria a judge scores the output against; the task score is the weighted sum of met criteria, normalized to 0.0–1.0. Judge selection + scoring is host-internal (nondeterministic the score is a recorded fact).",
148
149
  "items": {
149
150
  "type": "object",
150
151
  "additionalProperties": false,
@@ -172,7 +173,7 @@
172
173
  "fixtures": {
173
174
  "type": "object",
174
175
  "additionalProperties": false,
175
- "description": "MAY. Deterministic substitutes for live tool/memory I/O so a `golden`/`regression` eval is reproducible. When present, the eval host MUST inject `toolResponses` in place of live tool calls and seed `memorySeed` before the invocation. The `live-shadow` mode is the explicit exception \u2014 it ignores `fixtures` and runs against live tools/memory.",
176
+ "description": "MAY. Deterministic substitutes for live tool/memory I/O so a `golden`/`regression` eval is reproducible. When present, the eval host MUST inject `toolResponses` in place of live tool calls and seed `memorySeed` before the invocation. The `live-shadow` mode is the explicit exception it ignores `fixtures` and runs against live tools/memory.",
176
177
  "properties": {
177
178
  "toolResponses": {
178
179
  "type": "array",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/artifact-type-pack-manifest.schema.json",
4
4
  "title": "ArtifactTypePackManifest",
5
- "description": "Manifest for a published OpenWOP artifact-type pack \u2014 `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 \u2014 the JSON Schema, rendering hint, lifecycle, and export-format hints for the rich outputs workflow nodes produce \u2014 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`.",
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
6
  "type": "object",
7
7
  "required": [
8
8
  "name",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "name": {
22
22
  "type": "string",
23
- "description": "Reverse-DNS pack name per `node-packs.md` \u00a7Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`). Mirror of `prompt-pack-manifest.schema.json#/properties/name`.",
23
+ "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`.",
24
24
  "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
25
25
  "minLength": 1,
26
26
  "maxLength": 256
@@ -65,7 +65,7 @@
65
65
  "properties": {
66
66
  "openwop": {
67
67
  "type": "string",
68
- "description": "Semver range \u2014 which openwop protocol versions this pack works against. Example: `>=1.1 <2.0.0`."
68
+ "description": "Semver range which openwop protocol versions this pack works against. Example: `>=1.1 <2.0.0`."
69
69
  }
70
70
  },
71
71
  "additionalProperties": false
@@ -75,7 +75,7 @@
75
75
  "additionalProperties": {
76
76
  "type": "string"
77
77
  },
78
- "description": "Other packs this pack depends on. Map of pack name \u2192 semver range. Resolved transitively at workflow-register time."
78
+ "description": "Other packs this pack depends on. Map of pack name semver range. Resolved transitively at workflow-register time."
79
79
  },
80
80
  "peerDependencies": {
81
81
  "type": "object",
@@ -106,25 +106,21 @@
106
106
  "additionalProperties": false,
107
107
  "properties": {
108
108
  "artifactTypeId": {
109
- "allOf": [
110
- {
111
- "$ref": "ids.schema.json#/$defs/typeId"
112
- },
113
- {
114
- "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$"
115
- }
116
- ],
117
- "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.*`."
109
+ "type": "string",
110
+ "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.*`.",
111
+ "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
112
+ "minLength": 1,
113
+ "maxLength": 256
118
114
  },
119
115
  "schemaRef": {
120
116
  "type": "string",
121
117
  "minLength": 1,
122
- "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` \u00a7\"Canonical schema location\"."
118
+ "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\"."
123
119
  },
124
120
  "schemaVersion": {
125
121
  "type": "integer",
126
122
  "minimum": 0,
127
- "description": "Non-negative integer artifact-schema version, parallel to the per-kind integer in `capabilities.schemaVersions`. Absent \u21d2 treated as 0. Bumped when the artifact schema changes shape. A version *declaration*, not a validation guarantee (RFC 0075 / P1-2)."
123
+ "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)."
128
124
  },
129
125
  "validation": {
130
126
  "type": "string",
@@ -132,7 +128,7 @@
132
128
  "open",
133
129
  "closed"
134
130
  ],
135
- "description": "RFC 0075. Strictness contract of the artifact's `schemaRef` schema. `closed` \u21d2 closed-world (`additionalProperties: false`); a consumer MAY rely on the absence of unknown fields. `open` (recommended for AI/LLM-produced artifacts) \u21d2 the schema tolerates extra fields to absorb model drift; consumers MUST ignore unknown fields per COMPATIBILITY.md \u00a72.1. Absent \u21d2 `open` (the forward-compatible default). The `additionalProperties:false` requirement on `schemaRef` was relaxed MUST \u2192 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."
131
+ "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."
136
132
  },
137
133
  "displayName": {
138
134
  "type": "string",
@@ -150,7 +146,7 @@
150
146
  "pattern": "^([a-z][a-z0-9]*|vendor\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*|x-[a-z][a-z0-9-]*)$"
151
147
  },
152
148
  "uniqueItems": true,
153
- "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 \u2014 it standardizes the identifier so two hosts agree what `pptx` names, not how the bytes are produced."
149
+ "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."
154
150
  },
155
151
  "syncOn": {
156
152
  "type": "string",
@@ -171,19 +167,19 @@
171
167
  },
172
168
  "diffable": {
173
169
  "type": "boolean",
174
- "description": "True if the artifact's schema supports structural diffing (informs run-diff tooling per rest-endpoints.md \u00a7:diff). Non-normative."
170
+ "description": "True if the artifact's schema supports structural diffing (informs run-diff tooling per rest-endpoints.md §:diff). Non-normative."
175
171
  }
176
172
  },
177
173
  "patternProperties": {
178
174
  "^(openwop-|x-|vendor\\.)": {
179
- "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` \u00a7\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque \u2014 a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` \u00a7\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
175
+ "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` §\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` §\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
180
176
  }
181
177
  }
182
178
  },
183
179
  "RenderingHint": {
184
180
  "type": "object",
185
181
  "additionalProperties": false,
186
- "description": "Advisory rendering hint. Reuses the closed vocabulary defined in ai-envelope.md \u00a7\"Rendering hints\" (RFC 0055). Advisory only \u2014 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).",
182
+ "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).",
187
183
  "properties": {
188
184
  "display": {
189
185
  "type": "string",
@@ -218,7 +214,7 @@
218
214
  },
219
215
  "Signing": {
220
216
  "type": "object",
221
- "description": "Optional signing metadata. See node-packs.md \u00a7signing.",
217
+ "description": "Optional signing metadata. See node-packs.md §signing.",
222
218
  "additionalProperties": false,
223
219
  "properties": {
224
220
  "publicKeyRef": {
@@ -242,7 +238,7 @@
242
238
  },
243
239
  "patternProperties": {
244
240
  "^(openwop-|x-|vendor\\.)": {
245
- "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` \u00a7\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque \u2014 a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` \u00a7\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
241
+ "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` §\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` §\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
246
242
  }
247
243
  },
248
244
  "x-openwop-seeded-from": "v1"
@@ -232,45 +232,6 @@
232
232
  "additionalProperties": true,
233
233
  "x-openwop-seeded-from": "v1"
234
234
  },
235
- "signingKeys": {
236
- "type": "array",
237
- "description": "RFC 0168 §E.2 — the public keys this host signs certification bundles with. A bundle signature names a keyId; a verifier resolves it HERE, in the discovery document of the host the bundle is about, and checks the Ed25519 signature with the matching publicKey. Without this array a signature attests integrity only: it proves the bundle was not altered after signing and says nothing about who signed it, because a signer can mint a keypair and a keyId at will. RFC 0168 disposed of \"an Ed25519 attestation without a key registry is a signature nobody can check\" by naming this surface; this is that surface.",
238
- "items": {
239
- "type": "object",
240
- "additionalProperties": false,
241
- "required": [
242
- "keyId",
243
- "alg",
244
- "publicKey"
245
- ],
246
- "properties": {
247
- "keyId": {
248
- "$ref": "ids.schema.json#/$defs/keyId",
249
- "description": "The identifier a bundle signature carries in signature.keyId. Unique within this array."
250
- },
251
- "alg": {
252
- "const": "ed25519",
253
- "description": "RFC 0168 §E.2 fixes the attestation algorithm; no other value is defined."
254
- },
255
- "publicKey": {
256
- "type": "string",
257
- "pattern": "^[A-Za-z0-9_-]{43}$",
258
- "description": "The Ed25519 public key, base64url, unpadded (32 bytes) — the half that verifies, never the half that signs."
259
- },
260
- "use": {
261
- "enum": [
262
- "certification-bundle"
263
- ],
264
- "description": "What the key signs. Closed, so a future use is an explicit addition rather than a reinterpretation of a key already published for something else."
265
- },
266
- "retiredAt": {
267
- "type": "string",
268
- "format": "date-time",
269
- "description": "When the key stopped signing. A retired key stays listed so bundles it already signed remain verifiable; dropping it would silently invalidate historical evidence, which is the opposite of what an evidence trail is for."
270
- }
271
- }
272
- }
273
- },
274
235
  "discovery": {
275
236
  "type": "object",
276
237
  "description": "Discovery advertisement (capabilities-change-detection.md). Optional in v1; absence means the host serves only the public unauthenticated payload at /.well-known/openwop. Landed by RFC 0011.",
@@ -254,7 +254,7 @@
254
254
  "properties": {
255
255
  "id": {
256
256
  "type": "string",
257
- "pattern": "^openwop\\.(?!it\\.(?:artifact-schema-compile-bounded|artifact-type-legacy-ids|capability-example-root-layout|certification-floor-enforcement|chain-subchain-unsupported-refused|compensation-profile|core-manifest-and-extension-registry|discovery-canonical-family-no-shadow|edge-condition-truthy-falsy|effect-identity-composition|effect-identity-cross-scope|error-envelope-canonical-shape|event-codemap-complete|form-content-packs|multi-region-effect-vocabulary|normative-example-extraction|openapi-asyncapi-sdk-parity|pack-manifest-extensions|protocol-version-grammar|registry-declarative-kinds|rfc-0147-self-audit|rfc-lifecycle-coherence|semantic-digest-v2|spec-corpus-validity|spec-section-citations|tool-result-trust-monotone|v2-alias-covers-reword|v2-corpus-tag-pinned|v2-declaration-parity|v2-error-registry-prose-parity|v2-event-naming-rule|v2-events-channel-parity|v2-externally-gated-never-stable|v2-id-kinds-bound|v2-bundle-signature-attributable|v2-one-signing-scheme|v2-path-parity|v2-release-identity|v2-req-only-assertions|v2-seams-not-in-canonical|v2-security-defaults-table|v2-spec-artifacts-digest|v2-threat-model-template|v2-witness-required|versioned-composition-profiles|workflow-chain-internal-flag|workload-identity-profile)\\.)(requirement|it|scenario|floor|profile|family)\\.[a-z0-9]",
257
+ "pattern": "^openwop\\.(?!it\\.(?:artifact-schema-compile-bounded|artifact-type-legacy-ids|capability-example-root-layout|certification-floor-enforcement|chain-subchain-unsupported-refused|compensation-profile|core-manifest-and-extension-registry|discovery-canonical-family-no-shadow|edge-condition-truthy-falsy|effect-identity-composition|effect-identity-cross-scope|error-envelope-canonical-shape|event-codemap-complete|form-content-packs|multi-region-effect-vocabulary|normative-example-extraction|openapi-asyncapi-sdk-parity|pack-manifest-extensions|protocol-version-grammar|registry-declarative-kinds|rfc-0147-self-audit|rfc-lifecycle-coherence|semantic-digest-v2|spec-corpus-validity|spec-section-citations|tool-result-trust-monotone|v2-alias-covers-reword|v2-corpus-tag-pinned|v2-declaration-parity|v2-error-registry-prose-parity|v2-event-naming-rule|v2-events-channel-parity|v2-externally-gated-never-stable|v2-one-signing-scheme|v2-path-parity|v2-release-identity|v2-req-only-assertions|v2-seams-not-in-canonical|v2-security-defaults-table|v2-spec-artifacts-digest|v2-threat-model-template|v2-witness-required|versioned-composition-profiles|workflow-chain-internal-flag|workload-identity-profile)\\.)(requirement|it|scenario|floor|profile|family)\\.[a-z0-9]",
258
258
  "description": "RFC 0168 §A.1 — `openwop.<area>.<slug>`. The suite mints six areas: `requirement` (an explicit `req()` id), `it` (a per-test id from the scenario file and title), `scenario` and `floor` (per-file rows), `profile` (a claimed-profile row) and `family` (a capability gate). The lookahead refuses every id minted from a corpus-coherence file: those run in the spec repo’s CI and MUST NOT appear in a host bundle (conformance.md §\"Two products, two ledgers\"; RFC 0168 §D.1). `scripts/check-req-only.mjs` fails when the list drifts from `conformance/src/coherence/`."
259
259
  },
260
260
  "scenario": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/chat-card-pack-manifest.schema.json",
4
4
  "title": "ChatCardPackManifest",
5
- "description": "Manifest for a published OpenWOP AI chat card pack \u2014 `pack.json` at the pack root with `kind: \"card\"`. Peer to the node / workflow-chain / prompt / artifact-type pack manifests; disjoint via the `kind` discriminator. See `spec/v1/chat-card-packs.md` for the canonical contract and RFC 0071 Phase 2 for the rationale.\n\nA chat card pack distributes AI step cards: each card binds a prompt template (with typed input slots) to a typed output artifact. When a host advertises `host.chat.cardPacks: supported` and a registered card is invoked, the host substitutes inputs into the prompt, routes the call through `ctx.aiEnvelope.generate`, and (when `outputArtifactType` is set) validates the result against the referenced artifact-type pack's schema before emitting `artifact.created`.",
5
+ "description": "Manifest for a published OpenWOP AI chat card pack `pack.json` at the pack root with `kind: \"card\"`. Peer to the node / workflow-chain / prompt / artifact-type pack manifests; disjoint via the `kind` discriminator. See `spec/v1/chat-card-packs.md` for the canonical contract and RFC 0071 Phase 2 for the rationale.\n\nA chat card pack distributes AI step cards: each card binds a prompt template (with typed input slots) to a typed output artifact. When a host advertises `host.chat.cardPacks: supported` and a registered card is invoked, the host substitutes inputs into the prompt, routes the call through `ctx.aiEnvelope.generate`, and (when `outputArtifactType` is set) validates the result against the referenced artifact-type pack's schema before emitting `artifact.created`.",
6
6
  "type": "object",
7
7
  "required": [
8
8
  "name",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "name": {
22
22
  "type": "string",
23
- "description": "Reverse-DNS pack name per `node-packs.md` \u00a7Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`).",
23
+ "description": "Reverse-DNS pack name per `node-packs.md` §Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`).",
24
24
  "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
25
25
  "minLength": 1,
26
26
  "maxLength": 256
@@ -65,7 +65,7 @@
65
65
  "properties": {
66
66
  "openwop": {
67
67
  "type": "string",
68
- "description": "Semver range \u2014 which openwop protocol versions this pack works against."
68
+ "description": "Semver range which openwop protocol versions this pack works against."
69
69
  }
70
70
  },
71
71
  "additionalProperties": false
@@ -75,7 +75,7 @@
75
75
  "additionalProperties": {
76
76
  "type": "string"
77
77
  },
78
- "description": "Other packs this pack depends on (e.g., the artifact-type pack declaring this card's `outputArtifactType`). Map of pack name \u2192 semver range."
78
+ "description": "Other packs this pack depends on (e.g., the artifact-type pack declaring this card's `outputArtifactType`). Map of pack name semver range."
79
79
  },
80
80
  "peerDependencies": {
81
81
  "type": "object",
@@ -106,20 +106,16 @@
106
106
  "additionalProperties": false,
107
107
  "properties": {
108
108
  "cardTypeId": {
109
- "allOf": [
110
- {
111
- "$ref": "ids.schema.json#/$defs/typeId"
112
- },
113
- {
114
- "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$"
115
- }
116
- ],
117
- "description": "Reverse-DNS card identifier. Same pattern and reserved scopes as a pack `name`. The value `WorkflowNode.cardType` / `ctx.chat.emitCard` MAY reference. Third parties MUST NOT publish under `core.*`."
109
+ "type": "string",
110
+ "description": "Reverse-DNS card identifier. Same pattern and reserved scopes as a pack `name`. The value `WorkflowNode.cardType` / `ctx.chat.emitCard` MAY reference. Third parties MUST NOT publish under `core.*`.",
111
+ "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
112
+ "minLength": 1,
113
+ "maxLength": 256
118
114
  },
119
115
  "schemaVersion": {
120
116
  "type": "integer",
121
117
  "minimum": 0,
122
- "description": "Non-negative integer card-schema version (the envelope/artifact integer-version axis). Absent \u21d2 treated as 0."
118
+ "description": "Non-negative integer card-schema version (the envelope/artifact integer-version axis). Absent treated as 0."
123
119
  },
124
120
  "prompt": {
125
121
  "$ref": "#/$defs/PromptSpec"
@@ -154,7 +150,7 @@
154
150
  },
155
151
  "patternProperties": {
156
152
  "^(openwop-|x-|vendor\\.)": {
157
- "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` \u00a7\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque \u2014 a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` \u00a7\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
153
+ "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` §\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` §\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
158
154
  }
159
155
  }
160
156
  },
@@ -181,7 +177,7 @@
181
177
  "additionalProperties": {
182
178
  "type": "string"
183
179
  },
184
- "description": "Map of `{{placeholder}}` name \u2192 input path (e.g. `\"spec\": \"inputs.spec\"`)."
180
+ "description": "Map of `{{placeholder}}` name input path (e.g. `\"spec\": \"inputs.spec\"`)."
185
181
  },
186
182
  "temperature": {
187
183
  "type": "number",
@@ -209,7 +205,7 @@
209
205
  },
210
206
  "type": {
211
207
  "type": "string",
212
- "description": "Closed portable subset OR a `vendor.<org>.<kind>` / `x-<kind>` host extension other hosts ignore. The portable subset (G9, resolved 2026-05-27 against MyndHyve's `CardFieldType`): `text`, `longtext`, `number`, `boolean`, `select`, `multiselect`, `file`, `artifact-ref`. MyndHyve maps `textarea`\u2192`longtext` and `toggle`\u2192`boolean`; its product-specific kinds (`canvas-reference`, `collection-reference`, `color`) are host extensions (`vendor.myndhyve.*`), not portable.",
208
+ "description": "Closed portable subset OR a `vendor.<org>.<kind>` / `x-<kind>` host extension other hosts ignore. The portable subset (G9, resolved 2026-05-27 against MyndHyve's `CardFieldType`): `text`, `longtext`, `number`, `boolean`, `select`, `multiselect`, `file`, `artifact-ref`. MyndHyve maps `textarea`→`longtext` and `toggle`→`boolean`; its product-specific kinds (`canvas-reference`, `collection-reference`, `color`) are host extensions (`vendor.myndhyve.*`), not portable.",
213
209
  "pattern": "^(text|longtext|number|boolean|select|multiselect|file|artifact-ref|vendor\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*|x-[a-z][a-z0-9-]*)$"
214
210
  },
215
211
  "label": {
@@ -230,7 +226,7 @@
230
226
  },
231
227
  "Signing": {
232
228
  "type": "object",
233
- "description": "Optional signing metadata. See node-packs.md \u00a7signing.",
229
+ "description": "Optional signing metadata. See node-packs.md §signing.",
234
230
  "additionalProperties": false,
235
231
  "properties": {
236
232
  "publicKeyRef": {
@@ -251,7 +247,7 @@
251
247
  },
252
248
  "patternProperties": {
253
249
  "^(openwop-|x-|vendor\\.)": {
254
- "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` \u00a7\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque \u2014 a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` \u00a7\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
250
+ "description": "Vendor / host extension escape hatch (RFC 0138). A property matching `^(x-|vendor\\.)` is a HOST EXTENSION: its semantics are unspecified by this protocol, and a consumer that does not recognize one MUST ignore it rather than reject the pack. Resolves the contradiction in `host-extensions.md` §\"Vendor-prefixed namespaces\", which requires a client receiving an unknown vendor-prefixed field to treat it as opaque a field that `additionalProperties: false` previously made impossible to carry. SECURITY: an extension value is PACK-AUTHORED, therefore untrusted; \"ignore\" means ignore. See `node-packs.md` §\"Vendor extensions on pack manifests\" and the `pack-manifest-extension-opaque` invariant."
255
251
  }
256
252
  },
257
253
  "x-openwop-seeded-from": "v1"
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/debug-bundle.schema.json",
4
4
  "title": "RunDebugBundle",
5
- "description": "Portable JSON export of a single run's diagnostic state. See spec/v1/debug-bundle.md. Additive over v1 per COMPATIBILITY.md \u00a72.1: optional endpoint; hosts MAY omit.",
5
+ "description": "Portable JSON export of a single run's diagnostic state. See spec/v1/debug-bundle.md. Additive over v1 per COMPATIBILITY.md §2.1: optional endpoint; hosts MAY omit.",
6
6
  "type": "object",
7
7
  "required": [
8
8
  "bundleVersion",
@@ -16,7 +16,7 @@
16
16
  "properties": {
17
17
  "bundleVersion": {
18
18
  "const": "2",
19
- "description": "RFC 0172 \u00a7B axis 10 \u2014 one const family; this bundle is \"2\" in v2."
19
+ "description": "RFC 0172 §B axis 10 one const family; this bundle is \"2\" in v2."
20
20
  },
21
21
  "generatedAt": {
22
22
  "type": "string",
@@ -47,7 +47,7 @@
47
47
  },
48
48
  "run": {
49
49
  "type": "object",
50
- "description": "Run snapshot \u2014 same shape as GET /v1/runs/{runId}. See run-snapshot.schema.json.",
50
+ "description": "Run snapshot same shape as GET /v1/runs/{runId}. See run-snapshot.schema.json.",
51
51
  "required": [
52
52
  "runId",
53
53
  "workflowId",
@@ -121,7 +121,7 @@
121
121
  "currentNodeId": {
122
122
  "oneOf": [
123
123
  {
124
- "$ref": "ids.schema.json#/$defs/nodeId"
124
+ "type": "string"
125
125
  },
126
126
  {
127
127
  "type": "null"
@@ -167,7 +167,7 @@
167
167
  "nodeId": {
168
168
  "oneOf": [
169
169
  {
170
- "$ref": "ids.schema.json#/$defs/nodeId"
170
+ "type": "string"
171
171
  },
172
172
  {
173
173
  "type": "null"
@@ -198,7 +198,7 @@
198
198
  "parentSpanId": {
199
199
  "oneOf": [
200
200
  {
201
- "$ref": "ids.schema.json#/$defs/spanId"
201
+ "type": "string"
202
202
  },
203
203
  {
204
204
  "type": "null"
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/eval-summary.schema.json",
4
4
  "title": "EvalSummary",
5
- "description": "RFC 0081 \u00a7C. The terminal scorecard of an eval run (the `mode: \"eval\"` projection over `POST /v1/runs`, RFC 0081 \u00a7B): the aggregate + per-task scores, cost, latency, schema-validity, and safety findings, plus the suite provenance and (for `regression` mode) the score delta vs a baseline. Set as the eval run's output and served by `GET /v1/runs/{runId}/eval-summary`. SECURITY invariant `eval-summary-no-content-leak`: the summary carries scores, ids, counts, and redaction-safe safety descriptors only \u2014 NEVER task output bodies, rubric prose, model completions, prompts, or credential material (SR-1). A consumer reads the run's normal projection for any body.",
5
+ "description": "RFC 0081 §C. The terminal scorecard of an eval run (the `mode: \"eval\"` projection over `POST /v1/runs`, RFC 0081 §B): the aggregate + per-task scores, cost, latency, schema-validity, and safety findings, plus the suite provenance and (for `regression` mode) the score delta vs a baseline. Set as the eval run's output and served by `GET /v1/runs/{runId}/eval-summary`. SECURITY invariant `eval-summary-no-content-leak`: the summary carries scores, ids, counts, and redaction-safe safety descriptors only NEVER task output bodies, rubric prose, model completions, prompts, or credential material (SR-1). A consumer reads the run's normal projection for any body.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -41,11 +41,11 @@
41
41
  "type": "number",
42
42
  "minimum": 0,
43
43
  "maximum": 1,
44
- "description": "The suite-level score (0.0\u20131.0): the aggregation (host-defined, typically the mean) of per-task scores."
44
+ "description": "The suite-level score (0.0–1.0): the aggregation (host-defined, typically the mean) of per-task scores."
45
45
  },
46
46
  "passed": {
47
47
  "type": "boolean",
48
- "description": "Whether the run cleared the suite's `thresholds` (RFC 0081 \u00a7A) \u2014 `aggregateScore >= passScore` AND, when declared, `totalCostUsd <= maxCostUsd` AND the p95 latency bar. The load-bearing flag an RFC 0082 deployment gate may require (`requiredEval`)."
48
+ "description": "Whether the run cleared the suite's `thresholds` (RFC 0081 §A) `aggregateScore >= passScore` AND, when declared, `totalCostUsd <= maxCostUsd` AND the p95 latency bar. The load-bearing flag an RFC 0082 deployment gate may require (`requiredEval`)."
49
49
  },
50
50
  "taskCount": {
51
51
  "type": "integer",
@@ -60,7 +60,7 @@
60
60
  "totalCostUsd": {
61
61
  "type": "number",
62
62
  "minimum": 0,
63
- "description": "MAY. Total cost of the run, summed from the per-task RFC 0026 `provider.usage` events (the scalar only \u2014 never a pricing breakdown or rate card; `eval-summary-no-content-leak`)."
63
+ "description": "MAY. Total cost of the run, summed from the per-task RFC 0026 `provider.usage` events (the scalar only never a pricing breakdown or rate card; `eval-summary-no-content-leak`)."
64
64
  },
65
65
  "tasks": {
66
66
  "type": "array",
@@ -83,7 +83,7 @@
83
83
  "type": "number",
84
84
  "minimum": 0,
85
85
  "maximum": 1,
86
- "description": "Task score (0.0\u20131.0)."
86
+ "description": "Task score (0.0–1.0)."
87
87
  },
88
88
  "passed": {
89
89
  "type": "boolean",
@@ -105,7 +105,7 @@
105
105
  },
106
106
  "safetyFindings": {
107
107
  "type": "array",
108
- "description": "MAY. Redaction-safe safety findings (primarily `adversarial` mode). Each is a `{kind, severity}` descriptor \u2014 NO excerpted content, prompt, or completion text (`eval-summary-no-content-leak`).",
108
+ "description": "MAY. Redaction-safe safety findings (primarily `adversarial` mode). Each is a `{kind, severity}` descriptor NO excerpted content, prompt, or completion text (`eval-summary-no-content-leak`).",
109
109
  "items": {
110
110
  "type": "object",
111
111
  "additionalProperties": false,
@@ -117,7 +117,7 @@
117
117
  "kind": {
118
118
  "type": "string",
119
119
  "minLength": 1,
120
- "description": "Finding category (e.g. `jailbreak`, `pii-leak`, `unsafe-tool-call`) \u2014 a category label, not excerpted content."
120
+ "description": "Finding category (e.g. `jailbreak`, `pii-leak`, `unsafe-tool-call`) a category label, not excerpted content."
121
121
  },
122
122
  "severity": {
123
123
  "type": "string",
@@ -135,14 +135,6 @@
135
135
  }
136
136
  }
137
137
  },
138
- "pinnedNodeIds": {
139
- "type": "array",
140
- "items": {
141
- "$ref": "ids.schema.json#/$defs/nodeId"
142
- },
143
- "uniqueItems": true,
144
- "description": "MAY. The node ids whose outputs were PINNED (mocked) for this eval run rather than executed, so a reader knows the verdict's scope. Ids only, never the pinned values: this summary MUST be content-free of task output (runs.md), and a pin IS a task output. The values live on the eval run's own resume snapshot, behind the run's auth, where a reproducer with access can fetch them. Added 2026-09-04 after a tier-1 host proposed `pinned: true` on each node.completed event and asked first \u2014 replay-ness is a run property (replay.md \u00a7Determinism 5, webhooks.md \u00a7Replay), so the per-event flag was refused and the seat moved here: reproducibility of SCOPE on the wire, reproducibility of VALUES behind the boundary."
145
- },
146
138
  "regression": {
147
139
  "type": "object",
148
140
  "additionalProperties": false,
@@ -153,14 +145,15 @@
153
145
  ],
154
146
  "properties": {
155
147
  "baselineRunId": {
156
- "$ref": "ids.schema.json#/$defs/runId",
148
+ "type": "string",
149
+ "minLength": 1,
157
150
  "description": "The prior eval run this run is compared against."
158
151
  },
159
152
  "scoreDelta": {
160
153
  "type": "number",
161
154
  "minimum": -1,
162
155
  "maximum": 1,
163
- "description": "`aggregateScore` minus the baseline's (negative \u21d2 regression)."
156
+ "description": "`aggregateScore` minus the baseline's (negative regression)."
164
157
  },
165
158
  "diffRef": {
166
159
  "type": "string",