@openwop/spec-artifacts 2.42.8 → 2.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CORPUS-STAMP.json +37 -36
- package/api/seams-v2.yaml +1 -1
- package/api/v2/asyncapi.yaml +1 -1
- package/api/v2/openapi.yaml +5 -4
- package/package.json +1 -1
- package/schemas/audit-verify-result.schema.json +40 -8
- package/schemas/v2/audit-verify-result.schema.json +106 -10
- package/schemas/v2/capabilities.schema.json +96 -0
- package/schemas/v2/error-envelope.schema.json +3 -1
- package/schemas/v2/registry-version-manifest.schema.json +2 -2
- package/schemas/v2/suspend-request.schema.json +1 -1
- package/spec/v1/core-standard-manifest.json +2 -2
- package/spec/v1/gaps.json +238 -0
- package/spec/v2/core/capabilities.md +5 -1
- package/spec/v2/core/errors.md +3 -2
- package/spec/v2/core/interrupt.md +13 -2
- package/spec/v2/core/packs.md +9 -2
- package/spec/v2/core/security-defaults.md +13 -2
- package/spec/v2/corrections.json +18 -1
- package/spec/v2/declaration.json +37 -12
- package/spec/v2/errors.json +11 -1
- package/spec/v2/ext/brand/README.md +1 -1
- package/spec/v2/ext/canvas/README.md +1 -1
- package/spec/v2/ext/chat/README.md +2 -2
- package/spec/v2/ext/coordination/README.md +1 -1
- package/spec/v2/ext/dataIntegration/README.md +1 -1
- package/spec/v2/ext/entities/README.md +2 -2
- package/spec/v2/ext/kanban/README.md +2 -2
- package/spec/v2/ext/knowledge/README.md +2 -2
- package/spec/v2/ext/launchStudio/README.md +1 -1
- package/spec/v2/ext/messaging/README.md +1 -1
- package/spec/v2/ext/restTransport/README.md +2 -2
- package/spec/v2/ext/webResearch/README.md +2 -2
- package/spec/v2/facets/auditLogIntegrity.schema.json +30 -0
- package/spec/v2/release.json +2 -2
- package/spec/v2/surface-baseline.json +50 -2
|
@@ -238,7 +238,7 @@
|
|
|
238
238
|
},
|
|
239
239
|
"yanked": {
|
|
240
240
|
"type": "boolean",
|
|
241
|
-
"description": "
|
|
241
|
+
"description": "This version is yanked (spec/v2/core/packs.md §\"Version manifests\"). The registry keeps serving its manifest, tarball and signature, and its pack index never names it `latest` while an unyanked version exists. A consumer resolving a range excludes it; an exact pin MAY still resolve it."
|
|
242
242
|
},
|
|
243
243
|
"yankedReason": {
|
|
244
244
|
"type": "string",
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
"supersededBy": {
|
|
254
254
|
"type": "string",
|
|
255
255
|
"maxLength": 256,
|
|
256
|
-
"description": "Optional pointer to the version (or `<name>@<version>`) that replaces this one.
|
|
256
|
+
"description": "Optional pointer to the version (or `<name>@<version>`) that replaces this one. Display only: a consumer that refuses or warns about a deprecated version can name it (spec/v2/core/packs.md §\"Version manifests\")."
|
|
257
257
|
},
|
|
258
258
|
"advisoryUrl": {
|
|
259
259
|
"type": "string",
|
|
@@ -299,7 +299,7 @@
|
|
|
299
299
|
"approve",
|
|
300
300
|
"escalate"
|
|
301
301
|
],
|
|
302
|
-
"description": "RFC 0186 §A.3 — the disposition applied when `timeoutMs` elapses with no resolution. Every gate with a timer needs one; two production hosts recorded it as a bare key on `approval.requested` (280 rows on one) because the seat did not exist. `escalate` pairs with a host-defined escalation target. A `timeoutMs` of `0` means no timer, and `onTimeout` is then meaningless."
|
|
302
|
+
"description": "RFC 0186 §A.3 — the disposition applied when `timeoutMs` elapses with no resolution. Every gate with a timer needs one; two production hosts recorded it as a bare key on `approval.requested` (280 rows on one) because the seat did not exist. `escalate` pairs with a host-defined escalation target. A `timeoutMs` of `0` means no timer, and `onTimeout` is then meaningless. Absent means `reject` (RFC 0223; interrupt.md §Rejection): the gate fails closed, the node and run fail with `approval_rejected` unless an edge routes the failure. No JSON-Schema `default` is declared, because a validator that fills defaults would write a value the host never recorded."
|
|
303
303
|
},
|
|
304
304
|
"description": {
|
|
305
305
|
"type": "string"
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"provenance": {
|
|
5
5
|
"suite": {
|
|
6
6
|
"package": "@openwop/openwop-conformance",
|
|
7
|
-
"version": "2.
|
|
7
|
+
"version": "2.43.0"
|
|
8
8
|
},
|
|
9
9
|
"note": "Derived from the corpus at generation time. Regenerate with --write; verify with --check."
|
|
10
10
|
},
|
|
@@ -421,5 +421,5 @@
|
|
|
421
421
|
"$id": "https://openwop.dev/spec/v1/workspace-file.schema.json"
|
|
422
422
|
}
|
|
423
423
|
],
|
|
424
|
-
"digest": "
|
|
424
|
+
"digest": "17d0bdd9a9fd20dcd7df1c5312e9e00e77ee641ca24970d4c6ec6130d0fbf4ae"
|
|
425
425
|
}
|
package/spec/v1/gaps.json
CHANGED
|
@@ -13068,6 +13068,23 @@
|
|
|
13068
13068
|
}
|
|
13069
13069
|
]
|
|
13070
13070
|
},
|
|
13071
|
+
{
|
|
13072
|
+
"id": "openwop.gap.0220.4",
|
|
13073
|
+
"rfc": "0220",
|
|
13074
|
+
"local": "G4",
|
|
13075
|
+
"section": "§B",
|
|
13076
|
+
"surface": "`brand`, `canvas`, `coordination` and `launchStudio` have no tier-2 host. MyndHyve's executors for them run in the browser engine or on `canvas-runtime`, which does no OpenWOP version negotiation. `coordination`'s vote/consensus nodes need server-side agent dispatch.",
|
|
13077
|
+
"witness": "unclassified",
|
|
13078
|
+
"requirementId": null,
|
|
13079
|
+
"disposition": "externally-gated",
|
|
13080
|
+
"target": "tier-2-host-serves-family",
|
|
13081
|
+
"sources": [
|
|
13082
|
+
{
|
|
13083
|
+
"file": "RFCS/registers/0220-ext-families-graduate-on-evidence.gaps.md",
|
|
13084
|
+
"token": "G4"
|
|
13085
|
+
}
|
|
13086
|
+
]
|
|
13087
|
+
},
|
|
13071
13088
|
{
|
|
13072
13089
|
"id": "openwop.gap.0221.1",
|
|
13073
13090
|
"rfc": "0221",
|
|
@@ -13085,6 +13102,227 @@
|
|
|
13085
13102
|
}
|
|
13086
13103
|
]
|
|
13087
13104
|
},
|
|
13105
|
+
{
|
|
13106
|
+
"id": "openwop.gap.0222.1",
|
|
13107
|
+
"rfc": "0222",
|
|
13108
|
+
"local": "G1",
|
|
13109
|
+
"section": "§A",
|
|
13110
|
+
"surface": "The earlier major's registry write endpoints (`deprecate`, `yank`, `keychain`, `keychain/rotate`), their scopes, the `rotationProof` chain and the 72-hour unpublish window have no v2 home.",
|
|
13111
|
+
"witness": "unclassified",
|
|
13112
|
+
"requirementId": null,
|
|
13113
|
+
"disposition": "closed",
|
|
13114
|
+
"target": null,
|
|
13115
|
+
"sources": [
|
|
13116
|
+
{
|
|
13117
|
+
"file": "RFCS/registers/0222-v2-registry-operations.gaps.md",
|
|
13118
|
+
"token": "G1"
|
|
13119
|
+
}
|
|
13120
|
+
]
|
|
13121
|
+
},
|
|
13122
|
+
{
|
|
13123
|
+
"id": "openwop.gap.0222.2",
|
|
13124
|
+
"rfc": "0222",
|
|
13125
|
+
"local": "G2",
|
|
13126
|
+
"section": "§C",
|
|
13127
|
+
"surface": "No corpus schema describes `.well-known/openwop-registry.json`, so the `signingKeys[]` members §C names are validated only by the conformance leg.",
|
|
13128
|
+
"witness": "unclassified",
|
|
13129
|
+
"requirementId": null,
|
|
13130
|
+
"disposition": "closed",
|
|
13131
|
+
"target": null,
|
|
13132
|
+
"sources": [
|
|
13133
|
+
{
|
|
13134
|
+
"file": "RFCS/registers/0222-v2-registry-operations.gaps.md",
|
|
13135
|
+
"token": "G2"
|
|
13136
|
+
}
|
|
13137
|
+
]
|
|
13138
|
+
},
|
|
13139
|
+
{
|
|
13140
|
+
"id": "openwop.gap.0223.1",
|
|
13141
|
+
"rfc": "0223",
|
|
13142
|
+
"local": "G1",
|
|
13143
|
+
"section": "§Conformance",
|
|
13144
|
+
"surface": "The routed case (a rejected gate followed over an `all_complete` or `any_failed` edge) has no witness: no registered fixture has a gate with an outgoing edge, and widening `conformance-approval` would force every host to re-register it.",
|
|
13145
|
+
"witness": "unclassified",
|
|
13146
|
+
"requirementId": null,
|
|
13147
|
+
"disposition": "transferred",
|
|
13148
|
+
"target": "openwop#1700",
|
|
13149
|
+
"sources": [
|
|
13150
|
+
{
|
|
13151
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13152
|
+
"token": "G1"
|
|
13153
|
+
}
|
|
13154
|
+
]
|
|
13155
|
+
},
|
|
13156
|
+
{
|
|
13157
|
+
"id": "openwop.gap.0223.2",
|
|
13158
|
+
"rfc": "0223",
|
|
13159
|
+
"local": "G2",
|
|
13160
|
+
"section": "§Conformance",
|
|
13161
|
+
"surface": "The timeout disposition has no witness: no registered fixture carries a gate with a short `timeoutMs`, and the suite cannot make a host's timer fire.",
|
|
13162
|
+
"witness": "unclassified",
|
|
13163
|
+
"requirementId": null,
|
|
13164
|
+
"disposition": "transferred",
|
|
13165
|
+
"target": "openwop#1700",
|
|
13166
|
+
"sources": [
|
|
13167
|
+
{
|
|
13168
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13169
|
+
"token": "G2"
|
|
13170
|
+
}
|
|
13171
|
+
]
|
|
13172
|
+
},
|
|
13173
|
+
{
|
|
13174
|
+
"id": "openwop.gap.0223.3",
|
|
13175
|
+
"rfc": "0223",
|
|
13176
|
+
"local": "G3",
|
|
13177
|
+
"section": "§Implementation notes",
|
|
13178
|
+
"surface": "The v2 reference host does not record `action` on `interrupt.resolved`, does not emit `approval.rejected`, fails the run directly rather than through the scheduler, and has no timeout disposition.",
|
|
13179
|
+
"witness": "unclassified",
|
|
13180
|
+
"requirementId": null,
|
|
13181
|
+
"disposition": "externally-gated",
|
|
13182
|
+
"target": "openwop-examples-v2-reference-followup",
|
|
13183
|
+
"sources": [
|
|
13184
|
+
{
|
|
13185
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13186
|
+
"token": "G3"
|
|
13187
|
+
}
|
|
13188
|
+
]
|
|
13189
|
+
},
|
|
13190
|
+
{
|
|
13191
|
+
"id": "openwop.gap.0223.4",
|
|
13192
|
+
"rfc": "0223",
|
|
13193
|
+
"local": "G4",
|
|
13194
|
+
"section": "§Implementation notes",
|
|
13195
|
+
"surface": "openwop-app records no `action` on single reject or timeout, emits no `interrupt.resolved` on quorum reject, never emits `approval.rejected`, and emits no `node.failed` / `failedNodeId` on either reject path.",
|
|
13196
|
+
"witness": "unclassified",
|
|
13197
|
+
"requirementId": null,
|
|
13198
|
+
"disposition": "externally-gated",
|
|
13199
|
+
"target": "openwop-app-followup",
|
|
13200
|
+
"sources": [
|
|
13201
|
+
{
|
|
13202
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13203
|
+
"token": "G4"
|
|
13204
|
+
}
|
|
13205
|
+
]
|
|
13206
|
+
},
|
|
13207
|
+
{
|
|
13208
|
+
"id": "openwop.gap.0223.5",
|
|
13209
|
+
"rfc": "0223",
|
|
13210
|
+
"local": "G5",
|
|
13211
|
+
"section": "§Implementation notes",
|
|
13212
|
+
"surface": "MyndHyve fails the gate with the unregistered `APPROVAL_REJECTED`.",
|
|
13213
|
+
"witness": "unclassified",
|
|
13214
|
+
"requirementId": null,
|
|
13215
|
+
"disposition": "externally-gated",
|
|
13216
|
+
"target": "myndhyve-next-cut",
|
|
13217
|
+
"sources": [
|
|
13218
|
+
{
|
|
13219
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13220
|
+
"token": "G5"
|
|
13221
|
+
}
|
|
13222
|
+
]
|
|
13223
|
+
},
|
|
13224
|
+
{
|
|
13225
|
+
"id": "openwop.gap.0223.6",
|
|
13226
|
+
"rfc": "0223",
|
|
13227
|
+
"local": "G6",
|
|
13228
|
+
"section": "§Unresolved questions",
|
|
13229
|
+
"surface": "The `majority` threshold was stated from one v1 fixture.",
|
|
13230
|
+
"witness": "unclassified",
|
|
13231
|
+
"requirementId": null,
|
|
13232
|
+
"disposition": "closed",
|
|
13233
|
+
"target": null,
|
|
13234
|
+
"sources": [
|
|
13235
|
+
{
|
|
13236
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13237
|
+
"token": "G6"
|
|
13238
|
+
}
|
|
13239
|
+
]
|
|
13240
|
+
},
|
|
13241
|
+
{
|
|
13242
|
+
"id": "openwop.gap.0223.7",
|
|
13243
|
+
"rfc": "0223",
|
|
13244
|
+
"local": "G7",
|
|
13245
|
+
"section": "§Unresolved questions",
|
|
13246
|
+
"surface": "`onTimeout: approve` re-legalises the fail-open timeout RFC 0093 ruled non-conformant; this RFC defines only the absent and `reject` cases.",
|
|
13247
|
+
"witness": "unclassified",
|
|
13248
|
+
"requirementId": null,
|
|
13249
|
+
"disposition": "transferred",
|
|
13250
|
+
"target": "openwop#1696",
|
|
13251
|
+
"sources": [
|
|
13252
|
+
{
|
|
13253
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13254
|
+
"token": "G7"
|
|
13255
|
+
}
|
|
13256
|
+
]
|
|
13257
|
+
},
|
|
13258
|
+
{
|
|
13259
|
+
"id": "openwop.gap.0223.8",
|
|
13260
|
+
"rfc": "0223",
|
|
13261
|
+
"local": "G8",
|
|
13262
|
+
"section": "§A",
|
|
13263
|
+
"surface": "A gate re-entered over a reject loop collides with the one-interrupt-per-key rule (`interrupt.md` §Re-entry); v2 has no per-iteration key derivation.",
|
|
13264
|
+
"witness": "unclassified",
|
|
13265
|
+
"requirementId": null,
|
|
13266
|
+
"disposition": "transferred",
|
|
13267
|
+
"target": "openwop#1697",
|
|
13268
|
+
"sources": [
|
|
13269
|
+
{
|
|
13270
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13271
|
+
"token": "G8"
|
|
13272
|
+
}
|
|
13273
|
+
]
|
|
13274
|
+
},
|
|
13275
|
+
{
|
|
13276
|
+
"id": "openwop.gap.0223.9",
|
|
13277
|
+
"rfc": "0223",
|
|
13278
|
+
"local": "G9",
|
|
13279
|
+
"section": "§Motivation",
|
|
13280
|
+
"surface": "Whether a run-failure code on `run.failed` / `node.failed` must be registered: `errors.md` scopes its MUST to error responses, overview §0 to every producer.",
|
|
13281
|
+
"witness": "unclassified",
|
|
13282
|
+
"requirementId": null,
|
|
13283
|
+
"disposition": "transferred",
|
|
13284
|
+
"target": "openwop#1698",
|
|
13285
|
+
"sources": [
|
|
13286
|
+
{
|
|
13287
|
+
"file": "RFCS/registers/0223-approval-reject-disposition.gaps.md",
|
|
13288
|
+
"token": "G9"
|
|
13289
|
+
}
|
|
13290
|
+
]
|
|
13291
|
+
},
|
|
13292
|
+
{
|
|
13293
|
+
"id": "openwop.gap.0224.1",
|
|
13294
|
+
"rfc": "0224",
|
|
13295
|
+
"local": "G1",
|
|
13296
|
+
"section": "§Conformance",
|
|
13297
|
+
"surface": "The witness is loopback only; `Accepted` needs a certified public v2 bundle from a host advertising the family.",
|
|
13298
|
+
"witness": "unclassified",
|
|
13299
|
+
"requirementId": null,
|
|
13300
|
+
"disposition": "externally-gated",
|
|
13301
|
+
"target": "v2-reference-public-cut",
|
|
13302
|
+
"sources": [
|
|
13303
|
+
{
|
|
13304
|
+
"file": "RFCS/registers/0224-v2-audit-log-integrity.gaps.md",
|
|
13305
|
+
"token": "G1"
|
|
13306
|
+
}
|
|
13307
|
+
]
|
|
13308
|
+
},
|
|
13309
|
+
{
|
|
13310
|
+
"id": "openwop.gap.0224.2",
|
|
13311
|
+
"rfc": "0224",
|
|
13312
|
+
"local": "G2",
|
|
13313
|
+
"section": "§Unresolved questions",
|
|
13314
|
+
"surface": "A dual-signing host lists a checkpoint under a key other than `checkpointPublicKey`, which the signature row fails; v2 advertises one key.",
|
|
13315
|
+
"witness": "unclassified",
|
|
13316
|
+
"requirementId": null,
|
|
13317
|
+
"disposition": "externally-gated",
|
|
13318
|
+
"target": "first-rotating-host",
|
|
13319
|
+
"sources": [
|
|
13320
|
+
{
|
|
13321
|
+
"file": "RFCS/registers/0224-v2-audit-log-integrity.gaps.md",
|
|
13322
|
+
"token": "G2"
|
|
13323
|
+
}
|
|
13324
|
+
]
|
|
13325
|
+
},
|
|
13088
13326
|
{
|
|
13089
13327
|
"id": "openwop.gap.spec.a2a-integration.g1",
|
|
13090
13328
|
"rfc": "0152",
|
|
@@ -111,7 +111,7 @@ These keys are not part of the v2 root:
|
|
|
111
111
|
|
|
112
112
|
Operation paths live in `spec/v2/path-manifest.json` ([`versioning.md`](versioning.md)). The declaration is generated from nothing and checked against everything (`scripts/check-declaration.mjs`).
|
|
113
113
|
|
|
114
|
-
## 5. Core families (
|
|
114
|
+
## 5. Core families (73)
|
|
115
115
|
|
|
116
116
|
Each heading below is a `spec/v2/declaration.json` row with `anchor: core`. `scripts/check-declaration.mjs` MUST fail when a heading here, a root key in the generated schema, or a pack peer-dependency identifier names a family the declaration does not. The peer-dependency identifier is identical to the key ([`packs.md`](packs.md)).
|
|
117
117
|
|
|
@@ -394,6 +394,10 @@ Witness `witnessable-gated`.
|
|
|
394
394
|
|
|
395
395
|
Witness `seam-gated`. Facets: `lanes`, `subjectLinkKey`.
|
|
396
396
|
|
|
397
|
+
### § auditLogIntegrity
|
|
398
|
+
|
|
399
|
+
Witness `witnessable-gated`. Facets: `checkpointSignatureAlgorithm`, `checkpointPublicKey`, `checkpointIntervalEntries`, `checkpointIntervalSeconds` ([security-defaults.md](security-defaults.md) §Audit-log integrity).
|
|
400
|
+
|
|
397
401
|
### § i18n
|
|
398
402
|
|
|
399
403
|
Witness `witnessable-gated`.
|
package/spec/v2/core/errors.md
CHANGED
|
@@ -8,7 +8,7 @@ Every error a v2 host returns is a row in one registry. A client routes on `erro
|
|
|
8
8
|
|
|
9
9
|
## The registry
|
|
10
10
|
|
|
11
|
-
`spec/v2/errors.json` holds one row per code: `{ code, httpStatus, retriable, details, since, deprecated? }` plus the provenance fields `statusSource` and `source`, and an optional one-line `meaning`. `spec/v2/errors.schema.json` defines the row. It registers **
|
|
11
|
+
`spec/v2/errors.json` holds one row per code: `{ code, httpStatus, retriable, details, since, deprecated? }` plus the provenance fields `statusSource` and `source`, and an optional one-line `meaning`. `spec/v2/errors.schema.json` defines the row. It registers **108** codes. `schemas/v2/error-envelope.schema.json` is GENERATED from it and MUST NOT be edited by hand.
|
|
12
12
|
|
|
13
13
|
- A host MUST return a registered code, or a vendor code, in every error response.
|
|
14
14
|
- A vendor code MUST match `^(?!openwop\.)[a-z][a-z0-9]*(-[a-z0-9]+)*\.[a-z][a-z0-9_]*$`, with its first segment an org registered in `spec/v2/declaration.json`. `openwop.` is reserved.
|
|
@@ -47,7 +47,7 @@ The idempotency mismatch code is `idempotency_key_mismatch` only ([idempotency.m
|
|
|
47
47
|
|
|
48
48
|
## Codes by HTTP status
|
|
49
49
|
|
|
50
|
-
Generated from `spec/v2/errors.json` (
|
|
50
|
+
Generated from `spec/v2/errors.json` (108 codes; `retriable` and `statusSource` are in the registry).
|
|
51
51
|
|
|
52
52
|
Code | Status
|
|
53
53
|
--- | ---
|
|
@@ -130,6 +130,7 @@ Code | Status
|
|
|
130
130
|
`payload_too_large` | 413
|
|
131
131
|
`workspace_too_large` | 413
|
|
132
132
|
`unsupported_media_type` | 415
|
|
133
|
+
`approval_rejected` | 422
|
|
133
134
|
`capability_not_provided` | 422
|
|
134
135
|
`capability_required` | 422
|
|
135
136
|
`connection_auth_metadata_mismatch` | 422
|
|
@@ -42,7 +42,7 @@ Per-kind rules:
|
|
|
42
42
|
- An in-memory cache MAY serve in-process replays but MUST NOT replace the event log for cross-process replays.
|
|
43
43
|
- A host MUST validate the resume value against `resumeSchema` when one is declared, and MUST refuse a failing value with `400 validation_error`.
|
|
44
44
|
|
|
45
|
-
`timeoutMs`, when set, is the interrupt's own deadline.
|
|
45
|
+
`timeoutMs`, when set, is the interrupt's own deadline. What an approval gate does when it elapses is §Rejection.
|
|
46
46
|
|
|
47
47
|
## Events
|
|
48
48
|
|
|
@@ -113,6 +113,17 @@ The token grammar and the `interrupt.tokenAlgs[]` / `kid` check are [identity.md
|
|
|
113
113
|
- `requiredApprovals` sets the quorum (default 1). `rejectionPolicy` is `single-veto` (default) or `majority`.
|
|
114
114
|
- When `overrideBypassesQuorum` is `true`, a configured override principal MAY release the gate alone; otherwise its vote counts once.
|
|
115
115
|
|
|
116
|
+
### Rejection
|
|
117
|
+
|
|
118
|
+
A `reject` exits the suspend. The host MUST record `action: "reject"` and `decision: "rejected"` on `interrupt.resolved`, and SHOULD also emit `approval.rejected`. The resume value is returned to the node that raised the interrupt (§Re-entry and resume values).
|
|
119
|
+
|
|
120
|
+
- A node that does not turn the rejection into an output MUST fail with `approval_rejected` ([errors.md](errors.md)) and `retryable: false` on the `node.failed` error, and MUST NOT be retried.
|
|
121
|
+
- A rejected gate is a failed source. It MUST NOT satisfy an `all_success`, `any_success` or `none_failed` edge. The run continues past it only over an edge whose `triggerRule` admits a failed source (`all_complete` or `any_failed`).
|
|
122
|
+
- When no such edge exists, the run MUST terminate `failed` with `run.failed.error.code` `approval_rejected` and `failedNodeId` naming the gate.
|
|
123
|
+
- The gate resolves rejected on one eligible `reject` under `single-veto`, or when rejects exceed half of `requiredApprovals` under `majority`. A vote that does not decide the gate MUST NOT emit `interrupt.resolved`.
|
|
124
|
+
- When a non-zero `timeoutMs` elapses with no resolution and `onTimeout` is absent or `reject`, the host MUST resolve the gate rejected, recording `action: "timeout"`, `decision: "rejected"` and `reason: "timeout"`, and MUST apply the rules above. A host MUST NOT accept `timeout` on a resume request.
|
|
125
|
+
- On replay the failure MUST be derived from the recorded `interrupt.resolved`, never re-decided.
|
|
126
|
+
|
|
116
127
|
## Approver enforcement
|
|
117
128
|
|
|
118
129
|
Enforcement is an obligation of the fields, not a discovery flag. The facet `spec/v2/facets/interrupt.schema.json` carries `tokenAlgs[]` (REQUIRED) and `refKinds[]` ⊆ `principal`, `group`, `role`.
|
|
@@ -131,4 +142,4 @@ Refs are opaque to the engine; the host resolves them against its own identity m
|
|
|
131
142
|
|
|
132
143
|
The v1 interrupt-token drain is [identity.md](identity.md) §4.
|
|
133
144
|
|
|
134
|
-
*Sources: RFC 0170, RFC 0171, RFC 0173, RFC 0187, RFC 0196.*
|
|
145
|
+
*Sources: RFC 0170, RFC 0171, RFC 0173, RFC 0187, RFC 0196, RFC 0223.*
|
package/spec/v2/core/packs.md
CHANGED
|
@@ -90,9 +90,16 @@ The same block applies to a **bare manifest** — the `pack.json` inside the tar
|
|
|
90
90
|
- A verifier MUST verify the signature against the issuing registry's key for `keyId`, and MUST check the pack name against that key's `permittedNamespaces`.
|
|
91
91
|
- A signature over tarball bytes is not a v2 signature; such a pack MUST be re-signed, not relabeled.
|
|
92
92
|
|
|
93
|
+
Only a `signingKeys[]` entry whose `status` is `active` MAY sign a new publication. A key MUST stay listed while a served version names it, and a verifier MUST NOT refuse a version because its key is not `active`.
|
|
94
|
+
|
|
93
95
|
## Version manifests
|
|
94
96
|
|
|
95
|
-
`kind` is REQUIRED on every version manifest and every bare manifest.
|
|
97
|
+
`kind` is REQUIRED on every version manifest and every bare manifest. Lifecycle flags sit outside the signature; changing one republishes the version manifest.
|
|
98
|
+
|
|
99
|
+
- `versionDeprecated: true`: still served; a consumer MAY refuse to install it.
|
|
100
|
+
- `yanked: true`: its manifest, tarball and signature stay served, and the pack index MUST NOT name it `latest` while an unyanked version exists. A range MUST skip it; a pin MAY resolve it. Advisory-listed versions MUST be yanked.
|
|
101
|
+
|
|
102
|
+
A registry MUST refuse a submission that breaks these rules or republishes a version, with `pack_integrity_failure`, `pack_validation_failed`, `pack_signature_invalid`, `pack_engine_unsupported`, `pack_peer_dependency_undefined` or `version_conflict`.
|
|
96
103
|
|
|
97
104
|
## The registry's own schemas
|
|
98
105
|
|
|
@@ -111,4 +118,4 @@ A registry MUST validate submissions against vendored copies of these schemas pi
|
|
|
111
118
|
- The v1 registry tree is frozen through the overlap, behind the v2 tree.
|
|
112
119
|
- `testMode` advertises the v1 `/v1/packs-test/*` mirror, a conformance seam ([conformance.md §"The seams profile"](conformance.md)). It remains advertisable through the overlap and is removed at 3.0.
|
|
113
120
|
|
|
114
|
-
*Sources: RFC 0177, RFC 0212.*
|
|
121
|
+
*Sources: RFC 0177, RFC 0212, RFC 0222.*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Security Defaults
|
|
2
2
|
|
|
3
3
|
> **Status: Stable.**
|
|
4
|
-
> **Normative home:** `sandbox`, `compensation`, `purposePropagation`.
|
|
4
|
+
> **Normative home:** `sandbox`, `compensation`, `purposePropagation`, `auditLogIntegrity`.
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
@@ -28,6 +28,7 @@ A security-load-bearing behavior is an obligation of the surface that needs it.
|
|
|
28
28
|
| `idempotency` | Layer-2 effect identity (§Layer-2 effect identity) | witnessable-gated (fixture provider) | `logical-effect-id-retry-stable` |
|
|
29
29
|
| an `oauth2` or `oidc` lane | protected-resource metadata and challenges ([identity.md §2.5](identity.md)) | witnessable-gated | `auth-challenge-no-oracle` |
|
|
30
30
|
| any outbound request | no inbound credential on an onward hop (§Onward hops) | seam-gated | `inbound-credential-no-passthrough` |
|
|
31
|
+
| `auditLogIntegrity` | a chained, checkpointed, verifiable audit log (§Audit-log integrity) | witnessable-gated | `audit-checkpoint-signed-over-root` |
|
|
31
32
|
|
|
32
33
|
### Auth lanes
|
|
33
34
|
|
|
@@ -91,6 +92,16 @@ One credential is not inbound in this sense: an A2A push-config credential (`aut
|
|
|
91
92
|
|
|
92
93
|
A host advertising `purposePropagation` MUST re-emit a `permittedPurposes` label it received (A2A `metadata.openwop.permittedPurposes`, `TriggerEvent.permittedPurposes`) on every onward hop of the same data, narrowing and never widening, and MUST treat `[]` as no onward use. `purposePropagation.propagatesOnward` is `false` only on a host with no onward hop. The family advertises propagation, not enforcement.
|
|
93
94
|
|
|
95
|
+
### Audit-log integrity
|
|
96
|
+
|
|
97
|
+
A host advertising `auditLogIntegrity` MUST keep an audit log a privileged insider cannot silently rewrite. It:
|
|
98
|
+
|
|
99
|
+
- MUST keep the log append-only, each entry carrying `prevHash`, the lowercase-hex SHA-256 of the prior entry's canonical JSON ([conformance.md §Canonical JSON](conformance.md)), `null` for the first;
|
|
100
|
+
- MUST sign a checkpoint anchoring at most `checkpointIntervalEntries` entries, and anchor an entry within `checkpointIntervalSeconds` of its append. The range, leaves, root and signature are [RFC 0218 §A](https://github.com/openwop/openwop/blob/main/RFCS/0218-audit-checkpoint-preimage.md); the signature is Ed25519 (`checkpointSignatureAlgorithm`) under `checkpointPublicKey`, a key used for no other surface;
|
|
101
|
+
- MUST serve `GET /audit/verify` (scope `audit:read`), answering `schemas/v2/audit-verify-result.schema.json` with every checkpoint whose `atSequence` is in the range, ascending, and the anomalies of [RFC 0218 §C](https://github.com/openwop/openwop/blob/main/RFCS/0218-audit-checkpoint-preimage.md). A host that does not advertise the family MAY omit the operation.
|
|
102
|
+
|
|
103
|
+
The `audit-log-integrity` and `audit-checkpoint-signature` scenarios witness the verify body, each signature, and the cadence. The root is not witnessable from outside, because entries are not on the wire; tamper detection is a host-internal test.
|
|
104
|
+
|
|
94
105
|
## Relaxations
|
|
95
106
|
|
|
96
107
|
A relaxation, where one is legitimate — a development deployment, a single-tenant appliance — is an operator setting, never a discovery field. Every relaxation a host runs under MUST be recorded in its certification bundle as `host.relaxations[]` (`schemas/v2/certification-bundle.schema.json`): `{ obligation, durability, reason }`, `durability ∈ session | deployment | persisted`.
|
|
@@ -131,4 +142,4 @@ Rows `C6.1`–`C6.9` are `spec/v1/migrations.json` entries.
|
|
|
131
142
|
|
|
132
143
|
See also: identity.md, replay.md, webhooks.md, capabilities.md, conformance.md.
|
|
133
144
|
|
|
134
|
-
*Sources: RFC 0150, RFC 0163, RFC 0164, RFC 0170, RFC 0173, RFC 0214.*
|
|
145
|
+
*Sources: RFC 0150, RFC 0163, RFC 0164, RFC 0170, RFC 0173, RFC 0214, RFC 0218, RFC 0224.*
|
package/spec/v2/corrections.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "./corrections.schema.json",
|
|
3
3
|
"$comment": "RFC 0197 §A.4 — v2 Class-3 corrections. Seeded with P3 only. The 2.8.2 removal of `workflowChainPacks.deferredParameters` and `.hostExpansionSeam` (P1) is deliberately NOT seeded: a committed bundle carried `deferredParameters` and then failed `capabilities-root-closed`, so the row would fail R3 — which is the point. P1 is recorded as the motivating defect in COMPATIBILITY.md §3a, not laundered into this register.",
|
|
4
4
|
"version": 1,
|
|
5
|
-
"updated": "2026-09-
|
|
5
|
+
"updated": "2026-09-28",
|
|
6
6
|
"rows": [
|
|
7
7
|
{
|
|
8
8
|
"id": "openwop.correction.v2.1",
|
|
@@ -43,6 +43,23 @@
|
|
|
43
43
|
"manifestsScanned": 156,
|
|
44
44
|
"note": "The prior shape is any string; the corrected shape is the axis-1 `<major>.<minor>` grammar that spec/v2/core/versioning.md §1.5 and the v2-min-client-version scenario already required of an advertised value. Bundle leg: all 8 committed evidence/v2-host-bundles/*.json advertise minClientVersion, and every value conforms (seven \"1.0\", MyndHyve \"0.1\"), so 0 carry a value the pattern rejects. The one \"0.1.0\" in the corpus is a major-1 witness under evidence/rfc-witnesses/, not a v2 bundle. Registry leg: minClientVersion is a discovery field, not a manifest field; 0 of 156 pack.json documents on openwop-registry origin/main (c15d3d6) carry it. The schema added a pattern only, so no property, type or required entry moved and check-v2-surface-monotone sees no change."
|
|
45
45
|
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "openwop.correction.v2.3",
|
|
49
|
+
"date": "2026-09-28",
|
|
50
|
+
"class": "w3c-class-3",
|
|
51
|
+
"rfc": "0218",
|
|
52
|
+
"pointers": [
|
|
53
|
+
"schemas/v2/audit-verify-result.schema.json#/chainValid",
|
|
54
|
+
"schemas/v2/audit-verify-result.schema.json#/anomalies"
|
|
55
|
+
],
|
|
56
|
+
"compatibilityEntry": "an audit anomaly's shape, and `chainValid` as the aggregate verdict",
|
|
57
|
+
"priorShapeCensus": {
|
|
58
|
+
"bundles": 0,
|
|
59
|
+
"manifests": 0,
|
|
60
|
+
"manifestsScanned": 157,
|
|
61
|
+
"note": "The prior shape is a verify result with `chainValid: true` beside a non-empty `anomalies`, or `chainValid: false` beside an empty one; the corrected shape is the root if/then/else RFC 0218 §C.4 adds, which the schema's `chainValid` and `anomalies` descriptions already required. Bundle leg: none of the 9 committed evidence/v2-host-bundles/*.json carries a `GET /audit/verify` body (no `chainValid` member anywhere). Registry leg: a verify result is not a manifest field; 0 of 157 pack.json documents on openwop-registry origin/main (4c5de1f) carry `chainValid`. The Anomaly members RFC 0218 §C adds are OPTIONAL additions that check-v2-surface-monotone reports as additive."
|
|
62
|
+
}
|
|
46
63
|
}
|
|
47
64
|
]
|
|
48
65
|
}
|
package/spec/v2/declaration.json
CHANGED
|
@@ -1621,6 +1621,31 @@
|
|
|
1621
1621
|
"owningRfc": "0154",
|
|
1622
1622
|
"facetsFrom": "spec/v2/facets/auth.schema.json"
|
|
1623
1623
|
},
|
|
1624
|
+
{
|
|
1625
|
+
"key": "auditLogIntegrity",
|
|
1626
|
+
"kind": "family",
|
|
1627
|
+
"normativeText": [
|
|
1628
|
+
"spec/v2/core/security-defaults.md"
|
|
1629
|
+
],
|
|
1630
|
+
"anchor": "core",
|
|
1631
|
+
"section": "core/capabilities.md#auditLogIntegrity",
|
|
1632
|
+
"peerDependencyId": "auditLogIntegrity",
|
|
1633
|
+
"witness": "witnessable-gated",
|
|
1634
|
+
"maturity": {
|
|
1635
|
+
"technical": "experimental",
|
|
1636
|
+
"adoption": "none"
|
|
1637
|
+
},
|
|
1638
|
+
"facets": [
|
|
1639
|
+
"checkpointSignatureAlgorithm",
|
|
1640
|
+
"checkpointPublicKey",
|
|
1641
|
+
"checkpointIntervalEntries",
|
|
1642
|
+
"checkpointIntervalSeconds"
|
|
1643
|
+
],
|
|
1644
|
+
"floorScenarios": [],
|
|
1645
|
+
"requirementIds": [],
|
|
1646
|
+
"owningRfc": "0224",
|
|
1647
|
+
"facetsFrom": "spec/v2/facets/auditLogIntegrity.schema.json"
|
|
1648
|
+
},
|
|
1624
1649
|
{
|
|
1625
1650
|
"key": "i18n",
|
|
1626
1651
|
"kind": "family",
|
|
@@ -1737,7 +1762,7 @@
|
|
|
1737
1762
|
"extensionName": "rest-transport",
|
|
1738
1763
|
"witness": "witnessable-gated",
|
|
1739
1764
|
"maturity": {
|
|
1740
|
-
"technical": "
|
|
1765
|
+
"technical": "stable",
|
|
1741
1766
|
"adoption": "single-witness"
|
|
1742
1767
|
},
|
|
1743
1768
|
"facets": [
|
|
@@ -1779,7 +1804,7 @@
|
|
|
1779
1804
|
"witness": "claims-check",
|
|
1780
1805
|
"maturity": {
|
|
1781
1806
|
"technical": "experimental",
|
|
1782
|
-
"adoption": "
|
|
1807
|
+
"adoption": "none"
|
|
1783
1808
|
},
|
|
1784
1809
|
"facets": [],
|
|
1785
1810
|
"floorScenarios": [],
|
|
@@ -1797,7 +1822,7 @@
|
|
|
1797
1822
|
"witness": "claims-check",
|
|
1798
1823
|
"maturity": {
|
|
1799
1824
|
"technical": "experimental",
|
|
1800
|
-
"adoption": "
|
|
1825
|
+
"adoption": "none"
|
|
1801
1826
|
},
|
|
1802
1827
|
"facets": [],
|
|
1803
1828
|
"floorScenarios": [],
|
|
@@ -1814,7 +1839,7 @@
|
|
|
1814
1839
|
"extensionName": "chat",
|
|
1815
1840
|
"witness": "claims-check",
|
|
1816
1841
|
"maturity": {
|
|
1817
|
-
"technical": "
|
|
1842
|
+
"technical": "stable",
|
|
1818
1843
|
"adoption": "single-witness"
|
|
1819
1844
|
},
|
|
1820
1845
|
"facets": [],
|
|
@@ -1833,7 +1858,7 @@
|
|
|
1833
1858
|
"witness": "claims-check",
|
|
1834
1859
|
"maturity": {
|
|
1835
1860
|
"technical": "experimental",
|
|
1836
|
-
"adoption": "
|
|
1861
|
+
"adoption": "none"
|
|
1837
1862
|
},
|
|
1838
1863
|
"facets": [],
|
|
1839
1864
|
"floorScenarios": [],
|
|
@@ -1851,7 +1876,7 @@
|
|
|
1851
1876
|
"witness": "claims-check",
|
|
1852
1877
|
"maturity": {
|
|
1853
1878
|
"technical": "experimental",
|
|
1854
|
-
"adoption": "
|
|
1879
|
+
"adoption": "none"
|
|
1855
1880
|
},
|
|
1856
1881
|
"facets": [],
|
|
1857
1882
|
"floorScenarios": [],
|
|
@@ -1868,7 +1893,7 @@
|
|
|
1868
1893
|
"extensionName": "entities",
|
|
1869
1894
|
"witness": "claims-check",
|
|
1870
1895
|
"maturity": {
|
|
1871
|
-
"technical": "
|
|
1896
|
+
"technical": "stable",
|
|
1872
1897
|
"adoption": "single-witness"
|
|
1873
1898
|
},
|
|
1874
1899
|
"facets": [],
|
|
@@ -1886,7 +1911,7 @@
|
|
|
1886
1911
|
"extensionName": "kanban",
|
|
1887
1912
|
"witness": "claims-check",
|
|
1888
1913
|
"maturity": {
|
|
1889
|
-
"technical": "
|
|
1914
|
+
"technical": "stable",
|
|
1890
1915
|
"adoption": "single-witness"
|
|
1891
1916
|
},
|
|
1892
1917
|
"facets": [],
|
|
@@ -1904,7 +1929,7 @@
|
|
|
1904
1929
|
"extensionName": "knowledge",
|
|
1905
1930
|
"witness": "claims-check",
|
|
1906
1931
|
"maturity": {
|
|
1907
|
-
"technical": "
|
|
1932
|
+
"technical": "stable",
|
|
1908
1933
|
"adoption": "single-witness"
|
|
1909
1934
|
},
|
|
1910
1935
|
"facets": [],
|
|
@@ -1923,7 +1948,7 @@
|
|
|
1923
1948
|
"witness": "claims-check",
|
|
1924
1949
|
"maturity": {
|
|
1925
1950
|
"technical": "experimental",
|
|
1926
|
-
"adoption": "
|
|
1951
|
+
"adoption": "none"
|
|
1927
1952
|
},
|
|
1928
1953
|
"facets": [],
|
|
1929
1954
|
"floorScenarios": [],
|
|
@@ -1941,7 +1966,7 @@
|
|
|
1941
1966
|
"witness": "claims-check",
|
|
1942
1967
|
"maturity": {
|
|
1943
1968
|
"technical": "experimental",
|
|
1944
|
-
"adoption": "
|
|
1969
|
+
"adoption": "none"
|
|
1945
1970
|
},
|
|
1946
1971
|
"facets": [],
|
|
1947
1972
|
"floorScenarios": [],
|
|
@@ -1958,7 +1983,7 @@
|
|
|
1958
1983
|
"extensionName": "web-research",
|
|
1959
1984
|
"witness": "claims-check",
|
|
1960
1985
|
"maturity": {
|
|
1961
|
-
"technical": "
|
|
1986
|
+
"technical": "stable",
|
|
1962
1987
|
"adoption": "single-witness"
|
|
1963
1988
|
},
|
|
1964
1989
|
"facets": [],
|
package/spec/v2/errors.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://openwop.dev/spec/v2/errors.schema.json",
|
|
3
3
|
"$comment": "RFC 0171 §B.1 — the error registry: one row per code {code, meaning?, httpStatus, retriable, details, since, deprecated?}. schemas/v2/error-envelope.schema.json is GENERATED from it (scripts/generate-error-envelope.mjs). Retry timing lives in Retry-After only (§B.2). statusSource records whether the status was stated in v1 prose, a v1 convention, or decided here. details is null until a code's details schema is registered (a null row means details is an open object for that code — closure over details is the RFC 0171 Phase 3 follow-up G-row).",
|
|
4
4
|
"version": "2.0",
|
|
5
|
-
"updated": "2026-09-
|
|
5
|
+
"updated": "2026-09-28",
|
|
6
6
|
"vendorCodePattern": "^(?!openwop\\.)[a-z][a-z0-9]*(-[a-z0-9]+)*\\.[a-z][a-z0-9_]*$",
|
|
7
7
|
"rows": [
|
|
8
8
|
{
|
|
@@ -839,6 +839,16 @@
|
|
|
839
839
|
"since": "2.0",
|
|
840
840
|
"source": "spec/v2/core/errors.md §The envelope — a request body whose Content-Type the host does not accept (RFC 9110 §15.5.16); registered 2026-09-05 because both production hosts had to invent it"
|
|
841
841
|
},
|
|
842
|
+
{
|
|
843
|
+
"code": "approval_rejected",
|
|
844
|
+
"meaning": "An approval gate resolved rejected (a decision, a quorum or a timeout) and no edge routed the failure, so the node and the run failed.",
|
|
845
|
+
"httpStatus": 422,
|
|
846
|
+
"statusSource": "v2 decision",
|
|
847
|
+
"retriable": false,
|
|
848
|
+
"details": null,
|
|
849
|
+
"since": "2.43",
|
|
850
|
+
"source": "RFC 0223; spec/v2/core/interrupt.md §Rejection"
|
|
851
|
+
},
|
|
842
852
|
{
|
|
843
853
|
"code": "capability_not_provided",
|
|
844
854
|
"meaning": "The host does not provide a capability the request or pack requires.",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| **witness:** | `claims-check` |
|
|
10
10
|
| **technical:** | `experimental` |
|
|
11
|
-
| **adoption:** | `
|
|
11
|
+
| **adoption:** | `none` |
|
|
12
12
|
| **peer-dependency id** | `brand` |
|
|
13
13
|
| **advertised as** | `extensions.<org>.brand` |
|
|
14
14
|
| **declared facets** | none defined |
|