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.
- package/CHANGELOG.md +39 -0
- package/README.md +17 -1
- package/agent-spine-plugin/CHANGELOG.md +1 -1
- package/agent-spine-plugin/docs/host-integration.md +1 -15
- package/agent-spine-plugin/docs/preflight-recall.md +1 -1
- package/agent-spine-plugin/scripts/check-install.js +1 -6
- package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
- package/agent-spine-plugin/scripts/release-check.js +2 -3
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
- package/agent-spine-plugin/src/hook.js +40 -40
- package/agent-spine-plugin/src/lib/briefing.js +6 -3
- package/agent-spine-plugin/src/lib/hook-context.js +63 -64
- package/agent-spine-plugin/src/lib/hook-output.js +115 -94
- package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
- package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
- package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
- package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
- package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
- package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
- package/agent-spine-plugin/src/lib/source-roots.js +26 -16
- package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
- package/bin/core-bootstrap.js +18 -10
- package/bin/launcher-mode.js +5 -0
- package/bin/launcher-runtime.js +27 -0
- package/bin/verify-bundled-agent-sources.cjs +28 -2
- package/blun.mjs +798 -143
- package/bundled-agent-sources.json +192 -155
- package/package.json +1 -1
- package/standard-skills/translate-native/README.md +1334 -1
- package/standard-skills/translate-native/SKILL.md +1 -1
- package/standard-skills/translate-native/VERSION +1 -1
- package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
- package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
- package/standard-skills/translate-native/integrations/website_localization.py +234 -10
- package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
- package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
- package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
- package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
- package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
- package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
- package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
- package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
- package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
- package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
- package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
- package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
- package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
- package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
- package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
- package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
- package/standard-skills/translate-native/provenance.json +2 -2
- package/standard-skills/translate-native/references/commercial-localization.md +96 -17
- package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
- package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
- package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/VERSION +1 -1
- package/standard-tools/language-guard/blun_language_guard.py +3 -1
- package/standard-tools/language-guard/check_commercial_review.py +69 -9
- package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/provenance.json +2 -2
- package/standard-tools/manifest.json +1 -1
- package/worker-host.mjs +215 -82
- package/agent-spine-plugin/scripts/check-install-king.js +0 -37
|
@@ -21,15 +21,30 @@ from typing import Any, Iterator, Protocol
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
SCHEMA_VERSION = 1
|
|
24
|
-
APPROVAL_SCHEMA = "blun.website-localization-approval.
|
|
25
|
-
RECEIPT_BINDING_SCHEMA = "blun.localization-quality-receipt-binding.
|
|
24
|
+
APPROVAL_SCHEMA = "blun.website-localization-approval.v10"
|
|
25
|
+
RECEIPT_BINDING_SCHEMA = "blun.localization-quality-receipt-binding.v9"
|
|
26
26
|
INDEPENDENT_MODEL_REVIEW_SCHEMA = "blun.independent-model-review.v1"
|
|
27
|
-
PUBLICATION_EVIDENCE_SCHEMA = "blun.website-localization-release-evidence.
|
|
27
|
+
PUBLICATION_EVIDENCE_SCHEMA = "blun.website-localization-release-evidence.v14"
|
|
28
|
+
PUBLICATION_EVIDENCE_CAPABILITIES_SCHEMA = (
|
|
29
|
+
"blun.website-localization-release-evidence-capabilities.v8"
|
|
30
|
+
)
|
|
31
|
+
PUBLICATION_EVIDENCE_FIELDS = (
|
|
32
|
+
"schema", "release_evidence_contract_sha256", "job_id", "target_locale",
|
|
33
|
+
"target_sha256", "approval_id",
|
|
34
|
+
"content_type", "result_sha256", "approval_sha256",
|
|
35
|
+
"quality_receipt_sha256", "evidence_request_id", "evidence_revision",
|
|
36
|
+
"quality_profile",
|
|
37
|
+
"commercial_profile", "commercial_quality_profile", "commercial_review",
|
|
38
|
+
"commercial_review_routing_contract_sha256",
|
|
39
|
+
"commercial_review_resolution_contract_sha256",
|
|
40
|
+
"commercial_review_resolution",
|
|
41
|
+
)
|
|
28
42
|
MAX_TEXT_BYTES = 2_000_000
|
|
29
43
|
MAX_RECEIPT_LENGTH = 16_384
|
|
30
44
|
MAX_TTL_SECONDS = 31_536_000.0
|
|
31
45
|
HEX64 = re.compile(r"^[0-9a-f]{64}$")
|
|
32
46
|
TOKEN = re.compile(r"^[A-Za-z0-9_.:-]{1,256}$")
|
|
47
|
+
EVIDENCE_REQUEST_ID = re.compile(r"^blun-l10n-evidence-[0-9a-f]{64}$")
|
|
33
48
|
_COLUMNS = (
|
|
34
49
|
"approval_id", "job_id", "target_locale", "target_sha256",
|
|
35
50
|
"result_json", "result_sha256", "approval_json", "approval_sha256",
|
|
@@ -56,6 +71,9 @@ _WORKER = _load_module(
|
|
|
56
71
|
"blun_website_localization_release_worker",
|
|
57
72
|
_ROOT / "integrations" / "website_localization_worker.py",
|
|
58
73
|
)
|
|
74
|
+
COMMERCIAL_REVIEW_RESOLUTION_SCHEMA = (
|
|
75
|
+
_WORKER._COMMERCIAL.REVIEW_RESOLUTION_SCHEMA
|
|
76
|
+
)
|
|
59
77
|
|
|
60
78
|
|
|
61
79
|
class LocalizationReleaseBlocked(RuntimeError):
|
|
@@ -122,17 +140,23 @@ class WebsiteReadiness:
|
|
|
122
140
|
blocked: tuple[tuple[str, str], ...]
|
|
123
141
|
|
|
124
142
|
|
|
125
|
-
def validate_publication_evidence(
|
|
143
|
+
def validate_publication_evidence(
|
|
144
|
+
value: Any,
|
|
145
|
+
*,
|
|
146
|
+
require_current_locale_quality: bool = True,
|
|
147
|
+
) -> dict[str, Any]:
|
|
126
148
|
"""Validate the content-free release proof carried to a CMS."""
|
|
127
149
|
|
|
128
|
-
if
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
if (
|
|
151
|
+
not isinstance(require_current_locale_quality, bool)
|
|
152
|
+
or not isinstance(value, dict)
|
|
153
|
+
or set(value) != set(PUBLICATION_EVIDENCE_FIELDS)
|
|
154
|
+
):
|
|
133
155
|
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
134
156
|
if (
|
|
135
157
|
value.get("schema") != PUBLICATION_EVIDENCE_SCHEMA
|
|
158
|
+
or value.get("release_evidence_contract_sha256")
|
|
159
|
+
!= publication_evidence_contract()["sha256"]
|
|
136
160
|
or any(
|
|
137
161
|
not isinstance(value.get(field), str)
|
|
138
162
|
or TOKEN.fullmatch(value[field]) is None
|
|
@@ -145,18 +169,111 @@ def validate_publication_evidence(value: Any) -> dict[str, Any]:
|
|
|
145
169
|
"quality_receipt_sha256",
|
|
146
170
|
)
|
|
147
171
|
)
|
|
172
|
+
or not isinstance(value.get("evidence_request_id"), str)
|
|
173
|
+
or EVIDENCE_REQUEST_ID.fullmatch(value["evidence_request_id"]) is None
|
|
174
|
+
or not isinstance(value.get("evidence_revision"), str)
|
|
175
|
+
or TOKEN.fullmatch(value["evidence_revision"]) is None
|
|
148
176
|
):
|
|
149
177
|
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
178
|
+
quality_profile = value.get("quality_profile")
|
|
179
|
+
if (
|
|
180
|
+
not isinstance(quality_profile, dict)
|
|
181
|
+
or set(quality_profile) != {"locale", "version", "sha256"}
|
|
182
|
+
or quality_profile.get("locale") != value["target_locale"]
|
|
183
|
+
or not isinstance(quality_profile.get("version"), str)
|
|
184
|
+
or TOKEN.fullmatch(quality_profile["version"]) is None
|
|
185
|
+
or HEX64.fullmatch(str(quality_profile.get("sha256"))) is None
|
|
186
|
+
):
|
|
187
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
188
|
+
if require_current_locale_quality:
|
|
189
|
+
try:
|
|
190
|
+
current_quality = _WORKER._PLANNER.quality_profile_for(
|
|
191
|
+
value["target_locale"],
|
|
192
|
+
)
|
|
193
|
+
expected_quality_profile = {
|
|
194
|
+
"locale": current_quality["locale"],
|
|
195
|
+
"version": current_quality["version"],
|
|
196
|
+
"sha256": current_quality["sha256"],
|
|
197
|
+
}
|
|
198
|
+
except Exception:
|
|
199
|
+
raise LocalizationReleaseBlocked(
|
|
200
|
+
"publication.evidence.invalid"
|
|
201
|
+
) from None
|
|
202
|
+
if quality_profile != expected_quality_profile:
|
|
203
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
150
204
|
profile = value.get("commercial_profile")
|
|
205
|
+
commercial_quality_profile = value.get("commercial_quality_profile")
|
|
151
206
|
review = value.get("commercial_review")
|
|
207
|
+
routing_contract_sha256 = value.get(
|
|
208
|
+
"commercial_review_routing_contract_sha256"
|
|
209
|
+
)
|
|
210
|
+
resolution_contract_sha256 = value.get(
|
|
211
|
+
"commercial_review_resolution_contract_sha256"
|
|
212
|
+
)
|
|
213
|
+
resolution = value.get("commercial_review_resolution")
|
|
152
214
|
if (
|
|
153
|
-
(
|
|
215
|
+
len({
|
|
216
|
+
profile is None,
|
|
217
|
+
commercial_quality_profile is None,
|
|
218
|
+
review is None,
|
|
219
|
+
}) != 1
|
|
220
|
+
or (profile is None) != (routing_contract_sha256 is None)
|
|
221
|
+
or (profile is None) != (resolution_contract_sha256 is None)
|
|
154
222
|
or (value["content_type"] == "commercial") != (profile is not None)
|
|
155
223
|
):
|
|
156
224
|
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
157
225
|
if profile is not None:
|
|
158
226
|
if not isinstance(profile, str) or TOKEN.fullmatch(profile) is None:
|
|
159
227
|
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
228
|
+
expected_commercial_quality = None
|
|
229
|
+
if require_current_locale_quality:
|
|
230
|
+
try:
|
|
231
|
+
current_commercial_quality = (
|
|
232
|
+
_WORKER._PLANNER.commercial_quality_profile_for(
|
|
233
|
+
value["target_locale"],
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
expected_commercial_quality = {
|
|
237
|
+
"profile": current_commercial_quality[
|
|
238
|
+
"commercial_profile"
|
|
239
|
+
],
|
|
240
|
+
"version": current_commercial_quality["version"],
|
|
241
|
+
"sha256": current_commercial_quality["sha256"],
|
|
242
|
+
}
|
|
243
|
+
except Exception:
|
|
244
|
+
raise LocalizationReleaseBlocked(
|
|
245
|
+
"publication.evidence.invalid"
|
|
246
|
+
) from None
|
|
247
|
+
if (
|
|
248
|
+
profile != _WORKER._PLANNER.COMMERCIAL_PROFILE
|
|
249
|
+
or (
|
|
250
|
+
require_current_locale_quality
|
|
251
|
+
and commercial_quality_profile != expected_commercial_quality
|
|
252
|
+
)
|
|
253
|
+
or HEX64.fullmatch(str(routing_contract_sha256)) is None
|
|
254
|
+
or routing_contract_sha256
|
|
255
|
+
!= _WORKER._COMMERCIAL.public_review_routing_contract(profile)[
|
|
256
|
+
"sha256"
|
|
257
|
+
]
|
|
258
|
+
or HEX64.fullmatch(str(resolution_contract_sha256)) is None
|
|
259
|
+
or resolution_contract_sha256
|
|
260
|
+
!= _WORKER._COMMERCIAL.public_review_resolution_contract(profile)[
|
|
261
|
+
"sha256"
|
|
262
|
+
]
|
|
263
|
+
):
|
|
264
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
265
|
+
if (
|
|
266
|
+
not isinstance(commercial_quality_profile, dict)
|
|
267
|
+
or set(commercial_quality_profile)
|
|
268
|
+
!= {"profile", "version", "sha256"}
|
|
269
|
+
or commercial_quality_profile.get("profile") != profile
|
|
270
|
+
or not isinstance(commercial_quality_profile.get("version"), str)
|
|
271
|
+
or TOKEN.fullmatch(commercial_quality_profile["version"]) is None
|
|
272
|
+
or HEX64.fullmatch(
|
|
273
|
+
str(commercial_quality_profile.get("sha256"))
|
|
274
|
+
) is None
|
|
275
|
+
):
|
|
276
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
160
277
|
try:
|
|
161
278
|
review = _WORKER._COMMERCIAL.validate_summary(
|
|
162
279
|
review,
|
|
@@ -168,7 +285,64 @@ def validate_publication_evidence(value: Any) -> dict[str, Any]:
|
|
|
168
285
|
)
|
|
169
286
|
except _WORKER._COMMERCIAL.CommercialReviewBlocked:
|
|
170
287
|
raise LocalizationReleaseBlocked("publication.evidence.invalid") from None
|
|
171
|
-
|
|
288
|
+
if review["status"] == "verified":
|
|
289
|
+
if resolution is not None:
|
|
290
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
291
|
+
else:
|
|
292
|
+
try:
|
|
293
|
+
resolution = _WORKER._COMMERCIAL.validate_review_resolution(
|
|
294
|
+
resolution, review, profile,
|
|
295
|
+
)
|
|
296
|
+
except _WORKER._COMMERCIAL.CommercialReviewBlocked:
|
|
297
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
298
|
+
elif resolution is not None:
|
|
299
|
+
raise LocalizationReleaseBlocked("publication.evidence.invalid")
|
|
300
|
+
return json.loads(_canonical_json({
|
|
301
|
+
**value,
|
|
302
|
+
"commercial_review": review,
|
|
303
|
+
"commercial_review_resolution": resolution,
|
|
304
|
+
}))
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _commercial_review_resolution(
|
|
308
|
+
result: dict[str, Any],
|
|
309
|
+
approval: dict[str, Any],
|
|
310
|
+
) -> dict[str, Any] | None:
|
|
311
|
+
review = result["commercial_review"]
|
|
312
|
+
if (
|
|
313
|
+
result["content_type"] != "commercial"
|
|
314
|
+
or review["status"] == "verified"
|
|
315
|
+
):
|
|
316
|
+
return None
|
|
317
|
+
human_receipt_sha256 = approval["human_review_receipt_sha256"]
|
|
318
|
+
independent = approval["independent_model_review"]
|
|
319
|
+
if human_receipt_sha256 is not None:
|
|
320
|
+
method = "qualified_human"
|
|
321
|
+
receipt_sha256 = human_receipt_sha256
|
|
322
|
+
provider = None
|
|
323
|
+
else:
|
|
324
|
+
method = "independent_model"
|
|
325
|
+
receipt_sha256 = independent["receipt_sha256"]
|
|
326
|
+
provider = json.loads(_canonical_json(independent["provider"]))
|
|
327
|
+
return {
|
|
328
|
+
"schema": COMMERCIAL_REVIEW_RESOLUTION_SCHEMA,
|
|
329
|
+
"profile": review["profile"],
|
|
330
|
+
"contract_sha256": approval[
|
|
331
|
+
"commercial_review_resolution_contract_sha256"
|
|
332
|
+
],
|
|
333
|
+
"status": "resolved",
|
|
334
|
+
"reviewed_dimensions": json.loads(_canonical_json(
|
|
335
|
+
review["review_required_dimensions"]
|
|
336
|
+
)),
|
|
337
|
+
"reviewed_offer_count": review["offer_count"],
|
|
338
|
+
"reviewed_offers": json.loads(_canonical_json(
|
|
339
|
+
review["review_required_offers"]
|
|
340
|
+
)),
|
|
341
|
+
"method": method,
|
|
342
|
+
"receipt_sha256": receipt_sha256,
|
|
343
|
+
"primary_provider": json.loads(_canonical_json(result["provider"])),
|
|
344
|
+
"provider": provider,
|
|
345
|
+
}
|
|
172
346
|
|
|
173
347
|
|
|
174
348
|
@dataclass(frozen=True)
|
|
@@ -204,6 +378,74 @@ def _hash_text(value: str) -> str:
|
|
|
204
378
|
return hashlib.sha256(value.encode("utf-8")).hexdigest()
|
|
205
379
|
|
|
206
380
|
|
|
381
|
+
def _publication_evidence_contract_body() -> dict[str, Any]:
|
|
382
|
+
return {
|
|
383
|
+
"schema": PUBLICATION_EVIDENCE_CAPABILITIES_SCHEMA,
|
|
384
|
+
"release_evidence_schema": PUBLICATION_EVIDENCE_SCHEMA,
|
|
385
|
+
"required_fields": list(PUBLICATION_EVIDENCE_FIELDS),
|
|
386
|
+
"bindings": {
|
|
387
|
+
"sha256_fields": [
|
|
388
|
+
"release_evidence_contract_sha256", "target_sha256",
|
|
389
|
+
"result_sha256", "approval_sha256", "quality_receipt_sha256",
|
|
390
|
+
"commercial_review_routing_contract_sha256",
|
|
391
|
+
"commercial_review_resolution_contract_sha256",
|
|
392
|
+
],
|
|
393
|
+
"lineage_fields": ["evidence_request_id", "evidence_revision"],
|
|
394
|
+
"target_identity_fields": [
|
|
395
|
+
"job_id", "target_locale", "target_sha256", "approval_id",
|
|
396
|
+
],
|
|
397
|
+
"quality_profile": "exact-current-target-locale-quality-profile",
|
|
398
|
+
"signed_container": "blun.cms-localization-publication.v3",
|
|
399
|
+
},
|
|
400
|
+
"commercial_scope": {
|
|
401
|
+
"content_type": "commercial",
|
|
402
|
+
"required_non_null": [
|
|
403
|
+
"commercial_profile", "commercial_quality_profile",
|
|
404
|
+
"commercial_review", "commercial_review_routing_contract_sha256",
|
|
405
|
+
"commercial_review_resolution_contract_sha256",
|
|
406
|
+
],
|
|
407
|
+
"review_evidence_contract_sha256": (
|
|
408
|
+
"exact-current-public-commercial-evidence-contract"
|
|
409
|
+
),
|
|
410
|
+
"review_resolution_contract_sha256": (
|
|
411
|
+
"exact-current-public-commercial-resolution-contract"
|
|
412
|
+
),
|
|
413
|
+
"quality_profile": (
|
|
414
|
+
"exact-current-target-locale-commercial-quality-profile"
|
|
415
|
+
),
|
|
416
|
+
"resolution": "required-only-when-review-required",
|
|
417
|
+
"non_commercial_fields": "all-null",
|
|
418
|
+
},
|
|
419
|
+
"content_policy": {
|
|
420
|
+
"source_text": False,
|
|
421
|
+
"target_text": False,
|
|
422
|
+
"raw_receipt": False,
|
|
423
|
+
"reviewer_identity": False,
|
|
424
|
+
"reviewer_prose": False,
|
|
425
|
+
"commercial_review_routing": False,
|
|
426
|
+
"project_prices": False,
|
|
427
|
+
"project_brands": False,
|
|
428
|
+
"authentication_material": False,
|
|
429
|
+
},
|
|
430
|
+
"tamper_policy": "reject-complete-publication-before-host-commit",
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def publication_evidence_contract() -> dict[str, Any]:
|
|
435
|
+
"""Return the exact content-free contract advertised to CMS adapters."""
|
|
436
|
+
body = _publication_evidence_contract_body()
|
|
437
|
+
return {**body, "sha256": _hash_text(_canonical_json(body))}
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def validate_publication_evidence_contract(value: Any) -> dict[str, Any]:
|
|
441
|
+
"""Reject a partial, reordered, altered, or merely rehashed contract."""
|
|
442
|
+
body = _publication_evidence_contract_body()
|
|
443
|
+
expected = {**body, "sha256": _hash_text(_canonical_json(body))}
|
|
444
|
+
if value != expected:
|
|
445
|
+
raise LocalizationReleaseBlocked("publication.evidence_contract.invalid")
|
|
446
|
+
return json.loads(_canonical_json(expected))
|
|
447
|
+
|
|
448
|
+
|
|
207
449
|
def _text(value: Any, code: str, *, limit: int = 256) -> str:
|
|
208
450
|
if not isinstance(value, str) or not value or value != value.strip():
|
|
209
451
|
raise LocalizationReleaseBlocked(code)
|
|
@@ -242,12 +484,37 @@ def _independent_model_review(value: Any, primary_provider: dict[str, Any]) -> t
|
|
|
242
484
|
return normalized, _receipt(value.get("receipt"), "independent_model_review.receipt.required")
|
|
243
485
|
|
|
244
486
|
|
|
487
|
+
def _commercial_resolution_contract_sha256(
|
|
488
|
+
job: dict[str, Any],
|
|
489
|
+
result: dict[str, Any],
|
|
490
|
+
) -> str | None:
|
|
491
|
+
commercial_profile = job.get("commercial_profile")
|
|
492
|
+
commercial_review = result["commercial_review"]
|
|
493
|
+
if commercial_profile is None or commercial_review["status"] != "review_required":
|
|
494
|
+
return None
|
|
495
|
+
try:
|
|
496
|
+
expected = _WORKER._COMMERCIAL.public_review_resolution_contract(
|
|
497
|
+
commercial_profile,
|
|
498
|
+
)["sha256"]
|
|
499
|
+
except (KeyError, TypeError, ValueError):
|
|
500
|
+
raise LocalizationReleaseBlocked("approval.binding_mismatch") from None
|
|
501
|
+
if (
|
|
502
|
+
job.get("commercial_review_resolution_contract_sha256") != expected
|
|
503
|
+
or result.get("commercial_review_resolution_contract_sha256")
|
|
504
|
+
!= expected
|
|
505
|
+
):
|
|
506
|
+
raise LocalizationReleaseBlocked("approval.binding_mismatch")
|
|
507
|
+
return expected
|
|
508
|
+
|
|
509
|
+
|
|
245
510
|
def _receipt_binding(
|
|
246
511
|
job_id: str,
|
|
247
512
|
job: dict[str, Any],
|
|
248
513
|
result: dict[str, Any],
|
|
249
514
|
result_sha256: str,
|
|
250
515
|
*,
|
|
516
|
+
evidence_request_id: str,
|
|
517
|
+
evidence_revision: str,
|
|
251
518
|
review_kind: str,
|
|
252
519
|
review_provider: dict[str, str] | None = None,
|
|
253
520
|
) -> dict[str, Any]:
|
|
@@ -257,9 +524,23 @@ def _receipt_binding(
|
|
|
257
524
|
raise LocalizationReleaseBlocked("review.binding.invalid")
|
|
258
525
|
if (review_kind == "independent_model") != (review_provider is not None):
|
|
259
526
|
raise LocalizationReleaseBlocked("review.binding.invalid")
|
|
527
|
+
if (
|
|
528
|
+
not isinstance(evidence_request_id, str)
|
|
529
|
+
or EVIDENCE_REQUEST_ID.fullmatch(evidence_request_id) is None
|
|
530
|
+
or not isinstance(evidence_revision, str)
|
|
531
|
+
or TOKEN.fullmatch(evidence_revision) is None
|
|
532
|
+
):
|
|
533
|
+
raise LocalizationReleaseBlocked("review.evidence_context.invalid")
|
|
534
|
+
commercial_profile = job.get("commercial_profile")
|
|
535
|
+
commercial_review = result["commercial_review"]
|
|
536
|
+
resolution_contract_sha256 = _commercial_resolution_contract_sha256(
|
|
537
|
+
job, result,
|
|
538
|
+
)
|
|
260
539
|
binding = {
|
|
261
540
|
"schema": RECEIPT_BINDING_SCHEMA,
|
|
262
541
|
"review_kind": review_kind,
|
|
542
|
+
"evidence_request_id": evidence_request_id,
|
|
543
|
+
"evidence_revision": evidence_revision,
|
|
263
544
|
"job_id": job_id,
|
|
264
545
|
"result_sha256": result_sha256,
|
|
265
546
|
"source_text": job["source"]["text"],
|
|
@@ -276,8 +557,15 @@ def _receipt_binding(
|
|
|
276
557
|
"software_version": result["software_version"],
|
|
277
558
|
"review_confidence": result["review_confidence"],
|
|
278
559
|
"quality_profile": result["quality_profile"],
|
|
279
|
-
"commercial_profile":
|
|
280
|
-
"commercial_review":
|
|
560
|
+
"commercial_profile": commercial_profile,
|
|
561
|
+
"commercial_review": commercial_review,
|
|
562
|
+
"commercial_review_routing": result["commercial_review_routing"],
|
|
563
|
+
"commercial_review_routing_contract_sha256": result[
|
|
564
|
+
"commercial_review_routing_contract_sha256"
|
|
565
|
+
],
|
|
566
|
+
"commercial_review_resolution_contract_sha256": (
|
|
567
|
+
resolution_contract_sha256
|
|
568
|
+
),
|
|
281
569
|
"human_review_required": result["human_review_required"],
|
|
282
570
|
"independent_review_required": result["independent_review_required"],
|
|
283
571
|
}
|
|
@@ -351,7 +639,10 @@ def _validate_result(job: dict[str, Any], result: Any) -> dict[str, Any]:
|
|
|
351
639
|
"source_locale", "target_locale", "content_type", "glossary_version",
|
|
352
640
|
"policy_version", "provider", "software_version", "candidate",
|
|
353
641
|
"quality_passes", "integrity", "review_confidence",
|
|
354
|
-
"quality_profile", "commercial_review", "
|
|
642
|
+
"quality_profile", "commercial_review", "commercial_review_routing",
|
|
643
|
+
"commercial_review_routing_contract_sha256",
|
|
644
|
+
"commercial_review_resolution_contract_sha256",
|
|
645
|
+
"human_review_required",
|
|
355
646
|
"independent_review_required", "release_required",
|
|
356
647
|
}
|
|
357
648
|
if set(result) != expected:
|
|
@@ -379,6 +670,12 @@ def _validate_result(job: dict[str, Any], result: Any) -> dict[str, Any]:
|
|
|
379
670
|
"version": job["target"]["quality_profile_version"],
|
|
380
671
|
"sha256": job["target"]["quality_profile_sha256"],
|
|
381
672
|
}
|
|
673
|
+
if job["content_type"] == "commercial":
|
|
674
|
+
expected_quality_profile["commercial"] = {
|
|
675
|
+
"profile": job["commercial_profile"],
|
|
676
|
+
"version": job["commercial_quality_profile"]["version"],
|
|
677
|
+
"sha256": job["commercial_quality_profile"]["sha256"],
|
|
678
|
+
}
|
|
382
679
|
if result.get("quality_profile") != expected_quality_profile:
|
|
383
680
|
raise LocalizationReleaseBlocked("result.quality_profile.invalid")
|
|
384
681
|
if result.get("schema") != _WORKER.RESULT_SCHEMA or result.get("worker_schema") != _WORKER.WORKER_SCHEMA:
|
|
@@ -420,16 +717,48 @@ def _validate_result(job: dict[str, Any], result: Any) -> dict[str, Any]:
|
|
|
420
717
|
):
|
|
421
718
|
raise LocalizationReleaseBlocked("result.independent_review.invalid")
|
|
422
719
|
commercial_review = result.get("commercial_review")
|
|
720
|
+
commercial_review_routing = result.get("commercial_review_routing")
|
|
721
|
+
commercial_routing_contract_sha256 = result.get(
|
|
722
|
+
"commercial_review_routing_contract_sha256"
|
|
723
|
+
)
|
|
724
|
+
commercial_resolution_contract_sha256 = result.get(
|
|
725
|
+
"commercial_review_resolution_contract_sha256"
|
|
726
|
+
)
|
|
423
727
|
if job["content_type"] == "commercial":
|
|
728
|
+
expected_routing_contract_sha256 = job[
|
|
729
|
+
"commercial_review_routing_contract_sha256"
|
|
730
|
+
]
|
|
731
|
+
if commercial_routing_contract_sha256 != expected_routing_contract_sha256:
|
|
732
|
+
raise LocalizationReleaseBlocked("result.commercial_review.invalid")
|
|
733
|
+
if commercial_resolution_contract_sha256 != job[
|
|
734
|
+
"commercial_review_resolution_contract_sha256"
|
|
735
|
+
]:
|
|
736
|
+
raise LocalizationReleaseBlocked("result.commercial_review.invalid")
|
|
424
737
|
try:
|
|
425
|
-
_WORKER._COMMERCIAL.validate_summary(
|
|
738
|
+
commercial_review = _WORKER._COMMERCIAL.validate_summary(
|
|
426
739
|
commercial_review,
|
|
427
740
|
job["commercial_profile"],
|
|
428
741
|
review_required=independent_review_required,
|
|
429
742
|
)
|
|
743
|
+
if commercial_review["status"] == "review_required":
|
|
744
|
+
_WORKER._COMMERCIAL.validate_review_routing_context(
|
|
745
|
+
commercial_review_routing,
|
|
746
|
+
job["source"]["text"],
|
|
747
|
+
candidate,
|
|
748
|
+
commercial_review,
|
|
749
|
+
job["commercial_profile"],
|
|
750
|
+
)
|
|
751
|
+
elif commercial_review_routing is not None:
|
|
752
|
+
raise _WORKER._COMMERCIAL.CommercialReviewBlocked(
|
|
753
|
+
"review.commercial.routing_invalid",
|
|
754
|
+
)
|
|
430
755
|
except _WORKER._COMMERCIAL.CommercialReviewBlocked:
|
|
431
756
|
raise LocalizationReleaseBlocked("result.commercial_review.invalid") from None
|
|
432
|
-
elif
|
|
757
|
+
elif any(value is not None for value in (
|
|
758
|
+
commercial_review, commercial_review_routing,
|
|
759
|
+
commercial_routing_contract_sha256,
|
|
760
|
+
commercial_resolution_contract_sha256,
|
|
761
|
+
)):
|
|
433
762
|
raise LocalizationReleaseBlocked("result.commercial_review.invalid")
|
|
434
763
|
return result
|
|
435
764
|
|
|
@@ -491,6 +820,8 @@ class LocalizationReleaseStore:
|
|
|
491
820
|
quality_verifier: QualityReceiptVerifier,
|
|
492
821
|
authority: ApprovalAuthority,
|
|
493
822
|
*,
|
|
823
|
+
evidence_request_id: str,
|
|
824
|
+
evidence_revision: str,
|
|
494
825
|
now: float | int,
|
|
495
826
|
ttl_seconds: float | int = 2_592_000,
|
|
496
827
|
human_review_receipt: str | None = None,
|
|
@@ -508,6 +839,13 @@ class LocalizationReleaseStore:
|
|
|
508
839
|
result_json = _canonical_json(result)
|
|
509
840
|
result_hash = _hash_text(result_json)
|
|
510
841
|
quality_receipt = _receipt(quality_receipt, "quality.receipt.invalid")
|
|
842
|
+
if (
|
|
843
|
+
not isinstance(evidence_request_id, str)
|
|
844
|
+
or EVIDENCE_REQUEST_ID.fullmatch(evidence_request_id) is None
|
|
845
|
+
or not isinstance(evidence_revision, str)
|
|
846
|
+
or TOKEN.fullmatch(evidence_revision) is None
|
|
847
|
+
):
|
|
848
|
+
raise LocalizationReleaseBlocked("review.evidence_context.invalid")
|
|
511
849
|
verifier = getattr(quality_verifier, "verify", None)
|
|
512
850
|
if not callable(verifier):
|
|
513
851
|
raise LocalizationReleaseBlocked("quality.verifier.invalid")
|
|
@@ -518,6 +856,8 @@ class LocalizationReleaseStore:
|
|
|
518
856
|
job,
|
|
519
857
|
result,
|
|
520
858
|
result_hash,
|
|
859
|
+
evidence_request_id=evidence_request_id,
|
|
860
|
+
evidence_revision=evidence_revision,
|
|
521
861
|
review_kind="quality",
|
|
522
862
|
),
|
|
523
863
|
receipt=quality_receipt,
|
|
@@ -544,6 +884,8 @@ class LocalizationReleaseStore:
|
|
|
544
884
|
job,
|
|
545
885
|
result,
|
|
546
886
|
result_hash,
|
|
887
|
+
evidence_request_id=evidence_request_id,
|
|
888
|
+
evidence_revision=evidence_revision,
|
|
547
889
|
review_kind="qualified_human",
|
|
548
890
|
),
|
|
549
891
|
receipt=human_review_receipt,
|
|
@@ -571,6 +913,8 @@ class LocalizationReleaseStore:
|
|
|
571
913
|
job,
|
|
572
914
|
result,
|
|
573
915
|
result_hash,
|
|
916
|
+
evidence_request_id=evidence_request_id,
|
|
917
|
+
evidence_revision=evidence_revision,
|
|
574
918
|
review_kind="independent_model",
|
|
575
919
|
review_provider=provider,
|
|
576
920
|
),
|
|
@@ -598,6 +942,8 @@ class LocalizationReleaseStore:
|
|
|
598
942
|
job,
|
|
599
943
|
result,
|
|
600
944
|
result_hash,
|
|
945
|
+
evidence_request_id=evidence_request_id,
|
|
946
|
+
evidence_revision=evidence_revision,
|
|
601
947
|
review_kind="qualified_human",
|
|
602
948
|
),
|
|
603
949
|
receipt=human_review_receipt,
|
|
@@ -616,6 +962,11 @@ class LocalizationReleaseStore:
|
|
|
616
962
|
|
|
617
963
|
immutable = {
|
|
618
964
|
"schema": APPROVAL_SCHEMA,
|
|
965
|
+
"release_evidence_contract_sha256": (
|
|
966
|
+
publication_evidence_contract()["sha256"]
|
|
967
|
+
),
|
|
968
|
+
"evidence_request_id": evidence_request_id,
|
|
969
|
+
"evidence_revision": evidence_revision,
|
|
619
970
|
"job_id": job_id,
|
|
620
971
|
"source_sha256": result["source_sha256"],
|
|
621
972
|
"target_sha256": result["target_sha256"],
|
|
@@ -629,10 +980,16 @@ class LocalizationReleaseStore:
|
|
|
629
980
|
"worker_schema": result["worker_schema"],
|
|
630
981
|
"review_confidence": result["review_confidence"],
|
|
631
982
|
"quality_profile": result["quality_profile"],
|
|
983
|
+
"commercial_review_routing_contract_sha256": result[
|
|
984
|
+
"commercial_review_routing_contract_sha256"
|
|
985
|
+
],
|
|
632
986
|
"result_sha256": result_hash,
|
|
633
987
|
"quality_receipt_sha256": _hash_text(quality_receipt),
|
|
634
988
|
"human_review_receipt_sha256": human_hash,
|
|
635
989
|
"independent_model_review": independent_binding,
|
|
990
|
+
"commercial_review_resolution_contract_sha256": (
|
|
991
|
+
_commercial_resolution_contract_sha256(job, result)
|
|
992
|
+
),
|
|
636
993
|
}
|
|
637
994
|
approval_id = "blun-l10n-approval-" + _hash_text(_canonical_json(immutable))
|
|
638
995
|
payload = {
|
|
@@ -715,19 +1072,28 @@ class LocalizationReleaseStore:
|
|
|
715
1072
|
raise LocalizationReleaseBlocked("translation_memory.json.invalid") from None
|
|
716
1073
|
result = _validate_result(job, result)
|
|
717
1074
|
expected_keys = {
|
|
718
|
-
"schema", "
|
|
1075
|
+
"schema", "release_evidence_contract_sha256",
|
|
1076
|
+
"evidence_request_id", "evidence_revision", "job_id",
|
|
1077
|
+
"source_sha256", "target_sha256", "source_locale",
|
|
719
1078
|
"target_locale", "content_type", "glossary_version", "policy_version",
|
|
720
1079
|
"provider", "software_version", "worker_schema", "result_sha256",
|
|
721
1080
|
"review_confidence",
|
|
722
1081
|
"quality_profile",
|
|
1082
|
+
"commercial_review_routing_contract_sha256",
|
|
723
1083
|
"quality_receipt_sha256", "human_review_receipt_sha256",
|
|
724
1084
|
"independent_model_review", "approval_id",
|
|
1085
|
+
"commercial_review_resolution_contract_sha256",
|
|
725
1086
|
"approved_at", "expires_at",
|
|
726
1087
|
}
|
|
727
1088
|
if set(payload) != expected_keys:
|
|
728
1089
|
raise LocalizationReleaseBlocked("approval.binding_mismatch")
|
|
729
1090
|
binding = {
|
|
730
1091
|
"schema": APPROVAL_SCHEMA,
|
|
1092
|
+
"release_evidence_contract_sha256": (
|
|
1093
|
+
publication_evidence_contract()["sha256"]
|
|
1094
|
+
),
|
|
1095
|
+
"evidence_request_id": payload.get("evidence_request_id"),
|
|
1096
|
+
"evidence_revision": payload.get("evidence_revision"),
|
|
731
1097
|
"job_id": row["job_id"],
|
|
732
1098
|
"source_sha256": result["source_sha256"],
|
|
733
1099
|
"target_sha256": result["target_sha256"],
|
|
@@ -741,12 +1107,26 @@ class LocalizationReleaseStore:
|
|
|
741
1107
|
"worker_schema": result["worker_schema"],
|
|
742
1108
|
"review_confidence": result["review_confidence"],
|
|
743
1109
|
"quality_profile": result["quality_profile"],
|
|
1110
|
+
"commercial_review_routing_contract_sha256": result[
|
|
1111
|
+
"commercial_review_routing_contract_sha256"
|
|
1112
|
+
],
|
|
744
1113
|
"result_sha256": row["result_sha256"],
|
|
1114
|
+
"commercial_review_resolution_contract_sha256": (
|
|
1115
|
+
_commercial_resolution_contract_sha256(job, result)
|
|
1116
|
+
),
|
|
745
1117
|
"approved_at": row["approved_at"],
|
|
746
1118
|
"expires_at": row["expires_at"],
|
|
747
1119
|
}
|
|
748
1120
|
if any(payload.get(name) != value for name, value in binding.items()):
|
|
749
1121
|
raise LocalizationReleaseBlocked("approval.binding_mismatch")
|
|
1122
|
+
if (
|
|
1123
|
+
EVIDENCE_REQUEST_ID.fullmatch(
|
|
1124
|
+
str(payload.get("evidence_request_id"))
|
|
1125
|
+
) is None
|
|
1126
|
+
or not isinstance(payload.get("evidence_revision"), str)
|
|
1127
|
+
or TOKEN.fullmatch(payload["evidence_revision"]) is None
|
|
1128
|
+
):
|
|
1129
|
+
raise LocalizationReleaseBlocked("approval.binding_mismatch")
|
|
750
1130
|
if payload.get("approval_id") != row["approval_id"]:
|
|
751
1131
|
raise LocalizationReleaseBlocked("approval.binding_mismatch")
|
|
752
1132
|
if HEX64.fullmatch(str(payload.get("quality_receipt_sha256"))) is None:
|
|
@@ -811,6 +1191,9 @@ class LocalizationReleaseStore:
|
|
|
811
1191
|
candidate=result["candidate"],
|
|
812
1192
|
release_evidence=validate_publication_evidence({
|
|
813
1193
|
"schema": PUBLICATION_EVIDENCE_SCHEMA,
|
|
1194
|
+
"release_evidence_contract_sha256": payload[
|
|
1195
|
+
"release_evidence_contract_sha256"
|
|
1196
|
+
],
|
|
814
1197
|
"job_id": row["job_id"],
|
|
815
1198
|
"target_locale": row["target_locale"],
|
|
816
1199
|
"target_sha256": row["target_sha256"],
|
|
@@ -819,10 +1202,33 @@ class LocalizationReleaseStore:
|
|
|
819
1202
|
"result_sha256": row["result_sha256"],
|
|
820
1203
|
"approval_sha256": row["approval_sha256"],
|
|
821
1204
|
"quality_receipt_sha256": payload["quality_receipt_sha256"],
|
|
1205
|
+
"evidence_request_id": payload["evidence_request_id"],
|
|
1206
|
+
"evidence_revision": payload["evidence_revision"],
|
|
1207
|
+
"quality_profile": {
|
|
1208
|
+
"locale": result["quality_profile"]["locale"],
|
|
1209
|
+
"version": result["quality_profile"]["version"],
|
|
1210
|
+
"sha256": result["quality_profile"]["sha256"],
|
|
1211
|
+
},
|
|
822
1212
|
"commercial_profile": job.get("commercial_profile"),
|
|
1213
|
+
"commercial_quality_profile": (
|
|
1214
|
+
json.loads(_canonical_json(
|
|
1215
|
+
result["quality_profile"].get("commercial")
|
|
1216
|
+
))
|
|
1217
|
+
if result["content_type"] == "commercial"
|
|
1218
|
+
else None
|
|
1219
|
+
),
|
|
823
1220
|
"commercial_review": json.loads(
|
|
824
1221
|
_canonical_json(result["commercial_review"])
|
|
825
1222
|
),
|
|
1223
|
+
"commercial_review_routing_contract_sha256": result[
|
|
1224
|
+
"commercial_review_routing_contract_sha256"
|
|
1225
|
+
],
|
|
1226
|
+
"commercial_review_resolution_contract_sha256": result[
|
|
1227
|
+
"commercial_review_resolution_contract_sha256"
|
|
1228
|
+
],
|
|
1229
|
+
"commercial_review_resolution": _commercial_review_resolution(
|
|
1230
|
+
result, payload,
|
|
1231
|
+
),
|
|
826
1232
|
}),
|
|
827
1233
|
approved_at=float(row["approved_at"]),
|
|
828
1234
|
expires_at=float(row["expires_at"]),
|