@openwop/spec-artifacts 2.0.0-rc.9 → 2.0.1

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 (39) hide show
  1. package/CORPUS-STAMP.json +40 -37
  2. package/api/seams-v2.yaml +1 -1
  3. package/api/v2/asyncapi.yaml +1 -1
  4. package/api/v2/openapi.yaml +17 -19
  5. package/package.json +1 -1
  6. package/schemas/capabilities.schema.json +40 -1
  7. package/schemas/run-snapshot.schema.json +103 -33
  8. package/schemas/v2/agent-deployment-transition.schema.json +5 -6
  9. package/schemas/v2/agent-deployment.schema.json +8 -9
  10. package/schemas/v2/agent-eval-suite.schema.json +11 -12
  11. package/schemas/v2/artifact-type-pack-manifest.schema.json +22 -18
  12. package/schemas/v2/certification-bundle.schema.json +1 -1
  13. package/schemas/v2/chat-card-pack-manifest.schema.json +19 -15
  14. package/schemas/v2/debug-bundle.schema.json +6 -6
  15. package/schemas/v2/effect-ledger-projection.schema.json +4 -3
  16. package/schemas/v2/effect-seam-manifest.schema.json +30 -7
  17. package/schemas/v2/error-envelope.schema.json +185 -138
  18. package/schemas/v2/eval-summary.schema.json +17 -10
  19. package/schemas/v2/goal.schema.json +5 -5
  20. package/schemas/v2/ids.schema.json +120 -22
  21. package/schemas/v2/node-pack-manifest.schema.json +27 -31
  22. package/schemas/v2/proposal.schema.json +7 -8
  23. package/schemas/v2/run-event-payloads.schema.json +258 -245
  24. package/schemas/v2/run-event.schema.json +2 -126
  25. package/schemas/v2/run-options.schema.json +1 -1
  26. package/schemas/v2/run-snapshot.schema.json +34 -13
  27. package/schemas/v2/webhook-delivery.schema.json +26 -0
  28. package/schemas/v2/workflow-chain-pack-manifest.schema.json +41 -45
  29. package/schemas/v2/workflow-definition.schema.json +31 -36
  30. package/spec/v1/core-standard-manifest.json +2 -2
  31. package/spec/v1/deprecations.json +79 -67
  32. package/spec/v1/deprecations.schema.json +23 -7
  33. package/spec/v1/extensions.json +3 -2
  34. package/spec/v2/declaration.json +57 -33
  35. package/spec/v2/errors.json +421 -360
  36. package/spec/v2/id-field-bindings.json +105 -0
  37. package/spec/v2/profiles.json +31 -7
  38. package/spec/v2/release.json +3 -3
  39. package/spec/v2/retention-floors.json +35 -0
@@ -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-transition.schema.json",
4
4
  "title": "AgentDeploymentTransition",
5
- "description": "RFC 0082 §E. The request body of POST /v1/agents/{agentId}/deployments a deployment state-transition request. The host authorizes it fail-closed against the RFC 0049 `deploy:*` scope, runs any configured RFC 0051 approvalGate, enforces the RFC 0081 eval evidence when the gate requires it, and on success emits the matching `deployment.*` event and returns the updated `agent-deployment.schema.json` record. Carries no manifest body or credential material (SR-1).",
5
+ "description": "RFC 0082 \u00a7E. The request body of POST /v1/agents/{agentId}/deployments \u2014 a deployment state-transition request. The host authorizes it fail-closed against the RFC 0049 `deploy:*` scope, runs any configured RFC 0051 approvalGate, enforces the RFC 0081 eval evidence when the gate requires it, and on success emits the matching `deployment.*` event and returns the updated `agent-deployment.schema.json` record. Carries no manifest body or credential material (SR-1).",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -24,7 +24,7 @@
24
24
  "rollback",
25
25
  "adjust-canary"
26
26
  ],
