blun-king-cli 9.1.597 → 9.1.600

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 (106) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +17 -1
  3. package/agent-spine-plugin/CHANGELOG.md +1 -1
  4. package/agent-spine-plugin/docs/host-integration.md +1 -15
  5. package/agent-spine-plugin/docs/preflight-recall.md +1 -1
  6. package/agent-spine-plugin/scripts/check-install.js +1 -6
  7. package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
  8. package/agent-spine-plugin/scripts/release-check.js +2 -3
  9. package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
  10. package/agent-spine-plugin/src/hook.js +40 -40
  11. package/agent-spine-plugin/src/lib/briefing.js +6 -3
  12. package/agent-spine-plugin/src/lib/hook-context.js +63 -64
  13. package/agent-spine-plugin/src/lib/hook-output.js +115 -94
  14. package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
  15. package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
  16. package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
  17. package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
  18. package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
  19. package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
  20. package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
  21. package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
  22. package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
  23. package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
  24. package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
  25. package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
  26. package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
  27. package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
  28. package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
  29. package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
  30. package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
  31. package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
  32. package/agent-spine-plugin/src/lib/source-roots.js +26 -16
  33. package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
  34. package/bin/core-bootstrap.js +18 -10
  35. package/bin/launcher-mode.js +5 -0
  36. package/bin/launcher-runtime.js +27 -0
  37. package/bin/verify-bundled-agent-sources.cjs +28 -2
  38. package/blun.mjs +798 -143
  39. package/bundled-agent-sources.json +192 -155
  40. package/package.json +1 -1
  41. package/standard-skills/translate-native/README.md +1334 -1
  42. package/standard-skills/translate-native/SKILL.md +1 -1
  43. package/standard-skills/translate-native/VERSION +1 -1
  44. package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
  45. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
  46. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
  47. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
  48. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
  49. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
  50. package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
  51. package/standard-skills/translate-native/integrations/website_localization.py +234 -10
  52. package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
  53. package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
  54. package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
  55. package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
  56. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
  57. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
  58. package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
  59. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
  60. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
  61. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
  62. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
  63. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
  64. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
  65. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
  66. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
  67. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
  68. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
  69. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
  70. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
  71. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
  72. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
  73. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
  74. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
  75. package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
  76. package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
  77. package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
  78. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
  79. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
  80. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
  81. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
  82. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
  83. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
  84. package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
  85. package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
  86. package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
  87. package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
  88. package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
  89. package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
  90. package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
  91. package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
  92. package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
  93. package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
  94. package/standard-skills/translate-native/provenance.json +2 -2
  95. package/standard-skills/translate-native/references/commercial-localization.md +96 -17
  96. package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
  97. package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
  98. package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
  99. package/standard-tools/language-guard/VERSION +1 -1
  100. package/standard-tools/language-guard/blun_language_guard.py +3 -1
  101. package/standard-tools/language-guard/check_commercial_review.py +69 -9
  102. package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
  103. package/standard-tools/language-guard/provenance.json +2 -2
  104. package/standard-tools/manifest.json +1 -1
  105. package/worker-host.mjs +215 -82
  106. package/agent-spine-plugin/scripts/check-install-king.js +0 -37
