@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.
- package/CORPUS-STAMP.json +40 -37
- package/api/seams-v2.yaml +1 -1
- package/api/v2/asyncapi.yaml +1 -1
- package/api/v2/openapi.yaml +17 -19
- package/package.json +1 -1
- package/schemas/capabilities.schema.json +40 -1
- package/schemas/run-snapshot.schema.json +103 -33
- package/schemas/v2/agent-deployment-transition.schema.json +5 -6
- package/schemas/v2/agent-deployment.schema.json +8 -9
- package/schemas/v2/agent-eval-suite.schema.json +11 -12
- package/schemas/v2/artifact-type-pack-manifest.schema.json +22 -18
- package/schemas/v2/certification-bundle.schema.json +1 -1
- package/schemas/v2/chat-card-pack-manifest.schema.json +19 -15
- package/schemas/v2/debug-bundle.schema.json +6 -6
- package/schemas/v2/effect-ledger-projection.schema.json +4 -3
- package/schemas/v2/effect-seam-manifest.schema.json +30 -7
- package/schemas/v2/error-envelope.schema.json +185 -138
- package/schemas/v2/eval-summary.schema.json +17 -10
- package/schemas/v2/goal.schema.json +5 -5
- package/schemas/v2/ids.schema.json +120 -22
- package/schemas/v2/node-pack-manifest.schema.json +27 -31
- package/schemas/v2/proposal.schema.json +7 -8
- package/schemas/v2/run-event-payloads.schema.json +258 -245
- package/schemas/v2/run-event.schema.json +2 -126
- package/schemas/v2/run-options.schema.json +1 -1
- package/schemas/v2/run-snapshot.schema.json +34 -13
- package/schemas/v2/webhook-delivery.schema.json +26 -0
- package/schemas/v2/workflow-chain-pack-manifest.schema.json +41 -45
- package/schemas/v2/workflow-definition.schema.json +31 -36
- package/spec/v1/core-standard-manifest.json +2 -2
- package/spec/v1/deprecations.json +79 -67
- package/spec/v1/deprecations.schema.json +23 -7
- package/spec/v1/extensions.json +3 -2
- package/spec/v2/declaration.json +57 -33
- package/spec/v2/errors.json +421 -360
- package/spec/v2/id-field-bindings.json +105 -0
- package/spec/v2/profiles.json +31 -7
- package/spec/v2/release.json +3 -3
- 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/workflow-chain-pack-manifest.schema.json",
|
|
4
4
|
"title": "WorkflowChainPackManifest",
|
|
5
|
-
"description": "Manifest for a published OpenWOP workflow-chain pack
|
|
5
|
+
"description": "Manifest for a published OpenWOP workflow-chain pack \u2014 `pack.json` at the pack root with `kind: \"workflow-chain\"`. Distinct from node-pack-manifest.schema.json. See workflow-chain-packs.md for the canonical contract and RFC 0013 for the rationale. Chain packs are workflow-edit-time abstractions: a host editor expands each declared chain inline into the parent workflow at author time, so the dispatching runtime sees only concrete `core.*` (or published-vendor) typeIds.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": [
|
|
8
8
|
"name",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"properties": {
|
|
15
15
|
"name": {
|
|
16
16
|
"type": "string",
|
|
17
|
-
"description": "Reverse-DNS pack name per node-packs.md
|
|
17
|
+
"description": "Reverse-DNS pack name per node-packs.md \u00a7Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*` / `local.*`).",
|
|
18
18
|
"pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
|
|
19
19
|
"minLength": 1,
|
|
20
20
|
"maxLength": 256
|
|
@@ -64,18 +64,18 @@
|
|
|
64
64
|
"properties": {
|
|
65
65
|
"openwop": {
|
|
66
66
|
"type": "string",
|
|
67
|
-
"description": "Semver range
|
|
67
|
+
"description": "Semver range \u2014 which openwop protocol versions this pack works against."
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"additionalProperties": false,
|
|
71
|
-
"$comment": "Open by design
|
|
71
|
+
"$comment": "Open by design \u2014 packs MAY advertise extra engine constraints (`node`, `python`, etc.) that consumer hosts ignore but operator tooling consumes. Mirrors the shape used in node-pack-manifest.schema.json."
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"type": "object",
|
|
75
75
|
"additionalProperties": {
|
|
76
76
|
"type": "string"
|
|
77
77
|
},
|
|
78
|
-
"description": "Other node packs whose typeIds this pack's chains reference. Map of pack name
|
|
78
|
+
"description": "Other node packs whose typeIds this pack's chains reference. Map of pack name \u2192 semver range. The host editor uses this map at expansion time to verify referenced typeIds resolve."
|
|
79
79
|
},
|
|
80
80
|
"chains": {
|
|
81
81
|
"type": "array",
|
|
@@ -101,11 +101,11 @@
|
|
|
101
101
|
"parameters",
|
|
102
102
|
"dag"
|
|
103
103
|
],
|
|
104
|
-
"description": "A single workflow-chain entry
|
|
104
|
+
"description": "A single workflow-chain entry \u2014 a pre-configured DAG fragment + parameter schema that the host editor expands inline at author time. See workflow-chain-packs.md \u00a7Chain entry shape.",
|
|
105
105
|
"properties": {
|
|
106
106
|
"chainId": {
|
|
107
107
|
"$ref": "ids.schema.json#/$defs/chainId",
|
|
108
|
-
"description": "Canonical chain id
|
|
108
|
+
"description": "Canonical chain id \u2014 namespaced like a node typeId (reverse-DNS pattern). The pack's `name` prefix is recommended (e.g., pack `vendor.acme.editor-presets` exposing `vendor.acme.generatePRD`)."
|
|
109
109
|
},
|
|
110
110
|
"version": {
|
|
111
111
|
"type": "string",
|
|
@@ -123,13 +123,13 @@
|
|
|
123
123
|
},
|
|
124
124
|
"internal": {
|
|
125
125
|
"type": "boolean",
|
|
126
|
-
"description": "RFC 0135
|
|
126
|
+
"description": "RFC 0135 \u2014 when true, this chain is a composition-only fragment (typically an RFC 0133 sub-chain child): hosts MUST omit it from default template-gallery/picker listings while keeping it loadable, resolvable by id, composable, and expandable exactly like any other chain. Presentational/discovery semantics only \u2014 NOT an authorization boundary (a host MUST NOT treat it as access control). Absent \u21d2 false (listed). See workflow-chain-packs.md \u00a7\"Chain visibility (RFC 0135)\"."
|
|
127
127
|
},
|
|
128
128
|
"parameters": {
|
|
129
129
|
"type": "object",
|
|
130
|
-
"description": "JSON Schema 2020-12 fragment describing the parameter values the host editor MUST collect from the author at drop time. Authors-supplied values are validated against this schema before expansion proceeds; invalid input MUST be rejected with `chain_parameter_invalid`. RECOGNIZED EXTENSION KEY (RFC 0124 / WCP4): a property MAY carry `x-openwop-sensitive: true` to declare the parameter secret-class. A host that recognizes it MUST NOT expansion-time-freeze that parameter (plaintext secret-at-rest leak, SR-1) and MUST NOT materialize it as a plaintext `source:\"variable\"` binding (the value would land in the run-scoped bag / `RunSnapshot.variables`
|
|
130
|
+
"description": "JSON Schema 2020-12 fragment describing the parameter values the host editor MUST collect from the author at drop time. Authors-supplied values are validated against this schema before expansion proceeds; invalid input MUST be rejected with `chain_parameter_invalid`. RECOGNIZED EXTENSION KEY (RFC 0124 / WCP4): a property MAY carry `x-openwop-sensitive: true` to declare the parameter secret-class. A host that recognizes it MUST NOT expansion-time-freeze that parameter (plaintext secret-at-rest leak, SR-1) and MUST NOT materialize it as a plaintext `source:\"variable\"` binding (the value would land in the run-scoped bag / `RunSnapshot.variables` \u2014 the same SR-1 leak one layer down). Instead, per the 2026-07-04 \u00a7Security amendment: it is deferrable ONLY in a prompt-body position, where it MUST be materialized as a `source:\"secret\"` `PromptVariable` (BYOK-resolved via `capabilities.secrets`, redacted to `[REDACTED:<secretId>]` in `prompt.composed`, never bagged); in ANY other position (whole-value `node.inputs`, embedded non-prompt `config`, or a host lacking deferred / `secrets` support) it MUST fail closed with `sensitive_param_not_deferrable` (422). Per-run supply is a `credentialRef` secret reference, never plaintext. See `workflow-chain-packs.md` \u00a7\"Deferred-parameter expansion\" / RFC 0124 \u00a7Security.",
|
|
131
131
|
"additionalProperties": true,
|
|
132
|
-
"$comment": "Open by design
|
|
132
|
+
"$comment": "Open by design \u2014 this field IS a JSON Schema document, so it must accept any of the 30+ JSON Schema 2020-12 keywords (`type`, `properties`, `required`, `oneOf`, `allOf`, etc.). Strict closure would require importing the JSON Schema meta-schema."
|
|
133
133
|
},
|
|
134
134
|
"dag": {
|
|
135
135
|
"$ref": "#/$defs/WorkflowDefinitionFragment"
|
|
@@ -160,18 +160,18 @@
|
|
|
160
160
|
"items": {
|
|
161
161
|
"$ref": "#/$defs/SubChainRef"
|
|
162
162
|
},
|
|
163
|
-
"description": "RFC 0133
|
|
163
|
+
"description": "RFC 0133 \u00a71.1. OPTIONAL. Child chains this chain composes at RUN TIME. Each entry names a chain (a sibling `chainId` in this pack, or an externally published chain) that a node references via `config.subChainRef`. Unlike RFC 0013's author-time inline splice, a referenced sub-chain is co-instantiated as its own registered workflow and dispatched by the parent as a child run (both parent and child stay owned + builder-editable). A host without runtime child dispatch MUST refuse instantiation with `sub_chain_unsupported` (422) rather than flatten. Requires `capabilities.workflowChainPacks.subChains.supported: true`. See `workflow-chain-packs.md` \u00a7\"Sub-chain composition (RFC 0133)\"."
|
|
164
164
|
},
|
|
165
165
|
"producedVariables": {
|
|
166
166
|
"type": "array",
|
|
167
167
|
"items": {
|
|
168
168
|
"$ref": "#/$defs/ProducedVariable"
|
|
169
169
|
},
|
|
170
|
-
"description": "RFC 0133
|
|
170
|
+
"description": "RFC 0133 \u00a72.2. OPTIONAL. Run-scoped values a node writes to the executor's variable bag during the run and downstream nodes read by name via a `{ type:\"variable\", variableName }` input binding \u2014 where the value is NOT an author-time `parameter` and rides no typed output port. Prefer edges (a typed `sourceOutput`\u2192`targetInput` hand-off) wherever a node exposes a value on a port; `producedVariables` is only for values written to the run bag with no typed port. On expansion the host emits these into `WorkflowDefinition.variables[]` as run-scoped entries (name + type, no value). Any `{ type:\"variable\" }` read of an UNDECLARED name (not here and not a materialized parameter) is a `variable_undeclared` manifest error. See `workflow-chain-packs.md` \u00a7\"Produced (run-scoped) variables (RFC 0133)\"."
|
|
171
171
|
},
|
|
172
172
|
"compensation": {
|
|
173
173
|
"type": "object",
|
|
174
|
-
"description": "RFC 0157 (RFC 0013 revision
|
|
174
|
+
"description": "RFC 0157 (RFC 0013 revision \u00d7 RFC 0151 \u00a7B) \u2014 the chain-level compensation POLICY, MIRROR of `compensation-policy.schema.json` (copied inline; a conformance leg asserts equality apart from this description). On expansion it becomes the registered definition's `settings.compensation`: if the parent has none, the host MUST copy it; if the parent already carries one that is not deep-equal, expansion MUST fail `chain_compensation_policy_conflict` \u2014 a merged policy nobody wrote is exactly the guess-at-a-contract failure the policy exists to prevent. Absent \u21d2 the chain expresses no policy and inherits the parent's (or none).",
|
|
175
175
|
"additionalProperties": false,
|
|
176
176
|
"required": [
|
|
177
177
|
"triggers"
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
"profileVersion": {
|
|
181
181
|
"type": "string",
|
|
182
182
|
"pattern": "^[1-9][0-9]*$",
|
|
183
|
-
"description": "The RFC 0151 profile version this policy was authored against. OPTIONAL; when present it MUST equal the host's advertised `capabilities.compensation.profileVersion` or registration fails, because `profileVersion` is part of the inverse-action identity (
|
|
183
|
+
"description": "The RFC 0151 profile version this policy was authored against. OPTIONAL; when present it MUST equal the host's advertised `capabilities.compensation.profileVersion` or registration fails, because `profileVersion` is part of the inverse-action identity (\u00a7C) and a workflow authored under one ordering rule MUST NOT mint identities under another."
|
|
184
184
|
},
|
|
185
185
|
"orderingModel": {
|
|
186
186
|
"type": "string",
|
|
@@ -189,7 +189,7 @@
|
|
|
189
189
|
"dependency-graph"
|
|
190
190
|
],
|
|
191
191
|
"default": "reverse-completion",
|
|
192
|
-
"description": "RFC 0151
|
|
192
|
+
"description": "RFC 0151 \u00a7A/\u00a7C. `reverse-completion` (default) orders inverse actions by descending durable forward-completion sequence; `dependency-graph` MUST be a DAG and preserve reverse dependency order. The value MUST be one of the host's advertised `capabilities.compensation.orderingModels[]`; a host MUST refuse the workflow at registration otherwise, so an unwind never discovers at failure time that its ordering rule is unimplemented."
|
|
193
193
|
},
|
|
194
194
|
"triggers": {
|
|
195
195
|
"type": "array",
|
|
@@ -204,12 +204,12 @@
|
|
|
204
204
|
"operator-request"
|
|
205
205
|
]
|
|
206
206
|
},
|
|
207
|
-
"description": "Which events start an unwind. REQUIRED and closed
|
|
207
|
+
"description": "Which events start an unwind. REQUIRED and closed \u2014 a policy that names no trigger is not a policy, and an open string here would let a host and an author disagree about a word. `node-failure`: a node reaches terminal failure after its own RFC 0009 retry policy and the run cannot continue. `run-cancel`: an RFC 0094 cancel is accepted while committed effects exist. `cap-breach`: an RFC 0058 / RFC 0084 `cap.breached` hard stop. `operator-request`: an authorized operator explicitly requests an unwind (\u00a7E) \u2014 MUST be authorized per RFC 0049, binding tenant, principal, action, and plan version. A trigger not listed here does NOT start an unwind; the run ends with its committed effects in place and `compensationStatus: none`, which is the honest shape \u2014 no generic rollback is inferred from an undeclared trigger (RFC 0151 \u00a7Compatibility)."
|
|
208
208
|
},
|
|
209
209
|
"retry": {
|
|
210
210
|
"type": "object",
|
|
211
211
|
"additionalProperties": false,
|
|
212
|
-
"description": "Defaults for inverse actions whose node-level `compensation.retry` is absent. A node's own bounds always win. Retries reuse the inverse action's stable identity (
|
|
212
|
+
"description": "Defaults for inverse actions whose node-level `compensation.retry` is absent. A node's own bounds always win. Retries reuse the inverse action's stable identity (\u00a7C) \u2014 never a fresh one, or a transient refund failure mints a second refund.",
|
|
213
213
|
"properties": {
|
|
214
214
|
"maxAttempts": {
|
|
215
215
|
"type": "integer",
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
"manual-intervention"
|
|
234
234
|
],
|
|
235
235
|
"default": "record-outcome",
|
|
236
|
-
"description": "RFC 0151
|
|
236
|
+
"description": "RFC 0151 \u00a7E \u2014 what the host does when an inverse action exhausts its retries. Either way the run MUST route to RFC 0053 dead-letter handling and the run's `compensationStatus` follows the \u00a7D fold (`partial` or `failed`). `record-outcome` (default): record the failure and continue unwinding the remaining actions. `manual-intervention`: additionally emit `compensation.manual_intervention_required` and stop issuing further inverse actions until an authorized operator retries, skips with recorded justification, substitutes a registered action, or terminates as uncompensated \u2014 the rollup reads `manual` while that is unresolved. Requires `capabilities.compensation.manualIntervention: true`; a host that does not advertise it MUST refuse a policy that selects it."
|
|
237
237
|
},
|
|
238
238
|
"approvalScope": {
|
|
239
239
|
"type": "string",
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
"all"
|
|
243
243
|
],
|
|
244
244
|
"default": "declared",
|
|
245
|
-
"description": "RFC 0151
|
|
245
|
+
"description": "RFC 0151 \u00a7E. `declared` (default): only inverse actions whose node sets `compensation.requiresApproval: true` create an RFC 0051 approval interrupt. `all`: every inverse action does, regardless of the node's declaration. This value can only ESCALATE \u2014 there is no `none`, because a policy MUST NOT strip an approval a node declared for itself (RFC 0147 R9: an inverse action can itself be harmful)."
|
|
246
246
|
},
|
|
247
247
|
"onParentCancel": {
|
|
248
248
|
"type": "string",
|
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
"manual"
|
|
253
253
|
],
|
|
254
254
|
"default": "continue",
|
|
255
|
-
"description": "RFC 0151
|
|
255
|
+
"description": "RFC 0151 \u00a7C \u2014 cancellation of the parent run MUST NOT silently abandon an active compensation. `continue`: the unwind runs to its terminal rollup. `pause`: emit `compensation.paused` and hold for authorized intervention (the run's own `status` carries the wait). `manual`: emit `compensation.manual_intervention_required` and stop; rollup reads `manual`. `pause`/`manual` require `capabilities.compensation.manualIntervention: true`."
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
}
|
|
@@ -260,7 +260,7 @@
|
|
|
260
260
|
"additionalProperties": false,
|
|
261
261
|
"patternProperties": {
|
|
262
262
|
"^(openwop-|x-|vendor\\.)": {
|
|
263
|
-
"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`
|
|
263
|
+
"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."
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
},
|
|
@@ -269,7 +269,7 @@
|
|
|
269
269
|
"required": [
|
|
270
270
|
"ref"
|
|
271
271
|
],
|
|
272
|
-
"description": "RFC 0133
|
|
272
|
+
"description": "RFC 0133 \u00a71.1. A reference to a child chain the parent composes. `ref` is EITHER a string naming a SIBLING `chainId` in this pack's `chains[]`, OR an object naming an externally published chain (resolved + signature-verified like any pack dependency). A sibling `ref` that matches no `chainId`, or an external `ref` that fails resolution/verification, is `sub_chain_unresolved`. A chain that transitively composes itself is `sub_chain_cycle`.",
|
|
273
273
|
"properties": {
|
|
274
274
|
"ref": {
|
|
275
275
|
"oneOf": [
|
|
@@ -299,7 +299,7 @@
|
|
|
299
299
|
},
|
|
300
300
|
"version": {
|
|
301
301
|
"type": "string",
|
|
302
|
-
"description": "Semver range for the external chain. Co-registration SHOULD pin the resolved version into the parent's ownership record for reproducibility (RFC 0133
|
|
302
|
+
"description": "Semver range for the external chain. Co-registration SHOULD pin the resolved version into the parent's ownership record for reproducibility (RFC 0133 \u00a7Unresolved #1, resolved: pin)."
|
|
303
303
|
}
|
|
304
304
|
},
|
|
305
305
|
"additionalProperties": false
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
"producedBy",
|
|
317
317
|
"type"
|
|
318
318
|
],
|
|
319
|
-
"description": "RFC 0133
|
|
319
|
+
"description": "RFC 0133 \u00a72.2. A run-scoped variable a chain declares: written by one node and read by others via a `{ type:\"variable\", variableName }` input binding. Run-scoped \u2014 carries NO author-time value (that is what `parameters` are for); the manifest distinguishes the two.",
|
|
320
320
|
"properties": {
|
|
321
321
|
"name": {
|
|
322
322
|
"type": "string",
|
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
"required": [
|
|
370
370
|
"nodes"
|
|
371
371
|
],
|
|
372
|
-
"description": "Subset of workflow-definition.schema.json. `id`/`name`/`version`/`triggers`/`settings`/`metadata` MUST be omitted (host generates per-expansion); `variables` is replaced by the chain's top-level `parameters`. See workflow-chain-packs.md
|
|
372
|
+
"description": "Subset of workflow-definition.schema.json. `id`/`name`/`version`/`triggers`/`settings`/`metadata` MUST be omitted (host generates per-expansion); `variables` is replaced by the chain's top-level `parameters`. See workflow-chain-packs.md \u00a7WorkflowDefinitionFragment.",
|
|
373
373
|
"properties": {
|
|
374
374
|
"nodes": {
|
|
375
375
|
"type": "array",
|
|
@@ -403,10 +403,7 @@
|
|
|
403
403
|
"description": "Node id, unique within the fragment. Hosts MUST rewrite these to globally-unique ids at expansion time."
|
|
404
404
|
},
|
|
405
405
|
"typeId": {
|
|
406
|
-
"
|
|
407
|
-
"pattern": "^[a-z][a-zA-Z0-9._-]*$",
|
|
408
|
-
"minLength": 1,
|
|
409
|
-
"maxLength": 256
|
|
406
|
+
"$ref": "ids.schema.json#/$defs/typeId"
|
|
410
407
|
},
|
|
411
408
|
"name": {
|
|
412
409
|
"type": "string"
|
|
@@ -425,7 +422,7 @@
|
|
|
425
422
|
},
|
|
426
423
|
"config": {
|
|
427
424
|
"type": "object",
|
|
428
|
-
"description": "Node config
|
|
425
|
+
"description": "Node config \u2014 host-validated against the referenced typeId's config schema. String fields MAY contain `{{params.<name>}}` placeholders that the host MUST substitute at expansion time. RFC 0133: a `core.subWorkflow` / `core.dispatch` (child-run) node MAY carry `subChainRef: string` \u2014 a declared `subChains[].ref` (sibling `chainId` or external ref) the host rewrites to the minted child `workflowId` at co-expansion time (\u00a71.3 step 3). A concrete `config.workflowId` inside a fragment remains INVALID \u2014 a chain MUST NOT pin a host-specific workflow id (the `not` guard below enforces it).",
|
|
429
426
|
"additionalProperties": false,
|
|
430
427
|
"not": {
|
|
431
428
|
"required": [
|
|
@@ -436,33 +433,32 @@
|
|
|
436
433
|
"subChainRef": {
|
|
437
434
|
"type": "string",
|
|
438
435
|
"pattern": "^[a-z][a-zA-Z0-9._-]*$",
|
|
439
|
-
"description": "RFC 0133
|
|
436
|
+
"description": "RFC 0133 \u00a71.2. A declared `subChains[].ref` this node dispatches as a child run. The host rewrites it to the minted child `config.workflowId` at co-expansion time. MUST match a `subChains[].ref` (sibling `chainId` or external ref's `chainId`), else `sub_chain_unresolved`."
|
|
440
437
|
}
|
|
441
438
|
},
|
|
442
|
-
"$comment": "Open by design
|
|
439
|
+
"$comment": "Open by design \u2014 node config shapes are per-typeId and only known to the host at expansion time when the referenced typeId's config schema is resolved. Cross-typeId enforcement happens at the expansion step, not at manifest-validation time. The `not: { required: ['workflowId'] }` guard is the ONE closed constraint: RFC 0133 forbids pinning a concrete host-specific workflow id inside a portable chain fragment (use `subChainRef` instead)."
|
|
443
440
|
},
|
|
444
441
|
"inputs": {
|
|
445
442
|
"type": "object",
|
|
446
443
|
"description": "Per-port input wiring. String values MAY contain `{{params.<name>}}` placeholders.",
|
|
447
444
|
"additionalProperties": true,
|
|
448
|
-
"$comment": "Open by design
|
|
445
|
+
"$comment": "Open by design \u2014 port shapes are per-typeId, same reasoning as `config` above."
|
|
449
446
|
},
|
|
450
447
|
"compensation": {
|
|
451
448
|
"type": "object",
|
|
452
|
-
"description": "RFC 0157 (RFC 0013 revision
|
|
449
|
+
"description": "RFC 0157 (RFC 0013 revision \u00d7 RFC 0151 \u00a7B) \u2014 MIRROR of `workflow-definition.schema.json#/$defs/WorkflowNode/properties/compensation`, copied inline so this manifest stays self-contained (no cross-file `$ref`); a conformance leg asserts the two stay byte-equal apart from this description. The inverse action for this fragment node. `nodeTypeId` MUST resolve at expansion (step 3) exactly as `typeId` does \u2014 `chain_unresolvable_typeid`; `inputMapping` strings MAY carry `{{params.<name>}}` and MUST be substituted at expansion (step 5); node-id references inside `inputMapping` MUST be rewritten with the expansion prefix (step 6). Survives expansion verbatim into the registered `WorkflowNode.compensation`.",
|
|
453
450
|
"additionalProperties": false,
|
|
454
451
|
"required": [
|
|
455
452
|
"nodeTypeId"
|
|
456
453
|
],
|
|
457
454
|
"properties": {
|
|
458
455
|
"nodeTypeId": {
|
|
459
|
-
"
|
|
460
|
-
"minLength": 1,
|
|
456
|
+
"$ref": "ids.schema.json#/$defs/typeId",
|
|
461
457
|
"description": "Node type implementing the inverse action. MUST resolve at registration time."
|
|
462
458
|
},
|
|
463
459
|
"inputMapping": {
|
|
464
460
|
"type": "object",
|
|
465
|
-
"description": "Derived from recorded facts only
|
|
461
|
+
"description": "Derived from recorded facts only \u2014 node outputs and run inputs already in the event log.",
|
|
466
462
|
"additionalProperties": true
|
|
467
463
|
},
|
|
468
464
|
"retry": {
|
|
@@ -481,17 +477,17 @@
|
|
|
481
477
|
},
|
|
482
478
|
"requiresApproval": {
|
|
483
479
|
"type": "boolean",
|
|
484
|
-
"description": "RFC 0151
|
|
480
|
+
"description": "RFC 0151 \u00a7C \u2014 an inverse action can itself be harmful (RFC 0147 R9), so it may be gated behind the same approval surface as a forward effect."
|
|
485
481
|
},
|
|
486
482
|
"waiveRequiresApproval": {
|
|
487
483
|
"type": "boolean",
|
|
488
|
-
"description": "RFC 0151
|
|
484
|
+
"description": "RFC 0151 \u00a7B/\u00a7E (S36, 2026-08-17) \u2014 OPTIONAL. When true, ABANDONING this inverse action (\u00a7E `skip with justification` or `terminate as uncompensated`) requires an RFC 0051 approval to have resolved `approved` first \u2014 if a human must authorize RUNNING an inverse, a human must authorize deciding it will NEVER run. DEFAULT = the obligation's EFFECTIVE `requiresApproval` (after the policy's `approvalScope` escalation, \u00a7B) \u2014 NOT false \u2014 so the field is purely additive: no existing document changes meaning. Stamped onto the obligation at MINT time like `requiresApproval` (a mid-flight redefinition cannot change who had to authorize). Does NOT apply to `substitute` (still an attempt to undo; a substitution is a new planVersion whose own `requiresApproval` governs it). No policy-level counterpart: because the default inherits the effective value, an `approvalScope` escalation escalates waives with it."
|
|
489
485
|
}
|
|
490
486
|
}
|
|
491
487
|
},
|
|
492
488
|
"irreversibleEffect": {
|
|
493
489
|
"type": "boolean",
|
|
494
|
-
"description": "RFC 0151
|
|
490
|
+
"description": "RFC 0151 \u00a7B UQ4 (resolved 2026-08-16), mirrored into chain fragments per RFC 0157 \u2014 the fragment author states that this node's committed effect HAS NO INVERSE. Mutually exclusive with `compensation` (host MUST reject both at pack install / chain expansion); expansion copies it onto the expanded `WorkflowNode` unchanged. See `workflow-definition.schema.json` `WorkflowNode.irreversibleEffect`."
|
|
495
491
|
}
|
|
496
492
|
},
|
|
497
493
|
"additionalProperties": false,
|
|
@@ -530,7 +526,7 @@
|
|
|
530
526
|
},
|
|
531
527
|
"condition": {
|
|
532
528
|
"$ref": "#/$defs/EdgeCondition",
|
|
533
|
-
"description": "Optional edge condition
|
|
529
|
+
"description": "Optional edge condition \u2014 the SAME shape as a top-level workflow edge's condition (workflow-definition.schema.json \u00a7EdgeCondition). When present, the edge contributes to the target only if the condition holds against the source node's output, letting a chain express content routing (router/switch/conditional branches). Safety-fix (RFC 0013 amendment 2026-07-03): the field was previously typed `string`, contradicting this description; no chain used the string form (hosts dropped the field at expansion), so correcting it to the object shape breaks no conformant behavior."
|
|
534
530
|
},
|
|
535
531
|
"triggerRule": {
|
|
536
532
|
"type": "string",
|
|
@@ -542,14 +538,14 @@
|
|
|
542
538
|
"any_failed"
|
|
543
539
|
],
|
|
544
540
|
"default": "all_success",
|
|
545
|
-
"description": "Optional fan-in / error-routing rule
|
|
541
|
+
"description": "Optional fan-in / error-routing rule \u2014 the SAME shape and enum as a top-level workflow edge's `triggerRule` (workflow-definition.schema.json \u00a7WorkflowEdge). Governs how the target node fires given its incoming edges: `all_success` (default \u2014 every incoming edge's source succeeded), `any_success`, `all_complete` (fire when all sources have finished regardless of success \u2014 best-effort completion), `none_failed`, `any_failed`. Additive (RFC 0125): omitting it is identical to `all_success`, the implicit prior behavior. Mirrors the RFC 0013 2026-07-03 `condition` amendment's WorkflowEdge\u2192FragmentEdge move. Expansion MUST carry this value onto the resulting `WorkflowEdge` so the scheduler honors it (see `workflow-chain-packs.md` \u00a7\"Expansion semantics\")."
|
|
546
542
|
}
|
|
547
543
|
},
|
|
548
544
|
"additionalProperties": false
|
|
549
545
|
},
|
|
550
546
|
"EdgeCondition": {
|
|
551
547
|
"type": "object",
|
|
552
|
-
"description": "Edge condition
|
|
548
|
+
"description": "Edge condition \u2014 identical to workflow-definition.schema.json \u00a7EdgeCondition (RFC 0013 \u00a7edges: 'same shape as a top-level workflow definition'). Inlined here so the manifest schema is self-contained for pack-loader validators. RFC 0134 added `truthy`/`falsy` (kept in sync with the top-level def).",
|
|
553
549
|
"properties": {
|
|
554
550
|
"type": {
|
|
555
551
|
"type": "string",
|
|
@@ -580,7 +576,7 @@
|
|
|
580
576
|
},
|
|
581
577
|
"Signing": {
|
|
582
578
|
"type": "object",
|
|
583
|
-
"description": "Optional signing metadata. Reuses node-packs.md
|
|
579
|
+
"description": "Optional signing metadata. Reuses node-packs.md \u00a7signing unchanged.",
|
|
584
580
|
"properties": {
|
|
585
581
|
"publicKeyRef": {
|
|
586
582
|
"type": "string",
|
|
@@ -603,7 +599,7 @@
|
|
|
603
599
|
},
|
|
604
600
|
"patternProperties": {
|
|
605
601
|
"^(openwop-|x-|vendor\\.)": {
|
|
606
|
-
"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`
|
|
602
|
+
"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."
|
|
607
603
|
}
|
|
608
604
|
},
|
|
609
605
|
"x-openwop-seeded-from": "v1"
|