27
- "description": "The lifecycle operation. `promote`: advance toward production (draft→test→staged→active) into `toState`. `pause`: active→paused. `deprecate`: active→deprecated. `rollback`: active→rolled-back, restoring a prior version. `adjust-canary`: change the active version's `canaryPercent`. Legal transitions + the seven-state machine are normative in `agent-deployment.md` §C."
27
+ "description": "The lifecycle operation. `promote`: advance toward production (draft\u2192test\u2192staged\u2192active) into `toState`. `pause`: active\u2192paused. `deprecate`: active\u2192deprecated. `rollback`: active\u2192rolled-back, restoring a prior version. `adjust-canary`: change the active version's `canaryPercent`. Legal transitions + the seven-state machine are normative in `agent-deployment.md` \u00a7C."
28
28
  },
29
29
  "toState": {
30
30
  "type": "string",
@@ -43,7 +43,7 @@
43
43
  "type": "string",
44
44
  "minLength": 1,
45
45
  "maxLength": 64,
46
- "description": "MAY. The named deployment channel this transition targets (e.g. `stable`). The version becomes resolvable by `AgentRef.channel` = this value (RFC 0082 §A/§B)."
46
+ "description": "MAY. The named deployment channel this transition targets (e.g. `stable`). The version becomes resolvable by `AgentRef.channel` = this value (RFC 0082 \u00a7A/\u00a7B)."
47
47
  },
48
48
  "canaryPercent": {
49
49
  "type": "integer",
@@ -52,9 +52,8 @@
52
52
  "description": "MAY. For `promote` to `active` or `adjust-canary`, the share of channel traffic this version takes. A host advertising `capabilities.agents.deployment.canary: false` MUST reject any value < 100."
53
53
  },
54
54
  "evalRunId": {
55
- "type": "string",
56
- "minLength": 1,
57
- "description": "MAY. The RFC 0081 eval run whose `EvalSummary.passed` the gate verifies before emitting `deployment.promoted` (the §E evidence). Required when the target `approvalGate` is configured with `requiredEval`; an unmet eval gate is rejected with `eval_gate_unmet`."
55
+ "$ref": "ids.schema.json#/$defs/runId",
56
+ "description": "MAY. The RFC 0081 eval run whose `EvalSummary.passed` the gate verifies before emitting `deployment.promoted` (the \u00a7E evidence). Required when the target `approvalGate` is configured with `requiredEval`; an unmet eval gate is rejected with `eval_gate_unmet`."
58
57
  },
59
58
  "reason": {
60
59
  "type": "string",
@@ -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 §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).",
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).",
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 §B 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 \u00a7B 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 §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`)."
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`)."
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–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."
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."
41
41
  },
42
42
  "rollbackPointer": {
43
43
  "type": "string",
@@ -51,17 +51,16 @@
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 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 \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`."
55
55
  },
56
56
  "evalRunId": {
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."
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."
60
59
  },
61
60
  "approvalGateId": {
62
61
  "type": "string",
63
62
  "minLength": 1,
64
- "description": "MAY. The RFC 0051 `approvalGate` that authorized the last transition (the §E human gate). Content-free reference."
63
+ "description": "MAY. The RFC 0051 `approvalGate` that authorized the last transition (the \u00a7E human gate). Content-free reference."
65
64
  }
66
65
  },
67
66
  "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 §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).",
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).",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -20,12 +20,11 @@
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 (§D `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 (\u00a7D `regression` mode) is between like versions."
24
24
  },
25
25
  "targetAgentId": {
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."
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."
29
28
  },
30
29
  "modes": {
31
30
  "type": "array",
@@ -41,7 +40,7 @@
41
40
  "live-shadow"
42
41
  ]
43
42
  },
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`."
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`."
45
44
  },
46
45
  "allowedModels": {
47
46
  "type": "array",
@@ -57,18 +56,18 @@
57
56
  "general"
58
57
  ]
59
58
  },
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."
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."
61
60
  },