@@ -0,0 +1,896 @@
1
+ #!/usr/bin/env python3
2
+ """Canonical OpenAPI 3.1 profile for the public CMS submission sidecar."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import json
8
+ from typing import Any, Mapping
9
+
10
+
11
+ DOCUMENT_SCHEMA = "blun.cms-public-submission-dispatch-openapi.v13"
12
+ RESPONSE_SCHEMA = "blun.cms-public-submission-dispatch-openapi-response.v1"
13
+ EU_TARGET_LOCALES = (
14
+ "bg-BG", "hr-HR", "cs-CZ", "da-DK", "nl-NL", "en-IE", "et-EE",
15
+ "fi-FI", "fr-FR", "de-AT", "el-GR", "hu-HU", "ga-IE", "it-IT",
16
+ "lv-LV", "lt-LT", "mt-MT", "pl-PL", "pt-PT", "ro-RO", "sk-SK",
17
+ "sl-SI", "es-ES", "sv-SE",
18
+ )
19
+ CONTENT_TYPES = (
20
+ "headline", "cta", "marketing", "ui", "documentation", "seo",
21
+ "legal", "commercial",
22
+ )
23
+
24
+
25
+ def _canonical(value: Any) -> bytes:
26
+ return json.dumps(
27
+ value, ensure_ascii=False, allow_nan=False, sort_keys=True,
28
+ separators=(",", ":"),
29
+ ).encode("utf-8")
30
+
31
+
32
+ def _schema_ref(name: str) -> dict[str, str]:
33
+ return {"$ref": "#/components/schemas/" + name}
34
+
35
+
36
+ def _closed_object(
37
+ properties: Mapping[str, Any], *, optional: tuple[str, ...] = (),
38
+ ) -> dict[str, Any]:
39
+ return {
40
+ "type": "object",
41
+ "additionalProperties": False,
42
+ "required": sorted(set(properties) - set(optional)),
43
+ "properties": dict(properties),
44
+ }
45
+
46
+
47
+ def _exact_schema(value: Any) -> dict[str, Any]:
48
+ """Describe one content-free capability value without allowing drift."""
49
+ if isinstance(value, Mapping):
50
+ properties = {
51
+ str(name): _exact_schema(content)
52
+ for name, content in value.items()
53
+ }
54
+ return _closed_object(properties)
55
+ if value is None:
56
+ return {"type": "null"}
57
+ if isinstance(value, bool):
58
+ return {"type": "boolean", "const": value}
59
+ if isinstance(value, int):
60
+ return {"type": "integer", "const": value}
61
+ if isinstance(value, float):
62
+ return {"type": "number", "const": value}
63
+ if isinstance(value, str):
64
+ return {"type": "string", "const": value}
65
+ if isinstance(value, (list, tuple)):
66
+ items = [_exact_schema(item) for item in value]
67
+ return {
68
+ "type": "array", "prefixItems": items, "items": False,
69
+ "minItems": len(items), "maxItems": len(items),
70
+ }
71
+ raise TypeError("unsupported exact OpenAPI capability value")
72
+
73
+
74
+ def _bounded_text(*, source: bool = False) -> dict[str, Any]:
75
+ schema: dict[str, Any] = {
76
+ "type": "string", "minLength": 1, "x-unicode-normalization": "NFC",
77
+ "x-nul-forbidden": True,
78
+ }
79
+ if source:
80
+ schema.update({"maxLength": 1_000_000, "x-max-utf8-bytes": 1_000_000})
81
+ else:
82
+ schema["maxLength"] = 256
83
+ return schema
84
+
85
+
86
+ def _source_payload_schemas(capabilities: Mapping[str, Any]) -> dict[str, Any]:
87
+ contracts = capabilities["source_payload_schemas"]
88
+ localization = _closed_object({
89
+ "source_id": _bounded_text(),
90
+ "source_revision": _bounded_text(),
91
+ "source_text": _bounded_text(source=True),
92
+ "source_locale": {
93
+ **_bounded_text(),
94
+ "pattern": "^[A-Za-z]{2,8}(?:-(?:[A-Za-z]{4}|[A-Za-z]{2}|[0-9]{3}|[A-Za-z0-9]{5,8}))*$",
95
+ "x-canonical-bcp47": True,
96
+ },
97
+ "content_type": {"type": "string", "enum": list(CONTENT_TYPES)},
98
+ "glossary_version": _bounded_text(),
99
+ "policy_version": _bounded_text(),
100
+ "provider_id": _bounded_text(),
101
+ "model_id": _bounded_text(),
102
+ "model_version": _bounded_text(),
103
+ "software_version": _bounded_text(),
104
+ "target_locales": {
105
+ "type": "array", "minItems": 1, "maxItems": 24,
106
+ "uniqueItems": True,
107
+ "items": {"type": "string", "enum": list(EU_TARGET_LOCALES)},
108
+ "x-source-language-excluded": True,
109
+ },
110
+ }, optional=("target_locales",))
111
+ common = {
112
+ "event_id": _schema_ref("Token"),
113
+ "site_id": _schema_ref("Token"),
114
+ "website_version": _schema_ref("Token"),
115
+ "source_sequence": {"type": "integer", "minimum": 1},
116
+ }
117
+ change = _closed_object({
118
+ "schema": {"const": contracts["change"]},
119
+ **common,
120
+ "localization": _schema_ref("LocalizationRequest"),
121
+ })
122
+ cancellation = _closed_object({
123
+ "schema": {"const": contracts["cancellation"]},
124
+ "cancellation_id": _schema_ref("Token"),
125
+ **common,
126
+ "source_id": _schema_ref("Token"),
127
+ })
128
+ tombstone = _closed_object({
129
+ "schema": {"const": contracts["tombstone"]},
130
+ "tombstone_id": _schema_ref("Token"),
131
+ **common,
132
+ "source_id": _schema_ref("Token"),
133
+ })
134
+ return {
135
+ "LocalizationRequest": localization,
136
+ "ContentChange": change,
137
+ "ContentCancellation": cancellation,
138
+ "ContentTombstone": tombstone,
139
+ "SourcePayload": {
140
+ "oneOf": [
141
+ _schema_ref("ContentChange"),
142
+ _schema_ref("ContentCancellation"),
143
+ _schema_ref("ContentTombstone"),
144
+ ],
145
+ "discriminator": {
146
+ "propertyName": "schema",
147
+ "mapping": {
148
+ contracts["change"]: "#/components/schemas/ContentChange",
149
+ contracts["cancellation"]: "#/components/schemas/ContentCancellation",
150
+ contracts["tombstone"]: "#/components/schemas/ContentTombstone",
151
+ },
152
+ },
153
+ "description": (
154
+ "One complete canonical change, cancellation, or tombstone; "
155
+ "runtime validation remains authoritative for NFC, UTF-8 byte "
156
+ "limits, BCP-47 canonicalization, and source-language exclusion."
157
+ ),
158
+ "x-downstream-capabilities-sha256": capabilities[
159
+ "public_submission_capabilities_sha256"
160
+ ],
161
+ },
162
+ }
163
+
164
+
165
+ def _operation(
166
+ contract: Mapping[str, Any], *, operation_id: str,
167
+ tag: str, summary: str, request_schema: str | None,
168
+ response_component: str, headers: bool = False,
169
+ degraded_response_component: str | None = None,
170
+ ) -> dict[str, Any]:
171
+ responses = {
172
+ str(contract["success_status"]): {
173
+ "description": "Exact validated content-free response.",
174
+ "content": {
175
+ "application/json": {
176
+ "schema": _schema_ref(response_component),
177
+ },
178
+ },
179
+ },
180
+ }
181
+ for status in contract["error_statuses"]:
182
+ codes = list(contract["error_codes"][str(status)])
183
+ schema: dict[str, Any] = _closed_object({
184
+ "schema": {
185
+ "const": "blun.cms-public-submission-dispatch-http-error.v1",
186
+ },
187
+ "status": {"const": "BLOCK"},
188
+ "error_code": {"type": "string", "enum": codes},
189
+ })
190
+ description = "Fail-closed content-free error."
191
+ if status == 503 and degraded_response_component is not None:
192
+ schema = {
193
+ "oneOf": [
194
+ _schema_ref(degraded_response_component),
195
+ schema,
196
+ ],
197
+ }
198
+ description = (
199
+ "Validated degraded monitor state or fail-closed "
200
+ "content-free error."
201
+ )
202
+ responses[str(status)] = {
203
+ "description": description,
204
+ "content": {"application/json": {"schema": schema}},
205
+ "x-error-codes": codes,
206
+ }
207
+ operation: dict[str, Any] = {
208
+ "operationId": operation_id,
209
+ "summary": summary,
210
+ "tags": [tag],
211
+ "security": [{"hostAuthentication": []}],
212
+ "x-authentication-scope": contract["scope"],
213
+ "x-principal-schema": contract["principal_schema"],
214
+ "x-success-status": contract["success_status"],
215
+ "x-error-statuses": list(contract["error_statuses"]),
216
+ "x-error-codes": dict(contract["error_codes"]),
217
+ "x-response-invariants": list(contract["response_invariants"]),
218
+ "responses": dict(sorted(responses.items(), key=lambda item: int(item[0]))),
219
+ }
220
+ if request_schema is not None:
221
+ operation["requestBody"] = {
222
+ "required": True,
223
+ "content": {
224
+ "application/json": {
225
+ "schema": _schema_ref(request_schema),
226
+ },
227
+ },
228
+ }
229
+ parameters = []
230
+ precondition_header = contract["capabilities_precondition_header"]
231
+ if precondition_header is not None:
232
+ parameters.append({
233
+ "name": precondition_header, "in": "header", "required": True,
234
+ "schema": _schema_ref("Sha256"),
235
+ "description": (
236
+ "Must equal the complete capability SHA-256 obtained from the "
237
+ "immediately preceding authenticated discovery response."
238
+ ),
239
+ })
240
+ if headers:
241
+ parameters.extend([
242
+ {
243
+ "name": "Idempotency-Key", "in": "header", "required": True,
244
+ "schema": _schema_ref("Token"),
245
+ "description": "Must equal the immutable request identity.",
246
+ },
247
+ {
248
+ "name": "X-Localization-Source-Payload-SHA256",
249
+ "in": "header", "required": True,
250
+ "schema": _schema_ref("Sha256"),
251
+ "description": "SHA-256 of the complete canonical source payload.",
252
+ },
253
+ ])
254
+ if parameters:
255
+ operation["parameters"] = parameters
256
+ return operation
257
+
258
+
259
+ def _status_schema() -> dict[str, Any]:
260
+ nullable_sha = {"oneOf": [_schema_ref("Sha256"), {"type": "null"}]}
261
+ nullable_count = {
262
+ "oneOf": [
263
+ {"type": "integer", "minimum": 0, "maximum": 20},
264
+ {"type": "null"},
265
+ ],
266
+ }
267
+ nullable_time = {
268
+ "oneOf": [{"type": "number", "minimum": 0}, {"type": "null"}],
269
+ }
270
+ properties = {
271
+ "operation": {"type": "string", "enum": ["change", "cancellation", "tombstone"]},
272
+ "request_id": _schema_ref("Token"), "event_id": _schema_ref("Token"),
273
+ "site_id": _schema_ref("Token"), "payload_sha256": _schema_ref("Sha256"),
274
+ "commercial_contract_binding": {
275
+ "oneOf": [_schema_ref("CommercialContractBinding"), {"type": "null"}],
276
+ },
277
+ "source_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
278
+ "delivery_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
279
+ "client_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
280
+ "status": {"type": "string", "enum": ["accepted", "failed", "leased", "pending", "retry_wait"]},
281
+ "attempts": {"type": "integer", "minimum": 0, "maximum": 20},
282
+ "next_attempt_at": {"type": "number", "minimum": 0},
283
+ "lease_expires_at": nullable_time, "lease_expired": {"type": "boolean"},
284
+ "last_error_code": {"oneOf": [_schema_ref("ErrorCode"), {"type": "null"}]},
285
+ "remote_status": {"type": ["string", "null"], "enum": [None, "failed", "leased", "pending", "retry_wait", "succeeded"]},
286
+ "remote_attempts": nullable_count,
287
+ "remote_capabilities_sha256": nullable_sha,
288
+ "remote_binding_sha256": nullable_sha,
289
+ "remote_website_capability_binding": {"oneOf": [_schema_ref("WebsiteCapabilityBinding"), {"type": "null"}]},
290
+ "response_sha256": nullable_sha,
291
+ }
292
+ remote_complete = {"properties": {
293
+ "remote_status": {"type": "string", "enum": ["failed", "leased", "pending", "retry_wait", "succeeded"]},
294
+ "remote_attempts": {"type": "integer", "minimum": 0, "maximum": 20},
295
+ "remote_capabilities_sha256": _schema_ref("Sha256"),
296
+ "remote_binding_sha256": _schema_ref("Sha256"),
297
+ "remote_website_capability_binding": _schema_ref("WebsiteCapabilityBinding"),
298
+ "response_sha256": _schema_ref("Sha256"),
299
+ }}
300
+ return {
301
+ "type": "object", "additionalProperties": False,
302
+ "required": sorted(properties), "properties": properties,
303
+ "allOf": [
304
+ {
305
+ "if": {"properties": {"status": {"const": "leased"}}},
306
+ "then": {"properties": {"lease_expires_at": {"type": "number", "minimum": 0}}},
307
+ "else": {"properties": {"lease_expires_at": {"type": "null"}}},
308
+ },
309
+ {
310
+ "if": {"properties": {"status": {"const": "accepted"}}},
311
+ "then": remote_complete, "else": {"not": remote_complete},
312
+ },
313
+ {
314
+ "if": {"properties": {"operation": {
315
+ "enum": ["cancellation", "tombstone"],
316
+ }}},
317
+ "then": {"properties": {
318
+ "commercial_contract_binding": {"type": "null"},
319
+ }},
320
+ },
321
+ ],
322
+ "x-invariants": [
323
+ "attempts_lte_client_max_attempts", "leased_iff_lease_expires_at",
324
+ "accepted_iff_remote_website_binding_complete_and_valid",
325
+ "accepted_commercial_contract_matches_remote_registry",
326
+ ],
327
+ "description": "Content-free durable submission state; accepted is not publication.",
328
+ }
329
+
330
+
331
+ def _read_request_schema(schema: str) -> dict[str, Any]:
332
+ return _closed_object({
333
+ "schema": {"const": schema},
334
+ "operation": {
335
+ "type": "string", "enum": ["change", "cancellation", "tombstone"],
336
+ },
337
+ "request_id": _schema_ref("Token"),
338
+ "event_id": _schema_ref("Token"),
339
+ "site_id": _schema_ref("Token"),
340
+ "payload_sha256": _schema_ref("Sha256"),
341
+ })
342
+
343
+
344
+ def _downstream_submission_status_schema() -> dict[str, Any]:
345
+ nullable_count = {
346
+ "oneOf": [
347
+ {"type": "integer", "minimum": 0, "maximum": 20},
348
+ {"type": "null"},
349
+ ],
350
+ }
351
+ return _closed_object({
352
+ "schema": {"const": "blun.cms-source-delivery-submission-status.v2"},
353
+ "operation": {
354
+ "type": "string", "enum": ["change", "cancellation", "tombstone"],
355
+ },
356
+ "request_id": _schema_ref("Token"), "event_id": _schema_ref("Token"),
357
+ "site_id": _schema_ref("Token"), "payload_sha256": _schema_ref("Sha256"),
358
+ "status": {"type": "string", "enum": ["accepted", "failed", "pending"]},
359
+ "stage": {"type": "string", "enum": [
360
+ "website_acceptance", "sidecar_delivery", "source_acceptance",
361
+ ]},
362
+ "website_status": {"type": "string", "enum": [
363
+ "failed", "leased", "pending", "retry_wait", "succeeded",
364
+ ]},
365
+ "website_attempts": {"type": "integer", "minimum": 0, "maximum": 20},
366
+ "website_delivery_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
367
+ "sidecar_status": {"type": ["string", "null"], "enum": [
368
+ None, "failed", "leased", "pending", "retry_wait", "succeeded",
369
+ ]},
370
+ "sidecar_attempts": nullable_count,
371
+ "sidecar_delivery_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
372
+ "source_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
373
+ "next_attempt_at": {"type": "number", "minimum": 0},
374
+ "lease_expired": {"type": "boolean"},
375
+ "error_code": {"oneOf": [_schema_ref("ErrorCode"), {"type": "null"}]},
376
+ "website_capability_binding": _schema_ref("WebsiteCapabilityBinding"),
377
+ })
378
+
379
+
380
+ def _source_capability_binding_schema() -> dict[str, Any]:
381
+ return _closed_object({
382
+ "schema": {"const": "blun.cms-source-capability-binding.v2"},
383
+ "status": {"const": "verified"},
384
+ "capabilities_sha256": _schema_ref("Sha256"),
385
+ "commercial_rendering_registry_sha256": _schema_ref("Sha256"),
386
+ "database_roles": {
387
+ "type": "array",
388
+ "prefixItems": [
389
+ {"const": "changes"}, {"const": "removals"},
390
+ {"const": "lifecycle"},
391
+ ],
392
+ "items": False, "minItems": 3, "maxItems": 3,
393
+ },
394
+ })
395
+
396
+
397
+ def _source_status_schema() -> dict[str, Any]:
398
+ nullable_token = {"oneOf": [_schema_ref("Token"), {"type": "null"}]}
399
+ nullable_sha = {"oneOf": [_schema_ref("Sha256"), {"type": "null"}]}
400
+ nullable_error = {"oneOf": [_schema_ref("ErrorCode"), {"type": "null"}]}
401
+ nullable_retry_count = {"oneOf": [
402
+ {"type": "integer", "minimum": 0, "maximum": 20}, {"type": "null"},
403
+ ]}
404
+ nullable_count = {"oneOf": [
405
+ {"type": "integer", "minimum": 0, "maximum": 1_000_000},
406
+ {"type": "null"},
407
+ ]}
408
+ locale_array = {
409
+ "type": "array", "items": _schema_ref("Token"),
410
+ "maxItems": 24, "uniqueItems": True,
411
+ }
412
+ queue_properties = {
413
+ name: {"type": "integer", "minimum": 0, "maximum": 1_000_000}
414
+ for name in ("cancelled", "failed", "leased", "pending", "retry_wait", "succeeded")
415
+ }
416
+ def queue_count_shape(names: tuple[str, ...]) -> dict[str, Any]:
417
+ return _closed_object({name: queue_properties[name] for name in names})
418
+
419
+ active_queue_states = (
420
+ "failed", "leased", "pending", "retry_wait", "succeeded",
421
+ )
422
+ queue_counts = {"oneOf": [
423
+ _closed_object({}),
424
+ queue_count_shape(active_queue_states),
425
+ queue_count_shape(("cancelled",) + active_queue_states),
426
+ ]}
427
+ return _closed_object({
428
+ "schema": {"const": "blun.cms-source-service-status.v4"},
429
+ "event_id": _schema_ref("Token"), "site_id": _schema_ref("Token"),
430
+ "website_version": _schema_ref("Token"),
431
+ "source_sequence": {
432
+ "type": "integer", "minimum": 1, "maximum": 1_000_000,
433
+ },
434
+ "change_sha256": _schema_ref("Sha256"),
435
+ "dispatch_status": {"type": "string", "enum": [
436
+ "failed", "leased", "pending", "retry_wait", "succeeded",
437
+ ]},
438
+ "dispatch_attempts": {"type": "integer", "minimum": 0, "maximum": 20},
439
+ "dispatch_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
440
+ "dispatch_error_code": nullable_error,
441
+ "plan_id": nullable_token, "job_count": nullable_count,
442
+ "lifecycle_state": {"type": ["string", "null"], "enum": [
443
+ None, "failed", "leased", "pending", "retry_wait", "terminal", "watching",
444
+ ]},
445
+ "lifecycle_poll_attempts": {"type": "integer", "minimum": 0, "maximum": 20},
446
+ "lifecycle_error_code": nullable_error,
447
+ "remote_status": {"type": ["string", "null"], "enum": [
448
+ None, "awaiting_approval", "cancelled", "deleted", "deleting",
449
+ "deletion_failed", "localization_failed", "processing",
450
+ "publication_blocked", "publication_failed", "published",
451
+ "publishing", "queue_recovery", "ready", "superseded",
452
+ ]},
453
+ "lifecycle_sha256": nullable_sha,
454
+ "required_locales": locale_array, "approved_locales": locale_array,
455
+ "blocked_locales": {
456
+ "type": "array", "maxItems": 24, "items": {
457
+ "type": "array", "prefixItems": [
458
+ _schema_ref("Token"), _schema_ref("ErrorCode"),
459
+ ], "items": False, "minItems": 2, "maxItems": 2,
460
+ },
461
+ },
462
+ "queue_counts": queue_counts,
463
+ "notification_state": {"type": "string", "enum": [
464
+ "awaiting_registration", "awaiting_terminal", "disabled", "failed",
465
+ "leased", "pending", "retry_wait", "succeeded",
466
+ ]},
467
+ "notification_id": nullable_token, "notification_sha256": nullable_sha,
468
+ "notification_attempts": {"type": "integer", "minimum": 0, "maximum": 20},
469
+ "notification_max_attempts": nullable_retry_count,
470
+ "notification_error_code": nullable_error,
471
+ "terminal_receiver_capabilities_sha256": nullable_sha,
472
+ "terminal_processing_state": {"type": "string", "enum": [
473
+ "awaiting_notification", "awaiting_registration", "disabled", "failed",
474
+ "leased", "pending", "retry_wait", "succeeded", "watching",
475
+ ]},
476
+ "terminal_processing_poll_attempts": {
477
+ "type": "integer", "minimum": 0, "maximum": 1_000_000,
478
+ },
479
+ "terminal_processing_failures": {"type": "integer", "minimum": 0, "maximum": 20},
480
+ "terminal_processing_error_code": nullable_error,
481
+ "receiver_processing_state": {"type": ["string", "null"], "enum": [
482
+ None, "failed", "leased", "pending", "retry_wait", "succeeded",
483
+ ]},
484
+ "receiver_processing_attempts": nullable_retry_count,
485
+ "receiver_processing_max_attempts": nullable_retry_count,
486
+ "receiver_processing_error_code": nullable_error,
487
+ "receiver_processed_at": {
488
+ "oneOf": [{"type": "number", "minimum": 0}, {"type": "null"}],
489
+ },
490
+ })
491
+
492
+
493
+ def _source_lifecycle_schema() -> dict[str, Any]:
494
+ remote_statuses = [
495
+ "awaiting_approval", "cancelled", "deleted", "deleting",
496
+ "deletion_failed", "localization_failed", "processing",
497
+ "publication_blocked", "publication_failed", "published", "publishing",
498
+ "queue_recovery", "ready", "superseded",
499
+ ]
500
+ result = _closed_object({
501
+ "schema": {"const": "blun.cms-source-delivery-submission-lifecycle.v4"},
502
+ "status": {"type": "string", "enum": [
503
+ "accepted", "failed", "pending", *remote_statuses,
504
+ ]},
505
+ "stage": {"type": "string", "enum": [
506
+ "website_acceptance", "sidecar_delivery", "source_acceptance",
507
+ "source_processing", "localization_lifecycle",
508
+ ]},
509
+ "submission": _schema_ref("DownstreamSubmissionStatus"),
510
+ "source_status": {
511
+ "oneOf": [_schema_ref("SourceServiceStatus"), {"type": "null"}],
512
+ },
513
+ "source_capability_binding": {
514
+ "oneOf": [_schema_ref("SourceCapabilityBinding"), {"type": "null"}],
515
+ },
516
+ "website_capability_binding": _schema_ref("WebsiteCapabilityBinding"),
517
+ "sidecar_capabilities_sha256": _schema_ref("Sha256"),
518
+ "source_capabilities_sha256": _schema_ref("Sha256"),
519
+ })
520
+ return _closed_object({
521
+ "schema": {"const": "blun.cms-source-delivery-submission-lifecycle-response.v1"},
522
+ "api_schema": {"const": "blun.cms-source-delivery-submission-http.v3"},
523
+ "result": result,
524
+ "accepted_implies_publication": {"const": False},
525
+ })
526
+
527
+
528
+ def build_document(capabilities: Mapping[str, Any]) -> dict[str, Any]:
529
+ """Build one origin-free document from an already verified capability."""
530
+ operations = capabilities["operations"]
531
+ all_error_codes = sorted({
532
+ code
533
+ for operation in operations.values()
534
+ for codes in operation["error_codes"].values()
535
+ for code in codes
536
+ })
537
+ path_specs = {
538
+ operations["capabilities"]["path"]: {
539
+ "get": _operation(
540
+ operations["capabilities"], operation_id="discoverCapabilities",
541
+ tag="Discovery", summary="Discover the exact active sidecar contract",
542
+ request_schema=None, response_component="CapabilitiesResponse",
543
+ ),
544
+ },
545
+ operations["commercial_profile"]["path"]: {
546
+ "get": _operation(
547
+ operations["commercial_profile"],
548
+ operation_id="readCommercialLocalizationProfile",
549
+ tag="Commercial localization",
550
+ summary="Read the live-bound brand-neutral price and offer profile",
551
+ request_schema=None,
552
+ response_component="CommercialProfileResponse",
553
+ ),
554
+ },
555
+ operations["enqueue"]["path"]: {
556
+ "post": _operation(
557
+ operations["enqueue"], operation_id="enqueueSubmission",
558
+ tag="Tenant submissions",
559
+ summary="Durably enqueue one change, cancellation, or tombstone",
560
+ request_schema="EnqueueRequest", response_component="QueueResponse",
561
+ headers=True,
562
+ ),
563
+ },
564
+ operations["health"]["path"]: {
565
+ "get": _operation(
566
+ operations["health"], operation_id="readHealth",
567
+ tag="Operations", summary="Read durable outbox health",
568
+ request_schema=None, response_component="HealthResponse",
569
+ degraded_response_component="HealthResponse",
570
+ ),
571
+ },
572
+ operations["lifecycle"]["path"]: {
573
+ "post": _operation(
574
+ operations["lifecycle"], operation_id="readSubmissionLifecycle",
575
+ tag="Tenant submissions",
576
+ summary="Read verified downstream localization lifecycle",
577
+ request_schema="LifecycleRequest",
578
+ response_component="LifecycleResponse",
579
+ ),
580
+ },
581
+ operations["openapi"]["path"]: {
582
+ "get": _operation(
583
+ operations["openapi"], operation_id="readOpenApi",
584
+ tag="Discovery", summary="Read this capability-bound OpenAPI profile",
585
+ request_schema=None, response_component="OpenApiResponse",
586
+ ),
587
+ },
588
+ operations["readiness"]["path"]: {
589
+ "get": _operation(
590
+ operations["readiness"], operation_id="readReadiness",
591
+ tag="Operations", summary="Read supervised worker readiness",
592
+ request_schema=None, response_component="ReadinessResponse",
593
+ degraded_response_component="ReadinessResponse",
594
+ ),
595
+ },
596
+ operations["status"]["path"]: {
597
+ "post": _operation(
598
+ operations["status"], operation_id="readSubmissionStatus",
599
+ tag="Tenant submissions", summary="Read one fully identified submission",
600
+ request_schema="StatusRequest", response_component="StatusResponse",
601
+ ),
602
+ },
603
+ }
604
+ envelope = lambda schema, key, reference: {
605
+ "type": "object", "additionalProperties": False,
606
+ "required": ["schema", key, "capabilities_sha256"],
607
+ "properties": {
608
+ "schema": {"const": schema}, key: reference,
609
+ "capabilities_sha256": {"const": capabilities["sha256"]},
610
+ },
611
+ }
612
+ status_envelope = lambda schema: {
613
+ "type": "object", "additionalProperties": False,
614
+ "required": [
615
+ "schema", "api_schema", "status", "capabilities_sha256",
616
+ "accepted_implies_publication",
617
+ ],
618
+ "properties": {
619
+ "schema": {"const": schema},
620
+ "api_schema": {"const": capabilities["api_schema"]},
621
+ "status": _schema_ref("SubmissionStatus"),
622
+ "capabilities_sha256": {"const": capabilities["sha256"]},
623
+ "accepted_implies_publication": {"const": False},
624
+ },
625
+ }
626
+ count_map = {
627
+ "type": "object", "additionalProperties": False,
628
+ "required": ["accepted", "failed", "leased", "pending", "retry_wait"],
629
+ "properties": {
630
+ name: {"type": "integer", "minimum": 0, "maximum": 1_000_000}
631
+ for name in ("accepted", "failed", "leased", "pending", "retry_wait")
632
+ },
633
+ }
634
+ operation_map = {
635
+ "type": "object", "additionalProperties": False,
636
+ "required": ["cancellation", "change", "tombstone"],
637
+ "properties": {
638
+ name: {"type": "integer", "minimum": 0, "maximum": 1_000_000}
639
+ for name in ("cancellation", "change", "tombstone")
640
+ },
641
+ }
642
+ schemas = {
643
+ "Sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
644
+ "Token": {"type": "string", "pattern": "^[A-Za-z0-9_.:-]{1,256}$"},
645
+ "ErrorCode": {"type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,127}$"},
646
+ "WebsiteCapabilityBinding": _closed_object({
647
+ "schema": {
648
+ "const": "blun.cms-source-delivery-runtime-capability-binding.v2",
649
+ },
650
+ "status": {"const": "verified"},
651
+ "database_role": {"const": "source_delivery"},
652
+ "delivery_capabilities_sha256": _schema_ref("Sha256"),
653
+ "runtime_capabilities_sha256": _schema_ref("Sha256"),
654
+ "commercial_rendering_registry_sha256": _schema_ref("Sha256"),
655
+ "terminal_receiver_capabilities_sha256": _schema_ref("Sha256"),
656
+ "binding_sha256": _schema_ref("Sha256"),
657
+ }),
658
+ "Error": {
659
+ "type": "object", "additionalProperties": False,
660
+ "required": ["schema", "status", "error_code"],
661
+ "properties": {
662
+ "schema": {"const": "blun.cms-public-submission-dispatch-http-error.v1"},
663
+ "status": {"const": "BLOCK"},
664
+ "error_code": {"type": "string", "enum": all_error_codes},
665
+ },
666
+ },
667
+ "Capabilities": {
668
+ **_exact_schema(capabilities),
669
+ "description": (
670
+ "The complete immutable capability generation. Every nested "
671
+ "field is closed and fixed to this document's active pins."
672
+ ),
673
+ "x-capabilities-sha256": capabilities["sha256"],
674
+ },
675
+ "CommercialProfile": _exact_schema(
676
+ capabilities["commercial_profile"]
677
+ ),
678
+ "CommercialRenderingRegistry": _exact_schema(
679
+ capabilities["commercial_rendering_registry"]
680
+ ),
681
+ "CommercialContractBinding": _exact_schema(
682
+ capabilities["commercial_contract_binding"]
683
+ ),
684
+ "CommercialProfileResponse": _closed_object({
685
+ "schema": {
686
+ "const": operations["commercial_profile"]["response_schema"],
687
+ },
688
+ "api_schema": {"const": capabilities["api_schema"]},
689
+ "commercial_profile": _schema_ref("CommercialProfile"),
690
+ "commercial_rendering_registry": _schema_ref(
691
+ "CommercialRenderingRegistry"
692
+ ),
693
+ "website_capability_binding": _schema_ref(
694
+ "WebsiteCapabilityBinding"
695
+ ),
696
+ "capabilities_sha256": {"const": capabilities["sha256"]},
697
+ "content_free": {"const": True},
698
+ "publication_authority": {"const": False},
699
+ }),
700
+ **_source_payload_schemas(capabilities),
701
+ "EnqueueRequest": {
702
+ "type": "object", "additionalProperties": False,
703
+ "required": [
704
+ "schema", "payload", "source_max_attempts",
705
+ "delivery_max_attempts", "client_max_attempts",
706
+ "commercial_contract_binding",
707
+ ],
708
+ "properties": {
709
+ "schema": {"const": operations["enqueue"]["request_schema"]},
710
+ "payload": _schema_ref("SourcePayload"),
711
+ "source_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
712
+ "delivery_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
713
+ "client_max_attempts": {"type": "integer", "minimum": 1, "maximum": 20},
714
+ "commercial_contract_binding": {
715
+ "oneOf": [
716
+ _schema_ref("CommercialContractBinding"),
717
+ {"type": "null"},
718
+ ],
719
+ "description": (
720
+ "Exact current binding for commercial changes; null "
721
+ "for every other content type and removal operation."
722
+ ),
723
+ },
724
+ },
725
+ "allOf": [{
726
+ "if": {
727
+ "properties": {
728
+ "payload": {
729
+ "type": "object",
730
+ "required": ["schema", "localization"],
731
+ "properties": {
732
+ "schema": {"const": capabilities[
733
+ "source_payload_schemas"
734
+ ]["change"]},
735
+ "localization": {
736
+ "type": "object",
737
+ "required": ["content_type"],
738
+ "properties": {
739
+ "content_type": {"const": "commercial"},
740
+ },
741
+ },
742
+ },
743
+ },
744
+ },
745
+ },
746
+ "then": {
747
+ "properties": {
748
+ "commercial_contract_binding": _schema_ref(
749
+ "CommercialContractBinding"
750
+ ),
751
+ },
752
+ },
753
+ "else": {
754
+ "properties": {
755
+ "commercial_contract_binding": {"type": "null"},
756
+ },
757
+ },
758
+ }],
759
+ },
760
+ "StatusRequest": _read_request_schema(
761
+ operations["status"]["request_schema"]
762
+ ),
763
+ "LifecycleRequest": _read_request_schema(
764
+ operations["lifecycle"]["request_schema"]
765
+ ),
766
+ "SubmissionStatus": _status_schema(),
767
+ "DownstreamSubmissionStatus": _downstream_submission_status_schema(),
768
+ "SourceCapabilityBinding": _source_capability_binding_schema(),
769
+ "SourceServiceStatus": _source_status_schema(),
770
+ "SourceLifecycle": _source_lifecycle_schema(),
771
+ "QueueResponse": status_envelope(operations["enqueue"]["response_schema"]),
772
+ "StatusResponse": status_envelope(operations["status"]["response_schema"]),
773
+ "LifecycleResponse": _closed_object({
774
+ "schema": {"const": operations["lifecycle"]["response_schema"]},
775
+ "api_schema": {"const": capabilities["api_schema"]},
776
+ "lifecycle": _closed_object({
777
+ "dispatch_status": _schema_ref("SubmissionStatus"),
778
+ "source_lifecycle": _schema_ref("SourceLifecycle"),
779
+ }),
780
+ "capabilities_sha256": {"const": capabilities["sha256"]},
781
+ "accepted_implies_publication": {"const": False},
782
+ }),
783
+ "Health": {
784
+ "type": "object", "additionalProperties": False,
785
+ "required": ["status", "counts", "operations", "due", "expired_leases", "failed", "expected_capabilities_sha256"],
786
+ "properties": {
787
+ "status": {"type": "string", "enum": ["blocked", "ok"]},
788
+ "counts": count_map, "operations": operation_map,
789
+ "due": {"type": "integer", "minimum": 0, "maximum": 1_000_000},
790
+ "expired_leases": {"type": "integer", "minimum": 0, "maximum": 1_000_000},
791
+ "failed": {"type": "integer", "minimum": 0, "maximum": 1_000_000},
792
+ "expected_capabilities_sha256": {"const": capabilities["public_submission_capabilities_sha256"]},
793
+ },
794
+ "allOf": [{
795
+ "if": {"properties": {"status": {"const": "ok"}}},
796
+ "then": {"properties": {
797
+ "expired_leases": {"const": 0}, "failed": {"const": 0},
798
+ }},
799
+ "else": {"anyOf": [
800
+ {"properties": {"expired_leases": {"minimum": 1}}},
801
+ {"properties": {"failed": {"minimum": 1}}},
802
+ ]},
803
+ }],
804
+ "x-invariants": list(operations["health"]["response_invariants"]),
805
+ },
806
+ "HealthResponse": envelope(
807
+ operations["health"]["response_schema"], "health", _schema_ref("Health")
808
+ ),
809
+ "Readiness": {
810
+ "type": "object", "additionalProperties": False,
811
+ "required": ["schema", "status", "worker_state", "outbox_status", "error_code", "capabilities_sha256"],
812
+ "properties": {
813
+ "schema": {"const": "blun.cms-public-submission-worker-readiness.v1"},
814
+ "status": {"type": "string", "enum": ["not_ready", "ready"]},
815
+ "worker_state": {"type": "string", "enum": ["closed", "failed", "running", "stopped", "stopping", "unmanaged"]},
816
+ "outbox_status": {"type": ["string", "null"], "enum": [None, "blocked", "ok"]},
817
+ "error_code": {"oneOf": [_schema_ref("ErrorCode"), {"type": "null"}]},
818
+ "capabilities_sha256": {"const": capabilities["public_submission_capabilities_sha256"]},
819
+ },
820
+ "oneOf": [
821
+ {"properties": {
822
+ "status": {"const": "ready"},
823
+ "worker_state": {"const": "running"},
824
+ "outbox_status": {"const": "ok"},
825
+ "error_code": {"type": "null"},
826
+ }},
827
+ {"properties": {
828
+ "status": {"const": "not_ready"},
829
+ "error_code": _schema_ref("ErrorCode"),
830
+ }},
831
+ ],
832
+ "x-invariants": list(operations["readiness"]["response_invariants"]),
833
+ },
834
+ "ReadinessResponse": envelope(
835
+ operations["readiness"]["response_schema"], "readiness", _schema_ref("Readiness")
836
+ ),
837
+ "CapabilitiesResponse": {
838
+ "type": "object", "additionalProperties": False,
839
+ "required": ["schema", "capabilities"],
840
+ "properties": {
841
+ "schema": {"const": operations["capabilities"]["response_schema"]},
842
+ "capabilities": _schema_ref("Capabilities"),
843
+ },
844
+ },
845
+ "OpenApiResponse": {
846
+ "type": "object", "additionalProperties": False,
847
+ "required": ["schema", "openapi", "openapi_sha256", "capabilities_sha256"],
848
+ "properties": {
849
+ "schema": {"const": RESPONSE_SCHEMA},
850
+ "openapi": {"type": "object"},
851
+ "openapi_sha256": _schema_ref("Sha256"),
852
+ "capabilities_sha256": {"const": capabilities["sha256"]},
853
+ },
854
+ },
855
+ }
856
+ return {
857
+ "openapi": "3.1.0",
858
+ "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
859
+ "info": {
860
+ "title": "CMS Public Submission Sidecar API",
861
+ "version": capabilities["api_schema"],
862
+ "description": (
863
+ "Provider-neutral, fail-closed transport for durable website "
864
+ "localization submissions. Acceptance never implies publication."
865
+ ),
866
+ },
867
+ "tags": [
868
+ {"name": "Discovery"}, {"name": "Commercial localization"},
869
+ {"name": "Tenant submissions"},
870
+ {"name": "Operations"},
871
+ ],
872
+ "paths": dict(sorted(path_specs.items())),
873
+ "components": {
874
+ "securitySchemes": {
875
+ "hostAuthentication": {
876
+ "type": "apiKey", "in": "header", "name": "Authorization",
877
+ "description": (
878
+ "Deployment-owned credential placeholder. The host may require "
879
+ "additional signed headers and exact body-hash binding."
880
+ ),
881
+ "x-host-defined": True,
882
+ },
883
+ },
884
+ "schemas": schemas,
885
+ },
886
+ "x-schema": DOCUMENT_SCHEMA,
887
+ "x-capabilities-sha256": capabilities["sha256"],
888
+ "x-downstream-capabilities-sha256": capabilities["public_submission_capabilities_sha256"],
889
+ "x-retry-ownership": capabilities["retry_ownership"],
890
+ "x-fail-closed-semantics": capabilities["semantics"],
891
+ "x-servers-omitted-intentionally": True,
892
+ }
893
+
894
+
895
+ def document_sha256(document: Mapping[str, Any]) -> str:
896
+ return hashlib.sha256(_canonical(dict(document))).hexdigest()