62
61
  "thresholds": {
63
62
  "type": "object",
64
63
  "additionalProperties": false,
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).",
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).",
66
65
  "properties": {
67
66
  "passScore": {
68
67
  "type": "number",
69
68
  "minimum": 0,
70
69
  "maximum": 1,
71
- "description": "The minimum aggregate score (0.0–1.0) for `EvalSummary.passed: true`."
70
+ "description": "The minimum aggregate score (0.0\u20131.0) for `EvalSummary.passed: true`."
72
71
  },
73
72
  "maxCostUsd": {
74
73
  "type": "number",
@@ -101,7 +100,7 @@
101
100
  "description": "Suite-unique task identifier (kebab-case). Carried verbatim on `eval.scored.taskId` and the per-task summary entry."
102
101
  },
103
102
  "input": {
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."
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."
105
104
  },
106
105
  "expected": {
107
106
  "type": "object",
@@ -145,7 +144,7 @@
145
144
  "rubric": {
146
145
  "type": "array",
147
146
  "minItems": 1,
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).",
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).",
149
148
  "items": {
150
149
  "type": "object",
151
150
  "additionalProperties": false,
@@ -173,7 +172,7 @@
173
172
  "fixtures": {
174
173
  "type": "object",
175
174
  "additionalProperties": false,
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.",
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.",
177
176
  "properties": {
178
177
  "toolResponses": {
179
178
  "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 `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`.",
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`.",
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` §Naming. 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` \u00a7Naming. 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 which openwop protocol versions this pack works against. Example: `>=1.1 <2.0.0`."
68
+ "description": "Semver range \u2014 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 semver range. Resolved transitively at workflow-register time."
78
+ "description": "Other packs this pack depends on. Map of pack name \u2192 semver range. Resolved transitively at workflow-register time."
79
79
  },
80
80
  "peerDependencies": {
81
81
  "type": "object",
@@ -106,21 +106,25 @@
106
106
  "additionalProperties": false,
107
107
  "properties": {
108
108
  "artifactTypeId": {
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
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.*`."
114
118
  },
115
119
  "schemaRef": {
116
120
  "type": "string",
117
121
  "minLength": 1,
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\"."
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\"."
119
123
  },
120
124
  "schemaVersion": {
121
125
  "type": "integer",
122
126
  "minimum": 0,
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)."
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)."
124
128
  },
125
129
  "validation": {
126
130
  "type": "string",
@@ -128,7 +132,7 @@
128
132
  "open",
129
133
  "closed"
130
134
  ],
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."
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."
132
136
  },
133
137
  "displayName": {
134
138
  "type": "string",
@@ -146,7 +150,7 @@
146
150
  "pattern": "^([a-z][a-z0-9]*|vendor\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*|x-[a-z][a-z0-9-]*)$"
147
151
  },
148
152
  "uniqueItems": true,
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."
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."
150
154
  },
151
155
  "syncOn": {
152
156
  "type": "string",
@@ -167,19 +171,19 @@
167
171
  },
168
172
  "diffable": {
169
173
  "type": "boolean",
170
- "description": "True if the artifact's schema supports structural diffing (informs run-diff tooling per rest-endpoints.md §:diff). Non-normative."
174
+ "description": "True if the artifact's schema supports structural diffing (informs run-diff tooling per rest-endpoints.md \u00a7:diff). Non-normative."
171
175
  }
172
176
  },
173
177
  "patternProperties": {
174
178
  "^(openwop-|x-|vendor\\.)": {
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."
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."
176
180
  }
177
181
  }
178
182
  },
179
183
  "RenderingHint": {
180
184
  "type": "object",
181
185
  "additionalProperties": false,
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).",
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).",
183
187
  "properties": {
184
188
  "display": {
185
189
  "type": "string",
@@ -214,7 +218,7 @@
214
218
  },
215
219
  "Signing": {
216
220
  "type": "object",
217
- "description": "Optional signing metadata. See node-packs.md §signing.",
221
+ "description": "Optional signing metadata. See node-packs.md \u00a7signing.",
218
222
  "additionalProperties": false,
219
223
  "properties": {
220
224
  "publicKeyRef": {
@@ -238,7 +242,7 @@
238
242
  },
239
243
  "patternProperties": {
240
244
  "^(openwop-|x-|vendor\\.)": {
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."
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."
242
246
  }
243
247
  },
244
248
  "x-openwop-seeded-from": "v1"
@@ -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-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-eos-clock|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-retention-floors|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 `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 \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`.",
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` §Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`).",
23
+ "description": "Reverse-DNS pack name per `node-packs.md` \u00a7Naming. 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 which openwop protocol versions this pack works against."
68
+ "description": "Semver range \u2014 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 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 \u2192 semver range."
79
79
  },
80
80
  "peerDependencies": {
81
81
  "type": "object",
@@ -106,16 +106,20 @@
106
106
  "additionalProperties": false,
107
107
  "properties": {
108
108
  "cardTypeId": {
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
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.*`."
114
118
  },
115
119
  "schemaVersion": {
116
120
  "type": "integer",
117
121
  "minimum": 0,
118
- "description": "Non-negative integer card-schema version (the envelope/artifact integer-version axis). Absent treated as 0."
122
+ "description": "Non-negative integer card-schema version (the envelope/artifact integer-version axis). Absent \u21d2 treated as 0."
119
123
  },
120
124
  "prompt": {
121
125
  "$ref": "#/$defs/PromptSpec"
@@ -150,7 +154,7 @@
150
154
  },
151
155
  "patternProperties": {
152
156
  "^(openwop-|x-|vendor\\.)": {
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."
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."
154
158
  }
155
159
  }
156
160
  },
@@ -177,7 +181,7 @@
177
181
  "additionalProperties": {
178
182
  "type": "string"
179
183
  },
180
- "description": "Map of `{{placeholder}}` name input path (e.g. `\"spec\": \"inputs.spec\"`)."
184
+ "description": "Map of `{{placeholder}}` name \u2192 input path (e.g. `\"spec\": \"inputs.spec\"`)."
181
185
  },
182
186
  "temperature": {
183
187
  "type": "number",
@@ -205,7 +209,7 @@
205
209
  },
206
210
  "type": {
207
211
  "type": "string",
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.",
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.",
209
213
  "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-]*)$"
210
214
  },
211
215
  "label": {
@@ -226,7 +230,7 @@
226
230
  },
227
231
  "Signing": {
228
232
  "type": "object",
229
- "description": "Optional signing metadata. See node-packs.md §signing.",
233
+ "description": "Optional signing metadata. See node-packs.md \u00a7signing.",
230
234
  "additionalProperties": false,
231
235
  "properties": {
232
236
  "publicKeyRef": {
@@ -247,7 +251,7 @@
247
251
  },
248
252
  "patternProperties": {
249
253
  "^(openwop-|x-|vendor\\.)": {
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."
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."
251
255
  }
252
256
  },
253
257
  "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 §2.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 \u00a72.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 §B axis 10 one const family; this bundle is \"2\" in v2."
19
+ "description": "RFC 0172 \u00a7B axis 10 \u2014 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 same shape as GET /v1/runs/{runId}. See run-snapshot.schema.json.",
50
+ "description": "Run snapshot \u2014 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
- "type": "string"
124
+ "$ref": "ids.schema.json#/$defs/nodeId"
125
125
  },
126
126
  {
127
127
  "type": "null"
@@ -167,7 +167,7 @@
167
167
  "nodeId": {
168
168
  "oneOf": [
169
169
  {
170
- "type": "string"
170
+ "$ref": "ids.schema.json#/$defs/nodeId"
171
171
  },
172
172
  {
173
173
  "type": "null"
@@ -198,7 +198,7 @@
198
198
  "parentSpanId": {
199
199
  "oneOf": [
200
200
  {
201
- "type": "string"
201
+ "$ref": "ids.schema.json#/$defs/spanId"
202
202
  },
203
203
  {
204
204
  "type": "null"
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/effect-ledger-projection.schema.json",
4
- "title": "Effect ledger projection (RFC 0173 §C.2)",
5
- "description": "GET /runs/{runId}/effects the Layer-2 effect records keyed on business identity (the activity recipe is the documented fallback). Content-free of provider payloads.",
4
+ "title": "Effect ledger projection (RFC 0173 \u00a7C.2)",
5
+ "description": "GET /runs/{runId}/effects \u2014 the Layer-2 effect records keyed on business identity (the activity recipe is the documented fallback). Content-free of provider payloads.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -58,7 +58,8 @@
58
58
  "completed",
59
59
  "released",
60
60
  "escaped"
61
- ]
61
+ ],
62
+ "description": "The attempt's lifecycle state. The enum is the VOCABULARY a host must label attempts with, not a set of states every host must produce: a host emits the states its own effect lifecycle actually reaches, and one that only claims and completes attempts emits only `claimed` and `completed`. Both floor scenarios that read this projection witness attempt EXISTENCE and identity \u2014 `v2-effect-seam-no-refire` compares row COUNTS across a replay fork and `v2-effect-identity-business-key` reads `effectId`/`providerKey` across attempts; neither reads `state`. So a two-state ledger is schema-valid and witness-sufficient, and `released`/`escaped` are projection surface for operators rather than witness surface for the suite. What a host MUST NOT do is record only exceptional attempts: a ledger that writes a row only when an effect ESCAPES leaves a correctly-suppressed effect invisible, and suppression is then unwitnessable \u2014 the no-re-fire scenario records `blocked` on an empty source ledger rather than passing on 0 == 0."
62
63
  },
63
64
  "at": {
64
65
  "type": "string",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://openwop.dev/spec/v2/effect-seam-manifest.schema.json",
4
- "title": "Effect-seam manifest (RFC 0173 §C)",
5
- "description": "Host-declared, machine-checkable list of every outbound effect path the node runtime can reach (RFC 0173 §C.1: `{ seam, kind, guarded: true, guardedBy }`; `branchReFires` states the RFC 0140 G6 asymmetry). Served at GET /host/effect-seams (canonical, not a test seam). A seam omitted is invisible to the suite (negative-existence); the RFC 0140 R5 audit is the control.",
4
+ "title": "Effect-seam manifest (RFC 0173 \u00a7C)",
5
+ "description": "Host-declared, machine-checkable list of every outbound effect path the node runtime can reach (RFC 0173 \u00a7C.1: `{ seam, kind, guarded: true, guardedBy }`; `branchReFires` states the RFC 0140 G6 asymmetry). Served at GET /host/effect-seams (canonical, not a test seam). A seam omitted is invisible to the suite (negative-existence); the RFC 0140 R5 audit is the control.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -69,15 +69,18 @@
69
69
  "type": "string",
70
70
  "enum": [
71
71
  "http",
72
+ "smtp",
72
73
  "queue",
73
74
  "storage",
74
75
  "provider-sdk",
75
- "webhook-fanout"
76
- ]
76
+ "webhook-fanout",
77
+ "other"
78
+ ],
79
+ "description": "The outbound WIRE MECHANISM this seam leaves the host by \u2014 not the suite's driving mechanism, and not the business purpose. `other` is the escape for a mechanism this list does not name (raw TCP, gRPC, a filesystem write, a device SDK); a row using it MUST carry `note` saying which, so an unnameable mechanism is still auditable and no seam can hide behind a vague label. Completeness outranks driveability: a path the suite cannot drive (SMTP, for one) is still MUST-list \u2014 the scenario records it `inapplicable` with that reason, and an omitted row is invisible to the suite entirely (replay.md)."
77
80
  },
78
81
  "guarded": {
79
82
  "const": true,
80
- "description": "RFC 0173 §C.1 every row MUST be guarded; the scenario asserts it and drives one seam of each kind through the suite's receiver."
83
+ "description": "RFC 0173 \u00a7C.1 \u2014 every row MUST be guarded; the scenario asserts it and drives one seam of each kind through the suite's receiver."
81
84
  },
82
85
  "guardedBy": {
83
86
  "type": "string",
@@ -86,11 +89,31 @@
86
89
  },
87
90
  "branchReFires": {
88
91
  "type": "boolean",
89
- "description": "RFC 0140 G6 a `branch` fork re-fires this seam by design; stated here and witnessed as a permission."
92
+ "description": "RFC 0140 G6 \u2014 a `branch` fork re-fires this seam by design; stated here and witnessed as a permission."
90
93
  },
91
94
  "note": {
92
- "type": "string"
95
+ "type": "string",
96
+ "description": "Free text. REQUIRED when `kind` is `other`, where it MUST name the mechanism."
93
97
  }
98
+ },
99
+ "if": {
100
+ "properties": {
101
+ "kind": {
102
+ "const": "other"
103
+ }
104
+ },
105
+ "required": [
106
+ "kind"
107
+ ]
108
+ },
109
+ "then": {
110
+ "required": [
111
+ "seam",
112
+ "kind",
113
+ "guarded",
114
+ "guardedBy",
115
+ "note"
116
+ ]
94
117
  }
95
118
  }
96
119
  }